Merge branch 'ntfs_rebase'
[reactos.git] / modules / rostests / winetests / user32 / dialog.c
1 /* Unit test suite for the dialog functions.
2 *
3 * Copyright 2004 Bill Medland
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 *
20 *
21 * This test suite currently works by building a quite complex hierarchy of
22 * objects in a variety of styles and then performs a limited number of tests
23 * for the previous and next dialog group or tab items.
24 *
25 * The test specifically does not test all possibilities at this time since
26 * there are several cases where the Windows behaviour is rather strange and
27 * significant work would be required to get the Wine code to duplicate the
28 * strangeness, especially since most are in situations that would not
29 * normally be met.
30 */
31
32 #include "precomp.h"
33
34 #define MAXHWNDS 1024
35 static HWND hwnd [MAXHWNDS];
36 static unsigned int numwnds=1; /* 0 is reserved for null */
37
38 /* Global handles */
39 static HINSTANCE g_hinst; /* This application's HINSTANCE */
40 static HWND g_hwndMain, g_hwndButton1, g_hwndButton2, g_hwndButtonCancel;
41 static HWND g_hwndTestDlg, g_hwndTestDlgBut1, g_hwndTestDlgBut2, g_hwndTestDlgEdit;
42 static HWND g_hwndInitialFocusT1, g_hwndInitialFocusT2, g_hwndInitialFocusGroupBox;
43
44 static LONG g_styleInitialFocusT1, g_styleInitialFocusT2;
45 static BOOL g_bInitialFocusInitDlgResult, g_bReceivedCommand;
46
47 static BOOL g_terminated;
48
49 typedef struct {
50 INT_PTR id;
51 int parent;
52 DWORD style;
53 DWORD exstyle;
54 } h_entry;
55
56 static const h_entry hierarchy [] = {
57 /* 0 is reserved for the null window */
58 { 1, 0, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE},
59 { 20, 1, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
60 { 2, 1, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
61 { 60, 2, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
62 /* What happens with groups when the parent is disabled */
63 { 8, 2, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, WS_EX_CONTROLPARENT},
64 { 85, 8, WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP, 0},
65 { 9, 8, WS_CHILD, WS_EX_CONTROLPARENT},
66 { 86, 9, WS_CHILD | WS_VISIBLE, 0},
67 { 87, 9, WS_CHILD | WS_VISIBLE, 0},
68 { 31, 8, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
69 { 10, 2, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
70 { 88, 10, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
71 { 11, 10, WS_CHILD, WS_EX_CONTROLPARENT},
72 { 89, 11, WS_CHILD | WS_VISIBLE, 0},
73 { 32, 11, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
74 { 90, 11, WS_CHILD | WS_VISIBLE, 0},
75 { 33, 10, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
76 { 21, 2, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
77 { 61, 2, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
78 { 3, 1, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
79 { 22, 3, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
80 { 62, 3, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
81 { 7, 3, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
82 { 4, 7, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
83 { 83, 4, WS_CHILD | WS_VISIBLE, 0},
84 { 5, 4, WS_CHILD | WS_VISIBLE | DS_CONTROL, 0},
85 /* A couple of controls around the main dialog */
86 { 29, 5, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
87 { 81, 5, WS_CHILD | WS_VISIBLE, 0},
88 /* The main dialog with lots of controls */
89 { 6, 5, WS_CHILD | WS_VISIBLE, WS_EX_CONTROLPARENT},
90 /* At the start of a dialog */
91 /* Disabled controls are skipped */
92 { 63, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
93 /* Invisible controls are skipped */
94 { 64, 6, WS_CHILD | WS_TABSTOP, 0},
95 /* Invisible disabled controls are skipped */
96 { 65, 6, WS_CHILD | WS_DISABLED | WS_TABSTOP, 0},
97 /* Non-tabstop controls are skipped for tabs but not for groups */
98 { 66, 6, WS_CHILD | WS_VISIBLE, 0},
99 /* End of first group, with no tabstops in it */
100 { 23, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
101 /* At last a tabstop */
102 { 67, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
103 /* A group that is totally disabled or invisible */
104 { 24, 6, WS_CHILD | WS_DISABLED | WS_GROUP, 0},
105 { 68, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
106 { 69, 6, WS_CHILD | WS_TABSTOP, 0},
107 /* A valid group in the middle of the dialog (not the first nor last group*/
108 { 25, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
109 /* A non-tabstop item will be skipped for tabs */
110 { 70, 6, WS_CHILD | WS_VISIBLE, 0},
111 /* A disabled item will be skipped for tabs and groups */
112 { 71, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
113 /* A valid item will be found for tabs and groups */
114 { 72, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
115 /* A disabled item to skip when looking for the next group item */
116 { 73, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
117 /* The next group begins with an enabled visible label */
118 { 26, 6, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
119 { 74, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
120 { 75, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
121 /* That group is terminated by a disabled label */
122 { 27, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_GROUP, 0},
123 { 76, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
124 { 77, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
125 /* That group is terminated by an invisible label */
126 { 28, 6, WS_CHILD | WS_GROUP, 0},
127 /* The end of the dialog with item for loop and recursion testing */
128 { 78, 6, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
129 /* No tabstop so skipped for prev tab, but found for prev group */
130 { 79, 6, WS_CHILD | WS_VISIBLE, 0},
131 { 80, 6, WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_TABSTOP, 0},
132 /* A couple of controls after the main dialog */
133 { 82, 5, WS_CHILD | WS_VISIBLE, 0},
134 { 30, 5, WS_CHILD | WS_VISIBLE | WS_GROUP, 0},
135 /* And around them */
136 { 84, 4, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 0},
137 {0, 0, 0, 0}
138 };
139
140 static BOOL CreateWindows (HINSTANCE hinst)
141 {
142 const h_entry *p = hierarchy;
143
144 while (p->id != 0)
145 {
146 DWORD style, exstyle;
147 char ctrlname[9];
148
149 /* Basically assert that the hierarchy is valid and track the
150 * maximum control number
151 */
152 if (p->id >= numwnds)
153 {
154 if (p->id >= sizeof(hwnd)/sizeof(hwnd[0]))
155 {
156 trace ("Control %ld is out of range\n", p->id);
157 return FALSE;
158 }
159 else
160 numwnds = p->id+1;
161 }
162 if (p->id <= 0)
163 {
164 trace ("Control %ld is out of range\n", p->id);
165 return FALSE;
166 }
167 if (hwnd[p->id] != 0)
168 {
169 trace ("Control %ld is used more than once\n", p->id);
170 return FALSE;
171 }
172
173 /* Create the control */
174 sprintf (ctrlname, "ctrl%4.4ld", p->id);
175 hwnd[p->id] = CreateWindowExA(p->exstyle, p->parent ? "static" : "GetNextDlgItemWindowClass", ctrlname, p->style, 10, 10, 10, 10, hwnd[p->parent], p->parent ? (HMENU) (2000 + p->id) : 0, hinst, 0);
176 if (!hwnd[p->id])
177 {
178 trace ("Failed to create control %ld\n", p->id);
179 return FALSE;
180 }
181
182 /* Check that the styles are as we specified (except the main one
183 * which is quite frequently messed up). If this keeps breaking then
184 * we could mask out the bits that don't concern us.
185 */
186 if (p->parent)
187 {
188 style = GetWindowLongA(hwnd[p->id], GWL_STYLE);
189 exstyle = GetWindowLongA(hwnd[p->id], GWL_EXSTYLE);
190 if (style != p->style || exstyle != p->exstyle)
191 {
192 trace ("Style mismatch at %ld: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle);
193 }
194 }
195 p++;
196 }
197
198 return TRUE;
199 }
200
201 /* Form the lParam of a WM_KEYDOWN message */
202 static DWORD KeyDownData (int repeat, int scancode, int extended, int wasdown)
203 {
204 return ((repeat & 0x0000FFFF) | ((scancode & 0x00FF) << 16) |
205 (extended ? 0x01000000 : 0) | (wasdown ? 0x40000000 : 0));
206 }
207
208 /* Form a WM_KEYDOWN VK_TAB message to the specified window */
209 static void FormTabMsg (MSG *pMsg, HWND hwnd)
210 {
211 pMsg->hwnd = hwnd;
212 pMsg->message = WM_KEYDOWN;
213 pMsg->wParam = VK_TAB;
214 pMsg->lParam = KeyDownData (1, 0x0F, 0, 0);
215 /* pMsg->time is not set. It shouldn't be needed */
216 /* pMsg->pt is ignored */
217 }
218
219 /* Form a WM_KEYDOWN VK_RETURN message to the specified window */
220 static void FormEnterMsg (MSG *pMsg, HWND hwnd)
221 {
222 pMsg->hwnd = hwnd;
223 pMsg->message = WM_KEYDOWN;
224 pMsg->wParam = VK_RETURN;
225 pMsg->lParam = KeyDownData (1, 0x1C, 0, 0);
226 /* pMsg->time is not set. It shouldn't be needed */
227 /* pMsg->pt is ignored */
228 }
229
230 /***********************************************************************
231 *
232 * The actual tests
233 */
234
235 typedef struct
236 {
237 int isok; /* or is it todo */
238 int test;
239 int dlg;
240 int ctl;
241 int tab;
242 int prev;
243 int res;
244 } test_record;
245
246 static int id (HWND h)
247 {
248 unsigned int i;
249 for (i = 0; i < numwnds; i++)
250 if (hwnd[i] == h)
251 return i;
252 return -1;
253 }
254
255 /* Tests
256 *
257 * Tests 1-8 test the hCtl argument of null or the dialog itself.
258 *
259 * 1. Prev Group of null is null
260 * 2. Prev Tab of null is null
261 * 3. Prev Group of hDlg in hDlg is null
262 * 4. Prev Tab of hDlg in hDlg is null
263 * 5. Next Group of null is first visible enabled child
264 * Check it skips invisible, disabled and both.
265 * 6. Next Tab of null is first visible enabled tabstop
266 * Check it skips invisible, disabled, nontabstop, and in combination.
267 * 7. Next Group of hDlg in hDlg is as of null
268 * 8. Next Tab of hDlg in hDlg is as of null
269 *
270 * Tests 9-14 test descent
271 *
272 * 9. DS_CONTROL does not result in descending the hierarchy for Tab Next
273 * 10. DS_CONTROL does not result in descending the hierarchy for Group Next
274 * 11. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Next
275 * 12. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Next
276 * 13. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Prev
277 * 14. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Prev
278 *
279 * Tests 15-24 are the basic Prev/Next Group tests
280 *
281 * 15. Next Group of a visible enabled non-group control is the next visible
282 * enabled non-group control, if there is one before the next group
283 * 16. Next Group of a visible enabled non-group control wraps around to the
284 * beginning of the group on finding a control that starts another group.
285 * Note that the group is in the middle of the dialog.
286 * 17. As 16 except note that the next group is started with a disabled
287 * visible control.
288 * 18. As 16 except note that the next group is started with an invisible
289 * enabled control.
290 * 19. Next Group wraps around the controls of the dialog
291 * 20. Next Group is the same even if the initial control is disabled.
292 * 21. Next Group is the same even if the initial control is invisible.
293 * 22. Next Group is the same even if the initial control has the group style
294 * 23. Next Group returns the initial control if there is no visible enabled
295 * control in the group. (Initial control disabled and not group style).
296 * 24. Prev version of test 16.
297 * Prev Group of a visible enabled non-group control wraps around to the
298 * beginning of the group on finding a control that starts the group.
299 * Note that the group is in the middle of the dialog.
300 *
301 * In tests 25 to 28 the control is sitting under dialogs which do not have
302 * the WS_EX_CONTROLPARENT style and so cannot be reached from the top of
303 * the dialog.
304 *
305 * 25. Next Group of an inaccessible control is as if it were accessible
306 * 26. Prev Group of an inaccessible control begins searching at the highest
307 * level ancestor that did not permit recursion down the hierarchy
308 * 27. Next Tab of an inaccessible control is as if it were accessible
309 * 28. Prev Tab of an inaccessible control begins searching at the highest
310 * level ancestor that did not permit recursion down the hierarchy.
311 *
312 * Tests 29- are the basic Tab tests
313 *
314 * 29. Next Tab of a control is the next visible enabled control with the
315 * Tabstop style (N.B. skips disabled, invisible and non-tabstop)
316 * 30. Prev Tab of a control is the previous visible enabled control with the
317 * Tabstop style (N.B. skips disabled, invisible and non-tabstop)
318 * 31. Next Tab test with at least two layers of descent and finding the
319 * result not at the first control.
320 * 32. Next Tab test with at least two layers of descent with the descent and
321 * control at the start of each level.
322 * 33. Prev Tab test with at least two layers of descent and finding the
323 * result not at the last control.
324 * 34. Prev Tab test with at least two layers of descent with the descent and
325 * control at the end of each level.
326 *
327 * 35. Passing NULL may result in the first child being the one returned.
328 * (group test)
329 * 36. Passing NULL may result in the first child being the one returned.
330 * (tab test)
331 */
332
333 static void test_GetNextDlgItem(void)
334 {
335 static test_record test [] =
336 {
337 /* isok test dlg ctl tab prev res */
338
339 { 1, 1, 6, 0, 0, 1, 0},
340 { 1, 2, 6, 0, 1, 1, 0},
341 { 1, 3, 6, 6, 0, 1, 0},
342 { 1, 4, 6, 6, 1, 1, 0},
343 { 1, 5, 6, 0, 0, 0, 66},
344 { 1, 6, 6, 0, 1, 0, 67},
345 { 1, 7, 6, 6, 0, 0, 66},
346 { 1, 8, 6, 6, 1, 0, 67},
347
348 { 1, 9, 4, 83, 1, 0, 84},
349 { 1, 10, 4, 83, 0, 0, 5},
350 { 1, 11, 5, 81, 1, 0, 67},
351 { 1, 12, 5, 81, 0, 0, 66},
352 { 1, 13, 5, 82, 1, 1, 78},
353
354 { 1, 14, 5, 82, 0, 1, 79},
355 { 1, 15, 6, 70, 0, 0, 72},
356 { 1, 16, 6, 72, 0, 0, 25},
357 { 1, 17, 6, 75, 0, 0, 26},
358 { 1, 18, 6, 77, 0, 0, 76},
359 { 1, 19, 6, 79, 0, 0, 66},
360 { 1, 20, 6, 71, 0, 0, 72},
361 { 1, 21, 6, 64, 0, 0, 66},
362
363 { 1, 22, 6, 25, 0, 0, 70},
364 { 1, 23, 6, 68, 0, 0, 68},
365 { 1, 24, 6, 25, 0, 1, 72},
366 { 1, 25, 1, 70, 0, 0, 72},
367 /*{ 0, 26, 1, 70, 0, 1, 3}, Crashes Win95*/
368 { 1, 27, 1, 70, 1, 0, 72},
369 /*{ 0, 28, 1, 70, 1, 1, 61}, Crashes Win95*/
370
371 { 1, 29, 6, 67, 1, 0, 72},
372 { 1, 30, 6, 72, 1, 1, 67},
373
374 { 1, 35, 2, 0, 0, 0, 60},
375 { 1, 36, 2, 0, 1, 0, 60},
376
377 { 0, 0, 0, 0, 0, 0, 0} /* End of test */
378 };
379 const test_record *p = test;
380
381 ok (CreateWindows (g_hinst), "Could not create test windows\n");
382
383 while (p->dlg)
384 {
385 HWND a;
386 a = (p->tab ? GetNextDlgTabItem : GetNextDlgGroupItem) (hwnd[p->dlg], hwnd[p->ctl], p->prev);
387 todo_wine_if (!p->isok)
388 ok (a == hwnd[p->res], "Test %d: %s %s item of %d in %d was %d instead of %d\n", p->test, p->prev ? "Prev" : "Next", p->tab ? "Tab" : "Group", p->ctl, p->dlg, id(a), p->res);
389 p++;
390 }
391 }
392
393 /*
394 * OnMainWindowCreate
395 */
396 static BOOL OnMainWindowCreate(HWND hwnd, LPCREATESTRUCTA lpcs)
397 {
398 g_hwndButton1 = CreateWindowA("button", "Button &1",
399 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | BS_TEXT,
400 10, 10, 80, 80, hwnd, (HMENU)100, g_hinst, 0);
401 if (!g_hwndButton1) return FALSE;
402
403 g_hwndButton2 = CreateWindowA("button", "Button &2",
404 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
405 110, 10, 80, 80, hwnd, (HMENU)200, g_hinst, 0);
406 if (!g_hwndButton2) return FALSE;
407
408 g_hwndButtonCancel = CreateWindowA("button", "Cancel",
409 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
410 210, 10, 80, 80, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
411 if (!g_hwndButtonCancel) return FALSE;
412
413 return TRUE;
414 }
415
416
417 /*
418 * OnTestDlgCreate
419 */
420
421 static BOOL OnTestDlgCreate (HWND hwnd, LPCREATESTRUCTA lpcs)
422 {
423 g_hwndTestDlgEdit = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING |
424 WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
425 "Edit", "Edit",
426 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL,
427 16,33,184,24, hwnd, (HMENU)101, g_hinst, 0);
428 if (!g_hwndTestDlgEdit) return FALSE;
429
430 g_hwndTestDlgBut1 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
431 | WS_EX_NOPARENTNOTIFY,
432 "button", "Button &1",
433 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
434 204,33,30,24, hwnd, (HMENU)201, g_hinst, 0);
435 if (!g_hwndTestDlgBut1) return FALSE;
436
437 g_hwndTestDlgBut2 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
438 | WS_EX_NOPARENTNOTIFY, "button",
439 "Button &2",
440 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
441 90,102,80,24, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
442 if (!g_hwndTestDlgBut2) return FALSE;
443
444 return TRUE;
445 }
446
447 static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam,
448 LPARAM lParam)
449 {
450 switch (uiMsg)
451 {
452 /* Add blank case statements for these to ensure we don't use them
453 * by mistake.
454 */
455 case DM_GETDEFID: break;
456 case DM_SETDEFID: break;
457
458 case WM_CREATE:
459 return (OnMainWindowCreate (hwnd,
460 (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
461 case WM_COMMAND:
462 if (wParam == IDCANCEL)
463 {
464 g_terminated = TRUE;
465 return 0;
466 }
467 break;
468 }
469
470 return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
471 }
472
473 static LRESULT CALLBACK disabled_test_proc (HWND hwnd, UINT uiMsg,
474 WPARAM wParam, LPARAM lParam)
475 {
476 switch (uiMsg)
477 {
478 case WM_INITDIALOG:
479 {
480 DWORD dw;
481 HWND hwndOk;
482
483 dw = SendMessageA(hwnd, DM_GETDEFID, 0, 0);
484 assert(DC_HASDEFID == HIWORD(dw));
485 hwndOk = GetDlgItem(hwnd, LOWORD(dw));
486 assert(hwndOk);
487 EnableWindow(hwndOk, FALSE);
488
489 PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0);
490 PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
491 break;
492 }
493 case WM_COMMAND:
494 if (wParam == IDOK)
495 {
496 g_terminated = TRUE;
497 EndDialog(hwnd, 0);
498 return 0;
499 }
500 else if (wParam == IDCANCEL)
501 {
502 EndDialog(hwnd, 0);
503 return 0;
504 }
505 break;
506 }
507
508 return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
509 }
510
511 static LRESULT CALLBACK testDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
512 LPARAM lParam)
513 {
514 switch (uiMsg)
515 {
516 /* Add blank case statements for these to ensure we don't use them
517 * by mistake.
518 */
519 case DM_GETDEFID: break;
520 case DM_SETDEFID: break;
521
522 case WM_CREATE:
523 return (OnTestDlgCreate (hwnd,
524 (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
525 case WM_COMMAND:
526 if(LOWORD(wParam) == 300) g_bReceivedCommand = TRUE;
527 }
528
529 return DefDlgProcA (hwnd, uiMsg, wParam, lParam);
530 }
531
532 static LRESULT CALLBACK test_control_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
533 {
534 switch(msg)
535 {
536 case WM_CREATE:
537 {
538 static const short sample[] = { 10,1,2,3,4,5 };
539 CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
540 short *data = cs->lpCreateParams;
541 ok(!memcmp(data, sample, sizeof(sample)), "data mismatch: %d,%d,%d,%d,%d\n", data[0], data[1], data[2], data[3], data[4]);
542 }
543 return 0;
544
545 default:
546 break;
547 }
548
549 return DefWindowProcA(hwnd, msg, wparam, lparam);
550 }
551
552 static BOOL RegisterWindowClasses (void)
553 {
554 WNDCLASSA cls;
555
556 cls.style = 0;
557 cls.lpfnWndProc = DefWindowProcA;
558 cls.cbClsExtra = 0;
559 cls.cbWndExtra = 0;
560 cls.hInstance = g_hinst;
561 cls.hIcon = NULL;
562 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
563 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
564 cls.lpszMenuName = NULL;
565 cls.lpszClassName = "GetNextDlgItemWindowClass";
566
567 if (!RegisterClassA (&cls)) return FALSE;
568
569 cls.lpfnWndProc = main_window_procA;
570 cls.lpszClassName = "IsDialogMessageWindowClass";
571 if (!RegisterClassA (&cls)) return FALSE;
572
573 cls.lpfnWndProc = test_control_procA;
574 cls.lpszClassName = "TESTCONTROL";
575 if (!RegisterClassA (&cls)) return FALSE;
576
577 GetClassInfoA(0, "#32770", &cls);
578 cls.lpfnWndProc = testDlgWinProc;
579 cls.lpszClassName = "WM_NEXTDLGCTLWndClass";
580 if (!RegisterClassA (&cls)) return FALSE;
581
582 return TRUE;
583 }
584
585 static void test_WM_NEXTDLGCTL(void)
586 {
587 HWND child1, child2, child3;
588 MSG msg;
589 DWORD dwVal;
590
591 g_hwndTestDlg = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
592 | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,
593 "WM_NEXTDLGCTLWndClass",
594 "WM_NEXTDLGCTL Message test window",
595 WS_POPUPWINDOW | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_OVERLAPPED |
596 WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK | DS_SETFONT | DS_MODALFRAME,
597 0, 0, 235, 135,
598 NULL, NULL, g_hinst, 0);
599
600 assert (g_hwndTestDlg);
601 assert (g_hwndTestDlgBut1);
602 assert (g_hwndTestDlgBut2);
603 assert (g_hwndTestDlgEdit);
604
605 /*
606 * Test message DM_SETDEFID
607 */
608
609 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, IDCANCEL, 0 );
610 DefDlgProcA( g_hwndTestDlgBut1, BM_SETSTYLE, BS_DEFPUSHBUTTON, FALSE );
611 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
612
613 ok ( IDCANCEL == (LOWORD(dwVal)), "Did not set default ID\n" );
614
615 /*
616 * Check whether message WM_NEXTDLGCTL is changing the focus to next control and if
617 * the destination control is a button, style of the button should be changed to
618 * BS_DEFPUSHBUTTON with out making it default.
619 */
620
621 /*
622 * Keep the focus on Edit control.
623 */
624
625 if ( SetFocus( g_hwndTestDlgEdit ) )
626 {
627 ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n");
628
629 /*
630 * Test message WM_NEXTDLGCTL
631 */
632 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
633 ok ((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n");
634
635 /*
636 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
637 */
638 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
639 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
640
641 /*
642 * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
643 * the style of default button changed to BS_PUSHBUTTON.
644 */
645 if ( IDCANCEL == (LOWORD(dwVal)) )
646 {
647 ok ( ((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
648 "Button1 style not set to BS_DEFPUSHBUTTON\n" );
649
650 ok ( !((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
651 "Button2's style not changed to BS_PUSHBUTTON\n" );
652 }
653
654 /*
655 * Move focus to Button2 using "WM_NEXTDLGCTL"
656 */
657 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
658 ok ((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n");
659
660 /*
661 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
662 */
663 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
664 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
665
666 /*
667 * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
668 * the style of button which lost the focus changed to BS_PUSHBUTTON.
669 */
670 if ( IDCANCEL == (LOWORD(dwVal)) )
671 {
672 ok ( ((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
673 "Button2 style not set to BS_DEFPUSHBUTTON\n" );
674
675 ok ( !((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
676 "Button1's style not changed to BS_PUSHBUTTON\n" );
677 }
678
679 /*
680 * Move focus to Edit control using "WM_NEXTDLGCTL"
681 */
682 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
683 ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n");
684
685 /*
686 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
687 */
688 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
689 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
690 }
691
692 /* test nested default buttons */
693
694 child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 50, 50,
695 g_hwndTestDlg, (HMENU)100, g_hinst, NULL);
696 ok(child1 != NULL, "failed to create first child\n");
697 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 60, 60, 30, 30,
698 g_hwndTestDlg, (HMENU)200, g_hinst, NULL);
699 ok(child2 != NULL, "failed to create second child\n");
700 /* create nested child */
701 child3 = CreateWindowA("button", "child3", WS_VISIBLE|WS_CHILD, 10, 10, 10, 10,
702 child1, (HMENU)300, g_hinst, NULL);
703 ok(child3 != NULL, "failed to create subchild\n");
704
705 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 200, 0);
706 dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
707 ok(LOWORD(dwVal) == 200, "expected 200, got %x\n", dwVal);
708
709 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 300, 0);
710 dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
711 ok(LOWORD(dwVal) == 300, "expected 300, got %x\n", dwVal);
712 ok(SendMessageW( child3, WM_GETDLGCODE, 0, 0) != DLGC_DEFPUSHBUTTON,
713 "expected child3 not to be marked as DLGC_DEFPUSHBUTTON\n");
714
715 g_bReceivedCommand = FALSE;
716 FormEnterMsg (&msg, child3);
717 ok(IsDialogMessageA(g_hwndTestDlg, &msg), "Did not handle the ENTER\n");
718 ok(g_bReceivedCommand, "Did not trigger the default Button action\n");
719
720 DestroyWindow(child3);
721 DestroyWindow(child2);
722 DestroyWindow(child1);
723 DestroyWindow(g_hwndTestDlg);
724 }
725
726 static LRESULT CALLBACK hook_proc(INT code, WPARAM wParam, LPARAM lParam)
727 {
728 ok(0, "unexpected hook called, code %d\n", code);
729 return CallNextHookEx(NULL, code, wParam, lParam);
730 }
731
732 static BOOL g_MSGF_DIALOGBOX;
733 static LRESULT CALLBACK hook_proc2(INT code, WPARAM wParam, LPARAM lParam)
734 {
735 ok(code == MSGF_DIALOGBOX, "unexpected hook called, code %d\n", code);
736 g_MSGF_DIALOGBOX = code == MSGF_DIALOGBOX;
737 return CallNextHookEx(NULL, code, wParam, lParam);
738 }
739
740 static void test_IsDialogMessage(void)
741 {
742 HHOOK hook;
743 MSG msg;
744
745 g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass",
746 WS_OVERLAPPEDWINDOW,
747 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
748 NULL, NULL, g_hinst, 0);
749
750 assert (g_hwndMain);
751 assert (g_hwndButton1);
752 assert (g_hwndButtonCancel);
753
754 if (0)
755 {
756 /* crashes on Windows */
757 IsDialogMessageA(NULL, NULL);
758 IsDialogMessageA(g_hwndMain, NULL);
759 }
760
761 /* The focus should initially be nowhere. The first TAB should take it
762 * to the first button. The second TAB should take it to the Cancel
763 * button.
764 */
765
766 /* valid window, invalid message window */
767 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc2, NULL, GetCurrentThreadId());
768 FormTabMsg (&msg, (HWND)0xbeefbeef);
769 ok (!IsDialogMessageA(g_hwndMain, &msg), "expected failure\n");
770 ok(g_MSGF_DIALOGBOX, "hook wasn't called\n");
771 g_MSGF_DIALOGBOX = FALSE;
772 UnhookWindowsHookEx(hook);
773
774 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
775 FormTabMsg (&msg, g_hwndMain);
776
777 ok (!IsDialogMessageA(NULL, &msg), "expected failure\n");
778 ok (!IsDialogMessageA((HWND)0xbeefbeef, &msg), "expected failure\n");
779
780 UnhookWindowsHookEx(hook);
781
782 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle first TAB\n");
783 ok ((GetFocus() == g_hwndButton1), "Focus did not move to first button\n");
784 FormTabMsg (&msg, g_hwndButton1);
785 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle second TAB\n");
786 ok ((GetFocus() == g_hwndButtonCancel),
787 "Focus did not move to cancel button\n");
788 FormEnterMsg (&msg, g_hwndButtonCancel);
789 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
790 ok (g_terminated, "ENTER did not terminate\n");
791
792 /* matching but invalid window handles, NULL */
793 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
794
795 FormTabMsg (&msg, NULL);
796 ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
797
798 /* matching but invalid window handles, not NULL */
799 FormTabMsg (&msg, (HWND)0xbeefbeef);
800 ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
801
802 UnhookWindowsHookEx(hook);
803 }
804
805
806 static INT_PTR CALLBACK delayFocusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
807 LPARAM lParam)
808 {
809 switch (uiMsg)
810 {
811 case WM_INITDIALOG:
812 g_hwndMain = hDlg;
813 g_hwndInitialFocusGroupBox = GetDlgItem(hDlg,100);
814 g_hwndButton1 = GetDlgItem(hDlg,200);
815 g_hwndButton2 = GetDlgItem(hDlg,201);
816 g_hwndButtonCancel = GetDlgItem(hDlg,IDCANCEL);
817 g_styleInitialFocusT1 = GetWindowLongA(g_hwndInitialFocusGroupBox, GWL_STYLE);
818
819 /* Initially check the second radio button */
820 SendMessageA(g_hwndButton1, BM_SETCHECK, BST_UNCHECKED, 0);
821 SendMessageA(g_hwndButton2, BM_SETCHECK, BST_CHECKED , 0);
822 /* Continue testing after dialog initialization */
823 PostMessageA(hDlg, WM_USER, 0, 0);
824 return g_bInitialFocusInitDlgResult;
825
826 case WM_COMMAND:
827 if (LOWORD(wParam) == IDCANCEL)
828 {
829 EndDialog(hDlg, LOWORD(wParam));
830 return TRUE;
831 }
832 return FALSE;
833
834 case WM_USER:
835 g_styleInitialFocusT2 = GetWindowLongA(hDlg, GWL_STYLE);
836 g_hwndInitialFocusT1 = GetFocus();
837 SetFocus(hDlg);
838 g_hwndInitialFocusT2 = GetFocus();
839 PostMessageA(hDlg, WM_COMMAND, IDCANCEL, 0);
840 return TRUE;
841 }
842
843 return FALSE;
844 }
845
846 static INT_PTR CALLBACK focusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
847 LPARAM lParam)
848 {
849 switch (uiMsg)
850 {
851 case WM_INITDIALOG:
852 SetWindowTextA(GetDlgItem(hDlg, 200), "new caption");
853 return TRUE;
854
855 case WM_COMMAND:
856 if (LOWORD(wParam) == 200)
857 {
858 if (HIWORD(wParam) == EN_SETFOCUS)
859 g_hwndInitialFocusT1 = (HWND)lParam;
860 }
861 return FALSE;
862 }
863
864 return FALSE;
865 }
866
867 /* Helper for InitialFocusTest */
868 static const char * GetHwndString(HWND hw)
869 {
870 if (hw == NULL)
871 return "a null handle";
872 if (hw == g_hwndMain)
873 return "the dialog handle";
874 if (hw == g_hwndInitialFocusGroupBox)
875 return "the group box control";
876 if (hw == g_hwndButton1)
877 return "the first button";
878 if (hw == g_hwndButton2)
879 return "the second button";
880 if (hw == g_hwndButtonCancel)
881 return "the cancel button";
882
883 return "unknown handle";
884 }
885
886 static void test_focus(void)
887 {
888 /* Test 1:
889 * This test intentionally returns FALSE in response to WM_INITDIALOG
890 * without setting focus to a control. This is what MFC's CFormView does.
891 *
892 * Since the WM_INITDIALOG handler returns FALSE without setting the focus,
893 * the focus should initially be NULL. Later, when we manually set focus to
894 * the dialog, the default handler should set focus to the first control that
895 * is "visible, not disabled, and has the WS_TABSTOP style" (MSDN). Because the
896 * second radio button has been checked, it should be the first control
897 * that meets these criteria and should receive the focus.
898 */
899
900 g_bInitialFocusInitDlgResult = FALSE;
901 g_hwndInitialFocusT1 = (HWND) -1;
902 g_hwndInitialFocusT2 = (HWND) -1;
903 g_styleInitialFocusT1 = -1;
904 g_styleInitialFocusT2 = -1;
905
906 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
907
908 ok (((g_styleInitialFocusT1 & WS_TABSTOP) == 0),
909 "Error in wrc - Detected WS_TABSTOP as default style for GROUPBOX\n");
910
911 ok (((g_styleInitialFocusT2 & WS_VISIBLE) == 0),
912 "Modal dialogs should not be shown until the message queue first goes empty\n");
913
914 ok ((g_hwndInitialFocusT1 == NULL),
915 "Error in initial focus when WM_INITDIALOG returned FALSE: "
916 "Expected NULL focus, got %s (%p).\n",
917 GetHwndString(g_hwndInitialFocusT1), g_hwndInitialFocusT1);
918
919 ok ((g_hwndInitialFocusT2 == g_hwndButton2),
920 "Error after first SetFocus() when WM_INITDIALOG returned FALSE: "
921 "Expected the second button (%p), got %s (%p).\n",
922 g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
923 g_hwndInitialFocusT2);
924
925 /* Test 2:
926 * This is the same as above, except WM_INITDIALOG is made to return TRUE.
927 * This should cause the focus to go to the second radio button right away
928 * and stay there (until the user indicates otherwise).
929 */
930
931 g_bInitialFocusInitDlgResult = TRUE;
932 g_hwndInitialFocusT1 = (HWND) -1;
933 g_hwndInitialFocusT2 = (HWND) -1;
934 g_styleInitialFocusT1 = -1;
935 g_styleInitialFocusT2 = -1;
936
937 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
938
939 ok ((g_hwndInitialFocusT1 == g_hwndButton2),
940 "Error in initial focus when WM_INITDIALOG returned TRUE: "
941 "Expected the second button (%p), got %s (%p).\n",
942 g_hwndButton2, GetHwndString(g_hwndInitialFocusT1),
943 g_hwndInitialFocusT1);
944
945 ok ((g_hwndInitialFocusT2 == g_hwndButton2),
946 "Error after first SetFocus() when WM_INITDIALOG returned TRUE: "
947 "Expected the second button (%p), got %s (%p).\n",
948 g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
949 g_hwndInitialFocusT2);
950
951 /* Test 3:
952 * If the dialog has DS_CONTROL and it's not visible then we shouldn't change focus */
953 {
954 HWND hDlg;
955 HRSRC hResource;
956 HANDLE hTemplate;
957 DLGTEMPLATE* pTemplate;
958 HWND hTextbox;
959 DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
960
961 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPCSTR)RT_DIALOG);
962 hTemplate = LoadResource(g_hinst, hResource);
963 pTemplate = LockResource(hTemplate);
964
965 g_hwndInitialFocusT1 = 0;
966 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
967 ok (hDlg != 0, "Failed to create test dialog.\n");
968
969 ok ((g_hwndInitialFocusT1 == 0),
970 "Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
971
972 /* Also make sure that WM_SETFOCUS selects the textbox's text */
973 hTextbox = GetDlgItem(hDlg, 200);
974 SendMessageA(hTextbox, WM_SETTEXT, 0, (LPARAM)"Hello world");
975
976 SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
977 SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
978 ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd);
979
980 /* but WM_ACTIVATE does not */
981 SendMessageA(hTextbox, EM_SETSEL, 0, 0);
982 SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
983 SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
984 ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd);
985
986 DestroyWindow(hDlg);
987 }
988
989 /* Test 4:
990 * If the dialog has no tab-accessible controls, set focus to first control */
991 {
992 HWND hDlg;
993 HRSRC hResource;
994 HANDLE hTemplate;
995 DLGTEMPLATE* pTemplate;
996 HWND hLabel;
997
998 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_2", (LPCSTR)RT_DIALOG);
999 hTemplate = LoadResource(g_hinst, hResource);
1000 pTemplate = LockResource(hTemplate);
1001
1002 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1003 ok(hDlg != 0, "Failed to create test dialog.\n");
1004 hLabel = GetDlgItem(hDlg, 200);
1005
1006 ok(GetFocus() == hLabel, "Focus not set to label, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1007
1008 DestroyWindow(hDlg);
1009
1010 /* Also check focus after WM_ACTIVATE and WM_SETFOCUS */
1011 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, NULL, 0);
1012 ok(hDlg != 0, "Failed to create test dialog.\n");
1013 hLabel = GetDlgItem(hDlg, 200);
1014
1015 SetFocus(NULL);
1016 SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
1017 ok(GetFocus() == NULL, "Focus set on WM_ACTIVATE, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1018
1019 SetFocus(NULL);
1020 SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
1021 ok(GetFocus() == hLabel, "Focus not set to label on WM_SETFOCUS, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1022
1023 DestroyWindow(hDlg);
1024 }
1025
1026 /* Test 5:
1027 * Select textbox's text on creation */
1028 {
1029 HWND hDlg;
1030 HRSRC hResource;
1031 HANDLE hTemplate;
1032 DLGTEMPLATE* pTemplate;
1033 HWND edit;
1034 DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
1035
1036 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_3", (LPCSTR)RT_DIALOG);
1037 hTemplate = LoadResource(g_hinst, hResource);
1038 pTemplate = LockResource(hTemplate);
1039
1040 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1041 ok(hDlg != 0, "Failed to create test dialog.\n");
1042 edit = GetDlgItem(hDlg, 200);
1043
1044 ok(GetFocus() == edit, "Focus not set to edit, focus=%p, dialog=%p, edit=%p\n",
1045 GetFocus(), hDlg, edit);
1046 SendMessageA(edit, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
1047 ok(selectionStart == 0 && selectionEnd == 11,
1048 "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n",
1049 selectionStart, selectionEnd);
1050
1051 DestroyWindow(hDlg);
1052 }
1053 }
1054
1055 static void test_GetDlgItemText(void)
1056 {
1057 char string[64];
1058 BOOL ret;
1059
1060 strcpy(string, "Overwrite Me");
1061 ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0]));
1062 ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n");
1063
1064 ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")),
1065 "string retrieved using GetDlgItemText should have been NULL terminated\n");
1066 }
1067
1068 static void test_GetDlgItem(void)
1069 {
1070 HWND hwnd, child1, child2, hwnd2;
1071 BOOL ret;
1072
1073 hwnd = CreateWindowA("button", "parent", WS_VISIBLE, 0, 0, 100, 100, NULL, 0, g_hinst, NULL);
1074 ok(hwnd != NULL, "failed to created window\n");
1075
1076 /* created with the same ID */
1077 child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1078 ok(child1 != NULL, "failed to create first child\n");
1079 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1080 ok(child2 != NULL, "failed to create second child\n");
1081
1082 hwnd2 = GetDlgItem(hwnd, 0);
1083 ok(hwnd2 == child1, "expected first child, got %p\n", hwnd2);
1084
1085 hwnd2 = GetTopWindow(hwnd);
1086 ok(hwnd2 == child1, "expected first child to be top, got %p\n", hwnd2);
1087
1088 ret = SetWindowPos(child1, child2, 0, 0, 0, 0, SWP_NOMOVE);
1089 ok(ret, "got %d\n", ret);
1090 hwnd2 = GetTopWindow(hwnd);
1091 ok(hwnd2 == child2, "expected second child to be top, got %p\n", hwnd2);
1092
1093 /* top window from child list is picked */
1094 hwnd2 = GetDlgItem(hwnd, 0);
1095 ok(hwnd2 == child2, "expected second child, got %p\n", hwnd2);
1096
1097 /* Now test how GetDlgItem searches */
1098 DestroyWindow(child2);
1099 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, child1, 0, g_hinst, NULL);
1100 ok(child2 != NULL, "failed to create second child\n");
1101
1102 /* give child2 an ID */
1103 SetWindowLongA(child2, GWLP_ID, 100);
1104
1105 hwnd2 = GetDlgItem(hwnd, 100);
1106 ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1107
1108 /* make the ID of child2 public with a WS_EX_CONTROLPARENT parent */
1109 SetWindowLongA(child1, GWL_EXSTYLE, WS_EX_CONTROLPARENT);
1110
1111 hwnd2 = GetDlgItem(hwnd, 100);
1112 ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1113
1114 DestroyWindow(child1);
1115 DestroyWindow(child2);
1116 DestroyWindow(hwnd);
1117 }
1118
1119 static INT_PTR CALLBACK DestroyDlgWinProc (HWND hDlg, UINT uiMsg,
1120 WPARAM wParam, LPARAM lParam)
1121 {
1122 if (uiMsg == WM_INITDIALOG)
1123 {
1124 DestroyWindow(hDlg);
1125 return TRUE;
1126 }
1127 return FALSE;
1128 }
1129
1130 static INT_PTR CALLBACK DestroyOnCloseDlgWinProc (HWND hDlg, UINT uiMsg,
1131 WPARAM wParam, LPARAM lParam)
1132 {
1133 switch (uiMsg)
1134 {
1135 case WM_INITDIALOG:
1136 PostMessageA(hDlg, WM_CLOSE, 0, 0);
1137 return TRUE;
1138 case WM_CLOSE:
1139 DestroyWindow(hDlg);
1140 return TRUE;
1141 case WM_DESTROY:
1142 PostQuitMessage(0);
1143 return TRUE;
1144 }
1145 return FALSE;
1146 }
1147
1148 static INT_PTR CALLBACK TestInitDialogHandleProc (HWND hDlg, UINT uiMsg,
1149 WPARAM wParam, LPARAM lParam)
1150 {
1151 if (uiMsg == WM_INITDIALOG)
1152 {
1153 HWND expected = GetNextDlgTabItem(hDlg, NULL, FALSE);
1154 ok(expected == (HWND)wParam,
1155 "Expected wParam to be the handle to the first tabstop control (%p), got %p\n",
1156 expected, (HWND)wParam);
1157
1158 EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1159 return TRUE;
1160 }
1161 return FALSE;
1162 }
1163
1164 static INT_PTR CALLBACK TestDefButtonDlgProc (HWND hDlg, UINT uiMsg,
1165 WPARAM wParam, LPARAM lParam)
1166 {
1167 switch (uiMsg)
1168 {
1169 case WM_INITDIALOG:
1170 EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1171 return TRUE;
1172 }
1173 return FALSE;
1174 }
1175
1176 static INT_PTR CALLBACK TestReturnKeyDlgProc (HWND hDlg, UINT uiMsg,
1177 WPARAM wParam, LPARAM lParam)
1178 {
1179 static int received_idok;
1180
1181 switch (uiMsg)
1182 {
1183 case WM_INITDIALOG:
1184 {
1185 MSG msg = {hDlg, WM_KEYDOWN, VK_RETURN, 0x011c0001};
1186
1187 received_idok = -1;
1188 IsDialogMessageA(hDlg, &msg);
1189 ok(received_idok == 0xdead, "WM_COMMAND/0xdead not received\n");
1190
1191 received_idok = -2;
1192 IsDialogMessageA(hDlg, &msg);
1193 ok(received_idok == IDOK, "WM_COMMAND/IDOK not received\n");
1194
1195 EndDialog(hDlg, 0);
1196 return TRUE;
1197 }
1198
1199 case DM_GETDEFID:
1200 if (received_idok == -1)
1201 {
1202 HWND hwnd = GetDlgItem(hDlg, 0xdead);
1203 ok(!hwnd, "dialog item with ID 0xdead should not exist\n");
1204 SetWindowLongA(hDlg, DWLP_MSGRESULT, MAKELRESULT(0xdead, DC_HASDEFID));
1205 return TRUE;
1206 }
1207 return FALSE;
1208
1209 case WM_COMMAND:
1210 received_idok = wParam;
1211 return TRUE;
1212 }
1213 return FALSE;
1214 }
1215
1216 static INT_PTR CALLBACK TestControlStyleDlgProc(HWND hdlg, UINT msg,
1217 WPARAM wparam, LPARAM lparam)
1218 {
1219 HWND control;
1220 DWORD style, exstyle;
1221 char buf[256];
1222
1223 switch (msg)
1224 {
1225 case WM_INITDIALOG:
1226 control = GetDlgItem(hdlg, 7);
1227 ok(control != 0, "dialog control with id 7 not found\n");
1228 style = GetWindowLongA(control, GWL_STYLE);
1229 ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1230 exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1231 ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT|WS_EX_CLIENTEDGE, got %#x\n", exstyle);
1232 buf[0] = 0;
1233 GetWindowTextA(control, buf, sizeof(buf));
1234 ok(strcmp(buf, "bump7") == 0, "expected bump7, got %s\n", buf);
1235
1236 control = GetDlgItem(hdlg, 8);
1237 ok(control != 0, "dialog control with id 8 not found\n");
1238 style = GetWindowLongA(control, GWL_STYLE);
1239 ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1240 exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1241 ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT, got %#x\n", exstyle);
1242 buf[0] = 0;
1243 GetWindowTextA(control, buf, sizeof(buf));
1244 ok(strcmp(buf, "bump8") == 0, "expected bump8, got %s\n", buf);
1245
1246 EndDialog(hdlg, -7);
1247 return TRUE;
1248 }
1249 return FALSE;
1250 }
1251
1252 static void test_DialogBoxParamA(void)
1253 {
1254 INT_PTR ret;
1255 HWND hwnd_invalid = (HWND)0x4444;
1256
1257 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DLG_CHILD_POPUP", 0, TestControlStyleDlgProc, 0);
1258 ok(ret == -7, "expected -7, got %ld\n", ret);
1259
1260 SetLastError(0xdeadbeef);
1261 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0);
1262 ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %ld, expected 0\n", ret);
1263 ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1264 broken(GetLastError() == 0xdeadbeef),
1265 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1266
1267 /* Test a dialog which destroys itself on WM_INITDIALOG. */
1268 SetLastError(0xdeadbeef);
1269 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyDlgWinProc, 0);
1270 ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1271 ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1272 GetLastError() == ERROR_SUCCESS ||
1273 broken(GetLastError() == 0xdeadbeef),
1274 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1275
1276 /* Test a dialog which destroys itself on WM_CLOSE. */
1277 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyOnCloseDlgWinProc, 0);
1278 ok(0 == ret, "DialogBoxParamA returned %ld, expected 0\n", ret);
1279
1280 SetLastError(0xdeadbeef);
1281 ret = DialogBoxParamA(GetModuleHandleA(NULL), "RESOURCE_INVALID" , 0, 0, 0);
1282 ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1283 ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() ||
1284 broken(GetLastError() == 0xdeadbeef),
1285 "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError());
1286
1287 SetLastError(0xdeadbeef);
1288 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DIALOG_INVALID_CLASS", 0, DestroyDlgWinProc, 0);
1289 ok(ret == -1, "DialogBoxParamA returned %ld, expected -1\n", ret);
1290 ok(GetLastError() == 0, "got %d\n", GetLastError());
1291
1292 SetLastError(0xdeadbeef);
1293 ret = DefDlgProcA(0, WM_ERASEBKGND, 0, 0);
1294 ok(ret == 0, "DefDlgProcA returned %ld, expected 0\n", ret);
1295 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1296 broken(GetLastError() == 0xdeadbeef),
1297 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError());
1298
1299 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestInitDialogHandleProc, 0);
1300 ok(ret == IDOK, "Expected IDOK\n");
1301
1302 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestDefButtonDlgProc, 0);
1303 ok(ret == IDOK, "Expected IDOK\n");
1304
1305 DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestReturnKeyDlgProc, 0);
1306 }
1307
1308 static void test_DisabledDialogTest(void)
1309 {
1310 g_terminated = FALSE;
1311 DialogBoxParamA(g_hinst, "IDD_DIALOG", NULL, disabled_test_proc, 0);
1312 ok(FALSE == g_terminated, "dialog with disabled ok button has been terminated\n");
1313 }
1314
1315 static INT_PTR CALLBACK messageBoxFontDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
1316 LPARAM lParam)
1317 {
1318 if (uiMsg == WM_INITDIALOG) {
1319 SetFocus(hDlg);
1320 return 1;
1321 }
1322
1323 return 0;
1324 }
1325
1326 static void test_MessageBoxFontTest(void)
1327 {
1328 /* This dialog template defines a dialog template which got 0x7fff as its
1329 * font size and omits the other font members. On WinNT, passing such a
1330 * dialog template to CreateDialogIndirectParamW will result in a dialog
1331 * being created which uses the message box font. We test that here.
1332 */
1333
1334 static unsigned char dlgTemplate[] =
1335 {
1336 /* Dialog header */
1337 0x01,0x00, /* Version */
1338 0xff,0xff, /* Extended template marker */
1339 0x00,0x00,0x00,0x00, /* Context Help ID */
1340 0x00,0x00,0x00,0x00, /* Extended style */
1341 0xc0,0x00,0xc8,0x80, /* Style (WS_SYSMENU|WS_CAPTION|WS_POPUP|DS_SETFONT|DS_MODALFRAME) */
1342 0x01,0x00, /* Control count */
1343 0x00,0x00, /* X */
1344 0x00,0x00, /* Y */
1345 0x80,0x00, /* Width */
1346 0x80,0x00, /* Height */
1347 0x00,0x00, /* Menu name */
1348 0x00,0x00, /* Class name */
1349 'T',0x00,'e',0x00, /* Caption (unicode) */
1350 's',0x00,'t',0x00,
1351 0x00,0x00,
1352 0xff,0x7f, /* Font height (0x7fff = message box font) */
1353
1354 /* Control #1 */
1355 0x00,0x00, /* Align to DWORD (header is 42 bytes) */
1356 0x00,0x00,0x00,0x00, /* Context Help ID */
1357 0x00,0x00,0x00,0x00, /* Extended style */
1358 0x00,0x00,0x00,0x50, /* Style (WS_CHILD|WS_VISIBLE) */
1359 0x00,0x00, /* X */
1360 0x00,0x00, /* Y */
1361 0x80,0x00, /* Width */
1362 0x80,0x00, /* Height */
1363 0x00,0x01,0x00,0x00, /* Control ID (256) */
1364 0xff,0xff,0x82,0x00, /* Class (Static) */
1365 'W',0x00,'I',0x00, /* Caption (unicode) */
1366 'N',0x00,'E',0x00,
1367 ' ',0x00,'d',0x00,
1368 'i',0x00,'a',0x00,
1369 'l',0x00,'o',0x00,
1370 'g',0x00,' ',0x00,
1371 't',0x00,'e',0x00,
1372 's',0x00,'t',0x00,
1373 '.',0x00,0x00,0x00,
1374 0x00,0x00, /* Size of extended data */
1375
1376 0x00,0x00 /* Align to DWORD */
1377 };
1378
1379 HWND hDlg;
1380 HFONT hFont;
1381 LOGFONTW lfStaticFont;
1382 NONCLIENTMETRICSW ncMetrics;
1383
1384 /* Check if the dialog can be created from the template. On Win9x, this should fail
1385 * because we are calling the W function which is not implemented, but that's what
1386 * we want, because passing such a template to CreateDialogIndirectParamA would crash
1387 * anyway.
1388 */
1389 hDlg = CreateDialogIndirectParamW(g_hinst, (LPCDLGTEMPLATEW)dlgTemplate, NULL, messageBoxFontDlgWinProc, 0);
1390 if (!hDlg)
1391 {
1392 win_skip("dialog wasn't created\n");
1393 return;
1394 }
1395
1396 hFont = (HFONT) SendDlgItemMessageW(hDlg, 256, WM_GETFONT, 0, 0);
1397 if (!hFont)
1398 {
1399 skip("dialog uses system font\n");
1400 DestroyWindow(hDlg);
1401 return;
1402 }
1403 GetObjectW(hFont, sizeof(LOGFONTW), &lfStaticFont);
1404
1405 ncMetrics.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth);
1406 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0);
1407 ok( !memcmp(&lfStaticFont, &ncMetrics.lfMessageFont, FIELD_OFFSET(LOGFONTW, lfFaceName)) &&
1408 !lstrcmpW(lfStaticFont.lfFaceName, ncMetrics.lfMessageFont.lfFaceName),
1409 "dialog doesn't use message box font\n");
1410 DestroyWindow(hDlg);
1411 }
1412
1413 static void test_SaveRestoreFocus(void)
1414 {
1415 HWND hDlg;
1416 HRSRC hResource;
1417 HANDLE hTemplate;
1418 DLGTEMPLATE* pTemplate;
1419 LONG_PTR foundId;
1420 HWND foundHwnd;
1421
1422 /* create the dialog */
1423 hResource = FindResourceA(g_hinst, "MULTI_EDIT_DIALOG", (LPCSTR)RT_DIALOG);
1424 hTemplate = LoadResource(g_hinst, hResource);
1425 pTemplate = LockResource(hTemplate);
1426
1427 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, messageBoxFontDlgWinProc, 0);
1428 ok (hDlg != 0, "Failed to create test dialog.\n");
1429
1430 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1431 ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %ld\n", 1000, foundId);
1432
1433 SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
1434 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1435 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1436 ok (foundId == 1001, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
1437 SetFocus(GetNextDlgTabItem(hDlg, NULL, FALSE));
1438
1439 /* de- then reactivate the dialog */
1440 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1441 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1442
1443 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1444 ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1000, foundId);
1445
1446 /* select the next tabbable item */
1447 SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
1448
1449 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1450 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1451
1452 /* de- then reactivate the dialog */
1453 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1454 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1455
1456 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1457 ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
1458
1459 /* set focus to the dialog */
1460 SetFocus(hDlg);
1461
1462 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1463 ok (foundId == 1000, "First edit box should have gained focus on dialog focus. Expected: %d, Found: %ld\n", 1000, foundId);
1464
1465 /* select second tabbable item */
1466 SetFocus(GetNextDlgTabItem(hDlg, GetNextDlgTabItem(hDlg, NULL, FALSE), FALSE));
1467
1468 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1469 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1470
1471 /* send WM_ACTIVATE message to already active dialog */
1472 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1473
1474 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1475 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1476
1477 /* disable the 2nd box */
1478 EnableWindow(GetFocus(), FALSE);
1479
1480 foundHwnd = GetFocus();
1481 ok (foundHwnd == NULL, "Second edit box should have lost focus after being disabled. Expected: %p, Found: %p\n", NULL, foundHwnd);
1482
1483 /* de- then reactivate the dialog */
1484 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1485 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1486
1487 foundHwnd = GetFocus();
1488 ok (foundHwnd == NULL, "No controls should have gained focus after dialog reactivation. Expected: %p, Found: %p\n", NULL, foundHwnd);
1489
1490 /* clean up */
1491 DestroyWindow(hDlg);
1492 }
1493
1494 static INT_PTR CALLBACK timer_message_dlg_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
1495 {
1496 static int count;
1497 BOOL visible;
1498
1499 switch (msg)
1500 {
1501 case WM_INITDIALOG:
1502 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1503 ok(!visible, "Dialog should not be visible.\n");
1504 SetTimer(wnd, 1, 100, NULL);
1505 Sleep(200);
1506 return FALSE;
1507
1508 case WM_COMMAND:
1509 if (LOWORD(wparam) != IDCANCEL) return FALSE;
1510 EndDialog(wnd, LOWORD(wparam));
1511 return TRUE;
1512
1513 case WM_TIMER:
1514 if (wparam != 1) return FALSE;
1515 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1516 if (!count++)
1517 {
1518 ok(!visible, "Dialog should not be visible.\n");
1519 PostMessageA(wnd, WM_USER, 0, 0);
1520 }
1521 else
1522 {
1523 ok(visible, "Dialog should be visible.\n");
1524 PostMessageA(wnd, WM_COMMAND, IDCANCEL, 0);
1525 }
1526 return TRUE;
1527
1528 case WM_USER:
1529 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1530 ok(visible, "Dialog should be visible.\n");
1531 return TRUE;
1532
1533 default:
1534 return FALSE;
1535 }
1536 }
1537
1538 static void test_timer_message(void)
1539 {
1540 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc);
1541 }
1542
1543 static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam)
1544 {
1545 if (code == HCBT_ACTIVATE)
1546 {
1547 HWND msgbox = (HWND)wParam, msghwnd;
1548 char text[64];
1549
1550 if (msgbox)
1551 {
1552 text[0] = 0;
1553 GetWindowTextA(msgbox, text, sizeof(text));
1554 ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text);
1555
1556 msghwnd = GetDlgItem(msgbox, 0xffff);
1557 ok(msghwnd != NULL, "Expected static control\n");
1558
1559 text[0] = 0;
1560 GetWindowTextA(msghwnd, text, sizeof(text));
1561 ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text);
1562
1563 SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0);
1564 SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0);
1565 }
1566 }
1567
1568 return CallNextHookEx(NULL, code, wParam, lParam);
1569 }
1570
1571 struct create_window_params
1572 {
1573 BOOL owner;
1574 char caption[64];
1575 DWORD style;
1576 };
1577
1578 static DWORD WINAPI create_window_thread(void *param)
1579 {
1580 struct create_window_params *p = param;
1581 HWND owner = 0;
1582
1583 if (p->owner)
1584 {
1585 owner = CreateWindowExA(0, "Static", NULL, WS_POPUP, 10, 10, 10, 10, 0, 0, 0, NULL);
1586 ok(owner != 0, "failed to create owner window\n");
1587 }
1588
1589 MessageBoxA(owner, NULL, p->caption, p->style);
1590
1591 if (owner) DestroyWindow(owner);
1592
1593 return 0;
1594 }
1595
1596 static HWND wait_for_window(const char *caption)
1597 {
1598 HWND hwnd;
1599 DWORD timeout = 0;
1600
1601 for (;;)
1602 {
1603 hwnd = FindWindowA(NULL, caption);
1604 if (hwnd) break;
1605
1606 Sleep(50);
1607 timeout += 50;
1608 if (timeout > 3000)
1609 {
1610 ok(0, "failed to wait for a window %s\n", caption);
1611 break;
1612 }
1613 }
1614
1615 Sleep(50);
1616 return hwnd;
1617 }
1618
1619 static void test_MessageBox(void)
1620 {
1621 static const struct
1622 {
1623 DWORD mb_style;
1624 DWORD ex_style;
1625 } test[] =
1626 {
1627 { MB_OK, 0 },
1628 { MB_OK | MB_TASKMODAL, 0 },
1629 { MB_OK | MB_SYSTEMMODAL, WS_EX_TOPMOST },
1630 };
1631 struct create_window_params params;
1632 HANDLE thread;
1633 DWORD tid, i;
1634 HHOOK hook;
1635 int ret;
1636
1637 hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId());
1638
1639 ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL);
1640 ok(ret == IDCANCEL, "got %d\n", ret);
1641
1642 UnhookWindowsHookEx(hook);
1643
1644 sprintf(params.caption, "pid %08x, tid %08x, time %08x",
1645 GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentTime());
1646
1647 params.owner = FALSE;
1648
1649 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
1650 {
1651 HWND hwnd;
1652 DWORD ex_style;
1653
1654 params.style = test[i].mb_style;
1655
1656 thread = CreateThread(NULL, 0, create_window_thread, &params, 0, &tid);
1657
1658 hwnd = wait_for_window(params.caption);
1659 ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1660 ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style);
1661
1662 PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
1663
1664 ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n");
1665 CloseHandle(thread);
1666 }
1667
1668 params.owner = TRUE;
1669
1670 for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
1671 {
1672 HWND hwnd;
1673 DWORD ex_style;
1674
1675 params.style = test[i].mb_style;
1676
1677 thread = CreateThread(NULL, 0, create_window_thread, &params, 0, &tid);
1678
1679 hwnd = wait_for_window(params.caption);
1680 ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE);
1681 ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style);
1682
1683 PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
1684
1685 ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n");
1686 CloseHandle(thread);
1687 }
1688 }
1689
1690 static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1691 {
1692 if (msg == WM_INITDIALOG)
1693 EndDialog(hdlg, 0);
1694
1695 return FALSE;
1696 }
1697
1698 static void test_dialog_custom_data(void)
1699 {
1700 DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc);
1701 }
1702
1703 START_TEST(dialog)
1704 {
1705 g_hinst = GetModuleHandleA (0);
1706
1707 if (!RegisterWindowClasses()) assert(0);
1708
1709 test_dialog_custom_data();
1710 test_GetNextDlgItem();
1711 test_IsDialogMessage();
1712 test_WM_NEXTDLGCTL();
1713 test_focus();
1714 test_GetDlgItem();
1715 test_GetDlgItemText();
1716 test_DialogBoxParamA();
1717 test_DisabledDialogTest();
1718 test_MessageBoxFontTest();
1719 test_SaveRestoreFocus();
1720 test_timer_message();
1721 test_MessageBox();
1722 }