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