From: Kevin Puetz PuetzKevinA@JohnDeere.com
Only one message at a time should be dispatched; if that message results in the handles becoming completed (or an APC queued, if COWAIT_ALERTABLE), the loop should immediately stop and return that outcome.
This replaces the arbitrary "100 message" limit; RPC/DDE messages get priority over WM_PAINT, and as long as they cause the handles to signal there's no need to reach an empty message queue. This also fixes a potential deadlock where MsgWaitForMultipleObjectsEx would wait for new messages when there were actually still un-examined messages left in the queue because the 100 message limit had been previously hit. --- dlls/combase/combase.c | 12 ++++++------ dlls/ole32/tests/compobj.c | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 9d6a16b54c0..fc8414b52d3 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -2098,7 +2098,7 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle
if (message_loop) { - DWORD start_time, wait_flags = 0; + DWORD start_time, wait_flags = MWMO_INPUTAVAILABLE; struct tlsdata *tlsdata;
if (FAILED(hr = com_get_tlsdata(&tlsdata))) @@ -2125,7 +2125,6 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle if (check_apc) { res = WaitForMultipleObjectsEx(handle_count, handles, !!(flags & COWAIT_WAITALL), 0, TRUE); - check_apc = FALSE; }
if (res == WAIT_TIMEOUT) @@ -2135,7 +2134,6 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle
if (res == WAIT_OBJECT_0 + handle_count) /* messages available */ { - int msg_count = 0; MSG msg;
/* call message filter */ @@ -2165,10 +2163,9 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle } }
- /* Some apps (e.g. Visio 2010) don't handle WM_PAINT properly and loop forever, - * so after processing 100 messages we go back to checking the wait handles */ - while (msg_count++ < 100 && com_peek_message(apt, &msg)) + if(com_peek_message(apt, &msg)) { + wait_flags |= MWMO_INPUTAVAILABLE; if (msg.message == WM_QUIT) { TRACE("Received WM_QUIT message\n"); @@ -2181,6 +2178,9 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle TranslateMessage(&msg); DispatchMessageW(&msg); } + } else { + /* no interesting input remains in the queue, so block until *new* messages are posted */ + wait_flags &= ~MWMO_INPUTAVAILABLE; } continue; } diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 94df7195e3c..66680ba5952 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2953,6 +2953,17 @@ static void test_CoWaitForMultipleHandles(void) success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); ok(!success, "CoWaitForMultipleHandles didn't pump any messages\n");
+ /* test CoWaitForMultipleHandles stops pumping messages as soon as its handles are signaled */ + index = 0xdeadbeef; + PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_semaphore); + PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); + hr = CoWaitForMultipleHandles(0, 50, 1, handles, &index); + ok(hr == S_OK, "expected S_OK, got 0x%08lx\n", hr); + ok(index == 0, "expected index 0, got %lu\n", index); + cowait_msgs_expect_queued(hWnd,WM_DDE_FIRST); /* WM_DDE_EXECUTE already pumped*/ + success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE); + ok(!success, "CoWaitForMultipleHandles didn't pump enough messages\n"); + /* test PostMessageA/SendMessageA from a different thread */
index = 0xdeadbeef; @@ -3039,6 +3050,16 @@ static void test_CoWaitForMultipleHandles(void) success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_FIRST, PM_REMOVE); ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
+ index = 0xdeadbeef; + PostMessageA(hWnd, WM_DDE_EXECUTE, 0, (LPARAM)execute_apc); + PostMessageA(hWnd, WM_DDE_FIRST, 0, 0); + hr = CoWaitForMultipleHandles(COWAIT_ALERTABLE, 50, 1, handles, &index); + ok(hr == S_OK, "expected S_OK, got 0x%08lx\n", hr); + ok(index == WAIT_IO_COMPLETION, "expected index WAIT_IO_COMPLETION, got %lu\n", index); + cowait_msgs_expect_queued(hWnd,WM_DDE_FIRST); /* WM_DDE_EXECUTE already pumped*/ + success = PeekMessageA(&msg, hWnd, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE); + ok(!success, "CoWaitForMultipleHandles didn't pump enough messages\n"); + /* test with COWAIT_INPUTAVAILABLE (semaphores are still locked) */
index = 0xdeadbeef;