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 让你的代码工作以便报告您正在观察的行为。