Search code examples
c++winapipidcreateprocess

How to get the process ID when starting Mozilla Firefox?


The task of getting the PID of the process that I'm starting, CreateProcess() ProcessInformation.dwProcessId does a great job of this, but in my case, the process that I start opens the child processes and then closes, and I need to get all the PIDs that creates the process I am opening.

I found this code, it receives the child PIDs but they do not match the final Firefox window, what am I doing wrong

Source: CreateProcess returns handle different than launched Chrome.exe

Update 1 After Drake Wu - MSFT comment, I used the following code

int test(const wchar_t* programPath) {
    HANDLE Job = CreateJobObject(nullptr, nullptr);
    if (!Job) {
        std::cout << "CreateJobObject, error " << GetLastError() << std::endl;
        return 0;
    }

    HANDLE IOPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1);
    if (!IOPort) {
        std::cout << "CreateIoCompletionPort, error " << GetLastError() << std::endl;
        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() << std::endl;
        return 0;
    }

    PROCESS_INFORMATION ProcessInformation;
    STARTUPINFOW StartupInfo = { sizeof(StartupInfo) };
    LPWSTR szCmdline = const_cast<LPWSTR>(programPath);

    if (!CreateProcessW(
        programPath,
        nullptr,
        nullptr,
        nullptr,
        FALSE,
        CREATE_SUSPENDED,
        nullptr,
        nullptr,
        &StartupInfo,
        &ProcessInformation))
    {
        std::cout << "CreateProcess, error " << GetLastError() << std::endl;
        return 0;
    }
    std::cout << "PID: " << ProcessInformation.dwProcessId << std::endl;
    if (!AssignProcessToJobObject(Job, ProcessInformation.hProcess)) {
        std::cout << "Assign, error " << GetLastError() << std::endl;
        return 0;
    }

    ResumeThread(ProcessInformation.hThread);
    CloseHandle(ProcessInformation.hThread);
    CloseHandle(ProcessInformation.hProcess);

    DWORD CompletionCode;
    ULONG_PTR CompletionKey;
    LPOVERLAPPED Overlapped;
    while (GetQueuedCompletionStatus(IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE))
    {
        switch (CompletionCode)
        {
        case JOB_OBJECT_MSG_NEW_PROCESS:
            std::cout << "New PID: " << (int)Overlapped << std::endl;
            break;
        case JOB_OBJECT_MSG_EXIT_PROCESS:
            std::cout << "Exit PID: " << (int)Overlapped << std::endl;
            break;
        case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
            std::cout << "JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO" << std::endl;
            break;
        default:
            break;
        }
        if (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
            break;
    }
    std::cout << "All done" << std::endl;
}

and I got the following results:

standart Firefox

test(L"C:\\Program Files\\Mozilla Firefox\\firefox.exe");

portable edition Firefox

test(L"D:\\FirefoxPortable\\FirefoxPortable.exe");

As before, PIDs are incorrectly returned. In the case of the portable version, the process hangs on the while loop, in the case of the standard version of firefox, GetQueuedCompletionStatus() returns JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO. Why am I getting the wrong result?

Update 2

I ran Visual Studio as an administrator and, but on standard startup everything displays correctly


Solution

  • I tested that the process of Firefox is not new and exit in order(the pid obtained by CreateProcess will exit), and your code will not receive the new Firefox process if there is any new process created later.

    You could use swtich-case statement, the following sample work for me:

    int openProgram(const wchar_t* programPath) {
        HANDLE Job = CreateJobObject(nullptr, nullptr);
        if (!Job) {
            std::cout << "CreateJobObject, error " << GetLastError() << std::endl;
            return 0;
        }
    
        HANDLE IOPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 1);
        if (!IOPort) {
            std::cout << "CreateIoCompletionPort, error " << GetLastError() << std::endl;
            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() << std::endl;
            return 0;
        }
    
        PROCESS_INFORMATION ProcessInformation;
        STARTUPINFO StartupInfo = { sizeof(StartupInfo) };
        LPTSTR szCmdline = _tcsdup(programPath);
        if (!CreateProcessW(
            nullptr,
            szCmdline,
            nullptr,
            nullptr,
            FALSE,
            CREATE_SUSPENDED,
            nullptr,
            nullptr,
            &StartupInfo,
            &ProcessInformation))
        {
            std::cout << "CreateProcess, error " << GetLastError() << std::endl;
            return 0;
        }
        std::cout << "PID: " << ProcessInformation.dwProcessId << std::endl;
        if (!AssignProcessToJobObject(Job, ProcessInformation.hProcess)) {
            std::cout << "Assign, error " << GetLastError() << std::endl;
            return 0;
        }
    
        ResumeThread(ProcessInformation.hThread);
        CloseHandle(ProcessInformation.hThread);
        CloseHandle(ProcessInformation.hProcess);
    
        DWORD CompletionCode;
        ULONG_PTR CompletionKey;
        LPOVERLAPPED Overlapped;
        while (GetQueuedCompletionStatus(IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE))
        {
            switch (CompletionCode)
            {
            case JOB_OBJECT_MSG_NEW_PROCESS:
                std::cout << "New PID: " << (int)Overlapped << std::endl;
                break;
            case JOB_OBJECT_MSG_EXIT_PROCESS:
                std::cout << "Exit PID: " << (int)Overlapped << std::endl;
                break;
            case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO:
                std::cout << "JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO" << std::endl;
                break;
            default:
                break;
            }
            if (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)
                break;
        }
        std::cout << "All done" << std::endl;
    }
    

    Result:

    enter image description here