From: "刘昌辉" Subject: ole32: make CoWaitForMultipleHandles continue dispatch message to OLE apartment window even received WM_QUIT message Message-Id: Date: Thu, 21 May 2015 15:48:38 +0800 Fixed "Bug 37680 - QQ 6.2: unable to quit QQ.exe cleanly" -- https://bugs.winehq.org/show_bug.cgi?id=37680 ------------------ Regards, Changhui Liu
Fixed "Bug 37680 - QQ 6.2: unable to quit QQ.exe cleanly"
 -- https://bugs.winehq.org/show_bug.cgi?id=37680





------------------
Regards,
Changhui Liu
 
From ddb3992d7a92d8fda90d7adc659441cff592d71d Mon Sep 17 00:00:00 2001 From: Changhui Liu Date: Thu, 21 May 2015 15:12:24 +0800 Subject: ole32: make CoWaitForMultipleHandles continue dispatch message to OLE apartment window even received WM_QUIT message To: wine-patches Reply-To: wine-devel --- dlls/ole32/compobj.c | 15 +++++++- dlls/ole32/tests/compobj.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 762f011..4a58d99 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -4427,6 +4427,7 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, APARTMENT *apt = COM_CurrentApt(); BOOL message_loop = apt && !apt->multi_threaded; BOOL check_apc = (dwFlags & COWAIT_ALERTABLE) != 0; + BOOL received_wm_quit = FALSE; TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, pHandles, lpdwindex); @@ -4507,6 +4508,17 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, } } + if (received_wm_quit) + { + while (PeekMessageW(&msg, apt->win, 0, 0, PM_REMOVE|PM_NOYIELD)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + continue; + } + /* 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 (count++ < 100 && COM_PeekMessage(apt, &msg)) @@ -4516,10 +4528,9 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, DispatchMessageW(&msg); if (msg.message == WM_QUIT) { + received_wm_quit = TRUE; TRACE("resending WM_QUIT to outer message loop\n"); PostQuitMessage(msg.wParam); - /* no longer need to process messages */ - message_loop = FALSE; break; } } diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 220052d..930b303 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2290,6 +2290,99 @@ static void test_CoWaitForMultipleHandles(void) CoUninitialize(); } + +/* Because the real RPC call message (DM_EXECUTERPC) will use LPARAM to pass a +pointer to struct dispatch_params witch contain RPC call information, +so here I define DM_EXECUTERPC_FAKE instead without construct a dispatch_params.*/ +#define DM_EXECUTERPC_FAKE (WM_USER + 3) + +static DWORD WINAPI RpcSendThread(LPVOID lpParameter) +{ + HWND hWnd = 0; + DWORD result = 0; + DWORD processId = 0; + DWORD threadId = 0; + const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', + '0','x','#','#','#','#','#','#','#','#',' ',0}; + + const WCHAR wszAptWinClass2[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0}; + + hWnd = FindWindowW(wszAptWinClass, NULL); + if (NULL == hWnd) + { + /*https://msdn.microsoft.com/en-us/library/windows/desktop/ms680112%28v=vs.85%29.aspx + COM creates a hidden window using the Windows class "OleMainThreadWndClass" in + each single-threaded apartment. A call to an object is received as a window message + to this hidden window. */ + hWnd = FindWindowW(wszAptWinClass2, NULL); + } + ok(hWnd!=NULL, "Expected OLE apartment window is valid!\n"); + + threadId = GetWindowThreadProcessId(hWnd, &processId); + ok(GetCurrentProcessId() == processId, "Expected OLE apartment window is in the test process!\n"); + + /*Wait for OLE apartment window process WM_QUIT message.*/ + Sleep (3000); + + /*Test OLE apartment window process a RPC after has received WM_QUIT message.*/ + if (!SendMessageTimeoutA(hWnd, DM_EXECUTERPC_FAKE, 0, 0xdeadbeef, SMTO_BLOCK, 3000, &result)) + { + ok(0, "The RPC request is hanging!\n"); + } + else + { + trace("The RPC request is processed OK!\n"); + } + + SetEvent((HANDLE)lpParameter); + + return 0; +} + +static void test_CoWaitForMultipleHandlesAfterReceivedQuitMsg(void) +{ + HWND hWnd; + HRESULT hr; + DWORD index; + HANDLE event; + HANDLE thread; + WNDCLASSEXA wc; + static const char cls_name[] = "cowait_test_class"; + + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.style = CS_VREDRAW | CS_HREDRAW; + wc.hInstance = GetModuleHandleA(0); + wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszClassName = cls_name; + wc.lpfnWndProc = DefWindowProcA; + RegisterClassExA(&wc); + + hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr); + + hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); + ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError()); + + event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(event != NULL, "CreateEventA Failed:%d\n", GetLastError()); + + PostQuitMessage(0); + + thread = CreateThread(NULL, 0, RpcSendThread, (void*)event, 0, NULL); + ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError()); + + hr = CoWaitForMultipleHandles(0, INFINITE, 1, &event, &index); + ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr); + + CloseHandle(event); + CloseHandle(thread); + DestroyWindow(hWnd); + UnregisterClassA(cls_name, GetModuleHandleA(0)); + CoUninitialize(); +} + static void init_funcs(void) { HMODULE hOle32 = GetModuleHandleA("ole32"); @@ -2351,4 +2444,5 @@ START_TEST(compobj) test_OleRegGetMiscStatus(); test_CoCreateGuid(); test_CoWaitForMultipleHandles(); + test_CoWaitForMultipleHandlesAfterReceivedQuitMsg(); } -- 1.9.1