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