[PATCH 1/2] user32/tests: Add a test exposing a SetActiveWindow inversion.

Rémi Bernon rbernon at codeweavers.com
Wed Jan 22 11:38:06 CST 2020


When calling SetForegroundWindow for a window in another thread, an
internal message is posted to the thread's message queue.

If this thread then calls SetForegroundWindow before processing its
messages it will execute the corresponding set_active_window first,
but then overwrite the active window later, when processing its internal
messages.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/user32/tests/win.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 0f683f858a1..38fcada570c 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -3246,7 +3246,9 @@ static void test_SetActiveWindow(HWND hwnd)
 struct create_window_thread_params
 {
     HWND window;
+    HWND other_window;
     HANDLE window_created;
+    HANDLE set_foreground;
     HANDLE test_finished;
 };
 
@@ -3255,12 +3257,23 @@ static DWORD WINAPI create_window_thread(void *param)
     struct create_window_thread_params *p = param;
     DWORD res;
     BOOL ret;
+    MSG msg;
 
+    p->other_window = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0);
     p->window = CreateWindowA("static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, 0, 0);
 
     ret = SetEvent(p->window_created);
     ok(ret, "SetEvent failed, last error %#x.\n", GetLastError());
 
+    res = WaitForSingleObject(p->set_foreground, INFINITE);
+    ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
+
+    SetForegroundWindow(p->other_window);
+    check_active_state(p->other_window, p->other_window, p->other_window);
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg);
+    todo_wine
+    check_active_state(p->other_window, p->other_window, p->other_window);
+
     res = WaitForSingleObject(p->test_finished, INFINITE);
     ok(res == WAIT_OBJECT_0, "Wait failed (%#x), last error %#x.\n", res, GetLastError());
 
@@ -3355,6 +3368,8 @@ static void test_SetForegroundWindow(HWND hwnd)
 
     thread_params.window_created = CreateEventW(NULL, FALSE, FALSE, NULL);
     ok(!!thread_params.window_created, "CreateEvent failed, last error %#x.\n", GetLastError());
+    thread_params.set_foreground = CreateEventW(NULL, FALSE, FALSE, NULL);
+    ok(!!thread_params.set_foreground, "CreateEvent failed, last error %#x.\n", GetLastError());
     thread_params.test_finished = CreateEventW(NULL, FALSE, FALSE, NULL);
     ok(!!thread_params.test_finished, "CreateEvent failed, last error %#x.\n", GetLastError());
     thread = CreateThread(NULL, 0, create_window_thread, &thread_params, 0, &tid);
@@ -3388,9 +3403,19 @@ static void test_SetForegroundWindow(HWND hwnd)
     ok(!SetForegroundWindow(hwnd2), "SetForegroundWindow failed\n");
     check_wnd_state(hwnd, hwnd, hwnd, 0);
 
+    SetForegroundWindow(hwnd);
+    check_active_state(hwnd, hwnd, hwnd);
+    SetForegroundWindow(thread_params.window);
+    check_active_state(0, thread_params.window, 0);
+    SetForegroundWindow(hwnd);
+    check_active_state(hwnd, hwnd, hwnd);
+    res = SetEvent(thread_params.set_foreground);
+    ok(res, "SetEvent failed, last error %#x.\n", GetLastError());
+
     SetEvent(thread_params.test_finished);
     WaitForSingleObject(thread, INFINITE);
     CloseHandle(thread_params.test_finished);
+    CloseHandle(thread_params.set_foreground);
     CloseHandle(thread_params.window_created);
     CloseHandle(thread);
     DestroyWindow(hwnd2);
-- 
2.25.0




More information about the wine-devel mailing list