comctl32: Don't ignore page creation error for a non-modal propery sheet.
[wine.git] / dlls / comctl32 / tests / propsheet.c
blobea9b4a8e6266f3db6ad3b926ef6acbf4e4ec09b9
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>
23 #include "msg.h"
25 #include "resources.h"
27 #include "wine/test.h"
29 static HWND parenthwnd;
30 static HWND sheethwnd;
32 static BOOL rtl;
33 static LONG active_page = -1;
35 #define IDC_APPLY_BUTTON 12321
37 static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageA)(const PROPSHEETPAGEA *desc);
38 static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageW)(const PROPSHEETPAGEW *desc);
39 static BOOL (WINAPI *pDestroyPropertySheetPage)(HPROPSHEETPAGE proppage);
40 static INT_PTR (WINAPI *pPropertySheetA)(const PROPSHEETHEADERA *header);
42 static void detect_locale(void)
44 DWORD reading_layout;
45 rtl = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER,
46 (void *)&reading_layout, sizeof(reading_layout)) && reading_layout == 1;
49 /* try to make sure pending X events have been processed before continuing */
50 static void flush_events(void)
52 MSG msg;
53 int diff = 200;
54 int min_timeout = 100;
55 DWORD time = GetTickCount() + diff;
57 while (diff > 0)
59 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
60 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
61 diff = time - GetTickCount();
66 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
68 switch(msg)
70 case PSCB_PRECREATE:
72 HMODULE module = GetModuleHandleA("comctl32.dll");
73 DWORD size, buffer_size;
74 HRSRC hrsrc;
76 hrsrc = FindResourceA(module, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */),
77 (LPSTR)RT_DIALOG);
78 size = SizeofResource(module, hrsrc);
79 ok(size != 0, "Failed to get size of propsheet dialog resource\n");
80 buffer_size = HeapSize(GetProcessHeap(), 0, (void *)lparam);
81 ok(buffer_size == 2 * size, "Unexpected template buffer size %u, resource size %u\n",
82 buffer_size, size);
83 break;
85 case PSCB_INITIALIZED:
87 char caption[256];
88 GetWindowTextA(hwnd, caption, sizeof(caption));
89 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
90 sheethwnd = hwnd;
91 return 0;
94 return 0;
97 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
98 LPARAM lparam)
100 switch(msg)
102 case WM_INITDIALOG:
104 HWND sheet = GetParent(hwnd);
105 char caption[256];
106 GetWindowTextA(sheet, caption, sizeof(caption));
107 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
108 return TRUE;
111 case WM_NOTIFY:
113 NMHDR *nmhdr = (NMHDR *)lparam;
114 switch(nmhdr->code)
116 case PSN_APPLY:
117 return TRUE;
118 default:
119 return FALSE;
122 case WM_NCDESTROY:
123 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
124 return TRUE;
126 default:
127 return FALSE;
131 static void test_title(void)
133 HPROPSHEETPAGE hpsp[1];
134 PROPSHEETPAGEA psp;
135 PROPSHEETHEADERA psh;
136 HWND hdlg;
137 DWORD style;
139 memset(&psp, 0, sizeof(psp));
140 psp.dwSize = sizeof(psp);
141 psp.dwFlags = 0;
142 psp.hInstance = GetModuleHandleA(NULL);
143 U(psp).pszTemplate = "prop_page1";
144 U2(psp).pszIcon = NULL;
145 psp.pfnDlgProc = page_dlg_proc;
146 psp.lParam = 0;
148 hpsp[0] = pCreatePropertySheetPageA(&psp);
150 memset(&psh, 0, sizeof(psh));
151 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
152 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
153 psh.pszCaption = "test caption";
154 psh.nPages = 1;
155 psh.hwndParent = GetDesktopWindow();
156 U3(psh).phpage = hpsp;
157 psh.pfnCallback = sheet_callback;
159 hdlg = (HWND)pPropertySheetA(&psh);
160 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
162 style = GetWindowLongA(hdlg, GWL_STYLE);
163 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|
164 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
165 "got unexpected style: %x\n", style);
167 DestroyWindow(hdlg);
170 static void test_nopage(void)
172 HPROPSHEETPAGE hpsp[1];
173 PROPSHEETPAGEA psp;
174 PROPSHEETHEADERA psh;
175 HWND hdlg, hpage;
176 MSG msg;
178 memset(&psp, 0, sizeof(psp));
179 psp.dwSize = sizeof(psp);
180 psp.dwFlags = 0;
181 psp.hInstance = GetModuleHandleA(NULL);
182 U(psp).pszTemplate = "prop_page1";
183 U2(psp).pszIcon = NULL;
184 psp.pfnDlgProc = page_dlg_proc;
185 psp.lParam = 0;
187 hpsp[0] = pCreatePropertySheetPageA(&psp);
189 memset(&psh, 0, sizeof(psh));
190 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
191 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
192 psh.pszCaption = "test caption";
193 psh.nPages = 1;
194 psh.hwndParent = GetDesktopWindow();
195 U3(psh).phpage = hpsp;
196 psh.pfnCallback = sheet_callback;
198 hdlg = (HWND)pPropertySheetA(&psh);
199 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
201 ShowWindow(hdlg,SW_NORMAL);
202 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0);
203 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */
204 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
205 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */
206 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0);
207 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, active_page);
208 flush_events();
209 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
211 /* Check that the property sheet was fully redrawn */
212 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
213 "expected no pending WM_PAINT messages\n");
214 DestroyWindow(hdlg);
217 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
219 switch(msg)
221 case PSCB_INITIALIZED:
223 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
224 PostQuitMessage(0);
225 return FALSE;
228 return FALSE;
231 static void register_parent_wnd_class(void)
233 WNDCLASSA cls;
235 cls.style = 0;
236 cls.lpfnWndProc = DefWindowProcA;
237 cls.cbClsExtra = 0;
238 cls.cbWndExtra = 0;
239 cls.hInstance = GetModuleHandleA(NULL);
240 cls.hIcon = 0;
241 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
242 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
243 cls.lpszMenuName = NULL;
244 cls.lpszClassName = "parent class";
245 RegisterClassA(&cls);
248 static void test_disableowner(void)
250 HPROPSHEETPAGE hpsp[1];
251 PROPSHEETPAGEA psp;
252 PROPSHEETHEADERA psh;
253 INT_PTR p;
255 register_parent_wnd_class();
256 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
258 memset(&psp, 0, sizeof(psp));
259 psp.dwSize = sizeof(psp);
260 psp.dwFlags = 0;
261 psp.hInstance = GetModuleHandleA(NULL);
262 U(psp).pszTemplate = "prop_page1";
263 U2(psp).pszIcon = NULL;
264 psp.pfnDlgProc = NULL;
265 psp.lParam = 0;
267 hpsp[0] = pCreatePropertySheetPageA(&psp);
269 memset(&psh, 0, sizeof(psh));
270 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
271 psh.dwFlags = PSH_USECALLBACK;
272 psh.pszCaption = "test caption";
273 psh.nPages = 1;
274 psh.hwndParent = parenthwnd;
275 U3(psh).phpage = hpsp;
276 psh.pfnCallback = disableowner_callback;
278 p = pPropertySheetA(&psh);
279 ok(p == 0, "Expected 0, got %ld\n", p);
280 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
281 DestroyWindow(parenthwnd);
284 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
286 switch(msg){
287 case WM_NOTIFY:
289 LPNMHDR hdr = (LPNMHDR)lparam;
290 switch(hdr->code){
291 case PSN_SETACTIVE:
292 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
293 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0);
294 return TRUE;
295 case PSN_KILLACTIVE:
296 /* prevent navigation away from the fourth page */
297 if(active_page == 3){
298 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE);
299 return TRUE;
302 break;
305 return FALSE;
308 static WNDPROC old_nav_dialog_proc;
310 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
312 switch (msg)
314 case DM_SETDEFID:
315 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" );
316 break;
318 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp );
321 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
323 static BOOL done;
324 if (code == HCBT_CREATEWND)
326 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp;
328 /* The first dialog created will be the parent dialog */
329 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG)
331 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc );
332 done = TRUE;
336 return CallNextHookEx( NULL, code, wp, lp );
339 static void test_wiznavigation(void)
341 HPROPSHEETPAGE hpsp[4];
342 PROPSHEETPAGEA psp[4];
343 PROPSHEETHEADERA psh;
344 HWND hdlg, control;
345 LONG_PTR controlID;
346 DWORD style;
347 LRESULT defidres;
348 BOOL hwndtoindex_supported = TRUE;
349 const INT nextID = 12324;
350 const INT backID = 12323;
351 HHOOK hook;
353 /* set up a hook proc in order to subclass the main dialog early on */
354 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
356 /* create the property sheet pages */
357 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
359 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
360 psp[0].hInstance = GetModuleHandleA(NULL);
361 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
362 psp[0].pfnDlgProc = nav_page_proc;
363 hpsp[0] = pCreatePropertySheetPageA(&psp[0]);
365 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
366 psp[1].hInstance = GetModuleHandleA(NULL);
367 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
368 psp[1].pfnDlgProc = nav_page_proc;
369 hpsp[1] = pCreatePropertySheetPageA(&psp[1]);
371 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
372 psp[2].hInstance = GetModuleHandleA(NULL);
373 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
374 psp[2].pfnDlgProc = nav_page_proc;
375 hpsp[2] = pCreatePropertySheetPageA(&psp[2]);
377 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
378 psp[3].hInstance = GetModuleHandleA(NULL);
379 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
380 psp[3].pfnDlgProc = nav_page_proc;
381 hpsp[3] = pCreatePropertySheetPageA(&psp[3]);
383 /* set up the property sheet dialog */
384 memset(&psh, 0, sizeof(psh));
385 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
386 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
387 psh.pszCaption = "A Wizard";
388 psh.nPages = 4;
389 psh.hwndParent = GetDesktopWindow();
390 U3(psh).phpage = hpsp;
391 hdlg = (HWND)pPropertySheetA(&psh);
392 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
394 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
396 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
397 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
398 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
399 "got unexpected style: %x\n", style);
401 control = GetFocus();
402 controlID = GetWindowLongPtrA(control, GWLP_ID);
403 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
405 /* simulate pressing the Next button */
406 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
407 if (!active_page) hwndtoindex_supported = FALSE;
408 if (hwndtoindex_supported)
409 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
411 control = GetFocus();
412 controlID = GetWindowLongPtrA(control, GWLP_ID);
413 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);
415 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
416 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
418 /* set the focus to the second edit box on this page */
419 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
421 /* press next again */
422 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
423 if (hwndtoindex_supported)
424 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
426 control = GetFocus();
427 controlID = GetWindowLongPtrA(control, GWLP_ID);
428 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
430 /* back button */
431 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
432 if (hwndtoindex_supported)
433 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
435 control = GetFocus();
436 controlID = GetWindowLongPtrA(control, GWLP_ID);
437 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);
439 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
440 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
442 /* press next twice */
443 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
444 if (hwndtoindex_supported)
445 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
446 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
447 if (hwndtoindex_supported)
448 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
449 else
450 active_page = 3;
452 control = GetFocus();
453 controlID = GetWindowLongPtrA(control, GWLP_ID);
454 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
456 /* try to navigate away, but shouldn't be able to */
457 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
458 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
460 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
461 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
463 DestroyWindow(hdlg);
464 UnhookWindowsHookEx( hook );
467 static void test_buttons(void)
469 HPROPSHEETPAGE hpsp[1];
470 PROPSHEETPAGEA psp;
471 PROPSHEETHEADERA psh;
472 HWND hdlg;
473 HWND button;
474 RECT rc;
475 int prevRight, top;
477 memset(&psp, 0, sizeof(psp));
478 psp.dwSize = sizeof(psp);
479 psp.dwFlags = 0;
480 psp.hInstance = GetModuleHandleA(NULL);
481 U(psp).pszTemplate = "prop_page1";
482 U2(psp).pszIcon = NULL;
483 psp.pfnDlgProc = page_dlg_proc;
484 psp.lParam = 0;
486 hpsp[0] = pCreatePropertySheetPageA(&psp);
488 memset(&psh, 0, sizeof(psh));
489 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
490 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
491 psh.pszCaption = "test caption";
492 psh.nPages = 1;
493 psh.hwndParent = GetDesktopWindow();
494 U3(psh).phpage = hpsp;
495 psh.pfnCallback = sheet_callback;
497 hdlg = (HWND)pPropertySheetA(&psh);
498 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
500 /* OK button */
501 button = GetDlgItem(hdlg, IDOK);
502 GetWindowRect(button, &rc);
503 prevRight = rc.right;
504 top = rc.top;
506 /* Cancel button */
507 button = GetDlgItem(hdlg, IDCANCEL);
508 GetWindowRect(button, &rc);
509 ok(rc.top == top, "Cancel button should have same top as OK button\n");
510 if (rtl)
511 ok(rc.left < prevRight, "Cancel button should be to the left of OK button\n");
512 else
513 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
514 prevRight = rc.right;
516 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
517 GetWindowRect(button, &rc);
518 ok(rc.top == top, "Apply button should have same top as OK button\n");
519 if (rtl)
520 ok(rc.left < prevRight, "Apply button should be to the left of Cancel button\n");
521 else
522 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
523 prevRight = rc.right;
525 button = GetDlgItem(hdlg, IDHELP);
526 GetWindowRect(button, &rc);
527 ok(rc.top == top, "Help button should have same top as OK button\n");
528 if (rtl)
529 ok(rc.left < prevRight, "Help button should be to the left of Apply button\n");
530 else
531 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
533 DestroyWindow(hdlg);
536 static BOOL add_button_has_been_pressed;
538 static INT_PTR CALLBACK
539 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
541 switch (msg)
543 case WM_COMMAND:
544 switch(LOWORD(wparam))
546 case IDC_PS_PUSHBUTTON1:
547 switch(HIWORD(wparam))
549 case BN_CLICKED:
550 add_button_has_been_pressed = TRUE;
551 return TRUE;
553 break;
555 break;
557 return FALSE;
560 static void test_custom_default_button(void)
562 HWND hdlg, page;
563 PROPSHEETPAGEA psp[1];
564 PROPSHEETHEADERA psh;
565 MSG msg;
566 LRESULT result;
568 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
569 psp[0].dwFlags = PSP_USETITLE;
570 psp[0].hInstance = GetModuleHandleA(NULL);
571 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
572 U2(psp[0]).pszIcon = NULL;
573 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
574 psp[0].pszTitle = "Page1";
575 psp[0].lParam = 0;
577 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
578 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
579 psh.hwndParent = GetDesktopWindow();
580 psh.hInstance = GetModuleHandleA(NULL);
581 U(psh).pszIcon = NULL;
582 psh.pszCaption = "PropertySheet1";
583 psh.nPages = 1;
584 U3(psh).ppsp = psp;
585 U2(psh).nStartPage = 0;
587 /* The goal of the test is to make sure that the Add button is pressed
588 * when the ENTER key is pressed and a different control, a combobox,
589 * has the keyboard focus. */
590 add_button_has_been_pressed = FALSE;
592 /* Create the modeless property sheet. */
593 hdlg = (HWND)pPropertySheetA(&psh);
594 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
596 /* Set the Add button as the default button. */
597 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
599 /* Make sure the default button is the Add button. */
600 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
601 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
602 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
604 /* At this point, the combobox should have keyboard focus, so we press ENTER.
605 * Pull the lever, Kronk! */
606 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
607 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0);
609 /* Process all the messages in the queue for this thread. */
610 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
612 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */
613 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg)))
615 TranslateMessage(&msg);
616 DispatchMessageA(&msg);
620 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
622 DestroyWindow(hdlg);
625 #define RECEIVER_SHEET_CALLBACK 0
626 #define RECEIVER_SHEET_WINPROC 1
627 #define RECEIVER_PAGE 2
629 #define NUM_MSG_SEQUENCES 1
630 #define PROPSHEET_SEQ_INDEX 0
632 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
633 static WNDPROC oldWndProc;
635 static const struct message property_sheet_seq[] = {
636 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
637 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
638 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
639 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
640 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
641 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
642 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
643 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
644 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
645 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
646 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
647 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
648 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
649 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
650 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
651 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
652 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
653 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
654 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
655 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
656 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
657 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
658 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
659 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
660 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
661 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
662 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
663 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
664 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
665 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
666 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
667 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
668 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
669 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
670 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
671 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
672 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
673 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
674 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
675 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
676 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
677 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
678 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
679 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
680 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
681 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
682 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
683 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
684 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
685 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
686 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
687 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
688 /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
689 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
690 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
691 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
692 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
693 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
694 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
695 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
696 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
697 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
698 { WM_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
699 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
700 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
701 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
702 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
703 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
704 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
705 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
706 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
707 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
708 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
709 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
710 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
711 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
712 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
713 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
714 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
715 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
716 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
717 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
718 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
719 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
720 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
721 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
722 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
723 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
724 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
725 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
726 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
727 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
728 { 0 }
731 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
733 struct message msg = { 0 };
735 if (message < WM_USER &&
736 message != WM_GETICON &&
737 message != WM_GETTEXT &&
738 message != WM_IME_SETCONTEXT &&
739 message != WM_IME_NOTIFY &&
740 message != WM_PAINT &&
741 message != WM_ERASEBKGND &&
742 message != WM_SETCURSOR &&
743 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
744 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
745 message != 0x90)
747 msg.message = message;
748 msg.flags = sent|wparam|lparam|id;
749 msg.wParam = wParam;
750 msg.lParam = lParam;
751 msg.id = receiver;
752 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
756 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
758 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
760 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
763 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
765 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
767 switch (msg)
769 case PSCB_INITIALIZED:
770 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
771 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
772 return TRUE;
775 return TRUE;
778 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
779 LPARAM lParam)
781 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
783 return FALSE;
786 static void test_messages(void)
788 HPROPSHEETPAGE hpsp[1];
789 PROPSHEETPAGEA psp;
790 PROPSHEETHEADERA psh;
791 HWND hdlg;
793 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
795 memset(&psp, 0, sizeof(psp));
796 psp.dwSize = sizeof(psp);
797 psp.dwFlags = 0;
798 psp.hInstance = GetModuleHandleA(NULL);
799 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
800 U2(psp).pszIcon = NULL;
801 psp.pfnDlgProc = page_dlg_proc_messages;
802 psp.lParam = 0;
804 hpsp[0] = pCreatePropertySheetPageA(&psp);
806 memset(&psh, 0, sizeof(psh));
807 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
808 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
809 | PSH_MODELESS | PSH_USEICONID;
810 psh.pszCaption = "test caption";
811 psh.nPages = 1;
812 psh.hwndParent = GetDesktopWindow();
813 U3(psh).phpage = hpsp;
814 psh.pfnCallback = sheet_callback_messages;
816 hdlg = (HWND)pPropertySheetA(&psh);
817 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
819 ShowWindow(hdlg,SW_NORMAL);
821 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
823 DestroyWindow(hdlg);
826 static void test_PSM_ADDPAGE(void)
828 HPROPSHEETPAGE hpsp[5];
829 PROPSHEETPAGEA psp;
830 PROPSHEETHEADERA psh;
831 HWND hdlg, tab;
832 BOOL ret;
833 DWORD r;
835 memset(&psp, 0, sizeof(psp));
836 psp.dwSize = sizeof(psp);
837 psp.dwFlags = 0;
838 psp.hInstance = GetModuleHandleA(NULL);
839 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
840 U2(psp).pszIcon = NULL;
841 psp.pfnDlgProc = page_dlg_proc_messages;
842 psp.lParam = 0;
844 /* multiple pages with the same data */
845 hpsp[0] = pCreatePropertySheetPageA(&psp);
846 hpsp[1] = pCreatePropertySheetPageA(&psp);
847 hpsp[2] = pCreatePropertySheetPageA(&psp);
849 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
850 hpsp[3] = pCreatePropertySheetPageA(&psp);
852 psp.dwFlags = PSP_PREMATURE;
853 hpsp[4] = pCreatePropertySheetPageA(&psp);
855 memset(&psh, 0, sizeof(psh));
856 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
857 psh.dwFlags = PSH_MODELESS;
858 psh.pszCaption = "test caption";
859 psh.nPages = 1;
860 psh.hwndParent = GetDesktopWindow();
861 U3(psh).phpage = hpsp;
863 hdlg = (HWND)pPropertySheetA(&psh);
864 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
866 /* add pages one by one */
867 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
868 ok(ret == TRUE, "got %d\n", ret);
870 /* try with null and invalid value */
871 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
872 ok(ret == FALSE, "got %d\n", ret);
874 if (0)
876 /* crashes on native */
877 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
879 /* check item count */
880 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
882 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
883 ok(r == 2, "got %d\n", r);
885 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
886 ok(ret == TRUE, "got %d\n", ret);
888 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
889 ok(r == 3, "got %d\n", r);
891 /* add property sheet page that can't be created */
892 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
893 ok(ret == TRUE, "got %d\n", ret);
895 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
896 ok(r == 4, "got %d\n", r);
898 /* select page that can't be created */
899 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1);
900 ok(ret == TRUE, "got %d\n", ret);
902 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
903 ok(r == 3, "got %d\n", r);
905 /* test PSP_PREMATURE flag with incorrect property sheet page */
906 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
907 ok(ret == FALSE, "got %d\n", ret);
909 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
910 ok(r == 3, "got %d\n", r);
912 pDestroyPropertySheetPage(hpsp[4]);
913 DestroyWindow(hdlg);
916 static void test_PSM_INSERTPAGE(void)
918 HPROPSHEETPAGE hpsp[5];
919 PROPSHEETPAGEA psp;
920 PROPSHEETHEADERA psh;
921 HWND hdlg, tab;
922 BOOL ret;
923 DWORD r;
925 memset(&psp, 0, sizeof(psp));
926 psp.dwSize = sizeof(psp);
927 psp.dwFlags = 0;
928 psp.hInstance = GetModuleHandleA(NULL);
929 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
930 U2(psp).pszIcon = NULL;
931 psp.pfnDlgProc = page_dlg_proc_messages;
932 psp.lParam = 0;
934 /* multiple pages with the same data */
935 hpsp[0] = pCreatePropertySheetPageA(&psp);
936 hpsp[1] = pCreatePropertySheetPageA(&psp);
937 hpsp[2] = pCreatePropertySheetPageA(&psp);
939 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
940 hpsp[3] = pCreatePropertySheetPageA(&psp);
942 psp.dwFlags = PSP_PREMATURE;
943 hpsp[4] = pCreatePropertySheetPageA(&psp);
945 memset(&psh, 0, sizeof(psh));
946 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
947 psh.dwFlags = PSH_MODELESS;
948 psh.pszCaption = "test caption";
949 psh.nPages = 1;
950 psh.hwndParent = GetDesktopWindow();
951 U3(psh).phpage = hpsp;
953 hdlg = (HWND)pPropertySheetA(&psh);
954 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
956 /* add pages one by one */
957 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 5, (LPARAM)hpsp[1]);
958 ok(ret == TRUE, "got %d\n", ret);
960 /* try with invalid values */
961 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, 0);
962 ok(ret == FALSE, "got %d\n", ret);
964 if (0)
966 /* crashes on native */
967 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
970 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)hpsp[2]);
971 ok(ret == FALSE, "got %d\n", ret);
973 /* check item count */
974 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
976 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
977 ok(r == 2, "got %d\n", r);
979 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)hpsp[1], (LPARAM)hpsp[2]);
980 ok(ret == TRUE, "got %d\n", ret);
982 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
983 ok(r == 3, "got %d\n", r);
985 /* add property sheet page that can't be created */
986 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 1, (LPARAM)hpsp[3]);
987 ok(ret == TRUE, "got %d\n", ret);
989 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
990 ok(r == 4, "got %d\n", r);
992 /* select page that can't be created */
993 ret = SendMessageA(hdlg, PSM_SETCURSEL, 1, 0);
994 ok(ret == TRUE, "got %d\n", ret);
996 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
997 ok(r == 3, "got %d\n", r);
999 /* test PSP_PREMATURE flag with incorrect property sheet page */
1000 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)hpsp[4]);
1001 ok(ret == FALSE, "got %d\n", ret);
1003 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
1004 ok(r == 3, "got %d\n", r);
1006 pDestroyPropertySheetPage(hpsp[4]);
1007 DestroyWindow(hdlg);
1010 struct custom_proppage
1012 union
1014 PROPSHEETPAGEA pageA;
1015 PROPSHEETPAGEW pageW;
1016 } u;
1017 unsigned int addref_called;
1018 unsigned int release_called;
1021 static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp)
1023 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1024 PROPSHEETPAGEA *psp_orig = &cpage->u.pageA;
1026 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1028 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1029 psp->lParam, psp);
1030 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1031 ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1033 switch (msg)
1035 case PSPCB_ADDREF:
1036 ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1037 cpage->addref_called++;
1038 break;
1039 case PSPCB_RELEASE:
1040 ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1041 cpage->release_called++;
1042 break;
1043 default:
1044 ok(0, "Unexpected message %u\n", msg);
1047 return 1;
1050 static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp)
1052 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1053 PROPSHEETPAGEW *psp_orig = &cpage->u.pageW;
1055 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1056 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1057 psp->lParam, psp);
1058 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1059 ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1061 switch (msg)
1063 case PSPCB_ADDREF:
1064 ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1065 cpage->addref_called++;
1066 break;
1067 case PSPCB_RELEASE:
1068 ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1069 cpage->release_called++;
1070 break;
1071 default:
1072 ok(0, "Unexpected message %u\n", msg);
1075 return 1;
1078 static void test_CreatePropertySheetPage(void)
1080 static const WCHAR titleW[] = {'T','i','t','l','e',0};
1081 struct custom_proppage page;
1082 HPROPSHEETPAGE hpsp;
1083 BOOL ret;
1085 memset(&page.u.pageA, 0, sizeof(page.u.pageA));
1086 page.u.pageA.dwFlags = PSP_USECALLBACK;
1087 page.u.pageA.pfnDlgProc = page_dlg_proc_messages;
1088 page.u.pageA.pfnCallback = proppage_callback_a;
1089 page.u.pageA.lParam = (LPARAM)&page;
1090 page.u.pageA.pszTitle = "Title";
1092 /* Only minimal size validation is performed */
1093 for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1; page.u.pageA.dwSize <= PROPSHEETPAGEA_V4_SIZE + 1; page.u.pageA.dwSize++)
1095 page.addref_called = 0;
1096 hpsp = pCreatePropertySheetPageA(&page.u.pageA);
1098 if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE)
1099 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageA.dwSize);
1100 else
1102 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageA.dwSize);
1103 ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1106 if (hpsp)
1108 page.release_called = 0;
1109 ret = pDestroyPropertySheetPage(hpsp);
1110 ok(ret, "Failed to destroy a page\n");
1111 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1115 memset(&page.u.pageW, 0, sizeof(page.u.pageW));
1116 page.u.pageW.dwFlags = PSP_USECALLBACK;
1117 page.u.pageW.pfnDlgProc = page_dlg_proc_messages;
1118 page.u.pageW.pfnCallback = proppage_callback_w;
1119 page.u.pageW.lParam = (LPARAM)&page;
1120 page.u.pageW.pszTitle = titleW;
1122 for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1; page.u.pageW.dwSize <= PROPSHEETPAGEW_V4_SIZE + 1; page.u.pageW.dwSize++)
1124 page.addref_called = 0;
1125 hpsp = pCreatePropertySheetPageW(&page.u.pageW);
1127 if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE)
1128 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageW.dwSize);
1129 else
1131 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageW.dwSize);
1132 ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1135 if (hpsp)
1137 page.release_called = 0;
1138 ret = pDestroyPropertySheetPage(hpsp);
1139 ok(ret, "Failed to destroy a page\n");
1140 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1145 static void test_bad_control_class(void)
1147 PROPSHEETPAGEA psp;
1148 PROPSHEETHEADERA psh;
1149 HPROPSHEETPAGE hpsp;
1150 INT_PTR ret;
1152 memset(&psp, 0, sizeof(psp));
1153 psp.dwSize = sizeof(psp);
1154 psp.hInstance = GetModuleHandleA(NULL);
1155 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_BAD_CONTROL);
1156 psp.pfnDlgProc = page_dlg_proc;
1158 hpsp = pCreatePropertySheetPageA(&psp);
1159 ok(hpsp != 0, "CreatePropertySheetPage failed\n");
1161 memset(&psh, 0, sizeof(psh));
1162 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
1163 psh.nPages = 1;
1164 psh.hwndParent = GetDesktopWindow();
1165 U3(psh).phpage = &hpsp;
1167 ret = pPropertySheetA(&psh);
1168 ok(ret == 0, "got %ld\n", ret);
1170 /* Need to recreate hpsp otherwise the test fails under Windows */
1171 hpsp = pCreatePropertySheetPageA(&psp);
1172 ok(hpsp != 0, "CreatePropertySheetPage failed\n");
1173 U3(psh).phpage = &hpsp;
1175 psh.dwFlags = PSH_MODELESS;
1176 ret = pPropertySheetA(&psh);
1177 ok(ret != 0, "got %ld\n", ret);
1179 ok(IsWindow((HWND)ret), "bad window handle %#lx\n", ret);
1180 DestroyWindow((HWND)ret);
1183 static void init_functions(void)
1185 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
1187 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
1188 X(CreatePropertySheetPageA);
1189 X(CreatePropertySheetPageW);
1190 X(DestroyPropertySheetPage);
1191 X(PropertySheetA);
1192 #undef X
1195 START_TEST(propsheet)
1197 detect_locale();
1198 if (rtl)
1200 /* use locale-specific RTL resources when on an RTL locale */
1201 /* without this, propsheets on RTL locales use English LTR resources */
1202 trace("RTL locale detected\n");
1203 SetProcessDefaultLayout(LAYOUT_RTL);
1206 init_functions();
1208 test_bad_control_class();
1209 test_title();
1210 test_nopage();
1211 test_disableowner();
1212 test_wiznavigation();
1213 test_buttons();
1214 test_custom_default_button();
1215 test_messages();
1216 test_PSM_ADDPAGE();
1217 test_PSM_INSERTPAGE();
1218 test_CreatePropertySheetPage();