未调用 ReadFileEx() 完成例程

ReadFileEx() completion routine not called

我正在编写 class (PipeReader) 来处理 Windows 上的命名管道。 class 使用异步 IO 从管道读取。

到目前为止,我一直在没有事件循环的线程中使用 class,我不得不等待 IO 完成使用 SleepEx() 并且它起作用了。

现在我有第二个带有事件循环的线程和 PipeReader class 的第二个实例,但是从未调用第二个实例的完成例程。

致电CreateFile()

handle = CreateFile(fullServerName,
                         GENERIC_READ | GENERIC_WRITE,
                         0,
                         NULL,
                         OPEN_EXISTING,
                         FILE_FLAG_OVERLAPPED,
                         NULL);

致电ReadFileEx()

BOOL status = ReadFileEx(m_handle, ptr, readSize, &m_overlapped, &PipeReader::readFileCompleted);

在线程 1 中等待的有效代码:

while (SleepEx(msecs < 0 ? INFINITE : msecs, TRUE) == WAIT_IO_COMPLETION) {
    if (m_readFinished) // Set to true in the completion routine
        return true;

    msecs = // decrease msecs by the amount elapsed
    if (!msecs)
        break;
}

永远不会调用完成例程的线程 2 中的事件循环代码:

forever()
{
    forever()
    {
        bool haveMessage = PeekMessage(&msg, 0, 0, 0, PM_REMOVE);

        if (haveMessage)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            break; //No message leave loop
        }
    }


    HANDLE handles[1];
    handles[0] = m_hwnd;
    DWORD result = MsgWaitForMultipleObjectsEx(1, handles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE|MWMO_INPUTAVAILABLE);

}

编辑:

如果我将 MsgWaitForMultipleObjectsEx() 的呼叫替换为 :

WaitForSingleObjectEx(m_hwnd, INFINITE, TRUE);

还是不行。但是,如果我在事件循环中使用 SleepEx() 它会起作用。

这是因为m_hwnd不是内核句柄。因此 WaitForSingleObjectEx 失败并显示 WAIT_FAILEDGetLastError returns ERROR_INVALID_HANDLE - 结果线程永远不会进入可警告等待状态并且 APC 永远不会执行。你需要有另一个消息循环,例如:

  for ( ; ; ) {

    MSG msg;

    switch(MsgWaitForMultipleObjectsEx(0, 0, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE| MWMO_ALERTABLE)) 
    {

    case STATUS_WAIT_0 : 

      while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {

        switch(msg.message) {
        case WM_QUIT: 
          return;
        default: 
          if (!IsDialogMessage(hwnd, &msg))
          {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
      }
    }
    case WAIT_IO_COMPLETION :
    // apc called
    continue;
    default: return ;
    }