Windows 실행 파일을 실행하기 위해 C++에서 ::CreateProcess를 어떻게 호출합니까?
문제
다음과 같은 예를 찾고 있습니다.
- EXE를 실행합니다
- EXE가 완료될 때까지 기다립니다.
- 실행 파일이 완료되면 모든 핸들을 올바르게 닫습니다.
해결책
이 같은:
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/en-us/library/ms682512(VS.85).aspx
그냥 교체하세요 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 );
}
응용 프로그램이 Windows GUI 응용 프로그램인 경우 아래 코드를 사용하여 대기하는 것은 응용 프로그램에 대한 메시지가 처리되지 않으므로 이상적이지 않습니다.사용자에게는 애플리케이션이 중단된 것처럼 보입니다.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
다음과 같은 것 테스트되지 않은 아래 코드는 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);
}
}
}
}
exe가 콘솔 앱인 경우 stdout 및 stderr을 읽는 데 관심이 있을 수 있습니다. 이에 대해 겸허하게 다음 예를 참조하겠습니다.
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
약간의 코드이지만 생성하고 읽기 위해 이 코드의 변형을 사용했습니다.
준 관련 참고 사항에서 현재 프로세스보다 더 많은 권한이 있는 프로세스를 시작하려는 경우(예: 일반 사용자로 실행되는 기본 앱에서 관리자 권한이 필요한 관리 앱 실행) 다음을 수행할 수 없습니다. UAC 대화 상자가 실행되지 않으므로 Vista에서는 CreateProcess()를 사용하여 수행하십시오(활성화되어 있다고 가정).그러나 ShellExecute()를 사용하면 UAC 대화 상자가 트리거됩니다.
사용한다는 점을 명심하세요. WaitForSingleObject
이 시나리오에서는 문제가 발생할 수 있습니다.다음은 내 웹사이트의 팁에서 발췌한 것입니다.
애플리케이션에 창이 있지만 메시지를 펌핑하지 않기 때문에 문제가 발생합니다.생성된 애플리케이션이 브로드캐스트 대상 중 하나를 사용하여 SendMessage를 호출하는 경우(HWND_BROADCAST 또는 HWND_TOPMOST), SendMessage는 모든 애플리케이션이 메시지를 처리할 때까지 새 애플리케이션으로 반환되지 않습니다. 그러나 앱은 메시지를 펌핑하지 않기 때문에 메시지를 처리할 수 없습니다....그래서 새로운 앱이 작동을 멈추게 되고, 여러분의 기다림은 절대 성공하지 못할 것입니다....이중 자물쇠.
생성된 애플리케이션을 절대적으로 제어할 수 있는 경우 SendMessage 대신 SendMessageTimeout을 사용하는 등 취할 수 있는 조치가 있습니다(예:DDE 시작의 경우(아직 누군가 이를 사용하고 있는 경우)그러나 예를 들어 SetSysColors API를 사용하는 것과 같이 제어할 수 없는 암시적 SendMessage 브로드캐스트를 유발하는 상황이 있습니다.
이 문제를 해결하는 유일한 안전한 방법은 다음과 같습니다.
- Wait를 별도의 스레드로 분할하거나
- Wait에서 시간 제한을 사용하고 Wait 루프에서 PeekMessage를 사용하여 메시지를 펌핑하는지 확인하거나
- 사용
MsgWaitForMultipleObjects
API.
다음은 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