如何为句柄重新注册 IO 完成端口

How to reregister for IO Completion ports for a handle

我有一个使用 CreateFile 创建的 Windows 命名管道(服务器端是使用 CreateNamedPipe 创建的)。我使用 IO 完成端口在两端异步地 read/write 数据。

我需要在打开这些句柄后将它们发送给其他进程。我尝试在从 CreateIoCompletionPort 返回的句柄上调用 CloseHandle,然后在另一个进程中再次调用 CreateIoCompletionPort。但是它总是失败并且 GetLastError returns 87 (ERROR_INVALID_PARAMETER).

我也可以在一个过程中重现这一点,见下文。请注意,在我发送对象之前没有未完成的 reads/write。

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();
}

CreateIoCompletionPort 的文档表明您无法完成您想要完成的任务。与 I/O 完成端口关联的所有句柄都引用该端口,只要一个端口仍然打开,该端口就会保持活动状态:

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. Therefore, all of these handles must be properly closed to release the I/O completion port and its associated system resources. After these conditions are satisfied, close the I/O completion port handle by calling the CloseHandle function.

如果您使用 CreateFile 创建一个与 I/O 完成端口无关的新句柄,然后使用 DuplicateHandle 将其传递给其他进程,它应该可以工作。或者直接调用其他进程中的CreateFile

参考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.

换句话说,关闭 I/O 完成端口句柄没有任何作用。 I/O 完成端口仍然存在并且与管道句柄永久关联。您所尝试的根本不可能;您将需要重新架构。

另请注意:

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.