[COMCTL32_WINETEST]
[reactos.git] / rostests / winetests / comctl32 / propsheet.c
1 /* Unit test suite for property sheet control.
2 *
3 * Copyright 2006 Huw Davies
4 * Copyright 2009 Jan de Mooij
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <windows.h>
22 #include <commctrl.h>
23 #include "msg.h"
24
25 #include "resources.h"
26
27 #include "wine/test.h"
28
29 static HWND parenthwnd;
30 static HWND sheethwnd;
31
32 static LONG active_page = -1;
33
34 #define IDC_APPLY_BUTTON 12321
35
36
37 /* try to make sure pending X events have been processed before continuing */
38 static void flush_events(void)
39 {
40 MSG msg;
41 int diff = 200;
42 int min_timeout = 100;
43 DWORD time = GetTickCount() + diff;
44
45 while (diff > 0)
46 {
47 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break;
48 while (PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessage( &msg );
49 diff = time - GetTickCount();
50 }
51 }
52
53
54 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
55 {
56 switch(msg)
57 {
58 case PSCB_INITIALIZED:
59 {
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;
65 }
66 }
67 return 0;
68 }
69
70 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
71 LPARAM lparam)
72 {
73 switch(msg)
74 {
75 case WM_INITDIALOG:
76 {
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;
82 }
83
84 case WM_NOTIFY:
85 {
86 NMHDR *nmhdr = (NMHDR *)lparam;
87 switch(nmhdr->code)
88 {
89 case PSN_APPLY:
90 return TRUE;
91 default:
92 return FALSE;
93 }
94 }
95 case WM_NCDESTROY:
96 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
97 return TRUE;
98
99 default:
100 return FALSE;
101 }
102 }
103
104 static void test_title(void)
105 {
106 HPROPSHEETPAGE hpsp[1];
107 PROPSHEETPAGEA psp;
108 PROPSHEETHEADERA psh;
109 HWND hdlg;
110 DWORD style;
111
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;
120
121 hpsp[0] = CreatePropertySheetPageA(&psp);
122
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;
131
132 hdlg = (HWND)PropertySheetA(&psh);
133 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
134
135 style = GetWindowLong(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);
139
140 DestroyWindow(hdlg);
141 }
142
143 static void test_nopage(void)
144 {
145 HPROPSHEETPAGE hpsp[1];
146 PROPSHEETPAGEA psp;
147 PROPSHEETHEADERA psh;
148 HWND hdlg, hpage;
149 MSG msg;
150
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;
159
160 hpsp[0] = CreatePropertySheetPageA(&psp);
161
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;
170
171 hdlg = (HWND)PropertySheetA(&psh);
172 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
173
174 ShowWindow(hdlg,SW_NORMAL);
175 SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
176 hpage = PropSheet_GetCurrentPageHwnd(hdlg);
177 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, PropSheet_HwndToIndex(hdlg, hpage));
178 flush_events();
179 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
180
181 /* Check that the property sheet was fully redrawn */
182 ok(!PeekMessage(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE),
183 "expected no pending WM_PAINT messages\n");
184 DestroyWindow(hdlg);
185 }
186
187 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
188 {
189 switch(msg)
190 {
191 case PSCB_INITIALIZED:
192 {
193 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
194 PostQuitMessage(0);
195 return FALSE;
196 }
197 }
198 return FALSE;
199 }
200
201 static void register_parent_wnd_class(void)
202 {
203 WNDCLASSA cls;
204
205 cls.style = 0;
206 cls.lpfnWndProc = DefWindowProcA;
207 cls.cbClsExtra = 0;
208 cls.cbWndExtra = 0;
209 cls.hInstance = GetModuleHandleA(NULL);
210 cls.hIcon = 0;
211 cls.hCursor = LoadCursorA(0, IDC_ARROW);
212 cls.hbrBackground = GetStockObject(WHITE_BRUSH);
213 cls.lpszMenuName = NULL;
214 cls.lpszClassName = "parent class";
215 RegisterClassA(&cls);
216 }
217
218 static void test_disableowner(void)
219 {
220 HPROPSHEETPAGE hpsp[1];
221 PROPSHEETPAGEA psp;
222 PROPSHEETHEADERA psh;
223 INT_PTR p;
224
225 register_parent_wnd_class();
226 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
227
228 memset(&psp, 0, sizeof(psp));
229 psp.dwSize = sizeof(psp);
230 psp.dwFlags = 0;
231 psp.hInstance = GetModuleHandleA(NULL);
232 U(psp).pszTemplate = "prop_page1";
233 U2(psp).pszIcon = NULL;
234 psp.pfnDlgProc = NULL;
235 psp.lParam = 0;
236
237 hpsp[0] = CreatePropertySheetPageA(&psp);
238
239 memset(&psh, 0, sizeof(psh));
240 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
241 psh.dwFlags = PSH_USECALLBACK;
242 psh.pszCaption = "test caption";
243 psh.nPages = 1;
244 psh.hwndParent = parenthwnd;
245 U3(psh).phpage = hpsp;
246 psh.pfnCallback = disableowner_callback;
247
248 p = PropertySheetA(&psh);
249 todo_wine
250 ok(p == 0, "Expected 0, got %ld\n", p);
251 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
252 DestroyWindow(parenthwnd);
253 }
254
255 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
256 {
257 switch(msg){
258 case WM_NOTIFY:
259 {
260 LPNMHDR hdr = (LPNMHDR)lparam;
261 switch(hdr->code){
262 case PSN_SETACTIVE:
263 active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
264 return TRUE;
265 case PSN_KILLACTIVE:
266 /* prevent navigation away from the fourth page */
267 if(active_page == 3){
268 SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
269 return TRUE;
270 }
271 }
272 break;
273 }
274 }
275 return FALSE;
276 }
277
278 static void test_wiznavigation(void)
279 {
280 HPROPSHEETPAGE hpsp[4];
281 PROPSHEETPAGEA psp[4];
282 PROPSHEETHEADERA psh;
283 HWND hdlg, control;
284 LONG_PTR controlID;
285 DWORD style;
286 LRESULT defidres;
287 BOOL hwndtoindex_supported = TRUE;
288 const INT nextID = 12324;
289 const INT backID = 12323;
290
291 /* create the property sheet pages */
292 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
293
294 psp[0].dwSize = sizeof(PROPSHEETPAGEA);
295 psp[0].hInstance = GetModuleHandleA(NULL);
296 U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
297 psp[0].pfnDlgProc = nav_page_proc;
298 hpsp[0] = CreatePropertySheetPageA(&psp[0]);
299
300 psp[1].dwSize = sizeof(PROPSHEETPAGEA);
301 psp[1].hInstance = GetModuleHandleA(NULL);
302 U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
303 psp[1].pfnDlgProc = nav_page_proc;
304 hpsp[1] = CreatePropertySheetPageA(&psp[1]);
305
306 psp[2].dwSize = sizeof(PROPSHEETPAGEA);
307 psp[2].hInstance = GetModuleHandleA(NULL);
308 U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
309 psp[2].pfnDlgProc = nav_page_proc;
310 hpsp[2] = CreatePropertySheetPageA(&psp[2]);
311
312 psp[3].dwSize = sizeof(PROPSHEETPAGEA);
313 psp[3].hInstance = GetModuleHandleA(NULL);
314 U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
315 psp[3].pfnDlgProc = nav_page_proc;
316 hpsp[3] = CreatePropertySheetPageA(&psp[3]);
317
318 /* set up the property sheet dialog */
319 memset(&psh, 0, sizeof(psh));
320 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
321 psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
322 psh.pszCaption = "A Wizard";
323 psh.nPages = 4;
324 psh.hwndParent = GetDesktopWindow();
325 U3(psh).phpage = hpsp;
326 hdlg = (HWND)PropertySheetA(&psh);
327 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
328
329 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
330
331 style = GetWindowLong(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU);
332 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|
333 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK),
334 "got unexpected style: %x\n", style);
335
336 control = GetFocus();
337 controlID = GetWindowLongPtr(control, GWLP_ID);
338 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
339
340 /* simulate pressing the Next button */
341 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
342 if (!active_page) hwndtoindex_supported = FALSE;
343 if (hwndtoindex_supported)
344 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
345
346 control = GetFocus();
347 controlID = GetWindowLongPtr(control, GWLP_ID);
348 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);
349
350 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
351 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
352
353 /* set the focus to the second edit box on this page */
354 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
355
356 /* press next again */
357 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
358 if (hwndtoindex_supported)
359 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
360
361 control = GetFocus();
362 controlID = GetWindowLongPtr(control, GWLP_ID);
363 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
364
365 /* back button */
366 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
367 if (hwndtoindex_supported)
368 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
369
370 control = GetFocus();
371 controlID = GetWindowLongPtr(control, GWLP_ID);
372 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);
373
374 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
375 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
376
377 /* press next twice */
378 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
379 if (hwndtoindex_supported)
380 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
381 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
382 if (hwndtoindex_supported)
383 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
384 else
385 active_page = 3;
386
387 control = GetFocus();
388 controlID = GetWindowLongPtr(control, GWLP_ID);
389 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
390
391 /* try to navigate away, but shouldn't be able to */
392 SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
393 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
394
395 defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
396 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
397
398 DestroyWindow(hdlg);
399 }
400
401 static void test_buttons(void)
402 {
403 HPROPSHEETPAGE hpsp[1];
404 PROPSHEETPAGEA psp;
405 PROPSHEETHEADERA psh;
406 HWND hdlg;
407 HWND button;
408 RECT rc;
409 int prevRight, top;
410
411 memset(&psp, 0, sizeof(psp));
412 psp.dwSize = sizeof(psp);
413 psp.dwFlags = 0;
414 psp.hInstance = GetModuleHandleA(NULL);
415 U(psp).pszTemplate = "prop_page1";
416 U2(psp).pszIcon = NULL;
417 psp.pfnDlgProc = page_dlg_proc;
418 psp.lParam = 0;
419
420 hpsp[0] = CreatePropertySheetPageA(&psp);
421
422 memset(&psh, 0, sizeof(psh));
423 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
424 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
425 psh.pszCaption = "test caption";
426 psh.nPages = 1;
427 psh.hwndParent = GetDesktopWindow();
428 U3(psh).phpage = hpsp;
429 psh.pfnCallback = sheet_callback;
430
431 hdlg = (HWND)PropertySheetA(&psh);
432 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
433
434 /* OK button */
435 button = GetDlgItem(hdlg, IDOK);
436 GetWindowRect(button, &rc);
437 prevRight = rc.right;
438 top = rc.top;
439
440 /* Cancel button */
441 button = GetDlgItem(hdlg, IDCANCEL);
442 GetWindowRect(button, &rc);
443 ok(rc.top == top, "Cancel button should have same top as OK button\n");
444 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
445 prevRight = rc.right;
446
447 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
448 GetWindowRect(button, &rc);
449 ok(rc.top == top, "Apply button should have same top as OK button\n");
450 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
451 prevRight = rc.right;
452
453 button = GetDlgItem(hdlg, IDHELP);
454 GetWindowRect(button, &rc);
455 ok(rc.top == top, "Help button should have same top as OK button\n");
456 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
457
458 DestroyWindow(hdlg);
459 }
460
461 static BOOL add_button_has_been_pressed;
462
463 static INT_PTR CALLBACK
464 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
465 {
466 switch (msg)
467 {
468 case WM_COMMAND:
469 switch(LOWORD(wparam))
470 {
471 case IDC_PS_PUSHBUTTON1:
472 switch(HIWORD(wparam))
473 {
474 case BN_CLICKED:
475 add_button_has_been_pressed = TRUE;
476 return TRUE;
477 }
478 break;
479 }
480 break;
481 }
482 return FALSE;
483 }
484
485 static void test_custom_default_button(void)
486 {
487 HWND hdlg;
488 PROPSHEETPAGEA psp[1];
489 PROPSHEETHEADERA psh;
490 MSG msg;
491 LRESULT result;
492
493 psp[0].dwSize = sizeof (PROPSHEETPAGEA);
494 psp[0].dwFlags = PSP_USETITLE;
495 psp[0].hInstance = GetModuleHandleA(NULL);
496 U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
497 U2(psp[0]).pszIcon = NULL;
498 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
499 psp[0].pszTitle = "Page1";
500 psp[0].lParam = 0;
501
502 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
503 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
504 psh.hwndParent = GetDesktopWindow();
505 psh.hInstance = GetModuleHandleA(NULL);
506 U(psh).pszIcon = NULL;
507 psh.pszCaption = "PropertySheet1";
508 psh.nPages = 1;
509 U3(psh).ppsp = psp;
510 U2(psh).nStartPage = 0;
511
512 /* The goal of the test is to make sure that the Add button is pressed
513 * when the ENTER key is pressed and a different control, a combobox,
514 * has the keyboard focus. */
515 add_button_has_been_pressed = FALSE;
516
517 /* Create the modeless property sheet. */
518 hdlg = (HWND)PropertySheetA(&psh);
519 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
520
521 /* Set the Add button as the default button. */
522 SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
523
524 /* Make sure the default button is the Add button. */
525 result = SendMessage(hdlg, DM_GETDEFID, 0, 0);
526 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
527 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
528
529 /* At this point, the combobox should have keyboard focus, so we press ENTER.
530 * Pull the lever, Kronk! */
531 keybd_event(VK_RETURN, 0, 0, 0);
532
533 /* Process all the messages in the queue for this thread. */
534 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
535 {
536 if (!PropSheet_IsDialogMessage(hdlg, &msg))
537 {
538 TranslateMessage(&msg);
539 DispatchMessage(&msg);
540 }
541 }
542
543 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
544
545 DestroyWindow(hdlg);
546 }
547
548 #define RECEIVER_SHEET_CALLBACK 0
549 #define RECEIVER_SHEET_WINPROC 1
550 #define RECEIVER_PAGE 2
551
552 #define NUM_MSG_SEQUENCES 1
553 #define PROPSHEET_SEQ_INDEX 0
554
555 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
556 static WNDPROC oldWndProc;
557
558 static const struct message property_sheet_seq[] = {
559 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
560 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
561 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
562 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
563 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
564 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
565 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
566 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
567 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
568 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
569 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
570 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
571 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
572 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
573 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
574 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
575 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
576 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
577 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
578 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
579 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
580 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
581 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
582 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
583 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
584 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
585 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
586 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
587 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
588 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
589 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
590 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
591 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
592 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
593 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
594 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
595 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
596 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
597 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
598 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
599 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
600 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
601 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
602 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
603 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
604 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
605 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
606 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
607 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
608 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
609 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
610 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
611 /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
612 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
613 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
614 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
615 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
616 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
617 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
618 /*{ WM_GETICON, 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_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
622 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
623 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
624 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
625 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
626 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
627 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
628 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
629 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
630 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
631 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
632 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
633 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
634 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
635 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
636 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
637 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
638 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
639 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
640 { WM_GETICON, 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_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
644 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
645 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
646 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
647 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
648 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
649 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
650 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
651 { 0 }
652 };
653
654 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
655 {
656 struct message msg;
657
658 if (message < WM_USER &&
659 message != WM_GETICON &&
660 message != WM_GETTEXT &&
661 message != WM_IME_SETCONTEXT &&
662 message != WM_IME_NOTIFY &&
663 message != WM_PAINT &&
664 message != WM_ERASEBKGND &&
665 message != WM_SETCURSOR &&
666 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
667 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
668 message != 0x90)
669 {
670 /*trace("check_message: %04x, %04x\n", message, receiver);*/
671
672 msg.message = message;
673 msg.flags = sent|wparam|lparam|id;
674 msg.wParam = wParam;
675 msg.lParam = lParam;
676 msg.id = receiver;
677 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
678 }
679 }
680
681 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
682 {
683 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
684
685 return CallWindowProc (oldWndProc, hwnd, msg, wParam, lParam);
686 }
687
688 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
689 {
690 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
691
692 switch (msg)
693 {
694 case PSCB_INITIALIZED:
695 oldWndProc = (WNDPROC)GetWindowLongPtr (hwnd, GWLP_WNDPROC);
696 SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
697 return TRUE;
698 }
699
700 return TRUE;
701 }
702
703 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
704 LPARAM lParam)
705 {
706 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
707
708 return FALSE;
709 }
710
711 static void test_messages(void)
712 {
713 HPROPSHEETPAGE hpsp[1];
714 PROPSHEETPAGEA psp;
715 PROPSHEETHEADERA psh;
716 HWND hdlg;
717
718 init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
719
720 memset(&psp, 0, sizeof(psp));
721 psp.dwSize = sizeof(psp);
722 psp.dwFlags = 0;
723 psp.hInstance = GetModuleHandleA(NULL);
724 U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
725 U2(psp).pszIcon = NULL;
726 psp.pfnDlgProc = page_dlg_proc_messages;
727 psp.lParam = 0;
728
729 hpsp[0] = CreatePropertySheetPageA(&psp);
730
731 memset(&psh, 0, sizeof(psh));
732 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
733 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
734 | PSH_MODELESS | PSH_USEICONID;
735 psh.pszCaption = "test caption";
736 psh.nPages = 1;
737 psh.hwndParent = GetDesktopWindow();
738 U3(psh).phpage = hpsp;
739 psh.pfnCallback = sheet_callback_messages;
740
741 hdlg = (HWND)PropertySheetA(&psh);
742 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
743
744 ShowWindow(hdlg,SW_NORMAL);
745
746 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
747
748 DestroyWindow(hdlg);
749 }
750
751 static void test_PSM_ADDPAGE(void)
752 {
753 HPROPSHEETPAGE hpsp[5];
754 PROPSHEETPAGEA psp;
755 PROPSHEETHEADERA psh;
756 HWND hdlg, tab;
757 BOOL ret;
758 DWORD r;
759
760 memset(&psp, 0, sizeof(psp));
761 psp.dwSize = sizeof(psp);
762 psp.dwFlags = 0;
763 psp.hInstance = GetModuleHandleA(NULL);
764 U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
765 U2(psp).pszIcon = NULL;
766 psp.pfnDlgProc = page_dlg_proc_messages;
767 psp.lParam = 0;
768
769 /* two page with the same data */
770 hpsp[0] = CreatePropertySheetPageA(&psp);
771 hpsp[1] = CreatePropertySheetPageA(&psp);
772 hpsp[2] = CreatePropertySheetPageA(&psp);
773
774 U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR);
775 hpsp[3] = CreatePropertySheetPageA(&psp);
776
777 psp.dwFlags = PSP_PREMATURE;
778 hpsp[4] = CreatePropertySheetPageA(&psp);
779
780 memset(&psh, 0, sizeof(psh));
781 psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
782 psh.dwFlags = PSH_MODELESS;
783 psh.pszCaption = "test caption";
784 psh.nPages = 1;
785 psh.hwndParent = GetDesktopWindow();
786 U3(psh).phpage = hpsp;
787
788 hdlg = (HWND)PropertySheetA(&psh);
789 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
790
791 /* add pages one by one */
792 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
793 ok(ret == TRUE, "got %d\n", ret);
794
795 /* try with null and invalid value */
796 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
797 ok(ret == FALSE, "got %d\n", ret);
798
799 if (0)
800 {
801 /* crashes on native */
802 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
803 }
804 /* check item count */
805 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
806
807 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
808 ok(r == 2, "got %d\n", r);
809
810 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
811 ok(ret == TRUE, "got %d\n", ret);
812
813 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
814 ok(r == 3, "got %d\n", r);
815
816 /* add property sheet page that can't be created */
817 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]);
818 ok(ret == TRUE, "got %d\n", ret);
819
820 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
821 ok(r == 4, "got %d\n", r);
822
823 /* select page that can't be created */
824 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 0);
825 ok(ret == TRUE, "got %d\n", ret);
826
827 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
828 ok(r == 3, "got %d\n", r);
829
830 /* test PSP_PREMATURE flag with incorrect property sheet page */
831 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]);
832 ok(ret == FALSE, "got %d\n", ret);
833
834 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
835 ok(r == 3, "got %d\n", r);
836
837 DestroyWindow(hdlg);
838 }
839
840 START_TEST(propsheet)
841 {
842 test_title();
843 test_nopage();
844 test_disableowner();
845 test_wiznavigation();
846 test_buttons();
847 test_custom_default_button();
848 test_messages();
849 test_PSM_ADDPAGE();
850 }