comdlg32: Correct title of "Save As" dialog.
[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
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[3];
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     memset(&psh, 0, sizeof(psh));
775     psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
776     psh.dwFlags = PSH_MODELESS;
777     psh.pszCaption = "test caption";
778     psh.nPages = 1;
779     psh.hwndParent = GetDesktopWindow();
780     U3(psh).phpage = hpsp;
781
782     hdlg = (HWND)PropertySheetA(&psh);
783     ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg);
784
785     /* add pages one by one */
786     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]);
787     ok(ret == TRUE, "got %d\n", ret);
788
789     /* try with null and invalid value */
790     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0);
791     ok(ret == FALSE, "got %d\n", ret);
792
793 if (0)
794 {
795     /* crashes on native */
796     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE);
797 }
798     /* check item count */
799     tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0);
800
801     r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
802     ok(r == 2, "got %d\n", r);
803
804     ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]);
805     ok(ret == TRUE, "got %d\n", ret);
806
807     r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0);
808     ok(r == 3, "got %d\n", r);
809
810     DestroyWindow(hdlg);
811 }
812
813 START_TEST(propsheet)
814 {
815     test_title();
816     test_nopage();
817     test_disableowner();
818     test_wiznavigation();
819     test_buttons();
820     test_custom_default_button();
821     test_messages();
822     test_PSM_ADDPAGE();
823 }