Open piscisaureus opened 13 years ago
Dropping the path search code entirely and using the search mechanics built into CreateProcess should also be considered.
The downside is that it uses a different search rules than what (I think) people are familiar with from cmd.exe / spawnvpe(). On the upside, we could delete quite some code. Also the CreateProcess search rules are well-documented.
There are many options. They all suck to a greater or lesser extent. Windows has a bunch of rules in different places. I'm not really sure users will have any consistent expectations.
ShellExecute()
is probably the most complex API. It checks working directories, PATH, various registry keys, and probably more. Awful.ShellExecute()
, since it seems to do most of the things ShellExecute()
does, with the added bonus of also considering cmd.exe built-ins and the PATHEXT environment variable.CreateProcess()
's rules with lpApplicationName are very simple and easy to understand. They're also utterly unforgiving: no filename extension is added (no automatic .exe or .com or anything else), no PATH searching. If you give it an absolute path to a filename it'll try that absolute path and no other; if you give it a bare filename (or maybe a relative path? It doesn't specify) it'll try $CWD\filename. And that's it.CreateProcess()
without lpApplicationName does a search; application folder, $CWD, system32, system, \windows, $PATH, in that order. It will try each location with and without a .exe extension._spawnvpe()
will first try CreateProcess()
's lpApplicationName strategy. If that fails, and if a bare filename was supplied (with neither an absolute nor a relative path), it will then try each directory in the parent process's $PATH. Even if a child environment $PATH is specified, it will not be examined.Not directly used, but another Win32 lookup behaviour is found in SearchPath()
, which will check $CWD and then $PATH, or $PATH followed by $CWD, depending on options.
With the exception of SearchPath()
, none of these functions has a search API available. _spawnvpe()
is, I believe, directly equivalent to:
if(filename contains '\' or '/') {
CreateProcess(filename, commandline, ...); // try absolute filenames directly, do nothing else
} else {
filename = SearchPath(filename, ...); // search CWD and then PATH
CreateProcess(filename, commandline, ...);
}
I don't think trying to replicate ShellExecute()
or cmd.exe is a worthwhile endeavour. The rules are complex, not documented, and it'll just be a nightmare of complexity.
CreateProcess()
using lpApplicationName is far and away the simplest and easiest to understand, and easiest to implement, but it is probably too user-hostile.
CreateProcess()
without lpApplicationName uses well-defined, reasonably well-known rules. We get a lot of magic for free, including $CWD and $PATH searching. We do lose the ability to spawn executables with long filenames (the executable must have a fully-qualified filename that is no longer than MAX_PATH
), but Explorer itself struggles with such files, so we're not any worse than the operating system itself. Calling this is only marginally more dificult; we have to make sure that the program name is wrapped in quote marks if it contains spaces, but that's all the processing we'd need to do.
The _spawnvpe()
rules are tolerably defined, probably not widely known, closely analogous to what happens on UNIX platforms, and if we use SearchPath()
to implement them (as the pseudocode above), not too tricky to implement.
I think any of these three options is reasonable. I think it boils down to a question of whether we want:
CreateProcess()
, lpApplicationName)MAX_PATH
) (CreateProcess()
, no lpApplicationName)CreateProcess()
with lpApplicationName, using the raw filename if an absolute path is provided, and SearchPath()
if a bare filename is used).I am a strong -1 on the current code--it's complex, it doesn't correspond with any built-in API or C/POSIX function, its rules aren't really documented to callers--and a +0 on each of the above three. Perhaps a +0.5 on option 3.
uv_spawn uses the
PATH
environment variable to locate the executable to be spawned.On unix, if the user explicitly supplies an environment block, the
PATH
from this environment is used. If the supplied environment does not contain aPATH
variable,:/bin:/usr/bin
is used as a fallback.On windows the search path from the parent process is always used.
This semantic difference may need to be resolved.