Fixes a regression introduced by 8d7de32cd646f3d1f118836e643e6146c9837278.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59034
-- v4: win32u: Clear STARTF_USESHOWWINDOW in MessageBoxIndirectW(). user32/tests: Add tests showing that MessageBox() resets STARTF_USESHOWWINDOW. win32u: Implement NtUserModifyUserStartupInfoFlags(). win32u: Fetch startup info flags during initialization. win32u: Ignore statup cmd show mode for owned windows.
From: Paul Gofman pgofman@codeweavers.com
Fixes a regression introduced by 8d7de32cd646f3d1f118836e643e6146c9837278.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59034 --- dlls/user32/tests/win.c | 36 ++++++++++++++++++++++-------------- dlls/win32u/window.c | 1 + 2 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 354d6ed5ca3..6073e087cb4 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -13677,20 +13677,27 @@ static const struct test_startupinfo_showwindow_test test_startupinfo_showwindow static void test_startupinfo_showwindow_proc( int test_id ) { const struct test_startupinfo_showwindow_test *test = &test_startupinfo_showwindow_tests[test_id]; - static const DWORD ignored_window_styles[] = - { - WS_CHILD, - WS_POPUP, /* WS_POPUP windows are not ignored when used with WS_CAPTION (which is WS_BORDER | WS_DLGFRAME) */ - WS_CHILD | WS_POPUP, - WS_POPUP | WS_BORDER, - WS_POPUP | WS_DLGFRAME, - WS_POPUP | WS_SYSMENU | WS_THICKFRAME| WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + static const struct + { + DWORD style; + BOOL parent; + } + ignored_window_styles[] = + { + { WS_CHILD, TRUE }, + { WS_POPUP }, /* Unowned WS_POPUP windows are not ignored when used with WS_CAPTION (which is WS_BORDER | WS_DLGFRAME) */ + { WS_CHILD | WS_POPUP, TRUE }, + { WS_POPUP | WS_BORDER }, + { WS_POPUP | WS_DLGFRAME }, + { WS_POPUP | WS_SYSMENU | WS_THICKFRAME| WS_MINIMIZEBOX | WS_MAXIMIZEBOX }, + { WS_OVERLAPPED, TRUE }, /* owned window */ + { WS_POPUP | WS_CAPTION, TRUE }, /* owned window */ }; BOOL bval, expected; STARTUPINFOW sa; unsigned int i; DWORD style; - HWND hwnd; + HWND parent, hwnd;
GetStartupInfoW( &sa );
@@ -13705,26 +13712,27 @@ static void test_startupinfo_showwindow_proc( int test_id ) * SW_ variants for ShowWindow() which are not altered by startup info still consume startup info usage so can * only be tested once per process. */
- hwnd = CreateWindowA( "static", "parent", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, + parent = CreateWindowA( "static", "parent", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW( NULL ), NULL ); pump_messages(); for (i = 0; i < ARRAY_SIZE(ignored_window_styles); ++i) { winetest_push_context( "%u", i ); - hwnd = CreateWindowA( "static", "overlapped", ignored_window_styles[i], 0, 0, 0, 0, - ignored_window_styles[i] & WS_CHILD ? hwnd : NULL, NULL, + hwnd = CreateWindowA( "static", "overlapped", ignored_window_styles[i].style, 0, 0, 0, 0, + ignored_window_styles[i].parent ? parent : NULL, NULL, GetModuleHandleW( NULL ), NULL ); ok( !!hwnd, "got NULL.\n" ); ShowWindow( hwnd, SW_SHOW ); bval = IsWindowVisible( hwnd ); - if ((ignored_window_styles[i] & (WS_CHILD | WS_POPUP)) == WS_CHILD) + if ((ignored_window_styles[i].style & (WS_CHILD | WS_POPUP)) == WS_CHILD) ok( !bval, "unexpectedly visible.\n" ); else ok( bval, "unexpectedly invisible.\n" ); pump_messages(); + DestroyWindow( hwnd ); winetest_pop_context(); } - DestroyWindow( hwnd ); + DestroyWindow( parent ); pump_messages();
style = test->style; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 340ab31e857..a933687635e 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -4739,6 +4739,7 @@ static BOOL show_window( HWND hwnd, INT cmd )
if ((!(style & (WS_POPUP | WS_CHILD)) || ((style & (WS_POPUP | WS_CHILD | WS_CAPTION)) == (WS_POPUP | WS_CAPTION))) + && !get_window_relative( hwnd, GW_OWNER ) && InterlockedExchange( &first_window, 0 )) { RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
From: Paul Gofman pgofman@codeweavers.com
And use those to track first use instead of first_window parameter. --- dlls/user32/tests/win.c | 14 +++++++++----- dlls/win32u/class.c | 1 + dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 32 ++++++++++++++++++++++++++------ 4 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 6073e087cb4..693a95f3d72 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -31,6 +31,7 @@ #include "wingdi.h" #include "winuser.h" #include "winreg.h" +#include "winternl.h"
#include "wine/test.h"
@@ -13693,18 +13694,21 @@ static void test_startupinfo_showwindow_proc( int test_id ) { WS_OVERLAPPED, TRUE }, /* owned window */ { WS_POPUP | WS_CAPTION, TRUE }, /* owned window */ }; + + RTL_USER_PROCESS_PARAMETERS *up = NtCurrentTeb()->Peb->ProcessParameters; BOOL bval, expected; - STARTUPINFOW sa; unsigned int i; DWORD style; HWND parent, hwnd;
- GetStartupInfoW( &sa ); + winetest_push_context( "test %d", test_id );
- winetest_push_context( "show %u, test %d", sa.wShowWindow, test_id ); + ok( up->dwFlags & STARTF_USESHOWWINDOW, "got %#lx.\n", up->dwFlags ); + ok( up->wShowWindow == SW_HIDE, "got %lu.\n.", up->wShowWindow );
- ok( sa.dwFlags & STARTF_USESHOWWINDOW, "got %#lx.\n", sa.dwFlags ); - ok( sa.wShowWindow == SW_HIDE, "got %u.\n.", sa.wShowWindow ); + /* Startup window parameters are fetched early and current values don't affect behaviour. */ + up->dwFlags = 0; + up->wShowWindow = SW_SHOW;
/* First test windows which are not affected by startup info. ShowWindow() called for those doesn't count as * consuming startup info, it is still used with the next applicable window. diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 9cc5b6402aa..dc1a42b381d 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -249,6 +249,7 @@ static void init_user(void) { NtQuerySystemInformation( SystemBasicInformation, &system_info, sizeof(system_info), NULL );
+ init_startup_info(); shared_session_init(); gdi_init(); sysparams_init(); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index ee76854c7e4..983e097187b 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -301,6 +301,7 @@ extern HWND get_progman_window(void); extern HWND get_taskman_window(void); extern BOOL is_client_surface_window( struct client_surface *surface, HWND hwnd ); extern HICON get_window_icon_info( HWND hwnd, UINT type, HICON icon, ICONINFO *ret ); +extern void init_startup_info(void);
/* to release pointers retrieved by win_get_ptr */ static inline void release_win_ptr( struct tagWND *ptr ) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a933687635e..f5c022b227f 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -53,6 +53,29 @@ static void *client_objects[MAX_USER_HANDLES]; #define PLACE_MAX 0x0002 #define PLACE_RECT 0x0004
+static volatile unsigned int startup_info_flags; +static unsigned int startup_show_window; + +static unsigned int set_startup_info_flags( unsigned int mask, unsigned int flags ) +{ + unsigned int prev, new; + + do + { + prev = startup_info_flags; + new = (prev & ~mask) | flags; + } while (InterlockedCompareExchange( (LONG volatile *)&startup_info_flags, new, prev ) != prev ); + return prev; +} + +void init_startup_info(void) +{ + RTL_USER_PROCESS_PARAMETERS *p = NtCurrentTeb()->Peb->ProcessParameters; + + startup_show_window = p->wShowWindow; + set_startup_info_flags( ~0u, p->dwFlags ); +} + /*********************************************************************** * alloc_user_handle */ @@ -4724,7 +4747,6 @@ void update_window_state( HWND hwnd ) */ static BOOL show_window( HWND hwnd, INT cmd ) { - static volatile LONG first_window = 1; WND *win; HWND parent; DWORD style = get_window_long( hwnd, GWL_STYLE ), new_style; @@ -4740,13 +4762,11 @@ static BOOL show_window( HWND hwnd, INT cmd ) if ((!(style & (WS_POPUP | WS_CHILD)) || ((style & (WS_POPUP | WS_CHILD | WS_CAPTION)) == (WS_POPUP | WS_CAPTION))) && !get_window_relative( hwnd, GW_OWNER ) - && InterlockedExchange( &first_window, 0 )) + && set_startup_info_flags( STARTF_USESHOWWINDOW, 0 ) & STARTF_USESHOWWINDOW) { - RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters; - - if (params->dwFlags & STARTF_USESHOWWINDOW && (cmd == SW_SHOW || cmd == SW_SHOWNORMAL || cmd == SW_SHOWDEFAULT)) + if (cmd == SW_SHOW || cmd == SW_SHOWNORMAL || cmd == SW_SHOWDEFAULT) { - cmd = params->wShowWindow; + cmd = startup_show_window; TRACE( "hwnd=%p, using cmd %d from startup info.\n", hwnd, cmd ); } }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/win.c | 75 +++++++++++++++++++++++++++++++++++++ dlls/win32u/main.c | 5 +++ dlls/win32u/win32syscalls.h | 5 +-- dlls/win32u/win32u.spec | 2 +- dlls/win32u/window.c | 11 ++++++ dlls/wow64win/user.c | 8 ++++ include/ntuser.h | 1 + 7 files changed, 103 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 693a95f3d72..13dff9d672d 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -64,6 +64,8 @@ static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); static HICON (WINAPI *pInternalGetWindowIcon)(HWND window, UINT type); static BOOL (WINAPI *pSetProcessLaunchForegroundPolicy)(DWORD,DWORD);
+static BOOL (WINAPI *pNtUserModifyUserStartupInfoFlags)(DWORD,DWORD); + static BOOL test_lbuttondown_flag; static DWORD num_gettext_msgs; static DWORD num_settext_msgs; @@ -13777,6 +13779,65 @@ static void test_startupinfo_showwindow_proc( int test_id ) winetest_pop_context(); }
+static void test_showwindow_proc_modify_flags(void) +{ + RTL_USER_PROCESS_PARAMETERS *up = NtCurrentTeb()->Peb->ProcessParameters; + HWND hwnd; + BOOL ret; + + if (!pNtUserModifyUserStartupInfoFlags) + { + win_skip( "NtUserModifyUserStartupInfoFlags is not available.\n" ); + return; + } + + ok( up->dwFlags & STARTF_USESHOWWINDOW, "got %#lx.\n", up->dwFlags ); + ok( up->wShowWindow == SW_HIDE, "got %lu.\n.", up->wShowWindow ); + + /* Startup window parameters are fetched early and current values don't affect behaviour. */ + up->dwFlags = 0; + up->wShowWindow = SW_SHOW; + + pNtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, 0 ); + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + ok( ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); + + pNtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, STARTF_USESHOWWINDOW ); + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + ok( !ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); + + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + ok( ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); + + pNtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, STARTF_USESHOWWINDOW ); + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + ok( !ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); +} + static void test_startupinfo_showwindow( char **argv ) { STARTUPINFOA sa = {.cb = sizeof(STARTUPINFOA)}; @@ -13795,6 +13856,11 @@ static void test_startupinfo_showwindow( char **argv ) ok( ret, "got error %lu\n", GetLastError() ); wait_child_process( &info ); } + + sprintf( cmdline, "%s %s showwindow_proc_modify_flags", argv[0], argv[1] ); + ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sa, &info ); + ok( ret, "got error %lu\n", GetLastError() ); + wait_child_process( &info ); }
static void test_cascade_windows(void) @@ -14273,6 +14339,7 @@ START_TEST(win) int argc = winetest_get_mainargs( &argv ); HMODULE user32 = GetModuleHandleA( "user32.dll" ); HMODULE gdi32 = GetModuleHandleA("gdi32.dll"); + HMODULE win32u = GetModuleHandleA("win32u.dll"); pGetWindowInfo = (void *)GetProcAddress( user32, "GetWindowInfo" ); pGetWindowModuleFileNameA = (void *)GetProcAddress( user32, "GetWindowModuleFileNameA" ); pGetLayeredWindowAttributes = (void *)GetProcAddress( user32, "GetLayeredWindowAttributes" ); @@ -14293,6 +14360,8 @@ START_TEST(win) pInternalGetWindowIcon = (void *)GetProcAddress( user32, "InternalGetWindowIcon" ); pSetProcessLaunchForegroundPolicy = (void*)GetProcAddress( user32, "SetProcessLaunchForegroundPolicy" );
+ pNtUserModifyUserStartupInfoFlags = (void*)GetProcAddress( win32u, "NtUserModifyUserStartupInfoFlags" ); + if (argc == 4) { HWND hwnd; @@ -14328,6 +14397,12 @@ START_TEST(win) return; }
+ if (argc == 3 && !strcmp(argv[2], "showwindow_proc_modify_flags")) + { + test_showwindow_proc_modify_flags(); + return; + } + if (!RegisterWindowClasses()) assert(0);
hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window", diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 193c2c048bf..c0482ba059f 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -1962,6 +1962,11 @@ LRESULT SYSCALL_API NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARA SYSCALL_FUNC( NtUserMessageCall ); }
+BOOL SYSCALL_API NtUserModifyUserStartupInfoFlags( DWORD mask, DWORD flags ) +{ + SYSCALL_FUNC( NtUserModifyUserStartupInfoFlags ); +} + BOOL SYSCALL_API NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ) { SYSCALL_FUNC( NtUserMoveWindow ); diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 69982b52833..7826afd3fc3 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -1209,7 +1209,7 @@ SYSCALL_ENTRY( 0x14b5, NtUserMessageCall, 28 ) \ SYSCALL_ENTRY( 0x14b6, NtUserMinInitialize, 0 ) \ SYSCALL_ENTRY( 0x14b7, NtUserMinMaximize, 0 ) \ - SYSCALL_ENTRY( 0x14b8, NtUserModifyUserStartupInfoFlags, 0 ) \ + SYSCALL_ENTRY( 0x14b8, NtUserModifyUserStartupInfoFlags, 8 ) \ SYSCALL_ENTRY( 0x14b9, NtUserModifyWindowTouchCapability, 0 ) \ SYSCALL_ENTRY( 0x14ba, NtUserMoveWindow, 24 ) \ SYSCALL_ENTRY( 0x14bb, NtUserMsgWaitForMultipleObjectsEx, 20 ) \ @@ -2751,7 +2751,7 @@ SYSCALL_ENTRY( 0x14b5, NtUserMessageCall, 56 ) \ SYSCALL_ENTRY( 0x14b6, NtUserMinInitialize, 0 ) \ SYSCALL_ENTRY( 0x14b7, NtUserMinMaximize, 0 ) \ - SYSCALL_ENTRY( 0x14b8, NtUserModifyUserStartupInfoFlags, 0 ) \ + SYSCALL_ENTRY( 0x14b8, NtUserModifyUserStartupInfoFlags, 16 ) \ SYSCALL_ENTRY( 0x14b9, NtUserModifyWindowTouchCapability, 0 ) \ SYSCALL_ENTRY( 0x14ba, NtUserMoveWindow, 48 ) \ SYSCALL_ENTRY( 0x14bb, NtUserMsgWaitForMultipleObjectsEx, 40 ) \ @@ -3929,7 +3929,6 @@ SYSCALL_STUB( NtUserMarkWindowForRawMouse ) \ SYSCALL_STUB( NtUserMinInitialize ) \ SYSCALL_STUB( NtUserMinMaximize ) \ - SYSCALL_STUB( NtUserModifyUserStartupInfoFlags ) \ SYSCALL_STUB( NtUserModifyWindowTouchCapability ) \ SYSCALL_STUB( NtUserNavigateFocus ) \ SYSCALL_STUB( NtUserNlsKbdSendIMENotification ) \ diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index f0ccfba35cb..e3e80a05d0c 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1207,7 +1207,7 @@ @ stdcall -syscall NtUserMessageCall(long long long long long long long) @ stub -syscall NtUserMinInitialize @ stub -syscall NtUserMinMaximize -@ stub -syscall NtUserModifyUserStartupInfoFlags +@ stdcall -syscall NtUserModifyUserStartupInfoFlags(long long) @ stub -syscall NtUserModifyWindowTouchCapability @ stdcall -syscall NtUserMoveWindow(long long long long long long) @ stdcall -syscall NtUserMsgWaitForMultipleObjectsEx(long ptr long long long) diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index f5c022b227f..d149410dd81 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -6452,3 +6452,14 @@ BOOL WINAPI NtUserGetWindowDisplayAffinity( HWND hwnd, DWORD *affinity ) *affinity = WDA_NONE; return TRUE; } + +/***************************************************************** + * NtUserModifyUserStartupInfoFlags (win32u.@) + */ +BOOL WINAPI NtUserModifyUserStartupInfoFlags( DWORD mask, DWORD flags ) +{ + TRACE( "%#x, %#x.\n", (int)mask, (int)flags ); + + set_startup_info_flags( mask, flags ); + return TRUE; +} diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 398f0fa2f6f..b728e7c01d7 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -3807,6 +3807,14 @@ NTSTATUS WINAPI wow64_NtUserMessageCall( UINT *args ) return message_call_32to64( hwnd, msg, wparam, lparam, result_info, type, ansi ); }
+NTSTATUS WINAPI wow64_NtUserModifyUserStartupInfoFlags( UINT *args ) +{ + DWORD mask = get_ulong( &args ); + DWORD flags = get_ulong( &args ); + + return NtUserModifyUserStartupInfoFlags( mask, flags ); +} + NTSTATUS WINAPI wow64_NtUserMoveWindow( UINT *args ) { HWND hwnd = get_handle( &args ); diff --git a/include/ntuser.h b/include/ntuser.h index 664bcfe459d..8b9d177419b 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -933,6 +933,7 @@ W32KAPI INT WINAPI NtUserMenuItemFromPoint( HWND hwnd, HMENU handle, int x, W32KAPI BOOL WINAPI NtUserMessageBeep( UINT type ); W32KAPI LRESULT WINAPI NtUserMessageCall( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *result_info, DWORD type, BOOL ansi ); +W32KAPI BOOL WINAPI NtUserModifyUserStartupInfoFlags( DWORD mask, DWORD flags ); W32KAPI BOOL WINAPI NtUserMoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy, BOOL repaint ); W32KAPI DWORD WINAPI NtUserMsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags );
From: Paul Gofman pgofman@codeweavers.com
--- dlls/user32/tests/dialog.c | 100 ++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index 49b8f1968a0..a8c366cc7df 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -40,6 +40,8 @@ #include "winuser.h" #include "winnls.h"
+static BOOL (WINAPI *pNtUserModifyUserStartupInfoFlags)(DWORD,DWORD); + #define MAXHWNDS 1024 static HWND hwnd [MAXHWNDS]; static unsigned int numwnds=1; /* 0 is reserved for null */ @@ -147,6 +149,17 @@ static const h_entry hierarchy [] = { {0, 0, 0, 0} };
+static void pump_messages(void) +{ + MSG msg; + + while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } +} + static DWORD get_button_style(HWND button) { return GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK; @@ -2248,7 +2261,63 @@ static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam) return CallNextHookEx(NULL, code, wParam, lParam); }
-static void test_MessageBox(void) +static LRESULT CALLBACK msgbox_hook_proc2(INT code, WPARAM wParam, LPARAM lParam) +{ + return 1; /* prevent message box or dialog window creation. */ +} + +static void test_message_box_startup_info(void) +{ + HHOOK hook; + HWND hwnd; + int ret; + + hook = SetWindowsHookExA( WH_CBT, msgbox_hook_proc2, NULL, GetCurrentThreadId() ); + ret = DialogBoxParamA( GetModuleHandleA( NULL ), "TEST_EMPTY_DIALOG", 0, NULL, 0 ); + ok(ret == -1, "got %d\n", ret); + UnhookWindowsHookEx( hook ); + + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + /* startup info window show flags are in effect. */ + ret = IsWindowVisible( hwnd ); + ok( !ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); + + /* set startup info flags once again. */ + pNtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, STARTF_USESHOWWINDOW ); + hook = SetWindowsHookExA( WH_CBT, msgbox_hook_proc2, NULL, GetCurrentThreadId() ); + ret = MessageBoxA(NULL, "Text", "MSGBOX caption", msgbox_type); + todo_wine ok(!ret, "got %d\n", ret); /* Wine returns -1 here. */ + UnhookWindowsHookEx( hook ); + + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + /* startup info flags have no effect, while the message box window wasn't even created. */ + todo_wine ok( ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); + + /* sanity check, set startup flags once againg and check that it works */ + pNtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, STARTF_USESHOWWINDOW ); + hwnd = CreateWindowA( "static", "overlapped2", WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandleW(NULL), NULL ); + ok( !!hwnd, "got NULL.\n" ); + pump_messages(); + ShowWindow( hwnd, SW_SHOWDEFAULT ); + ret = IsWindowVisible( hwnd ); + /* startup info flags have no effect, while the message box window wasn't even created. */ + ok( !ret, "got %d.\n", ret ); + DestroyWindow( hwnd ); + pump_messages(); +} + +static void test_MessageBox(char **argv) { static const UINT tests[] = { @@ -2260,6 +2329,9 @@ static void test_MessageBox(void) MB_OKCANCEL | MB_TASKMODAL | MB_TOPMOST, MB_OKCANCEL | MB_TASKMODAL | MB_SYSTEMMODAL | MB_TOPMOST, }; + STARTUPINFOA sa = {.cb = sizeof(STARTUPINFOA)}; + PROCESS_INFORMATION info; + char cmdline[MAX_PATH]; unsigned int i; HHOOK hook; int ret; @@ -2278,6 +2350,18 @@ static void test_MessageBox(void) }
UnhookWindowsHookEx(hook); + + if (!pNtUserModifyUserStartupInfoFlags) + { + win_skip("NtUserModifyUserStartupInfoFlags is not available.\n"); + return; + } + sa.dwFlags = STARTF_USESHOWWINDOW; + sa.wShowWindow = SW_HIDE; + sprintf(cmdline, "%s %s message_box_startup_info", argv[0], argv[1]); + ret = CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &sa, &info); + ok(ret, "got error %lu\n", GetLastError()); + wait_child_process(&info); }
static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) @@ -2436,10 +2520,22 @@ static void test_create_controls(void)
START_TEST(dialog) { + char **argv; + int argc = winetest_get_mainargs( &argv ); + HMODULE win32u = GetModuleHandleA("win32u.dll"); + + pNtUserModifyUserStartupInfoFlags = (void*)GetProcAddress(win32u, "NtUserModifyUserStartupInfoFlags"); + g_hinst = GetModuleHandleA (0);
if (!RegisterWindowClasses()) assert(0);
+ if (argc == 3 && !strcmp(argv[2], "message_box_startup_info")) + { + test_message_box_startup_info(); + return; + } + test_dialog_custom_data(); test_GetNextDlgItem(); test_IsDialogMessage(); @@ -2453,6 +2549,6 @@ START_TEST(dialog) test_MessageBoxFontTest(); test_SaveRestoreFocus(); test_timer_message(); - test_MessageBox(); + test_MessageBox(argv); test_capture_release(); }
From: Paul Gofman pgofman@codeweavers.com
Fixes a regression introduced by 8d7de32cd646f3d1f118836e643e6146c9837278. --- dlls/user32/msgbox.c | 1 + dlls/user32/tests/dialog.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c index 12eea8e92d7..009f3858c60 100644 --- a/dlls/user32/msgbox.c +++ b/dlls/user32/msgbox.c @@ -540,6 +540,7 @@ INT WINAPI MessageBoxIndirectW( LPMSGBOXPARAMSW msgbox ) EnumThreadWindows(GetCurrentThreadId(), MSGBOX_EnumProc, (LPARAM)&threadWindows); }
+ NtUserModifyUserStartupInfoFlags( STARTF_USESHOWWINDOW, 0 ); ret=DialogBoxIndirectParamW(msgbox->hInstance, tmplate, msgbox->hwndOwner, MSGBOX_DlgProc, (LPARAM)msgbox);
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c index a8c366cc7df..20e21bea0bc 100644 --- a/dlls/user32/tests/dialog.c +++ b/dlls/user32/tests/dialog.c @@ -2300,7 +2300,7 @@ static void test_message_box_startup_info(void) ShowWindow( hwnd, SW_SHOWDEFAULT ); ret = IsWindowVisible( hwnd ); /* startup info flags have no effect, while the message box window wasn't even created. */ - todo_wine ok( ret, "got %d.\n", ret ); + ok( ret, "got %d.\n", ret ); DestroyWindow( hwnd ); pump_messages();
v4: - remove '`first_window` pre-check; - add patches to fix another regressive aspect of commit 8d7de32cd646f3d1f118836e643e6146c9837278 (also reproduced with the app from Bug 59034 after the initial fix). Message box dialog has flags "compatible" with startup info. I think the added dialog test clearly distinguishes between the potential handling of the hidden (or minimized) window while showing message box (with, e. g., some message handling or another window show on the way, how that happens with Wine from DIALOG_DoDialogBox, while that doesn't work reliably) and some explicit disablement of startup info effect in the MessageBox. In the test the dialog window is not even created (due to handling in the hook) while the startup info doesn't have an effect after that, suggesting that is explicitly cleared during MessageBox processing but before hitting any window procedures. While doing the same with DialogBoxIndirect doesn't have that behaviour, suggesting that is specific to MessageBox and not (modal) dialogs in genera l.
Rémi Bernon (@rbernon) commented about dlls/win32u/window.c:
if ((!(style & (WS_POPUP | WS_CHILD)) || ((style & (WS_POPUP | WS_CHILD | WS_CAPTION)) == (WS_POPUP | WS_CAPTION)))
&& !get_window_relative( hwnd, GW_OWNER )
Lets keep the && aligned with the other below. It's otherwise harder to read assumed operator precedence.
This merge request was approved by Rémi Bernon.