C++ Winapi CreateProcess 问题与命令行

Pro*_*oid 1 c++ parameters null winapi createprocess

我正在使用CreateProcess这种方式:

resultCreate = CreateProcess(Command, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

//"Command" contains the executable file to execute
//"CommandLine" contains the parameters to pass to that executable
Run Code Online (Sandbox Code Playgroud)

参数如下:

Param1: "C:\Users\myuser\Desktop\file.dll"
Param2: "file" (module name)
Param3: " " (blank)
Run Code Online (Sandbox Code Playgroud)

所以完整的命令行字符串将是:

"C:\Users\myuser\Desktop\file.dll" file " "
Run Code Online (Sandbox Code Playgroud)

CreateProcess 成功运行可执行文件并应用前两个参数,但是当到达第三个时,它会抛出错误

The specified process could not be found.
Function " " could not be called, due to " " doesn't exist in the DLL "(null)"
Run Code Online (Sandbox Code Playgroud)

如何正确传递所需的参数?

Rem*_*eau 5

当同时使用lpApplicationName和 时lpCommandLine,您需要将可执行路径作为lpCommandLine值的第一个参数包含在内,即使您在lpApplication值中指定了可执行路径。该lpCommandLine原样传递是衍生的进程,大多数RTLS(尤其是基于C-RTLS,但其他人也一样)预计第一个命令行参数是可执行文件的路径,因为这是命令行控制台是如何运作的。这甚至在CreateProcess()文档中提到:

如果两个lpApplicationNamelpCommandLine是非NULL,则空终止字符串指向lpApplicationName指定执行的模块,并且通过指向空终止字符串lpCommandLine指定命令行。新进程可用于GetCommandLine检索整个命令行。用 C 编写的控制台进程可以使用 argc 和 argv 参数来解析命令行。因为 argv[0] 是模块名称,C 程序员通常在命令行中重复模块名称作为第一个标记。

这也涵盖在 MSDN 支持中:

信息:了解 CreateProcess 和命令行参数

创建 32 位进程时 CreateProcess() 的行为

情况1:

如果传递了 ApplicationName 参数并且 CommandLine 参数为 NULL,则 ApplicationName 参数也用作 CommandLine。这并不意味着您可以在 ApplicationName 字符串中传递额外的命令行参数。例如,以下调用将失败并显示“找不到文件”错误:

CreateProcess( "c:\\MyApp.exe Param1 Param2", NULL, ... )
Run Code Online (Sandbox Code Playgroud)

案例2:

另一方面,如果 CommandLine 参数为非 NULL 且 ApplicationName 参数为 NULL,则 API 会尝试从 CommandLine 参数中提取应用程序名称。

案例3:

当您将有效的字符串指针传递给 ApplicationName 和 CommandLine 参数时,CreateProcess() 函数的灵活性(以及可能的混淆点)就会出现。这允许您指定要执行的应用程序以及传递给应用程序的完整命令行。人们可能认为传递给创建的应用程序的命令行是 ApplicationName 和 CommandLine 参数的组合,但事实并非如此。因此,由 CreateProcess 创建的进程可以接收其 .exe 名称以外的值作为其“argv[0]”参数。以下是产生这种“异常”行为的调用 CreateProcess 的示例:

CreateProcess( "c:\\MyApp.exe", "Param1 Param2 Param3", ...)
Run Code Online (Sandbox Code Playgroud)

MyApp 的参数如下:

argv[0] == "Param1"
argv[1] == "Param2"
argv[2] == "Param3"
Run Code Online (Sandbox Code Playgroud)

注意:ANSI 规范要求 argv[0] 应等于应用程序名称,但 CreateProcess 为调用应用程序提供了覆盖 32 位进程的此规则的灵活性。

第 3 种情况适用于您的情况。

使用类似这样的东西:

std::string Command = "<exe path>";
std::string CommandLine = "\"" + Command + "\" <parameters>";

// std::string::c_str() returns a const pointer. The first parameter
// of CreateProcessA() is const, but the second parameter must be a
// non-const pointer to writable memory, because CreateProcessW() can
// modify the data...
//
resultCreate = CreateProcessA(Command.c_str(), &CommandLine[0], ...);
Run Code Online (Sandbox Code Playgroud)

std::wstring Command = L"<exe path>";
std::wstring CommandLine = L"\"" + Command + L"\" <parameters>";

// std::wstring::c_str() returns a const pointer. The first parameter
// of CreateProcessW() is const, but the second parameter must be a
// non-const pointer to writable memory, because CreateProcessW() can
// modify the data...
//
resultCreate = CreateProcessW(Command.c_str(), &CommandLine[0], ...);
Run Code Online (Sandbox Code Playgroud)

或者,省略lpApplicationName并将完整的命令行指定为lpCommandLine

std::string CommandLine = "\"<exe path>\" <parameters>";
resultCreate = CreateProcessA(NULL, &CommandLine[0], ...);
Run Code Online (Sandbox Code Playgroud)

std::wstring CommandLine = L"\"<exe path>\" <parameters>";
resultCreate = CreateProcessW(NULL, &CommandLine[0], ...);
Run Code Online (Sandbox Code Playgroud)