AFAIK, GetQueuedCompletionStatusEx
return FALSE
when User APC got executed. And GetLastError()
return WAIT_IO_COMPLETION
. Thus, it will never dequeue any completion packets when User APC got executed.
This is my code that work perfectly for me.
if (!::GetQueuedCompletionStatusEx(m_hIoCompletionPort, CompletionPackets, uCompletionPacketsToDequeue, &uCompletionPacketsRemoved, dwTimeToSleep, TRUE))
{
DWORD dwError = ::GetLastError();
if (dwError == WAIT_IO_COMPLETION)
{
// User Terminate Instance.
ATLASSERT(m_blTerminating);
hrResult = S_OK;
break;
}
else if (dwError != ERROR_TIMEOUT)
{
hrResult = HRESULT_FROM_WIN32(dwError);
break;
}
// One or more Timer has elapsed.
ATLASSERT(m_Timers.GetCount() != 0);
uCompletionPacketsRemoved = 0;
}