Andrii Matiiash
Andrii Matiiash

Reputation: 568

How to transfer the duplicated handle to the child process?

I used DuplicateHandle for sharing a kernel object to the child process, I need to transfer handle of this object to that process, how to do this?

int main() {
    STARTUPINFO cif;
    ZeroMemory(&cif, sizeof(STARTUPINFO));
    PROCESS_INFORMATION pi;
    CreateProcess("sp.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, 
    &cif, &pi);

    HANDLE Semaphore = CreateSemaphore(NULL, 0, 1, NULL);

    DuplicateHandle(GetCurrentProcess(), Semaphore, pi.hProcess, NULL, 
    DUPLICATE_SAME_ACCESS, FALSE, 0);

    WaitForSingleObject(Semaphore, INFINITE);
    cout << "Test3: access granted";

    CloseHandle(pi.hProcess);
    CloseHandle(Semaphore);
}

Upvotes: 2

Views: 2505

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598384

If you call DuplicateHandle() in the parent process, you must specify the child process as the target process, accept the newly duplicated handle, and then use an IPC mechanism of your choosing to send the duplicated handle to the child process, eg:

int main() {
    STARTUPINFO cif;
    ZeroMemory(&cif, sizeof(cif));
    cif.cb = sizeof(cif);

    PROCESS_INFORMATION pi;
    ZeroMemory(&pi, sizeof(pi));

    if (!CreateProcess("sp.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, 
    &cif, &pi))
    {
        cout << "Test3: CreateProcess failed";
    }
    else
    {
        HANDLE hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
        if (!hSemaphore)
        {
            cout << "Test3: CreateSemaphore failed";
        }
        else
        {
            HANDLE hDupSemaphore = NULL;

            if (!DuplicateHandle(GetCurrentProcess(), hSemaphore, pi.hProcess, &hDupSemaphore, DUPLICATE_SAME_ACCESS, FALSE, 0))
            {
                cout << "Test3: DuplicateHandle failed";
            }
            else
            {
                // send hDupSemaphore to child process via IPC ...

                if (WaitForSingleObject(hSemaphore, INFINITE) == WAIT_OBJECT_0)
                {
                    cout << "Test3: access granted";
                    ReleaseSemaphore(hSemaphore, 1, NULL);
                }
                else
                    cout << "Test3: WaitForSingleObject failed";

                CloseHandle(hDupSemaphore);
            }

            CloseHandle(hSemaphore);
        }

        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    }

    return 0;
}

Otherwise, have the child process be the one to call DuplicateHandle() instead. You can pass the parent's process ID and desired handle value to the child process via the command-line or other IPC mechanism, and then have the child process open the process ID with OpenProcess() and call DuplicateHandle() when it is ready to duplicate the source handle.

Otherwise, you can create the desired handle as inheritable (or use SetHandleInformation() to mark it as inheritable after it is created), and then call CreateProcess() with the bInheritHandles parameter set to TRUE. Note that this will inherit ALL inheritable handles, unless you programmatically specify which handles the child process can inherit using STARTUPINFOEX instead of STARTUPINFO (Vista and later only).

On the other hand, you are trying to share a Semaphore, which can have a name assigned to it, so you should just create the semaphore with a name assigned and then pass that name to the child process so it can create/open its own semaphore handle using the same name. This is documented behavior, and is the preferred way to share kernel objects across process boundaries:

If the function succeeds, the return value is a handle to the semaphore object. If the named semaphore object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.

Upvotes: 5

Related Questions