CallWindowProc can call a window proc of hwnd belonging to another thread but DispatchMessage can't

Dmitry Timoshkov dmitry at baikal.ru
Mon Oct 4 02:35:36 CDT 2004


Hello,

this is a result I've got debugging a crash occuring in my application
on interthread window activation. Unfortunately this patch doesn't help
to eliminate the crash.

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    CallWindowProc can call a window proc of hwnd belonging to another
    thread but DispatchMessage can't. Add a test case.

diff -u cvs/hq/wine/dlls/user/tests/msg.c wine/dlls/user/tests/msg.c
--- cvs/hq/wine/dlls/user/tests/msg.c	2004-09-22 16:49:01.000000000 +0900
+++ wine/dlls/user/tests/msg.c	2004-10-04 16:22:16.000000000 +0900
@@ -2682,6 +2682,80 @@ static void test_paint_messages(void)
     DestroyWindow( hwnd );
 }
 
+struct wnd_event
+{
+    HWND hwnd;
+    HANDLE event;
+};
+
+static DWORD WINAPI thread_proc(void *param)
+{
+    MSG msg;
+    struct wnd_event *wnd_event = (struct wnd_event *)param;
+
+    wnd_event->hwnd = CreateWindowExA(0, "TestWindowClass", "window caption text", WS_OVERLAPPEDWINDOW,
+                                      100, 100, 200, 200, 0, 0, 0, NULL);
+    ok(wnd_event->hwnd != 0, "Failed to create overlapped window\n");
+
+    SetEvent(wnd_event->event);
+
+    while (GetMessage(&msg, 0, 0, 0))
+    {
+	TranslateMessage(&msg);
+	DispatchMessage(&msg);
+    }
+
+    return 0;
+}
+
+static void test_interthread_messages(void)
+{
+    HANDLE hThread;
+    DWORD tid;
+    WNDPROC proc;
+    MSG msg;
+    char buf[256];
+    int len, expected_len;
+    struct wnd_event wnd_event;
+
+    wnd_event.event = CreateEvent(NULL, 0, 0, NULL);
+
+    hThread = CreateThread(NULL, 0, thread_proc, &wnd_event, 0, &tid);
+    ok(hThread != NULL, "CreateThread failed, error %ld\n", GetLastError());
+
+    ok(WaitForSingleObject(wnd_event.event, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+
+    CloseHandle(wnd_event.event);
+
+    SetLastError(0xdeadbeef);
+    ok(!DestroyWindow(wnd_event.hwnd), "DestroyWindow succeded\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "wrong error code %ld\n", GetLastError());
+
+    proc = (WNDPROC)GetWindowLongPtrA(wnd_event.hwnd, GWLP_WNDPROC);
+    ok(proc != NULL, "GetWindowLongPtrA(GWLP_WNDPROC) error %ld\n", GetLastError());
+
+    expected_len = lstrlenA("window caption text");
+    memset(buf, 0, sizeof(buf));
+    SetLastError(0xdeadbeef);
+    len = CallWindowProcA(proc, wnd_event.hwnd, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
+    ok(len == expected_len, "CallWindowProcA(WM_GETTEXT) error %ld, len %d, expected len %d\n", GetLastError(), len, expected_len);
+    ok(!lstrcmpA(buf, "window caption text"), "window text mismatch\n");
+
+    msg.hwnd = wnd_event.hwnd;
+    msg.message = WM_GETTEXT;
+    msg.wParam = sizeof(buf);
+    msg.wParam = (LPARAM)buf;
+    memset(buf, 0, sizeof(buf));
+    SetLastError(0xdeadbeef);
+    len = DispatchMessageA(&msg);
+    ok(!len && GetLastError() == ERROR_MESSAGE_SYNC_ONLY,
+       "DispatchMessageA(WM_GETTEXT) succeded on another thread window: ret %d, error %ld\n", len, GetLastError());
+
+    ok(PostMessageA(wnd_event.hwnd, WM_QUIT, 0, 0), "PostMessageA(WM_QUIT) error %ld\n", GetLastError());
+
+    ok(WaitForSingleObject(hThread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+    CloseHandle(hThread);
+}
 
 /************* window procedures ********************/
 
@@ -2946,6 +3020,7 @@ START_TEST(msg)
     test_mdi_messages();
     test_button_messages();
     test_paint_messages();
+    test_interthread_messages();
 
     UnhookWindowsHookEx(hCBT_hook);
 }
diff -u cvs/hq/wine/windows/message.c wine/windows/message.c
--- cvs/hq/wine/windows/message.c	2004-09-23 20:12:00.000000000 +0900
+++ wine/windows/message.c	2004-10-04 16:16:00.000000000 +0900
@@ -752,6 +752,13 @@ LONG WINAPI DispatchMessageA( const MSG*
     int painting;
     WNDPROC winproc;
 
+    if (GetWindowThreadProcessId(msg->hwnd, NULL) != GetCurrentThreadId())
+    {
+        ERR( "cannot dispatch msg to other thread window %p\n", msg->hwnd );
+        SetLastError( ERROR_MESSAGE_SYNC_ONLY );
+        return 0;
+    }
+
       /* Process timer messages */
     if ((msg->message == WM_TIMER) || (msg->message == WM_SYSTIMER))
     {
@@ -775,13 +782,6 @@ LONG WINAPI DispatchMessageA( const MSG*
         if (msg->hwnd) SetLastError( ERROR_INVALID_WINDOW_HANDLE );
         return 0;
     }
-    if (wndPtr == WND_OTHER_PROCESS)
-    {
-        if (IsWindow( msg->hwnd ))
-            ERR( "cannot dispatch msg to other process window %p\n", msg->hwnd );
-        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
-        return 0;
-    }
     if (!(winproc = wndPtr->winproc))
     {
         WIN_ReleasePtr( wndPtr );
@@ -799,7 +799,7 @@ LONG WINAPI DispatchMessageA( const MSG*
     SPY_ExitMessage( SPY_RESULT_OK, msg->hwnd, msg->message, retval,
                      msg->wParam, msg->lParam );
 
-    if (painting && (wndPtr = WIN_GetPtr( msg->hwnd )) && (wndPtr != WND_OTHER_PROCESS))
+    if (painting && (wndPtr = WIN_GetPtr( msg->hwnd )))
     {
         BOOL validate = ((wndPtr->flags & WIN_NEEDS_BEGINPAINT) && wndPtr->hrgnUpdate);
         wndPtr->flags &= ~WIN_NEEDS_BEGINPAINT;






More information about the wine-patches mailing list