WinAPI - 当 C:\Program 文件存在时 CreateProcessW 失败
WinAPI - CreateProcessW fails when C:\Program file exists
我运行下面的C代码创建了一个进程。 exe文件位于C:\Program Files\Exes\Start\process1.exe
CreateProcessW(NULL, (char*) exePath,
NULL, NULL, TRUE,
flags,
NULL, NULL, &startupInfo, &processInformation);
现在有些计算机随机将这个名为 Program 的文件位于 C:\Program 中,这会导致创建过程失败并出现错误:
%1 is not a valid Win32 application.
除了重命名文件之外,是否还有解决此问题的方法,因为有几十个 Windows 虚拟机在其上执行此 C 代码。此错误随机发生在几台机器上。
这段代码是如何编译的? CreateProcessW 的第二个参数定义为 LPWSTR
,这意味着它应该只接受宽字符串。
下一个问题:由于强制转换,无法确定 exePath
的来源。这是重要的原因是第二个参数被定义为 LPWSTR
,而不是 LPCWSTR
(即 const 宽字符串),原因如下:CreateProcessW
可以写入缓冲区。
然后是第三个问题 - 您的 exe 路径中有一个 space。当作为第二个参数 (lpCommandLine) 传递时,CreateProcess
有一些愚蠢的逻辑来猜测 exe 名称结束的位置和命令行的开始位置。这需要引用编码命令行的 exe 路径部分。
当您拥有 exe 的完整路径且没有参数时,最简单/最安全的做法是将其作为 lpApplicationName 参数传递。这是一个 const 参数,它避免了任何潜在的未定义行为,如果您的命令行源是常量字符串文字等,则可能导致这种行为。并且只是用作要执行的 exe 的路径,因此没有(也不能)有任何引号要求。
CreateProcess(exePath,NULL,...);
旁白:使用 CreateProcess
的两个参数基本上可以让您将启动的应用程序的 argv[0] 设置为您想要的任何值。因此,您可以 运行 来自特定路径/exe 名称的应用程序,但使 argv[0] 指向其他路径或 exe 名称。
要将参数传递给 exe,而不是传递完整(引号括起)路径,您可以像这样简单地做一些事情:
WCHAR cmdLine[] = TEXT("console1.exe --version");
CreateProcessW(exePath,cmdLine,...);
编辑 感谢 Paul Sanders 和其他指出未引用的 exe 路径的评论,这也让我完全打破了我原来的答案,这个答案在我没有意识到的情况下解决了.
感谢 RbMm 发现了我的答案,感谢 eryksun 向我展示了近 20 年来我一直在错误地阅读文档。
Chris 在那里提出了很多好的观点,你应该采纳它们,但真正的问题,正如 immibis 所说,是你错误地使用了 CreateProcess
API。如果它包含任何空格,您完成它的方式需要引用 exepath
。
因此,在解决 Chris 提出的所有问题后,请执行以下操作:
CreateProcessW (exePath, NULL,
NULL, NULL, TRUE,
creation_flags,
NULL, NULL, &startupInfo, &processInformation);
即只需交换第一个和第二个参数(并且可能使用更具描述性的名称 flags
,就像我在这里所做的那样)。
您可以在第二个参数中传递您可能需要的任何命令行参数,如果这成为一项要求的话。还有,read the docs.
编辑(找回我的代表:)
此外,正如 Chris 所说,exepath
在这里需要是一个宽字符串,所以我去掉了你的(冗余)强制转换,它实际上会产生编译器错误(C++)或警告(C)(所以,一个警告,猜测,因为你的 post 被标记为 C,谢谢@Barmak)。
无论如何,如果您现在没有得到一个,那么 exepath
实际上必须已经 成为 一个宽字符串,所以一切都很好。如果没有,那么你显然需要解决这个问题,但我想这整个问题只是你 post 中的一个错字,因为你显然 did 让你的代码工作以便报告您正在观察的行为。
我运行下面的C代码创建了一个进程。 exe文件位于C:\Program Files\Exes\Start\process1.exe
CreateProcessW(NULL, (char*) exePath,
NULL, NULL, TRUE,
flags,
NULL, NULL, &startupInfo, &processInformation);
现在有些计算机随机将这个名为 Program 的文件位于 C:\Program 中,这会导致创建过程失败并出现错误:
%1 is not a valid Win32 application.
除了重命名文件之外,是否还有解决此问题的方法,因为有几十个 Windows 虚拟机在其上执行此 C 代码。此错误随机发生在几台机器上。
这段代码是如何编译的? CreateProcessW 的第二个参数定义为 LPWSTR
,这意味着它应该只接受宽字符串。
下一个问题:由于强制转换,无法确定 exePath
的来源。这是重要的原因是第二个参数被定义为 LPWSTR
,而不是 LPCWSTR
(即 const 宽字符串),原因如下:CreateProcessW
可以写入缓冲区。
然后是第三个问题 - 您的 exe 路径中有一个 space。当作为第二个参数 (lpCommandLine) 传递时,CreateProcess
有一些愚蠢的逻辑来猜测 exe 名称结束的位置和命令行的开始位置。这需要引用编码命令行的 exe 路径部分。
当您拥有 exe 的完整路径且没有参数时,最简单/最安全的做法是将其作为 lpApplicationName 参数传递。这是一个 const 参数,它避免了任何潜在的未定义行为,如果您的命令行源是常量字符串文字等,则可能导致这种行为。并且只是用作要执行的 exe 的路径,因此没有(也不能)有任何引号要求。
CreateProcess(exePath,NULL,...);
旁白:使用 CreateProcess
的两个参数基本上可以让您将启动的应用程序的 argv[0] 设置为您想要的任何值。因此,您可以 运行 来自特定路径/exe 名称的应用程序,但使 argv[0] 指向其他路径或 exe 名称。
要将参数传递给 exe,而不是传递完整(引号括起)路径,您可以像这样简单地做一些事情:
WCHAR cmdLine[] = TEXT("console1.exe --version");
CreateProcessW(exePath,cmdLine,...);
编辑 感谢 Paul Sanders 和其他指出未引用的 exe 路径的评论,这也让我完全打破了我原来的答案,这个答案在我没有意识到的情况下解决了. 感谢 RbMm 发现了我的答案,感谢 eryksun 向我展示了近 20 年来我一直在错误地阅读文档。
Chris 在那里提出了很多好的观点,你应该采纳它们,但真正的问题,正如 immibis 所说,是你错误地使用了 CreateProcess
API。如果它包含任何空格,您完成它的方式需要引用 exepath
。
因此,在解决 Chris 提出的所有问题后,请执行以下操作:
CreateProcessW (exePath, NULL,
NULL, NULL, TRUE,
creation_flags,
NULL, NULL, &startupInfo, &processInformation);
即只需交换第一个和第二个参数(并且可能使用更具描述性的名称 flags
,就像我在这里所做的那样)。
您可以在第二个参数中传递您可能需要的任何命令行参数,如果这成为一项要求的话。还有,read the docs.
编辑(找回我的代表:)
此外,正如 Chris 所说,exepath
在这里需要是一个宽字符串,所以我去掉了你的(冗余)强制转换,它实际上会产生编译器错误(C++)或警告(C)(所以,一个警告,猜测,因为你的 post 被标记为 C,谢谢@Barmak)。
无论如何,如果您现在没有得到一个,那么 exepath
实际上必须已经 成为 一个宽字符串,所以一切都很好。如果没有,那么你显然需要解决这个问题,但我想这整个问题只是你 post 中的一个错字,因为你显然 did 让你的代码工作以便报告您正在观察的行为。