comctl32/propsheet: Enforce minimal PROPSHEETPAGE structure size when creating a...
[wine.git] / dlls / comctl32 / tests / propsheet.c
blob8a4e6d187c1a9e5d160f59741c2529e81bcbe933
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 LONG active_page = -1;
34 #define IDC_APPLY_BUTTON 12321
37 /* try to make sure pending X events have been processed before continuing */
38 static void flush_events(void)
40 MSG msg;
41 int diff = 200;
42 int min_timeout = 100;
43 DWORD time = GetTickCount() + diff;
45 while (diff > 0)
47 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
48 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
49 diff = time - GetTickCount();
54 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
56 switch(msg)
58 case PSCB_PRECREATE:
60 HMODULE module = GetModuleHandleA("comctl32.dll");
61 DWORD size, buffer_size;
62 HRSRC hrsrc;
64 hrsrc = FindResourceA(module, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */),
65 (LPSTR)RT_DIALOG);
66 size = SizeofResource(module, hrsrc);
67 ok(size != 0, "Failed to get size of propsheet dialog resource\n");
68 buffer_size = HeapSize(GetProcessHeap(), 0, (void *)lparam);
69 ok(buffer_size == 2 * size, "Unexpected template buffer size %u, resource size %u\n",
70 buffer_size, size);
71 break;
73 case PSCB_INITIALIZED:
75 char caption[256];
76 GetWindowTextA(hwnd, caption, sizeof(caption));
77 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
78 sheethwnd = hwnd;
79 return 0;
82 return 0;
85 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
86 LPARAM lparam)
88 switch(msg)
90 case WM_INITDIALOG:
92 HWND sheet = GetParent(hwnd);
93 char caption[256];
94 GetWindowTextA(sheet, caption, sizeof(caption));
95 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
96 return TRUE;
99 case WM_NOTIFY:
101 NMHDR *nmhdr = (NMHDR *)lparam;
102 switch(nmhdr->code)
104 case PSN_APPLY:
105 return TRUE;
106 default:
107 return FALSE;
110 case WM_NCDESTROY:
111 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
112 return TRUE;
114 default:
115 return FALSE;
119 static void test_title(void)
121 HPROPSHEETPAGE hpsp[1];
122 PROPSHEETPAGEA psp;
123 PROPSHEETHEADERA psh;
124 HWND hdlg;
125 DWORD style;
127 memset(&psp, 0, sizeof(psp));
128 psp.dwSize = sizeof(psp);
129 psp.dwFlags = 0;
130 psp.hInstance = GetModuleHandleA(NULL);
131 U(psp).pszTemplate = "prop_page1";
132 U2(psp).pszIcon = NULL;
133 psp.pfnDlgProc = page_dlg_proc;
134 psp.lParam = 0;
136 hpsp[0] = CreatePropertySheetPageA(&psp);
138 memset(&psh, 0, sizeof(psh));
139 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
140 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
141 psh.pszCaption = "test caption";
142 psh.nPages = 1;
143 psh.hwndParent = GetDesktopWindow();
144 U3(psh).phpage = hpsp;
145 psh.pfnCallback = sheet_callback;
147 hdlg = (HWND)PropertySheetA(&psh);
148 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
150 style = GetWindowLongA(hdlg, GWL_STYLE);
151 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|
152 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
153 "got unexpected style: %x\n", style);
155 DestroyWindow(hdlg);
158 static void test_nopage(void)
160 HPROPSHEETPAGE hpsp[1];
161 PROPSHEETPAGEA psp;
162 PROPSHEETHEADERA psh;
163 HWND hdlg, hpage;
164 MSG msg;
166 memset(&psp, 0, sizeof(psp));
167 psp.dwSize = sizeof(psp);
168 psp.dwFlags = 0;
169 psp.hInstance = GetModuleHandleA(NULL);
170 U(psp).pszTemplate = "prop_page1";
171 U2(psp).pszIcon = NULL;
172 psp.pfnDlgProc = page_dlg_proc;
173 psp.lParam = 0;
175 hpsp[0] = CreatePropertySheetPageA(&psp);
177 memset(&psh, 0, sizeof(psh));
178 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
179 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
180 psh.pszCaption = "test caption";
181 psh.nPages = 1;
182 psh.hwndParent = GetDesktopWindow();
183 U3(psh).phpage = hpsp;
184 psh.pfnCallback = sheet_callback;
186 hdlg = (HWND)PropertySheetA(&psh);
187 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
189 ShowWindow(hdlg,SW_NORMAL);
190 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0);
191 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */
192 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
193 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */
194 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0);
195 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, active_page);
196 flush_events();
197 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
199 /* Check that the property sheet was fully redrawn */
200 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
201 "expected no pending WM_PAINT messages\n");
202 DestroyWindow(hdlg);
205 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
207 switch(msg)
209 case PSCB_INITIALIZED:
211 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
212 PostQuitMessage(0);
213 return FALSE;
216 return FALSE;
219 static void register_parent_wnd_class(void)
221 WNDCLASSA cls;
223 cls.style = 0;
224 cls.lpfnWndProc = DefWindowProcA;
225 cls.cbClsExtra = 0;
226 cls.cbWndExtra = 0;
227 cls.hInstance = GetModuleHandleA(NULL);
228 cls.hIcon = 0;
229 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
230 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
231 cls.lpszMenuName = NULL;
232 cls.lpszClassName = "parent class";
233 RegisterClassA(&cls);
236 static void test_disableowner(void)
238 HPROPSHEETPAGE hpsp[1];
239 PROPSHEETPAGEA psp;
240 PROPSHEETHEADERA psh;
241 INT_PTR p;
243 register_parent_wnd_class();
244 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
246 memset(&psp, 0, sizeof(psp));
247 psp.dwSize = sizeof(psp);
248 psp.dwFlags = 0;
249 psp.hInstance = GetModuleHandleA(NULL);
250 U(psp).pszTemplate = "prop_page1";
251 U2(psp).pszIcon = NULL;
252 psp.pfnDlgProc = NULL;
253 psp.lParam = 0;
255 hpsp[0] = CreatePropertySheetPageA(&psp);
257 memset(&psh, 0, sizeof(psh));
258 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
259 psh.dwFlags = PSH_USECALLBACK;
260 psh.pszCaption = "test caption";
261 psh.nPages = 1;
262 psh.hwndParent = parenthwnd;
263 U3(psh).phpage = hpsp;
264 psh.pfnCallback = disableowner_callback;
266 p = PropertySheetA(&psh);
267 todo_wine
268 ok(p == 0, "Expected 0, got %ld\n", p);
269 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
270 DestroyWindow(parenthwnd);
273 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
275 switch(msg){
276 case WM_NOTIFY:
278 LPNMHDR hdr = (LPNMHDR)lparam;
279 switch(hdr->code){
280 case PSN_SETACTIVE:
281 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
282 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0);
283 return TRUE;
284 case PSN_KILLACTIVE:
285 /* prevent navigation away from the fourth page */
286 if(active_page == 3){
287 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE);
288 return TRUE;
291 break;
294 return FALSE;
297 static WNDPROC old_nav_dialog_proc;
299 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
301 switch (msg)
303 case DM_SETDEFID:
304 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" );
305 break;
307 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp );
310 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
312 static BOOL done;
313 if (code == HCBT_CREATEWND)
315 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp;
317 /* The first dialog created will be the parent dialog */
318 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG)
320 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc );
321 done = TRUE;
325 return CallNextHookEx( NULL, code, wp, lp );
328 static void test_wiznavigation(void)
330 HPROPSHEETPAGE hpsp[4];
331 PROPSHEETPAGEA psp[4];
332 PROPSHEETHEADERA psh;
333 HWND hdlg, control;
334 LONG_PTR controlID;
335 DWORD style;
336 LRESULT defidres;
337 BOOL hwndtoindex_supported = TRUE;
338 const INT nextID = 12324;
339 const INT backID = 12323;
340 HHOOK hook;
342 /* set up a hook proc in order to subclass the main dialog early on */
343 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
345 /* create the property sheet pages */
346 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
348 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
349 psp[0].hInstance = GetModuleHandleA(NULL);
350 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
351 psp[0].pfnDlgProc = nav_page_proc;
352 hpsp[0] = CreatePropertySheetPageA(&psp[0]);
354 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
355 psp[1].hInstance = GetModuleHandleA(NULL);
356 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
357 psp[1].pfnDlgProc = nav_page_proc;
358 hpsp[1] = CreatePropertySheetPageA(&psp[1]);
360 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
361 psp[2].hInstance = GetModuleHandleA(NULL);
362 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
363 psp[2].pfnDlgProc = nav_page_proc;
364 hpsp[2] = CreatePropertySheetPageA(&psp[2]);
366 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
367 psp[3].hInstance = GetModuleHandleA(NULL);
368 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
369 psp[3].pfnDlgProc = nav_page_proc;
370 hpsp[3] = CreatePropertySheetPageA(&psp[3]);
372 /* set up the property sheet dialog */
373 memset(&psh, 0, sizeof(psh));
374 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
375 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
376 psh.pszCaption = "A Wizard";
377 psh.nPages = 4;
378 psh.hwndParent = GetDesktopWindow();
379 U3(psh).phpage = hpsp;
380 hdlg = (HWND)PropertySheetA(&psh);
381 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
383 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
385 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
386 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
387 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
388 "got unexpected style: %x\n", style);
390 control = GetFocus();
391 controlID = GetWindowLongPtrA(control, GWLP_ID);
392 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
394 /* simulate pressing the Next button */
395 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
396 if (!active_page) hwndtoindex_supported = FALSE;
397 if (hwndtoindex_supported)
398 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
400 control = GetFocus();
401 controlID = GetWindowLongPtrA(control, GWLP_ID);
402 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);
404 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
405 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
407 /* set the focus to the second edit box on this page */
408 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
410 /* press next again */
411 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
412 if (hwndtoindex_supported)
413 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
415 control = GetFocus();
416 controlID = GetWindowLongPtrA(control, GWLP_ID);
417 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
419 /* back button */
420 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
421 if (hwndtoindex_supported)
422 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
424 control = GetFocus();
425 controlID = GetWindowLongPtrA(control, GWLP_ID);
426 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);
428 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
429 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
431 /* press next twice */
432 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
433 if (hwndtoindex_supported)
434 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
435 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
436 if (hwndtoindex_supported)
437 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
438 else
439 active_page = 3;
441 control = GetFocus();
442 controlID = GetWindowLongPtrA(control, GWLP_ID);
443 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
445 /* try to navigate away, but shouldn't be able to */
446 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
447 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
449 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
450 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
452 DestroyWindow(hdlg);
453 UnhookWindowsHookEx( hook );
456 static void test_buttons(void)
458 HPROPSHEETPAGE hpsp[1];
459 PROPSHEETPAGEA psp;
460 PROPSHEETHEADERA psh;
461 HWND hdlg;
462 HWND button;
463 RECT rc;
464 int prevRight, top;
466 memset(&psp, 0, sizeof(psp));
467 psp.dwSize = sizeof(psp);
468 psp.dwFlags = 0;
469 psp.hInstance = GetModuleHandleA(NULL);
470 U(psp).pszTemplate = "prop_page1";
471 U2(psp).pszIcon = NULL;
472 psp.pfnDlgProc = page_dlg_proc;
473 psp.lParam = 0;
475 hpsp[0] = CreatePropertySheetPageA(&psp);
477 memset(&psh, 0, sizeof(psh));
478 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
479 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
480 psh.pszCaption = "test caption";
481 psh.nPages = 1;
482 psh.hwndParent = GetDesktopWindow();
483 U3(psh).phpage = hpsp;
484 psh.pfnCallback = sheet_callback;
486 hdlg = (HWND)PropertySheetA(&psh);
487 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
489 /* OK button */
490 button = GetDlgItem(hdlg, IDOK);
491 GetWindowRect(button, &rc);
492 prevRight = rc.right;
493 top = rc.top;
495 /* Cancel button */
496 button = GetDlgItem(hdlg, IDCANCEL);
497 GetWindowRect(button, &rc);
498 ok(rc.top == top, "Cancel button should have same top as OK button\n");
499 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
500 prevRight = rc.right;
502 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
503 GetWindowRect(button, &rc);
504 ok(rc.top == top, "Apply button should have same top as OK button\n");
505 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
506 prevRight = rc.right;
508 button = GetDlgItem(hdlg, IDHELP);
509 GetWindowRect(button, &rc);
510 ok(rc.top == top, "Help button should have same top as OK button\n");
511 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
513 DestroyWindow(hdlg);
516 static BOOL add_button_has_been_pressed;
518 static INT_PTR CALLBACK
519 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
521 switch (msg)
523 case WM_COMMAND:
524 switch(LOWORD(wparam))
526 case IDC_PS_PUSHBUTTON1:
527 switch(HIWORD(wparam))
529 case BN_CLICKED:
530 add_button_has_been_pressed = TRUE;
531 return TRUE;
533 break;
535 break;
537 return FALSE;
540 static void test_custom_default_button(void)
542 HWND hdlg, page;
543 PROPSHEETPAGEA psp[1];
544 PROPSHEETHEADERA psh;
545 MSG msg;
546 LRESULT result;
548 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
549 psp[0].dwFlags = PSP_USETITLE;
550 psp[0].hInstance = GetModuleHandleA(NULL);
551 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
552 U2(psp[0]).pszIcon = NULL;
553 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
554 psp[0].pszTitle = "Page1";
555 psp[0].lParam = 0;
557 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
558 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
559 psh.hwndParent = GetDesktopWindow();
560 psh.hInstance = GetModuleHandleA(NULL);
561 U(psh).pszIcon = NULL;
562 psh.pszCaption = "PropertySheet1";
563 psh.nPages = 1;
564 U3(psh).ppsp = psp;
565 U2(psh).nStartPage = 0;
567 /* The goal of the test is to make sure that the Add button is pressed
568 * when the ENTER key is pressed and a different control, a combobox,
569 * has the keyboard focus. */
570 add_button_has_been_pressed = FALSE;
572 /* Create the modeless property sheet. */
573 hdlg = (HWND)PropertySheetA(&psh);
574 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
576 /* Set the Add button as the default button. */
577 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
579 /* Make sure the default button is the Add button. */
580 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
581 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
582 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
584 /* At this point, the combobox should have keyboard focus, so we press ENTER.
585 * Pull the lever, Kronk! */
586 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
587 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0);
589 /* Process all the messages in the queue for this thread. */
590 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
592 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */
593 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg)))
595 TranslateMessage(&msg);
596 DispatchMessageA(&msg);
600 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
602 DestroyWindow(hdlg);
605 #define RECEIVER_SHEET_CALLBACK 0
606 #define RECEIVER_SHEET_WINPROC 1
607 #define RECEIVER_PAGE 2
609 #define NUM_MSG_SEQUENCES 1
610 #define PROPSHEET_SEQ_INDEX 0
612 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
613 static WNDPROC oldWndProc;
615 static const struct message property_sheet_seq[] = {
616 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
617 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
618 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
619 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
620 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
621 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
622 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
623 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
624 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
625 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
626 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
627 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
628 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
629 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
630 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
631 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
632 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
633 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
634 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
635 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
636 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
637 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
638 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
639 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
640 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
641 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
642 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
643 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
644 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
645 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
646 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
647 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
648 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
649 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
650 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
651 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
652 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
653 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
654 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
655 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
656 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
657 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
658 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
659 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
660 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
661 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
662 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
663 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
664 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
665 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
666 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
667 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
668 /*{ WM_NCPAINT, 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_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
673 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
674 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
675 /*{ WM_GETICON, 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_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
679 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
680 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
681 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
682 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
683 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
684 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
685 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
686 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
687 { WM_CTLCOLORBTN, 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_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
692 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
693 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
694 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
695 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
696 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
697 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
698 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
699 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
700 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
701 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
702 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
703 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
704 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
705 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
706 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
707 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
708 { 0 }
711 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
713 struct message msg;
715 if (message < WM_USER &&
716 message != WM_GETICON &&
717 message != WM_GETTEXT &&
718 message != WM_IME_SETCONTEXT &&
719 message != WM_IME_NOTIFY &&
720 message != WM_PAINT &&
721 message != WM_ERASEBKGND &&
722 message != WM_SETCURSOR &&
723 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
724 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
725 message != 0x90)
727 msg.message = message;
728 msg.flags = sent|wparam|lparam|id;
729 msg.wParam = wParam;
730 msg.lParam = lParam;
731 msg.id = receiver;
732 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
736 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
738 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
740 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
743 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
745 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
747 switch (msg)
749 case PSCB_INITIALIZED:
750 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
751 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
752 return TRUE;
755 return TRUE;
758 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
759 LPARAM lParam)
761 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
763 return FALSE;
766 static void test_messages(void)
768 HPROPSHEETPAGE hpsp[1];
769 PROPSHEETPAGEA psp;
770 PROPSHEETHEADERA psh;
771 HWND hdlg;
773 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
775 memset(&psp, 0, sizeof(psp));
776 psp.dwSize = sizeof(psp);
777 psp.dwFlags = 0;
778 psp.hInstance = GetModuleHandleA(NULL);
779 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
780 U2(psp).pszIcon = NULL;
781 psp.pfnDlgProc = page_dlg_proc_messages;
782 psp.lParam = 0;
784 hpsp[0] = CreatePropertySheetPageA(&psp);
786 memset(&psh, 0, sizeof(psh));
787 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
788 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
789 | PSH_MODELESS | PSH_USEICONID;
790 psh.pszCaption = "test caption";
791 psh.nPages = 1;
792 psh.hwndParent = GetDesktopWindow();
793 U3(psh).phpage = hpsp;
794 psh.pfnCallback = sheet_callback_messages;
796 hdlg = (HWND)PropertySheetA(&psh);
797 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
799 ShowWindow(hdlg,SW_NORMAL);
801 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
803 DestroyWindow(hdlg);
806 static void test_PSM_ADDPAGE(void)
808 HPROPSHEETPAGE hpsp[5];
809 PROPSHEETPAGEA psp;
810 PROPSHEETHEADERA psh;
811 HWND hdlg, tab;
812 BOOL ret;
813 DWORD r;
815 memset(&psp, 0, sizeof(psp));
816 psp.dwSize = sizeof(psp);
817 psp.dwFlags = 0;
818 psp.hInstance = GetModuleHandleA(NULL);
819 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
820 U2(psp).pszIcon = NULL;
821 psp.pfnDlgProc = page_dlg_proc_messages;
822 psp.lParam = 0;
824 /* multiple pages with the same data */
825 hpsp[0] = CreatePropertySheetPageA(&psp);
826 hpsp[1] = CreatePropertySheetPageA(&psp);
827 hpsp[2] = CreatePropertySheetPageA(&psp);
829 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
830 hpsp[3] = CreatePropertySheetPageA(&psp);
832 psp.dwFlags = PSP_PREMATURE;
833 hpsp[4] = CreatePropertySheetPageA(&psp);
835 memset(&psh, 0, sizeof(psh));
836 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
837 psh.dwFlags = PSH_MODELESS;
838 psh.pszCaption = "test caption";
839 psh.nPages = 1;
840 psh.hwndParent = GetDesktopWindow();
841 U3(psh).phpage = hpsp;
843 hdlg = (HWND)PropertySheetA(&psh);
844 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
846 /* add pages one by one */
847 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
848 ok(ret == TRUE, "got %d\n", ret);
850 /* try with null and invalid value */
851 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
852 ok(ret == FALSE, "got %d\n", ret);
854 if (0)
856 /* crashes on native */
857 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
859 /* check item count */
860 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
862 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
863 ok(r == 2, "got %d\n", r);
865 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
866 ok(ret == TRUE, "got %d\n", ret);
868 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
869 ok(r == 3, "got %d\n", r);
871 /* add property sheet page that can't be created */
872 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
873 ok(ret == TRUE, "got %d\n", ret);
875 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
876 ok(r == 4, "got %d\n", r);
878 /* select page that can't be created */
879 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1);
880 ok(ret == TRUE, "got %d\n", ret);
882 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
883 ok(r == 3, "got %d\n", r);
885 /* test PSP_PREMATURE flag with incorrect property sheet page */
886 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
887 ok(ret == FALSE, "got %d\n", ret);
889 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
890 ok(r == 3, "got %d\n", r);
892 DestroyPropertySheetPage(hpsp[4]);
893 DestroyWindow(hdlg);
896 static void test_PSM_INSERTPAGE(void)
898 HPROPSHEETPAGE hpsp[5];
899 PROPSHEETPAGEA psp;
900 PROPSHEETHEADERA psh;
901 HWND hdlg, tab;
902 BOOL ret;
903 DWORD r;
905 memset(&psp, 0, sizeof(psp));
906 psp.dwSize = sizeof(psp);
907 psp.dwFlags = 0;
908 psp.hInstance = GetModuleHandleA(NULL);
909 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
910 U2(psp).pszIcon = NULL;
911 psp.pfnDlgProc = page_dlg_proc_messages;
912 psp.lParam = 0;
914 /* multiple pages with the same data */
915 hpsp[0] = CreatePropertySheetPageA(&psp);
916 hpsp[1] = CreatePropertySheetPageA(&psp);
917 hpsp[2] = CreatePropertySheetPageA(&psp);
919 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
920 hpsp[3] = CreatePropertySheetPageA(&psp);
922 psp.dwFlags = PSP_PREMATURE;
923 hpsp[4] = CreatePropertySheetPageA(&psp);
925 memset(&psh, 0, sizeof(psh));
926 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
927 psh.dwFlags = PSH_MODELESS;
928 psh.pszCaption = "test caption";
929 psh.nPages = 1;
930 psh.hwndParent = GetDesktopWindow();
931 U3(psh).phpage = hpsp;
933 hdlg = (HWND)PropertySheetA(&psh);
934 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
936 /* add pages one by one */
937 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 5, (LPARAM)hpsp[1]);
938 ok(ret == TRUE, "got %d\n", ret);
940 /* try with invalid values */
941 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, 0);
942 ok(ret == FALSE, "got %d\n", ret);
944 if (0)
946 /* crashes on native */
947 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
950 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)hpsp[2]);
951 ok(ret == FALSE, "got %d\n", ret);
953 /* check item count */
954 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
956 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
957 ok(r == 2, "got %d\n", r);
959 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)hpsp[1], (LPARAM)hpsp[2]);
960 ok(ret == TRUE, "got %d\n", ret);
962 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
963 ok(r == 3, "got %d\n", r);
965 /* add property sheet page that can't be created */
966 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 1, (LPARAM)hpsp[3]);
967 ok(ret == TRUE, "got %d\n", ret);
969 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
970 ok(r == 4, "got %d\n", r);
972 /* select page that can't be created */
973 ret = SendMessageA(hdlg, PSM_SETCURSEL, 1, 0);
974 ok(ret == TRUE, "got %d\n", ret);
976 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
977 ok(r == 3, "got %d\n", r);
979 /* test PSP_PREMATURE flag with incorrect property sheet page */
980 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)hpsp[4]);
981 ok(ret == FALSE, "got %d\n", ret);
983 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
984 ok(r == 3, "got %d\n", r);
986 DestroyPropertySheetPage(hpsp[4]);
987 DestroyWindow(hdlg);
990 struct custom_proppage
992 union
994 PROPSHEETPAGEA pageA;
995 PROPSHEETPAGEW pageW;
996 } u;
997 unsigned int addref_called;
998 unsigned int release_called;
1001 static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp)
1003 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1004 PROPSHEETPAGEA *psp_orig = &cpage->u.pageA;
1006 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1008 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1009 psp->lParam, psp);
1010 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1011 ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1013 switch (msg)
1015 case PSPCB_ADDREF:
1016 ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1017 cpage->addref_called++;
1018 break;
1019 case PSPCB_RELEASE:
1020 ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1021 cpage->release_called++;
1022 break;
1023 default:
1024 ok(0, "Unexpected message %u\n", msg);
1027 return 1;
1030 static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp)
1032 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1033 PROPSHEETPAGEW *psp_orig = &cpage->u.pageW;
1035 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1036 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n",
1037 psp->lParam, psp);
1038 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1039 ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1041 switch (msg)
1043 case PSPCB_ADDREF:
1044 ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize);
1045 cpage->addref_called++;
1046 break;
1047 case PSPCB_RELEASE:
1048 ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize);
1049 cpage->release_called++;
1050 break;
1051 default:
1052 ok(0, "Unexpected message %u\n", msg);
1055 return 1;
1058 static void test_CreatePropertySheetPage(void)
1060 static const WCHAR titleW[] = {'T','i','t','l','e',0};
1061 struct custom_proppage page;
1062 HPROPSHEETPAGE hpsp;
1063 BOOL ret;
1065 memset(&page.u.pageA, 0, sizeof(page.u.pageA));
1066 page.u.pageA.dwFlags = PSP_USECALLBACK;
1067 page.u.pageA.pfnDlgProc = page_dlg_proc_messages;
1068 page.u.pageA.pfnCallback = proppage_callback_a;
1069 page.u.pageA.lParam = (LPARAM)&page;
1070 page.u.pageA.pszTitle = "Title";
1072 /* Only minimal size validation is performed */
1073 for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1; page.u.pageA.dwSize <= PROPSHEETPAGEA_V4_SIZE + 1; page.u.pageA.dwSize++)
1075 page.addref_called = 0;
1076 hpsp = CreatePropertySheetPageA(&page.u.pageA);
1078 if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE)
1079 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageA.dwSize);
1080 else
1082 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageA.dwSize);
1083 todo_wine_if(page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE)
1084 ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1087 if (hpsp)
1089 page.release_called = 0;
1090 ret = DestroyPropertySheetPage(hpsp);
1091 ok(ret, "Failed to destroy a page\n");
1092 todo_wine
1093 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1097 memset(&page.u.pageW, 0, sizeof(page.u.pageW));
1098 page.u.pageW.dwFlags = PSP_USECALLBACK;
1099 page.u.pageW.pfnDlgProc = page_dlg_proc_messages;
1100 page.u.pageW.pfnCallback = proppage_callback_w;
1101 page.u.pageW.lParam = (LPARAM)&page;
1102 page.u.pageW.pszTitle = titleW;
1104 for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1; page.u.pageW.dwSize <= PROPSHEETPAGEW_V4_SIZE + 1; page.u.pageW.dwSize++)
1106 page.addref_called = 0;
1107 hpsp = CreatePropertySheetPageW(&page.u.pageW);
1109 if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE)
1110 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageW.dwSize);
1111 else
1113 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageW.dwSize);
1114 todo_wine_if(page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE)
1115 ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1118 if (hpsp)
1120 page.release_called = 0;
1121 ret = DestroyPropertySheetPage(hpsp);
1122 ok(ret, "Failed to destroy a page\n");
1123 todo_wine
1124 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1129 START_TEST(propsheet)
1131 test_title();
1132 test_nopage();
1133 test_disableowner();
1134 test_wiznavigation();
1135 test_buttons();
1136 test_custom_default_button();
1137 test_messages();
1138 test_PSM_ADDPAGE();
1139 test_PSM_INSERTPAGE();
1140 test_CreatePropertySheetPage();