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
25 #include "resources.h"
27 #include "wine/test.h"
31 static HWND parenthwnd
;
32 static HWND sheethwnd
;
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)
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)
62 int min_timeout
= 100;
63 DWORD time
= GetTickCount() + diff
;
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
)
80 HMODULE module
= GetModuleHandleA("comctl32.dll");
81 DWORD size
, buffer_size
;
84 hrsrc
= FindResourceA(module
, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */),
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",
97 case PSCB_INITIALIZED
:
100 GetWindowTextA(hwnd
, caption
, sizeof(caption
));
101 ok(!strcmp(caption
,"test caption"), "caption: %s\n", caption
);
109 static INT_PTR CALLBACK
page_dlg_proc(HWND hwnd
, UINT msg
, WPARAM wparam
,
116 PROPSHEETPAGEA
*psp
= (PROPSHEETPAGEA
*)lparam
;
117 HWND sheet
= GetParent(hwnd
);
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
));
133 NMHDR
*nmhdr
= (NMHDR
*)lparam
;
143 ok(!SendMessageA(sheethwnd
, PSM_INDEXTOHWND
, 400, 0),"Should always be 0\n");
151 static void test_title(void)
153 HPROPSHEETPAGE hpsp
[1];
155 PROPSHEETHEADERA psh
;
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
;
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";
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
);
191 static void test_nopage(void)
193 HPROPSHEETPAGE hpsp
[1];
195 PROPSHEETHEADERA psh
;
199 memset(&psp
, 0, sizeof(psp
));
200 psp
.dwSize
= sizeof(psp
);
202 psp
.hInstance
= GetModuleHandleA(NULL
);
203 U(psp
).pszTemplate
= "prop_page1";
204 U2(psp
).pszIcon
= NULL
;
205 psp
.pfnDlgProc
= page_dlg_proc
;
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";
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
);
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");
238 static int CALLBACK
disableowner_callback(HWND hwnd
, UINT msg
, LPARAM lparam
)
242 case PSCB_INITIALIZED
:
244 ok(IsWindowEnabled(parenthwnd
) == 0, "parent window should be disabled\n");
252 static void register_parent_wnd_class(void)
257 cls
.lpfnWndProc
= DefWindowProcA
;
260 cls
.hInstance
= GetModuleHandleA(NULL
);
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];
273 PROPSHEETHEADERA psh
;
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
);
282 psp
.hInstance
= GetModuleHandleA(NULL
);
283 U(psp
).pszTemplate
= "prop_page1";
284 U2(psp
).pszIcon
= NULL
;
285 psp
.pfnDlgProc
= NULL
;
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";
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
)
310 LPNMHDR hdr
= (LPNMHDR
)lparam
;
313 active_page
= /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
314 (int)SendMessageA(hdr
->hwndFrom
, PSM_HWNDTOINDEX
, (WPARAM
)hwnd
, 0);
317 /* prevent navigation away from the fourth page */
318 if(active_page
== 3){
319 SetWindowLongPtrA(hwnd
, DWLP_MSGRESULT
, TRUE
);
329 static WNDPROC old_nav_dialog_proc
;
331 static LRESULT CALLBACK
new_nav_dialog_proc( HWND hwnd
, UINT msg
, WPARAM wp
, LPARAM lp
)
336 ok( IsWindowEnabled( GetDlgItem(hwnd
, wp
) ), "button is not enabled\n" );
339 return CallWindowProcW( old_nav_dialog_proc
, hwnd
, msg
, wp
, lp
);
342 static LRESULT CALLBACK
hook_proc( int code
, WPARAM wp
, LPARAM lp
)
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
);
357 return CallNextHookEx( NULL
, code
, wp
, lp
);
360 static void test_wiznavigation(void)
362 HPROPSHEETPAGE hpsp
[4];
363 PROPSHEETPAGEA psp
[4];
364 PROPSHEETHEADERA psh
;
369 BOOL hwndtoindex_supported
= TRUE
;
370 const INT nextID
= 12324;
371 const INT backID
= 12323;
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";
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
);
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
);
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
));
485 UnhookWindowsHookEx( hook
);
488 static void test_buttons(void)
490 HPROPSHEETPAGE hpsp
[1];
492 PROPSHEETHEADERA psh
;
498 memset(&psp
, 0, sizeof(psp
));
499 psp
.dwSize
= sizeof(psp
);
501 psp
.hInstance
= GetModuleHandleA(NULL
);
502 U(psp
).pszTemplate
= "prop_page1";
503 U2(psp
).pszIcon
= NULL
;
504 psp
.pfnDlgProc
= page_dlg_proc
;
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";
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");
522 button
= GetDlgItem(hdlg
, IDOK
);
523 GetWindowRect(button
, &rc
);
524 prevRight
= rc
.right
;
528 button
= GetDlgItem(hdlg
, IDCANCEL
);
529 GetWindowRect(button
, &rc
);
530 ok(rc
.top
== top
, "Cancel button should have same top as OK button\n");
532 ok(rc
.left
< prevRight
, "Cancel button should be to the left of OK button\n");
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");
541 ok(rc
.left
< prevRight
, "Apply button should be to the left of Cancel button\n");
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");
550 ok(rc
.left
< prevRight
, "Help button should be to the left of Apply button\n");
552 ok(rc
.left
> prevRight
, "Help button should be to the right of Apply button\n");
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
)
565 switch(LOWORD(wparam
))
567 case IDC_PS_PUSHBUTTON1
:
568 switch(HIWORD(wparam
))
571 add_button_has_been_pressed
= TRUE
;
581 static void test_custom_default_button(void)
584 PROPSHEETPAGEA psp
[1];
585 PROPSHEETHEADERA psh
;
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";
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";
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");
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 },*/
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
) &&
769 msg
.message
= message
;
770 msg
.flags
= sent
|wparam
|lparam
|id
;
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
);
791 case PSCB_INITIALIZED
:
792 oldWndProc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_WNDPROC
);
793 SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)&sheet_callback_messages_proc
);
800 static INT_PTR CALLBACK
page_dlg_proc_messages(HWND hwnd
, UINT msg
, WPARAM wParam
,
803 save_message(hwnd
, msg
, wParam
, lParam
, RECEIVER_PAGE
);
808 static void test_messages(void)
810 HPROPSHEETPAGE hpsp
[1];
812 PROPSHEETHEADERA psh
;
815 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
817 memset(&psp
, 0, sizeof(psp
));
818 psp
.dwSize
= sizeof(psp
);
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
;
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";
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
);
848 static void test_PSM_ADDPAGE(void)
850 HPROPSHEETPAGE hpsp
[5];
852 PROPSHEETHEADERA psh
;
857 memset(&psp
, 0, sizeof(psp
));
858 psp
.dwSize
= sizeof(psp
);
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
;
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";
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
);
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]);
938 static void test_PSM_INSERTPAGE(void)
940 HPROPSHEETPAGE hpsp
[5];
942 PROPSHEETHEADERA psh
;
947 memset(&psp
, 0, sizeof(psp
));
948 psp
.dwSize
= sizeof(psp
);
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
;
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";
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
);
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
1036 PROPSHEETPAGEA pageA
;
1037 PROPSHEETPAGEW pageW
;
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",
1053 if (psp
->dwFlags
& PSP_USETITLE
)
1054 ok(psp_orig
->pszTitle
!= psp
->pszTitle
, "Expected different page title pointer\n");
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
);
1068 ok(psp
->dwSize
> PROPSHEETPAGEA_V1_SIZE
, "Expected ADDREF for V2+ only, got size %lu\n", psp
->dwSize
);
1069 cpage
->addref_called
++;
1072 ok(psp
->dwSize
>= PROPSHEETPAGEA_V1_SIZE
, "Unexpected RELEASE, got size %lu\n", psp
->dwSize
);
1073 cpage
->release_called
++;
1076 ok(0, "Unexpected message %u\n", msg
);
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",
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
);
1102 ok(psp
->dwSize
> PROPSHEETPAGEW_V1_SIZE
, "Expected ADDREF for V2+ only, got size %lu\n", psp
->dwSize
);
1103 cpage
->addref_called
++;
1106 ok(psp
->dwSize
>= PROPSHEETPAGEW_V1_SIZE
, "Unexpected RELEASE, got size %lu\n", psp
->dwSize
);
1107 cpage
->release_called
++;
1110 ok(0, "Unexpected message %u\n", msg
);
1116 static void test_CreatePropertySheetPage(void)
1118 struct custom_proppage page
;
1119 HPROPSHEETPAGE hpsp
;
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
);
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");
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
);
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");
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)
1202 PROPSHEETHEADERA psh
;
1203 HPROPSHEETPAGE hpsp
;
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
;
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
)
1250 static void test_page_dialog_texture(void)
1252 HPROPSHEETPAGE hpsp
[1];
1253 PROPSHEETHEADERA psh
;
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";
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
);
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());
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
;
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
;
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";
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
;
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";
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
);
1404 static void init_uxtheme_functions(void)
1406 HMODULE uxtheme
= LoadLibraryA("uxtheme.dll");
1408 #define X(f) p##f = (void *)GetProcAddress(uxtheme, #f);
1410 X(IsThemeDialogTextureEnabled
)
1414 START_TEST(propsheet
)
1416 ULONG_PTR ctx_cookie
;
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();
1435 test_disableowner();
1436 test_wiznavigation();
1438 test_custom_default_button();
1441 test_PSM_INSERTPAGE();
1442 test_CreatePropertySheetPage();
1443 test_page_dialog_texture();
1444 test_invalid_hpropsheetpage();
1446 if (!load_v6_module(&ctx_cookie
, &ctx
))
1449 init_comctl32_functions();
1452 test_page_dialog_texture();
1454 unload_v6_module(ctx_cookie
, ctx
);