comctl32/tests: Fix some test failures on comctl32 4.70.
[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
24 #include "resources.h"
25
26 #include "wine/test.h"
27
28 static HWND parent;
29 static HWND sheethwnd;
30
31 static LONG active_page = -1;
32
33 #define IDC_APPLY_BUTTON 12321
34
35 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
36 {
37     switch(msg)
38     {
39     case PSCB_INITIALIZED:
40       {
41         char caption[256];
42         GetWindowTextA(hwnd, caption, sizeof(caption));
43         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
44         sheethwnd = hwnd;
45         return 0;
46       }
47     }
48     return 0;
49 }
50
51 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
52                                       LPARAM lparam)
53 {
54     switch(msg)
55     {
56     case WM_INITDIALOG:
57       {
58         HWND sheet = GetParent(hwnd);
59         char caption[256];
60         GetWindowTextA(sheet, caption, sizeof(caption));
61         ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
62         return TRUE;
63       }
64
65     case WM_NOTIFY:
66       {
67         NMHDR *nmhdr = (NMHDR *)lparam;
68         switch(nmhdr->code)
69         {
70         case PSN_APPLY:
71             return TRUE;
72         default:
73             return FALSE;
74         }
75       }
76     case WM_NCDESTROY:
77         ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n");
78         return TRUE;
79
80     default:
81         return FALSE;
82     }
83 }
84
85 static void test_title(void)
86 {
87     HPROPSHEETPAGE hpsp[1];
88     PROPSHEETPAGEA psp;
89     PROPSHEETHEADERA psh;
90     HWND hdlg;
91
92     memset(&psp, 0, sizeof(psp));
93     psp.dwSize = sizeof(psp);
94     psp.dwFlags = 0;
95     psp.hInstance = GetModuleHandleA(NULL);
96     U(psp).pszTemplate = "prop_page1";
97     U2(psp).pszIcon = NULL;
98     psp.pfnDlgProc = page_dlg_proc;
99     psp.lParam = 0;
100
101     hpsp[0] = CreatePropertySheetPageA(&psp);
102
103     memset(&psh, 0, sizeof(psh));
104     psh.dwSize = sizeof(psh);
105     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
106     psh.pszCaption = "test caption";
107     psh.nPages = 1;
108     psh.hwndParent = GetDesktopWindow();
109     U3(psh).phpage = hpsp;
110     psh.pfnCallback = sheet_callback;
111
112     hdlg = (HWND)PropertySheetA(&psh);
113     if (hdlg == INVALID_HANDLE_VALUE)
114     {
115         win_skip("comctl32 4.70 needs dwSize adjustment\n");
116         psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
117         hdlg = (HWND)PropertySheetA(&psh);
118     }
119     DestroyWindow(hdlg);
120 }
121
122 static void test_nopage(void)
123 {
124     HPROPSHEETPAGE hpsp[1];
125     PROPSHEETPAGEA psp;
126     PROPSHEETHEADERA psh;
127     HWND hdlg;
128
129     memset(&psp, 0, sizeof(psp));
130     psp.dwSize = sizeof(psp);
131     psp.dwFlags = 0;
132     psp.hInstance = GetModuleHandleA(NULL);
133     U(psp).pszTemplate = "prop_page1";
134     U2(psp).pszIcon = NULL;
135     psp.pfnDlgProc = page_dlg_proc;
136     psp.lParam = 0;
137
138     hpsp[0] = CreatePropertySheetPageA(&psp);
139
140     memset(&psh, 0, sizeof(psh));
141     psh.dwSize = sizeof(psh);
142     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
143     psh.pszCaption = "test caption";
144     psh.nPages = 1;
145     psh.hwndParent = GetDesktopWindow();
146     U3(psh).phpage = hpsp;
147     psh.pfnCallback = sheet_callback;
148
149     hdlg = (HWND)PropertySheetA(&psh);
150     if (hdlg == INVALID_HANDLE_VALUE)
151     {
152         win_skip("comctl32 4.70 needs dwSize adjustment\n");
153         psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
154         hdlg = (HWND)PropertySheetA(&psh);
155     }
156     ShowWindow(hdlg,SW_NORMAL);
157     SendMessage(hdlg, PSM_REMOVEPAGE, 0, 0);
158     RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW);
159     DestroyWindow(hdlg);
160 }
161
162 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam)
163 {
164     switch(msg)
165     {
166     case PSCB_INITIALIZED:
167       {
168         ok(IsWindowEnabled(parent) == 0, "parent window should be disabled\n");
169         PostQuitMessage(0);
170         return FALSE;
171       }
172     }
173     return FALSE;
174 }
175
176 static void register_parent_wnd_class(void)
177 {
178     WNDCLASSA cls;
179
180     cls.style = 0;
181     cls.lpfnWndProc = DefWindowProcA;
182     cls.cbClsExtra = 0;
183     cls.cbWndExtra = 0;
184     cls.hInstance = GetModuleHandleA(NULL);
185     cls.hIcon = 0;
186     cls.hCursor = LoadCursorA(0, IDC_ARROW);
187     cls.hbrBackground = GetStockObject(WHITE_BRUSH);
188     cls.lpszMenuName = NULL;
189     cls.lpszClassName = "parent class";
190     RegisterClassA(&cls);
191 }
192
193 static void test_disableowner(void)
194 {
195     HPROPSHEETPAGE hpsp[1];
196     PROPSHEETPAGEA psp;
197     PROPSHEETHEADERA psh;
198     INT_PTR p;
199
200     register_parent_wnd_class();
201     parent = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0);
202
203     memset(&psp, 0, sizeof(psp));
204     psp.dwSize = sizeof(psp);
205     psp.dwFlags = 0;
206     psp.hInstance = GetModuleHandleA(NULL);
207     U(psp).pszTemplate = "prop_page1";
208     U2(psp).pszIcon = NULL;
209     psp.pfnDlgProc = NULL;
210     psp.lParam = 0;
211
212     hpsp[0] = CreatePropertySheetPageA(&psp);
213
214     memset(&psh, 0, sizeof(psh));
215     psh.dwSize = sizeof(psh);
216     psh.dwFlags = PSH_USECALLBACK;
217     psh.pszCaption = "test caption";
218     psh.nPages = 1;
219     psh.hwndParent = parent;
220     U3(psh).phpage = hpsp;
221     psh.pfnCallback = disableowner_callback;
222
223     p = PropertySheetA(&psh);
224     todo_wine
225     ok(p == 0, "Expected 0, got %ld\n", p);
226     ok(IsWindowEnabled(parent) != 0, "parent window should be enabled\n");
227     DestroyWindow(parent);
228 }
229
230 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
231 {
232     switch(msg){
233     case WM_NOTIFY:
234         {
235             LPNMHDR hdr = (LPNMHDR)lparam;
236             switch(hdr->code){
237             case PSN_SETACTIVE:
238                 active_page = PropSheet_HwndToIndex(hdr->hwndFrom, hwnd);
239                 return TRUE;
240             case PSN_KILLACTIVE:
241                 /* prevent navigation away from the fourth page */
242                 if(active_page == 3){
243                     SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
244                     return TRUE;
245                 }
246             }
247             break;
248         }
249     }
250     return FALSE;
251 }
252
253 static void test_wiznavigation(void)
254 {
255     HPROPSHEETPAGE hpsp[4];
256     PROPSHEETPAGEA psp[4];
257     PROPSHEETHEADERA psh;
258     HWND hdlg, control;
259     LONG_PTR controlID;
260     LRESULT defidres;
261     BOOL hwndtoindex_supported = TRUE;
262     const INT nextID = 12324;
263     const INT backID = 12323;
264
265     /* create the property sheet pages */
266     memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4);
267
268     psp[0].dwSize = sizeof(PROPSHEETPAGEA);
269     psp[0].hInstance = GetModuleHandleA(NULL);
270     U(psp[0]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO);
271     psp[0].pfnDlgProc = nav_page_proc;
272     hpsp[0] = CreatePropertySheetPageA(&psp[0]);
273
274     psp[1].dwSize = sizeof(PROPSHEETPAGEA);
275     psp[1].hInstance = GetModuleHandleA(NULL);
276     U(psp[1]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT);
277     psp[1].pfnDlgProc = nav_page_proc;
278     hpsp[1] = CreatePropertySheetPageA(&psp[1]);
279
280     psp[2].dwSize = sizeof(PROPSHEETPAGEA);
281     psp[2].hInstance = GetModuleHandleA(NULL);
282     U(psp[2]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO);
283     psp[2].pfnDlgProc = nav_page_proc;
284     hpsp[2] = CreatePropertySheetPageA(&psp[2]);
285
286     psp[3].dwSize = sizeof(PROPSHEETPAGEA);
287     psp[3].hInstance = GetModuleHandleA(NULL);
288     U(psp[3]).pszTemplate = MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT);
289     psp[3].pfnDlgProc = nav_page_proc;
290     hpsp[3] = CreatePropertySheetPageA(&psp[3]);
291
292     /* set up the property sheet dialog */
293     memset(&psh, 0, sizeof(psh));
294     psh.dwSize = sizeof(psh);
295     psh.dwFlags = PSH_MODELESS | PSH_WIZARD;
296     psh.pszCaption = "A Wizard";
297     psh.nPages = 4;
298     psh.hwndParent = GetDesktopWindow();
299     U3(psh).phpage = hpsp;
300     hdlg = (HWND)PropertySheetA(&psh);
301     if (hdlg == INVALID_HANDLE_VALUE)
302     {
303         win_skip("comctl32 4.70 needs dwSize adjustment\n");
304         psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
305         hdlg = (HWND)PropertySheetA(&psh);
306     }
307
308     ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page);
309
310     control = GetFocus();
311     controlID = GetWindowLongPtr(control, GWLP_ID);
312     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
313
314     /* simulate pressing the Next button */
315     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
316     if (!active_page) hwndtoindex_supported = FALSE;
317     if (hwndtoindex_supported)
318         ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page);
319
320     control = GetFocus();
321     controlID = GetWindowLongPtr(control, GWLP_ID);
322     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);
323
324     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
325     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
326
327     /* set the focus to the second edit box on this page */
328     SetFocus(GetNextDlgTabItem(hdlg, control, FALSE));
329
330     /* press next again */
331     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
332     if (hwndtoindex_supported)
333         ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
334
335     control = GetFocus();
336     controlID = GetWindowLongPtr(control, GWLP_ID);
337     ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID);
338
339     /* back button */
340     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
341     if (hwndtoindex_supported)
342         ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page);
343
344     control = GetFocus();
345     controlID = GetWindowLongPtr(control, GWLP_ID);
346     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);
347
348     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
349     ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres));
350
351     /* press next twice */
352     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
353     if (hwndtoindex_supported)
354         ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page);
355     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0);
356     if (hwndtoindex_supported)
357         ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page);
358     else
359         active_page = 3;
360
361     control = GetFocus();
362     controlID = GetWindowLongPtr(control, GWLP_ID);
363     ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID);
364
365     /* try to navigate away, but shouldn't be able to */
366     SendMessage(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0);
367     ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page);
368
369     defidres = SendMessage(hdlg, DM_GETDEFID, 0, 0);
370     ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres));
371
372     DestroyWindow(hdlg);
373 }
374 static void test_buttons(void)
375 {
376     HPROPSHEETPAGE hpsp[1];
377     PROPSHEETPAGEA psp;
378     PROPSHEETHEADERA psh;
379     HWND hdlg;
380     HWND button;
381     RECT rc;
382     int prevRight, top;
383
384     memset(&psp, 0, sizeof(psp));
385     psp.dwSize = sizeof(psp);
386     psp.dwFlags = 0;
387     psp.hInstance = GetModuleHandleA(NULL);
388     U(psp).pszTemplate = "prop_page1";
389     U2(psp).pszIcon = NULL;
390     psp.pfnDlgProc = page_dlg_proc;
391     psp.lParam = 0;
392
393     hpsp[0] = CreatePropertySheetPageA(&psp);
394
395     memset(&psh, 0, sizeof(psh));
396     psh.dwSize = sizeof(psh);
397     psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
398     psh.pszCaption = "test caption";
399     psh.nPages = 1;
400     psh.hwndParent = GetDesktopWindow();
401     U3(psh).phpage = hpsp;
402     psh.pfnCallback = sheet_callback;
403
404     hdlg = (HWND)PropertySheetA(&psh);
405     if (hdlg == INVALID_HANDLE_VALUE)
406     {
407         win_skip("comctl32 4.70 needs dwSize adjustment\n");
408         psh.dwSize = sizeof(psh) - sizeof(HBITMAP) - sizeof(HPALETTE) - sizeof(HBITMAP);
409         hdlg = (HWND)PropertySheetA(&psh);
410     }
411
412     /* OK button */
413     button = GetDlgItem(hdlg, IDOK);
414     GetWindowRect(button, &rc);
415     prevRight = rc.right;
416     top = rc.top;
417
418     /* Cancel button */
419     button = GetDlgItem(hdlg, IDCANCEL);
420     GetWindowRect(button, &rc);
421     ok(rc.top == top, "Cancel button should have same top as OK button\n");
422     ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n");
423     prevRight = rc.right;
424
425     button = GetDlgItem(hdlg, IDC_APPLY_BUTTON);
426     GetWindowRect(button, &rc);
427     ok(rc.top == top, "Apply button should have same top as OK button\n");
428     ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n");
429     prevRight = rc.right;
430
431     button = GetDlgItem(hdlg, IDHELP);
432     GetWindowRect(button, &rc);
433     ok(rc.top == top, "Help button should have same top as OK button\n");
434     ok(rc.left > prevRight, "Help button should be to the right of Apply button\n");
435
436     DestroyWindow(hdlg);
437 }
438
439 START_TEST(propsheet)
440 {
441     test_title();
442     test_nopage();
443     test_disableowner();
444     test_wiznavigation();
445     test_buttons();
446 }