advapi32: Make rpcrt4 a delayed import to work around circular dependencies with...
[wine/testsucceed.git] / dlls / comctl32 / tests / propsheet.c
blobbfbaaa0e7bd2f35899c27ee7293a6c25f378034d
1 /* Unit test suite for property sheet control.
3 * Copyright 2006 Huw Davies
4 * Copyright 2009 Jan de Mooij
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <windows.h>
22 #include <commctrl.h>
24 #include "resources.h"
26 #include "wine/test.h"
28 static HWND parent;
29 static HWND sheethwnd;
31 static LONG active_page = -1;
33 #define IDC_APPLY_BUTTON 12321
35 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
37 switch(msg)
39 case PSCB_INITIALIZED:
41 char caption[256];
42 GetWindowTextA(hwnd, caption, sizeof(caption));
43 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
44 sheethwnd = hwnd;
45 return 0;
48 return 0;
51 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
52 LPARAM lparam)
54 switch(msg)
56 case WM_INITDIALOG:
58 HWND sheet = GetParent(hwnd);
59 char caption[256];
60 GetWindowTextA(sheet, caption, sizeof(caption));
61 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
62 return TRUE;
65 case WM_NOTIFY:
67 NMHDR *nmhdr = (NMHDR *)lparam;
68 switch(nmhdr->code)
70 case PSN_APPLY:
71 return TRUE;
72 default:
73 return FALSE;
76 case WM_NCDESTROY:
77 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
78 return TRUE;
80 default:
81 return FALSE;
85 static void test_title(void)
87 HPROPSHEETPAGE hpsp[1];
88 PROPSHEETPAGEA psp;
89 PROPSHEETHEADERA psh;
90 HWND hdlg;
92 memset(&psp, 0, sizeof(psp));
93 psp.dwSize = sizeof(psp);
94 psp.dwFlags = 0;
95 psp.hInstance = GetModuleHandleA(NULL);
96 U(psp).pszTemplate = "prop_page1";
97 U2(psp).pszIcon = NULL;
98 psp.pfnDlgProc = page_dlg_proc;
99 psp.lParam = 0;
101 hpsp[0] = CreatePropertySheetPageA(&psp);
103 memset(&psh, 0, sizeof(psh));
104 psh.dwSize = sizeof(psh);
105 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
106 psh.pszCaption = "test caption";
107 psh.nPages = 1;
108 psh.hwndParent = GetDesktopWindow();
109 U3(psh).phpage = hpsp;
110 psh.pfnCallback = sheet_callback;
112 hdlg = (HWND)PropertySheetA(&psh);
113 if (hdlg == INVALID_HANDLE_VALUE)
115 win_skip("comctl32 4.70 needs dwSize adjustment\n");
116 psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
117 hdlg = (HWND)PropertySheetA(&psh);
119 DestroyWindow(hdlg);
122 static void test_nopage(void)
124 HPROPSHEETPAGE hpsp[1];
125 PROPSHEETPAGEA psp;
126 PROPSHEETHEADERA psh;
127 HWND hdlg;
129 memset(&psp, 0, sizeof(psp));
130 psp.dwSize = sizeof(psp);
131 psp.dwFlags = 0;
132 psp.hInstance = GetModuleHandleA(NULL);
133 U(psp).pszTemplate = "prop_page1";
134 U2(psp).pszIcon = NULL;
135 psp.pfnDlgProc = page_dlg_proc;
136 psp.lParam = 0;
138 hpsp[0] = CreatePropertySheetPageA(&psp);
140 memset(&psh, 0, sizeof(psh));
141 psh.dwSize = sizeof(psh);
142 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
143 psh.pszCaption = "test caption";
144 psh.nPages = 1;
145 psh.hwndParent = GetDesktopWindow();
146 U3(psh).phpage = hpsp;
147 psh.pfnCallback = sheet_callback;
149 hdlg = (HWND)PropertySheetA(&psh);
150 if (hdlg == INVALID_HANDLE_VALUE)
152 win_skip("comctl32 4.70 needs dwSize adjustment\n");
153 psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
154 hdlg = (HWND)PropertySheetA(&psh);
156 ShowWindow(hdlg,SW_NORMAL);
157 SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
158 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
159 DestroyWindow(hdlg);
162 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
164 switch(msg)
166 case PSCB_INITIALIZED:
168 ok(IsWindowEnabled(parent) == 0, "parent window should be disabled\n");
169 PostQuitMessage(0);
170 return FALSE;
173 return FALSE;
176 static void register_parent_wnd_class(void)
178 WNDCLASSA cls;
180 cls.style = 0;
181 cls.lpfnWndProc = DefWindowProcA;
182 cls.cbClsExtra = 0;
183 cls.cbWndExtra = 0;
184 cls.hInstance = GetModuleHandleA(NULL);
185 cls.hIcon = 0;
186 cls.hCursor = LoadCursorA(0, IDC_ARROW);
187 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
188 cls.lpszMenuName = NULL;
189 cls.lpszClassName = "parent class";
190 RegisterClassA(&cls);
193 static void test_disableowner(void)
195 HPROPSHEETPAGE hpsp[1];
196 PROPSHEETPAGEA psp;
197 PROPSHEETHEADERA psh;
198 INT_PTR p;
200 register_parent_wnd_class();
201 parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
203 memset(&psp, 0, sizeof(psp));
204 psp.dwSize = sizeof(psp);
205 psp.dwFlags = 0;
206 psp.hInstance = GetModuleHandleA(NULL);
207 U(psp).pszTemplate = "prop_page1";
208 U2(psp).pszIcon = NULL;
209 psp.pfnDlgProc = NULL;
210 psp.lParam = 0;
212 hpsp[0] = CreatePropertySheetPageA(&psp);
214 memset(&psh, 0, sizeof(psh));
215 psh.dwSize = sizeof(psh);
216 psh.dwFlags = PSH_USECALLBACK;
217 psh.pszCaption = "test caption";
218 psh.nPages = 1;
219 psh.hwndParent = parent;
220 U3(psh).phpage = hpsp;
221 psh.pfnCallback = disableowner_callback;
223 p = PropertySheetA(&psh);
224 todo_wine
225 ok(p == 0, "Expected 0, got %ld\n", p);
226 ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n");
227 DestroyWindow(parent);
230 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
232 switch(msg){
233 case WM_NOTIFY:
235 LPNMHDR hdr = (LPNMHDR)lparam;
236 switch(hdr->code){
237 case PSN_SETACTIVE:
238 active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
239 return TRUE;
240 case PSN_KILLACTIVE:
241 /* prevent navigation away from the fourth page */
242 if(active_page == 3){
243 SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
244 return TRUE;
247 break;
250 return FALSE;
253 static void test_wiznavigation(void)
255 HPROPSHEETPAGE hpsp[4];
256 PROPSHEETPAGEA psp[4];
257 PROPSHEETHEADERA psh;
258 HWND hdlg, control;
259 LONG_PTR controlID;
260 LRESULT defidres;
261 BOOL hwndtoindex_supported = TRUE;
262 const INT nextID = 12324;
263 const INT backID = 12323;
265 /* create the property sheet pages */
266 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
268 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
269 psp[0].hInstance = GetModuleHandleA(NULL);
270 U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
271 psp[0].pfnDlgProc = nav_page_proc;
272 hpsp[0] = CreatePropertySheetPageA(&psp[0]);
274 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
275 psp[1].hInstance = GetModuleHandleA(NULL);
276 U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
277 psp[1].pfnDlgProc = nav_page_proc;
278 hpsp[1] = CreatePropertySheetPageA(&psp[1]);
280 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
281 psp[2].hInstance = GetModuleHandleA(NULL);
282 U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
283 psp[2].pfnDlgProc = nav_page_proc;
284 hpsp[2] = CreatePropertySheetPageA(&psp[2]);
286 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
287 psp[3].hInstance = GetModuleHandleA(NULL);
288 U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
289 psp[3].pfnDlgProc = nav_page_proc;
290 hpsp[3] = CreatePropertySheetPageA(&psp[3]);
292 /* set up the property sheet dialog */
293 memset(&psh, 0, sizeof(psh));
294 psh.dwSize = sizeof(psh);
295 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
296 psh.pszCaption = "A Wizard";
297 psh.nPages = 4;
298 psh.hwndParent = GetDesktopWindow();
299 U3(psh).phpage = hpsp;
300 hdlg = (HWND)PropertySheetA(&psh);
301 if (hdlg == INVALID_HANDLE_VALUE)
303 win_skip("comctl32 4.70 needs dwSize adjustment\n");
304 psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
305 hdlg = (HWND)PropertySheetA(&psh);
308 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
310 control = GetFocus();
311 controlID = GetWindowLongPtr(control, GWLP_ID);
312 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
314 /* simulate pressing the Next button */
315 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
316 if (!active_page) hwndtoindex_supported = FALSE;
317 if (hwndtoindex_supported)
318 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
320 control = GetFocus();
321 controlID = GetWindowLongPtr(control, GWLP_ID);
322 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);
324 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
325 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
327 /* set the focus to the second edit box on this page */
328 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
330 /* press next again */
331 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
332 if (hwndtoindex_supported)
333 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
335 control = GetFocus();
336 controlID = GetWindowLongPtr(control, GWLP_ID);
337 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
339 /* back button */
340 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
341 if (hwndtoindex_supported)
342 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
344 control = GetFocus();
345 controlID = GetWindowLongPtr(control, GWLP_ID);
346 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);
348 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
349 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
351 /* press next twice */
352 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
353 if (hwndtoindex_supported)
354 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
355 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
356 if (hwndtoindex_supported)
357 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
358 else
359 active_page = 3;
361 control = GetFocus();
362 controlID = GetWindowLongPtr(control, GWLP_ID);
363 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
365 /* try to navigate away, but shouldn't be able to */
366 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
367 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
369 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
370 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
372 DestroyWindow(hdlg);
375 static void test_buttons(void)
377 HPROPSHEETPAGE hpsp[1];
378 PROPSHEETPAGEA psp;
379 PROPSHEETHEADERA psh;
380 HWND hdlg;
381 HWND button;
382 RECT rc;
383 int prevRight, top;
385 memset(&psp, 0, sizeof(psp));
386 psp.dwSize = sizeof(psp);
387 psp.dwFlags = 0;
388 psp.hInstance = GetModuleHandleA(NULL);
389 U(psp).pszTemplate = "prop_page1";
390 U2(psp).pszIcon = NULL;
391 psp.pfnDlgProc = page_dlg_proc;
392 psp.lParam = 0;
394 hpsp[0] = CreatePropertySheetPageA(&psp);
396 memset(&psh, 0, sizeof(psh));
397 psh.dwSize = sizeof(psh);
398 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
399 psh.pszCaption = "test caption";
400 psh.nPages = 1;
401 psh.hwndParent = GetDesktopWindow();
402 U3(psh).phpage = hpsp;
403 psh.pfnCallback = sheet_callback;
405 hdlg = (HWND)PropertySheetA(&psh);
406 if (hdlg == INVALID_HANDLE_VALUE)
408 win_skip("comctl32 4.70 needs dwSize adjustment\n");
409 psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
410 hdlg = (HWND)PropertySheetA(&psh);
413 /* OK button */
414 button = GetDlgItem(hdlg, IDOK);
415 GetWindowRect(button, &rc);
416 prevRight = rc.right;
417 top = rc.top;
419 /* Cancel button */
420 button = GetDlgItem(hdlg, IDCANCEL);
421 GetWindowRect(button, &rc);
422 ok(rc.top == top, "Cancel button should have same top as OK button\n");
423 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
424 prevRight = rc.right;
426 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
427 GetWindowRect(button, &rc);
428 ok(rc.top == top, "Apply button should have same top as OK button\n");
429 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
430 prevRight = rc.right;
432 button = GetDlgItem(hdlg, IDHELP);
433 GetWindowRect(button, &rc);
434 ok(rc.top == top, "Help button should have same top as OK button\n");
435 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
437 DestroyWindow(hdlg);
440 static BOOL add_button_has_been_pressed;
442 static INT_PTR CALLBACK
443 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
445 switch (msg)
447 case WM_COMMAND:
448 switch(LOWORD(wparam))
450 case IDC_PS_PUSHBUTTON1:
451 switch(HIWORD(wparam))
453 case BN_CLICKED:
454 add_button_has_been_pressed = TRUE;
455 return TRUE;
457 break;
459 break;
461 return FALSE;
464 static void test_custom_default_button(void)
466 HWND hdlg;
467 PROPSHEETPAGEA psp[1];
468 PROPSHEETHEADERA psh;
469 MSG msg;
470 LRESULT result;
472 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
473 psp[0].dwFlags = PSP_USETITLE;
474 psp[0].hInstance = GetModuleHandleA(NULL);
475 U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
476 U2(psp[0]).pszIcon = NULL;
477 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
478 psp[0].pszTitle = "Page1";
479 psp[0].lParam = 0;
481 psh.dwSize = sizeof (PROPSHEETHEADERA);
482 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
483 psh.hwndParent = GetDesktopWindow();
484 psh.hInstance = GetModuleHandleA(NULL);
485 U(psh).pszIcon = NULL;
486 psh.pszCaption = "PropertySheet1";
487 psh.nPages = 1;
488 U3(psh).ppsp = psp;
489 U2(psh).nStartPage = 0;
491 /* The goal of the test is to make sure that the Add button is pressed
492 * when the ENTER key is pressed and a different control, a combobox,
493 * has the keyboard focus. */
494 add_button_has_been_pressed = FALSE;
496 /* Create the modeless property sheet. */
497 hdlg = (HWND)PropertySheetA(&psh);
498 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
500 /* Set the Add button as the default button. */
501 SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
503 /* Make sure the default button is the Add button. */
504 result = SendMessage(hdlg, DM_GETDEFID, 0, 0);
505 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
506 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
508 /* At this point, the combobox should have keyboard focus, so we press ENTER.
509 * Pull the lever, Kronk! */
510 keybd_event(VK_RETURN, 0, 0, 0);
512 /* Process all the messages in the queue for this thread. */
513 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
515 if (!PropSheet_IsDialogMessage(hdlg, &msg))
517 TranslateMessage(&msg);
518 DispatchMessage(&msg);
522 todo_wine
523 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
525 DestroyWindow(hdlg);
528 START_TEST(propsheet)
530 test_title();
531 test_nopage();
532 test_disableowner();
533 test_wiznavigation();
534 test_buttons();
535 test_custom_default_button();