Question

Vous cherchez un exemple qui :

  1. Lance un EXE
  2. Attend la fin de l'EXE.
  3. Ferme correctement toutes les poignées lorsque l'exécutable se termine.
Était-ce utile?

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().

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 :

  1. diviser l'attente en un fil de discussion séparé, ou
  2. 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
  3. 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top