From: Esme Povirk esme@codeweavers.com
On modern Windows, SetForegroundWindow permissions can be lost by focusing some other window or going too long without a focused window in the process. So the earlier a test is run, the better the chances of actually being assigned focus.
The "hide already hidden window from background thread" test seems to take slightly too long when combined with the other hide window test, so it is moved to make a smaller gap.
Focus-related messages have been added in cases where they weren't sent before, and most have been made non-optional so we can notice if this breaks again. --- dlls/user32/tests/msg.c | 112 +++++++++++++++++++++++++++------------- 1 file changed, 77 insertions(+), 35 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index 0ee1eaa393e..c796eec8349 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -148,7 +148,8 @@ typedef enum { hook=0x100, winevent_hook=0x200, kbd_hook=0x400, - winevent_hook_todo=0x800 + winevent_hook_todo=0x800, + wparam_optional=0x1000 } msg_flags_t;
struct message { @@ -517,6 +518,8 @@ static const struct message WmShowMaxOverlappedSeq[] = { { WM_GETMINMAXINFO, sent|defwinproc }, { WM_NCCALCSIZE, sent|wparam, TRUE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, + { WM_NCPAINT, sent|wparam|optional, 1 }, + { WM_ERASEBKGND, sent|optional }, { HCBT_ACTIVATE, hook|optional }, { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, { WM_QUERYNEWPALETTE, sent|wparam|lparam|optional, 0, 0 }, @@ -718,10 +721,10 @@ static const struct message WmDestroyOverlappedSeq[] = { { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { 0x0090, sent|optional }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, - { WM_NCACTIVATE, sent|optional|wparam, 0 }, - { WM_ACTIVATE, sent|optional }, - { WM_ACTIVATEAPP, sent|optional|wparam, 0 }, - { WM_KILLFOCUS, sent|optional|wparam, 0 }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATE, sent }, + { WM_ACTIVATEAPP, sent|wparam, 0 }, + { WM_KILLFOCUS, sent|wparam, 0 }, { WM_IME_SETCONTEXT, sent|wparam|optional, 0 }, { WM_IME_NOTIFY, sent|wparam|optional|defwinproc, 1 }, { EVENT_OBJECT_DESTROY, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, @@ -2667,6 +2670,12 @@ static void dump_sequence(const struct message *expected, const char *context, c /* don't match messages if their defwinproc status differs */ expected++; } + else if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && + (expected->flags & wparam_optional)) + { + /* don't match if wparam differs */ + expected++; + } else { expected++; @@ -2733,7 +2742,15 @@ static void ok_sequence_(const struct message *expected_list, const char *contex { if (expected->flags & wparam) { - if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo) + if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && + (expected->flags & wparam_optional)) + { + /* don't match if wparam differs */ + expected++; + count++; + continue; + } + else if (((expected->wParam ^ actual->wParam) & ~expected->wp_mask) && todo) { todo_wine { failcount ++; @@ -5542,19 +5559,7 @@ static void test_messages(void) flush_events(); ok_sequence(WmHideOverlappedSeq, "ShowWindow(SW_HIDE):overlapped", FALSE);
- /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */ - ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n"); - flush_events(); - ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE); - - /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */ - hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid ); - ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); - ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); - CloseHandle(hthread); - flush_events(); - ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE); - + /* sometimes focus stealing prevention is active here on Windows */ ShowWindow(hwnd, SW_SHOW); flush_events(); ok_sequence(WmShowOverlappedSeq, "ShowWindow(SW_SHOW):overlapped", TRUE); @@ -5606,6 +5611,22 @@ static void test_messages(void) ok(!IsWindowVisible(hwnd), "window should not be visible at this point\n"); ok(GetActiveWindow() == hwnd, "window should still be active\n");
+ /* The following tests usually trigger focus stealing prevention on Windows */ + /* test ShowWindow(SW_HIDE) on a hidden window - single threaded */ + flush_events(); + flush_sequence(); + ok(ShowWindow(hwnd, SW_HIDE) == FALSE, "ShowWindow(SW_HIDE) expected FALSE\n"); + flush_events(); + ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE); + + /* test ShowWindow(SW_HIDE) on a hidden window - multi-threaded */ + hthread = CreateThread( NULL, 0, hide_window_thread, hwnd, 0, &tid ); + ok(hthread != NULL, "CreateThread failed, error %ld\n", GetLastError()); + ok(WaitForSingleObject(hthread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); + CloseHandle(hthread); + flush_events(); + ok_sequence(WmEmptySeq, "ShowWindow(SW_HIDE):overlapped", FALSE); + /* test WM_SETREDRAW on a visible top level window */ ShowWindow(hwnd, SW_SHOW); flush_events(); @@ -14455,16 +14476,25 @@ static const struct message WmShow[] = { { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, /* order undefined with the next 2 messages */ { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { 0 } }; static const struct message WmShowNoActivate_1[] = { { HCBT_MINMAX, hook|lparam, 0, SW_SHOWNOACTIVATE }, - { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { WM_WINDOWPOSCHANGING, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, - { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { HCBT_ACTIVATE, hook|optional }, /* Windows sometimes activates the window */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, + { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, + { HCBT_SETFOCUS, hook|optional }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, + { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_STATECHANGED, 0, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE }, { WM_MOVE, sent|defwinproc|optional }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, @@ -14515,8 +14545,11 @@ static const struct message WmRestore_1[] = { { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional|wparam_optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_RESTORED }, @@ -14612,7 +14645,10 @@ static const struct message WmShowMinimized_1[] = { { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional|wparam_optional, SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOSIZE|SWP_NOMOVE }, + { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|optional, 0, 0 }, /* sometimes sent on win7 */ { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|lparam|defwinproc, SIZE_MINIMIZED, 0 }, @@ -14712,8 +14748,11 @@ static const struct message WmShowMaximized_1[] = { { EVENT_OBJECT_REORDER, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { EVENT_OBJECT_SHOW, winevent_hook|wparam|lparam, 0, 0 }, { HCBT_ACTIVATE, hook|optional }, /* win2000 doesn't send it */ + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* win2000 doesn't send it */ + { WM_WINDOWPOSCHANGED, sent|wparam|optional|wparam_optional, SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, /* win2000 doesn't send it */ + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_SHOWWINDOW|SWP_FRAMECHANGED|SWP_NOCOPYBITS|SWP_STATECHANGED }, { WM_MOVE, sent|defwinproc }, { WM_SIZE, sent|wparam|defwinproc, SIZE_MAXIMIZED }, @@ -18051,21 +18090,21 @@ static const struct message WmSetParentSeq_2[] = { { EVENT_OBJECT_HIDE, winevent_hook|wparam|lparam, 0, 0 }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE }, { HCBT_SETFOCUS, hook|optional }, - { WM_NCACTIVATE, sent|wparam|optional, 0 }, - { WM_ACTIVATE, sent|wparam|optional, 0 }, - { WM_ACTIVATEAPP, sent|wparam|optional, 0 }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam, OBJID_CLIENT, 0 }, + { WM_NCACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATE, sent|wparam, 0 }, + { WM_ACTIVATEAPP, sent|wparam, 0 }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, { WM_KILLFOCUS, sent|wparam, 0 }, { EVENT_OBJECT_PARENTCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam, SWP_NOSIZE }, - { HCBT_ACTIVATE, hook|optional }, - { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|optional, 0, 0 }, + { HCBT_ACTIVATE, hook }, + { EVENT_SYSTEM_FOREGROUND, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, - { WM_NCACTIVATE, sent|wparam|optional, 1 }, - { WM_ACTIVATE, sent|wparam|optional, 1 }, - { HCBT_SETFOCUS, hook|optional }, - { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|optional, OBJID_CLIENT, 0 }, - { WM_SETFOCUS, sent|optional|defwinproc }, + { WM_NCACTIVATE, sent|wparam, 1 }, + { WM_ACTIVATE, sent|wparam, 1 }, + { HCBT_SETFOCUS, hook }, + { EVENT_OBJECT_FOCUS, winevent_hook|wparam|lparam|winevent_hook_todo, OBJID_CLIENT, 0 }, + { WM_SETFOCUS, sent|defwinproc }, { WM_WINDOWPOSCHANGED, sent|wparam, SWP_NOREDRAW|SWP_NOSIZE|SWP_NOCLIENTSIZE }, { WM_MOVE, sent|defwinproc|wparam, 0 }, { EVENT_OBJECT_LOCATIONCHANGE, winevent_hook|wparam|lparam|winevent_hook_todo, 0, 0 }, @@ -19816,21 +19855,24 @@ START_TEST(msg) hCBT_hook = SetWindowsHookExA(WH_CBT, cbt_hook_proc, 0, GetCurrentThreadId()); if (!hCBT_hook) win_skip( "cannot set global hook, will skip hook tests\n" );
+ /* Keep tests that care about focus early, so other tests don't trip focus stealing prevention. */ + /* Tests after test_messages may not be able to focus windows. */ + test_SetParent(); + test_ShowWindow(); + test_messages(); + test_winevents(); test_SendMessage_other_thread(1); test_SendMessage_other_thread(2); test_InSendMessage(); test_SetFocus(); - test_SetParent(); test_PostMessage(); test_broadcast(); - test_ShowWindow(); test_PeekMessage(); test_PeekMessage2(); test_PeekMessage3(); test_WaitForInputIdle( test_argv[0] ); test_scrollwindowex(); - test_messages(); test_setwindowpos(); test_showwindow(); invisible_parent_tests();