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