From: Kevin Puetz PuetzKevinA@JohnDeere.com
If a message arrives for which IMessageFilter::MessagePending returns PENDINGMSG_CANCELCALL, CoMsgWaitForMultipleHandles should immediately return RPC_E_CALL_CANCELED, without waiting any longer for its handles, or pumping any messages (including the one which caused the MessagePending)
Previously the code set the desired HRESULT, but then simply looped again and overwrote it. --- dlls/combase/combase.c | 2 ++ dlls/ole32/tests/compobj.c | 45 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+)
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 08a648451f0..5a9dbcab605 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -2130,6 +2130,7 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle case PENDINGMSG_CANCELCALL: WARN("call canceled\n"); hr = RPC_E_CALL_CANCELED; + goto done; break; case PENDINGMSG_WAITNOPROCESS: case PENDINGMSG_WAITDEFPROCESS: @@ -2191,6 +2192,7 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD flags, DWORD timeout, ULONG handle } break; } +done: if (post_quit) PostQuitMessage(exit_code);
TRACE("-- %#lx\n", hr); diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 8467e86a66f..ad8c61085ec 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -975,6 +975,16 @@ static DWORD WINAPI MessageFilter_MessagePending( return PENDINGMSG_WAITNOPROCESS; }
+static DWORD WINAPI MessageFilter_MessagePending_cancel( + IMessageFilter *iface, + HTASK threadIDCallee, + DWORD dwTickCount, + DWORD dwPendingType) +{ + trace("MessagePending(cancel)\n"); + return PENDINGMSG_CANCELCALL; +} + static const IMessageFilterVtbl MessageFilter_Vtbl = { MessageFilter_QueryInterface, @@ -987,6 +997,18 @@ static const IMessageFilterVtbl MessageFilter_Vtbl =
static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
+static const IMessageFilterVtbl MessageFilter_Vtbl_cancel = +{ + MessageFilter_QueryInterface, + MessageFilter_AddRef, + MessageFilter_Release, + MessageFilter_HandleInComingCall, + MessageFilter_RetryRejectedCall, + MessageFilter_MessagePending_cancel +}; + +static IMessageFilter MessageFilter_cancel = { &MessageFilter_Vtbl_cancel }; + static void test_CoRegisterMessageFilter(void) { HRESULT hr; @@ -2611,6 +2633,14 @@ static DWORD CALLBACK post_message_thread(LPVOID arg) return 0; }
+static DWORD CALLBACK post_input_later_thread(LPVOID arg) +{ + HWND hWnd = arg; + Sleep(50); + PostMessageA(hWnd, WM_CHAR, VK_ESCAPE, 0); + return 0; +} + static const char cls_name[] = "cowait_test_class";
static UINT cowait_msgs[100], cowait_msgs_first, cowait_msgs_last; @@ -2749,6 +2779,21 @@ static DWORD CALLBACK test_CoWaitForMultipleHandles_thread(LPVOID arg) success = PeekMessageA(&msg, NULL, uMSG, uMSG, PM_REMOVE); ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n");
+ hr = CoRegisterMessageFilter(&MessageFilter_cancel, NULL); + ok(hr == S_OK, "CoRegisterMessageFilter failed: %08lx\n", hr); + + /* a message which arrives during the wait calls IMessageFilter::PendingMessage, + * which can cancel the wait (without pumping the message) */ + thread = CreateThread(NULL, 0, post_input_later_thread, hWnd, 0, &tid); + hr = CoWaitForMultipleHandles(0, 200, 2, handles, &index); + ok(hr == RPC_E_CALL_CANCELED, "expected RPC_E_CALL_CANCELED, got 0x%08lx\n", hr); + success = PeekMessageA(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE); + ok(success, "CoWaitForMultipleHandles unexpectedly pumped messages\n"); + CloseHandle(thread); + + hr = CoRegisterMessageFilter(NULL, NULL); + ok(hr == S_OK, "CoRegisterMessageFilter failed: %08lx\n", hr); + DestroyWindow(hWnd); CoUninitialize();