How do I call ::CreateProcess in c++ to launch a Windows executable?
寻找一个示例:
启动一个EXE
等待EXE完成。
可执行文件完成后,正确关闭所有句柄。
类似这样的东西:
1 2 3 4 5 6 7 8
| 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);
} |
http://msdn.microsoft.com/zh-cn/library/ms682512(VS.85).aspx
上有一个示例
只需用包含程序的常量或变量替换argv[1]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #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]\
", 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).\
", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
} |
如果您的应用程序是Windows GUI应用程序,则使用下面的代码进行等待不是理想的选择,因为将不会处理应用程序的消息。对于用户来说,您的应用程序似乎已挂起。
1
| WaitForSingleObject(&processInfo.hProcess, INFINITE) |
类似于下面未经测试的代码可能会更好,因为它将继续处理Windows消息队列,并且您的应用程序将保持响应状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| //-- 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);
}
}
}
} |
如果您的exe恰好是一个控制台应用程序,则您可能有兴趣阅读stdout和stderr,为此,我将很谦虚地向您推荐以下示例:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
这是一小段代码,但是我使用了这些代码的变体来生成和读取。
在半相关说明中,如果您要启动一个具有比当前进程更多特权的进程(例如,从以普通用户身份运行的主应用程序启动需要管理员权限的管理应用程序),无法在Vista上使用CreateProcess()这样做,因为它不会触发UAC对话框(假设已启用)。但是,在使用ShellExecute()时会触发UAC对话框。
这是在Windows 10上运行的新示例。使用Windows10 sdk时,必须改为使用CreateProcessW。此示例已注释,希望可以自我解释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
| #ifdef _WIN32
#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <cstdlib>
#include <string>
#include
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).\
", 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).\
", 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).\
", 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).\
");
return 0;
}
// Terminate Process
if( !TerminateProcess(pi.hProcess,1))
{
printf("ExitProcess failed (%d).\
", GetLastError() );
return 0;
}
// Wait until child process exits.
if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
{
printf("Wait for exit process failed(%d).\
", GetLastError() );
return 0;
}
// Close process and thread handles.
if( !CloseHandle( pi.hProcess ))
{
printf("Cannot close process handle(%d).\
", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
if( !CloseHandle( pi.hThread ))
{
printf("Cannot close thread handle (%d).\
", GetLastError() );
return 0;
}
else
{
pi.hProcess = NULL;
}
return 1;
}
};//class process
#endif //win32 |
也许这是最完整的?
http://goffconcepts.com/techarticles/development/cpp/createprocess.html
请记住,在这种情况下使用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_BROADCAST or 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.
如果您对衍生的应用程序有绝对的控制权,那么可以采取一些措施,例如使用SendMessageTimeout而不是SendMessage(例如,对于DDE启动,如果有人仍在使用它)。但是有些情况会导致无法控制的隐式SendMessage广播,例如使用SetSysColors API。
解决此问题的唯一安全方法是:
将"等待"分为一个单独的线程,或者
在Wait上使用超时,并在Wait循环中使用PeekMessage,以确保您泵送消息,或者
使用MsgWaitForMultipleObjects API。
|