From: "Changhui Liu" Subject: ole32:fix CoWaitForMultipleHandles cause RPC hang Message-Id: Date: Thu, 11 Dec 2014 22:07:24 +0800 Because there's a RPC request need to be handled by OLE apartment window proc apartment_wndproc. So, after received a WM_QUIT, if the GUI thread in calling CoWaitForMultipleHandles don't handle message loop any more , the RPC will never be handled, the RPC dispatch thread will be hang.
Because there's a RPC request need to be handled by OLE apartment window proc apartment_wndproc.
So, after received a WM_QUIT,
if the GUI thread in calling CoWaitForMultipleHandles don't handle message loop any more ,
the RPC will never be handled, the RPC dispatch thread will be hang.
From 519800d3fd25b78eae6b87064b6db99d8777f375 Mon Sep 17 00:00:00 2001 From: Changhui Liu Date: Thu, 11 Dec 2014 21:13:21 +0800 Subject: ole32:fix CoWaitForMultipleHandles cause RPC hang To: wine-patches Reply-To: wine-devel --- dlls/ole32/compobj.c | 12 +++-- dlls/ole32/tests/compobj.c | 110 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 4 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index da466c4..759bec4 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -4428,6 +4428,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 has_received_wm_quit = 0; TRACE("(0x%08x, 0x%08x, %d, %p, %p)\n", dwFlags, dwTimeout, cHandles, pHandles, lpdwindex); @@ -4517,10 +4518,13 @@ HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, DispatchMessageW(&msg); if (msg.message == WM_QUIT) { - TRACE("resending WM_QUIT to outer message loop\n"); - PostQuitMessage(msg.wParam); - /* no longer need to process messages */ - message_loop = FALSE; + if (!has_received_wm_quit) + { + has_received_wm_quit = TRUE; + TRACE("resending WM_QUIT to outer message loop\n"); + PostQuitMessage(msg.wParam); + } + break; } } diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index eed5ac8..55c9157 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -2283,6 +2283,115 @@ static void test_CoWaitForMultipleHandles(void) CoUninitialize(); } +#define DM_EXECUTERPC_FAKE (0x403) +static HANDLE g_rpc_event = 0; +static volatile char g_rpc_handled = FALSE; + +DWORD WINAPI RpcThread(LPVOID lpParameter) +{ + HWND hWnd = 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}; + /*Wait for CoWaitForMultipleHandles to receive a WM_QUIT message*/ + Sleep (5000); + + hWnd = FindWindowW(wszAptWinClass, NULL); + ok(hWnd!=NULL, "Expected OLE apartment window is valid!"); + + /*Wait for a RPC request to be processed. + This is a very simple demo, + the RPC process flow is very complex in fact if we saw the backtrace in wine. + */ + SendMessageA(hWnd, DM_EXECUTERPC_FAKE, 0, 0); + + g_rpc_handled = TRUE ; + + return 0; +} + +DWORD WINAPI MonThread(LPVOID lpParameter) +{ + DWORD wait_count = 0; + + /*wait 10 seconds for the RPC request*/ + while (wait_count < 10) + { + Sleep(1000); + + if (g_rpc_handled) + break; + + ++wait_count; + trace("sleep %d second\n", wait_count); + } + + if (wait_count >= 10) + { + ok(0, "The RPC request is hanging!\n"); + } + else + { + trace("The RPC request is processed OK!\n"); + } + + SetEvent(g_rpc_event); + + return 0; +} + +static void test_CoWaitForMultipleHandlesHangRpc(void) +{ + static const char cls_name[] = "cowait_test_class"; + HANDLE thread; + DWORD index; + WNDCLASSEXA wc; + BOOL success; + HRESULT hr; + HWND hWnd; + + hr = pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + ok(hr == S_OK, "CoInitializeEx failed with error 0x%08x\n", hr); + + 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; + success = RegisterClassExA(&wc) != 0; + ok(success, "RegisterClassExA failed %u\n", GetLastError()); + + hWnd = CreateWindowExA(0, cls_name, "Test", WS_TILEDWINDOW, 0, 0, 640, 480, 0, 0, 0, 0); + ok(hWnd != 0, "CreateWindowExA failed %u\n", GetLastError()); + + g_rpc_event = CreateEventA(NULL, FALSE, FALSE, NULL); + ok(g_rpc_event != NULL, "CreateEventA Failed:%d\n", GetLastError()); + + PostQuitMessage(0); + + thread = CreateThread(NULL, 0, RpcThread, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError()); + CloseHandle(thread); + + thread = CreateThread(NULL, 0, MonThread, NULL, 0, NULL); + ok(thread != NULL, "CreateThread failed, error %u\n", GetLastError()); + CloseHandle(thread); + + hr = CoWaitForMultipleHandles(0, INFINITE, 1, &g_rpc_event, &index); + ok(hr == S_OK, "Expected S_OK, got 0x%08x\n", hr); + + CloseHandle(g_rpc_event); + + DestroyWindow(hWnd); + + success = UnregisterClassA(cls_name, GetModuleHandleA(0)); + ok(success, "UnregisterClass failed %u\n", GetLastError()); + + CoUninitialize(); +} + static void init_funcs(void) { HMODULE hOle32 = GetModuleHandleA("ole32"); @@ -2344,4 +2453,5 @@ START_TEST(compobj) test_OleRegGetMiscStatus(); test_CoCreateGuid(); test_CoWaitForMultipleHandles(); + test_CoWaitForMultipleHandlesHangRpc(); } -- 1.9.1