shell32/tests: Use SetRect instead of open coding it.
[wine.git] / dlls / comctl32 / tests / propsheet.c
blob659429880165eb38a3042faa58222f8e9cbb8e8b
1 /* Unit test suite for property sheet control.
3 * Copyright 2006 Huw Davies
4 * Copyright 2009 Jan de Mooij
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <windows.h>
22 #include <commctrl.h>
23 #include "msg.h"
25 #include "resources.h"
27 #include "wine/test.h"
29 static HWND parenthwnd;
30 static HWND sheethwnd;
32 static LONG active_page = -1;
34 #define IDC_APPLY_BUTTON 12321
37 /* try to make sure pending X events have been processed before continuing */
38 static void flush_events(void)
40 MSG msg;
41 int diff = 200;
42 int min_timeout = 100;
43 DWORD time = GetTickCount() + diff;
45 while (diff > 0)
47 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
48 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
49 diff = time - GetTickCount();
54 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
56 switch(msg)
58 case PSCB_INITIALIZED:
60 char caption[256];
61 GetWindowTextA(hwnd, caption, sizeof(caption));
62 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
63 sheethwnd = hwnd;
64 return 0;
67 return 0;
70 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
71 LPARAM lparam)
73 switch(msg)
75 case WM_INITDIALOG:
77 HWND sheet = GetParent(hwnd);
78 char caption[256];
79 GetWindowTextA(sheet, caption, sizeof(caption));
80 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
81 return TRUE;
84 case WM_NOTIFY:
86 NMHDR *nmhdr = (NMHDR *)lparam;
87 switch(nmhdr->code)
89 case PSN_APPLY:
90 return TRUE;
91 default:
92 return FALSE;
95 case WM_NCDESTROY:
96 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
97 return TRUE;
99 default:
100 return FALSE;
104 static void test_title(void)
106 HPROPSHEETPAGE hpsp[1];
107 PROPSHEETPAGEA psp;
108 PROPSHEETHEADERA psh;
109 HWND hdlg;
110 DWORD style;
112 memset(&psp, 0, sizeof(psp));
113 psp.dwSize = sizeof(psp);
114 psp.dwFlags = 0;
115 psp.hInstance = GetModuleHandleA(NULL);
116 U(psp).pszTemplate = "prop_page1";
117 U2(psp).pszIcon = NULL;
118 psp.pfnDlgProc = page_dlg_proc;
119 psp.lParam = 0;
121 hpsp[0] = CreatePropertySheetPageA(&psp);
123 memset(&psh, 0, sizeof(psh));
124 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
125 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
126 psh.pszCaption = "test caption";
127 psh.nPages = 1;
128 psh.hwndParent = GetDesktopWindow();
129 U3(psh).phpage = hpsp;
130 psh.pfnCallback = sheet_callback;
132 hdlg = (HWND)PropertySheetA(&psh);
133 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
135 style = GetWindowLongA(hdlg, GWL_STYLE);
136 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|
137 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
138 "got unexpected style: %x\n", style);
140 DestroyWindow(hdlg);
143 static void test_nopage(void)
145 HPROPSHEETPAGE hpsp[1];
146 PROPSHEETPAGEA psp;
147 PROPSHEETHEADERA psh;
148 HWND hdlg, hpage;
149 MSG msg;
151 memset(&psp, 0, sizeof(psp));
152 psp.dwSize = sizeof(psp);
153 psp.dwFlags = 0;
154 psp.hInstance = GetModuleHandleA(NULL);
155 U(psp).pszTemplate = "prop_page1";
156 U2(psp).pszIcon = NULL;
157 psp.pfnDlgProc = page_dlg_proc;
158 psp.lParam = 0;
160 hpsp[0] = CreatePropertySheetPageA(&psp);
162 memset(&psh, 0, sizeof(psh));
163 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
164 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
165 psh.pszCaption = "test caption";
166 psh.nPages = 1;
167 psh.hwndParent = GetDesktopWindow();
168 U3(psh).phpage = hpsp;
169 psh.pfnCallback = sheet_callback;
171 hdlg = (HWND)PropertySheetA(&psh);
172 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
174 ShowWindow(hdlg,SW_NORMAL);
175 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0);
176 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */
177 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
178 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */
179 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0);
180 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, active_page);
181 flush_events();
182 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
184 /* Check that the property sheet was fully redrawn */
185 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
186 "expected no pending WM_PAINT messages\n");
187 DestroyWindow(hdlg);
190 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
192 switch(msg)
194 case PSCB_INITIALIZED:
196 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
197 PostQuitMessage(0);
198 return FALSE;
201 return FALSE;
204 static void register_parent_wnd_class(void)
206 WNDCLASSA cls;
208 cls.style = 0;
209 cls.lpfnWndProc = DefWindowProcA;
210 cls.cbClsExtra = 0;
211 cls.cbWndExtra = 0;
212 cls.hInstance = GetModuleHandleA(NULL);
213 cls.hIcon = 0;
214 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
215 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
216 cls.lpszMenuName = NULL;
217 cls.lpszClassName = "parent class";
218 RegisterClassA(&cls);
221 static void test_disableowner(void)
223 HPROPSHEETPAGE hpsp[1];
224 PROPSHEETPAGEA psp;
225 PROPSHEETHEADERA psh;
226 INT_PTR p;
228 register_parent_wnd_class();
229 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
231 memset(&psp, 0, sizeof(psp));
232 psp.dwSize = sizeof(psp);
233 psp.dwFlags = 0;
234 psp.hInstance = GetModuleHandleA(NULL);
235 U(psp).pszTemplate = "prop_page1";
236 U2(psp).pszIcon = NULL;
237 psp.pfnDlgProc = NULL;
238 psp.lParam = 0;
240 hpsp[0] = CreatePropertySheetPageA(&psp);
242 memset(&psh, 0, sizeof(psh));
243 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
244 psh.dwFlags = PSH_USECALLBACK;
245 psh.pszCaption = "test caption";
246 psh.nPages = 1;
247 psh.hwndParent = parenthwnd;
248 U3(psh).phpage = hpsp;
249 psh.pfnCallback = disableowner_callback;
251 p = PropertySheetA(&psh);
252 todo_wine
253 ok(p == 0, "Expected 0, got %ld\n", p);
254 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
255 DestroyWindow(parenthwnd);
258 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
260 switch(msg){
261 case WM_NOTIFY:
263 LPNMHDR hdr = (LPNMHDR)lparam;
264 switch(hdr->code){
265 case PSN_SETACTIVE:
266 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */
267 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0);
268 return TRUE;
269 case PSN_KILLACTIVE:
270 /* prevent navigation away from the fourth page */
271 if(active_page == 3){
272 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE);
273 return TRUE;
276 break;
279 return FALSE;
282 static WNDPROC old_nav_dialog_proc;
284 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
286 switch (msg)
288 case DM_SETDEFID:
289 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" );
290 break;
292 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp );
295 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp )
297 static BOOL done;
298 if (code == HCBT_CREATEWND)
300 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp;
302 /* The first dialog created will be the parent dialog */
303 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG)
305 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc );
306 done = TRUE;
310 return CallNextHookEx( NULL, code, wp, lp );
313 static void test_wiznavigation(void)
315 HPROPSHEETPAGE hpsp[4];
316 PROPSHEETPAGEA psp[4];
317 PROPSHEETHEADERA psh;
318 HWND hdlg, control;
319 LONG_PTR controlID;
320 DWORD style;
321 LRESULT defidres;
322 BOOL hwndtoindex_supported = TRUE;
323 const INT nextID = 12324;
324 const INT backID = 12323;
325 HHOOK hook;
327 /* set up a hook proc in order to subclass the main dialog early on */
328 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() );
330 /* create the property sheet pages */
331 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
333 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
334 psp[0].hInstance = GetModuleHandleA(NULL);
335 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
336 psp[0].pfnDlgProc = nav_page_proc;
337 hpsp[0] = CreatePropertySheetPageA(&psp[0]);
339 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
340 psp[1].hInstance = GetModuleHandleA(NULL);
341 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
342 psp[1].pfnDlgProc = nav_page_proc;
343 hpsp[1] = CreatePropertySheetPageA(&psp[1]);
345 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
346 psp[2].hInstance = GetModuleHandleA(NULL);
347 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
348 psp[2].pfnDlgProc = nav_page_proc;
349 hpsp[2] = CreatePropertySheetPageA(&psp[2]);
351 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
352 psp[3].hInstance = GetModuleHandleA(NULL);
353 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
354 psp[3].pfnDlgProc = nav_page_proc;
355 hpsp[3] = CreatePropertySheetPageA(&psp[3]);
357 /* set up the property sheet dialog */
358 memset(&psh, 0, sizeof(psh));
359 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
360 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
361 psh.pszCaption = "A Wizard";
362 psh.nPages = 4;
363 psh.hwndParent = GetDesktopWindow();
364 U3(psh).phpage = hpsp;
365 hdlg = (HWND)PropertySheetA(&psh);
366 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
368 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
370 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
371 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
372 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
373 "got unexpected style: %x\n", style);
375 control = GetFocus();
376 controlID = GetWindowLongPtrA(control, GWLP_ID);
377 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
379 /* simulate pressing the Next button */
380 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
381 if (!active_page) hwndtoindex_supported = FALSE;
382 if (hwndtoindex_supported)
383 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
385 control = GetFocus();
386 controlID = GetWindowLongPtrA(control, GWLP_ID);
387 ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID);
389 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
390 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
392 /* set the focus to the second edit box on this page */
393 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
395 /* press next again */
396 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
397 if (hwndtoindex_supported)
398 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
400 control = GetFocus();
401 controlID = GetWindowLongPtrA(control, GWLP_ID);
402 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
404 /* back button */
405 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
406 if (hwndtoindex_supported)
407 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
409 control = GetFocus();
410 controlID = GetWindowLongPtrA(control, GWLP_ID);
411 ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID);
413 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
414 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
416 /* press next twice */
417 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
418 if (hwndtoindex_supported)
419 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
420 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
421 if (hwndtoindex_supported)
422 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
423 else
424 active_page = 3;
426 control = GetFocus();
427 controlID = GetWindowLongPtrA(control, GWLP_ID);
428 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
430 /* try to navigate away, but shouldn't be able to */
431 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
432 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
434 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
435 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
437 DestroyWindow(hdlg);
438 UnhookWindowsHookEx( hook );
441 static void test_buttons(void)
443 HPROPSHEETPAGE hpsp[1];
444 PROPSHEETPAGEA psp;
445 PROPSHEETHEADERA psh;
446 HWND hdlg;
447 HWND button;
448 RECT rc;
449 int prevRight, top;
451 memset(&psp, 0, sizeof(psp));
452 psp.dwSize = sizeof(psp);
453 psp.dwFlags = 0;
454 psp.hInstance = GetModuleHandleA(NULL);
455 U(psp).pszTemplate = "prop_page1";
456 U2(psp).pszIcon = NULL;
457 psp.pfnDlgProc = page_dlg_proc;
458 psp.lParam = 0;
460 hpsp[0] = CreatePropertySheetPageA(&psp);
462 memset(&psh, 0, sizeof(psh));
463 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
464 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
465 psh.pszCaption = "test caption";
466 psh.nPages = 1;
467 psh.hwndParent = GetDesktopWindow();
468 U3(psh).phpage = hpsp;
469 psh.pfnCallback = sheet_callback;
471 hdlg = (HWND)PropertySheetA(&psh);
472 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
474 /* OK button */
475 button = GetDlgItem(hdlg, IDOK);
476 GetWindowRect(button, &rc);
477 prevRight = rc.right;
478 top = rc.top;
480 /* Cancel button */
481 button = GetDlgItem(hdlg, IDCANCEL);
482 GetWindowRect(button, &rc);
483 ok(rc.top == top, "Cancel button should have same top as OK button\n");
484 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
485 prevRight = rc.right;
487 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
488 GetWindowRect(button, &rc);
489 ok(rc.top == top, "Apply button should have same top as OK button\n");
490 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
491 prevRight = rc.right;
493 button = GetDlgItem(hdlg, IDHELP);
494 GetWindowRect(button, &rc);
495 ok(rc.top == top, "Help button should have same top as OK button\n");
496 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
498 DestroyWindow(hdlg);
501 static BOOL add_button_has_been_pressed;
503 static INT_PTR CALLBACK
504 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
506 switch (msg)
508 case WM_COMMAND:
509 switch(LOWORD(wparam))
511 case IDC_PS_PUSHBUTTON1:
512 switch(HIWORD(wparam))
514 case BN_CLICKED:
515 add_button_has_been_pressed = TRUE;
516 return TRUE;
518 break;
520 break;
522 return FALSE;
525 static void test_custom_default_button(void)
527 HWND hdlg, page;
528 PROPSHEETPAGEA psp[1];
529 PROPSHEETHEADERA psh;
530 MSG msg;
531 LRESULT result;
533 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
534 psp[0].dwFlags = PSP_USETITLE;
535 psp[0].hInstance = GetModuleHandleA(NULL);
536 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
537 U2(psp[0]).pszIcon = NULL;
538 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
539 psp[0].pszTitle = "Page1";
540 psp[0].lParam = 0;
542 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
543 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
544 psh.hwndParent = GetDesktopWindow();
545 psh.hInstance = GetModuleHandleA(NULL);
546 U(psh).pszIcon = NULL;
547 psh.pszCaption = "PropertySheet1";
548 psh.nPages = 1;
549 U3(psh).ppsp = psp;
550 U2(psh).nStartPage = 0;
552 /* The goal of the test is to make sure that the Add button is pressed
553 * when the ENTER key is pressed and a different control, a combobox,
554 * has the keyboard focus. */
555 add_button_has_been_pressed = FALSE;
557 /* Create the modeless property sheet. */
558 hdlg = (HWND)PropertySheetA(&psh);
559 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
561 /* Set the Add button as the default button. */
562 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
564 /* Make sure the default button is the Add button. */
565 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0);
566 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
567 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
569 /* At this point, the combobox should have keyboard focus, so we press ENTER.
570 * Pull the lever, Kronk! */
571 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0);
572 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0);
574 /* Process all the messages in the queue for this thread. */
575 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
577 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */
578 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg)))
580 TranslateMessage(&msg);
581 DispatchMessageA(&msg);
585 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
587 DestroyWindow(hdlg);
590 #define RECEIVER_SHEET_CALLBACK 0
591 #define RECEIVER_SHEET_WINPROC 1
592 #define RECEIVER_PAGE 2
594 #define NUM_MSG_SEQUENCES 1
595 #define PROPSHEET_SEQ_INDEX 0
597 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
598 static WNDPROC oldWndProc;
600 static const struct message property_sheet_seq[] = {
601 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
602 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
603 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
604 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
605 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
606 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
607 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
608 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
609 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
610 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
611 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
612 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
613 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
614 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
615 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
616 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
617 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
618 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
619 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
620 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
621 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
622 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
623 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
624 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
625 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
626 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
627 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
628 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
629 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
630 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
631 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
632 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
633 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
634 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
635 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
636 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
637 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
638 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
639 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
640 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
641 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
642 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
643 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
644 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
645 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
646 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
647 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
648 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
649 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
650 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
651 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
652 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
653 /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
654 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
655 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
656 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
657 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
658 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
659 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
660 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
661 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
662 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
663 { WM_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
664 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
665 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
666 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
667 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
668 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
669 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
670 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
671 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
672 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
673 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
674 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
675 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
676 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
677 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
678 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
679 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
680 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
681 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
682 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
683 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
684 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
685 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
686 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
687 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
688 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
689 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
690 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
691 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
692 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
693 { 0 }
696 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
698 struct message msg;
700 if (message < WM_USER &&
701 message != WM_GETICON &&
702 message != WM_GETTEXT &&
703 message != WM_IME_SETCONTEXT &&
704 message != WM_IME_NOTIFY &&
705 message != WM_PAINT &&
706 message != WM_ERASEBKGND &&
707 message != WM_SETCURSOR &&
708 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
709 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
710 message != 0x90)
712 msg.message = message;
713 msg.flags = sent|wparam|lparam|id;
714 msg.wParam = wParam;
715 msg.lParam = lParam;
716 msg.id = receiver;
717 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
721 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
723 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
725 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam);
728 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
730 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
732 switch (msg)
734 case PSCB_INITIALIZED:
735 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
736 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
737 return TRUE;
740 return TRUE;
743 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
744 LPARAM lParam)
746 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
748 return FALSE;
751 static void test_messages(void)
753 HPROPSHEETPAGE hpsp[1];
754 PROPSHEETPAGEA psp;
755 PROPSHEETHEADERA psh;
756 HWND hdlg;
758 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
760 memset(&psp, 0, sizeof(psp));
761 psp.dwSize = sizeof(psp);
762 psp.dwFlags = 0;
763 psp.hInstance = GetModuleHandleA(NULL);
764 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
765 U2(psp).pszIcon = NULL;
766 psp.pfnDlgProc = page_dlg_proc_messages;
767 psp.lParam = 0;
769 hpsp[0] = CreatePropertySheetPageA(&psp);
771 memset(&psh, 0, sizeof(psh));
772 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
773 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
774 | PSH_MODELESS | PSH_USEICONID;
775 psh.pszCaption = "test caption";
776 psh.nPages = 1;
777 psh.hwndParent = GetDesktopWindow();
778 U3(psh).phpage = hpsp;
779 psh.pfnCallback = sheet_callback_messages;
781 hdlg = (HWND)PropertySheetA(&psh);
782 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
784 ShowWindow(hdlg,SW_NORMAL);
786 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
788 DestroyWindow(hdlg);
791 static void test_PSM_ADDPAGE(void)
793 HPROPSHEETPAGE hpsp[5];
794 PROPSHEETPAGEA psp;
795 PROPSHEETHEADERA psh;
796 HWND hdlg, tab;
797 BOOL ret;
798 DWORD r;
800 memset(&psp, 0, sizeof(psp));
801 psp.dwSize = sizeof(psp);
802 psp.dwFlags = 0;
803 psp.hInstance = GetModuleHandleA(NULL);
804 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
805 U2(psp).pszIcon = NULL;
806 psp.pfnDlgProc = page_dlg_proc_messages;
807 psp.lParam = 0;
809 /* two page with the same data */
810 hpsp[0] = CreatePropertySheetPageA(&psp);
811 hpsp[1] = CreatePropertySheetPageA(&psp);
812 hpsp[2] = CreatePropertySheetPageA(&psp);
814 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
815 hpsp[3] = CreatePropertySheetPageA(&psp);
817 psp.dwFlags = PSP_PREMATURE;
818 hpsp[4] = CreatePropertySheetPageA(&psp);
820 memset(&psh, 0, sizeof(psh));
821 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
822 psh.dwFlags = PSH_MODELESS;
823 psh.pszCaption = "test caption";
824 psh.nPages = 1;
825 psh.hwndParent = GetDesktopWindow();
826 U3(psh).phpage = hpsp;
828 hdlg = (HWND)PropertySheetA(&psh);
829 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
831 /* add pages one by one */
832 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
833 ok(ret == TRUE, "got %d\n", ret);
835 /* try with null and invalid value */
836 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
837 ok(ret == FALSE, "got %d\n", ret);
839 if (0)
841 /* crashes on native */
842 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
844 /* check item count */
845 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
847 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
848 ok(r == 2, "got %d\n", r);
850 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
851 ok(ret == TRUE, "got %d\n", ret);
853 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
854 ok(r == 3, "got %d\n", r);
856 /* add property sheet page that can't be created */
857 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
858 ok(ret == TRUE, "got %d\n", ret);
860 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
861 ok(r == 4, "got %d\n", r);
863 /* select page that can't be created */
864 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1);
865 ok(ret == TRUE, "got %d\n", ret);
867 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
868 ok(r == 3, "got %d\n", r);
870 /* test PSP_PREMATURE flag with incorrect property sheet page */
871 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
872 ok(ret == FALSE, "got %d\n", ret);
874 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
875 ok(r == 3, "got %d\n", r);
877 DestroyPropertySheetPage(hpsp[4]);
878 DestroyWindow(hdlg);
881 START_TEST(propsheet)
883 test_title();
884 test_nopage();
885 test_disableowner();
886 test_wiznavigation();
887 test_buttons();
888 test_custom_default_button();
889 test_messages();
890 test_PSM_ADDPAGE();