tags:

views:

12221

answers:

6

Looking for an example that:

  1. Launches an EXE
  2. Waits for the EXE to finish.
  3. Properly closes all the handles when the executable finishes.
+7  A: 

There is an example at http://msdn.microsoft.com/en-us/library/ms682512(VS.85).aspx

Just replace the argv[1] with your constant or variable containing the program.

crashmstr
+9  A: 

Something like this:

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);
}
1800 INFORMATION
Wimmel
Why use :: to specify global namespace on WaitForSingleObject but not on the other API calls?
divideandconquer.se
That would be force of habit
1800 INFORMATION
You should close the thread handle immediately, if you're not going to use it. Not a big problem here, though.
MSalters
Why should I close it immediately? It doesn't save any resources
1800 INFORMATION
You're missing a ; after the WaitForSingleObject() call.
Keith G
+3  A: 

if your exe happens to be a console app, you might be interested in reading the stdout and stderr -- for that, I'll humbly refer you to this example:

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

It's a bit of a mouthful of code, but I've used variations of this code to spawn and read.

Mike Ellery
+2  A: 

On a semi-related note, if you want to start a process that has more privileges than your current process (say, launching an admin app, which requires Administrator rights, from the main app running as a normal user), you can't do so using CreateProcess() on Vista since it won't trigger the UAC dialog (assuming it is enabled). The UAC dialog is triggered when using ShellExecute(), though.

Andy
+1  A: 

If you application is a Windows GUI application then using the code below to do the waiting is not ideal as messages for your application will not be getting processing. To the user it will look like your application has hung.

WaitForSingleObject(&processInfo.hProcess, INFINITE)

Something like the untested code below might be better as it will keep processing the windows message queue and your application will remain responsive:

//-- 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);
      }
    }
  }
}
jussij
No, that's not how you combine a message loop and a wait. Use MsgWaitForMultipleObjects( QS_ALLEVENTS ); [http://msdn.microsoft.com/en-us/library/ms684242(VS.85).aspx]
MSalters
+2  A: 

Bear in mind that using WaitForSingleObject can get you into trouble in this scenario. The following is snipped from a tip on my website:

The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (*HWND_BROADCAST* or *HWND_TOPMOST*), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.

If you have absolute control over the spawned application, then there are measures you can take, such as using SendMessageTimeout rather than SendMessage (e.g. for DDE initiations, if anybody is still using that). But there are situations which cause implicit SendMessage broadcasts over which you have no control, such as using the SetSysColors API for instance.

The only safe ways round this are (a) split off the Wait into a separate thread, or (b) use a timeout on the Wait and use PeekMessage in your Wait loop to ensure that you pump messages, or (c) use the MsgWaitForMultipleObjects API.

Bob Moore