Why those two different behaviors with WaitForSingleObject function in CPP

前端 未结 2 1798
别那么骄傲
别那么骄傲 2021-01-23 01:57

I have the following code sample:

#include 
#include 
#include 

using namespace std;

void main()
{
    SHELLEXEC         


        
相关标签:
2条回答
  • 2021-01-23 02:34

    I tried your code on Windows 10, and SysInternals Process Monitor shows the following:

    As you can see, calc.exe spawns a new process and then ends, thus satisfying the wait. That is why you see your output immediately. This second process is the actual calculator process. In my case, it is located at this path:

    C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1612.3341.0_x64__8wekyb3d8bbwe\Calculator.exe
    
    0 讨论(0)
  • 2021-01-23 02:34

    As marcinj explained, calc.exe is launching a second process and then exiting immediately. You are waiting on a HANDLE to the calc.exe process, so that wait is satisfied when calc.exe exits.

    If you want to wait until all (grand)children processes have ended, you need to wrap the calc.exe process inside of a Job object.

    Call CreateJobObject(), pass the HANDLE of the calc.exe process to AssignProcessToJobObject(), and then wait for notifications from the job object (simply waiting on the job itself will not work, see How do I wait until all processes in a job have exited? for an explanation why).

    Any new processes that calc.exe launches, and that they launch, and so on, will automatically be added to the same job (unless they explicitly request not to be added to the job, via the CREATE_BREAKAWAY_FROM_JOB flag of CreateProcess(), but let's not worry about that in this example). When the job notifies you that all processes have ended, you can stop waiting for further notifications.

    For example:

    #include <windows.h>
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main()
    {
        HANDLE Job = CreateJobObject(NULL, NULL);
        if (!Job)
        {
            std::cout << "CreateJobObject, error " << GetLastError() << "\n";
            return 0;
        }
    
        HANDLE IOPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
        if (!IOPort)
        {
            std::cout << "CreateIoCompletionPort, error " << GetLastError() << "\n";
            CloseHandle(Job);
            return 0;
        }
    
        JOBOBJECT_ASSOCIATE_COMPLETION_PORT Port;
        Port.CompletionKey = Job;
        Port.CompletionPort = IOPort;
        if (!SetInformationJobObject(Job, JobObjectAssociateCompletionPortInformation, &Port, sizeof(Port)))
        {
            std::cout << "SetInformation, error " << GetLastError() << "\n";
            CloseHandle(IOPort);
            CloseHandle(Job);
            return 0;
        }
    
        STARTUPINFO si = { sizeof(STARTUPINFO) };
        PROCESS_INFORMATION pi = {};
    
        WCHAR cmdline[] = L"calc.exe";
        if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
        {
            std::cout << "CreateProcess, error " << GetLastError() << "\n";
            CloseHandle(IOPort);
            CloseHandle(Job);
            return 0;
        }
    
        if (!AssignProcessToJobObject(Job, pi.hProcess))
        {
            std::cout << "Assign, error " << GetLastError() << "\n";
            TerminateProcess(pi.hProcess, 0);
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
            CloseHandle(IOPort);
            CloseHandle(Job);
            return 0;
        }
    
        ResumeThread(pi.hThread);
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    
        DWORD CompletionCode;
        ULONG_PTR CompletionKey;
        LPOVERLAPPED Overlapped;
    
        while (GetQueuedCompletionStatus(IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE))
        {
            if ((reinterpret_cast<HANDLE>(CompletionKey) == Job) &&
                (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO))
            {
                break;
            }
        }
    
        CloseHandle(IOPort);
        CloseHandle(Job);
    
        std::cout << "hi! Im done!";
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题