From: Dmitry Timoshkov Subject: [1/3] user32/tests: Add a test for calling SetWindowPos for other thread window. Resend. Message-Id: <20150430180354.c499dd97.dmitry@baikal.ru> Date: Thu, 30 Apr 2015 18:03:54 +0800 This test shows that SetWindowPos is supposed to send all its messages from the caller's thread causing every SendMessage perfom an inter-thread message processing. Testbot failures are not related to this patch. --- dlls/user32/tests/msg.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 5ef3840..f2ba805 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -14679,7 +14679,6 @@ static void test_SendMessage_other_thread(int thread_n) hthread = CreateThread(NULL, 0, thread_n == 1 ? SendMessage_thread_1 : SendMessage_thread_2, &wnd_event, 0, &tid); ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); - CloseHandle(hthread); flush_events(); flush_sequence(); @@ -14747,6 +14746,125 @@ else trace("main: call DestroyWindow\n"); DestroyWindow(msg.hwnd); + WaitForSingleObject(hthread, INFINITE); + CloseHandle(hthread); + + flush_events(); + flush_sequence(); +} + +static const struct message swp_1[] = { + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE|SWP_NOACTIVATE }, + { 0 } +}; +static const struct message swp_2[] = { + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOCLIENTSIZE }, + { WM_MOVE, sent|defwinproc|wparam, 0 }, + { WM_GETTEXT, sent|optional }, + { WM_NCCALCSIZE, sent|optional }, + { 0 } +}; + +static DWORD WINAPI SetWindowPos_thread(void *param) +{ + struct wnd_event *wnd_event = param; + + trace("thread: starting\n"); + WaitForSingleObject(wnd_event->start_event, INFINITE); + + trace("thread: call SetWindowPos\n"); + /* just move to avoid too complex message sequence, what matters is + * WM_WINDOWPOSCHANGING + WM_WINDOWPOSCHANGED sent from other thread. + */ + SetWindowPos(wnd_event->hwnd, 0, -100, -100, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + trace("thread: ret SetWindowPos\n"); + + return 0; +} + +static void test_SetWindowPos_other_thread(void) +{ + DWORD qs_all_input = QS_ALLINPUT & ~QS_RAWINPUT; + HANDLE hthread; + struct wnd_event wnd_event; + DWORD tid, ret, timeout; + MSG msg; + + wnd_event.start_event = CreateEventA(NULL, 0, 0, NULL); + + wnd_event.hwnd = CreateWindowExA(0, "TestWindowClass", NULL, WS_OVERLAPPEDWINDOW, + 100, 100, 200, 200, 0, 0, 0, NULL); + ok(wnd_event.hwnd != 0, "CreateWindowEx failed\n"); + + hthread = CreateThread(NULL, 0, SetWindowPos_thread, &wnd_event, 0, &tid); + ok(hthread != NULL, "CreateThread failed, error %d\n", GetLastError()); + + flush_events(); + flush_sequence(); + + ret = GetQueueStatus(QS_SENDMESSAGE); + ok(ret == 0, "wrong status %08x\n", ret); + + SetEvent(wnd_event.start_event); + + /* wait for other thread's SendMessage */ + timeout = 0; + for (;;) + { + ret = GetQueueStatus(QS_SENDMESSAGE); + if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break; + Sleep(50); + timeout += 50; + if (timeout > 500) + { + ok(0, "time out waiting for SendMessage from other thread\n"); + break; + } + } + + ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); + ok(ret == MAKELONG(0, QS_SENDMESSAGE), "wrong status %08x\n", ret); + + trace("main: call PeekMessage\n"); + ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n"); + ok_sequence(swp_1, "SetWindowPos from other thread 1", TRUE); + + /* wait for other thread's SendMessage */ + timeout = 0; + for (;;) + { + ret = GetQueueStatus(QS_SENDMESSAGE); + if (ret == MAKELONG(QS_SENDMESSAGE, QS_SENDMESSAGE)) break; + Sleep(50); + timeout += 50; + if (timeout > 500) + { +todo_wine + ok(0, "time out waiting for SendMessage from other thread\n"); + break; + } + } + + ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); +todo_wine + ok(ret == MAKELONG(0, QS_SENDMESSAGE), "wrong status %08x\n", ret); + + trace("main: call PeekMessage\n"); + ok(!PeekMessageA(&msg, 0, 0, 0, PM_REMOVE), "PeekMessage should fail\n"); + ok_sequence(swp_2, "SetWindowPos from other thread 2", TRUE); + + /* intentionally yield */ + MsgWaitForMultipleObjects(0, NULL, FALSE, 100, qs_all_input); + + ret = GetQueueStatus(QS_SENDMESSAGE|QS_POSTMESSAGE); + ok(ret == 0, "wrong status %08x\n", ret); + + trace("main: call DestroyWindow\n"); + DestroyWindow(msg.hwnd); + + WaitForSingleObject(hthread, INFINITE); + CloseHandle(hthread); + flush_events(); flush_sequence(); } @@ -14890,6 +15008,10 @@ START_TEST(msg) * which rely on active/foreground windows being correct. */ test_SetForegroundWindow(); + /* calling SetWindowPos from other thread breaks window activation + * under Wine, so keep it here. + */ + test_SetWindowPos_other_thread(); UnhookWindowsHookEx(hCBT_hook); if (pUnhookWinEvent && hEvent_hook) -- 2.3.7