From: Jacek Caban Subject: user32: Use top level window as dialog parent for modal dialogs. Message-Id: <5703A45A.80006@codeweavers.com> Date: Tue, 5 Apr 2016 13:41:14 +0200 This is part of the fix for bug 40282. Build VM of testbot seems down. Here are results of cross compiled submission: https://testbot.winehq.org/JobDetails.pl?Key=21902 Signed-off-by: Jacek Caban --- dlls/user32/dialog.c | 16 ++++----- dlls/user32/tests/win.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 8 deletions(-) diff --git a/dlls/user32/dialog.c b/dlls/user32/dialog.c index 3ea426d..2bacf4d 100644 --- a/dlls/user32/dialog.c +++ b/dlls/user32/dialog.c @@ -587,24 +587,24 @@ static HWND DIALOG_CreateIndirect( HINSTANCE hInst, LPCVOID dlgTemplate, if (modal && owner) { HWND parent; - disabled_owner = owner; /* * Owner needs to be top level window. We need to duplicate the logic from server, - * because we need to disable it before creating dialog window. + * because we need to disable it before creating dialog window. Note that we do that + * even if dialog has WS_CHILD, but only for modal dialogs, which matched what + * Windows does. */ - while ((GetWindowLongW( disabled_owner, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) == WS_CHILD) + while ((GetWindowLongW( owner, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) == WS_CHILD) { - parent = GetParent( disabled_owner ); + parent = GetParent( owner ); if (!parent || parent == GetDesktopWindow()) break; - disabled_owner = parent; + owner = parent; } - if (IsWindowEnabled( disabled_owner )) + if (IsWindowEnabled( owner )) { flags |= DF_OWNERENABLED; + disabled_owner = owner; EnableWindow( disabled_owner, FALSE ); } - else - disabled_owner = NULL; } if (unicode) diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 957e8a1d..7f078d1 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -4420,6 +4420,96 @@ static void test_dialog_styles(void) } } +struct dlg_parent_param +{ + HWND parent; + HWND gwl_parent; + HWND owner; + HWND root; +}; + +static INT_PTR WINAPI parent_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) { + struct dlg_parent_param *param = (void*)lparam; + check_parents(hwnd, param->parent, param->gwl_parent, param->owner ? NULL : param->parent, param->owner, + param->root ? param->root : hwnd, param->root ? param->parent : hwnd); + EndDialog(hwnd, 1); + } + + return 0; +} + +static void test_dialog_parent(void) +{ + HWND dialog, parent, child, child2, desktop = GetDesktopWindow(); + struct dlg_parent_param param; + INT_PTR ret; + struct + { + DLGTEMPLATE dt; + WORD menu_name; + WORD class_id; + WORD class_atom; + WCHAR caption[1]; + } dlg_data; + + dlg_data.dt.dwExtendedStyle = 0; + dlg_data.dt.cdit = 0; + dlg_data.dt.x = 0; + dlg_data.dt.y = 0; + dlg_data.dt.cx = 100; + dlg_data.dt.cy = 100; + dlg_data.menu_name = 0; + dlg_data.class_id = 0; + dlg_data.class_atom = 0; + dlg_data.caption[0] = 0; + + parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + /* Create a child without WS_CHILD flag. It's a valid owner window. */ + child = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + SetParent(child, parent); + /* Regular child. If passed as an owner, its parent will be true owner window. */ + child2 = CreateWindowExA(0, "static", NULL, WS_CHILD, 0, 0, 0, 0, child, NULL, NULL, NULL); + + trace("parent %p child %p child2 %p desktop %p\n", parent, child, child2, desktop); + + /* When dialog is created with WS_CHILD style, its parent depends on function used to create it. */ + dlg_data.dt.style = WS_CHILD; + + /* CreateDialogIndirectParam uses passed parent as dialog parent. */ + dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0); + ok(dialog != 0, "dialog creation failed\n"); + check_parents(dialog, child2, child2, child2, NULL, parent, child); + DestroyWindow(dialog); + + /* DialogBoxIndirectParam uses the first parent of passed owner that's not a child window as dialog + * parent (like in case of dialog with owner). */ + param.parent = child; + param.gwl_parent = child; + param.owner = NULL; + param.root = parent; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); + ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + + /* Dialogs without WS_CHILD behave as expected, they use passed owner just like CreateWindow does. */ + dlg_data.dt.style = WS_OVERLAPPEDWINDOW; + + dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0); + ok(dialog != 0, "dialog creation failed\n"); + check_parents(dialog, desktop, child, NULL, child, dialog, dialog); + DestroyWindow(dialog); + + param.parent = desktop; + param.gwl_parent = child; + param.owner = child; + param.root = NULL; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); + ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + + DestroyWindow(parent); +} + static void test_scrollwindow( HWND hwnd) { HDC hdc; @@ -8943,6 +9033,7 @@ START_TEST(win) test_AdjustWindowRect(); test_window_styles(); test_dialog_styles(); + test_dialog_parent(); test_redrawnow(); test_csparentdc(); test_SetWindowLong();