According to the docs, CreateProcess can be passed an executable name
as first argument, or a command line as a second argument (from which the
executable name will be extracted).
If you pass an executable name, the docs say PATH
won't be searched.
if you pass a command line instead, the first token is extracted to be used
as the executable name and PATH
is supposed to be searched.
In my case, though, my call to CreateProcess
---with a command line only and
with a modified environment--- doesn't find the sought executable. It only
succeeds if I precede the command line with cmd.exe /c
(I understand why
it works this way).
For completeness, I'm not actually using the Windows API directly, but
subprocess.Popen
in Python, although I think I've narrowed down the problem
to the above circumstances. With shell = True
, the right environment is
picked up; with shell = False
(my desired way of creating the subprocess),
the call fails to locate my executable. The executable is a standalone exe, not an intrinsic command of cmd.exe.
Can someone please tell my what I'm doing wrong here or where's my misunderstanding?
Example code:
from subprocess import Popen
import os, sys
exe = "wc.exe" # No other wc.exe on the PATH
env = os.environ.copy()
new_path = os.path.expandvars(r"%HOMEDRIVE%%HOMEPATH%\SmallApps\GnuWin32\bin;%PATH%")
env["PATH"] = os.path.expandvars(new_path).encode(sys.getfilesystemencoding())
Popen(
args=[exe, "*.*"],
env=env,
# shell=True # Works if you uncomment this line.
)
You need to modify the environment of the current process if you want CreateProcess
to see it. Currently, the subshell (whether included in the command line or requested via shell=True
) is seeing your modified environment, but the direct invocation of CreateProcess
is not.
If I'm reading your question right, it sounds like you have an application named wc.exe
in the folder that %HOMEDRIVE%%HOMEPATH%\SmallApps\GnuWin32\bin
maps to. If that is the case, you would do better to set exe to the expanded version of %HOMEDRIVE%%HOMEPATH%\SmallApps\GnuWin32\bin\wc.exe
. Since this path and executable name may end up containing spaces, it wouldn't hurt to wrap it in quotes as well.
In short, don't rely on the path search. Not only is it prone to errors, it's also a potential security hole.
Thought of checking MSDN? CreateProcess documentation.
To quote one part of it:
The directory from which the application loaded.
The current directory for the parent process.
The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.