How does CreateProcess locate the executable?

2019-06-24 12:30发布

问题:

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.
)

回答1:

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.



回答2:

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.



回答3:

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.