Of course there's a horrible flaw in both CoWaitForMultipleHandles and
MsgWaitforMultipleObjectsEx: if you do a 'wait all' and there's a
message pump involved, it'll only return when all the handles are
signaled *and* you've got at least one message waiting for you in the
call.
Ahhh, the memories... here's a blast from the past (in unmanaged C++, of course)
// This function mimics the up-and-coming CoWaitForMultipleHandles
function but returns the DWORD result of
// WAIT_OBJECT_0 for handle zero, etc..., or WAIT_ABANDONED_0 for
abandoned handles, or
// WAIT_TIME if timeout expires
DWORD NiceWaitForMultipleHandles(
BOOL fAll, // Wait options, FALSE waits for any, TRUE waits
for all messages...
DWORD dwTimeout, // Timeout period, in milliseconds.
ULONG cHandles, // Number of elements in the pHandles array.
LPHANDLE pHandles) // Array of Win32 handles.
{
DWORD dwResult = WAIT_FAILED;
DWORD dwTimeLeft = dwTimeout;
static const DWORD dwOneSlice = 100; // do it in 100 millisecond chunks...
while (1)
{
if ( ! fAll)
{
dwResult = MsgWaitForMultipleObjects(cHandles, // number
of handles in the handle array
pHandles, //
pointer to the object-handle array
fAll, // any or all flag
dwTimeout, //
time-out interval in milliseconds
QS_ALLINPUT); // type
of input events to wait for (any input)
if (dwResult == WAIT_OBJECT_0 + cHandles)
{
// We have input messages, dispatch them!
MSG msg;
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// When we service messages, let's not count that against
the timeout specified so loop back...
continue;
}
}
else {
// MsgWaitForMultipleObjects is broken if ALL is chosen.
Deal with it the hard way...
// if we are not doing an instant check
if (0 != dwTimeLeft)
{
dwTimeout = dwOneSlice;
if (INFINITE != dwTimeLeft)
{
if (dwTimeLeft < dwTimeout)
dwTimeout = dwTimeLeft;
dwTimeLeft -= dwTimeout;
}
}
else
dwTimeout = dwTimeLeft;
dwResult = WaitForMultipleObjects(cHandles, // number of
handles in the handle array
pHandles, // pointer
to the object-handle array
fAll, // any or all flag
dwTimeout); // time-out
interval in milliseconds
}
if ((WAIT_OBJECT_0 <= dwResult) && (dwResult < (WAIT_OBJECT_0 +
cHandles)))
{
// Success on one/all handles
break;
}
else if ((WAIT_ABANDONED_0 <= dwResult) && (dwResult <
(WAIT_ABANDONED_0 + cHandles)))
{
// One or more handles abandoned
break;
}
else if (dwResult == WAIT_TIMEOUT)
{
// If we were waiting for ANY, or used up the whole timeout,
// we know it is a "hard" timeout...
if ( ! fAll || (0 == dwTimeLeft))
break;
MSG msg;
// Service the queue without yeilding...
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Note, we could adjust the dwTimeLeft to account for the
time spent dispatching
// messages, but in most cases we don't really care...
}
else break; // something I don't expect
}
return dwResult;
}
--
"You hide yourself with sanctimony, I hide myself with narcissism."
--T-Bone Burnett
Marc C. Brooks
http://musingmarc.blogspot.com
===================================
This list is hosted by DevelopMentorĀ® http://www.develop.com
View archives and manage your subscription(s) at http://discuss.develop.com