CreateProcess如何查找可执行文件?
根据文档,CreateProcess 可以接收一个可执行文件的名称作为第一个参数,或者一个命令行作为第二个参数(从中提取可执行文件的名称)。
如果你传递的是可执行文件的名称,文档说 PATH
不会被搜索。
如果你传递的是命令行,系统会提取第一个部分作为可执行文件的名称,并且会搜索 PATH
。
不过在我的情况下,我调用 CreateProcess
时只用了命令行和修改过的环境,却找不到想要的可执行文件。只有在命令行前加上 cmd.exe /c
时才成功(我明白为什么这样做有效)。
为了完整起见,我其实并不是直接使用 Windows API,而是在 Python 中使用 subprocess.Popen
,不过我觉得问题已经缩小到上述情况。当 shell = True
时,正确的环境会被选中;而当 shell = False
(这是我希望创建子进程的方式)时,调用就找不到我的可执行文件。这个可执行文件是一个独立的 exe 文件,而不是 cmd.exe 的内置命令。
有人能告诉我我哪里做错了,或者我哪里理解错了吗?
示例代码:
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.
)
3 个回答
想过去看看MSDN吗?这里有关于CreateProcess的文档。
引用其中的一部分内容:
应用程序加载的目录。
父进程的当前目录。
32位Windows系统目录。可以用GetSystemDirectory函数来获取这个目录的路径。
16位Windows系统目录。没有函数可以获取这个目录的路径,但系统会搜索这个目录。这个目录的名字是System。
Windows目录。可以用GetWindowsDirectory函数来获取这个目录的路径。
在PATH环境变量中列出的目录。需要注意的是,这个函数不会搜索由App Paths注册表键指定的每个应用程序的路径。如果想把这个每个应用程序的路径包含在搜索序列中,可以使用ShellExecute函数。
如果我理解你的问题没错,你的文件夹里有一个叫 wc.exe
的应用程序,这个文件夹的路径是 %HOMEDRIVE%%HOMEPATH%\SmallApps\GnuWin32\bin
。如果是这样的话,建议你直接使用这个应用程序的完整路径,也就是 %HOMEDRIVE%%HOMEPATH%\SmallApps\GnuWin32\bin\wc.exe
。因为这个路径和文件名可能会包含空格,所以最好把它放在引号里。
简单来说,不要依赖路径搜索。这样做不仅容易出错,还有可能带来安全隐患。
如果你想让CreateProcess
看到你修改过的环境变量,你需要改变当前这个进程的环境。现在,子shell(无论是通过命令行包含的,还是通过shell=True
请求的)能够看到你修改过的环境,但直接调用CreateProcess
却看不到。