user32: Fix for finding nested default buttons.
[wine] / dlls / comctl32 / tests / 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 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
37 {
38     switch(msg)
39     {
40     case PSCB_INITIALIZED:
41       {
42         char caption[256];
43         GetWindowTextA(hwnd, caption, sizeof(caption));
44         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
45         sheethwnd = hwnd;
46         return 0;
47       }
48     }
49     return 0;
50 }
51
52 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
53                                       LPARAM lparam)
54 {
55     switch(msg)
56     {
57     case WM_INITDIALOG:
58       {
59         HWND sheet = GetParent(hwnd);
60         char caption[256];
61         GetWindowTextA(sheet, caption, sizeof(caption));
62         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
63         return TRUE;
64       }
65
66     case WM_NOTIFY:
67       {
68         NMHDR *nmhdr = (NMHDR *)lparam;
69         switch(nmhdr->code)
70         {
71         case PSN_APPLY:
72             return TRUE;
73         default:
74             return FALSE;
75         }
76       }
77     case WM_NCDESTROY:
78         ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
79         return TRUE;
80
81     default:
82         return FALSE;
83     }
84 }
85
86 static void test_title(void)
87 {
88     HPROPSHEETPAGE hpsp[1];
89     PROPSHEETPAGEA psp;
90     PROPSHEETHEADERA psh;
91     HWND hdlg;
92
93     memset(&psp, 0, sizeof(psp));
94     psp.dwSize = sizeof(psp);
95     psp.dwFlags = 0;
96     psp.hInstance = GetModuleHandleA(NULL);
97     U(psp).pszTemplate = "prop_page1";
98     U2(psp).pszIcon = NULL;
99     psp.pfnDlgProc = page_dlg_proc;
100     psp.lParam = 0;
101
102     hpsp[0] = CreatePropertySheetPageA(&psp);
103
104     memset(&psh, 0, sizeof(psh));
105     psh.dwSize = CCSIZEOF_STRUCT(PROPSHEETHEADERA, pfnCallback);
106     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
107     psh.pszCaption = "test caption";
108     psh.nPages = 1;
109     psh.hwndParent = GetDesktopWindow();
110     U3(psh).phpage = hpsp;
111     psh.pfnCallback = sheet_callback;
112
113     hdlg = (HWND)PropertySheetA(&psh);
114     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
115
116     DestroyWindow(hdlg);
117 }
118
119 static void test_nopage(void)
120 {
121     HPROPSHEETPAGE hpsp[1];
122     PROPSHEETPAGEA psp;
123     PROPSHEETHEADERA psh;
124     HWND hdlg;
125
126     memset(&psp, 0, sizeof(psp));
127     psp.dwSize = sizeof(psp);
128     psp.dwFlags = 0;
129     psp.hInstance = GetModuleHandleA(NULL);
130     U(psp).pszTemplate = "prop_page1";
131     U2(psp).pszIcon = NULL;
132     psp.pfnDlgProc = page_dlg_proc;
133     psp.lParam = 0;
134
135     hpsp[0] = CreatePropertySheetPageA(&psp);
136
137     memset(&psh, 0, sizeof(psh));
138     psh.dwSize = CCSIZEOF_STRUCT(PROPSHEETHEADERA, pfnCallback);
139     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
140     psh.pszCaption = "test caption";
141     psh.nPages = 1;
142     psh.hwndParent = GetDesktopWindow();
143     U3(psh).phpage = hpsp;
144     psh.pfnCallback = sheet_callback;
145
146     hdlg = (HWND)PropertySheetA(&psh);
147     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg);
148
149     ShowWindow(hdlg,SW_NORMAL);
150     SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
151     RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
152     DestroyWindow(hdlg);
153 }
154
155 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
156 {
157     switch(msg)
158     {
159     case PSCB_INITIALIZED:
160       {
161         ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n");
162         PostQuitMessage(0);
163         return FALSE;
164       }
165     }
166     return FALSE;
167 }
168
169 static void register_parent_wnd_class(void)
170 {
171     WNDCLASSA cls;
172
173     cls.style = 0;
174     cls.lpfnWndProc = DefWindowProcA;
175     cls.cbClsExtra = 0;
176     cls.cbWndExtra = 0;
177     cls.hInstance = GetModuleHandleA(NULL);
178     cls.hIcon = 0;
179     cls.hCursor = LoadCursorA(0, IDC_ARROW);
180     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
181     cls.lpszMenuName = NULL;
182     cls.lpszClassName = "parent class";
183     RegisterClassA(&cls);
184 }
185
186 static void test_disableowner(void)
187 {
188     HPROPSHEETPAGE hpsp[1];
189     PROPSHEETPAGEA psp;
190     PROPSHEETHEADERA psh;
191     INT_PTR p;
192
193     register_parent_wnd_class();
194     parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
195
196     memset(&psp, 0, sizeof(psp));
197     psp.dwSize = sizeof(psp);
198     psp.dwFlags = 0;
199     psp.hInstance = GetModuleHandleA(NULL);
200     U(psp).pszTemplate = "prop_page1";
201     U2(psp).pszIcon = NULL;
202     psp.pfnDlgProc = NULL;
203     psp.lParam = 0;
204
205     hpsp[0] = CreatePropertySheetPageA(&psp);
206
207     memset(&psh, 0, sizeof(psh));
208     psh.dwSize = sizeof(psh);
209     psh.dwFlags = PSH_USECALLBACK;
210     psh.pszCaption = "test caption";
211     psh.nPages = 1;
212     psh.hwndParent = parenthwnd;
213     U3(psh).phpage = hpsp;
214     psh.pfnCallback = disableowner_callback;
215
216     p = PropertySheetA(&psh);
217     todo_wine
218     ok(p == 0, "Expected 0, got %ld\n", p);
219     ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
220     DestroyWindow(parenthwnd);
221 }
222
223 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
224 {
225     switch(msg){
226     case WM_NOTIFY:
227         {
228             LPNMHDR hdr = (LPNMHDR)lparam;
229             switch(hdr->code){
230             case PSN_SETACTIVE:
231                 active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
232                 return TRUE;
233             case PSN_KILLACTIVE:
234                 /* prevent navigation away from the fourth page */
235                 if(active_page == 3){
236                     SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
237                     return TRUE;
238                 }
239             }
240             break;
241         }
242     }
243     return FALSE;
244 }
245
246 static void test_wiznavigation(void)
247 {
248     HPROPSHEETPAGE hpsp[4];
249     PROPSHEETPAGEA psp[4];
250     PROPSHEETHEADERA psh;
251     HWND hdlg, control;
252     LONG_PTR controlID;
253     LRESULT defidres;
254     BOOL hwndtoindex_supported = TRUE;
255     const INT nextID = 12324;
256     const INT backID = 12323;
257
258     /* create the property sheet pages */
259     memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
260
261     psp[0].dwSize = sizeof(PROPSHEETPAGEA);
262     psp[0].hInstance = GetModuleHandleA(NULL);
263     U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
264     psp[0].pfnDlgProc = nav_page_proc;
265     hpsp[0] = CreatePropertySheetPageA(&psp[0]);
266
267     psp[1].dwSize = sizeof(PROPSHEETPAGEA);
268     psp[1].hInstance = GetModuleHandleA(NULL);
269     U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
270     psp[1].pfnDlgProc = nav_page_proc;
271     hpsp[1] = CreatePropertySheetPageA(&psp[1]);
272
273     psp[2].dwSize = sizeof(PROPSHEETPAGEA);
274     psp[2].hInstance = GetModuleHandleA(NULL);
275     U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
276     psp[2].pfnDlgProc = nav_page_proc;
277     hpsp[2] = CreatePropertySheetPageA(&psp[2]);
278
279     psp[3].dwSize = sizeof(PROPSHEETPAGEA);
280     psp[3].hInstance = GetModuleHandleA(NULL);
281     U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
282     psp[3].pfnDlgProc = nav_page_proc;
283     hpsp[3] = CreatePropertySheetPageA(&psp[3]);
284
285     /* set up the property sheet dialog */
286     memset(&psh, 0, sizeof(psh));
287     psh.dwSize = CCSIZEOF_STRUCT(PROPSHEETHEADERA, pfnCallback);
288     psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
289     psh.pszCaption = "A Wizard";
290     psh.nPages = 4;
291     psh.hwndParent = GetDesktopWindow();
292     U3(psh).phpage = hpsp;
293     hdlg = (HWND)PropertySheetA(&psh);
294     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
295
296     ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
297
298     control = GetFocus();
299     controlID = GetWindowLongPtr(control, GWLP_ID);
300     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
301
302     /* simulate pressing the Next button */
303     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
304     if (!active_page) hwndtoindex_supported = FALSE;
305     if (hwndtoindex_supported)
306         ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
307
308     control = GetFocus();
309     controlID = GetWindowLongPtr(control, GWLP_ID);
310     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);
311
312     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
313     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
314
315     /* set the focus to the second edit box on this page */
316     SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
317
318     /* press next again */
319     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
320     if (hwndtoindex_supported)
321         ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
322
323     control = GetFocus();
324     controlID = GetWindowLongPtr(control, GWLP_ID);
325     ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
326
327     /* back button */
328     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
329     if (hwndtoindex_supported)
330         ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
331
332     control = GetFocus();
333     controlID = GetWindowLongPtr(control, GWLP_ID);
334     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);
335
336     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
337     ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
338
339     /* press next twice */
340     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
341     if (hwndtoindex_supported)
342         ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
343     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
344     if (hwndtoindex_supported)
345         ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
346     else
347         active_page = 3;
348
349     control = GetFocus();
350     controlID = GetWindowLongPtr(control, GWLP_ID);
351     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
352
353     /* try to navigate away, but shouldn't be able to */
354     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
355     ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
356
357     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
358     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
359
360     DestroyWindow(hdlg);
361 }
362
363 static void test_buttons(void)
364 {
365     HPROPSHEETPAGE hpsp[1];
366     PROPSHEETPAGEA psp;
367     PROPSHEETHEADERA psh;
368     HWND hdlg;
369     HWND button;
370     RECT rc;
371     int prevRight, top;
372
373     memset(&psp, 0, sizeof(psp));
374     psp.dwSize = sizeof(psp);
375     psp.dwFlags = 0;
376     psp.hInstance = GetModuleHandleA(NULL);
377     U(psp).pszTemplate = "prop_page1";
378     U2(psp).pszIcon = NULL;
379     psp.pfnDlgProc = page_dlg_proc;
380     psp.lParam = 0;
381
382     hpsp[0] = CreatePropertySheetPageA(&psp);
383
384     memset(&psh, 0, sizeof(psh));
385     psh.dwSize = CCSIZEOF_STRUCT(PROPSHEETHEADERA, pfnCallback);
386     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
387     psh.pszCaption = "test caption";
388     psh.nPages = 1;
389     psh.hwndParent = GetDesktopWindow();
390     U3(psh).phpage = hpsp;
391     psh.pfnCallback = sheet_callback;
392
393     hdlg = (HWND)PropertySheetA(&psh);
394     ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n");
395
396     /* OK button */
397     button = GetDlgItem(hdlg, IDOK);
398     GetWindowRect(button, &rc);
399     prevRight = rc.right;
400     top = rc.top;
401
402     /* Cancel button */
403     button = GetDlgItem(hdlg, IDCANCEL);
404     GetWindowRect(button, &rc);
405     ok(rc.top == top, "Cancel button should have same top as OK button\n");
406     ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
407     prevRight = rc.right;
408
409     button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
410     GetWindowRect(button, &rc);
411     ok(rc.top == top, "Apply button should have same top as OK button\n");
412     ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
413     prevRight = rc.right;
414
415     button = GetDlgItem(hdlg, IDHELP);
416     GetWindowRect(button, &rc);
417     ok(rc.top == top, "Help button should have same top as OK button\n");
418     ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
419
420     DestroyWindow(hdlg);
421 }
422
423 static BOOL add_button_has_been_pressed;
424
425 static INT_PTR CALLBACK
426 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
427 {
428     switch (msg)
429     {
430     case WM_COMMAND:
431         switch(LOWORD(wparam))
432         {
433         case IDC_PS_PUSHBUTTON1:
434             switch(HIWORD(wparam))
435             {
436             case BN_CLICKED:
437                 add_button_has_been_pressed = TRUE;
438                 return TRUE;
439             }
440             break;
441         }
442         break;
443     }
444     return FALSE;
445 }
446
447 static void test_custom_default_button(void)
448 {
449     HWND hdlg;
450     PROPSHEETPAGEA psp[1];
451     PROPSHEETHEADERA psh;
452     MSG msg;
453     LRESULT result;
454
455     psp[0].dwSize = sizeof (PROPSHEETPAGEA);
456     psp[0].dwFlags = PSP_USETITLE;
457     psp[0].hInstance = GetModuleHandleA(NULL);
458     U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON);
459     U2(psp[0]).pszIcon = NULL;
460     psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc;
461     psp[0].pszTitle = "Page1";
462     psp[0].lParam = 0;
463
464     psh.dwSize = sizeof (PROPSHEETHEADERA);
465     psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS;
466     psh.hwndParent = GetDesktopWindow();
467     psh.hInstance = GetModuleHandleA(NULL);
468     U(psh).pszIcon = NULL;
469     psh.pszCaption =  "PropertySheet1";
470     psh.nPages = 1;
471     U3(psh).ppsp = psp;
472     U2(psh).nStartPage = 0;
473
474     /* The goal of the test is to make sure that the Add button is pressed
475      * when the ENTER key is pressed and a different control, a combobox,
476      * has the keyboard focus. */
477     add_button_has_been_pressed = FALSE;
478
479     /* Create the modeless property sheet. */
480     hdlg = (HWND)PropertySheetA(&psh);
481     ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n");
482
483     /* Set the Add button as the default button. */
484     SendMessage(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0);
485
486     /* Make sure the default button is the Add button. */
487     result = SendMessage(hdlg, DM_GETDEFID, 0, 0);
488     ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n");
489     ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n");
490
491     /* At this point, the combobox should have keyboard focus, so we press ENTER.
492      * Pull the lever, Kronk! */
493     keybd_event(VK_RETURN, 0, 0, 0);
494
495     /* Process all the messages in the queue for this thread. */
496     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
497     {
498         if (!PropSheet_IsDialogMessage(hdlg, &msg))
499         {
500             TranslateMessage(&msg);
501             DispatchMessage(&msg);
502         }
503     }
504
505     ok(add_button_has_been_pressed, "The Add button has not been pressed!\n");
506
507     DestroyWindow(hdlg);
508 }
509
510 #define RECEIVER_SHEET_CALLBACK 0
511 #define RECEIVER_SHEET_WINPROC  1
512 #define RECEIVER_PAGE           2
513
514 #define NUM_MSG_SEQUENCES   1
515 #define PROPSHEET_SEQ_INDEX 0
516
517 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
518 static WNDPROC oldWndProc;
519
520 static const struct message property_sheet_seq[] = {
521     { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
522     { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK },
523     { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
524     /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
525     { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
526     { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
527     { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
528     /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
529     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
530     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
531     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
532     { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
533     { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
534     { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
535     { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
536     { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
537     /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
538     { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
539     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
540     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
541     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
542     { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
543     { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
544     /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
545     { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
546     { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
547     { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
548     /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
549     { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
550     { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE },
551     { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE },
552     /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/
553     { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
554     { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE },
555     { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE },
556     { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE },
557     { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE },
558     { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
559     { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
560     /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
561     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
562     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
563     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
564     { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
565     { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE },
566     /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
567     { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
568     { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
569     { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
570     { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE },
571     { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
572     { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
573     /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
574     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
575     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
576     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
577     { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
578     { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
579     { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
580     /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
581     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
582     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
583     { WM_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
584     { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE },
585     { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE },
586     { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/
587     { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE },
588     { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE },
589     { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
590     { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
591     { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
592     { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
593     /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
594     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
595     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
596     { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
597     { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
598     { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE },
599     { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
600     { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC },
601     /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
602     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
603     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
604     { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
605     /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
606     { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE },
607     { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
608     { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE },
609     { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },
610     { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/
611     /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE },
612     { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/
613     { 0 }
614 };
615
616 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver)
617 {
618     struct message msg;
619
620     if (message < WM_USER &&
621         message != WM_GETICON &&
622         message != WM_GETTEXT &&
623         message != WM_IME_SETCONTEXT &&
624         message != WM_IME_NOTIFY &&
625         message != WM_PAINT &&
626         message != WM_ERASEBKGND &&
627         message != WM_SETCURSOR &&
628         (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) &&
629         (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) &&
630         message != 0x90)
631     {
632         /*trace("check_message: %04x, %04x\n", message, receiver);*/
633
634         msg.message = message;
635         msg.flags = sent|wparam|lparam|id;
636         msg.wParam = wParam;
637         msg.lParam = lParam;
638         msg.id = receiver;
639         add_message(sequences, PROPSHEET_SEQ_INDEX, &msg);
640     }
641 }
642
643 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
644 {
645     save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC);
646
647     return CallWindowProc (oldWndProc, hwnd, msg, wParam, lParam);
648 }
649
650 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam)
651 {
652     save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK);
653
654     switch (msg)
655     {
656     case PSCB_INITIALIZED:
657         oldWndProc = (WNDPROC)GetWindowLongPtr (hwnd, GWLP_WNDPROC);
658         SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc);
659         return TRUE;
660     }
661
662     return TRUE;
663 }
664
665 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam,
666                                                LPARAM lParam)
667 {
668     save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE);
669
670     return FALSE;
671 }
672
673 static void test_messages(void)
674 {
675     HPROPSHEETPAGE hpsp[1];
676     PROPSHEETPAGEA psp;
677     PROPSHEETHEADERA psh;
678     HWND hdlg;
679
680     init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
681
682     memset(&psp, 0, sizeof(psp));
683     psp.dwSize = sizeof(psp);
684     psp.dwFlags = 0;
685     psp.hInstance = GetModuleHandleA(NULL);
686     U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
687     U2(psp).pszIcon = NULL;
688     psp.pfnDlgProc = page_dlg_proc_messages;
689     psp.lParam = 0;
690
691     hpsp[0] = CreatePropertySheetPageA(&psp);
692
693     memset(&psh, 0, sizeof(psh));
694     psh.dwSize = CCSIZEOF_STRUCT(PROPSHEETHEADERA, pfnCallback);
695     psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK
696                   | PSH_MODELESS | PSH_USEICONID;
697     psh.pszCaption = "test caption";
698     psh.nPages = 1;
699     psh.hwndParent = GetDesktopWindow();
700     U3(psh).phpage = hpsp;
701     psh.pfnCallback = sheet_callback_messages;
702
703     hdlg = (HWND)PropertySheetA(&psh);
704     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
705
706     ShowWindow(hdlg,SW_NORMAL);
707
708     ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE);
709
710     DestroyWindow(hdlg);
711 }
712
713 static void test_PSM_ADDPAGE(void)
714 {
715     HPROPSHEETPAGE hpsp[3];
716     PROPSHEETPAGEA psp;
717     PROPSHEETHEADERA psh;
718     HWND hdlg, tab;
719     BOOL ret;
720     DWORD r;
721
722     memset(&psp, 0, sizeof(psp));
723     psp.dwSize = sizeof(psp);
724     psp.dwFlags = 0;
725     psp.hInstance = GetModuleHandleA(NULL);
726     U(psp).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST);
727     U2(psp).pszIcon = NULL;
728     psp.pfnDlgProc = page_dlg_proc_messages;
729     psp.lParam = 0;
730
731     /* two page with the same data */
732     hpsp[0] = CreatePropertySheetPageA(&psp);
733     hpsp[1] = CreatePropertySheetPageA(&psp);
734     hpsp[2] = CreatePropertySheetPageA(&psp);
735
736     memset(&psh, 0, sizeof(psh));
737     psh.dwSize = sizeof(psh);
738     psh.dwFlags = PSH_MODELESS;
739     psh.pszCaption = "test caption";
740     psh.nPages = 1;
741     psh.hwndParent = GetDesktopWindow();
742     U3(psh).phpage = hpsp;
743
744     hdlg = (HWND)PropertySheetA(&psh);
745     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
746
747     /* add pages one by one */
748     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
749     ok(ret == TRUE, "got %d\n", ret);
750
751     /* try with null and invalid value */
752     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
753     ok(ret == FALSE, "got %d\n", ret);
754
755 if (0)
756 {
757     /* crashes on native */
758     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
759 }
760     /* check item count */
761     tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
762
763     r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
764     ok(r == 2, "got %d\n", r);
765
766     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
767     ok(ret == TRUE, "got %d\n", ret);
768
769     r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
770     ok(r == 3, "got %d\n", r);
771
772     DestroyWindow(hdlg);
773 }
774
775 START_TEST(propsheet)
776 {
777     test_title();
778     test_nopage();
779     test_disableowner();
780     test_wiznavigation();
781     test_buttons();
782     test_custom_default_button();
783     test_messages();
784     test_PSM_ADDPAGE();
785 }