X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=rostests%2Fwinetests%2Fuser32%2Fwin.c;h=74c9ec8bd4d4093be73fa5ac5f012100e927e380;hp=437efbb45d99dceccdf7d33824edb7c2b8a648b4;hb=fa03a0ab6b6a182220990debc9e75b5237a0f6db;hpb=e5dd5ba644d425b1ea3b22e11128107dd23735b8 diff --git a/rostests/winetests/user32/win.c b/rostests/winetests/user32/win.c index 437efbb45d9..74c9ec8bd4d 100644 --- a/rostests/winetests/user32/win.c +++ b/rostests/winetests/user32/win.c @@ -652,6 +652,31 @@ static void test_parent_owner(void) DestroyWindow( child ); DestroyWindow( test ); DestroyWindow( owner ); + + /* Test that owner window takes into account WS_CHILD flag even if parent is set by SetParent. */ + owner = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, desktop ); + SetParent(owner, hwndMain); + check_parents( owner, hwndMain, hwndMain, NULL, NULL, hwndMain, owner ); + test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner ); + check_parents( test, desktop, owner, NULL, owner, test, test ); + DestroyWindow( owner ); + DestroyWindow( test ); + + owner = create_tool_window( WS_VISIBLE | WS_CHILD, desktop ); + SetParent(owner, hwndMain); + check_parents( owner, hwndMain, hwndMain, hwndMain, NULL, hwndMain, hwndMain ); + test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner ); + check_parents( test, desktop, hwndMain, NULL, hwndMain, test, test ); + DestroyWindow( owner ); + DestroyWindow( test ); + + owner = create_tool_window( WS_VISIBLE | WS_POPUP | WS_CHILD, desktop ); + SetParent(owner, hwndMain); + check_parents( owner, hwndMain, hwndMain, NULL, NULL, hwndMain, owner ); + test = create_tool_window( WS_VISIBLE | WS_OVERLAPPEDWINDOW, owner ); + check_parents( test, desktop, owner, NULL, owner, test, test ); + DestroyWindow( owner ); + DestroyWindow( test ); } static BOOL CALLBACK enum_proc( HWND hwnd, LPARAM lParam) @@ -1386,7 +1411,6 @@ static void test_MDI_create(HWND parent, HWND mdi_client, INT_PTR first_id) id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1403,7 +1427,6 @@ todo_wine id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1459,7 +1482,6 @@ todo_wine id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1480,7 +1502,6 @@ todo_wine id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1537,7 +1558,6 @@ todo_wine id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -1558,7 +1578,6 @@ todo_wine id = GetWindowLongPtrA(mdi_child, GWLP_ID); ok(id == first_id, "wrong child id %ld\n", id); hwnd = (HWND)SendMessageA(mdi_client, WM_MDIGETACTIVE, 0, 0); -todo_wine ok(!hwnd, "WM_MDIGETACTIVE should return 0, got %p\n", hwnd); SendMessageA(mdi_client, WM_MDIDESTROY, (WPARAM)mdi_child, 0); ok(!IsWindow(mdi_child), "WM_MDIDESTROY failed\n"); @@ -4177,10 +4196,8 @@ static void check_window_style(DWORD dwStyleIn, DWORD dwExStyleIn, DWORD dwStyle dwExStyleOut = dwExStyleIn & ~WS_EX_WINDOWEDGE; ok(dwActualStyle == dwStyleOut, "expected style %#x, got %#x\n", dwStyleOut, dwActualStyle); /* FIXME: Remove the condition below once Wine is fixed */ - if (dwActualExStyle != dwExStyleOut) - todo_wine ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); - else - ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); + todo_wine_if (dwActualExStyle != dwExStyleOut) + ok(dwActualExStyle == dwExStyleOut, "expected ex_style %#x, got %#x\n", dwExStyleOut, dwActualExStyle); DestroyWindow(hwnd); if (hwndParent) DestroyWindow(hwndParent); @@ -4239,6 +4256,74 @@ static INT_PTR WINAPI empty_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM return 0; } +static INT_PTR WINAPI empty_dlg_proc3(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) + EndDialog(hwnd, 0); + + return 0; +} + +struct dialog_param +{ + HWND parent, grand_parent; + DLGTEMPLATE *dlg_data; +}; + +static INT_PTR WINAPI empty_dlg_proc2(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) + { + DWORD style = GetWindowLongA(hwnd, GWL_STYLE); + struct dialog_param *param = (struct dialog_param *)lparam; + BOOL parent_is_child; + HWND disabled_hwnd; + + parent_is_child = (GetWindowLongA(param->parent, GWL_STYLE) & (WS_POPUP | WS_CHILD)) == WS_CHILD; + + ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); + if (parent_is_child) + { + ok(IsWindowEnabled(param->parent), "wrong state for %08x\n", style); + disabled_hwnd = param->grand_parent; + } + else + { + ok(!IsWindowEnabled(param->parent), "wrong state for %08x\n", style); + disabled_hwnd = param->parent; + } + + if (param->grand_parent) + { + if (parent_is_child) + ok(!IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style); + else + ok(IsWindowEnabled(param->grand_parent), "wrong state for %08x\n", style); + } + + DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, disabled_hwnd, empty_dlg_proc3, 0); + ok(IsWindowEnabled(disabled_hwnd), "wrong state for %08x\n", style); + + ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); + ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent); + if (param->grand_parent) + ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style); + + DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); + ok(IsWindowEnabled(hwnd), "wrong state for %p\n", hwnd); + ok(IsWindowEnabled(param->parent), "wrong state for %p\n", param->parent); + if (param->grand_parent) + ok(IsWindowEnabled(param->grand_parent), "wrong state for %p (%08x)\n", param->grand_parent, style); + + param->dlg_data->style |= WS_CHILD; + DialogBoxIndirectParamA(GetModuleHandleA(NULL), param->dlg_data, hwnd, empty_dlg_proc3, 0); + ok(IsWindowEnabled(hwnd), "wrong state for %p (%08x)\n", hwnd, style); + + EndDialog(hwnd, 0); + } + return 0; +} + static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_out, DWORD ex_style_out) { struct @@ -4250,11 +4335,19 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou WCHAR caption[1]; } dlg_data; DWORD style, ex_style; - HWND hwnd, parent = 0; + HWND hwnd, grand_parent = 0, parent = 0; + struct dialog_param param; if (style_in & WS_CHILD) - parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, + { + grand_parent = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + ok(grand_parent != 0, "grand_parent creation failed\n"); + } + + parent = CreateWindowExA(0, "static", NULL, style_in, + 0, 0, 0, 0, grand_parent, NULL, NULL, NULL); + ok(parent != 0, "parent creation failed, style %#x\n", style_in); dlg_data.dt.style = style_in; dlg_data.dt.dwExtendedStyle = ex_style_in; @@ -4278,6 +4371,8 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou ok(style == (style_out | DS_3DLOOK), "got %#x\n", style); ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); + ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in); + /* try setting the styles explicitly */ SetWindowLongA(hwnd, GWL_EXSTYLE, ex_style_in); style = GetWindowLongA(hwnd, GWL_STYLE); @@ -4307,13 +4402,22 @@ static void check_dialog_style(DWORD style_in, DWORD ex_style_in, DWORD style_ou else ex_style_out = ex_style_in & ~WS_EX_WINDOWEDGE; /* FIXME: Remove the condition below once Wine is fixed */ - if (ex_style != ex_style_out) - todo_wine ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); - else - ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); + todo_wine_if (ex_style != ex_style_out) + ok(ex_style == ex_style_out, "expected ex_style %#x, got %#x\n", ex_style_out, ex_style); DestroyWindow(hwnd); + + param.parent = parent; + param.grand_parent = grand_parent; + param.dlg_data = &dlg_data.dt; + DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, parent, empty_dlg_proc2, (LPARAM)¶m); + + ok(IsWindowEnabled(parent), "wrong parent state (dialog style %#x)\n", style_in); + if (grand_parent) + ok(IsWindowEnabled(grand_parent), "wrong grand parent state (dialog style %#x)\n", style_in); + DestroyWindow(parent); + DestroyWindow(grand_parent); } static void test_dialog_styles(void) @@ -4403,6 +4507,233 @@ static void test_dialog_styles(void) } } +struct dlg_parent_param +{ + HWND ga_parent; + HWND gwl_parent; + HWND get_parent; + HWND owner; + HWND root; + HWND ga_root_owner; +}; + +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->ga_parent, param->gwl_parent, param->get_parent, param->owner, + param->root ? param->root : hwnd, param->ga_root_owner ? param->ga_root_owner : hwnd); + + ok(!IsWindowEnabled(param->gwl_parent), "parent is not disabled\n"); + EndDialog(hwnd, 2); + ok(IsWindowEnabled(param->gwl_parent), "parent is not enabled\n"); + } + + return 0; +} + +static INT_PTR WINAPI reparent_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) { + ok(!IsWindowEnabled(GetParent(hwnd)), "parent is not disabled\n"); + SetParent(hwnd, (HWND)lparam); + } + + return 0; +} + +static INT_PTR WINAPI reparent_owned_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_INITDIALOG) { + HWND new_parent = (HWND)lparam; + HWND owner = GetWindow(hwnd, GW_OWNER); + ok(!IsWindowEnabled(owner), "owner is not disabled\n"); + SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE) | WS_CHILD); + SetParent(hwnd, new_parent); + ok(GetParent(hwnd) == new_parent, "GetParent(hwnd) = %p, expected %p\n", GetParent(hwnd), new_parent); + PostMessageA(hwnd, WM_QUIT, 0, 0); + } + + return 0; +} + +static LRESULT WINAPI reparent_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_ENTERIDLE) { + HWND dialog = (HWND)lparam; + HWND owner = GetParent(dialog); + /* EndDialog will enable owner */ + EnableWindow(owner, FALSE); + EndDialog(dialog, 2); + ok(IsWindowEnabled(owner), "owner is not enabled\n"); + /* ...but it won't be enabled on dialog exit */ + EnableWindow(owner, FALSE); + } + return DefWindowProcA( hwnd, msg, wparam, lparam ); +} + +static LRESULT WINAPI post_quit_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_ENTERIDLE) { + HWND dialog = (HWND)lparam; + PostMessageA(dialog, WM_QUIT, 0, 0); + } + return DefWindowProcA( hwnd, msg, wparam, lparam ); +} + +static LRESULT WINAPI destroy_dialog_owner_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_ENTERIDLE) { + HWND dialog = (HWND)lparam; + DestroyWindow(dialog); + } + return DefWindowProcA( hwnd, msg, wparam, lparam ); +} + +static void test_dialog_parent(void) +{ + HWND dialog, parent, child, child2, other, 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); + + ok(IsWindowEnabled(child2), "child2 is disabled\n"); + EnableWindow(child2, FALSE); + EndDialog(dialog, 0); + ok(IsWindowEnabled(child2), "child2 is not enabled\n"); + 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.ga_parent = param.gwl_parent = param.get_parent = child; + param.owner = NULL; + param.root = parent; + param.ga_root_owner = child; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); + ok(ret == 2, "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); + + ok(IsWindowEnabled(child), "child is disabled\n"); + EnableWindow(child, FALSE); + EndDialog(dialog, 0); + ok(IsWindowEnabled(child), "child is not enabled\n"); + DestroyWindow(dialog); + + param.ga_parent = desktop; + param.gwl_parent = child; + param.get_parent = NULL; + param.owner = child; + param.root = param.ga_root_owner = NULL; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); + ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + + other = CreateWindowExA(0, "static", NULL, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, NULL, NULL); + SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)reparent_dialog_owner_proc); + + /* When dialog is created with WS_CHILD|WS_POPUP style, we have an owner. */ + dlg_data.dt.style = WS_CHILD|WS_POPUP; + + dialog = CreateDialogIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, empty_dlg_proc, 0); + ok(dialog != 0, "dialog creation failed\n"); + check_parents(dialog, desktop, child, child, child, dialog, child); + + ok(IsWindowEnabled(child), "child is disabled\n"); + EnableWindow(child, FALSE); + EndDialog(dialog, 0); + ok(IsWindowEnabled(child), "child is not enabled\n"); + DestroyWindow(dialog); + + param.ga_parent = desktop; + param.gwl_parent = param.get_parent = child; + param.owner = child; + param.root = NULL; + param.ga_root_owner = child; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, parent_dlg_proc, (LPARAM)¶m); + ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + + /* If we change parent in WM_INITDIALOG for WS_CHILD dialog WM_ENTERIDLE is still sent to the original + * parent. EndDialog will enable the new parent. */ + EnableWindow(child, TRUE); + EnableWindow(other, FALSE); + dlg_data.dt.style = WS_CHILD; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_dlg_proc, (LPARAM)other); + ok(ret == 2, "DialogBoxIndirectParam returned %ld\n", ret); + ok(!IsWindowEnabled(other), "other is not disabled\n"); + ok(!IsWindowEnabled(child), "child is not disabled\n"); + ok(IsWindowEnabled(child2), "child2 is not enabled\n"); + EnableWindow(child, TRUE); + + /* If we change parent and style in WM_INITDIALOG for dialog with an owner to make it true child + * (thus GetParent() will return the new parent instead of an owner), WM_ENTERIDLE is still sent + * to the original parent. EndDialog will enable the new parent. */ + EnableWindow(other, FALSE); + dlg_data.dt.style = WS_OVERLAPPED; + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, child2, reparent_owned_dlg_proc, (LPARAM)other); + ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(!IsWindowEnabled(other), "other is not disabled\n"); + ok(!IsWindowEnabled(child), "child is not disabled\n"); + ok(IsWindowEnabled(child2), "child2 is not enabled\n"); + EnableWindow(child, TRUE); + EnableWindow(other, TRUE); + + /* Quit dialog message loop by sending WM_QUIT message. Dialog owner is not enabled. */ + SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)post_quit_dialog_owner_proc); + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0); + ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(!IsWindowEnabled(other), "other is enabled\n"); + EnableWindow(other, TRUE); + + /* Quit dialog message loop by destroying the window. Dialog owner is not enabled. */ + SetWindowLongPtrA(child, GWLP_WNDPROC, (ULONG_PTR)destroy_dialog_owner_proc); + ret = DialogBoxIndirectParamA(GetModuleHandleA(NULL), &dlg_data.dt, other, empty_dlg_proc, 0); + ok(ret == 1, "DialogBoxIndirectParam returned %ld\n", ret); + ok(!IsWindowEnabled(other), "other is enabled\n"); + EnableWindow(other, TRUE); + + DestroyWindow(parent); +} + static void test_scrollwindow( HWND hwnd) { HDC hdc; @@ -4510,11 +4841,25 @@ static void test_scrollvalidate( HWND parent) rcu.left,rcu.top,rcu.right,rcu.bottom); ReleaseDC( hwnd1, hdc); - /* test scrolling a window with an update region */ + /* test scrolling a rect by more than its size */ DestroyWindow( hwnd2); ValidateRect( hwnd1, NULL); SetRect( &rc, 40,40, 50,50); InvalidateRect( hwnd1, &rc, 1); + ScrollWindowEx( hwnd1, -20, 0, &rc, NULL, hrgn, &rcu, + SW_SCROLLCHILDREN | SW_INVALIDATE); + if (winetest_debug > 0) dump_region(hrgn); + SetRectRgn( exprgn, 20, 40, 30, 50); + SetRectRgn( tmprgn, 40, 40, 50, 50); + CombineRgn( exprgn, exprgn, tmprgn, RGN_OR); + ok( EqualRgn( exprgn, hrgn), "wrong update region\n"); + ok( rcu.left == 20 && rcu.top == 40 && rcu.right == 50 && rcu.bottom == 50, + "unexpected update rect: %d,%d - %d,%d\n", rcu.left,rcu.top,rcu.right,rcu.bottom); + + /* test scrolling a window with an update region */ + ValidateRect( hwnd1, NULL); + SetRect( &rc, 40,40, 50,50); + InvalidateRect( hwnd1, &rc, 1); GetClientRect( hwnd1, &rc); cliprc=rc; ScrollWindowEx( hwnd1, -10, 0, &rc, &cliprc, hrgn, &rcu, @@ -4999,8 +5344,8 @@ static void zero_parentdc_test(struct parentdc_test *t) t.w.r.f, got.w.r.f) #define parentdc_todo_field_ok(t, w, r, f, got) \ - if (t.w##_todo.r.f) todo_wine { parentdc_field_ok(t, w, r, f, got); } \ - else parentdc_field_ok(t, w, r, f, got) + todo_wine_if (t.w##_todo.r.f) \ + parentdc_field_ok(t, w, r, f, got); #define parentdc_rect_ok(t, w, r, got) \ parentdc_todo_field_ok(t, w, r, left, got); \ @@ -5670,7 +6015,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); expected_cx = expected_cy = -10; - SetRect( &expected_rect, 0, 0, 0, 0 ); + SetRectEmpty(&expected_rect); SetRect( &broken_rect, 0, 0, -10, -10 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -20, -20, -10, -10, parent, 0, 0, NULL); ok( hwnd != 0, "creation failed err %u\n", GetLastError()); @@ -5680,7 +6025,7 @@ static void test_CreateWindow(void) DestroyWindow(hwnd); expected_cx = expected_cy = -200000; - SetRect( &expected_rect, 0, 0, 0, 0 ); + SetRectEmpty(&expected_rect); SetRect( &broken_rect, 0, 0, -200000, -200000 ); hwnd = CreateWindowExA(0, "Sizes_WndClass", NULL, WS_CHILD, -300000, -300000, -200000, -200000, parent, 0, 0, NULL); ok( hwnd != 0, "creation failed err %u\n", GetLastError()); @@ -6232,7 +6577,7 @@ static void test_GetUpdateRect(void) flush_events( TRUE ); ShowWindow(hchild, SW_HIDE); - SetRect(&rc2, 0, 0, 0, 0); + SetRectEmpty(&rc2); ret = GetUpdateRect(hgrandparent, &rc1, FALSE); ok(!ret, "GetUpdateRect returned not empty region\n"); ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d,%d,%d) / (%d,%d,%d,%d)\n", @@ -6296,7 +6641,7 @@ static void test_GetUpdateRect(void) ShowWindow(hchild, SW_HIDE); - SetRect(&rc2, 0, 0, 0, 0); + SetRectEmpty(&rc2); ret = GetUpdateRect(hgrandparent, &rc1, FALSE); ok(!ret, "GetUpdateRect returned not empty region\n"); ok(EqualRect(&rc1, &rc2), "rects do not match (%d,%d,%d,%d) / (%d,%d,%d,%d)\n", @@ -6421,9 +6766,7 @@ static void run_NCRedrawLoop(UINT flags) DispatchMessageA(&msg); MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT); } - if (flags == (RDW_INVALIDATE | RDW_FRAME)) - todo_wine ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags); - else + todo_wine_if (flags == (RDW_INVALIDATE | RDW_FRAME)) ok(loopcount < 100, "Detected infinite WM_PAINT loop (%x).\n", flags); DestroyWindow(hwnd); } @@ -7247,7 +7590,7 @@ static void test_winregion(void) ok( ret == ERROR, "Expected ERROR, got %d\n", ret); ok( GetLastError() == 0xdeadbeef, "Expected , got %d\n", GetLastError()); - r.left = r.top = r.right = r.bottom = 0; + SetRectEmpty(&r); ret = pGetWindowRgnBox(hwnd, &r); ok( ret == SIMPLEREGION, "Expected SIMPLEREGION, got %d\n", ret); ok( r.left == 2 && r.top == 3 && r.right == 10 && r.bottom == 15, @@ -7258,10 +7601,10 @@ static void test_winregion(void) hrgn = CreateRectRgn(2, 3, 10, 15); ret = pMirrorRgn( hwnd, hrgn ); ok( ret == TRUE, "MirrorRgn failed %u\n", ret ); - r.left = r.top = r.right = r.bottom = 0; + SetRectEmpty(&r); GetWindowRect( hwnd, &r ); width = r.right - r.left; - r.left = r.top = r.right = r.bottom = 0; + SetRectEmpty(&r); ret = GetRgnBox( hrgn, &r ); ok( ret == SIMPLEREGION, "GetRgnBox failed %u\n", ret ); ok( r.left == width - 10 && r.top == 3 && r.right == width - 2 && r.bottom == 15, @@ -8662,6 +9005,186 @@ static void test_activateapp(HWND window1) DestroyWindow(window2); } +static LRESULT WINAPI winproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(!hwnd) { + int *count = (int*)lparam; + (*count)++; + } + return 0; +} + +static LRESULT WINAPI winproc_convA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_SETTEXT) + { + const char *text = (const char*)lparam; + + ok(!wparam, "wparam = %08lx\n", wparam); + ok(!strcmp(text, "text"), "WM_SETTEXT lparam = %s\n", text); + return 1; + } + return 0; +} + +static const WCHAR textW[] = {'t','e','x','t',0}; +static LRESULT WINAPI winproc_convW(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if(msg == WM_SETTEXT) + { + const WCHAR *text = (const WCHAR*)lparam; + + ok(!wparam, "wparam = %08lx\n", wparam); + ok(!lstrcmpW(text, textW), "WM_SETTEXT lparam = %s\n", wine_dbgstr_w(text)); + return 1; + } + return 0; +} + +static void test_winproc_handles(const char *argv0) +{ + static const WCHAR winproc_testW[] = {'w','i','n','p','r','o','c','_','t','e','s','t',0}; + + HINSTANCE hinst = GetModuleHandleA(NULL); + WNDCLASSA wnd_classA; + WNDCLASSW wnd_classW; + int count, ret; + PROCESS_INFORMATION info; + STARTUPINFOA startup; + char cmd[MAX_PATH]; + + memset(&wnd_classA, 0, sizeof(wnd_classA)); + wnd_classA.lpszClassName = "winproc_test"; + wnd_classA.lpfnWndProc = winproc; + ret = RegisterClassA(&wnd_classA); + ok(ret, "RegisterClass failed with error %d\n", GetLastError()); + + ret = GetClassInfoW(hinst, winproc_testW, &wnd_classW); + ok(ret, "GetClassInfoW failed with error %d\n", GetLastError()); + ok(wnd_classA.lpfnWndProc != wnd_classW.lpfnWndProc, + "winproc pointers should not be identical\n"); + + count = 0; + CallWindowProcA(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count); + ok(count == 1, "winproc should be called once (%d)\n", count); + count = 0; + CallWindowProcW(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count); + ok(count == 1, "winproc should be called once (%d)\n", count); + + ret = UnregisterClassW(winproc_testW, hinst); + ok(ret, "UnregisterClass failed with error %d\n", GetLastError()); + + /* crashes on 64-bit windows because lpfnWndProc handle is already freed */ + if (sizeof(void*) == 4) + { + count = 0; + CallWindowProcA(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count); + todo_wine ok(!count, "winproc should not be called (%d)\n", count); + CallWindowProcW(wnd_classW.lpfnWndProc, 0, 0, 0, (LPARAM)&count); + todo_wine ok(!count, "winproc should not be called (%d)\n", count); + } + + sprintf(cmd, "%s win winproc_limit", argv0); + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + ok(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, + &startup, &info), "CreateProcess failed.\n"); + winetest_wait_child_process(info.hProcess); + CloseHandle(info.hProcess); + CloseHandle(info.hThread); +} + +static void test_winproc_limit(void) +{ + WNDPROC winproc_handle; + LONG_PTR ret; + HWND hwnd; + int i; + + hwnd = CreateWindowExA(0, "static", "test", WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); + ok(hwnd != 0, "CreateWindowEx failed\n"); + + ok(SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc), + "SetWindowLongPtr failed\n"); + winproc_handle = (WNDPROC)GetWindowLongPtrW(hwnd, GWLP_WNDPROC); + ok(winproc_handle != winproc, "winproc pointers should not be identical\n"); + + /* run out of winproc slots */ + for(i = 2; i<0xffff; i++) + { + ok(SetWindowLongPtrA(hwnd, GWLP_WNDPROC, i), "SetWindowLongPtr failed (%d)\n", i); + if(GetWindowLongPtrW(hwnd, GWLP_WNDPROC) == i) + break; + } + ok(i != 0xffff, "unable to run out of winproc slots\n"); + + ret = SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convA); + ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError()); + ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n"); + ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n"); + + ret = SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)winproc_convW); + ok(ret, "SetWindowLongPtr failed with error %d\n", GetLastError()); + ok(SendMessageA(hwnd, WM_SETTEXT, 0, (LPARAM)"text"), "WM_SETTEXT failed\n"); + ok(SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)textW), "WM_SETTEXT with conversion failed\n"); + + /* Show that there's no message conversion when CallWindowProc is used */ + ok(CallWindowProcA(winproc_convW, hwnd, WM_SETTEXT, 0, (LPARAM)textW) == 1, + "winproc_convW returned error\n"); + ok(CallWindowProcW(winproc_convW, hwnd, WM_SETTEXT, 0, (LPARAM)textW) == 1, + "winproc_convW returned error\n"); + + i = 0; + CallWindowProcA(winproc_handle, 0, 0, 0, (LPARAM)&i); + ok(i == 1, "winproc should be called once (%d)\n", i); + i = 0; + CallWindowProcW(winproc_handle, 0, 0, 0, (LPARAM)&i); + ok(i == 1, "winproc should be called once (%d)\n", i); + + DestroyWindow(hwnd); + + i = 0; + CallWindowProcA(winproc_handle, 0, 0, 0, (LPARAM)&i); + ok(i == 1, "winproc should be called once (%d)\n", i); + i = 0; + CallWindowProcW(winproc_handle, 0, 0, 0, (LPARAM)&i); + ok(i == 1, "winproc should be called once (%d)\n", i); +} + +static void test_deferwindowpos(void) +{ + HDWP hdwp, hdwp2; + BOOL ret; + + hdwp = BeginDeferWindowPos(0); + ok(hdwp != NULL, "got %p\n", hdwp); + + ret = EndDeferWindowPos(NULL); + ok(!ret, "got %d\n", ret); + + hdwp2 = DeferWindowPos(NULL, NULL, NULL, 0, 0, 10, 10, 0); +todo_wine + ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) || + broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError()); + + hdwp2 = DeferWindowPos((HDWP)0xdead, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0); +todo_wine + ok(hdwp2 == NULL && ((GetLastError() == ERROR_INVALID_DWP_HANDLE) || + broken(GetLastError() == ERROR_INVALID_WINDOW_HANDLE) /* before win8 */), "got %p, error %d\n", hdwp2, GetLastError()); + + hdwp2 = DeferWindowPos(hdwp, NULL, NULL, 0, 0, 10, 10, 0); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + + hdwp2 = DeferWindowPos(hdwp, GetDesktopWindow(), NULL, 0, 0, 10, 10, 0); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + + hdwp2 = DeferWindowPos(hdwp, (HWND)0xdead, NULL, 0, 0, 10, 10, 0); + ok(hdwp2 == NULL && GetLastError() == ERROR_INVALID_WINDOW_HANDLE, "got %p, error %d\n", hdwp2, GetLastError()); + + ret = EndDeferWindowPos(hdwp); + ok(ret, "got %d\n", ret); +} + START_TEST(win) { char **argv; @@ -8696,6 +9219,12 @@ START_TEST(win) return; } + if (argc==3 && !strcmp(argv[2], "winproc_limit")) + { + test_winproc_limit(); + return; + } + if (!RegisterWindowClasses()) assert(0); hwndMain = CreateWindowExA(/*WS_EX_TOOLWINDOW*/ 0, "MainWindowClass", "Main window", @@ -8778,6 +9307,7 @@ START_TEST(win) test_AdjustWindowRect(); test_window_styles(); test_dialog_styles(); + test_dialog_parent(); test_redrawnow(); test_csparentdc(); test_SetWindowLong(); @@ -8801,6 +9331,8 @@ START_TEST(win) skip("ROSTESTS-208: Skipping test_activateapp(hwndMain).\n"); else test_activateapp(hwndMain); + test_winproc_handles(argv[0]); + test_deferwindowpos(); /* add the tests above this line */ if (hhook) UnhookWindowsHookEx(hhook);