From: Rémi Bernon rbernon@codeweavers.com
We cannot safely switch to the desktop window, and we also cannot safely destroy and re-create windows without risking to lose focus in favor of a foreign window. Lets create a dedicated window to which foreground will be returned whenever the test windows lose it. --- dlls/user32/tests/input.c | 2 +- dlls/user32/tests/msg.c | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index ab7dd6b5605..7915a8416d3 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -561,7 +561,7 @@ static inline BOOL is_mouse_message( UINT message ) }
#define create_foreground_window( a ) create_foreground_window_( __FILE__, __LINE__, a, 5 ) -HWND create_foreground_window_( const char *file, int line, BOOL fullscreen, UINT retries ) +static HWND create_foreground_window_( const char *file, int line, BOOL fullscreen, UINT retries ) { for (;;) { diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index a09d752786b..6fd76d28533 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -117,6 +117,7 @@ static HHOOK hKBD_hook; static HHOOK hCBT_hook; static DWORD cbt_hook_thread_id; static DWORD winevent_hook_thread_id; +static HWND foreground;
static const WCHAR testWindowClassW[] = { 'T','e','s','t','W','i','n','d','o','w','C','l','a','s','s','W',0 }; @@ -2695,6 +2696,76 @@ static void flush_sequence(void) LeaveCriticalSection( &sequence_cs ); }
+#define create_foreground_window( a ) create_foreground_window_( __FILE__, __LINE__, a, 5 ) +static HWND create_foreground_window_( const char *file, int line, BOOL fullscreen, UINT retries ) +{ + for (;;) + { + HWND hwnd; + BOOL ret; + + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | (fullscreen ? 0 : WS_VISIBLE), + 100, 100, 5, 5, NULL, NULL, NULL, NULL ); + ok_(file, line)( hwnd != NULL, "CreateWindowW failed, error %lu\n", GetLastError() ); + + if (fullscreen) + { + HMONITOR hmonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTOPRIMARY ); + MONITORINFO mi = {.cbSize = sizeof(MONITORINFO)}; + + ok_(file, line)( hmonitor != NULL, "MonitorFromWindow failed, error %lu\n", GetLastError() ); + ret = GetMonitorInfoW( hmonitor, &mi ); + ok_(file, line)( ret, "GetMonitorInfoW failed, error %lu\n", GetLastError() ); + ret = SetWindowPos( hwnd, 0, mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, + mi.rcMonitor.bottom - mi.rcMonitor.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW ); + ok_(file, line)( ret, "SetWindowPos failed, error %lu\n", GetLastError() ); + } + flush_events(); + + if (GetForegroundWindow() == hwnd) return hwnd; + ok_(file, line)( retries > 0, "failed to create foreground window\n" ); + if (!retries--) return hwnd; + + ret = DestroyWindow( hwnd ); + ok_(file, line)( ret, "DestroyWindow failed, error %lu\n", GetLastError() ); + flush_events(); + } +} + +static LRESULT CALLBACK foreground_window_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + if (msg == WM_USER) SetForegroundWindow( (HWND)wparam ); + if (msg == WM_CLOSE) PostQuitMessage( 0 ); + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static DWORD WINAPI foreground_window_thread( void *arg ) +{ + HANDLE event = arg; + MSG msg; + + foreground = create_foreground_window( FALSE ); + SetWindowLongPtrW( foreground, GWLP_WNDPROC, (LONG_PTR)foreground_window_wndproc ); + SetEvent( event ); + + while (GetMessageW( &msg, NULL, 0, 0 )) + { + if (msg.message == WM_QUIT) break; + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + + return 0; +} + +static void start_foreground_window_thread(void) +{ + HANDLE event = CreateEventA( NULL, FALSE, FALSE, NULL ); + CloseHandle( CreateThread( NULL, 0, foreground_window_thread, event, 0, NULL ) ); + WaitForSingleObject( event, 10000 ); + CloseHandle( event ); +} + static const char* message_type_name(int flags) { if (flags & hook) return "hook"; if (flags & kbd_hook) return "kbd_hook"; @@ -21399,6 +21470,8 @@ 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" );
+ start_foreground_window_thread(); + test_winevents(); test_SendMessage_other_thread(); test_setparent_status();