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

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

How do I call ::CreateProcess in c++ to launch a Windows executable?

寻找一个示例:

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

  • 类似这样的东西:

    1
    2
    3
    4
    5
    6
    7
    8
    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);
    }

    http://msdn.microsoft.com/zh-cn/library/ms682512(VS.85).aspx

    上有一个示例

    只需用包含程序的常量或变量替换argv[1]

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #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]\
    "
    , 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).\
    "
    , GetLastError() );
            return;
        }

        // Wait until child process exits.
        WaitForSingleObject( pi.hProcess, INFINITE );

        // Close process and thread handles.
        CloseHandle( pi.hProcess );
        CloseHandle( pi.hThread );
    }

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

    1
    WaitForSingleObject(&processInfo.hProcess, INFINITE)

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    //-- 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);
          }
        }
      }
    }


    如果您的exe恰好是一个控制台应用程序,则您可能有兴趣阅读stdout和stderr,为此,我将很谦虚地向您推荐以下示例:

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

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


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


    这是在Windows 10上运行的新示例。使用Windows10 sdk时,必须改为使用CreateProcessW。此示例已注释,希望可以自我解释。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    #ifdef _WIN32
    #include <Windows.h>
    #include <iostream>
    #include <stdio.h>
    #include <tchar.h>
    #include <cstdlib>
    #include <string>
    #include

    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).\
    "
    , 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).\
    "
    , 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).\
    "
    , 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).\
    "
    );
                    return 0;
                }

            // Terminate Process
                if( !TerminateProcess(pi.hProcess,1))
                {
                    printf("ExitProcess failed (%d).\
    "
    , GetLastError() );
                    return 0;
                }

            // Wait until child process exits.
                if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
                {
                    printf("Wait for exit process failed(%d).\
    "
    , GetLastError() );
                    return 0;
                }

            // Close process and thread handles.
                if( !CloseHandle( pi.hProcess ))
                {
                    printf("Cannot close process handle(%d).\
    "
    , GetLastError() );
                    return 0;
                }
                else
                {
                    pi.hProcess = NULL;
                }

                if( !CloseHandle( pi.hThread ))
                {
                    printf("Cannot close thread handle (%d).\
    "
    , GetLastError() );
                    return 0;
                }
                else
                {
                     pi.hProcess = NULL;
                }
                return 1;
        }
    };//class process
    #endif //win32

    也许这是最完整的?
    http://goffconcepts.com/techarticles/development/cpp/createprocess.html


    请记住,在这种情况下使用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,以确保您泵送消息,或者
  • 使用MsgWaitForMultipleObjects API。

  • 推荐阅读