Comment appeler ::CreateProcess en c++ pour lancer un exécutable Windows ?
Question
Vous cherchez un exemple qui :
- Lance un EXE
- Attend la fin de l'EXE.
- Ferme correctement toutes les poignées lorsque l'exécutable se termine.
La solution
Quelque chose comme ça:
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);
}
Autres conseils
Il y a un exemple sur http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx
Remplacez simplement le argv[1]
avec votre constante ou variable contenant le programme.
#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 );
}
Si votre application est une application Windows GUI, utiliser le code ci-dessous pour effectuer l'attente n'est pas idéal car les messages de votre application ne seront pas traités.Pour l’utilisateur, votre application aura l’impression d’être bloquée.
WaitForSingleObject(&processInfo.hProcess, INFINITE)
Quelque chose comme le non testé Le code ci-dessous pourrait être meilleur car il continuera à traiter la file d'attente des messages Windows et votre application restera réactive :
//-- 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);
}
}
}
}
si votre exe est une application console, vous pourriez être intéressé par la lecture de la sortie standard et de la sortie standard -- pour cela, je vous renvoie humblement à cet exemple :
http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351
C'est un peu une bouchée de code, mais j'ai utilisé des variantes de ce code pour générer et lire.
Sur une note semi-liée, si vous souhaitez démarrer un processus qui a plus de privilèges que votre processus actuel (par exemple, lancer une application d'administration, qui nécessite des droits d'administrateur, à partir de l'application principale exécutée en tant qu'utilisateur normal), vous ne pouvez pas faites-le en utilisant CreateProcess() sur Vista car cela ne déclenchera pas la boîte de dialogue UAC (en supposant qu'elle soit activée).La boîte de dialogue UAC est cependant déclenchée lors de l'utilisation de ShellExecute().
C'est peut-être le plus complet ?http://goffconcepts.com/techarticles/development/cpp/createprocess.html
Gardez à l'esprit qu'en utilisant WaitForSingleObject
peut vous causer des ennuis dans ce scénario.Ce qui suit est extrait d'une astuce sur mon site Web :
Le problème survient parce que votre application a une fenêtre mais ne pompe pas de messages.Si l'application générée appelle SendMessage avec l'une des cibles de diffusion (HWND_BROADCAST ou HWND_TOPMOST), alors SendMessage ne reviendra pas à la nouvelle application tant que toutes les applications n'auront pas traité le message - mais votre application ne peut pas gérer le message car elle ne pompe pas de messages....donc la nouvelle application se bloque, donc votre attente n'aboutit jamais....IMPASSE.
Si vous avez un contrôle absolu sur l'application générée, vous pouvez prendre certaines mesures, comme utiliser SendMessageTimeout plutôt que SendMessage (par ex.pour les initiations DDE, si quelqu'un l'utilise encore).Mais il existe des situations qui provoquent des diffusions SendMessage implicites sur lesquelles vous n'avez aucun contrôle, comme l'utilisation de l'API SetSysColors par exemple.
Les seuls moyens sûrs de contourner ce problème sont :
- diviser l'attente en un fil de discussion séparé, ou
- utilisez un délai d'attente sur l'attente et utilisez PeekMessage dans votre boucle d'attente pour vous assurer que vous pompez des messages, ou
- Utilisez le
MsgWaitForMultipleObjects
API.
Voici un nouvel exemple qui fonctionne sur Windows 10.Lorsque vous utilisez le SDK Windows10, vous devez utiliser CreateProcessW à la place.Cet exemple est commenté et, espérons-le, explicite.
#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