35e942c6b574ab0d5acfc0391f1ea79c9a4196d2
[reactos.git] / modules / rostests / winetests / comctl32 / propsheet.c
1 /* Unit test suite for property sheet control.
2 *
3 * Copyright 2006 Huw Davies
4 * Copyright 2009 Jan de Mooij
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 #include <reactos/undocuser.h>
24
25 static HWND parenthwnd;
26 static HWND sheethwnd;
27
28 static BOOL rtl;
29 static LONG active_page = -1;
30
31 #define IDC_APPLY_BUTTON 12321
32
33
34 static void detect_locale(void)
35 {
36 DWORD reading_layout;
37 rtl = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER,
38 (void *)&reading_layout, sizeof(reading_layout)) && reading_layout == 1;
39 }
40
41 /* try to make sure pending X events have been processed before continuing */
42 static void flush_events(void)
43 {
44 MSG msg;
45 int diff = 200;
46 int min_timeout = 100;
47 DWORD time = GetTickCount() + diff;
48
49 while (diff > 0)
50 {
51 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
52 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
53 diff = time - GetTickCount();
54 }
55 }
56
57
58 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
59 {
60 switch(msg)
61 {
62 case PSCB_PRECREATE:
63 {
64 HMODULE module = GetModuleHandleA("comctl32.dll");
65 DWORD size, buffer_size;
66 HRSRC hrsrc;
67
68 hrsrc = FindResourceA(module, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */),
69 (LPSTR)RT_DIALOG);
70 size = SizeofResource(module, hrsrc);
71 ok(size != 0, "Failed to get size of propsheet dialog resource\n");
72 buffer_size = HeapSize(GetProcessHeap(), 0, (void *)lparam);
73 ok(buffer_size == 2 * size, "Unexpected template buffer size %u, resource size %u\n",
74 buffer_size, size);
75 break;
76 }
77 case PSCB_INITIALIZED:
78 {
79 char caption[256];
80 GetWindowTextA(hwnd, caption, sizeof(caption));
81 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
82 sheethwnd = hwnd;
83 return 0;
84 }
85 }
86 return 0;
87 }
88
89 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
90 LPARAM lparam)
91 {
92 switch(msg)
93 {
94 case WM_INITDIALOG:
95 {
96 HWND sheet = GetParent(hwnd);
97 char caption[256];
98 GetWindowTextA(sheet, caption, sizeof(caption));
99 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
100 return TRUE;
101 }
102
103 case WM_NOTIFY:
104 {
105 NMHDR *nmhdr = (NMHDR *)lparam;
106 switch(nmhdr->code)
107 {
108 case PSN_APPLY:
109 return TRUE;
110 default:
111 return FALSE;
112 }
113 }
114 case WM_NCDESTROY:
115 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
116 return TRUE;
117
118 default:
119 return FALSE;
120 }
121 }
122
123 static void test_title(void)
124 {
125 HPROPSHEETPAGE hpsp[1];
126 PROPSHEETPAGEA psp;
127 PROPSHEETHEADERA psh;
128 HWND hdlg;
129 DWORD style;
130
131 memset(&psp, 0, sizeof(psp));
132 psp.dwSize = sizeof(psp);
133 psp.dwFlags = 0;
134 psp.hInstance = GetModuleHandleA(NULL);
135 U(psp).pszTemplate = "prop_page1";
136 U2(psp).pszIcon = NULL;
137 psp.pfnDlgProc = page_dlg_proc;
138 psp.lParam = 0;
139
140 hpsp[0] = CreatePropertySheetPageA(&psp);
141
142 memset(&psh, 0, sizeof(psh));
143 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
144 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
145 psh.pszCaption = "test caption";
146 psh.nPages = 1;
147 psh.hwndParent = GetDesktopWindow();
148 U3(psh).phpage = hpsp;
149 psh.pfnCallback = sheet_callback;
150
151 hdlg = (HWND)PropertySheetA(&psh);
152 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
153
154 style = GetWindowLongA(hdlg, GWL_STYLE);
155 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|
156 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
157 "got unexpected style: %x\n", style);
158
159 DestroyWindow(hdlg);
160 }
161
162 static void test_nopage(void)
163 {
164 HPROPSHEETPAGE hpsp[1];
165 PROPSHEETPAGEA psp;
166 PROPSHEETHEADERA psh;
167 HWND hdlg, hpage;
168 MSG msg;
169
170 memset(&psp, 0, sizeof(psp));
171 psp.dwSize = sizeof(psp);
172 psp.dwFlags = 0;
173 psp.hInstance = GetModuleHandleA(NULL);
174 U(psp).pszTemplate = "prop_page1";
175 U2(psp).pszIcon = NULL;
176 psp.pfnDlgProc = page_dlg_proc;
177 psp.lParam = 0;
178
179 hpsp[0] = CreatePropertySheetPageA(&psp);
180
181 memset(&psh, 0, sizeof(psh));
182 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
183 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
184 psh.pszCaption = "test caption";
185 psh.nPages = 1;
186 psh.hwndParent = GetDesktopWindow();
187 U3(psh).phpage = hpsp;
188 psh.pfnCallback = sheet_callback;
189
190 hdlg = (HWND)PropertySheetA(&psh);
191 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
192
193 ShowWindow(hdlg,SW_NORMAL);
194 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0);
195 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */
196 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
197 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */
198 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0);
199 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, active_page);
200 flush_events();
201 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
202
203 /* Check that the property sheet was fully redrawn */
204 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
205 "expected no pending WM_PAINT messages\n");
206 DestroyWindow(hdlg);
207 }
208
209 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
210 {
211 switch(msg)
212 {
213 case PSCB_INITIALIZED:
214 {
215 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
216 PostQuitMessage(0);
217 return FALSE;
218 }
219 }
220 return FALSE;
221 }
222
223 static void register_parent_wnd_class(void)
224 {
225 WNDCLASSA cls;
226
227 cls.style = 0;
228 cls.lpfnWndProc = DefWindowProcA;
229 cls.cbClsExtra = 0;
230 cls.cbWndExtra = 0;
231 cls.hInstance = GetModuleHandleA(NULL);
232 cls.hIcon = 0;
233 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
234 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
235 cls.lpszMenuName = NULL;
236 cls.lpszClassName = "parent class";
237 RegisterClassA(&cls);
238 }
239
240 static void test_disableowner(void)
241 {
242 HPROPSHEETPAGE hpsp[1];
243 PROPSHEETPAGEA psp;
244 PROPSHEETHEADERA psh;
245 INT_PTR p;
246
247 register_parent_wnd_class();
248 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
249
250 memset(&psp, 0, sizeof(psp));
251 psp.dwSize = sizeof(psp);
252 psp.dwFlags = 0;
253 psp.hInstance = GetModuleHandleA(NULL);
254 U(psp).pszTemplate = "prop_page1";
255 U2(psp).pszIcon = NULL;
256 psp.pfnDlgProc = NULL;
257 psp.lParam = 0;
258
259 hpsp[0] = CreatePropertySheetPageA(&psp);
260
261 memset(&psh, 0, sizeof(psh));
262 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
263 psh.dwFlags = PSH_USECALLBACK;
264 psh.pszCaption = "test caption";
265 psh.nPages = 1;
266 psh.hwndParent = parenthwnd;
267 U3(psh).phpage = hpsp;
268 psh.pfnCallback = disableowner_callback;
269
270 p = PropertySheetA(&psh);
271 todo_wine
272 ok(p == 0, "Expected 0, got %ld\n", p);
273 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
274 DestroyWindow(parenthwnd);
275 }
276
277 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
278 {
279 switch(msg){
280 case WM_NOTIFY:
281 {
282 LPNMHDR hdr = (LPNMHDR)lparam;
283 switch(hdr->code){
284 case PSN_SETACTIVE:
285 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
286 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0);
287 return TRUE;
288 case PSN_KILLACTIVE:
289 /* prevent navigation away from the fourth page */
290 if(active_page == 3){
291 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE);
292 return TRUE;
293 }
294 }
295 break;
296 }
297 }
298 return FALSE;
299 }
300
301 static WNDPROC old_nav_dialog_proc;
302
303 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
304 {
305 switch (msg)
306 {
307 case DM_SETDEFID:
308 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" );
309 break;
310 }
311 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp );
312 }
313
314 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
315 {
316 static BOOL done;
317 if (code == HCBT_CREATEWND)
318 {
319 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp;
320
321 /* The first dialog created will be the parent dialog */
322 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG)
323 {
324 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc );
325 done = TRUE;
326 }
327 }
328
329 return CallNextHookEx( NULL, code, wp, lp );
330 }
331
332 static void test_wiznavigation(void)
333 {
334 HPROPSHEETPAGE hpsp[4];
335 PROPSHEETPAGEA psp[4];
336 PROPSHEETHEADERA psh;
337 HWND hdlg, control;
338 LONG_PTR controlID;
339 DWORD style;
340 LRESULT defidres;
341 BOOL hwndtoindex_supported = TRUE;
342 const INT nextID = 12324;
343 const INT backID = 12323;
344 HHOOK hook;
345
346 /* set up a hook proc in order to subclass the main dialog early on */
347 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
348
349 /* create the property sheet pages */
350 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
351
352 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
353 psp[0].hInstance = GetModuleHandleA(NULL);
354 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
355 psp[0].pfnDlgProc = nav_page_proc;
356 hpsp[0] = CreatePropertySheetPageA(&psp[0]);
357
358 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
359 psp[1].hInstance = GetModuleHandleA(NULL);
360 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
361 psp[1].pfnDlgProc = nav_page_proc;
362 hpsp[1] = CreatePropertySheetPageA(&psp[1]);
363
364 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
365 psp[2].hInstance = GetModuleHandleA(NULL);
366 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
367 psp[2].pfnDlgProc = nav_page_proc;
368 hpsp[2] = CreatePropertySheetPageA(&psp[2]);
369
370 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
371 psp[3].hInstance = GetModuleHandleA(NULL);
372 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
373 psp[3].pfnDlgProc = nav_page_proc;
374 hpsp[3] = CreatePropertySheetPageA(&psp[3]);
375
376 /* set up the property sheet dialog */
377 memset(&psh, 0, sizeof(psh));
378 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
379 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
380 psh.pszCaption = "A Wizard";
381 psh.nPages = 4;
382 psh.hwndParent = GetDesktopWindow();
383 U3(psh).phpage = hpsp;
384 hdlg = (HWND)PropertySheetA(&psh);
385 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
386
387 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
388
389 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
390 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
391 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
392 "got unexpected style: %x\n", style);
393
394 control = GetFocus();
395 controlID = GetWindowLongPtrA(control, GWLP_ID);
396 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
397
398 /* simulate pressing the Next button */
399 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
400 if (!active_page) hwndtoindex_supported = FALSE;
401 if (hwndtoindex_supported)
402 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
403
404 control = GetFocus();
405 controlID = GetWindowLongPtrA(control, GWLP_ID);
406 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);
407
408 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
409 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
410
411 /* set the focus to the second edit box on this page */
412 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
413
414 /* press next again */
415 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
416 if (hwndtoindex_supported)
417 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
418
419 control = GetFocus();
420 controlID = GetWindowLongPtrA(control, GWLP_ID);
421 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
422
423 /* back button */
424 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
425 if (hwndtoindex_supported)
426 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
427
428 control = GetFocus();
429 controlID = GetWindowLongPtrA(control, GWLP_ID);
430 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);
431
432 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
433 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
434
435 /* press next twice */
436 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
437 if (hwndtoindex_supported)
438 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
439 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
440 if (hwndtoindex_supported)
441 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
442 else
443 active_page = 3;
444
445 control = GetFocus();
446 controlID = GetWindowLongPtrA(control, GWLP_ID);
447 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
448
449 /* try to navigate away, but shouldn't be able to */
450 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
451 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
452
453 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
454 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
455
456 DestroyWindow(hdlg);
457 UnhookWindowsHookEx( hook );
458 }
459
460 static void test_buttons(void)
461 {
462 HPROPSHEETPAGE hpsp[1];
463 PROPSHEETPAGEA psp;
464 PROPSHEETHEADERA psh;
465 HWND hdlg;
466 HWND button;
467 RECT rc;
468 int prevRight, top;
469
470 memset(&psp, 0, sizeof(psp));
471 psp.dwSize = sizeof(psp);
472 psp.dwFlags = 0;
473 psp.hInstance = GetModuleHandleA(NULL);
474 U(psp).pszTemplate = "prop_page1";
475 U2(psp).pszIcon = NULL;
476 psp.pfnDlgProc = page_dlg_proc;
477 psp.lParam = 0;
478
479 hpsp[0] = CreatePropertySheetPageA(&psp);
480
481 memset(&psh, 0, sizeof(psh));
482 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
483 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
484 psh.pszCaption = "test caption";
485 psh.nPages = 1;
486 psh.hwndParent = GetDesktopWindow();
487 U3(psh).phpage = hpsp;
488 psh.pfnCallback = sheet_callback;
489
490 hdlg = (HWND)PropertySheetA(&psh);
491 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
492
493 /* OK button */
494 button = GetDlgItem(hdlg, IDOK);
495 GetWindowRect(button, &rc);
496 prevRight = rc.right;
497 top = rc.top;
498
499 /* Cancel button */
500 button = GetDlgItem(hdlg, IDCANCEL);
501 GetWindowRect(button, &rc);
502 ok(rc.top == top, "Cancel button should have same top as OK button\n");
503 if (rtl)
504 ok(rc.left < prevRight, "Cancel button should be to the left of OK button\n");
505 else
506 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
507 prevRight = rc.right;
508
509 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
510 GetWindowRect(button, &rc);
511 ok(rc.top == top, "Apply button should have same top as OK button\n");
512 if (rtl)
513 ok(rc.left < prevRight, "Apply button should be to the left of Cancel button\n");
514 else
515 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
516 prevRight = rc.right;
517
518 button = GetDlgItem(hdlg, IDHELP);
519 GetWindowRect(button, &rc);
520 ok(rc.top == top, "Help button should have same top as OK button\n");
521 if (rtl)
522 ok(rc.left < prevRight, "Help button should be to the left of Apply button\n");
523 else
524 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
525
526 DestroyWindow(hdlg);
527 }
528
529 static BOOL add_button_has_been_pressed;
530
531 static INT_PTR CALLBACK
532 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
533 {
534 switch (msg)
535 {
536 case WM_COMMAND:
537 switch(LOWORD(wparam))
538 {
539 case IDC_PS_PUSHBUTTON1:
540 switch(HIWORD(wparam))
541 {
542 case BN_CLICKED:
543 add_button_has_been_pressed = TRUE;
544 return TRUE;
545 }
546 break;
547 }
548 break;
549 }
550 return FALSE;
551 }
552
553 static void test_custom_default_button(void)
554 {
555 HWND hdlg, page;
556 PROPSHEETPAGEA psp[1];
557 PROPSHEETHEADERA psh;
558 MSG msg;
559 LRESULT result;
560
561 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
562 psp[0].dwFlags = PSP_USETITLE;
563 psp[0].hInstance = GetModuleHandleA(NULL);
564 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
565 U2(psp[0]).pszIcon = NULL;
566 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
567 psp[0].pszTitle = "Page1";
568 psp[0].lParam = 0;
569
570 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
571 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
572 psh.hwndParent = GetDesktopWindow();
573 psh.hInstance = GetModuleHandleA(NULL);
574 U(psh).pszIcon = NULL;
575 psh.pszCaption = "PropertySheet1";
576 psh.nPages = 1;
577 U3(psh).ppsp = psp;
578 U2(psh).nStartPage = 0;
579
580 /* The goal of the test is to make sure that the Add button is pressed
581 * when the ENTER key is pressed and a different control, a combobox,
582 * has the keyboard focus. */
583 add_button_has_been_pressed = FALSE;
584
585 /* Create the modeless property sheet. */
586 hdlg = (HWND)PropertySheetA(&psh);
587 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
588
589 /* Set the Add button as the default button. */
590 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
591
592 /* Make sure the default button is the Add button. */
593 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
594 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
595 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
596
597 /* At this point, the combobox should have keyboard focus, so we press ENTER.
598 * Pull the lever, Kronk! */
599 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
600 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0);
601
602 /* Process all the messages in the queue for this thread. */
603 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
604 {
605 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */
606 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg)))
607 {
608 TranslateMessage(&msg);
609 DispatchMessageA(&msg);
610 }
611 }
612
613 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
614
615 DestroyWindow(hdlg);
616 }
617
618 #define RECEIVER_SHEET_CALLBACK 0
619 #define RECEIVER_SHEET_WINPROC 1
620 #define RECEIVER_PAGE 2
621
622 #define NUM_MSG_SEQUENCES 1
623 #define PROPSHEET_SEQ_INDEX 0
624
625 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
626 static WNDPROC oldWndProc;
627
628 static const struct message property_sheet_seq[] = {
629 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
630 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
631 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
632 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
633 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
634 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
635 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
636 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
637 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
638 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
639 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
640 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
641 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
642 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
643 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
644 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
645 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
646 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
647 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
648 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
649 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
650 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
651 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
652 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
653 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
654 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
655 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
656 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
657 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
658 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
659 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
660 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
661 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
662 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
663 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
664 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
665 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
666 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
667 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
668 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
669 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
670 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
671 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
672 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
673 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
674 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
675 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
676 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
677 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
678 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
679 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
680 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
681 /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
682 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
683 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
684 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
685 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
686 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
687 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
688 /*{ WM_GETICON, 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_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
692 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
693 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
694 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
695 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
696 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
697 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
698 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
699 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
700 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
701 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
702 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
703 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
704 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
705 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
706 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
707 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
708 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
709 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
710 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
711 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
712 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
713 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
714 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
715 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
716 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
717 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
718 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
719 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
720 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
721 { 0 }
722 };
723
724 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
725 {
726 struct message msg = { 0 };
727
728 if (message < WM_USER &&
729 message != WM_GETICON &&
730 message != WM_GETTEXT &&
731 message != WM_IME_SETCONTEXT &&
732 message != WM_IME_NOTIFY &&
733 message != WM_PAINT &&
734 message != WM_ERASEBKGND &&
735 message != WM_SETCURSOR &&
736 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
737 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
738 message != 0x90)
739 {
740 msg.message = message;
741 msg.flags = sent|wparam|lparam|id;
742 msg.wParam = wParam;
743 msg.lParam = lParam;
744 msg.id = receiver;
745 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
746 }
747 }
748
749 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
750 {
751 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
752
753 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
754 }
755
756 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
757 {
758 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
759
760 switch (msg)
761 {
762 case PSCB_INITIALIZED:
763 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
764 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
765 return TRUE;
766 }
767
768 return TRUE;
769 }
770
771 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
772 LPARAM lParam)
773 {
774 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
775
776 return FALSE;
777 }
778
779 static void test_messages(void)
780 {
781 HPROPSHEETPAGE hpsp[1];
782 PROPSHEETPAGEA psp;
783 PROPSHEETHEADERA psh;
784 HWND hdlg;
785
786 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
787
788 memset(&psp, 0, sizeof(psp));
789 psp.dwSize = sizeof(psp);
790 psp.dwFlags = 0;
791 psp.hInstance = GetModuleHandleA(NULL);
792 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
793 U2(psp).pszIcon = NULL;
794 psp.pfnDlgProc = page_dlg_proc_messages;
795 psp.lParam = 0;
796
797 hpsp[0] = CreatePropertySheetPageA(&psp);
798
799 memset(&psh, 0, sizeof(psh));
800 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
801 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
802 | PSH_MODELESS | PSH_USEICONID;
803 psh.pszCaption = "test caption";
804 psh.nPages = 1;
805 psh.hwndParent = GetDesktopWindow();
806 U3(psh).phpage = hpsp;
807 psh.pfnCallback = sheet_callback_messages;
808
809 hdlg = (HWND)PropertySheetA(&psh);
810 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
811
812 ShowWindow(hdlg,SW_NORMAL);
813
814 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
815
816 DestroyWindow(hdlg);
817 }
818
819 static void test_PSM_ADDPAGE(void)
820 {
821 HPROPSHEETPAGE hpsp[5];
822 PROPSHEETPAGEA psp;
823 PROPSHEETHEADERA psh;
824 HWND hdlg, tab;
825 BOOL ret;
826 DWORD r;
827
828 memset(&psp, 0, sizeof(psp));
829 psp.dwSize = sizeof(psp);
830 psp.dwFlags = 0;
831 psp.hInstance = GetModuleHandleA(NULL);
832 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
833 U2(psp).pszIcon = NULL;
834 psp.pfnDlgProc = page_dlg_proc_messages;
835 psp.lParam = 0;
836
837 /* multiple pages with the same data */
838 hpsp[0] = CreatePropertySheetPageA(&psp);
839 hpsp[1] = CreatePropertySheetPageA(&psp);
840 hpsp[2] = CreatePropertySheetPageA(&psp);
841
842 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
843 hpsp[3] = CreatePropertySheetPageA(&psp);
844
845 psp.dwFlags = PSP_PREMATURE;
846 hpsp[4] = CreatePropertySheetPageA(&psp);
847
848 memset(&psh, 0, sizeof(psh));
849 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
850 psh.dwFlags = PSH_MODELESS;
851 psh.pszCaption = "test caption";
852 psh.nPages = 1;
853 psh.hwndParent = GetDesktopWindow();
854 U3(psh).phpage = hpsp;
855
856 hdlg = (HWND)PropertySheetA(&psh);
857 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
858
859 /* add pages one by one */
860 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
861 ok(ret == TRUE, "got %d\n", ret);
862
863 /* try with null and invalid value */
864 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
865 ok(ret == FALSE, "got %d\n", ret);
866
867 if (0)
868 {
869 /* crashes on native */
870 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
871 }
872 /* check item count */
873 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
874
875 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
876 ok(r == 2, "got %d\n", r);
877
878 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
879 ok(ret == TRUE, "got %d\n", ret);
880
881 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
882 ok(r == 3, "got %d\n", r);
883
884 /* add property sheet page that can't be created */
885 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
886 ok(ret == TRUE, "got %d\n", ret);
887
888 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
889 ok(r == 4, "got %d\n", r);
890
891 /* select page that can't be created */
892 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1);
893 ok(ret == TRUE, "got %d\n", ret);
894
895 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
896 ok(r == 3, "got %d\n", r);
897
898 /* test PSP_PREMATURE flag with incorrect property sheet page */
899 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
900 ok(ret == FALSE, "got %d\n", ret);
901
902 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
903 ok(r == 3, "got %d\n", r);
904
905 DestroyPropertySheetPage(hpsp[4]);
906 DestroyWindow(hdlg);
907 }
908
909 static void test_PSM_INSERTPAGE(void)
910 {
911 HPROPSHEETPAGE hpsp[5];
912 PROPSHEETPAGEA psp;
913 PROPSHEETHEADERA psh;
914 HWND hdlg, tab;
915 BOOL ret;
916 DWORD r;
917
918 memset(&psp, 0, sizeof(psp));
919 psp.dwSize = sizeof(psp);
920 psp.dwFlags = 0;
921 psp.hInstance = GetModuleHandleA(NULL);
922 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
923 U2(psp).pszIcon = NULL;
924 psp.pfnDlgProc = page_dlg_proc_messages;
925 psp.lParam = 0;
926
927 /* multiple pages with the same data */
928 hpsp[0] = CreatePropertySheetPageA(&psp);
929 hpsp[1] = CreatePropertySheetPageA(&psp);
930 hpsp[2] = CreatePropertySheetPageA(&psp);
931
932 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
933 hpsp[3] = CreatePropertySheetPageA(&psp);
934
935 psp.dwFlags = PSP_PREMATURE;
936 hpsp[4] = CreatePropertySheetPageA(&psp);
937
938 memset(&psh, 0, sizeof(psh));
939 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
940 psh.dwFlags = PSH_MODELESS;
941 psh.pszCaption = "test caption";
942 psh.nPages = 1;
943 psh.hwndParent = GetDesktopWindow();
944 U3(psh).phpage = hpsp;
945
946 hdlg = (HWND)PropertySheetA(&psh);
947 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
948
949 /* add pages one by one */
950 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 5, (LPARAM)hpsp[1]);
951 ok(ret == TRUE, "got %d\n", ret);
952
953 /* try with invalid values */
954 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, 0);
955 ok(ret == FALSE, "got %d\n", ret);
956
957 if (0)
958 {
959 /* crashes on native */
960 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
961 }
962
963 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)hpsp[2]);
964 ok(ret == FALSE, "got %d\n", ret);
965
966 /* check item count */
967 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
968
969 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
970 ok(r == 2, "got %d\n", r);
971
972 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)hpsp[1], (LPARAM)hpsp[2]);
973 ok(ret == TRUE, "got %d\n", ret);
974
975 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
976 ok(r == 3, "got %d\n", r);
977
978 /* add property sheet page that can't be created */
979 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 1, (LPARAM)hpsp[3]);
980 ok(ret == TRUE, "got %d\n", ret);
981
982 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
983 ok(r == 4, "got %d\n", r);
984
985 /* select page that can't be created */
986 ret = SendMessageA(hdlg, PSM_SETCURSEL, 1, 0);
987 ok(ret == TRUE, "got %d\n", ret);
988
989 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
990 ok(r == 3, "got %d\n", r);
991
992 /* test PSP_PREMATURE flag with incorrect property sheet page */
993 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)hpsp[4]);
994 ok(ret == FALSE, "got %d\n", ret);
995
996 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
997 ok(r == 3, "got %d\n", r);
998
999 DestroyPropertySheetPage(hpsp[4]);
1000 DestroyWindow(hdlg);
1001 }
1002
1003 struct custom_proppage
1004 {
1005 union
1006 {
1007 PROPSHEETPAGEA pageA;
1008 PROPSHEETPAGEW pageW;
1009 } u;
1010 unsigned int addref_called;
1011 unsigned int release_called;
1012 };
1013
1014 static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp)
1015 {
1016 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1017 PROPSHEETPAGEA *psp_orig = &cpage->u.pageA;
1018
1019 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1020
1021 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1022 psp->lParam, psp);
1023 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1024 ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1025
1026 switch (msg)
1027 {
1028 case PSPCB_ADDREF:
1029 ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1030 cpage->addref_called++;
1031 break;
1032 case PSPCB_RELEASE:
1033 ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1034 cpage->release_called++;
1035 break;
1036 default:
1037 ok(0, "Unexpected message %u\n", msg);
1038 }
1039
1040 return 1;
1041 }
1042
1043 static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp)
1044 {
1045 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1046 PROPSHEETPAGEW *psp_orig = &cpage->u.pageW;
1047
1048 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1049 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1050 psp->lParam, psp);
1051 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1052 ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1053
1054 switch (msg)
1055 {
1056 case PSPCB_ADDREF:
1057 ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1058 cpage->addref_called++;
1059 break;
1060 case PSPCB_RELEASE:
1061 ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1062 cpage->release_called++;
1063 break;
1064 default:
1065 ok(0, "Unexpected message %u\n", msg);
1066 }
1067
1068 return 1;
1069 }
1070
1071 static void test_CreatePropertySheetPage(void)
1072 {
1073 static const WCHAR titleW[] = {'T','i','t','l','e',0};
1074 struct custom_proppage page;
1075 HPROPSHEETPAGE hpsp;
1076 BOOL ret;
1077
1078 memset(&page.u.pageA, 0, sizeof(page.u.pageA));
1079 page.u.pageA.dwFlags = PSP_USECALLBACK;
1080 page.u.pageA.pfnDlgProc = page_dlg_proc_messages;
1081 page.u.pageA.pfnCallback = proppage_callback_a;
1082 page.u.pageA.lParam = (LPARAM)&page;
1083 page.u.pageA.pszTitle = "Title";
1084
1085 /* Only minimal size validation is performed */
1086 for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1; page.u.pageA.dwSize <= PROPSHEETPAGEA_V4_SIZE + 1; page.u.pageA.dwSize++)
1087 {
1088 page.addref_called = 0;
1089 hpsp = CreatePropertySheetPageA(&page.u.pageA);
1090
1091 if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE)
1092 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageA.dwSize);
1093 else
1094 {
1095 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageA.dwSize);
1096 ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1097 }
1098
1099 if (hpsp)
1100 {
1101 page.release_called = 0;
1102 ret = DestroyPropertySheetPage(hpsp);
1103 ok(ret, "Failed to destroy a page\n");
1104 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1105 }
1106 }
1107
1108 memset(&page.u.pageW, 0, sizeof(page.u.pageW));
1109 page.u.pageW.dwFlags = PSP_USECALLBACK;
1110 page.u.pageW.pfnDlgProc = page_dlg_proc_messages;
1111 page.u.pageW.pfnCallback = proppage_callback_w;
1112 page.u.pageW.lParam = (LPARAM)&page;
1113 page.u.pageW.pszTitle = titleW;
1114
1115 for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1; page.u.pageW.dwSize <= PROPSHEETPAGEW_V4_SIZE + 1; page.u.pageW.dwSize++)
1116 {
1117 page.addref_called = 0;
1118 hpsp = CreatePropertySheetPageW(&page.u.pageW);
1119
1120 if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE)
1121 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageW.dwSize);
1122 else
1123 {
1124 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageW.dwSize);
1125 ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1126 }
1127
1128 if (hpsp)
1129 {
1130 page.release_called = 0;
1131 ret = DestroyPropertySheetPage(hpsp);
1132 ok(ret, "Failed to destroy a page\n");
1133 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1134 }
1135 }
1136 }
1137
1138 START_TEST(propsheet)
1139 {
1140 detect_locale();
1141 if (rtl)
1142 {
1143 /* use locale-specific RTL resources when on an RTL locale */
1144 /* without this, propsheets on RTL locales use English LTR resources */
1145 trace("RTL locale detected\n");
1146 SetProcessDefaultLayout(LAYOUT_RTL);
1147 }
1148
1149 test_title();
1150 test_nopage();
1151 test_disableowner();
1152 test_wiznavigation();
1153 test_buttons();
1154 test_custom_default_button();
1155 test_messages();
1156 test_PSM_ADDPAGE();
1157 test_PSM_INSERTPAGE();
1158 test_CreatePropertySheetPage();
1159 }