如何在C ++中调用:: CreateProcess来启动Windows可执行文件?

时间:2020-03-05 18:47:17  来源:igfitidea点击:

寻找一个例子:

  • 启动一个EXE
  • 等待EXE完成。
  • 可执行文件完成后,正确关闭所有句柄。

解决方案

回答

在http://msdn.microsoft.com/zh-cn/library/ms682512(VS.85).aspx中有一个示例

只需用包含程序的常量或者变量替换" argv [1]"即可。

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

回答

像这样的东西:

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

回答

如果exe恰好是一个控制台应用程序,那么我们可能会对阅读stdout和stderr感兴趣-为此,我将谦虚地向我们推荐此示例:

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

这是一小段代码,但是我使用了这些代码的变体来生成和读取。

回答

在半相关的注释上,如果我们要启动一个具有比当前进程更多特权的进程(例如,从以普通用户身份运行的主应用程序启动需要管理员权限的管理应用程序),则不能在Vista上使用CreateProcess()这样做,因为它不会触发UAC对话框(假设已启用)。但是,在使用ShellExecute()时会触发UAC对话框。

回答

如果应用程序是Windows GUI应用程序,则使用下面的代码进行等待不是理想的选择,因为将不会处理应用程序的消息。对于用户来说,应用程序似乎已挂起。

WaitForSingleObject(&processInfo.hProcess, INFINITE)

类似于下面未经测试的代码可能会更好,因为它将继续处理Windows消息队列,并且应用程序将保持响应状态:

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

回答

请记住,在这种情况下使用WaitForSingleObject会使我们陷入麻烦。以下是我网站上的提示摘录:

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.

如果我们对衍生的应用程序有绝对的控制权,那么可以采取一些措施,例如使用SendMessageTimeout而不是SendMessage(例如,对于DDE启动,如果有人仍在使用它)。但是在某些情况下会导致无法控制的隐式SendMessage广播,例如使用SetSysColors API。

解决此问题的唯一安全方法是:

  • 将"等待"分为一个单独的线程,或者
  • 在Wait上使用超时,并在Wait循环中使用PeekMessage,以确保我们泵送消息,或者
  • 使用MsgWaitForMultipleObjectsAPI。