Wie rufe ich ::CreateProcess in C++ auf, um eine ausführbare Windows-Datei zu starten?

StackOverflow https://stackoverflow.com/questions/42531

  •  09-06-2019
  •  | 
  •  

Frage

Suchen Sie nach einem Beispiel, das:

  1. Startet eine EXE-Datei
  2. Wartet auf den Abschluss der EXE-Datei.
  3. Schließt alle Handles ordnungsgemäß, wenn die ausführbare Datei beendet ist.
War es hilfreich?

Lösung

Etwas wie das:

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);
}

Andere Tipps

Ein Beispiel gibt es unter http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx

Ersetzen Sie einfach die argv[1] mit Ihrer Konstante oder Variablen, die das Programm enthält.

#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 );
}

Wenn es sich bei Ihrer Anwendung um eine Windows-GUI-Anwendung handelt, ist die Verwendung des folgenden Codes zum Warten nicht ideal, da Nachrichten für Ihre Anwendung nicht verarbeitet werden.Für den Benutzer sieht es so aus, als ob Ihre Anwendung hängen geblieben wäre.

WaitForSingleObject(&processInfo.hProcess, INFINITE)

So etwas wie das ungetestet Der folgende Code ist möglicherweise besser, da er weiterhin die Windows-Nachrichtenwarteschlange verarbeitet und Ihre Anwendung weiterhin reagiert:

//-- 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);
      }
    }
  }
}

Wenn es sich bei Ihrer Exe-Datei zufällig um eine Konsolen-App handelt, könnten Sie daran interessiert sein, stdout und stderr zu lesen – dafür verweise ich Sie demütig auf dieses Beispiel:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q190351

Es ist ein bisschen ein bisschen Code, aber ich habe Variationen dieses Codes zum Erzeugen und Lesen verwendet.

Eine halbwegs verwandte Anmerkung: Wenn Sie einen Prozess starten möchten, der über mehr Berechtigungen als Ihr aktueller Prozess verfügt (z. B. das Starten einer Admin-App, für die Administratorrechte erforderlich sind, von der Haupt-App aus, die als normaler Benutzer ausgeführt wird), ist dies nicht möglich Verwenden Sie dazu CreateProcess() unter Vista, da dadurch das UAC-Dialogfeld nicht ausgelöst wird (vorausgesetzt, es ist aktiviert).Der UAC-Dialog wird jedoch ausgelöst, wenn ShellExecute() verwendet wird.

Denken Sie daran, dass mit WaitForSingleObject kann Sie in diesem Szenario in Schwierigkeiten bringen.Das Folgende ist ein Auszug aus einem Tipp auf meiner Website:

Das Problem entsteht, weil Ihre Anwendung ein Fenster hat, aber keine Nachrichten weiterleitet.Wenn die erzeugte Anwendung SendMessage mit einem der Broadcast-Ziele aufruft (HWND_BROADCAST oder HWND_TOPMOST), dann kehrt SendMessage erst dann zur neuen Anwendung zurück, wenn alle Anwendungen die Nachricht verarbeitet haben – Ihre App kann die Nachricht jedoch nicht verarbeiten, da sie keine Nachrichten pumpt....Daher stürzt die neue App ab und Ihr Warten hat keinen Erfolg....SACKGASSE.

Wenn Sie die absolute Kontrolle über die erzeugte Anwendung haben, können Sie Maßnahmen ergreifen, z. B. die Verwendung von SendMessageTimeout anstelle von SendMessage (z. B.für DDE-Initiierungen, falls das noch jemand nutzt).Es gibt jedoch Situationen, die implizite SendMessage-Broadcasts verursachen, über die Sie keine Kontrolle haben, wie beispielsweise die Verwendung der SetSysColors-API.

Die einzig sicheren Möglichkeiten, dies zu umgehen, sind:

  1. das Wait in einen separaten Thread abspalten, oder
  2. Verwenden Sie eine Zeitüberschreitung für das Warten und verwenden Sie PeekMessage in Ihrer Warteschleife, um sicherzustellen, dass Sie Nachrichten pumpen, oder
  3. Benutze die MsgWaitForMultipleObjects API.

Hier ist ein neues Beispiel, das unter Windows 10 funktioniert.Wenn Sie das Windows10-SDK verwenden, müssen Sie stattdessen CreateProcessW verwenden.Dieses Beispiel ist kommentiert und hoffentlich selbsterklärend.

#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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top