如何在 C++ 中调用 ::CreateProcess 来启动 Windows 可执行文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I call ::CreateProcess in c++ to launch a Windows executable?
提问by jm.
Looking for an example that:
寻找一个例子:
- Launches an EXE
- Waits for the EXE to finish.
- Properly closes all the handles when the executable finishes.
- 启动一个 EXE
- 等待 EXE 完成。
- 可执行文件完成时正确关闭所有句柄。
回答by 1800 INFORMATION
Something like this:
像这样的东西:
STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;
if (CreateProcess(path, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
回答by crashmstr
There is an example at http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
有一个例子在 http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
Just replace the argv[1]
with your constant or variable containing the program.
只需将 替换为argv[1]
包含程序的常量或变量。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
回答by jussij
If you application is a Windows GUI application then using the code below to do the waiting is not ideal as messages for your application will not be getting processing. To the user it will look like your application has hung.
如果您的应用程序是 Windows GUI 应用程序,那么使用下面的代码进行等待并不理想,因为您的应用程序的消息将不会得到处理。对于用户来说,它看起来就像您的应用程序已挂起。
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Something like the untestedcode below might be better as it will keep processing the windows message queue and your application will remain responsive:
像下面未经测试的代码可能会更好,因为它会继续处理 Windows 消息队列,并且您的应用程序将保持响应:
//-- wait for the process to finish
while (true)
{
//-- see if the task has terminated
DWORD dwExitCode = WaitForSingleObject(ProcessInfo.hProcess, 0);
if ( (dwExitCode == WAIT_FAILED )
|| (dwExitCode == WAIT_OBJECT_0 )
|| (dwExitCode == WAIT_ABANDONED) )
{
DWORD dwExitCode;
//-- get the process exit code
GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
//-- the task has ended so close the handle
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
//-- save the exit code
lExitCode = dwExitCode;
return;
}
else
{
//-- see if there are any message that need to be processed
while (PeekMessage(&message.msg, 0, 0, 0, PM_NOREMOVE))
{
if (message.msg.message == WM_QUIT)
{
return;
}
//-- process the message queue
if (GetMessage(&message.msg, 0, 0, 0))
{
//-- process the message
TranslateMessage(&pMessage->msg);
DispatchMessage(&pMessage->msg);
}
}
}
}
回答by Mike Ellery
if your exe happens to be a console app, you might be interested in reading the stdout and stderr -- for that, I'll humbly refer you to this example:
如果您的 exe 恰好是一个控制台应用程序,您可能有兴趣阅读 stdout 和 stderr——为此,我会谦虚地向您推荐这个示例:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
It's a bit of a mouthful of code, but I've used variations of this code to spawn and read.
代码有点长,但我使用了这段代码的变体来生成和阅读。
回答by Andy
On a semi-related note, if you want to start a process that has more privileges than your current process (say, launching an admin app, which requires Administrator rights, from the main app running as a normal user), you can't do so using CreateProcess() on Vista since it won't trigger the UAC dialog (assuming it is enabled). The UAC dialog is triggered when using ShellExecute(), though.
在半相关说明中,如果您想启动一个比当前进程拥有更多权限的进程(例如,从以普通用户身份运行的主应用程序启动需要管理员权限的管理应用程序),则不能在 Vista 上使用 CreateProcess() 这样做,因为它不会触发 UAC 对话框(假设它已启用)。但是,在使用 ShellExecute() 时会触发 UAC 对话框。
回答by pcunite
Perhaps this is the most complete? http://goffconcepts.com/techarticles/development/cpp/createprocess.html
也许这是最完整的? http://goffconcepts.com/techarticles/development/cpp/createprocess.html
回答by Blue7
Here is a new example that works on windows 10. When using the windows10 sdk you have to use CreateProcessW instead. This example is commented and hopefully self explanatory.
这是一个适用于 Windows 10 的新示例。使用 windows10 sdk 时,您必须改用 CreateProcessW。这个例子有注释,希望能自我解释。
#ifdef _WIN32
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include <algorithm>
class process
{
public:
static PROCESS_INFORMATION launchProcess(std::string app, std::string arg)
{
// Prepare handles.
STARTUPINFO si;
PROCESS_INFORMATION pi; // The function returns this
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
//Prepare CreateProcess args
std::wstring app_w(app.length(), L' '); // Make room for characters
std::copy(app.begin(), app.end(), app_w.begin()); // Copy string to wstring.
std::wstring arg_w(arg.length(), L' '); // Make room for characters
std::copy(arg.begin(), arg.end(), arg_w.begin()); // Copy string to wstring.
std::wstring input = app_w + L" " + arg_w;
wchar_t* arg_concat = const_cast<wchar_t*>( input.c_str() );
const wchar_t* app_const = app_w.c_str();
// Start the child process.
if( !CreateProcessW(
app_const, // app path
arg_concat, // Command line (needs to include app path as first argument. args seperated by whitepace)
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
throw std::exception("Could not create child process");
}
else
{
std::cout << "[ ] Successfully launched child process" << std::endl;
}
// Return process handle
return pi;
}
static bool checkIfProcessIsActive(PROCESS_INFORMATION pi)
{
// Check if handle is closed
if ( pi.hProcess == NULL )
{
printf( "Process handle is closed or invalid (%d).\n", GetLastError());
return FALSE;
}
// If handle open, check if process is active
DWORD lpExitCode = 0;
if( GetExitCodeProcess(pi.hProcess, &lpExitCode) == 0)
{
printf( "Cannot return exit code (%d).\n", GetLastError() );
throw std::exception("Cannot return exit code");
}
else
{
if (lpExitCode == STILL_ACTIVE)
{
return TRUE;
}
else
{
return FALSE;
}
}
}
static bool stopProcess( PROCESS_INFORMATION &pi)
{
// Check if handle is invalid or has allready been closed
if ( pi.hProcess == NULL )
{
printf( "Process handle invalid. Possibly allready been closed (%d).\n");
return 0;
}
// Terminate Process
if( !TerminateProcess(pi.hProcess,1))
{
printf( "ExitProcess failed (%d).\n", GetLastError() );
return 0;
}
// Wait until child process exits.
if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
{
printf( "Wait for exit process failed(%d).\n", GetLastError() );
return 0;
}
// Close process and thread handles.
if( !CloseHandle( pi.hProcess ))
{
printf( "Cannot close process handle(%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
if( !CloseHandle( pi.hThread ))
{
printf( "Cannot close thread handle (%d).\n", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
return 1;
}
};//class process
#endif //win32
回答by Bob Moore
Bear in mind that using WaitForSingleObject
can get you into trouble in this scenario. The following is snipped from a tip on my website:
请记住,WaitForSingleObject
在这种情况下,使用可能会给您带来麻烦。以下内容摘自我网站上的提示:
The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (HWND_BROADCASTor HWND_TOPMOST), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.
出现问题是因为您的应用程序有一个窗口,但没有发送消息。如果生成的应用程序使用广播目标之一(HWND_BROADCAST或HWND_TOPMOST)调用 SendMessage ,则在所有应用程序都处理完消息之前,SendMessage 不会返回到新应用程序 - 但您的应用程序无法处理该消息,因为它不是' t 发送消息......所以新的应用程序锁定,所以你的等待永远不会成功......死锁。
If you have absolute control over the spawned application, then there are measures you can take, such as using SendMessageTimeout rather than SendMessage (e.g. for DDE initiations, if anybody is still using that). But there are situations which cause implicit SendMessage broadcasts over which you have no control, such as using the SetSysColors API for instance.
如果您对生成的应用程序拥有绝对控制权,那么您可以采取一些措施,例如使用 SendMessageTimeout 而不是 SendMessage(例如,对于 DDE 启动,如果有人仍在使用它)。但是有些情况会导致您无法控制的隐式 SendMessage 广播,例如使用 SetSysColors API。
The only safe ways round this are:
唯一安全的方法是:
- split off the Wait into a separate thread, or
- use a timeout on the Wait and use PeekMessage in your Wait loop to ensure that you pump messages, or
- use the
MsgWaitForMultipleObjects
API.
- 将 Wait 拆分为一个单独的线程,或
- 在等待上使用超时并在等待循环中使用 PeekMessage 以确保您发送消息,或
- 使用
MsgWaitForMultipleObjects
API。