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 <assert.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 
36 #include "wine/test.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wingdi.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 
43 #define MAXHWNDS 1024
44 static HWND hwnd [MAXHWNDS];
45 static unsigned int numwnds=1; /* 0 is reserved for null */
46 
47 /* Global handles */
48 static HINSTANCE g_hinst;                          /* This application's HINSTANCE */
49 static HWND g_hwndMain, g_hwndButton1, g_hwndButton2, g_hwndButtonCancel;
50 static HWND g_hwndTestDlg, g_hwndTestDlgBut1, g_hwndTestDlgBut2, g_hwndTestDlgEdit;
51 static HWND g_hwndInitialFocusT1, g_hwndInitialFocusT2, g_hwndInitialFocusGroupBox;
52 
53 static LONG g_styleInitialFocusT1, g_styleInitialFocusT2;
54 static BOOL g_bInitialFocusInitDlgResult, g_bReceivedCommand;
55 
56 static BOOL g_terminated;
57 static BOOL g_button1Clicked;
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 DWORD get_button_style(HWND button)
151 {
152     return GetWindowLongW(button, GWL_STYLE) & BS_TYPEMASK;
153 }
154 
155 static BOOL CreateWindows (HINSTANCE hinst)
156 {
157     const h_entry *p = hierarchy;
158 
159     while (p->id != 0)
160     {
161         DWORD style, exstyle;
162         char ctrlname[16];
163 
164         /* Basically assert that the hierarchy is valid and track the
165          * maximum control number
166          */
167         if (p->id >= numwnds)
168         {
169             if (p->id >=  ARRAY_SIZE(hwnd))
170             {
171                 trace ("Control %ld is out of range\n", p->id);
172                 return FALSE;
173             }
174             else
175                 numwnds = p->id+1;
176         }
177         if (p->id <= 0)
178         {
179             trace ("Control %ld is out of range\n", p->id);
180             return FALSE;
181         }
182         if (hwnd[p->id] != 0)
183         {
184             trace ("Control %ld is used more than once\n", p->id);
185             return FALSE;
186         }
187 
188         /* Create the control */
189         sprintf (ctrlname, "ctrl%4.4ld", p->id);
190         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);
191         if (!hwnd[p->id])
192         {
193             trace ("Failed to create control %ld\n", p->id);
194             return FALSE;
195         }
196 
197         /* Check that the styles are as we specified (except the main one
198          * which is quite frequently messed up).  If this keeps breaking then
199          * we could mask out the bits that don't concern us.
200          */
201         if (p->parent)
202         {
203             style = GetWindowLongA(hwnd[p->id], GWL_STYLE);
204             exstyle = GetWindowLongA(hwnd[p->id], GWL_EXSTYLE);
205             if (style != p->style || exstyle != p->exstyle)
206             {
207                 trace ("Style mismatch at %ld: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle);
208             }
209         }
210         p++;
211     }
212 
213     return TRUE;
214 }
215 
216 /* Form the lParam of a WM_KEYDOWN message */
217 static DWORD KeyDownData (int repeat, int scancode, int extended, int wasdown)
218 {
219     return ((repeat & 0x0000FFFF) | ((scancode & 0x00FF) << 16) |
220             (extended ? 0x01000000 : 0) | (wasdown ? 0x40000000 : 0));
221 }
222 
223 /* Form a WM_KEYDOWN VK_TAB message to the specified window */
224 static void FormTabMsg (MSG *pMsg, HWND hwnd)
225 {
226     pMsg->hwnd = hwnd;
227     pMsg->message = WM_KEYDOWN;
228     pMsg->wParam = VK_TAB;
229     pMsg->lParam = KeyDownData (1, 0x0F, 0, 0);
230     /* pMsg->time is not set.  It shouldn't be needed */
231     /* pMsg->pt is ignored */
232 }
233 
234 /* Form a WM_KEYDOWN VK_RETURN message to the specified window */
235 static void FormEnterMsg (MSG *pMsg, HWND hwnd)
236 {
237     pMsg->hwnd = hwnd;
238     pMsg->message = WM_KEYDOWN;
239     pMsg->wParam = VK_RETURN;
240     pMsg->lParam = KeyDownData (1, 0x1C, 0, 0);
241     /* pMsg->time is not set.  It shouldn't be needed */
242     /* pMsg->pt is ignored */
243 }
244 
245 /***********************************************************************
246  *
247  * The actual tests
248  */
249 
250 typedef struct
251 {
252     int isok; /* or is it todo */
253     int test;
254     int dlg;
255     int ctl;
256     int tab;
257     int prev;
258     int res;
259 } test_record;
260 
261 static int id (HWND h)
262 {
263     unsigned int i;
264     for (i = 0; i < numwnds; i++)
265         if (hwnd[i] == h)
266             return i;
267     return -1;
268 }
269 
270 /* Tests
271  *
272  * Tests 1-8 test the hCtl argument of null or the dialog itself.
273  *
274  *   1. Prev Group of null is null
275  *   2. Prev Tab of null is null
276  *   3. Prev Group of hDlg in hDlg is null
277  *   4. Prev Tab of hDlg in hDlg is null
278  *   5. Next Group of null is first visible enabled child
279  *      Check it skips invisible, disabled and both.
280  *   6. Next Tab of null is first visible enabled tabstop
281  *      Check it skips invisible, disabled, nontabstop, and in combination.
282  *   7. Next Group of hDlg in hDlg is as of null
283  *   8. Next Tab of hDlg in hDlg is as of null
284  *
285  * Tests 9-14 test descent
286  *
287  *   9. DS_CONTROL does not result in descending the hierarchy for Tab Next
288  *  10. DS_CONTROL does not result in descending the hierarchy for Group Next
289  *  11. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Next
290  *  12. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Next
291  *  13. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Prev
292  *  14. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Prev
293  *
294  * Tests 15-24 are the basic Prev/Next Group tests
295  *
296  *  15. Next Group of a visible enabled non-group control is the next visible
297  *      enabled non-group control, if there is one before the next group
298  *  16. Next Group of a visible enabled non-group control wraps around to the
299  *      beginning of the group on finding a control that starts another group.
300  *      Note that the group is in the middle of the dialog.
301  *  17. As 16 except note that the next group is started with a disabled
302  *      visible control.
303  *  18. As 16 except note that the next group is started with an invisible
304  *      enabled control.
305  *  19. Next Group wraps around the controls of the dialog
306  *  20. Next Group is the same even if the initial control is disabled.
307  *  21. Next Group is the same even if the initial control is invisible.
308  *  22. Next Group is the same even if the initial control has the group style
309  *  23. Next Group returns the initial control if there is no visible enabled
310  *      control in the group. (Initial control disabled and not group style).
311  *  24. Prev version of test 16.
312  *      Prev Group of a visible enabled non-group control wraps around to the
313  *      beginning of the group on finding a control that starts the group.
314  *      Note that the group is in the middle of the dialog.
315  *
316  * In tests 25 to 28 the control is sitting under dialogs which do not have
317  * the WS_EX_CONTROLPARENT style and so cannot be reached from the top of
318  * the dialog.
319  *
320  *  25. Next Group of an inaccessible control is as if it were accessible
321  *  26. Prev Group of an inaccessible control begins searching at the highest
322  *      level ancestor that did not permit recursion down the hierarchy
323  *  27. Next Tab of an inaccessible control is as if it were accessible
324  *  28. Prev Tab of an inaccessible control begins searching at the highest
325  *      level ancestor that did not permit recursion down the hierarchy.
326  *
327  * Tests 29- are the basic Tab tests
328  *
329  *  29. Next Tab of a control is the next visible enabled control with the
330  *      Tabstop style (N.B. skips disabled, invisible and non-tabstop)
331  *  30. Prev Tab of a control is the previous visible enabled control with the
332  *      Tabstop style (N.B. skips disabled, invisible and non-tabstop)
333  *  31. Next Tab test with at least two layers of descent and finding the
334  *      result not at the first control.
335  *  32. Next Tab test with at least two layers of descent with the descent and
336  *      control at the start of each level.
337  *  33. Prev Tab test with at least two layers of descent and finding the
338  *      result not at the last control.
339  *  34. Prev Tab test with at least two layers of descent with the descent and
340  *      control at the end of each level.
341  *
342  *  35. Passing NULL may result in the first child being the one returned.
343  *      (group test)
344  *  36. Passing NULL may result in the first child being the one returned.
345  *      (tab test)
346  */
347 
348 static void test_GetNextDlgItem(void)
349 {
350     static test_record test [] =
351     {
352         /* isok test dlg  ctl  tab  prev res  */
353 
354         {   1,   1,    6,   0,   0,   1,   0},
355         {   1,   2,    6,   0,   1,   1,   0},
356         {   1,   3,    6,   6,   0,   1,   0},
357         {   1,   4,    6,   6,   1,   1,   0},
358         {   1,   5,    6,   0,   0,   0,  66},
359         {   1,   6,    6,   0,   1,   0,  67},
360         {   1,   7,    6,   6,   0,   0,  66},
361         {   1,   8,    6,   6,   1,   0,  67},
362 
363         {   1,   9,    4,  83,   1,   0,  84},
364         {   1,  10,    4,  83,   0,   0,   5},
365         {   1,  11,    5,  81,   1,   0,  67},
366         {   1,  12,    5,  81,   0,   0,  66},
367         {   1,  13,    5,  82,   1,   1,  78},
368 
369         {   1,  14,    5,  82,   0,   1,  79},
370         {   1,  15,    6,  70,   0,   0,  72},
371         {   1,  16,    6,  72,   0,   0,  25},
372         {   1,  17,    6,  75,   0,   0,  26},
373         {   1,  18,    6,  77,   0,   0,  76},
374         {   1,  19,    6,  79,   0,   0,  66},
375         {   1,  20,    6,  71,   0,   0,  72},
376         {   1,  21,    6,  64,   0,   0,  66},
377 
378         {   1,  22,    6,  25,   0,   0,  70},
379         {   1,  23,    6,  68,   0,   0,  68},
380         {   1,  24,    6,  25,   0,   1,  72},
381         {   1,  25,    1,  70,   0,   0,  72},
382         /*{   0,  26,    1,  70,   0,   1,   3}, Crashes Win95*/
383         {   1,  27,    1,  70,   1,   0,  72},
384         /*{   0,  28,    1,  70,   1,   1,  61}, Crashes Win95*/
385 
386         {   1,  29,    6,  67,   1,   0,  72},
387         {   1,  30,    6,  72,   1,   1,  67},
388 
389         {   1,  35,    2,   0,   0,   0,  60},
390         {   1,  36,    2,   0,   1,   0,  60},
391 
392         {   0,   0,    0,   0,   0,   0,   0}  /* End of test */
393     };
394     const test_record *p = test;
395 
396     ok (CreateWindows (g_hinst), "Could not create test windows\n");
397 
398     while (p->dlg)
399     {
400         HWND a;
401         a = (p->tab ? GetNextDlgTabItem : GetNextDlgGroupItem) (hwnd[p->dlg], hwnd[p->ctl], p->prev);
402         todo_wine_if (!p->isok)
403             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);
404         p++;
405     }
406 }
407 
408 /*
409  *  OnMainWindowCreate
410  */
411 static BOOL OnMainWindowCreate(HWND hwnd, LPCREATESTRUCTA lpcs)
412 {
413     g_hwndButton1 = CreateWindowA("button", "Button &1",
414             WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | BS_TEXT,
415             10, 10, 80, 80, hwnd, (HMENU)100, g_hinst, 0);
416     if (!g_hwndButton1) return FALSE;
417 
418     g_hwndButton2 = CreateWindowA("button", "Button &2",
419             WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
420             110, 10, 80, 80, hwnd, (HMENU)200, g_hinst, 0);
421     if (!g_hwndButton2) return FALSE;
422 
423     g_hwndButtonCancel = CreateWindowA("button", "Cancel",
424             WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
425             210, 10, 80, 80, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
426     if (!g_hwndButtonCancel) return FALSE;
427 
428     return TRUE;
429 }
430 
431 
432 /*
433  *  OnTestDlgCreate
434  */
435 
436 static BOOL OnTestDlgCreate (HWND hwnd, LPCREATESTRUCTA lpcs)
437 {
438     g_hwndTestDlgEdit = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING |
439             WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
440             "Edit", "Edit",
441             WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL,
442             16,33,184,24, hwnd, (HMENU)101, g_hinst, 0);
443     if (!g_hwndTestDlgEdit) return FALSE;
444 
445     g_hwndTestDlgBut1 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
446             | WS_EX_NOPARENTNOTIFY,
447             "button", "Button &1",
448             WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
449             204,33,30,24, hwnd, (HMENU)201, g_hinst, 0);
450     if (!g_hwndTestDlgBut1) return FALSE;
451 
452     g_hwndTestDlgBut2 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
453             | WS_EX_NOPARENTNOTIFY, "button",
454             "Button &2",
455             WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
456             90,102,80,24, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
457     if (!g_hwndTestDlgBut2) return FALSE;
458 
459     return TRUE;
460 }
461 
462 static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam,
463         LPARAM lParam)
464 {
465     switch (uiMsg)
466     {
467         /* Add blank case statements for these to ensure we don't use them
468          * by mistake.
469          */
470         case DM_GETDEFID: break;
471         case DM_SETDEFID: break;
472 
473         case WM_CREATE:
474             return (OnMainWindowCreate (hwnd,
475                     (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
476         case WM_COMMAND:
477             if (wParam == IDCANCEL)
478             {
479                 g_terminated = TRUE;
480                 return 0;
481             }
482             else if ((wParam == 100 || wParam == 0xFFFF) && lParam)
483             {
484                 g_button1Clicked = TRUE;
485             }
486             break;
487     }
488 
489     return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
490 }
491 
492 static LRESULT CALLBACK disabled_test_proc (HWND hwnd, UINT uiMsg,
493         WPARAM wParam, LPARAM lParam)
494 {
495     switch (uiMsg)
496     {
497         case WM_INITDIALOG:
498         {
499             DWORD dw;
500             HWND hwndOk;
501 
502             dw = SendMessageA(hwnd, DM_GETDEFID, 0, 0);
503             assert(DC_HASDEFID == HIWORD(dw));
504             hwndOk = GetDlgItem(hwnd, LOWORD(dw));
505             assert(hwndOk);
506             EnableWindow(hwndOk, FALSE);
507 
508             PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0);
509             PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
510             break;
511         }
512         case WM_COMMAND:
513             if (wParam == IDOK)
514             {
515                 g_terminated = TRUE;
516                 EndDialog(hwnd, 0);
517                 return 0;
518             }
519             else if (wParam == IDCANCEL)
520             {
521                 EndDialog(hwnd, 0);
522                 return 0;
523             }
524             break;
525     }
526 
527     return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
528 }
529 
530 static LRESULT CALLBACK testDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
531         LPARAM lParam)
532 {
533     switch (uiMsg)
534     {
535         /* Add blank case statements for these to ensure we don't use them
536          * by mistake.
537          */
538         case DM_GETDEFID: break;
539         case DM_SETDEFID: break;
540 
541         case WM_CREATE:
542             return (OnTestDlgCreate (hwnd,
543                     (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
544         case WM_COMMAND:
545             if(LOWORD(wParam) == 300) g_bReceivedCommand = TRUE;
546     }
547 
548     return DefDlgProcA (hwnd, uiMsg, wParam, lParam);
549 }
550 
551 static LRESULT CALLBACK test_control_procA(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
552 {
553     switch(msg)
554     {
555         case WM_CREATE:
556         {
557             static const short sample[] = { 10,1,2,3,4,5 };
558             CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam;
559             short *data = cs->lpCreateParams;
560             ok(!memcmp(data, sample, sizeof(sample)), "data mismatch: %d,%d,%d,%d,%d\n", data[0], data[1], data[2], data[3], data[4]);
561         }
562         return 0;
563 
564     default:
565         break;
566     }
567 
568     return DefWindowProcA(hwnd, msg, wparam, lparam);
569 }
570 
571 static BOOL RegisterWindowClasses (void)
572 {
573     WNDCLASSA cls;
574 
575     cls.style = 0;
576     cls.lpfnWndProc = DefWindowProcA;
577     cls.cbClsExtra = 0;
578     cls.cbWndExtra = 0;
579     cls.hInstance = g_hinst;
580     cls.hIcon = NULL;
581     cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
582     cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
583     cls.lpszMenuName = NULL;
584     cls.lpszClassName = "GetNextDlgItemWindowClass";
585 
586     if (!RegisterClassA (&cls)) return FALSE;
587 
588     cls.lpfnWndProc = main_window_procA;
589     cls.lpszClassName = "IsDialogMessageWindowClass";
590     if (!RegisterClassA (&cls)) return FALSE;
591 
592     cls.lpfnWndProc = test_control_procA;
593     cls.lpszClassName = "TESTCONTROL";
594     if (!RegisterClassA (&cls)) return FALSE;
595 
596     GetClassInfoA(0, "#32770", &cls);
597     cls.lpfnWndProc = testDlgWinProc;
598     cls.lpszClassName = "WM_NEXTDLGCTLWndClass";
599     if (!RegisterClassA (&cls)) return FALSE;
600 
601     return TRUE;
602 }
603 
604 static void test_WM_NEXTDLGCTL(void)
605 {
606     HWND child1, child2, child3;
607     MSG msg;
608     DWORD dwVal;
609 
610     g_hwndTestDlg = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
611               | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,
612               "WM_NEXTDLGCTLWndClass",
613               "WM_NEXTDLGCTL Message test window",
614               WS_POPUPWINDOW | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_OVERLAPPED |
615               WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK | DS_SETFONT | DS_MODALFRAME,
616               0, 0, 235, 135,
617               NULL, NULL, g_hinst, 0);
618 
619     assert (g_hwndTestDlg);
620     assert (g_hwndTestDlgBut1);
621     assert (g_hwndTestDlgBut2);
622     assert (g_hwndTestDlgEdit);
623 
624     /*
625      * Test message DM_SETDEFID
626      */
627 
628     DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, IDCANCEL, 0 );
629     DefDlgProcA( g_hwndTestDlgBut1, BM_SETSTYLE, BS_DEFPUSHBUTTON, FALSE );
630     dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
631 
632     ok ( IDCANCEL == (LOWORD(dwVal)), "Did not set default ID\n" );
633 
634     /*
635      * Check whether message WM_NEXTDLGCTL is changing the focus to next control and if
636      * the destination control is a button, style of the button should be changed to
637      * BS_DEFPUSHBUTTON with out making it default.
638      */
639 
640     /* Keep the focus on Edit control. */
641     SetFocus(g_hwndTestDlgEdit);
642     ok((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n");
643 
644     /* Test message WM_NEXTDLGCTL */
645     DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0);
646     ok((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n");
647 
648     /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */
649     dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
650     ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
651 
652     /*
653      * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
654      * the style of default button changed to BS_PUSHBUTTON.
655      */
656     ok(get_button_style(g_hwndTestDlgBut1) == BS_DEFPUSHBUTTON, "Button1's style not set to BS_DEFPUSHBUTTON");
657     ok(get_button_style(g_hwndTestDlgBut2) == BS_PUSHBUTTON, "Button2's style not set to BS_PUSHBUTTON");
658 
659     /* Move focus to Button2 using "WM_NEXTDLGCTL" */
660     DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0);
661     ok((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n");
662 
663     /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */
664     dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
665     ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
666 
667     /*
668      * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
669      * the style of button which lost the focus changed to BS_PUSHBUTTON.
670      */
671     ok(get_button_style(g_hwndTestDlgBut1) == BS_PUSHBUTTON, "Button1's style not set to BS_PUSHBUTTON");
672     ok(get_button_style(g_hwndTestDlgBut2) == BS_DEFPUSHBUTTON, "Button2's style not set to BS_DEFPUSHBUTTON");
673 
674     /* Move focus to Edit control using "WM_NEXTDLGCTL" */
675     DefDlgProcA(g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0);
676     ok((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n");
677 
678     /* Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL" */
679     dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
680     ok(IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
681 
682     /* test nested default buttons */
683 
684     child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 50, 50,
685                            g_hwndTestDlg, (HMENU)100, g_hinst, NULL);
686     ok(child1 != NULL, "failed to create first child\n");
687     child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 60, 60, 30, 30,
688                            g_hwndTestDlg, (HMENU)200, g_hinst, NULL);
689     ok(child2 != NULL, "failed to create second child\n");
690     /* create nested child */
691     child3 = CreateWindowA("button", "child3", WS_VISIBLE|WS_CHILD, 10, 10, 10, 10,
692                            child1, (HMENU)300, g_hinst, NULL);
693     ok(child3 != NULL, "failed to create subchild\n");
694 
695     DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 200, 0);
696     dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
697     ok(LOWORD(dwVal) == 200, "expected 200, got %x\n", dwVal);
698 
699     DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 300, 0);
700     dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
701     ok(LOWORD(dwVal) == 300, "expected 300, got %x\n", dwVal);
702     ok(SendMessageW( child3, WM_GETDLGCODE, 0, 0) != DLGC_DEFPUSHBUTTON,
703        "expected child3 not to be marked as DLGC_DEFPUSHBUTTON\n");
704 
705     g_bReceivedCommand = FALSE;
706     FormEnterMsg (&msg, child3);
707     ok(IsDialogMessageA(g_hwndTestDlg, &msg), "Did not handle the ENTER\n");
708     ok(g_bReceivedCommand, "Did not trigger the default Button action\n");
709 
710     DestroyWindow(child3);
711     DestroyWindow(child2);
712     DestroyWindow(child1);
713     DestroyWindow(g_hwndTestDlg);
714 }
715 
716 static LRESULT CALLBACK hook_proc(INT code, WPARAM wParam, LPARAM lParam)
717 {
718     ok(0, "unexpected hook called, code %d\n", code);
719     return CallNextHookEx(NULL, code, wParam, lParam);
720 }
721 
722 static BOOL g_MSGF_DIALOGBOX;
723 static LRESULT CALLBACK hook_proc2(INT code, WPARAM wParam, LPARAM lParam)
724 {
725     ok(code == MSGF_DIALOGBOX, "unexpected hook called, code %d\n", code);
726     g_MSGF_DIALOGBOX = code == MSGF_DIALOGBOX;
727     return CallNextHookEx(NULL, code, wParam, lParam);
728 }
729 
730 static void test_IsDialogMessage(void)
731 {
732     HHOOK hook;
733     MSG msg;
734 
735     g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass",
736             WS_OVERLAPPEDWINDOW,
737             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
738             NULL, NULL, g_hinst, 0);
739 
740     assert (g_hwndMain);
741     assert (g_hwndButton1);
742     assert (g_hwndButtonCancel);
743 
744     if (0)
745     {
746         /* crashes on Windows */
747         IsDialogMessageA(NULL, NULL);
748         IsDialogMessageA(g_hwndMain, NULL);
749     }
750 
751     /* The focus should initially be nowhere.  The first TAB should take it
752      * to the first button.  The second TAB should take it to the Cancel
753      * button.
754      */
755 
756     /* valid window, invalid message window */
757     hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc2, NULL, GetCurrentThreadId());
758     FormTabMsg (&msg, (HWND)0xbeefbeef);
759     ok (!IsDialogMessageA(g_hwndMain, &msg), "expected failure\n");
760     ok(g_MSGF_DIALOGBOX, "hook wasn't called\n");
761     g_MSGF_DIALOGBOX = FALSE;
762     UnhookWindowsHookEx(hook);
763 
764     hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
765     FormTabMsg (&msg, g_hwndMain);
766 
767     ok (!IsDialogMessageA(NULL, &msg), "expected failure\n");
768     ok (!IsDialogMessageA((HWND)0xbeefbeef, &msg), "expected failure\n");
769 
770     UnhookWindowsHookEx(hook);
771 
772     ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle first TAB\n");
773     ok ((GetFocus() == g_hwndButton1), "Focus did not move to first button\n");
774     FormTabMsg (&msg, g_hwndButton1);
775     ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle second TAB\n");
776     ok ((GetFocus() == g_hwndButtonCancel),
777             "Focus did not move to cancel button\n");
778     FormEnterMsg (&msg, g_hwndButtonCancel);
779     ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
780     ok (g_terminated, "ENTER did not terminate\n");
781 
782     /* matching but invalid window handles, NULL */
783     hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
784 
785     FormTabMsg (&msg, NULL);
786     ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
787 
788     /* matching but invalid window handles, not NULL */
789     FormTabMsg (&msg, (HWND)0xbeefbeef);
790     ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
791 
792     UnhookWindowsHookEx(hook);
793     DestroyWindow(g_hwndMain);
794 
795     g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass", WS_OVERLAPPEDWINDOW,
796                                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, g_hinst, 0);
797     SetFocus(g_hwndButton1);
798     g_button1Clicked = FALSE;
799     FormEnterMsg(&msg, g_hwndButton1);
800     ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
801     ok(g_button1Clicked, "Did not receive button 1 click notification\n");
802 
803     g_button1Clicked = FALSE;
804     FormEnterMsg(&msg, g_hwndMain);
805     ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
806     ok(g_button1Clicked, "Did not receive button 1 click notification\n");
807 
808     g_button1Clicked = FALSE;
809     FormEnterMsg(&msg, g_hwndButton2);
810     ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
811     ok(g_button1Clicked, "Did not receive button 1 click notification\n");
812 
813     /* Button with id larger than 0xFFFF should also work */
814     g_button1Clicked = FALSE;
815     FormEnterMsg(&msg, g_hwndMain);
816     SetWindowLongPtrW(g_hwndButton1, GWLP_ID, 0x1FFFF);
817     ok(IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
818     ok(g_button1Clicked, "Did not receive button 1 click notification\n");
819 
820     DestroyWindow(g_hwndMain);
821 }
822 
823 
824 static INT_PTR CALLBACK delayFocusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
825         LPARAM lParam)
826 {
827     switch (uiMsg)
828     {
829     case WM_INITDIALOG:
830         g_hwndMain = hDlg;
831        g_hwndInitialFocusGroupBox = GetDlgItem(hDlg,100);
832        g_hwndButton1 = GetDlgItem(hDlg,200);
833        g_hwndButton2 = GetDlgItem(hDlg,201);
834        g_hwndButtonCancel = GetDlgItem(hDlg,IDCANCEL);
835        g_styleInitialFocusT1 = GetWindowLongA(g_hwndInitialFocusGroupBox, GWL_STYLE);
836 
837        /* Initially check the second radio button */
838        SendMessageA(g_hwndButton1, BM_SETCHECK, BST_UNCHECKED, 0);
839        SendMessageA(g_hwndButton2, BM_SETCHECK, BST_CHECKED  , 0);
840        /* Continue testing after dialog initialization */
841        PostMessageA(hDlg, WM_USER, 0, 0);
842        return g_bInitialFocusInitDlgResult;
843 
844     case WM_COMMAND:
845         if (LOWORD(wParam) == IDCANCEL)
846        {
847            EndDialog(hDlg, LOWORD(wParam));
848            return TRUE;
849        }
850        return FALSE;
851 
852     case WM_USER:
853        g_styleInitialFocusT2 = GetWindowLongA(hDlg, GWL_STYLE);
854         g_hwndInitialFocusT1 = GetFocus();
855        SetFocus(hDlg);
856         g_hwndInitialFocusT2 = GetFocus();
857        PostMessageA(hDlg, WM_COMMAND, IDCANCEL, 0);
858        return TRUE;
859     }
860 
861     return FALSE;
862 }
863 
864 static INT_PTR CALLBACK focusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
865         LPARAM lParam)
866 {
867     switch (uiMsg)
868     {
869     case WM_INITDIALOG:
870         SetWindowTextA(GetDlgItem(hDlg, 200), "new caption");
871         return TRUE;
872 
873     case WM_COMMAND:
874        if (LOWORD(wParam) == 200)
875        {
876            if (HIWORD(wParam) == EN_SETFOCUS)
877                g_hwndInitialFocusT1 = (HWND)lParam;
878        }
879        return FALSE;
880     }
881 
882     return FALSE;
883 }
884 
885 static INT_PTR CALLBACK EmptyProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
886 {
887     switch(uMsg) {
888     case WM_INITDIALOG:
889         return TRUE;
890     }
891     return FALSE;
892 }
893 
894 static INT_PTR CALLBACK focusChildDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
895         LPARAM lParam)
896 {
897     static HWND hChildDlg;
898 
899     switch (uiMsg)
900     {
901     case WM_INITDIALOG:
902     {
903         RECT rectHwnd;
904         struct  {
905             DLGTEMPLATE tmplate;
906             WORD menu,class,title;
907         } temp;
908 
909         SetFocus( GetDlgItem(hwnd, 200) );
910 
911         GetClientRect(hwnd,&rectHwnd);
912         temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK;
913         temp.tmplate.dwExtendedStyle = 0;
914         temp.tmplate.cdit = 0;
915         temp.tmplate.x = 0;
916         temp.tmplate.y = 0;
917         temp.tmplate.cx = 0;
918         temp.tmplate.cy = 0;
919         temp.menu = temp.class = temp.title = 0;
920 
921         hChildDlg = CreateDialogIndirectParamA(g_hinst, &temp.tmplate,
922                   hwnd, (DLGPROC)EmptyProcUserTemplate, 0);
923         ok(hChildDlg != 0, "Failed to create test dialog.\n");
924 
925         return FALSE;
926     }
927     case WM_CLOSE:
928         DestroyWindow(hChildDlg);
929         return TRUE;
930     }
931 
932     return FALSE;
933 }
934 
935 /* Helper for InitialFocusTest */
936 static const char * GetHwndString(HWND hw)
937 {
938   if (hw == NULL)
939     return "a null handle";
940   if (hw == g_hwndMain)
941     return "the dialog handle";
942   if (hw == g_hwndInitialFocusGroupBox)
943     return "the group box control";
944   if (hw == g_hwndButton1)
945     return "the first button";
946   if (hw == g_hwndButton2)
947     return "the second button";
948   if (hw == g_hwndButtonCancel)
949     return "the cancel button";
950 
951   return "unknown handle";
952 }
953 
954 static void test_focus(void)
955 {
956     /* Test 1:
957      * This test intentionally returns FALSE in response to WM_INITDIALOG
958      * without setting focus to a control. This is what MFC's CFormView does.
959      *
960      * Since the WM_INITDIALOG handler returns FALSE without setting the focus,
961      * the focus should initially be NULL. Later, when we manually set focus to
962      * the dialog, the default handler should set focus to the first control that
963      * is "visible, not disabled, and has the WS_TABSTOP style" (MSDN). Because the
964      * second radio button has been checked, it should be the first control
965      * that meets these criteria and should receive the focus.
966      */
967 
968     g_bInitialFocusInitDlgResult = FALSE;
969     g_hwndInitialFocusT1 = (HWND) -1;
970     g_hwndInitialFocusT2 = (HWND) -1;
971     g_styleInitialFocusT1 = -1;
972     g_styleInitialFocusT2 = -1;
973 
974     DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
975 
976     ok (((g_styleInitialFocusT1 & WS_TABSTOP) == 0),
977        "Error in wrc - Detected WS_TABSTOP as default style for GROUPBOX\n");
978 
979     ok (((g_styleInitialFocusT2 & WS_VISIBLE) == 0),
980        "Modal dialogs should not be shown until the message queue first goes empty\n");
981 
982     ok ((g_hwndInitialFocusT1 == NULL),
983         "Error in initial focus when WM_INITDIALOG returned FALSE: "
984         "Expected NULL focus, got %s (%p).\n",
985         GetHwndString(g_hwndInitialFocusT1), g_hwndInitialFocusT1);
986 
987     ok ((g_hwndInitialFocusT2 == g_hwndButton2),
988         "Error after first SetFocus() when WM_INITDIALOG returned FALSE: "
989         "Expected the second button (%p), got %s (%p).\n",
990         g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
991         g_hwndInitialFocusT2);
992 
993     /* Test 2:
994      * This is the same as above, except WM_INITDIALOG is made to return TRUE.
995      * This should cause the focus to go to the second radio button right away
996      * and stay there (until the user indicates otherwise).
997      */
998 
999     g_bInitialFocusInitDlgResult = TRUE;
1000     g_hwndInitialFocusT1 = (HWND) -1;
1001     g_hwndInitialFocusT2 = (HWND) -1;
1002     g_styleInitialFocusT1 = -1;
1003     g_styleInitialFocusT2 = -1;
1004 
1005     DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
1006 
1007     ok ((g_hwndInitialFocusT1 == g_hwndButton2),
1008        "Error in initial focus when WM_INITDIALOG returned TRUE: "
1009        "Expected the second button (%p), got %s (%p).\n",
1010        g_hwndButton2, GetHwndString(g_hwndInitialFocusT1),
1011        g_hwndInitialFocusT1);
1012 
1013     ok ((g_hwndInitialFocusT2 == g_hwndButton2),
1014        "Error after first SetFocus() when WM_INITDIALOG returned TRUE: "
1015        "Expected the second button (%p), got %s (%p).\n",
1016        g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
1017        g_hwndInitialFocusT2);
1018 
1019     /* Test 3:
1020      * If the dialog has DS_CONTROL and it's not visible then we shouldn't change focus */
1021     {
1022         HWND hDlg;
1023         HRSRC hResource;
1024         HANDLE hTemplate;
1025         DLGTEMPLATE* pTemplate;
1026         HWND hTextbox;
1027         DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
1028 
1029         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPCSTR)RT_DIALOG);
1030         hTemplate = LoadResource(g_hinst, hResource);
1031         pTemplate = LockResource(hTemplate);
1032 
1033         g_hwndInitialFocusT1 = 0;
1034         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1035         ok (hDlg != 0, "Failed to create test dialog.\n");
1036 
1037         ok ((g_hwndInitialFocusT1 == 0),
1038             "Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
1039 
1040         /* Also make sure that WM_SETFOCUS selects the textbox's text */
1041         hTextbox = GetDlgItem(hDlg, 200);
1042         SendMessageA(hTextbox, WM_SETTEXT, 0, (LPARAM)"Hello world");
1043 
1044         SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
1045         SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
1046         ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd);
1047 
1048         /* but WM_ACTIVATE does not */
1049         SendMessageA(hTextbox, EM_SETSEL, 0, 0);
1050         SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
1051         SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
1052         ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd);
1053 
1054         DestroyWindow(hDlg);
1055     }
1056 
1057     /* Test 4:
1058      * If the dialog has no tab-accessible controls, set focus to first control */
1059     {
1060         HWND hDlg;
1061         HRSRC hResource;
1062         HANDLE hTemplate;
1063         DLGTEMPLATE* pTemplate;
1064         HWND hLabel;
1065 
1066         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_2", (LPCSTR)RT_DIALOG);
1067         hTemplate = LoadResource(g_hinst, hResource);
1068         pTemplate = LockResource(hTemplate);
1069 
1070         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1071         ok(hDlg != 0, "Failed to create test dialog.\n");
1072         hLabel = GetDlgItem(hDlg, 200);
1073 
1074         ok(GetFocus() == hLabel, "Focus not set to label, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1075 
1076         DestroyWindow(hDlg);
1077 
1078         /* Also check focus after WM_ACTIVATE and WM_SETFOCUS */
1079         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, NULL, 0);
1080         ok(hDlg != 0, "Failed to create test dialog.\n");
1081         hLabel = GetDlgItem(hDlg, 200);
1082 
1083         SetFocus(NULL);
1084         SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
1085         ok(GetFocus() == NULL, "Focus set on WM_ACTIVATE, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1086 
1087         SetFocus(NULL);
1088         SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
1089         ok(GetFocus() == hLabel, "Focus not set to label on WM_SETFOCUS, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1090 
1091         DestroyWindow(hDlg);
1092     }
1093 
1094     /* Test 5:
1095      * Select textbox's text on creation */
1096     {
1097         HWND hDlg;
1098         HRSRC hResource;
1099         HANDLE hTemplate;
1100         DLGTEMPLATE* pTemplate;
1101         HWND edit;
1102         DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
1103 
1104         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_3", (LPCSTR)RT_DIALOG);
1105         hTemplate = LoadResource(g_hinst, hResource);
1106         pTemplate = LockResource(hTemplate);
1107 
1108         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1109         ok(hDlg != 0, "Failed to create test dialog.\n");
1110         edit = GetDlgItem(hDlg, 200);
1111 
1112         ok(GetFocus() == edit, "Focus not set to edit, focus=%p, dialog=%p, edit=%p\n",
1113                 GetFocus(), hDlg, edit);
1114         SendMessageA(edit, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
1115         ok(selectionStart == 0 && selectionEnd == 11,
1116                 "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n",
1117                 selectionStart, selectionEnd);
1118 
1119         DestroyWindow(hDlg);
1120     }
1121 
1122     /* Test 6:
1123      * Select textbox's text on creation when WM_INITDIALOG creates a child dialog. */
1124     {
1125         HWND hDlg;
1126         HRSRC hResource;
1127         HANDLE hTemplate;
1128         DLGTEMPLATE* pTemplate;
1129         HWND edit;
1130 
1131         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_3", (LPCSTR)RT_DIALOG);
1132         hTemplate = LoadResource(g_hinst, hResource);
1133         pTemplate = LockResource(hTemplate);
1134 
1135         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusChildDlgWinProc, 0);
1136         ok(hDlg != 0, "Failed to create test dialog.\n");
1137         edit = GetDlgItem(hDlg, 200);
1138 
1139         ok(GetFocus() == edit, "Focus not set to edit, focus=%p, dialog=%p, edit=%p\n",
1140                 GetFocus(), hDlg, edit);
1141 
1142         DestroyWindow(hDlg);
1143     }
1144 }
1145 
1146 static void test_GetDlgItemText(void)
1147 {
1148     char string[64];
1149     BOOL ret;
1150 
1151     strcpy(string, "Overwrite Me");
1152     ret = GetDlgItemTextA(NULL, 0, string, ARRAY_SIZE(string));
1153     ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n");
1154 
1155     ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")),
1156        "string retrieved using GetDlgItemText should have been NULL terminated\n");
1157 }
1158 
1159 static INT_PTR CALLBACK getdlgitem_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1160 {
1161     if (msg == WM_INITDIALOG)
1162     {
1163         char text[64];
1164         LONG_PTR val;
1165         HWND hwnd;
1166         BOOL ret;
1167 
1168         hwnd = GetDlgItem(hdlg, -1);
1169         ok(hwnd != NULL, "Expected dialog item.\n");
1170 
1171         *text = 0;
1172         ret = GetDlgItemTextA(hdlg, -1, text, ARRAY_SIZE(text));
1173         ok(ret && !strcmp(text, "Text1"), "Unexpected item text.\n");
1174 
1175         val = GetWindowLongA(hwnd, GWLP_ID);
1176         ok(val == -1, "Unexpected id.\n");
1177 
1178         val = GetWindowLongPtrA(hwnd, GWLP_ID);
1179         ok(val == -1, "Unexpected id %ld.\n", val);
1180 
1181         hwnd = GetDlgItem(hdlg, -2);
1182         ok(hwnd != NULL, "Expected dialog item.\n");
1183 
1184         val = GetWindowLongA(hwnd, GWLP_ID);
1185         ok(val == -2, "Unexpected id.\n");
1186 
1187         val = GetWindowLongPtrA(hwnd, GWLP_ID);
1188         ok(val == -2, "Unexpected id %ld.\n", val);
1189 
1190         EndDialog(hdlg, 0xdead);
1191     }
1192 
1193     return FALSE;
1194 }
1195 
1196 static void test_GetDlgItem(void)
1197 {
1198     HWND hwnd, child1, child2, hwnd2;
1199     INT_PTR retval;
1200     BOOL ret;
1201 
1202     hwnd = CreateWindowA("button", "parent", WS_VISIBLE, 0, 0, 100, 100, NULL, 0, g_hinst, NULL);
1203     ok(hwnd != NULL, "failed to created window\n");
1204 
1205     /* created with the same ID */
1206     child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1207     ok(child1 != NULL, "failed to create first child\n");
1208     child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1209     ok(child2 != NULL, "failed to create second child\n");
1210 
1211     hwnd2 = GetDlgItem(hwnd, 0);
1212     ok(hwnd2 == child1, "expected first child, got %p\n", hwnd2);
1213 
1214     hwnd2 = GetTopWindow(hwnd);
1215     ok(hwnd2 == child1, "expected first child to be top, got %p\n", hwnd2);
1216 
1217     ret = SetWindowPos(child1, child2, 0, 0, 0, 0, SWP_NOMOVE);
1218     ok(ret, "got %d\n", ret);
1219     hwnd2 = GetTopWindow(hwnd);
1220     ok(hwnd2 == child2, "expected second child to be top, got %p\n", hwnd2);
1221 
1222     /* top window from child list is picked */
1223     hwnd2 = GetDlgItem(hwnd, 0);
1224     ok(hwnd2 == child2, "expected second child, got %p\n", hwnd2);
1225 
1226     /* Now test how GetDlgItem searches */
1227     DestroyWindow(child2);
1228     child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, child1, 0, g_hinst, NULL);
1229     ok(child2 != NULL, "failed to create second child\n");
1230 
1231     /* give child2 an ID */
1232     SetWindowLongA(child2, GWLP_ID, 100);
1233 
1234     hwnd2 = GetDlgItem(hwnd, 100);
1235     ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1236 
1237     /* make the ID of child2 public with a WS_EX_CONTROLPARENT parent */
1238     SetWindowLongA(child1, GWL_EXSTYLE, WS_EX_CONTROLPARENT);
1239 
1240     hwnd2 = GetDlgItem(hwnd, 100);
1241     ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1242 
1243     DestroyWindow(child1);
1244     DestroyWindow(child2);
1245     DestroyWindow(hwnd);
1246 
1247     retval = DialogBoxParamA(g_hinst, "GETDLGITEM_TEST_DIALOG", NULL, getdlgitem_test_dialog_proc, 0);
1248     ok(retval == 0xdead, "Unexpected return value.\n");
1249 }
1250 
1251 static INT_PTR CALLBACK DestroyDlgWinProc (HWND hDlg, UINT uiMsg,
1252         WPARAM wParam, LPARAM lParam)
1253 {
1254     if (uiMsg == WM_INITDIALOG)
1255     {
1256         DestroyWindow(hDlg);
1257         return TRUE;
1258     }
1259     return FALSE;
1260 }
1261 
1262 static INT_PTR CALLBACK DestroyOnCloseDlgWinProc (HWND hDlg, UINT uiMsg,
1263         WPARAM wParam, LPARAM lParam)
1264 {
1265     switch (uiMsg)
1266     {
1267     case WM_INITDIALOG:
1268         PostMessageA(hDlg, WM_CLOSE, 0, 0);
1269         return TRUE;
1270     case WM_CLOSE:
1271         DestroyWindow(hDlg);
1272         return TRUE;
1273     case WM_DESTROY:
1274         PostQuitMessage(0);
1275         return TRUE;
1276     }
1277     return FALSE;
1278 }
1279 
1280 static INT_PTR CALLBACK TestInitDialogHandleProc (HWND hDlg, UINT uiMsg,
1281         WPARAM wParam, LPARAM lParam)
1282 {
1283     if (uiMsg == WM_INITDIALOG)
1284     {
1285         HWND expected = GetNextDlgTabItem(hDlg, NULL, FALSE);
1286         ok(expected == (HWND)wParam,
1287            "Expected wParam to be the handle to the first tabstop control (%p), got %p\n",
1288            expected, (HWND)wParam);
1289 
1290         EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1291         return TRUE;
1292     }
1293     return FALSE;
1294 }
1295 
1296 static INT_PTR CALLBACK TestDefButtonDlgProc (HWND hDlg, UINT uiMsg,
1297                                               WPARAM wParam, LPARAM lParam)
1298 {
1299     switch (uiMsg)
1300     {
1301     case WM_INITDIALOG:
1302         EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1303         return TRUE;
1304     }
1305     return FALSE;
1306 }
1307 
1308 static INT_PTR CALLBACK TestReturnKeyDlgProc (HWND hDlg, UINT uiMsg,
1309         WPARAM wParam, LPARAM lParam)
1310 {
1311     static int received_idok;
1312 
1313     switch (uiMsg)
1314     {
1315     case WM_INITDIALOG:
1316     {
1317         MSG msg = {hDlg, WM_KEYDOWN, VK_RETURN, 0x011c0001};
1318 
1319         received_idok = -1;
1320         IsDialogMessageA(hDlg, &msg);
1321         ok(received_idok == 0xdead, "WM_COMMAND/0xdead not received\n");
1322 
1323         received_idok = -2;
1324         IsDialogMessageA(hDlg, &msg);
1325         ok(received_idok == IDOK, "WM_COMMAND/IDOK not received\n");
1326 
1327         EndDialog(hDlg, 0);
1328         return TRUE;
1329     }
1330 
1331     case DM_GETDEFID:
1332         if (received_idok == -1)
1333         {
1334             HWND hwnd = GetDlgItem(hDlg, 0xdead);
1335             ok(!hwnd, "dialog item with ID 0xdead should not exist\n");
1336             SetWindowLongA(hDlg, DWLP_MSGRESULT, MAKELRESULT(0xdead, DC_HASDEFID));
1337             return TRUE;
1338         }
1339         return FALSE;
1340 
1341     case WM_COMMAND:
1342         received_idok = wParam;
1343         return TRUE;
1344     }
1345     return FALSE;
1346 }
1347 
1348 static INT_PTR CALLBACK TestControlStyleDlgProc(HWND hdlg, UINT msg,
1349                                                 WPARAM wparam, LPARAM lparam)
1350 {
1351     HWND control;
1352     DWORD style, exstyle;
1353     char buf[256];
1354 
1355     switch (msg)
1356     {
1357     case WM_INITDIALOG:
1358         control = GetDlgItem(hdlg, 7);
1359         ok(control != 0, "dialog control with id 7 not found\n");
1360         style = GetWindowLongA(control, GWL_STYLE);
1361         ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1362         exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1363         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);
1364         buf[0] = 0;
1365         GetWindowTextA(control, buf, sizeof(buf));
1366         ok(strcmp(buf, "bump7") == 0,  "expected bump7, got %s\n", buf);
1367 
1368         control = GetDlgItem(hdlg, 8);
1369         ok(control != 0, "dialog control with id 8 not found\n");
1370         style = GetWindowLongA(control, GWL_STYLE);
1371         ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1372         exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1373         ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT, got %#x\n", exstyle);
1374         buf[0] = 0;
1375         GetWindowTextA(control, buf, sizeof(buf));
1376         ok(strcmp(buf, "bump8") == 0,  "expected bump8, got %s\n", buf);
1377 
1378         EndDialog(hdlg, -7);
1379         return TRUE;
1380     }
1381     return FALSE;
1382 }
1383 
1384 static const WCHAR testtextW[] = {'W','n','d','T','e','x','t',0};
1385 static const char *testtext = "WndText";
1386 
1387 enum defdlgproc_text
1388 {
1389     DLGPROCTEXT_SNDMSGA = 0,
1390     DLGPROCTEXT_SNDMSGW,
1391     DLGPROCTEXT_DLGPROCA,
1392     DLGPROCTEXT_DLGPROCW,
1393     DLGPROCTEXT_SETTEXTA,
1394     DLGPROCTEXT_SETTEXTW,
1395 };
1396 
1397 static const char *testmodes[] =
1398 {
1399     "SNDMSGA",
1400     "SNDMSGW",
1401     "DLGPROCA",
1402     "DLGPROCW",
1403     "SETTEXTA",
1404     "SETTEXTW",
1405 };
1406 
1407 static INT_PTR CALLBACK test_aw_conversion_dlgprocA(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1408 {
1409     int mode = HandleToULong(GetPropA(hdlg, "test_mode"));
1410     WCHAR *text = (WCHAR *)lparam;
1411     char *textA = (char *)lparam;
1412 
1413     switch (msg)
1414     {
1415     case WM_SETTEXT:
1416     case WM_WININICHANGE:
1417     case WM_DEVMODECHANGE:
1418     case CB_DIR:
1419     case LB_DIR:
1420     case LB_ADDFILE:
1421     case EM_REPLACESEL:
1422         switch (mode)
1423         {
1424         case DLGPROCTEXT_DLGPROCA:
1425             ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A",
1426                 testmodes[mode], textA);
1427             break;
1428         case DLGPROCTEXT_DLGPROCW:
1429             ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A", testmodes[mode],
1430                 wine_dbgstr_w(text));
1431             break;
1432         case DLGPROCTEXT_SNDMSGA:
1433         case DLGPROCTEXT_SETTEXTA:
1434             if (IsWindowUnicode(hdlg))
1435             {
1436                 ok(text != testtextW && !lstrcmpW(text, testtextW),
1437                     "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1438             }
1439             else
1440                 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1441             break;
1442         case DLGPROCTEXT_SNDMSGW:
1443         case DLGPROCTEXT_SETTEXTW:
1444             if (IsWindowUnicode(hdlg))
1445                 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1446             else
1447                 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1448                     testmodes[mode], textA);
1449             break;
1450         }
1451         break;
1452     };
1453 
1454     return DefWindowProcW(hdlg, msg, wparam, lparam);
1455 }
1456 
1457 static INT_PTR CALLBACK test_aw_conversion_dlgprocW(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1458 {
1459     int mode = HandleToULong(GetPropA(hdlg, "test_mode"));
1460     WCHAR *text = (WCHAR *)lparam;
1461     char *textA = (char *)lparam;
1462 
1463     switch (msg)
1464     {
1465     case WM_SETTEXT:
1466     case WM_WININICHANGE:
1467     case WM_DEVMODECHANGE:
1468     case CB_DIR:
1469     case LB_DIR:
1470     case LB_ADDFILE:
1471     case EM_REPLACESEL:
1472         switch (mode)
1473         {
1474         case DLGPROCTEXT_DLGPROCA:
1475             ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A",
1476                 testmodes[mode], textA);
1477             break;
1478         case DLGPROCTEXT_DLGPROCW:
1479             ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A", testmodes[mode],
1480                 wine_dbgstr_w(text));
1481             break;
1482         case DLGPROCTEXT_SNDMSGA:
1483         case DLGPROCTEXT_SETTEXTA:
1484             if (IsWindowUnicode(hdlg))
1485                 ok(text != testtextW && !lstrcmpW(text, testtextW),
1486                     "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1487             else
1488                 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1489             break;
1490         case DLGPROCTEXT_SNDMSGW:
1491         case DLGPROCTEXT_SETTEXTW:
1492             if (IsWindowUnicode(hdlg))
1493                 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1494             else
1495                 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1496                     testmodes[mode], textA);
1497             break;
1498         }
1499         break;
1500     }
1501 
1502     return DefWindowProcA(hdlg, msg, wparam, lparam);
1503 }
1504 
1505 static void dlg_test_aw_message(HWND hdlg, UINT msg)
1506 {
1507     SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SNDMSGA));
1508     SendMessageA(hdlg, msg, 0, (LPARAM)testtext);
1509 
1510     SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SNDMSGW));
1511     SendMessageW(hdlg, msg, 0, (LPARAM)testtextW);
1512 
1513     SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_DLGPROCA));
1514     DefDlgProcA(hdlg, msg, 0, (LPARAM)testtext);
1515 
1516     SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_DLGPROCW));
1517     DefDlgProcW(hdlg, msg, 0, (LPARAM)testtextW);
1518 }
1519 
1520 static INT_PTR CALLBACK test_aw_conversion_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1521 {
1522     ULONG_PTR dlgproc, originalproc;
1523     WCHAR buffW[64];
1524     char buff[64];
1525     BOOL ret;
1526     INT len;
1527 
1528     switch (msg)
1529     {
1530     case WM_INITDIALOG:
1531         ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1532 
1533         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1534         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1535         dlg_test_aw_message(hdlg, CB_DIR);
1536         dlg_test_aw_message(hdlg, LB_DIR);
1537         dlg_test_aw_message(hdlg, LB_ADDFILE);
1538         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1539         dlg_test_aw_message(hdlg, WM_SETTEXT);
1540 
1541         /* WM_SETTEXT/WM_GETTEXT */
1542         originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1543         ok(originalproc == (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", originalproc);
1544 
1545         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1546         ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", dlgproc);
1547 
1548         dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocA);
1549         ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1550 
1551         dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1552         ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1553 
1554         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1555         ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1556 
1557         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1558         ret = SetWindowTextA(hdlg, testtext);
1559     todo_wine
1560         ok(ret, "Failed to set window text.\n");
1561 
1562         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1563         ret = SetWindowTextW(hdlg, testtextW);
1564     todo_wine
1565         ok(ret, "Failed to set window text.\n");
1566 
1567         memset(buff, 'A', sizeof(buff));
1568         len = GetWindowTextA(hdlg, buff, sizeof(buff));
1569         ok(buff[0] == 0 && buff[1] == 'A' && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1570            (BYTE)buff[0], (BYTE)buff[1], len);
1571 
1572         memset(buffW, 0xff, sizeof(buffW));
1573         len = GetWindowTextW(hdlg, buffW, 64);
1574         ok(!lstrcmpW(buffW, testtextW) && len == 0, "Unexpected window text %s, len %d\n", wine_dbgstr_w(buffW), len);
1575 
1576         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1577         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1578         dlg_test_aw_message(hdlg, CB_DIR);
1579         dlg_test_aw_message(hdlg, LB_DIR);
1580         dlg_test_aw_message(hdlg, LB_ADDFILE);
1581         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1582         dlg_test_aw_message(hdlg, WM_SETTEXT);
1583 
1584         dlgproc = SetWindowLongPtrW(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocW);
1585         ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1586 
1587         dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1588         ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1589 
1590         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1591         ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1592 
1593         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1594         ret = SetWindowTextA(hdlg, testtext);
1595     todo_wine
1596         ok(ret, "Failed to set window text.\n");
1597 
1598         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1599         ret = SetWindowTextW(hdlg, testtextW);
1600     todo_wine
1601         ok(ret, "Failed to set window text.\n");
1602 
1603         memset(buff, 'A', sizeof(buff));
1604         len = GetWindowTextA(hdlg, buff, sizeof(buff));
1605         ok(buff[0] == 0 && buff[1] == 'A' && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1606            (BYTE)buff[0], (BYTE)buff[1], len);
1607 
1608         memset(buffW, 0xff, sizeof(buffW));
1609         len = GetWindowTextW(hdlg, buffW, ARRAY_SIZE(buffW));
1610         ok(buffW[0] == 'W' && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1611             buffW[0], buffW[1], len);
1612 
1613         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1614         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1615         dlg_test_aw_message(hdlg, CB_DIR);
1616         dlg_test_aw_message(hdlg, LB_DIR);
1617         dlg_test_aw_message(hdlg, LB_ADDFILE);
1618         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1619         dlg_test_aw_message(hdlg, WM_SETTEXT);
1620 
1621         SetWindowLongPtrA(hdlg, DWLP_DLGPROC, originalproc);
1622         EndDialog(hdlg, -123);
1623         return TRUE;
1624     }
1625     return FALSE;
1626 }
1627 
1628 static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1629 {
1630     ULONG_PTR dlgproc, originalproc;
1631     WCHAR buffW[64];
1632     char buff[64];
1633     BOOL ret;
1634     INT len;
1635 
1636     switch (msg)
1637     {
1638     case WM_INITDIALOG:
1639         ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1640 
1641         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1642         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1643         dlg_test_aw_message(hdlg, CB_DIR);
1644         dlg_test_aw_message(hdlg, LB_DIR);
1645         dlg_test_aw_message(hdlg, LB_ADDFILE);
1646         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1647         dlg_test_aw_message(hdlg, WM_SETTEXT);
1648 
1649         originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1650         ok(originalproc != (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", originalproc);
1651 
1652         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1653         ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", dlgproc);
1654 
1655         dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocW);
1656         ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1657 
1658         dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1659         ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1660 
1661         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1662         ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1663 
1664         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1665         ret = SetWindowTextA(hdlg, testtext);
1666     todo_wine
1667         ok(ret, "Failed to set window text.\n");
1668 
1669         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1670         ret = SetWindowTextW(hdlg, testtextW);
1671     todo_wine
1672         ok(ret, "Failed to set window text.\n");
1673 
1674         memset(buff, 'A', sizeof(buff));
1675         len = GetWindowTextA(hdlg, buff, sizeof(buff));
1676         ok(!strcmp(buff, testtext) && len == 0, "Unexpected window text %s, len %d\n", buff, len);
1677 
1678         memset(buffW, 0xff, sizeof(buffW));
1679         len = GetWindowTextW(hdlg, buffW, 64);
1680         ok(buffW[0] == 0 && buffW[1] == 0xffff && len == 0, "Unexpected window text %s, len %d\n",
1681             wine_dbgstr_w(buffW), len);
1682 
1683         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1684         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1685         dlg_test_aw_message(hdlg, CB_DIR);
1686         dlg_test_aw_message(hdlg, LB_DIR);
1687         dlg_test_aw_message(hdlg, LB_ADDFILE);
1688         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1689         dlg_test_aw_message(hdlg, WM_SETTEXT);
1690 
1691         dlgproc = SetWindowLongPtrW(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocA);
1692         ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1693 
1694         dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1695         ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1696 
1697         dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1698         ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1699 
1700         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1701         ret = SetWindowTextA(hdlg, testtext);
1702     todo_wine
1703         ok(ret, "Failed to set window text.\n");
1704 
1705         SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1706         ret = SetWindowTextW(hdlg, testtextW);
1707     todo_wine
1708         ok(ret, "Failed to set window text.\n");
1709 
1710         memset(buff, 'A', sizeof(buff));
1711         len = GetWindowTextA(hdlg, buff, sizeof(buff));
1712         ok(!strcmp(buff, testtext) && len == 0, "Unexpected window text %s, len %d\n", buff, len);
1713 
1714         memset(buffW, 0xff, sizeof(buffW));
1715         len = GetWindowTextW(hdlg, buffW, ARRAY_SIZE(buffW));
1716         ok(buffW[0] == 0 && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1717             buffW[0], buffW[1], len);
1718 
1719         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1720         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1721         dlg_test_aw_message(hdlg, CB_DIR);
1722         dlg_test_aw_message(hdlg, LB_DIR);
1723         dlg_test_aw_message(hdlg, LB_ADDFILE);
1724         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1725         dlg_test_aw_message(hdlg, WM_SETTEXT);
1726 
1727         SetWindowLongPtrA(hdlg, DWLP_DLGPROC, originalproc);
1728         EndDialog(hdlg, -123);
1729         return TRUE;
1730     }
1731     return FALSE;
1732 }
1733 
1734 static LRESULT CALLBACK test_aw_conversion_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1735 {
1736     WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1737     int mode = HandleToULong(GetPropA(hwnd, "test_mode"));
1738     WCHAR *text = (WCHAR *)lparam;
1739     char *textA = (char *)lparam;
1740 
1741     switch (msg)
1742     {
1743     case WM_SETTEXT:
1744     case WM_WININICHANGE:
1745     case WM_DEVMODECHANGE:
1746     case CB_DIR:
1747     case LB_DIR:
1748     case LB_ADDFILE:
1749     case EM_REPLACESEL:
1750         switch (mode)
1751         {
1752         case DLGPROCTEXT_SNDMSGA:
1753             if (IsWindowUnicode(hwnd))
1754                 ok(text != testtextW && !lstrcmpW(text, testtextW),
1755                     "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1756             else
1757                 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1758             break;
1759         case DLGPROCTEXT_SNDMSGW:
1760             if (IsWindowUnicode(hwnd))
1761                 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1762             else
1763                 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1764                     testmodes[mode], textA);
1765             break;
1766         default:
1767             ok(0, "Unexpected test mode %d.\n", mode);
1768         }
1769         break;
1770     }
1771 
1772     return IsWindowUnicode(hwnd) ? CallWindowProcW(oldproc, hwnd, msg, wparam, lparam) :
1773         CallWindowProcA(oldproc, hwnd, msg, wparam, lparam);
1774 }
1775 
1776 static INT_PTR CALLBACK test_aw_conversion_dlgproc3(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1777 {
1778     BOOL is_unicode = !!lparam;
1779     LONG_PTR oldproc;
1780 
1781     switch (msg)
1782     {
1783     case WM_INITDIALOG:
1784         ok(is_unicode == IsWindowUnicode(hdlg), "Unexpected unicode window property.\n");
1785 
1786         oldproc = SetWindowLongPtrA(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
1787         SetWindowLongPtrA(hdlg, GWLP_USERDATA, oldproc);
1788         ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1789 
1790         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1791         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1792         dlg_test_aw_message(hdlg, CB_DIR);
1793         dlg_test_aw_message(hdlg, LB_DIR);
1794         dlg_test_aw_message(hdlg, LB_ADDFILE);
1795         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1796         dlg_test_aw_message(hdlg, WM_SETTEXT);
1797 
1798         SetWindowLongPtrW(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
1799         ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1800 
1801         dlg_test_aw_message(hdlg, WM_WININICHANGE);
1802         dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1803         dlg_test_aw_message(hdlg, CB_DIR);
1804         dlg_test_aw_message(hdlg, LB_DIR);
1805         dlg_test_aw_message(hdlg, LB_ADDFILE);
1806         dlg_test_aw_message(hdlg, EM_REPLACESEL);
1807         dlg_test_aw_message(hdlg, WM_SETTEXT);
1808 
1809         SetWindowLongPtrA(hdlg, GWLP_WNDPROC, oldproc);
1810         EndDialog(hdlg, -123);
1811         return TRUE;
1812     }
1813     return FALSE;
1814 }
1815 
1816 static void test_DialogBoxParam(void)
1817 {
1818     static const WCHAR nameW[] = {'T','E','S','T','_','E','M','P','T','Y','_','D','I','A','L','O','G',0};
1819     INT_PTR ret;
1820     HWND hwnd_invalid = (HWND)0x4444;
1821 
1822     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DLG_CHILD_POPUP", 0, TestControlStyleDlgProc, 0);
1823     ok(ret == -7, "expected -7, got %ld\n", ret);
1824 
1825     SetLastError(0xdeadbeef);
1826     ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0);
1827     ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %ld, expected 0\n", ret);
1828     ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1829        broken(GetLastError() == 0xdeadbeef),
1830        "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1831 
1832     /* Test a dialog which destroys itself on WM_INITDIALOG. */
1833     SetLastError(0xdeadbeef);
1834     ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyDlgWinProc, 0);
1835     ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1836     ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1837        GetLastError() == ERROR_SUCCESS ||
1838        broken(GetLastError() == 0xdeadbeef),
1839        "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1840 
1841     /* Test a dialog which destroys itself on WM_CLOSE. */
1842     ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyOnCloseDlgWinProc, 0);
1843     ok(0 == ret, "DialogBoxParamA returned %ld, expected 0\n", ret);
1844 
1845     SetLastError(0xdeadbeef);
1846     ret = DialogBoxParamA(GetModuleHandleA(NULL), "RESOURCE_INVALID" , 0, 0, 0);
1847     ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1848     ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() ||
1849        broken(GetLastError() == 0xdeadbeef),
1850        "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError());
1851 
1852     SetLastError(0xdeadbeef);
1853     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DIALOG_INVALID_CLASS", 0, DestroyDlgWinProc, 0);
1854     ok(ret == -1, "DialogBoxParamA returned %ld, expected -1\n", ret);
1855     ok(GetLastError() == 0, "got %d\n", GetLastError());
1856 
1857     SetLastError(0xdeadbeef);
1858     ret = DefDlgProcA(0, WM_ERASEBKGND, 0, 0);
1859     ok(ret == 0, "DefDlgProcA returned %ld, expected 0\n", ret);
1860     ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1861        broken(GetLastError() == 0xdeadbeef),
1862        "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError());
1863 
1864     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestInitDialogHandleProc, 0);
1865     ok(ret == IDOK, "Expected IDOK\n");
1866 
1867     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestDefButtonDlgProc, 0);
1868     ok(ret == IDOK, "Expected IDOK\n");
1869 
1870     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestReturnKeyDlgProc, 0);
1871     ok(ret == 0, "Unexpected ret value %ld.\n", ret);
1872 
1873     /* WM_SETTEXT handling in case of A/W dialog procedures vs A/W dialog window.  */
1874     ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc, 0);
1875     ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1876 
1877     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc2, 0);
1878     ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1879 
1880     ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc3, 1);
1881     ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1882 
1883     ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc3, 0);
1884     ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1885 }
1886 
1887 static void test_DisabledDialogTest(void)
1888 {
1889     g_terminated = FALSE;
1890     DialogBoxParamA(g_hinst, "IDD_DIALOG", NULL, disabled_test_proc, 0);
1891     ok(FALSE == g_terminated, "dialog with disabled ok button has been terminated\n");
1892 }
1893 
1894 static INT_PTR CALLBACK messageBoxFontDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
1895         LPARAM lParam)
1896 {
1897     if (uiMsg == WM_INITDIALOG) {
1898         SetFocus(hDlg);
1899         return 1;
1900     }
1901 
1902     return 0;
1903 }
1904 
1905 static void test_MessageBoxFontTest(void)
1906 {
1907     /* This dialog template defines a dialog template which got 0x7fff as its
1908      * font size and omits the other font members. On WinNT, passing such a
1909      * dialog template to CreateDialogIndirectParamW will result in a dialog
1910      * being created which uses the message box font. We test that here.
1911      */
1912 
1913     static unsigned char dlgTemplate[] =
1914     {
1915         /* Dialog header */
1916         0x01,0x00,              /* Version */
1917         0xff,0xff,              /* Extended template marker */
1918         0x00,0x00,0x00,0x00,    /* Context Help ID */
1919         0x00,0x00,0x00,0x00,    /* Extended style */
1920         0xc0,0x00,0xc8,0x80,    /* Style (WS_SYSMENU|WS_CAPTION|WS_POPUP|DS_SETFONT|DS_MODALFRAME) */
1921         0x01,0x00,              /* Control count */
1922         0x00,0x00,              /* X */
1923         0x00,0x00,              /* Y */
1924         0x80,0x00,              /* Width */
1925         0x80,0x00,              /* Height */
1926         0x00,0x00,              /* Menu name */
1927         0x00,0x00,              /* Class name */
1928         'T',0x00,'e',0x00,      /* Caption (unicode) */
1929         's',0x00,'t',0x00,
1930         0x00,0x00,
1931         0xff,0x7f,              /* Font height (0x7fff = message box font) */
1932 
1933         /* Control #1 */
1934         0x00,0x00,              /* Align to DWORD (header is 42 bytes) */
1935         0x00,0x00,0x00,0x00,    /* Context Help ID */
1936         0x00,0x00,0x00,0x00,    /* Extended style */
1937         0x00,0x00,0x00,0x50,    /* Style (WS_CHILD|WS_VISIBLE) */
1938         0x00,0x00,              /* X */
1939         0x00,0x00,              /* Y */
1940         0x80,0x00,              /* Width */
1941         0x80,0x00,              /* Height */
1942         0x00,0x01,0x00,0x00,    /* Control ID (256) */
1943         0xff,0xff,0x82,0x00,    /* Class (Static) */
1944         'W',0x00,'I',0x00,      /* Caption (unicode) */
1945         'N',0x00,'E',0x00,
1946         ' ',0x00,'d',0x00,
1947         'i',0x00,'a',0x00,
1948         'l',0x00,'o',0x00,
1949         'g',0x00,' ',0x00,
1950         't',0x00,'e',0x00,
1951         's',0x00,'t',0x00,
1952         '.',0x00,0x00,0x00,
1953         0x00,0x00,              /* Size of extended data */
1954 
1955         0x00,0x00               /* Align to DWORD */
1956     };
1957 
1958     HWND hDlg;
1959     HFONT hFont;
1960     LOGFONTW lfStaticFont;
1961     NONCLIENTMETRICSW ncMetrics;
1962 
1963     /* Check if the dialog can be created from the template. On Win9x, this should fail
1964      * because we are calling the W function which is not implemented, but that's what
1965      * we want, because passing such a template to CreateDialogIndirectParamA would crash
1966      * anyway.
1967      */
1968     hDlg = CreateDialogIndirectParamW(g_hinst, (LPCDLGTEMPLATEW)dlgTemplate, NULL, messageBoxFontDlgWinProc, 0);
1969     if (!hDlg)
1970     {
1971         win_skip("dialog wasn't created\n");
1972         return;
1973     }
1974 
1975     hFont = (HFONT) SendDlgItemMessageW(hDlg, 256, WM_GETFONT, 0, 0);
1976     if (!hFont)
1977     {
1978         skip("dialog uses system font\n");
1979         DestroyWindow(hDlg);
1980         return;
1981     }
1982     GetObjectW(hFont, sizeof(LOGFONTW), &lfStaticFont);
1983 
1984     ncMetrics.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth);
1985     SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0);
1986     ok( !memcmp(&lfStaticFont, &ncMetrics.lfMessageFont, FIELD_OFFSET(LOGFONTW, lfFaceName)) &&
1987         !lstrcmpW(lfStaticFont.lfFaceName, ncMetrics.lfMessageFont.lfFaceName),
1988         "dialog doesn't use message box font\n");
1989     DestroyWindow(hDlg);
1990 }
1991 
1992 static const char msgbox_title[] = "%5!z9ZXw*ia;57n/FGl.bCH,Su\"mfKN;foCqAU\'j6AmoJgAc_D:Z0A\'E6PF_O/w";
1993 static WCHAR expectedOK[] =
1994 {
1995 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
1996 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
1997 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
1998 'F','_','O','/','w','\r','\n',
1999 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2000 'M','e','s','s','a','g','e','\r','\n',
2001 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2002 'O','K',' ',' ',' ','\r','\n',
2003 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2004 };
2005 static WCHAR expectedOkCancel[] =
2006 {
2007 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2008 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2009 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2010 'F','_','O','/','w','\r','\n',
2011 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2012 'M','e','s','s','a','g','e','\r','\n',
2013 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2014 'O','K',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
2015 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2016 };
2017 static WCHAR expectedAbortRetryIgnore[] =
2018 {
2019 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2020 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2021 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2022 'F','_','O','/','w','\r','\n',
2023 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2024 'M','e','s','s','a','g','e','\r','\n',
2025 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2026 'A','b','o','r','t',' ',' ',' ','R','e','t','r','y',' ',' ',' ','I','g','n','o','r','e',' ',' ',' ','\r','\n',
2027 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2028 };
2029 
2030 static WCHAR expectedYesNo[] =
2031 {
2032 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2033 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2034 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2035 'F','_','O','/','w','\r','\n',
2036 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2037 'M','e','s','s','a','g','e','\r','\n',
2038 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2039 'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','\r','\n',
2040 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2041 };
2042 static WCHAR expectedYesNoCancel[] =
2043 {
2044 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2045 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2046 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2047 'F','_','O','/','w','\r','\n',
2048 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2049 'M','e','s','s','a','g','e','\r','\n',
2050 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2051 'Y','e','s',' ',' ',' ','N','o',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
2052 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2053 };
2054 static WCHAR expectedRetryCancel[] =
2055 {
2056 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2057 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2058 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2059 'F','_','O','/','w','\r','\n',
2060 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2061 'M','e','s','s','a','g','e','\r','\n',
2062 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2063 'R','e','t','r','y',' ',' ',' ','C','a','n','c','e','l',' ',' ',' ','\r','\n',
2064 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2065 };
2066 static WCHAR expectedCancelTryContinue[] =
2067 {
2068 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2069 '%','5','!','z','9','Z','X','w','*','i','a',';','5','7','n','/','F','G','l','.','b','C','H',',','S','u','"','m','f',
2070 'K','N',';','f','o','C','q','A','U','\'','j','6','A','m','o','J','g','A','c','_','D',':','Z','0','A','\'','E','6','P',
2071 'F','_','O','/','w','\r','\n',
2072 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2073 'M','e','s','s','a','g','e','\r','\n',
2074 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n',
2075 'C','a','n','c','e','l',' ',' ',' ','T','r','y',' ','A','g','a','i','n',' ',' ',' ','C','o','n','t','i','n','u','e',' ',' ',' ','\r','\n',
2076 '-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\r','\n', 0
2077 };
2078 
2079 BOOL non_english = FALSE;
2080 
2081 DWORD WINAPI WorkerThread(void *param)
2082 {
2083     WCHAR *expected = param;
2084     char windowTitle[sizeof(msgbox_title)];
2085     HWND hwndMbox;
2086     BOOL succeeded = FALSE;
2087 
2088     Sleep(200);
2089 
2090     hwndMbox = GetForegroundWindow();
2091 
2092     /* Find the Window, if it doesn't have focus */
2093     if (!(IsWindow(hwndMbox) &&
2094         GetWindowTextA(hwndMbox, windowTitle, sizeof(msgbox_title)) &&
2095         lstrcmpA(msgbox_title, windowTitle) == 0))
2096     {
2097         hwndMbox = FindWindowA(NULL, msgbox_title);
2098 
2099         if (!IsWindow(hwndMbox))
2100             goto cleanup;
2101     }
2102 
2103     SendMessageA(hwndMbox, WM_COPY, 0, 0);
2104 
2105     if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
2106     {
2107         HANDLE textHandle = GetClipboardData(CF_UNICODETEXT);
2108         WCHAR *text = GlobalLock(textHandle);
2109 
2110         if (text != NULL)
2111         {
2112             if(non_english)
2113                 ok(lstrlenW(text) > 0, "Empty string on clipboard\n");
2114             else
2115             {
2116                 succeeded = lstrcmpW(expected, text) == 0;
2117                 if(!succeeded)
2118                 {
2119                     ok(0, "%s\n", wine_dbgstr_w(text));
2120                     ok(0, "%s\n", wine_dbgstr_w(expected));
2121                 }
2122             }
2123 
2124             GlobalUnlock(textHandle);
2125         }
2126         else
2127             ok(0, "No text on clipboard.\n");
2128 
2129         CloseClipboard();
2130 
2131     }
2132     else
2133         trace("Clipboard error\n");
2134 
2135     PostMessageA(hwndMbox, WM_COMMAND, IDIGNORE, 0); /* For MB_ABORTRETRYIGNORE dialog. */
2136     PostMessageA(hwndMbox, WM_CLOSE, 0, 0);
2137 
2138 cleanup:
2139     ok(succeeded || non_english, "Failed to get string.\n");
2140 
2141     return 0;
2142 }
2143 
2144 static void test_MessageBox_WM_COPY_Test(void)
2145 {
2146     DWORD tid = 0;
2147 
2148     non_english = (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH);
2149     trace("non_english %d\n", non_english);
2150 
2151     CreateThread(NULL, 0, WorkerThread, &expectedOK, 0, &tid);
2152     MessageBoxA(NULL, "Message", msgbox_title, MB_OK);
2153 
2154     CreateThread(NULL, 0, WorkerThread, &expectedOkCancel, 0, &tid);
2155     MessageBoxA(NULL, "Message", msgbox_title, MB_OKCANCEL);
2156 
2157     CreateThread(NULL, 0, WorkerThread, &expectedAbortRetryIgnore, 0, &tid);
2158     MessageBoxA(NULL, "Message", msgbox_title, MB_ABORTRETRYIGNORE);
2159 
2160     CreateThread(NULL, 0, WorkerThread, &expectedYesNo, 0, &tid);
2161     MessageBoxA(NULL, "Message", msgbox_title, MB_YESNO);
2162 
2163     CreateThread(NULL, 0, WorkerThread, &expectedYesNoCancel, 0, &tid);
2164     MessageBoxA(NULL, "Message", msgbox_title, MB_YESNOCANCEL);
2165 
2166     CreateThread(NULL, 0, WorkerThread, &expectedRetryCancel, 0, &tid);
2167     MessageBoxA(NULL, "Message", msgbox_title, MB_RETRYCANCEL);
2168 
2169     CreateThread(NULL, 0, WorkerThread, &expectedCancelTryContinue, 0, &tid);
2170     MessageBoxA(NULL, "Message", msgbox_title, MB_CANCELTRYCONTINUE);
2171 }
2172 
2173 static void test_SaveRestoreFocus(void)
2174 {
2175     HWND hDlg;
2176     HRSRC hResource;
2177     HANDLE hTemplate;
2178     DLGTEMPLATE* pTemplate;
2179     LONG_PTR foundId;
2180     HWND foundHwnd;
2181 
2182     /* create the dialog */
2183     hResource = FindResourceA(g_hinst, "MULTI_EDIT_DIALOG", (LPCSTR)RT_DIALOG);
2184     hTemplate = LoadResource(g_hinst, hResource);
2185     pTemplate = LockResource(hTemplate);
2186 
2187     hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, messageBoxFontDlgWinProc, 0);
2188     ok (hDlg != 0, "Failed to create test dialog.\n");
2189 
2190     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2191     ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %ld\n", 1000, foundId);
2192 
2193     SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
2194     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
2195     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2196     ok (foundId == 1001, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
2197     SetFocus(GetNextDlgTabItem(hDlg, NULL, FALSE));
2198 
2199     /* de- then reactivate the dialog */
2200     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
2201     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
2202 
2203     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2204     ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1000, foundId);
2205 
2206     /* select the next tabbable item */
2207     SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
2208 
2209     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2210     ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
2211 
2212     /* de- then reactivate the dialog */
2213     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
2214     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
2215 
2216     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2217     ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
2218 
2219     /* set focus to the dialog */
2220     SetFocus(hDlg);
2221 
2222     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2223     ok (foundId == 1000, "First edit box should have gained focus on dialog focus. Expected: %d, Found: %ld\n", 1000, foundId);
2224 
2225     /* select second tabbable item */
2226     SetFocus(GetNextDlgTabItem(hDlg, GetNextDlgTabItem(hDlg, NULL, FALSE), FALSE));
2227 
2228     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2229     ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
2230 
2231     /* send WM_ACTIVATE message to already active dialog */
2232     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
2233 
2234     foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
2235     ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
2236 
2237     /* disable the 2nd box */
2238     EnableWindow(GetFocus(), FALSE);
2239 
2240     foundHwnd = GetFocus();
2241     ok (foundHwnd == NULL, "Second edit box should have lost focus after being disabled. Expected: %p, Found: %p\n", NULL, foundHwnd);
2242 
2243     /* de- then reactivate the dialog */
2244     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
2245     SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
2246 
2247     foundHwnd = GetFocus();
2248     ok (foundHwnd == NULL, "No controls should have gained focus after dialog reactivation. Expected: %p, Found: %p\n", NULL, foundHwnd);
2249 
2250     /* clean up */
2251     DestroyWindow(hDlg);
2252 }
2253 
2254 static INT_PTR CALLBACK timer_message_dlg_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
2255 {
2256     static int count;
2257     BOOL visible;
2258 
2259     switch (msg)
2260     {
2261         case WM_INITDIALOG:
2262             visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
2263             ok(!visible, "Dialog should not be visible.\n");
2264             SetTimer(wnd, 1, 100, NULL);
2265             Sleep(200);
2266             return FALSE;
2267 
2268         case WM_COMMAND:
2269             if (LOWORD(wparam) != IDCANCEL) return FALSE;
2270             EndDialog(wnd, LOWORD(wparam));
2271             return TRUE;
2272 
2273         case WM_TIMER:
2274             if (wparam != 1) return FALSE;
2275             visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
2276             if (!count++)
2277             {
2278                 ok(!visible, "Dialog should not be visible.\n");
2279                 PostMessageA(wnd, WM_USER, 0, 0);
2280             }
2281             else
2282             {
2283                 ok(visible, "Dialog should be visible.\n");
2284                 PostMessageA(wnd, WM_COMMAND, IDCANCEL, 0);
2285             }
2286             return TRUE;
2287 
2288         case WM_USER:
2289             visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
2290             ok(visible, "Dialog should be visible.\n");
2291             return TRUE;
2292 
2293         default:
2294             return FALSE;
2295     }
2296 }
2297 
2298 static void test_timer_message(void)
2299 {
2300     DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc);
2301 }
2302 
2303 static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam)
2304 {
2305     if (code == HCBT_ACTIVATE)
2306     {
2307         HWND msgbox = (HWND)wParam, msghwnd;
2308         char text[64];
2309 
2310         if (msgbox)
2311         {
2312             text[0] = 0;
2313             GetWindowTextA(msgbox, text, sizeof(text));
2314             ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text);
2315 
2316             msghwnd = GetDlgItem(msgbox, 0xffff);
2317             ok(msghwnd != NULL, "Expected static control\n");
2318 
2319             text[0] = 0;
2320             GetWindowTextA(msghwnd, text, sizeof(text));
2321             ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text);
2322 
2323             SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0);
2324             SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0);
2325         }
2326     }
2327 
2328     return CallNextHookEx(NULL, code, wParam, lParam);
2329 }
2330 
2331 struct create_window_params
2332 {
2333     BOOL owner;
2334     char caption[64];
2335     DWORD style;
2336 };
2337 
2338 static DWORD WINAPI create_window_thread(void *param)
2339 {
2340     struct create_window_params *p = param;
2341     HWND owner = 0;
2342 
2343     if (p->owner)
2344     {
2345         owner = CreateWindowExA(0, "Static", NULL, WS_POPUP, 10, 10, 10, 10, 0, 0, 0, NULL);
2346         ok(owner != 0, "failed to create owner window\n");
2347     }
2348 
2349     MessageBoxA(owner, NULL, p->caption, p->style);
2350 
2351     if (owner) DestroyWindow(owner);
2352 
2353     return 0;
2354 }
2355 
2356 static HWND wait_for_window(const char *caption)
2357 {
2358     HWND hwnd;
2359     DWORD timeout = 0;
2360 
2361     for (;;)
2362     {
2363         hwnd = FindWindowA(NULL, caption);
2364         if (hwnd) break;
2365 
2366         Sleep(50);
2367         timeout += 50;
2368         if (timeout > 3000)
2369         {
2370             ok(0, "failed to wait for a window %s\n", caption);
2371             break;
2372         }
2373     }
2374 
2375     Sleep(50);
2376     return hwnd;
2377 }
2378 
2379 static void test_MessageBox(void)
2380 {
2381     static const struct
2382     {
2383         DWORD mb_style;
2384         DWORD ex_style;
2385     } test[] =
2386     {
2387         { MB_OK, 0 },
2388         { MB_OK | MB_TASKMODAL, 0 },
2389         { MB_OK | MB_SYSTEMMODAL, WS_EX_TOPMOST },
2390     };
2391     struct create_window_params params;
2392     HANDLE thread;
2393     DWORD tid, i;
2394     HHOOK hook;
2395     int ret;
2396 
2397     hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId());
2398 
2399     ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL);
2400     ok(ret == IDCANCEL, "got %d\n", ret);
2401 
2402     UnhookWindowsHookEx(hook);
2403 
2404     sprintf(params.caption, "pid %08x, tid %08x, time %08x",
2405             GetCurrentProcessId(), GetCurrentThreadId(), GetCurrentTime());
2406 
2407     params.owner = FALSE;
2408 
2409     for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
2410     {
2411         HWND hwnd;
2412         DWORD ex_style;
2413 
2414         params.style = test[i].mb_style;
2415 
2416         thread = CreateThread(NULL, 0, create_window_thread, &params, 0, &tid);
2417 
2418         hwnd = wait_for_window(params.caption);
2419         ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE);
2420         ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style);
2421 
2422         PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
2423 
2424         ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n");
2425         CloseHandle(thread);
2426     }
2427 
2428     params.owner = TRUE;
2429 
2430     for (i = 0; i < sizeof(test)/sizeof(test[0]); i++)
2431     {
2432         HWND hwnd;
2433         DWORD ex_style;
2434 
2435         params.style = test[i].mb_style;
2436 
2437         thread = CreateThread(NULL, 0, create_window_thread, &params, 0, &tid);
2438 
2439         hwnd = wait_for_window(params.caption);
2440         ex_style = GetWindowLongA(hwnd, GWL_EXSTYLE);
2441         ok((ex_style & WS_EX_TOPMOST) == test[i].ex_style, "%d: got window ex_style %#x\n", i, ex_style);
2442 
2443         PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
2444 
2445         ok(WaitForSingleObject(thread, 5000) != WAIT_TIMEOUT, "thread failed to terminate\n");
2446         CloseHandle(thread);
2447     }
2448 }
2449 
2450 static INT_PTR CALLBACK custom_test_dialog_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
2451 {
2452     if (msg == WM_INITDIALOG)
2453         EndDialog(hdlg, 0);
2454 
2455     return FALSE;
2456 }
2457 
2458 static void test_dialog_custom_data(void)
2459 {
2460     DialogBoxA(g_hinst, "CUSTOM_TEST_DIALOG", NULL, custom_test_dialog_proc);
2461 }
2462 
2463 START_TEST(dialog)
2464 {
2465     g_hinst = GetModuleHandleA (0);
2466 
2467     if (!RegisterWindowClasses()) assert(0);
2468 
2469     test_dialog_custom_data();
2470     test_GetNextDlgItem();
2471     test_IsDialogMessage();
2472     test_WM_NEXTDLGCTL();
2473     test_focus();
2474     test_GetDlgItem();
2475     test_GetDlgItemText();
2476     test_DialogBoxParam();
2477     test_DisabledDialogTest();
2478     test_MessageBoxFontTest();
2479     test_SaveRestoreFocus();
2480     test_timer_message();
2481     test_MessageBox();
2482     test_MessageBox_WM_COPY_Test();
2483 }
2484