Como chamo ::CreateProcess em c++ para iniciar um executável do Windows?
Pergunta
Procurando um exemplo que:
- Inicia um EXE
- Aguarda a conclusão do EXE.
- Fecha corretamente todos os identificadores quando o executável termina.
Solução
Algo assim:
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);
}
Outras dicas
Há um exemplo em http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
Basta substituir o argv[1]
com sua constante ou variável que contém o programa.
#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 );
}
Se seu aplicativo for um aplicativo GUI do Windows, usar o código abaixo para fazer a espera não é ideal, pois as mensagens para seu aplicativo não serão processadas.Para o usuário, parecerá que seu aplicativo travou.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Algo como o não testado o código abaixo pode ser melhor, pois continuará processando a fila de mensagens do Windows e seu aplicativo permanecerá responsivo:
//-- 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);
}
}
}
}
se o seu exe for um aplicativo de console, você pode estar interessado em ler o stdout e o stderr - para isso, humildemente encaminharei você para este exemplo:
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
É um pouco complicado de código, mas usei variações desse código para gerar e ler.
Em uma nota semi-relacionada, se você deseja iniciar um processo que tenha mais privilégios do que o seu processo atual (por exemplo, iniciar um aplicativo administrativo, que requer direitos de administrador, no aplicativo principal executado como usuário normal), você não pode faça isso usando CreateProcess() no Vista, pois isso não acionará a caixa de diálogo do UAC (supondo que esteja ativado).A caixa de diálogo do UAC é acionada ao usar ShellExecute().
Talvez este seja o mais completo?http://goffconcepts.com/techarticles/development/cpp/createprocess.html
Tenha em mente que usar WaitForSingleObject
pode causar problemas neste cenário.O seguinte foi extraído de uma dica no meu site:
O problema surge porque seu aplicativo possui uma janela, mas não está bombeando mensagens.Se o aplicativo gerado invocar SendMessage com um dos destinos de transmissão (HWND_BROADCAST ou HWND_TOPMOST), então SendMessage não retornará ao novo aplicativo até que todos os aplicativos tenham manipulado a mensagem - mas seu aplicativo não pode manipular a mensagem porque não está bombeando mensagens....então o novo aplicativo trava, para que sua espera nunca seja bem-sucedida....IMPASSE.
Se você tiver controle absoluto sobre o aplicativo gerado, existem medidas que você pode tomar, como usar SendMessageTimeout em vez de SendMessage (por exemplo,para iniciações DDE, se alguém ainda estiver usando isso).Mas há situações que causam transmissões SendMessage implícitas sobre as quais você não tem controle, como usar a API SetSysColors, por exemplo.
As únicas maneiras seguras de contornar isso são:
- dividir o Wait em um thread separado ou
- use um tempo limite em Wait e use PeekMessage em seu loop Wait para garantir que você bombeie mensagens, ou
- use o
MsgWaitForMultipleObjects
API.
Aqui está um novo exemplo que funciona no Windows 10.Ao usar o SDK do Windows10, você deve usar CreateProcessW.Este exemplo é comentado e esperançosamente autoexplicativo.
#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