¿Cómo puedo llamar a ::CreateProcess en c++ para lanzar un ejecutable de Windows?

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

  •  09-06-2019
  •  | 
  •  

Pregunta

Buscando un ejemplo que:

  1. Lanza un EXE
  2. Espera a que el EXE a fin.
  3. Correctamente cierra todos los identificadores cuando el archivo ejecutable acabados.
¿Fue útil?

Solución

Algo como esto:

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

Otros consejos

Hay un ejemplo en http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx

Basta con sustituir el argv[1] con su constante o variable que contiene el 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 );
}

Si usted es una aplicación de Windows GUI de la aplicación, a continuación, utilizando el siguiente código para hacer la espera no es ideal como los mensajes que para su aplicación no se está procesando.Para el usuario se verá como en su aplicación se ha colgado.

WaitForSingleObject(&processInfo.hProcess, INFINITE)

Algo así como el no probado código de abajo podría ser mejor, ya que se mantendrá el procesamiento de la cola de mensajes de windows y su aplicación responde:

//-- 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 el archivo exe pasa a ser una aplicación de consola, que podría estar interesado en la lectura de la stdout y stderr-por eso, humildemente voy a referir a este ejemplo:

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

Es un poco de un bocado de código, pero he utilizado las variaciones de este código para generar y leer.

En un semi-nota relacionada, si desea iniciar un proceso que tiene más privilegios que en su proceso actual (es decir, el lanzamiento de un administrador de la aplicación, que requiere derechos de Administrador, desde la aplicación principal que se ejecuta como un usuario normal), no puede hacerlo utilizando CreateProcess() en la Vista ya que no va a desencadenar el cuadro de diálogo de UAC (suponiendo que está habilitada).El UAC de diálogo se activa cuando se utiliza ShellExecute(), aunque.

Tenga en cuenta que el uso de WaitForSingleObject puede meter en problemas en este escenario.El siguiente es cortada de un consejo en mi sitio web:

El problema surge debido a que su aplicación tiene una ventana, pero no es el bombeo de los mensajes.Si la aplicación generada invoca SendMessage con uno de los de difusión de los objetivos (HWND_BROADCAST o HWND_TOPMOST), entonces el SendMessage no regresará a la nueva aplicación hasta que todas las aplicaciones han manejado el mensaje -, pero su aplicación no puede controlar el mensaje porque no es de bombeo de mensajes....así que la nueva aplicación se bloquea, por lo que el tiempo de espera nunca tiene éxito....INTERBLOQUEO.

Si usted tiene el control absoluto sobre la aplicación generada, entonces hay medidas que usted puede tomar, tales como el uso de SendMessageTimeout en lugar de SendMessage (por ejemplo,por DDE iniciaciones, si alguien sigue usando ese).Pero hay situaciones que causan implícito SendMessage emisiones sobre las que no tienes control, tales como el uso de la API SetSysColors por ejemplo.

La única maneras seguras de esta ronda son:

  1. se separó de la Espera en un hilo separado, o
  2. el uso de un tiempo de espera en la Espera y el uso PeekMessage en su bucle de Espera para asegurarse de que la bomba de mensajes, o
  3. el uso de la MsgWaitForMultipleObjects La API.

Aquí es un nuevo ejemplo de que funciona en windows 10.Cuando se utiliza el windows10 sdk tienes que utilizar CreateProcessW lugar.Este ejemplo es comentada y esperemos que el auto explicativo.

#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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top