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