opengl32: Correctly interpret glMapBuffer() access in wow64 mapping.
[wine.git] / dlls / comctl32 / tests / propsheet.c
blob7c0d5f816425dc865e54dd9e93a199a195aa9339
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 #include "v6util.h"
31 static HWND parenthwnd;
32 static HWND sheethwnd;
34 static BOOL rtl;
35 static LONG active_page = -1;
37 static BOOL is_v6, is_theme_active;
39 #define IDC_APPLY_BUTTON 12321
41 static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageA)(const PROPSHEETPAGEA *desc);
42 static HPROPSHEETPAGE (WINAPI *pCreatePropertySheetPageW)(const PROPSHEETPAGEW *desc);
43 static BOOL (WINAPI *pDestroyPropertySheetPage)(HPROPSHEETPAGE proppage);
44 static INT_PTR (WINAPI *pPropertySheetA)(const PROPSHEETHEADERA *header);
45 static INT_PTR (WINAPI *pPropertySheetW)(const PROPSHEETHEADERW *header);
47 static BOOL (WINAPI *pIsThemeActive)(void);
48 static BOOL (WINAPI *pIsThemeDialogTextureEnabled)(HWND);
50 static void detect_locale(void)
52 DWORD reading_layout;
53 rtl = GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER,
54 (void *)&reading_layout, sizeof(reading_layout)) && reading_layout == 1;
57 /* try to make sure pending X events have been processed before continuing */
58 static void flush_events(void)
60 MSG msg;
61 int diff = 200;
62 int min_timeout = 100;
63 DWORD time = GetTickCount() + diff;
65 while (diff > 0)
67 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
68 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
69 diff = time - GetTickCount();
74 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
76 switch(msg)
78 case PSCB_PRECREATE:
80 HMODULE module = GetModuleHandleA("comctl32.dll");
81 DWORD size, buffer_size;
82 HRSRC hrsrc;
84 hrsrc = FindResourceA(module, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */),
85 (LPSTR)RT_DIALOG);
86 size = SizeofResource(module, hrsrc);
87 ok(size != 0, "Failed to get size of propsheet dialog resource\n");
88 buffer_size = HeapSize(GetProcessHeap(), 0, (void *)lparam);
89 /* Hebrew Windows 10 allocates 2 * size + 8,
90 * Arabic Windows 10 allocates 2 * size - 32,
91 * all others allocate exactly 2 * size */
92 ok(buffer_size >= 2 * size || broken(buffer_size == 2 * size - 32),
93 "Unexpected template buffer size %lu, resource size %lu\n",
94 buffer_size, size);
95 break;
97 case PSCB_INITIALIZED:
99 char caption[256];
100 GetWindowTextA(hwnd, caption, sizeof(caption));
101 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
102 sheethwnd = hwnd;
103 return 0;
106 return 0;
109 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
110 LPARAM lparam)
112 switch(msg)
114 case WM_INITDIALOG:
116 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)lparam;
117 HWND sheet = GetParent(hwnd);
118 char caption[256];
120 GetWindowTextA(sheet, caption, sizeof(caption));
121 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
123 if (psp->dwFlags & PSP_USETITLE)
125 ok(!strcmp(psp->pszTitle, "page title"), "psp->pszTitle = %s\n",
126 wine_dbgstr_a(psp->pszTitle));
128 return TRUE;
131 case WM_NOTIFY:
133 NMHDR *nmhdr = (NMHDR *)lparam;
134 switch(nmhdr->code)
136 case PSN_APPLY:
137 return TRUE;
138 default:
139 return FALSE;
142 case WM_NCDESTROY:
143 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
144 return TRUE;
146 default:
147 return FALSE;
151 static void test_title(void)
153 HPROPSHEETPAGE hpsp[1];
154 PROPSHEETPAGEA psp;
155 PROPSHEETHEADERA psh;
156 HWND hdlg;
157 DWORD style;
159 memset(&psp, 0, sizeof(psp));
160 psp.dwSize = sizeof(psp);
161 psp.dwFlags = PSP_USETITLE;
162 psp.hInstance = GetModuleHandleA(NULL);
163 psp.pszTitle = "page title";
164 U(psp).pszTemplate = "prop_page1";
165 U2(psp).pszIcon = NULL;
166 psp.pfnDlgProc = page_dlg_proc;
167 psp.lParam = 0;
169 hpsp[0] = pCreatePropertySheetPageA(&psp);
171 memset(&psh, 0, sizeof(psh));
172 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
173 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
174 psh.pszCaption = "test caption";
175 psh.nPages = 1;
176 psh.hwndParent = GetDesktopWindow();
177 U3(psh).phpage = hpsp;
178 psh.pfnCallback = sheet_callback;
180 hdlg = (HWND)pPropertySheetA(&psh);
181 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
183 style = GetWindowLongA(hdlg, GWL_STYLE);
184 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|
185 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
186 "got unexpected style: %lx\n", style);
188 DestroyWindow(hdlg);
191 static void test_nopage(void)
193 HPROPSHEETPAGE hpsp[1];
194 PROPSHEETPAGEA psp;
195 PROPSHEETHEADERA psh;
196 HWND hdlg, hpage;
197 MSG msg;
199 memset(&psp, 0, sizeof(psp));
200 psp.dwSize = sizeof(psp);
201 psp.dwFlags = 0;
202 psp.hInstance = GetModuleHandleA(NULL);
203 U(psp).pszTemplate = "prop_page1";
204 U2(psp).pszIcon = NULL;
205 psp.pfnDlgProc = page_dlg_proc;
206 psp.lParam = 0;
208 hpsp[0] = pCreatePropertySheetPageA(&psp);
210 memset(&psh, 0, sizeof(psh));
211 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
212 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
213 psh.pszCaption = "test caption";
214 psh.nPages = 1;
215 psh.hwndParent = GetDesktopWindow();
216 U3(psh).phpage = hpsp;
217 psh.pfnCallback = sheet_callback;
219 hdlg = (HWND)pPropertySheetA(&psh);
220 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
222 ShowWindow(hdlg,SW_NORMAL);
223 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0);
224 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */
225 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
226 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */
227 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0);
228 ok(hpage == NULL, "expected no current page, got %p, index=%ld\n", hpage, active_page);
229 flush_events();
230 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
232 /* Check that the property sheet was fully redrawn */
233 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
234 "expected no pending WM_PAINT messages\n");
235 DestroyWindow(hdlg);
238 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
240 switch(msg)
242 case PSCB_INITIALIZED:
244 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
245 PostQuitMessage(0);
246 return FALSE;
249 return FALSE;
252 static void register_parent_wnd_class(void)
254 WNDCLASSA cls;
256 cls.style = 0;
257 cls.lpfnWndProc = DefWindowProcA;
258 cls.cbClsExtra = 0;
259 cls.cbWndExtra = 0;
260 cls.hInstance = GetModuleHandleA(NULL);
261 cls.hIcon = 0;
262 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
263 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
264 cls.lpszMenuName = NULL;
265 cls.lpszClassName = "parent class";
266 RegisterClassA(&cls);
269 static void test_disableowner(void)
271 HPROPSHEETPAGE hpsp[1];
272 PROPSHEETPAGEA psp;
273 PROPSHEETHEADERA psh;
274 INT_PTR p;
276 register_parent_wnd_class();
277 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
279 memset(&psp, 0, sizeof(psp));
280 psp.dwSize = sizeof(psp);
281 psp.dwFlags = 0;
282 psp.hInstance = GetModuleHandleA(NULL);
283 U(psp).pszTemplate = "prop_page1";
284 U2(psp).pszIcon = NULL;
285 psp.pfnDlgProc = NULL;
286 psp.lParam = 0;
288 hpsp[0] = pCreatePropertySheetPageA(&psp);
290 memset(&psh, 0, sizeof(psh));
291 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
292 psh.dwFlags = PSH_USECALLBACK;
293 psh.pszCaption = "test caption";
294 psh.nPages = 1;
295 psh.hwndParent = parenthwnd;
296 U3(psh).phpage = hpsp;
297 psh.pfnCallback = disableowner_callback;
299 p = pPropertySheetA(&psh);
300 ok(p == 0, "Expected 0, got %Id\n", p);
301 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
302 DestroyWindow(parenthwnd);
305 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
307 switch(msg){
308 case WM_NOTIFY:
310 LPNMHDR hdr = (LPNMHDR)lparam;
311 switch(hdr->code){
312 case PSN_SETACTIVE:
313 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
314 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0);
315 return TRUE;
316 case PSN_KILLACTIVE:
317 /* prevent navigation away from the fourth page */
318 if(active_page == 3){
319 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE);
320 return TRUE;
323 break;
326 return FALSE;
329 static WNDPROC old_nav_dialog_proc;
331 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
333 switch (msg)
335 case DM_SETDEFID:
336 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" );
337 break;
339 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp );
342 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
344 static BOOL done;
345 if (code == HCBT_CREATEWND)
347 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp;
349 /* The first dialog created will be the parent dialog */
350 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG)
352 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc );
353 done = TRUE;
357 return CallNextHookEx( NULL, code, wp, lp );
360 static void test_wiznavigation(void)
362 HPROPSHEETPAGE hpsp[4];
363 PROPSHEETPAGEA psp[4];
364 PROPSHEETHEADERA psh;
365 HWND hdlg, control;
366 LONG_PTR controlID;
367 DWORD style;
368 LRESULT defidres;
369 BOOL hwndtoindex_supported = TRUE;
370 const INT nextID = 12324;
371 const INT backID = 12323;
372 HHOOK hook;
374 /* set up a hook proc in order to subclass the main dialog early on */
375 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
377 /* create the property sheet pages */
378 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
380 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
381 psp[0].hInstance = GetModuleHandleA(NULL);
382 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
383 psp[0].pfnDlgProc = nav_page_proc;
384 hpsp[0] = pCreatePropertySheetPageA(&psp[0]);
386 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
387 psp[1].hInstance = GetModuleHandleA(NULL);
388 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
389 psp[1].pfnDlgProc = nav_page_proc;
390 hpsp[1] = pCreatePropertySheetPageA(&psp[1]);
392 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
393 psp[2].hInstance = GetModuleHandleA(NULL);
394 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
395 psp[2].pfnDlgProc = nav_page_proc;
396 hpsp[2] = pCreatePropertySheetPageA(&psp[2]);
398 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
399 psp[3].hInstance = GetModuleHandleA(NULL);
400 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
401 psp[3].pfnDlgProc = nav_page_proc;
402 hpsp[3] = pCreatePropertySheetPageA(&psp[3]);
404 /* set up the property sheet dialog */
405 memset(&psh, 0, sizeof(psh));
406 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
407 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
408 psh.pszCaption = "A Wizard";
409 psh.nPages = 4;
410 psh.hwndParent = GetDesktopWindow();
411 U3(psh).phpage = hpsp;
412 hdlg = (HWND)pPropertySheetA(&psh);
413 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
415 ok(active_page == 0, "Active page should be 0. Is: %ld\n", active_page);
417 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
418 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
419 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
420 "got unexpected style: %lx\n", style);
422 control = GetFocus();
423 controlID = GetWindowLongPtrA(control, GWLP_ID);
424 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %Id\n", nextID, controlID);
426 /* simulate pressing the Next button */
427 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
428 if (!active_page) hwndtoindex_supported = FALSE;
429 if (hwndtoindex_supported)
430 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %ld\n", active_page);
432 control = GetFocus();
433 controlID = GetWindowLongPtrA(control, GWLP_ID);
434 ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %Id\n", IDC_PS_EDIT1, controlID);
436 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
437 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
439 /* set the focus to the second edit box on this page */
440 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
442 /* press next again */
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: %ld\n", active_page);
447 control = GetFocus();
448 controlID = GetWindowLongPtrA(control, GWLP_ID);
449 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %Id\n", IDC_PS_RADIO1, controlID);
451 /* back button */
452 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
453 if (hwndtoindex_supported)
454 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %ld\n", active_page);
456 control = GetFocus();
457 controlID = GetWindowLongPtrA(control, GWLP_ID);
458 ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %Id\n", IDC_PS_EDIT1, controlID);
460 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
461 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
463 /* press next twice */
464 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
465 if (hwndtoindex_supported)
466 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %ld\n", active_page);
467 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
468 if (hwndtoindex_supported)
469 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %ld\n", active_page);
470 else
471 active_page = 3;
473 control = GetFocus();
474 controlID = GetWindowLongPtrA(control, GWLP_ID);
475 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %Id\n", nextID, controlID);
477 /* try to navigate away, but shouldn't be able to */
478 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
479 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %ld\n", active_page);
481 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
482 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
484 DestroyWindow(hdlg);
485 UnhookWindowsHookEx( hook );
488 static void test_buttons(void)
490 HPROPSHEETPAGE hpsp[1];
491 PROPSHEETPAGEA psp;
492 PROPSHEETHEADERA psh;
493 HWND hdlg;
494 HWND button;
495 RECT rc;
496 int prevRight, top;
498 memset(&psp, 0, sizeof(psp));
499 psp.dwSize = sizeof(psp);
500 psp.dwFlags = 0;
501 psp.hInstance = GetModuleHandleA(NULL);
502 U(psp).pszTemplate = "prop_page1";
503 U2(psp).pszIcon = NULL;
504 psp.pfnDlgProc = page_dlg_proc;
505 psp.lParam = 0;
507 hpsp[0] = pCreatePropertySheetPageA(&psp);
509 memset(&psh, 0, sizeof(psh));
510 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
511 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
512 psh.pszCaption = "test caption";
513 psh.nPages = 1;
514 psh.hwndParent = GetDesktopWindow();
515 U3(psh).phpage = hpsp;
516 psh.pfnCallback = sheet_callback;
518 hdlg = (HWND)pPropertySheetA(&psh);
519 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
521 /* OK button */
522 button = GetDlgItem(hdlg, IDOK);
523 GetWindowRect(button, &rc);
524 prevRight = rc.right;
525 top = rc.top;
527 /* Cancel button */
528 button = GetDlgItem(hdlg, IDCANCEL);
529 GetWindowRect(button, &rc);
530 ok(rc.top == top, "Cancel button should have same top as OK button\n");
531 if (rtl)
532 ok(rc.left < prevRight, "Cancel button should be to the left of OK button\n");
533 else
534 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
535 prevRight = rc.right;
537 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
538 GetWindowRect(button, &rc);
539 ok(rc.top == top, "Apply button should have same top as OK button\n");
540 if (rtl)
541 ok(rc.left < prevRight, "Apply button should be to the left of Cancel button\n");
542 else
543 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
544 prevRight = rc.right;
546 button = GetDlgItem(hdlg, IDHELP);
547 GetWindowRect(button, &rc);
548 ok(rc.top == top, "Help button should have same top as OK button\n");
549 if (rtl)
550 ok(rc.left < prevRight, "Help button should be to the left of Apply button\n");
551 else
552 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
554 DestroyWindow(hdlg);
557 static BOOL add_button_has_been_pressed;
559 static INT_PTR CALLBACK
560 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
562 switch (msg)
564 case WM_COMMAND:
565 switch(LOWORD(wparam))
567 case IDC_PS_PUSHBUTTON1:
568 switch(HIWORD(wparam))
570 case BN_CLICKED:
571 add_button_has_been_pressed = TRUE;
572 return TRUE;
574 break;
576 break;
578 return FALSE;
581 static void test_custom_default_button(void)
583 HWND hdlg, page;
584 PROPSHEETPAGEA psp[1];
585 PROPSHEETHEADERA psh;
586 MSG msg;
587 LRESULT result;
589 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
590 psp[0].dwFlags = PSP_USETITLE;
591 psp[0].hInstance = GetModuleHandleA(NULL);
592 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
593 U2(psp[0]).pszIcon = NULL;
594 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
595 psp[0].pszTitle = "Page1";
596 psp[0].lParam = 0;
598 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
599 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
600 psh.hwndParent = GetDesktopWindow();
601 psh.hInstance = GetModuleHandleA(NULL);
602 U(psh).pszIcon = NULL;
603 psh.pszCaption = "PropertySheet1";
604 psh.nPages = 1;
605 U3(psh).ppsp = psp;
606 U2(psh).nStartPage = 0;
608 /* The goal of the test is to make sure that the Add button is pressed
609 * when the ENTER key is pressed and a different control, a combobox,
610 * has the keyboard focus. */
611 add_button_has_been_pressed = FALSE;
613 /* Create the modeless property sheet. */
614 hdlg = (HWND)pPropertySheetA(&psh);
615 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
617 /* Set the Add button as the default button. */
618 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
620 /* Make sure the default button is the Add button. */
621 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
622 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
623 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
625 /* At this point, the combobox should have keyboard focus, so we press ENTER.
626 * Pull the lever, Kronk! */
627 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
628 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0);
630 /* Process all the messages in the queue for this thread. */
631 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
633 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */
634 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg)))
636 TranslateMessage(&msg);
637 DispatchMessageA(&msg);
641 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
643 DestroyWindow(hdlg);
646 #define RECEIVER_SHEET_CALLBACK 0
647 #define RECEIVER_SHEET_WINPROC 1
648 #define RECEIVER_PAGE 2
650 #define NUM_MSG_SEQUENCES 1
651 #define PROPSHEET_SEQ_INDEX 0
653 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
654 static WNDPROC oldWndProc;
656 static const struct message property_sheet_seq[] = {
657 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
658 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
659 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
660 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
661 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
662 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
663 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
664 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
665 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
666 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
667 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
668 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
669 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
670 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
671 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
672 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
673 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
674 /*{ WM_NCACTIVATE, sent|id, 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_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
680 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
681 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
682 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
683 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
684 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
685 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
686 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
687 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
688 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
689 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
690 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
691 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
692 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
693 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
694 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
695 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
696 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
697 /*{ WM_GETTEXT, 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_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
701 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
702 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
703 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
704 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
705 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
706 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
707 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
708 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
709 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
710 /*{ WM_NCPAINT, 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_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
714 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
715 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
716 { WM_WINDOWPOSCHANGED, 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_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
721 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
722 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
723 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
724 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
725 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
726 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
727 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
728 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
729 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
730 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
731 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
732 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
733 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
734 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
735 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
736 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
737 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
738 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
739 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
740 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
741 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
742 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
743 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
744 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
745 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
746 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
747 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
748 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
749 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
750 { 0 }
753 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
755 struct message msg = { 0 };
757 if (message < WM_USER &&
758 message != WM_GETICON &&
759 message != WM_GETTEXT &&
760 message != WM_IME_SETCONTEXT &&
761 message != WM_IME_NOTIFY &&
762 message != WM_PAINT &&
763 message != WM_ERASEBKGND &&
764 message != WM_SETCURSOR &&
765 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
766 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
767 message != 0x90)
769 msg.message = message;
770 msg.flags = sent|wparam|lparam|id;
771 msg.wParam = wParam;
772 msg.lParam = lParam;
773 msg.id = receiver;
774 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
778 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
780 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
782 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
785 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
787 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
789 switch (msg)
791 case PSCB_INITIALIZED:
792 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
793 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
794 return TRUE;
797 return TRUE;
800 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
801 LPARAM lParam)
803 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
805 return FALSE;
808 static void test_messages(void)
810 HPROPSHEETPAGE hpsp[1];
811 PROPSHEETPAGEA psp;
812 PROPSHEETHEADERA psh;
813 HWND hdlg;
815 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
817 memset(&psp, 0, sizeof(psp));
818 psp.dwSize = sizeof(psp);
819 psp.dwFlags = 0;
820 psp.hInstance = GetModuleHandleA(NULL);
821 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
822 U2(psp).pszIcon = NULL;
823 psp.pfnDlgProc = page_dlg_proc_messages;
824 psp.lParam = 0;
826 hpsp[0] = pCreatePropertySheetPageA(&psp);
828 memset(&psh, 0, sizeof(psh));
829 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
830 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
831 | PSH_MODELESS | PSH_USEICONID;
832 psh.pszCaption = "test caption";
833 psh.nPages = 1;
834 psh.hwndParent = GetDesktopWindow();
835 U3(psh).phpage = hpsp;
836 psh.pfnCallback = sheet_callback_messages;
838 hdlg = (HWND)pPropertySheetA(&psh);
839 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
841 ShowWindow(hdlg,SW_NORMAL);
843 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
845 DestroyWindow(hdlg);
848 static void test_PSM_ADDPAGE(void)
850 HPROPSHEETPAGE hpsp[5];
851 PROPSHEETPAGEA psp;
852 PROPSHEETHEADERA psh;
853 HWND hdlg, tab;
854 BOOL ret;
855 DWORD r;
857 memset(&psp, 0, sizeof(psp));
858 psp.dwSize = sizeof(psp);
859 psp.dwFlags = 0;
860 psp.hInstance = GetModuleHandleA(NULL);
861 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
862 U2(psp).pszIcon = NULL;
863 psp.pfnDlgProc = page_dlg_proc_messages;
864 psp.lParam = 0;
866 /* multiple pages with the same data */
867 hpsp[0] = pCreatePropertySheetPageA(&psp);
868 hpsp[1] = pCreatePropertySheetPageA(&psp);
869 hpsp[2] = pCreatePropertySheetPageA(&psp);
871 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
872 hpsp[3] = pCreatePropertySheetPageA(&psp);
874 psp.dwFlags = PSP_PREMATURE;
875 hpsp[4] = pCreatePropertySheetPageA(&psp);
877 memset(&psh, 0, sizeof(psh));
878 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
879 psh.dwFlags = PSH_MODELESS;
880 psh.pszCaption = "test caption";
881 psh.nPages = 1;
882 psh.hwndParent = GetDesktopWindow();
883 U3(psh).phpage = hpsp;
885 hdlg = (HWND)pPropertySheetA(&psh);
886 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
888 /* add pages one by one */
889 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
890 ok(ret == TRUE, "got %d\n", ret);
892 /* try with null and invalid value */
893 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
894 ok(ret == FALSE, "got %d\n", ret);
896 if (0)
898 /* crashes on native */
899 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
901 /* check item count */
902 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
904 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
905 ok(r == 2, "got %ld\n", r);
907 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
908 ok(ret == TRUE, "got %d\n", ret);
910 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
911 ok(r == 3, "got %ld\n", r);
913 /* add property sheet page that can't be created */
914 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
915 ok(ret == TRUE, "got %d\n", ret);
917 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
918 ok(r == 4, "got %ld\n", r);
920 /* select page that can't be created */
921 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1);
922 ok(ret == TRUE, "got %d\n", ret);
924 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
925 ok(r == 3, "got %ld\n", r);
927 /* test PSP_PREMATURE flag with incorrect property sheet page */
928 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
929 ok(ret == FALSE, "got %d\n", ret);
931 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
932 ok(r == 3, "got %ld\n", r);
934 pDestroyPropertySheetPage(hpsp[4]);
935 DestroyWindow(hdlg);
938 static void test_PSM_INSERTPAGE(void)
940 HPROPSHEETPAGE hpsp[5];
941 PROPSHEETPAGEA psp;
942 PROPSHEETHEADERA psh;
943 HWND hdlg, tab;
944 BOOL ret;
945 DWORD r;
947 memset(&psp, 0, sizeof(psp));
948 psp.dwSize = sizeof(psp);
949 psp.dwFlags = 0;
950 psp.hInstance = GetModuleHandleA(NULL);
951 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
952 U2(psp).pszIcon = NULL;
953 psp.pfnDlgProc = page_dlg_proc_messages;
954 psp.lParam = 0;
956 /* multiple pages with the same data */
957 hpsp[0] = pCreatePropertySheetPageA(&psp);
958 hpsp[1] = pCreatePropertySheetPageA(&psp);
959 hpsp[2] = pCreatePropertySheetPageA(&psp);
961 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
962 hpsp[3] = pCreatePropertySheetPageA(&psp);
964 psp.dwFlags = PSP_PREMATURE;
965 hpsp[4] = pCreatePropertySheetPageA(&psp);
967 memset(&psh, 0, sizeof(psh));
968 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
969 psh.dwFlags = PSH_MODELESS;
970 psh.pszCaption = "test caption";
971 psh.nPages = 1;
972 psh.hwndParent = GetDesktopWindow();
973 U3(psh).phpage = hpsp;
975 hdlg = (HWND)pPropertySheetA(&psh);
976 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
978 /* add pages one by one */
979 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 5, (LPARAM)hpsp[1]);
980 ok(ret == TRUE, "got %d\n", ret);
982 /* try with invalid values */
983 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, 0);
984 ok(ret == FALSE, "got %d\n", ret);
986 if (0)
988 /* crashes on native */
989 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
992 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)hpsp[2]);
993 ok(ret == FALSE, "got %d\n", ret);
995 /* check item count */
996 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
998 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
999 ok(r == 2, "got %ld\n", r);
1001 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)hpsp[1], (LPARAM)hpsp[2]);
1002 ok(ret == TRUE, "got %d\n", ret);
1004 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
1005 ok(r == 3, "got %ld\n", r);
1007 /* add property sheet page that can't be created */
1008 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 1, (LPARAM)hpsp[3]);
1009 ok(ret == TRUE, "got %d\n", ret);
1011 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
1012 ok(r == 4, "got %ld\n", r);
1014 /* select page that can't be created */
1015 ret = SendMessageA(hdlg, PSM_SETCURSEL, 1, 0);
1016 ok(ret == TRUE, "got %d\n", ret);
1018 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
1019 ok(r == 3, "got %ld\n", r);
1021 /* test PSP_PREMATURE flag with incorrect property sheet page */
1022 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)hpsp[4]);
1023 ok(ret == FALSE, "got %d\n", ret);
1025 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
1026 ok(r == 3, "got %ld\n", r);
1028 pDestroyPropertySheetPage(hpsp[4]);
1029 DestroyWindow(hdlg);
1032 struct custom_proppage
1034 union
1036 PROPSHEETPAGEA pageA;
1037 PROPSHEETPAGEW pageW;
1038 } u;
1039 DWORD extra_data;
1040 unsigned int addref_called;
1041 unsigned int release_called;
1044 static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp)
1046 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1047 PROPSHEETPAGEA *psp_orig = &cpage->u.pageA;
1049 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1051 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %Ix, %p\n",
1052 psp->lParam, psp);
1053 if (psp->dwFlags & PSP_USETITLE)
1054 ok(psp_orig->pszTitle != psp->pszTitle, "Expected different page title pointer\n");
1055 else
1056 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1057 ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1058 if (psp->dwSize >= FIELD_OFFSET(struct custom_proppage, addref_called))
1060 struct custom_proppage *extra_data = (struct custom_proppage *)psp;
1061 ok(extra_data->extra_data == 0x1234, "Expected extra_data to be preserved, got %lx\n",
1062 extra_data->extra_data);
1065 switch (msg)
1067 case PSPCB_ADDREF:
1068 ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %lu\n", psp->dwSize);
1069 cpage->addref_called++;
1070 break;
1071 case PSPCB_RELEASE:
1072 ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %lu\n", psp->dwSize);
1073 cpage->release_called++;
1074 break;
1075 default:
1076 ok(0, "Unexpected message %u\n", msg);
1079 return 1;
1082 static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp)
1084 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam;
1085 PROPSHEETPAGEW *psp_orig = &cpage->u.pageW;
1087 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd);
1088 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %Ix, %p\n",
1089 psp->lParam, psp);
1090 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n");
1091 ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n");
1092 if (psp->dwSize >= FIELD_OFFSET(struct custom_proppage, addref_called))
1094 struct custom_proppage *extra_data = (struct custom_proppage *)psp;
1095 ok(extra_data->extra_data == 0x4321, "Expected extra_data to be preserved, got %lx\n",
1096 extra_data->extra_data);
1099 switch (msg)
1101 case PSPCB_ADDREF:
1102 ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %lu\n", psp->dwSize);
1103 cpage->addref_called++;
1104 break;
1105 case PSPCB_RELEASE:
1106 ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %lu\n", psp->dwSize);
1107 cpage->release_called++;
1108 break;
1109 default:
1110 ok(0, "Unexpected message %u\n", msg);
1113 return 1;
1116 static void test_CreatePropertySheetPage(void)
1118 struct custom_proppage page;
1119 HPROPSHEETPAGE hpsp;
1120 BOOL ret;
1122 memset(&page.u.pageA, 0, sizeof(page.u.pageA));
1123 page.u.pageA.dwFlags = PSP_USECALLBACK;
1124 page.u.pageA.pfnDlgProc = page_dlg_proc_messages;
1125 page.u.pageA.pfnCallback = proppage_callback_a;
1126 page.u.pageA.lParam = (LPARAM)&page;
1127 page.u.pageA.pszTitle = "Title";
1129 /* Only minimal size validation is performed */
1130 for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1;
1131 page.u.pageA.dwSize <= FIELD_OFFSET(struct custom_proppage, addref_called);
1132 page.u.pageA.dwSize++)
1134 page.extra_data = 0x1234;
1135 page.addref_called = 0;
1136 hpsp = pCreatePropertySheetPageA(&page.u.pageA);
1138 if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE)
1139 ok(hpsp == NULL, "Expected failure, size %lu\n", page.u.pageA.dwSize);
1140 else
1142 ok(hpsp != NULL, "Failed to create a page, size %lu\n", page.u.pageA.dwSize);
1143 ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1146 if (hpsp)
1148 page.release_called = 0;
1149 ret = pDestroyPropertySheetPage(hpsp);
1150 ok(ret, "Failed to destroy a page\n");
1151 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1155 page.u.pageA.dwSize = sizeof(PROPSHEETPAGEA);
1156 page.u.pageA.dwFlags |= PSP_USETITLE;
1157 page.addref_called = 0;
1158 hpsp = pCreatePropertySheetPageA(&page.u.pageA);
1159 ok(hpsp != NULL, "Failed to create a page, size %lu\n", page.u.pageA.dwSize);
1160 ok(page.addref_called == 1, "Expected ADDREF callback message\n");
1161 page.release_called = 0;
1162 ret = pDestroyPropertySheetPage(hpsp);
1163 ok(ret, "Failed to destroy a page\n");
1164 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1166 memset(&page.u.pageW, 0, sizeof(page.u.pageW));
1167 page.u.pageW.dwFlags = PSP_USECALLBACK;
1168 page.u.pageW.pfnDlgProc = page_dlg_proc_messages;
1169 page.u.pageW.pfnCallback = proppage_callback_w;
1170 page.u.pageW.lParam = (LPARAM)&page;
1171 page.u.pageW.pszTitle = L"Title";
1173 for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1;
1174 page.u.pageW.dwSize <= FIELD_OFFSET(struct custom_proppage, addref_called);
1175 page.u.pageW.dwSize++)
1177 page.extra_data = 0x4321;
1178 page.addref_called = 0;
1179 hpsp = pCreatePropertySheetPageW(&page.u.pageW);
1181 if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE)
1182 ok(hpsp == NULL, "Expected failure, size %lu\n", page.u.pageW.dwSize);
1183 else
1185 ok(hpsp != NULL, "Failed to create a page, size %lu\n", page.u.pageW.dwSize);
1186 ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n");
1189 if (hpsp)
1191 page.release_called = 0;
1192 ret = pDestroyPropertySheetPage(hpsp);
1193 ok(ret, "Failed to destroy a page\n");
1194 ok(page.release_called == 1, "Expected RELEASE callback message\n");
1199 static void test_bad_control_class(void)
1201 PROPSHEETPAGEA psp;
1202 PROPSHEETHEADERA psh;
1203 HPROPSHEETPAGE hpsp;
1204 INT_PTR ret;
1206 memset(&psp, 0, sizeof(psp));
1207 psp.dwSize = sizeof(psp);
1208 psp.hInstance = GetModuleHandleA(NULL);
1209 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_BAD_CONTROL);
1210 psp.pfnDlgProc = page_dlg_proc;
1212 hpsp = pCreatePropertySheetPageA(&psp);
1213 ok(hpsp != 0, "CreatePropertySheetPage failed\n");
1215 memset(&psh, 0, sizeof(psh));
1216 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
1217 psh.nPages = 1;
1218 psh.hwndParent = GetDesktopWindow();
1219 U3(psh).phpage = &hpsp;
1221 ret = pPropertySheetA(&psh);
1222 ok(ret == 0, "got %Id\n", ret);
1224 /* Need to recreate hpsp otherwise the test fails under Windows */
1225 hpsp = pCreatePropertySheetPageA(&psp);
1226 ok(hpsp != 0, "CreatePropertySheetPage failed\n");
1227 U3(psh).phpage = &hpsp;
1229 psh.dwFlags = PSH_MODELESS;
1230 ret = pPropertySheetA(&psh);
1231 ok(ret != 0, "got %Id\n", ret);
1233 ok(IsWindow((HWND)ret), "bad window handle %#Ix\n", ret);
1234 DestroyWindow((HWND)ret);
1237 static INT_PTR CALLBACK test_WM_CTLCOLORSTATIC_proc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
1239 switch(msg)
1241 case WM_INITDIALOG:
1242 sheethwnd = hwnd;
1243 return FALSE;
1245 default:
1246 return FALSE;
1250 static void test_page_dialog_texture(void)
1252 HPROPSHEETPAGE hpsp[1];
1253 PROPSHEETHEADERA psh;
1254 PROPSHEETPAGEA psp;
1255 ULONG_PTR dlgproc;
1256 HWND hdlg, hwnd;
1257 HBRUSH hbrush;
1258 BOOL ret;
1259 HDC hdc;
1261 memset(&psp, 0, sizeof(psp));
1262 psp.dwSize = sizeof(psp);
1263 psp.hInstance = GetModuleHandleA(NULL);
1264 U(psp).pszTemplate = "prop_page1";
1265 psp.pfnDlgProc = test_WM_CTLCOLORSTATIC_proc;
1266 hpsp[0] = pCreatePropertySheetPageA(&psp);
1268 memset(&psh, 0, sizeof(psh));
1269 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
1270 psh.dwFlags = PSH_MODELESS;
1271 psh.pszCaption = "caption";
1272 psh.nPages = 1;
1273 psh.hwndParent = GetDesktopWindow();
1274 U3(psh).phpage = hpsp;
1276 hdlg = (HWND)pPropertySheetA(&psh);
1277 ok(hdlg != INVALID_HANDLE_VALUE, "Got invalid handle value %p.\n", hdlg);
1278 flush_events();
1280 /* Test that page dialog procedure is unchanged */
1281 dlgproc = GetWindowLongPtrA(sheethwnd, DWLP_DLGPROC);
1282 ok(dlgproc == (ULONG_PTR)test_WM_CTLCOLORSTATIC_proc, "Unexpected dlgproc %#Ix.\n", dlgproc);
1284 /* Test that theme dialog texture is enabled for comctl32 v6, even when theming is off */
1285 ret = pIsThemeDialogTextureEnabled(sheethwnd);
1286 todo_wine_if(!is_v6)
1287 ok(ret == is_v6, "Wrong theme dialog texture status.\n");
1289 hwnd = CreateWindowA(WC_EDITA, "child", WS_POPUP | WS_VISIBLE, 1, 2, 50, 50, 0, 0, 0, NULL);
1290 ok(hwnd != NULL, "CreateWindowA failed, error %ld.\n", GetLastError());
1291 hdc = GetDC(hwnd);
1293 hbrush = (HBRUSH)SendMessageW(sheethwnd, WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd);
1294 if (is_v6 && is_theme_active)
1296 /* Test that dialog tab texture is enabled even without any child controls in the dialog */
1297 ok(hbrush != GetSysColorBrush(COLOR_BTNFACE), "Expected a different brush.\n");
1300 ReleaseDC(hwnd, hdc);
1301 DestroyWindow(hwnd);
1302 DestroyWindow(hdlg);
1305 static void test_invalid_hpropsheetpage(void)
1307 BYTE buf_pspW[sizeof(ULONG_PTR) + sizeof(PROPSHEETPAGEW)];
1308 BYTE buf_psp[sizeof(ULONG_PTR) + sizeof(PROPSHEETPAGEA)];
1309 HPROPSHEETPAGE hpsp[1];
1310 PROPSHEETHEADERW pshW;
1311 PROPSHEETHEADERA psh;
1312 PROPSHEETPAGEW *pspW;
1313 PROPSHEETPAGEA *psp;
1314 LRESULT ret;
1315 HWND hdlg;
1317 /* LocalSize throws exception on misaligned pointers (x86_64). */
1318 psp = (PROPSHEETPAGEA *)((ULONG_PTR)buf_psp & 0xf ? buf_psp : buf_psp + sizeof(ULONG_PTR));
1319 pspW = (PROPSHEETPAGEW *)((ULONG_PTR)buf_pspW & 0xf ? buf_pspW : buf_pspW + sizeof(ULONG_PTR));
1321 memset(psp, 0, sizeof(*psp));
1322 psp->dwSize = sizeof(*psp);
1323 psp->hInstance = GetModuleHandleA(NULL);
1324 U(psp)->pszTemplate = "prop_page1";
1325 U2(psp)->pszIcon = NULL;
1326 psp->pfnDlgProc = page_dlg_proc;
1327 psp->lParam = 0;
1329 /* Pass PROPSHEETPAGEA* instead of HPROPSHEETPAGE */
1330 hpsp[0] = (HPROPSHEETPAGE)psp;
1332 memset(&psh, 0, sizeof(psh));
1333 psh.dwSize = sizeof(psh);
1334 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
1335 psh.pszCaption = "test caption";
1336 psh.nPages = 1;
1337 psh.hwndParent = GetDesktopWindow();
1338 U3(psh).phpage = hpsp;
1339 psh.pfnCallback = sheet_callback;
1341 hdlg = (HWND)pPropertySheetA(&psh);
1342 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
1344 ret = SendMessageA(hdlg, PSM_INDEXTOPAGE, 0, 0);
1345 ok(ret, "page was not created\n");
1346 ok((HPROPSHEETPAGE)ret != hpsp[0], "invalid HPROPSHEETPAGE was preserved\n");
1347 DestroyWindow(hdlg);
1349 memset(pspW, 0, sizeof(*pspW));
1350 pspW->dwSize = sizeof(*pspW);
1351 pspW->hInstance = GetModuleHandleA(NULL);
1352 U(pspW)->pszTemplate = L"prop_page1";
1353 U2(pspW)->pszIcon = NULL;
1354 pspW->pfnDlgProc = page_dlg_proc;
1355 pspW->lParam = 0;
1357 /* Pass PROPSHEETPAGEW* instead of HPROPSHEETPAGE */
1358 hpsp[0] = (HPROPSHEETPAGE)pspW;
1360 hdlg = (HWND)pPropertySheetA(&psh);
1361 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
1363 ok(!SendMessageA(hdlg, PSM_INDEXTOPAGE, 0, 0), "there should be no pages\n");
1364 /* Pass PROPSHEETPAGE[AW]* instead of HPROPSHEETPAGE */
1365 ok(!SendMessageW(hdlg, PSM_ADDPAGE, 0, (LPARAM)pspW), "PSM_ADDPAGE succeeded\n");
1366 ok(SendMessageW(hdlg, PSM_ADDPAGE, 0, (LPARAM)psp), "PSM_ADDPAGE failed\n");
1367 ok(SendMessageA(hdlg, PSM_INDEXTOPAGE, 0, 0), "no pages after PSM_ADDPAGE\n");
1368 DestroyWindow(hdlg);
1370 /* Pass PROPSHEETPAGEW* instead of HPROPSHEETPAGE */
1371 hpsp[0] = (HPROPSHEETPAGE)pspW;
1373 memset(&pshW, 0, sizeof(pshW));
1374 pshW.dwSize = sizeof(pshW);
1375 pshW.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
1376 pshW.pszCaption = L"test caption";
1377 pshW.nPages = 1;
1378 pshW.hwndParent = GetDesktopWindow();
1379 U3(pshW).phpage = hpsp;
1380 pshW.pfnCallback = sheet_callback;
1382 hdlg = (HWND)pPropertySheetW(&pshW);
1383 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
1385 ret = SendMessageA(hdlg, PSM_INDEXTOPAGE, 0, 0);
1386 ok(ret, "page was not created\n");
1387 ok((HPROPSHEETPAGE)ret != hpsp[0], "invalid HPROPSHEETPAGE was preserved\n");
1388 DestroyWindow(hdlg);
1391 static void init_comctl32_functions(void)
1393 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
1395 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
1396 X(CreatePropertySheetPageA);
1397 X(CreatePropertySheetPageW);
1398 X(DestroyPropertySheetPage);
1399 X(PropertySheetA);
1400 X(PropertySheetW);
1401 #undef X
1404 static void init_uxtheme_functions(void)
1406 HMODULE uxtheme = LoadLibraryA("uxtheme.dll");
1408 #define X(f) p##f = (void *)GetProcAddress(uxtheme, #f);
1409 X(IsThemeActive)
1410 X(IsThemeDialogTextureEnabled)
1411 #undef X
1414 START_TEST(propsheet)
1416 ULONG_PTR ctx_cookie;
1417 HANDLE ctx;
1419 detect_locale();
1420 if (rtl)
1422 /* use locale-specific RTL resources when on an RTL locale */
1423 /* without this, propsheets on RTL locales use English LTR resources */
1424 trace("RTL locale detected\n");
1425 SetProcessDefaultLayout(LAYOUT_RTL);
1428 init_comctl32_functions();
1429 init_uxtheme_functions();
1430 is_theme_active = pIsThemeActive();
1432 test_bad_control_class();
1433 test_title();
1434 test_nopage();
1435 test_disableowner();
1436 test_wiznavigation();
1437 test_buttons();
1438 test_custom_default_button();
1439 test_messages();
1440 test_PSM_ADDPAGE();
1441 test_PSM_INSERTPAGE();
1442 test_CreatePropertySheetPage();
1443 test_page_dialog_texture();
1444 test_invalid_hpropsheetpage();
1446 if (!load_v6_module(&ctx_cookie, &ctx))
1447 return;
1449 init_comctl32_functions();
1450 is_v6 = TRUE;
1452 test_page_dialog_texture();
1454 unload_v6_module(ctx_cookie, ctx);