[PATCH] user32: Add a timeout when sending WM_WINE_DESTROYWINDOW

Andrew Eikum aeikum at codeweavers.com
Thu Feb 22 08:03:35 CST 2018


Without this change, the test will deadlock in DestroyWindow waiting
for the other thread to process the WM_WINE_DESTROYWINDOW message.

Note that this adds about 1 second of runtime to the test, waiting for
the SendMessage to time out. Windows does not time out like this.
Another option would be to use PostMessage, but that seems like a
larger change.

Signed-off-by: Andrew Eikum <aeikum at codeweavers.com>
---
 dlls/user32/tests/win.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/user32/win.c       |  4 +-
 2 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 96a2467da0..b8fa44878c 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -10433,6 +10433,103 @@ if (!is_wine) /* FIXME: remove once Wine is fixed */
     DestroyWindow(owner);
 }
 
+static struct destroy_data
+{
+    HWND main_wnd;
+    HWND thread_wnd;
+    HANDLE evt;
+    DWORD main_tid;
+} destroy_data;
+
+static LRESULT WINAPI destroy_thread_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+    }
+    return DefWindowProcA(hwnd, msg, wparam, lparam);
+}
+
+static DWORD CALLBACK destroy_thread(void *user)
+{
+    MSG msg;
+
+    destroy_data.thread_wnd = CreateWindowExA(0, "destroy_test_thread",
+            "destroy test thread", WS_CHILD, 100, 100, 100, 100,
+            destroy_data.main_wnd, 0, GetModuleHandleA(NULL), NULL);
+    ok(destroy_data.thread_wnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
+    if (!destroy_data.thread_wnd)
+        return 0;
+
+    PostThreadMessageW(destroy_data.main_tid, WM_USER, 0, 0);
+
+    while (GetMessageA(&msg, 0, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+
+    PostThreadMessageW(destroy_data.main_tid, WM_USER + 1, 0, 0);
+    WaitForSingleObject(destroy_data.evt, INFINITE);
+
+    return 0;
+}
+
+static void test_destroy_quit(void)
+{
+    MSG msg;
+    WNDCLASSA wnd_classA;
+    ATOM ret;
+    HANDLE thread;
+
+    destroy_data.main_tid = GetCurrentThreadId();
+    destroy_data.evt = CreateEventW(NULL, FALSE, FALSE, NULL);
+
+    memset(&wnd_classA, 0, sizeof(wnd_classA));
+    wnd_classA.lpszClassName = "destroy_test_main";
+    wnd_classA.lpfnWndProc = DefWindowProcA;
+    ret = RegisterClassA(&wnd_classA);
+    ok(ret, "RegisterClass failed with error %d\n", GetLastError());
+
+    memset(&wnd_classA, 0, sizeof(wnd_classA));
+    wnd_classA.lpszClassName = "destroy_test_thread";
+    wnd_classA.lpfnWndProc = destroy_thread_wndproc;
+    ret = RegisterClassA(&wnd_classA);
+    ok(ret, "RegisterClass failed with error %d\n", GetLastError());
+
+    destroy_data.main_wnd = CreateWindowExA(0, "destroy_test_main",
+            "destroy test main", WS_OVERLAPPED | WS_CAPTION, 100, 100, 100, 100,
+            0, 0, GetModuleHandleA(NULL), NULL);
+    ok(destroy_data.main_wnd != NULL, "CreateWindowEx failed with error %d\n", GetLastError());
+    if (!destroy_data.main_wnd)
+    {
+        CloseHandle(destroy_data.evt);
+        return;
+    }
+
+    thread = CreateThread(NULL, 0, &destroy_thread, 0, 0, NULL);
+
+    while (GetMessageA(&msg, 0, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+        if (msg.message == WM_USER)
+        {
+            DestroyWindow(destroy_data.main_wnd);
+        }
+        else if (msg.message == WM_USER + 1)
+        {
+            SetEvent(destroy_data.evt);
+            break;
+        }
+    }
+
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread);
+}
+
 START_TEST(win)
 {
     char **argv;
@@ -10583,6 +10680,7 @@ START_TEST(win)
     test_desktop();
     test_hide_window();
     test_minimize_window(hwndMain);
+    test_destroy_quit();
 
     /* add the tests above this line */
     if (hhook) UnhookWindowsHookEx(hhook);
diff --git a/dlls/user32/win.c b/dlls/user32/win.c
index b13032bd6e..939903e053 100644
--- a/dlls/user32/win.c
+++ b/dlls/user32/win.c
@@ -971,7 +971,7 @@ LRESULT WIN_DestroyWindow( HWND hwnd )
         for (i = 0; list[i]; i++)
         {
             if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
-            else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
+            else SendMessageTimeoutW( list[i], WM_WINE_DESTROYWINDOW, 0, 0, SMTO_ABORTIFHUNG, 1000, NULL );
         }
         HeapFree( GetProcessHeap(), 0, list );
     }
@@ -1047,7 +1047,7 @@ static void destroy_thread_window( HWND hwnd )
         for (i = 0; list[i]; i++)
         {
             if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] );
-            else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
+            else SendMessageTimeoutW( list[i], WM_WINE_DESTROYWINDOW, 0, 0, SMTO_ABORTIFHUNG, 1000, NULL );
         }
         HeapFree( GetProcessHeap(), 0, list );
     }
-- 
2.16.2




More information about the wine-devel mailing list