命令行的 C++ Winapi CreateProcess 问题
C++ Winapi CreateProcess issue with command line
我这样使用 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
参数如下:
Param1: "C:\Users\myuser\Desktop\file.dll"
Param2: "file" (module name)
Param3: " " (blank)
所以完整的命令行字符串是:
"C:\Users\myuser\Desktop\file.dll" file " "
CreateProcess
成功运行可执行文件并应用前两个参数,但是当到达第三个时,它抛出错误
The specified process could not be found.
Function " " could not be called, due to " " doesn't exist in the DLL "(null)"
如何正确传递所需的参数?
当同时使用 lpApplicationName
和 lpCommandLine
时,您需要将可执行文件路径作为 lpCommandLine
值的第一个参数,即使您在lpApplication
值。 lpCommandLine
按原样传递给生成的进程,大多数 RTL(尤其是基于 C 的 RTL,但也包括其他 RTL)期望第一个命令行参数是可执行路径,因为这就是命令行的方式控制台操作。 CreateProcess()
documentation:
中甚至提到了这一点
If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine
to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
这也包含在 MSDN 支持中:
INFO: Understanding CreateProcess and Command-line Arguments
Behavior of CreateProcess() When Creating a 32-bit Process
Case 1:
If the ApplicationName parameter is passed and the CommandLine parameter is NULL, then the ApplicationName parameter is also used as the CommandLine. This does not mean that you can pass additional command-line parameters in ApplicationName string. For example, the following call will fail with a "File Not Found" error:
CreateProcess( "c:\MyApp.exe Param1 Param2", NULL, ... )
Case 2:
On the other hand, if the CommandLine parameter is non-NULL and the ApplicationName parameter is NULL, then the API attempts to extract the application name from the CommandLine parameter.
Case 3:
The flexibility of the CreateProcess() function (and a possible point of confusion) arises when you pass a valid string pointer to both the ApplicationName and CommandLine parameters. This allows you to specify the application to be executed as well as the complete command line that is passed to the application. One might assume that the command line passed to the created application is a composite of the ApplicationName and CommandLine parameters, but this is not the case. As a result, a process created by CreateProcess can receive a value other than its .exe name as its "argv[0]" parameter. The following is an example of a call to CreateProcess that produces this "abnormal" behavior:
CreateProcess( "c:\MyApp.exe", "Param1 Param2 Param3", ...)
MyApp's arguments will be as follow:
argv[0] == "Param1"
argv[1] == "Param2"
argv[2] == "Param3"
NOTE: ANSI specifications require that argv[0] should be equal to the application name, but CreateProcess gives the calling application the flexibility to override this rule for 32-bit processes.
案例 #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], ...);
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], ...);
或者,省略 lpApplicationName
并将完整命令行指定为仅 lpCommandLine
:
std::string CommandLine = "\"<exe path>\" <parameters>";
resultCreate = CreateProcessA(NULL, &CommandLine[0], ...);
std::wstring CommandLine = L"\"<exe path>\" <parameters>";
resultCreate = CreateProcessW(NULL, &CommandLine[0], ...);
我这样使用 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
参数如下:
Param1: "C:\Users\myuser\Desktop\file.dll"
Param2: "file" (module name)
Param3: " " (blank)
所以完整的命令行字符串是:
"C:\Users\myuser\Desktop\file.dll" file " "
CreateProcess
成功运行可执行文件并应用前两个参数,但是当到达第三个时,它抛出错误
The specified process could not be found.
Function " " could not be called, due to " " doesn't exist in the DLL "(null)"
如何正确传递所需的参数?
当同时使用 lpApplicationName
和 lpCommandLine
时,您需要将可执行文件路径作为 lpCommandLine
值的第一个参数,即使您在lpApplication
值。 lpCommandLine
按原样传递给生成的进程,大多数 RTL(尤其是基于 C 的 RTL,但也包括其他 RTL)期望第一个命令行参数是可执行路径,因为这就是命令行的方式控制台操作。 CreateProcess()
documentation:
If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use
GetCommandLine
to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
这也包含在 MSDN 支持中:
INFO: Understanding CreateProcess and Command-line Arguments
Behavior of CreateProcess() When Creating a 32-bit Process
Case 1:
If the ApplicationName parameter is passed and the CommandLine parameter is NULL, then the ApplicationName parameter is also used as the CommandLine. This does not mean that you can pass additional command-line parameters in ApplicationName string. For example, the following call will fail with a "File Not Found" error:
CreateProcess( "c:\MyApp.exe Param1 Param2", NULL, ... )
Case 2:
On the other hand, if the CommandLine parameter is non-NULL and the ApplicationName parameter is NULL, then the API attempts to extract the application name from the CommandLine parameter.
Case 3:
The flexibility of the CreateProcess() function (and a possible point of confusion) arises when you pass a valid string pointer to both the ApplicationName and CommandLine parameters. This allows you to specify the application to be executed as well as the complete command line that is passed to the application. One might assume that the command line passed to the created application is a composite of the ApplicationName and CommandLine parameters, but this is not the case. As a result, a process created by CreateProcess can receive a value other than its .exe name as its "argv[0]" parameter. The following is an example of a call to CreateProcess that produces this "abnormal" behavior:
CreateProcess( "c:\MyApp.exe", "Param1 Param2 Param3", ...)
MyApp's arguments will be as follow:
argv[0] == "Param1" argv[1] == "Param2" argv[2] == "Param3"
NOTE: ANSI specifications require that argv[0] should be equal to the application name, but CreateProcess gives the calling application the flexibility to override this rule for 32-bit processes.
案例 #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], ...);
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], ...);
或者,省略 lpApplicationName
并将完整命令行指定为仅 lpCommandLine
:
std::string CommandLine = "\"<exe path>\" <parameters>";
resultCreate = CreateProcessA(NULL, &CommandLine[0], ...);
std::wstring CommandLine = L"\"<exe path>\" <parameters>";
resultCreate = CreateProcessW(NULL, &CommandLine[0], ...);