| /* Unit test suite for property sheet control. |
| * |
| * Copyright 2006 Huw Davies |
| * Copyright 2009 Jan de Mooij |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <windows.h> |
| #include <commctrl.h> |
| |
| #include "resources.h" |
| |
| #include "wine/test.h" |
| |
| static HWND parent; |
| static HWND sheethwnd; |
| |
| static LONG active_page = -1; |
| |
| #define IDC_APPLY_BUTTON 12321 |
| |
| static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) |
| { |
| switch(msg) |
| { |
| case PSCB_INITIALIZED: |
| { |
| char caption[256]; |
| GetWindowTextA(hwnd, caption, sizeof(caption)); |
| ok(!strcmp(caption,"test caption"), "caption: %s\n", caption); |
| sheethwnd = hwnd; |
| return 0; |
| } |
| } |
| return 0; |
| } |
| |
| static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, |
| LPARAM lparam) |
| { |
| switch(msg) |
| { |
| case WM_INITDIALOG: |
| { |
| HWND sheet = GetParent(hwnd); |
| char caption[256]; |
| GetWindowTextA(sheet, caption, sizeof(caption)); |
| ok(!strcmp(caption,"test caption"), "caption: %s\n", caption); |
| return TRUE; |
| } |
| |
| case WM_NOTIFY: |
| { |
| NMHDR *nmhdr = (NMHDR *)lparam; |
| switch(nmhdr->code) |
| { |
| case PSN_APPLY: |
| return TRUE; |
| default: |
| return FALSE; |
| } |
| } |
| case WM_NCDESTROY: |
| ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n"); |
| return TRUE; |
| |
| default: |
| return FALSE; |
| } |
| } |
| |
| static void test_title(void) |
| { |
| HPROPSHEETPAGE hpsp[1]; |
| PROPSHEETPAGEA psp; |
| PROPSHEETHEADERA psh; |
| HWND hdlg; |
| |
| memset(&psp, 0, sizeof(psp)); |
| psp.dwSize = sizeof(psp); |
| psp.dwFlags = 0; |
| psp.hInstance = GetModuleHandleA(NULL); |
| U(psp).pszTemplate = "prop_page1"; |
| U2(psp).pszIcon = NULL; |
| psp.pfnDlgProc = page_dlg_proc; |
| psp.lParam = 0; |
| |
| hpsp[0] = CreatePropertySheetPageA(&psp); |
| |
| memset(&psh, 0, sizeof(psh)); |
| psh.dwSize = sizeof(psh); |
| psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; |
| psh.pszCaption = "test caption"; |
| psh.nPages = 1; |
| psh.hwndParent = GetDesktopWindow(); |
| U3(psh).phpage = hpsp; |
| psh.pfnCallback = sheet_callback; |
| |
| hdlg = (HWND)PropertySheetA(&psh); |
| if (hdlg == INVALID_HANDLE_VALUE) |
| { |
| win_skip("comctl32 4.70 needs dwSize adjustment\n"); |
| psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); |
| hdlg = (HWND)PropertySheetA(&psh); |
| } |
| DestroyWindow(hdlg); |
| } |
| |
| static void test_nopage(void) |
| { |
| HPROPSHEETPAGE hpsp[1]; |
| PROPSHEETPAGEA psp; |
| PROPSHEETHEADERA psh; |
| HWND hdlg; |
| |
| memset(&psp, 0, sizeof(psp)); |
| psp.dwSize = sizeof(psp); |
| psp.dwFlags = 0; |
| psp.hInstance = GetModuleHandleA(NULL); |
| U(psp).pszTemplate = "prop_page1"; |
| U2(psp).pszIcon = NULL; |
| psp.pfnDlgProc = page_dlg_proc; |
| psp.lParam = 0; |
| |
| hpsp[0] = CreatePropertySheetPageA(&psp); |
| |
| memset(&psh, 0, sizeof(psh)); |
| psh.dwSize = sizeof(psh); |
| psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; |
| psh.pszCaption = "test caption"; |
| psh.nPages = 1; |
| psh.hwndParent = GetDesktopWindow(); |
| U3(psh).phpage = hpsp; |
| psh.pfnCallback = sheet_callback; |
| |
| hdlg = (HWND)PropertySheetA(&psh); |
| if (hdlg == INVALID_HANDLE_VALUE) |
| { |
| win_skip("comctl32 4.70 needs dwSize adjustment\n"); |
| psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); |
| hdlg = (HWND)PropertySheetA(&psh); |
| } |
| ShowWindow(hdlg,SW_NORMAL); |
| SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0); |
| RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); |
| DestroyWindow(hdlg); |
| } |
| |
| static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam) |
| { |
| switch(msg) |
| { |
| case PSCB_INITIALIZED: |
| { |
| ok(IsWindowEnabled(parent) == 0, "parent window should be disabled\n"); |
| PostQuitMessage(0); |
| return FALSE; |
| } |
| } |
| return FALSE; |
| } |
| |
| static void register_parent_wnd_class(void) |
| { |
| WNDCLASSA cls; |
| |
| cls.style = 0; |
| cls.lpfnWndProc = DefWindowProcA; |
| cls.cbClsExtra = 0; |
| cls.cbWndExtra = 0; |
| cls.hInstance = GetModuleHandleA(NULL); |
| cls.hIcon = 0; |
| cls.hCursor = LoadCursorA(0, IDC_ARROW); |
| cls.hbrBackground = GetStockObject(WHITE_BRUSH); |
| cls.lpszMenuName = NULL; |
| cls.lpszClassName = "parent class"; |
| RegisterClassA(&cls); |
| } |
| |
| static void test_disableowner(void) |
| { |
| HPROPSHEETPAGE hpsp[1]; |
| PROPSHEETPAGEA psp; |
| PROPSHEETHEADERA psh; |
| INT_PTR p; |
| |
| register_parent_wnd_class(); |
| parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0); |
| |
| memset(&psp, 0, sizeof(psp)); |
| psp.dwSize = sizeof(psp); |
| psp.dwFlags = 0; |
| psp.hInstance = GetModuleHandleA(NULL); |
| U(psp).pszTemplate = "prop_page1"; |
| U2(psp).pszIcon = NULL; |
| psp.pfnDlgProc = NULL; |
| psp.lParam = 0; |
| |
| hpsp[0] = CreatePropertySheetPageA(&psp); |
| |
| memset(&psh, 0, sizeof(psh)); |
| psh.dwSize = sizeof(psh); |
| psh.dwFlags = PSH_USECALLBACK; |
| psh.pszCaption = "test caption"; |
| psh.nPages = 1; |
| psh.hwndParent = parent; |
| U3(psh).phpage = hpsp; |
| psh.pfnCallback = disableowner_callback; |
| |
| p = PropertySheetA(&psh); |
| todo_wine |
| ok(p == 0, "Expected 0, got %ld\n", p); |
| ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n"); |
| DestroyWindow(parent); |
| } |
| |
| static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) |
| { |
| switch(msg){ |
| case WM_NOTIFY: |
| { |
| LPNMHDR hdr = (LPNMHDR)lparam; |
| switch(hdr->code){ |
| case PSN_SETACTIVE: |
| active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); |
| return TRUE; |
| case PSN_KILLACTIVE: |
| /* prevent navigation away from the fourth page */ |
| if(active_page == 3){ |
| SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE); |
| return TRUE; |
| } |
| } |
| break; |
| } |
| } |
| return FALSE; |
| } |
| |
| static void test_wiznavigation(void) |
| { |
| HPROPSHEETPAGE hpsp[4]; |
| PROPSHEETPAGEA psp[4]; |
| PROPSHEETHEADERA psh; |
| HWND hdlg, control; |
| LONG_PTR controlID; |
| LRESULT defidres; |
| BOOL hwndtoindex_supported = TRUE; |
| const INT nextID = 12324; |
| const INT backID = 12323; |
| |
| /* create the property sheet pages */ |
| memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4); |
| |
| psp[0].dwSize = sizeof(PROPSHEETPAGEA); |
| psp[0].hInstance = GetModuleHandleA(NULL); |
| U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO); |
| psp[0].pfnDlgProc = nav_page_proc; |
| hpsp[0] = CreatePropertySheetPageA(&psp[0]); |
| |
| psp[1].dwSize = sizeof(PROPSHEETPAGEA); |
| psp[1].hInstance = GetModuleHandleA(NULL); |
| U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT); |
| psp[1].pfnDlgProc = nav_page_proc; |
| hpsp[1] = CreatePropertySheetPageA(&psp[1]); |
| |
| psp[2].dwSize = sizeof(PROPSHEETPAGEA); |
| psp[2].hInstance = GetModuleHandleA(NULL); |
| U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO); |
| psp[2].pfnDlgProc = nav_page_proc; |
| hpsp[2] = CreatePropertySheetPageA(&psp[2]); |
| |
| psp[3].dwSize = sizeof(PROPSHEETPAGEA); |
| psp[3].hInstance = GetModuleHandleA(NULL); |
| U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT); |
| psp[3].pfnDlgProc = nav_page_proc; |
| hpsp[3] = CreatePropertySheetPageA(&psp[3]); |
| |
| /* set up the property sheet dialog */ |
| memset(&psh, 0, sizeof(psh)); |
| psh.dwSize = sizeof(psh); |
| psh.dwFlags = PSH_MODELESS | PSH_WIZARD; |
| psh.pszCaption = "A Wizard"; |
| psh.nPages = 4; |
| psh.hwndParent = GetDesktopWindow(); |
| U3(psh).phpage = hpsp; |
| hdlg = (HWND)PropertySheetA(&psh); |
| if (hdlg == INVALID_HANDLE_VALUE) |
| { |
| win_skip("comctl32 4.70 needs dwSize adjustment\n"); |
| psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); |
| hdlg = (HWND)PropertySheetA(&psh); |
| } |
| |
| ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page); |
| |
| control = GetFocus(); |
| controlID = GetWindowLongPtr(control, GWLP_ID); |
| ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); |
| |
| /* simulate pressing the Next button */ |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); |
| if (!active_page) hwndtoindex_supported = FALSE; |
| if (hwndtoindex_supported) |
| ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page); |
| |
| control = GetFocus(); |
| controlID = GetWindowLongPtr(control, GWLP_ID); |
| ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID); |
| |
| defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); |
| ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); |
| |
| /* set the focus to the second edit box on this page */ |
| SetFocus(GetNextDlgTabItem(hdlg, control, FALSE)); |
| |
| /* press next again */ |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); |
| if (hwndtoindex_supported) |
| ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); |
| |
| control = GetFocus(); |
| controlID = GetWindowLongPtr(control, GWLP_ID); |
| ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID); |
| |
| /* back button */ |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); |
| if (hwndtoindex_supported) |
| ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page); |
| |
| control = GetFocus(); |
| controlID = GetWindowLongPtr(control, GWLP_ID); |
| ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID); |
| |
| defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); |
| ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres)); |
| |
| /* press next twice */ |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); |
| if (hwndtoindex_supported) |
| ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); |
| if (hwndtoindex_supported) |
| ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page); |
| else |
| active_page = 3; |
| |
| control = GetFocus(); |
| controlID = GetWindowLongPtr(control, GWLP_ID); |
| ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); |
| |
| /* try to navigate away, but shouldn't be able to */ |
| SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); |
| ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page); |
| |
| defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0); |
| ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); |
| |
| DestroyWindow(hdlg); |
| } |
| |
| static void test_buttons(void) |
| { |
| HPROPSHEETPAGE hpsp[1]; |
| PROPSHEETPAGEA psp; |
| PROPSHEETHEADERA psh; |
| HWND hdlg; |
| HWND button; |
| RECT rc; |
| int prevRight, top; |
| |
| memset(&psp, 0, sizeof(psp)); |
| psp.dwSize = sizeof(psp); |
| psp.dwFlags = 0; |
| psp.hInstance = GetModuleHandleA(NULL); |
| U(psp).pszTemplate = "prop_page1"; |
| U2(psp).pszIcon = NULL; |
| psp.pfnDlgProc = page_dlg_proc; |
| psp.lParam = 0; |
| |
| hpsp[0] = CreatePropertySheetPageA(&psp); |
| |
| memset(&psh, 0, sizeof(psh)); |
| psh.dwSize = sizeof(psh); |
| psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; |
| psh.pszCaption = "test caption"; |
| psh.nPages = 1; |
| psh.hwndParent = GetDesktopWindow(); |
| U3(psh).phpage = hpsp; |
| psh.pfnCallback = sheet_callback; |
| |
| hdlg = (HWND)PropertySheetA(&psh); |
| if (hdlg == INVALID_HANDLE_VALUE) |
| { |
| win_skip("comctl32 4.70 needs dwSize adjustment\n"); |
| psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP); |
| hdlg = (HWND)PropertySheetA(&psh); |
| } |
| |
| /* OK button */ |
| button = GetDlgItem(hdlg, IDOK); |
| GetWindowRect(button, &rc); |
| prevRight = rc.right; |
| top = rc.top; |
| |
| /* Cancel button */ |
| button = GetDlgItem(hdlg, IDCANCEL); |
| GetWindowRect(button, &rc); |
| ok(rc.top == top, "Cancel button should have same top as OK button\n"); |
| ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n"); |
| prevRight = rc.right; |
| |
| button = GetDlgItem(hdlg, IDC_APPLY_BUTTON); |
| GetWindowRect(button, &rc); |
| ok(rc.top == top, "Apply button should have same top as OK button\n"); |
| ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n"); |
| prevRight = rc.right; |
| |
| button = GetDlgItem(hdlg, IDHELP); |
| GetWindowRect(button, &rc); |
| ok(rc.top == top, "Help button should have same top as OK button\n"); |
| ok(rc.left > prevRight, "Help button should be to the right of Apply button\n"); |
| |
| DestroyWindow(hdlg); |
| } |
| |
| static BOOL add_button_has_been_pressed; |
| |
| static INT_PTR CALLBACK |
| page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) |
| { |
| switch (msg) |
| { |
| case WM_COMMAND: |
| switch(LOWORD(wparam)) |
| { |
| case IDC_PS_PUSHBUTTON1: |
| switch(HIWORD(wparam)) |
| { |
| case BN_CLICKED: |
| add_button_has_been_pressed = TRUE; |
| return TRUE; |
| } |
| break; |
| } |
| break; |
| } |
| return FALSE; |
| } |
| |
| static void test_custom_default_button(void) |
| { |
| HWND hdlg; |
| PROPSHEETPAGEA psp[1]; |
| PROPSHEETHEADERA psh; |
| MSG msg; |
| LRESULT result; |
| |
| psp[0].dwSize = sizeof (PROPSHEETPAGEA); |
| psp[0].dwFlags = PSP_USETITLE; |
| psp[0].hInstance = GetModuleHandleA(NULL); |
| U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON); |
| U2(psp[0]).pszIcon = NULL; |
| psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc; |
| psp[0].pszTitle = "Page1"; |
| psp[0].lParam = 0; |
| |
| psh.dwSize = sizeof (PROPSHEETHEADERA); |
| psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; |
| psh.hwndParent = GetDesktopWindow(); |
| psh.hInstance = GetModuleHandleA(NULL); |
| U(psh).pszIcon = NULL; |
| psh.pszCaption = "PropertySheet1"; |
| psh.nPages = 1; |
| U3(psh).ppsp = psp; |
| U2(psh).nStartPage = 0; |
| |
| /* The goal of the test is to make sure that the Add button is pressed |
| * when the ENTER key is pressed and a different control, a combobox, |
| * has the keyboard focus. */ |
| add_button_has_been_pressed = FALSE; |
| |
| /* Create the modeless property sheet. */ |
| hdlg = (HWND)PropertySheetA(&psh); |
| ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n"); |
| |
| /* Set the Add button as the default button. */ |
| SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0); |
| |
| /* Make sure the default button is the Add button. */ |
| result = SendMessage(hdlg, DM_GETDEFID, 0, 0); |
| ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n"); |
| ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n"); |
| |
| /* At this point, the combobox should have keyboard focus, so we press ENTER. |
| * Pull the lever, Kronk! */ |
| keybd_event(VK_RETURN, 0, 0, 0); |
| |
| /* Process all the messages in the queue for this thread. */ |
| while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) |
| { |
| if (!PropSheet_IsDialogMessage(hdlg, &msg)) |
| { |
| TranslateMessage(&msg); |
| DispatchMessage(&msg); |
| } |
| } |
| |
| todo_wine |
| ok(add_button_has_been_pressed, "The Add button has not been pressed!\n"); |
| |
| DestroyWindow(hdlg); |
| } |
| |
| START_TEST(propsheet) |
| { |
| test_title(); |
| test_nopage(); |
| test_disableowner(); |
| test_wiznavigation(); |
| test_buttons(); |
| test_custom_default_button(); |
| } |