Search code examples
winapipipeportnamedcompletion

How to reregister for IO Completion ports for a handle


I have a Windows named pipe that I create with CreateFile (the server side was created using CreateNamedPipe). I use IO completion ports to read/write data asynchronously on both ends.

I need to send these handles to other processes after they've been opened. I tried to call CloseHandle on the handle returned from CreateIoCompletionPort, and then in the other process call CreateIoCompletionPort again. However it always fails and GetLastError returns 87 (ERROR_INVALID_PARAMETER).

I can also reproduce this in just one process, see below. Note there are no outstanding reads/write to the object before I send it.

std::wstring pipe_name = L"\\\\.\\pipe\\test.12345";
HANDLE server = CreateNamedPipeW(
    pipe_name.c_str(),
    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
    PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
    1,
    4096,
    4096,
    10000,
    NULL);
SECURITY_ATTRIBUTES security_attributes = {
    sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
HANDLE client = CreateFileW(
    pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE,
    0,
    &security_attributes,
    OPEN_EXISTING,
    SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED,
    NULL);
ULONG_PTR key = 1;
HANDLE comp_port = CreateIoCompletionPort(client, NULL, key, 1);

BOOL b1 = CloseHandle(comp_port);

comp_port = CreateIoCompletionPort(client, NULL, key, 1);
if (comp_port == NULL) {
  int last_err = GetLastError();
}

Solution

  • Referring to the documentation for CreateIoCompletionPort:

    A handle can be associated with only one I/O completion port, and after the association is made, the handle remains associated with that I/O completion port until it [the handle] is closed.

    [...] The I/O completion port handle and every file handle associated with that particular I/O completion port are known as references to the I/O completion port. The I/O completion port is released when there are no more references to it.

    In other words, closing the I/O completion port handle doesn't achieve anything. The I/O completion port still exists and is permanently associated with the pipe handle. What you're attempting simply isn't possible; you will need to rearchitecture.

    Note also:

    It is best not to share a file handle associated with an I/O completion port by using either handle inheritance or a call to the DuplicateHandle function. Operations performed with such duplicate handles generate completion notifications. Careful consideration is advised.