views:

42

answers:

1

I have a thread that creates COM objects that require a single threaded apartment.

Originally, this thread's main function put it into a WaitForMultipleObjects loop. Evidently this is a problem, because it prevents the COM message pump from doing it's job.

I replaced this with MsgWaitForMultipleObjects as a solution, but now I'm running into an issue: MsgWaitForMultipleObjects sometimes (often) returns WAIT_FAILED, but doesn't set an error.

The code handles a WAIT_FAILED return value by just continuing and trying to call MsgWaitForMultipleObjects again. The call to MsgWaitForMultipleObjects may return WAIT_FAILED a few times (the most I've seen is 9), but then it suddenly works with no problem.

The code is written so that this could potentially go into an infinite loop if the function were returning WAIT_FAILED for a valid reason. I know I should fix this, but at the moment I'm considering it a 'work around' because the MsgWaitForMultipleObjects call will eventually succeed.

This code is being tested on Windows 7, Vista, and XP (all 32-bit, Windows 7 32- and 64-bit).

Does anyone have any idea why this is happening?

The relevant code:

bool run = true;
while (run)
{
    DWORD ret = MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, 
        QS_ALLINPUT);

    switch (ret)
    {
        case WAIT_OBJECT_0:
        {
            ResetEvent(events[0]);
            ProcessWorkQueue();
            break;
        }

        case WAIT_OBJECT_0 + 1:
        {
            run = false;
            break;
        }

        case WAIT_OBJECT_0 + 2:
        {
            MSG msg;
            while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                DispatchMessage(&msg);
            break;
        }

        case WAIT_FAILED:
        {
            Logger::Output(L"Wait failed in Notify::Run(), error is " 
                + boost::lexical_cast<std::wstring>(GetLastError()));
        }
    }
}

Example output would be:

Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
Wait failed in Notify::Run(), error is 0
// At this point, the wait succeeds

I believe the WAIT_FAILED return value is only occurring after the wait has been broken by a message.

+2  A: 

That shouldn't be happening, and I sure can't explain exactly why it does. I do have a few pointers, however.

First, you're not calling TranslateMessage() before DispatchMessage() in your message pump. That's bad juju, and you don't want bad juju anywhere near MsgWaitForMultipleObjects().

You also might want to try explicitly calling MsgWaitForMultipleObjectsEx(), just in case it doesn't exhibit the same problem:

DWORD ret = MsgWaitForMultipleObjectsEx(2, events, INFINITE, QS_ALLINPUT, 0);

Finally, it might be far-fetched but consider what's happening after MsgWaitForMultipleObjects() returns and before GetLastError() is called. Disregarding the assignment to ret, I see an implicit call to std::wstring's constructor.

Can you guarantee std::wstring's constructor doesn't have some side-effect that clears the thread's last error code? I sure can't, so I'd move the call to GetLastError() into an good, old-fashioned, atomic assignment to a DWORD variable in the first line of the case statement.

Frédéric Hamidi
Thanks for the response. I omitted `TanslateMessage` because it shouldn't be handling any key messages, but I added it just in case. `GetLastError` is guaranteed to be called before the `std::wstring` is constructed, but I pre-stored the value anyway. Neither solved the problem, but I'll try using the Ex version.
dauphic
Sorry, as a side note, I know `GetLastError` isn't being set because I can sometimes see it has a value that means 'file not found,' and I know where this is getting set. Other times, it returns 0.
dauphic
The `Ex` version solved it, thank you.
dauphic