user32: Don't convert message arguments when calling dialog procedure.
[wine.git] / dlls / user32 / tests / dialog.c
blobab3eec88bc1fbfbb45975d1f9b2573344db22a6f
1 /* Unit test suite for the dialog functions.
3 * Copyright 2004 Bill Medland
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.
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.
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
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.
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.
32 #define WINVER 0x0600 /* For NONCLIENTMETRICS with padding */
34 #include <assert.h>
35 #include <stdio.h>
36 #include <stdarg.h>
38 #include "wine/test.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "wingdi.h"
42 #include "winuser.h"
44 #define MAXHWNDS 1024
45 static HWND hwnd [MAXHWNDS];
46 static unsigned int numwnds=1; /* 0 is reserved for null */
48 /* Global handles */
49 static HINSTANCE g_hinst; /* This application's HINSTANCE */
50 static HWND g_hwndMain, g_hwndButton1, g_hwndButton2, g_hwndButtonCancel;
51 static HWND g_hwndTestDlg, g_hwndTestDlgBut1, g_hwndTestDlgBut2, g_hwndTestDlgEdit;
52 static HWND g_hwndInitialFocusT1, g_hwndInitialFocusT2, g_hwndInitialFocusGroupBox;
54 static LONG g_styleInitialFocusT1, g_styleInitialFocusT2;
55 static BOOL g_bInitialFocusInitDlgResult, g_bReceivedCommand;
57 static BOOL g_terminated;
59 typedef struct {
60 INT_PTR id;
61 int parent;
62 DWORD style;
63 DWORD exstyle;
64 } h_entry;
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}
150 static BOOL CreateWindows (HINSTANCE hinst)
152 const h_entry *p = hierarchy;
154 while (p->id != 0)
156 DWORD style, exstyle;
157 char ctrlname[9];
159 /* Basically assert that the hierarchy is valid and track the
160 * maximum control number
162 if (p->id >= numwnds)
164 if (p->id >= sizeof(hwnd)/sizeof(hwnd[0]))
166 trace ("Control %ld is out of range\n", p->id);
167 return FALSE;
169 else
170 numwnds = p->id+1;
172 if (p->id <= 0)
174 trace ("Control %ld is out of range\n", p->id);
175 return FALSE;
177 if (hwnd[p->id] != 0)
179 trace ("Control %ld is used more than once\n", p->id);
180 return FALSE;
183 /* Create the control */
184 sprintf (ctrlname, "ctrl%4.4ld", p->id);
185 hwnd[p->id] = CreateWindowExA(p->exstyle, p->parent ? "static" : "GetNextDlgItemWindowClass", ctrlname, p->style, 10, 10, 10, 10, hwnd[p->parent], p->parent ? (HMENU) (2000 + p->id) : 0, hinst, 0);
186 if (!hwnd[p->id])
188 trace ("Failed to create control %ld\n", p->id);
189 return FALSE;
192 /* Check that the styles are as we specified (except the main one
193 * which is quite frequently messed up). If this keeps breaking then
194 * we could mask out the bits that don't concern us.
196 if (p->parent)
198 style = GetWindowLongA(hwnd[p->id], GWL_STYLE);
199 exstyle = GetWindowLongA(hwnd[p->id], GWL_EXSTYLE);
200 if (style != p->style || exstyle != p->exstyle)
202 trace ("Style mismatch at %ld: %8.8x %8.8x cf %8.8x %8.8x\n", p->id, style, exstyle, p->style, p->exstyle);
205 p++;
208 return TRUE;
211 /* Form the lParam of a WM_KEYDOWN message */
212 static DWORD KeyDownData (int repeat, int scancode, int extended, int wasdown)
214 return ((repeat & 0x0000FFFF) | ((scancode & 0x00FF) << 16) |
215 (extended ? 0x01000000 : 0) | (wasdown ? 0x40000000 : 0));
218 /* Form a WM_KEYDOWN VK_TAB message to the specified window */
219 static void FormTabMsg (MSG *pMsg, HWND hwnd)
221 pMsg->hwnd = hwnd;
222 pMsg->message = WM_KEYDOWN;
223 pMsg->wParam = VK_TAB;
224 pMsg->lParam = KeyDownData (1, 0x0F, 0, 0);
225 /* pMsg->time is not set. It shouldn't be needed */
226 /* pMsg->pt is ignored */
229 /* Form a WM_KEYDOWN VK_RETURN message to the specified window */
230 static void FormEnterMsg (MSG *pMsg, HWND hwnd)
232 pMsg->hwnd = hwnd;
233 pMsg->message = WM_KEYDOWN;
234 pMsg->wParam = VK_RETURN;
235 pMsg->lParam = KeyDownData (1, 0x1C, 0, 0);
236 /* pMsg->time is not set. It shouldn't be needed */
237 /* pMsg->pt is ignored */
240 /***********************************************************************
242 * The actual tests
245 typedef struct
247 int isok; /* or is it todo */
248 int test;
249 int dlg;
250 int ctl;
251 int tab;
252 int prev;
253 int res;
254 } test_record;
256 static int id (HWND h)
258 unsigned int i;
259 for (i = 0; i < numwnds; i++)
260 if (hwnd[i] == h)
261 return i;
262 return -1;
265 /* Tests
267 * Tests 1-8 test the hCtl argument of null or the dialog itself.
269 * 1. Prev Group of null is null
270 * 2. Prev Tab of null is null
271 * 3. Prev Group of hDlg in hDlg is null
272 * 4. Prev Tab of hDlg in hDlg is null
273 * 5. Next Group of null is first visible enabled child
274 * Check it skips invisible, disabled and both.
275 * 6. Next Tab of null is first visible enabled tabstop
276 * Check it skips invisible, disabled, nontabstop, and in combination.
277 * 7. Next Group of hDlg in hDlg is as of null
278 * 8. Next Tab of hDlg in hDlg is as of null
280 * Tests 9-14 test descent
282 * 9. DS_CONTROL does not result in descending the hierarchy for Tab Next
283 * 10. DS_CONTROL does not result in descending the hierarchy for Group Next
284 * 11. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Next
285 * 12. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Next
286 * 13. WS_EX_CONTROLPARENT results in descending the hierarchy for Tab Prev
287 * 14. WS_EX_CONTROLPARENT results in descending the hierarchy for Group Prev
289 * Tests 15-24 are the basic Prev/Next Group tests
291 * 15. Next Group of a visible enabled non-group control is the next visible
292 * enabled non-group control, if there is one before the next group
293 * 16. Next Group of a visible enabled non-group control wraps around to the
294 * beginning of the group on finding a control that starts another group.
295 * Note that the group is in the middle of the dialog.
296 * 17. As 16 except note that the next group is started with a disabled
297 * visible control.
298 * 18. As 16 except note that the next group is started with an invisible
299 * enabled control.
300 * 19. Next Group wraps around the controls of the dialog
301 * 20. Next Group is the same even if the initial control is disabled.
302 * 21. Next Group is the same even if the initial control is invisible.
303 * 22. Next Group is the same even if the initial control has the group style
304 * 23. Next Group returns the initial control if there is no visible enabled
305 * control in the group. (Initial control disabled and not group style).
306 * 24. Prev version of test 16.
307 * Prev Group of a visible enabled non-group control wraps around to the
308 * beginning of the group on finding a control that starts the group.
309 * Note that the group is in the middle of the dialog.
311 * In tests 25 to 28 the control is sitting under dialogs which do not have
312 * the WS_EX_CONTROLPARENT style and so cannot be reached from the top of
313 * the dialog.
315 * 25. Next Group of an inaccessible control is as if it were accessible
316 * 26. Prev Group of an inaccessible control begins searching at the highest
317 * level ancestor that did not permit recursion down the hierarchy
318 * 27. Next Tab of an inaccessible control is as if it were accessible
319 * 28. Prev Tab of an inaccessible control begins searching at the highest
320 * level ancestor that did not permit recursion down the hierarchy.
322 * Tests 29- are the basic Tab tests
324 * 29. Next Tab of a control is the next visible enabled control with the
325 * Tabstop style (N.B. skips disabled, invisible and non-tabstop)
326 * 30. Prev Tab of a control is the previous visible enabled control with the
327 * Tabstop style (N.B. skips disabled, invisible and non-tabstop)
328 * 31. Next Tab test with at least two layers of descent and finding the
329 * result not at the first control.
330 * 32. Next Tab test with at least two layers of descent with the descent and
331 * control at the start of each level.
332 * 33. Prev Tab test with at least two layers of descent and finding the
333 * result not at the last control.
334 * 34. Prev Tab test with at least two layers of descent with the descent and
335 * control at the end of each level.
337 * 35. Passing NULL may result in the first child being the one returned.
338 * (group test)
339 * 36. Passing NULL may result in the first child being the one returned.
340 * (tab test)
343 static void test_GetNextDlgItem(void)
345 static test_record test [] =
347 /* isok test dlg ctl tab prev res */
349 { 1, 1, 6, 0, 0, 1, 0},
350 { 1, 2, 6, 0, 1, 1, 0},
351 { 1, 3, 6, 6, 0, 1, 0},
352 { 1, 4, 6, 6, 1, 1, 0},
353 { 1, 5, 6, 0, 0, 0, 66},
354 { 1, 6, 6, 0, 1, 0, 67},
355 { 1, 7, 6, 6, 0, 0, 66},
356 { 1, 8, 6, 6, 1, 0, 67},
358 { 1, 9, 4, 83, 1, 0, 84},
359 { 1, 10, 4, 83, 0, 0, 5},
360 { 1, 11, 5, 81, 1, 0, 67},
361 { 1, 12, 5, 81, 0, 0, 66},
362 { 1, 13, 5, 82, 1, 1, 78},
364 { 1, 14, 5, 82, 0, 1, 79},
365 { 1, 15, 6, 70, 0, 0, 72},
366 { 1, 16, 6, 72, 0, 0, 25},
367 { 1, 17, 6, 75, 0, 0, 26},
368 { 1, 18, 6, 77, 0, 0, 76},
369 { 1, 19, 6, 79, 0, 0, 66},
370 { 1, 20, 6, 71, 0, 0, 72},
371 { 1, 21, 6, 64, 0, 0, 66},
373 { 1, 22, 6, 25, 0, 0, 70},
374 { 1, 23, 6, 68, 0, 0, 68},
375 { 1, 24, 6, 25, 0, 1, 72},
376 { 1, 25, 1, 70, 0, 0, 72},
377 /*{ 0, 26, 1, 70, 0, 1, 3}, Crashes Win95*/
378 { 1, 27, 1, 70, 1, 0, 72},
379 /*{ 0, 28, 1, 70, 1, 1, 61}, Crashes Win95*/
381 { 1, 29, 6, 67, 1, 0, 72},
382 { 1, 30, 6, 72, 1, 1, 67},
384 { 1, 35, 2, 0, 0, 0, 60},
385 { 1, 36, 2, 0, 1, 0, 60},
387 { 0, 0, 0, 0, 0, 0, 0} /* End of test */
389 const test_record *p = test;
391 ok (CreateWindows (g_hinst), "Could not create test windows\n");
393 while (p->dlg)
395 HWND a;
396 a = (p->tab ? GetNextDlgTabItem : GetNextDlgGroupItem) (hwnd[p->dlg], hwnd[p->ctl], p->prev);
397 todo_wine_if (!p->isok)
398 ok (a == hwnd[p->res], "Test %d: %s %s item of %d in %d was %d instead of %d\n", p->test, p->prev ? "Prev" : "Next", p->tab ? "Tab" : "Group", p->ctl, p->dlg, id(a), p->res);
399 p++;
404 * OnMainWindowCreate
406 static BOOL OnMainWindowCreate(HWND hwnd, LPCREATESTRUCTA lpcs)
408 g_hwndButton1 = CreateWindowA("button", "Button &1",
409 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON | BS_TEXT,
410 10, 10, 80, 80, hwnd, (HMENU)100, g_hinst, 0);
411 if (!g_hwndButton1) return FALSE;
413 g_hwndButton2 = CreateWindowA("button", "Button &2",
414 WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT,
415 110, 10, 80, 80, hwnd, (HMENU)200, g_hinst, 0);
416 if (!g_hwndButton2) return FALSE;
418 g_hwndButtonCancel = CreateWindowA("button", "Cancel",
419 WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
420 210, 10, 80, 80, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
421 if (!g_hwndButtonCancel) return FALSE;
423 return TRUE;
428 * OnTestDlgCreate
431 static BOOL OnTestDlgCreate (HWND hwnd, LPCREATESTRUCTA lpcs)
433 g_hwndTestDlgEdit = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING |
434 WS_EX_RIGHTSCROLLBAR | WS_EX_NOPARENTNOTIFY | WS_EX_CLIENTEDGE,
435 "Edit", "Edit",
436 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL,
437 16,33,184,24, hwnd, (HMENU)101, g_hinst, 0);
438 if (!g_hwndTestDlgEdit) return FALSE;
440 g_hwndTestDlgBut1 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
441 | WS_EX_NOPARENTNOTIFY,
442 "button", "Button &1",
443 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
444 204,33,30,24, hwnd, (HMENU)201, g_hinst, 0);
445 if (!g_hwndTestDlgBut1) return FALSE;
447 g_hwndTestDlgBut2 = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
448 | WS_EX_NOPARENTNOTIFY, "button",
449 "Button &2",
450 WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_TEXT,
451 90,102,80,24, hwnd, (HMENU)IDCANCEL, g_hinst, 0);
452 if (!g_hwndTestDlgBut2) return FALSE;
454 return TRUE;
457 static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam,
458 LPARAM lParam)
460 switch (uiMsg)
462 /* Add blank case statements for these to ensure we don't use them
463 * by mistake.
465 case DM_GETDEFID: break;
466 case DM_SETDEFID: break;
468 case WM_CREATE:
469 return (OnMainWindowCreate (hwnd,
470 (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
471 case WM_COMMAND:
472 if (wParam == IDCANCEL)
474 g_terminated = TRUE;
475 return 0;
477 break;
480 return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
483 static LRESULT CALLBACK disabled_test_proc (HWND hwnd, UINT uiMsg,
484 WPARAM wParam, LPARAM lParam)
486 switch (uiMsg)
488 case WM_INITDIALOG:
490 DWORD dw;
491 HWND hwndOk;
493 dw = SendMessageA(hwnd, DM_GETDEFID, 0, 0);
494 assert(DC_HASDEFID == HIWORD(dw));
495 hwndOk = GetDlgItem(hwnd, LOWORD(dw));
496 assert(hwndOk);
497 EnableWindow(hwndOk, FALSE);
499 PostMessageA(hwnd, WM_KEYDOWN, VK_RETURN, 0);
500 PostMessageA(hwnd, WM_COMMAND, IDCANCEL, 0);
501 break;
503 case WM_COMMAND:
504 if (wParam == IDOK)
506 g_terminated = TRUE;
507 EndDialog(hwnd, 0);
508 return 0;
510 else if (wParam == IDCANCEL)
512 EndDialog(hwnd, 0);
513 return 0;
515 break;
518 return DefWindowProcA (hwnd, uiMsg, wParam, lParam);
521 static LRESULT CALLBACK testDlgWinProc (HWND hwnd, UINT uiMsg, WPARAM wParam,
522 LPARAM lParam)
524 switch (uiMsg)
526 /* Add blank case statements for these to ensure we don't use them
527 * by mistake.
529 case DM_GETDEFID: break;
530 case DM_SETDEFID: break;
532 case WM_CREATE:
533 return (OnTestDlgCreate (hwnd,
534 (LPCREATESTRUCTA) lParam) ? 0 : (LRESULT) -1);
535 case WM_COMMAND:
536 if(LOWORD(wParam) == 300) g_bReceivedCommand = TRUE;
539 return DefDlgProcA (hwnd, uiMsg, wParam, lParam);
542 static BOOL RegisterWindowClasses (void)
544 WNDCLASSA cls;
546 cls.style = 0;
547 cls.lpfnWndProc = DefWindowProcA;
548 cls.cbClsExtra = 0;
549 cls.cbWndExtra = 0;
550 cls.hInstance = g_hinst;
551 cls.hIcon = NULL;
552 cls.hCursor = LoadCursorA (NULL, (LPCSTR)IDC_ARROW);
553 cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
554 cls.lpszMenuName = NULL;
555 cls.lpszClassName = "GetNextDlgItemWindowClass";
557 if (!RegisterClassA (&cls)) return FALSE;
559 cls.lpfnWndProc = main_window_procA;
560 cls.lpszClassName = "IsDialogMessageWindowClass";
562 if (!RegisterClassA (&cls)) return FALSE;
564 GetClassInfoA(0, "#32770", &cls);
565 cls.lpfnWndProc = testDlgWinProc;
566 cls.lpszClassName = "WM_NEXTDLGCTLWndClass";
567 if (!RegisterClassA (&cls)) return FALSE;
569 return TRUE;
572 static void test_WM_NEXTDLGCTL(void)
574 HWND child1, child2, child3;
575 MSG msg;
576 DWORD dwVal;
578 g_hwndTestDlg = CreateWindowExA( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR
579 | WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT | WS_EX_APPWINDOW,
580 "WM_NEXTDLGCTLWndClass",
581 "WM_NEXTDLGCTL Message test window",
582 WS_POPUPWINDOW | WS_CLIPSIBLINGS | WS_DLGFRAME | WS_OVERLAPPED |
583 WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK | DS_SETFONT | DS_MODALFRAME,
584 0, 0, 235, 135,
585 NULL, NULL, g_hinst, 0);
587 assert (g_hwndTestDlg);
588 assert (g_hwndTestDlgBut1);
589 assert (g_hwndTestDlgBut2);
590 assert (g_hwndTestDlgEdit);
593 * Test message DM_SETDEFID
596 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, IDCANCEL, 0 );
597 DefDlgProcA( g_hwndTestDlgBut1, BM_SETSTYLE, BS_DEFPUSHBUTTON, FALSE );
598 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
600 ok ( IDCANCEL == (LOWORD(dwVal)), "Did not set default ID\n" );
603 * Check whether message WM_NEXTDLGCTL is changing the focus to next control and if
604 * the destination control is a button, style of the button should be changed to
605 * BS_DEFPUSHBUTTON with out making it default.
609 * Keep the focus on Edit control.
612 if ( SetFocus( g_hwndTestDlgEdit ) )
614 ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't set on Edit control\n");
617 * Test message WM_NEXTDLGCTL
619 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
620 ok ((GetFocus() == g_hwndTestDlgBut1), "Focus didn't move to first button\n");
623 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
625 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
626 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
629 * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
630 * the style of default button changed to BS_PUSHBUTTON.
632 if ( IDCANCEL == (LOWORD(dwVal)) )
634 ok ( ((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
635 "Button1 style not set to BS_DEFPUSHBUTTON\n" );
637 ok ( !((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
638 "Button2's style not changed to BS_PUSHBUTTON\n" );
642 * Move focus to Button2 using "WM_NEXTDLGCTL"
644 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
645 ok ((GetFocus() == g_hwndTestDlgBut2), "Focus didn't move to second button\n");
648 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
650 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
651 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
654 * Check whether the style of the button which got the focus, changed to BS_DEFPUSHBUTTON and
655 * the style of button which lost the focus changed to BS_PUSHBUTTON.
657 if ( IDCANCEL == (LOWORD(dwVal)) )
659 ok ( ((GetWindowLongA( g_hwndTestDlgBut2, GWL_STYLE)) & BS_DEFPUSHBUTTON),
660 "Button2 style not set to BS_DEFPUSHBUTTON\n" );
662 ok ( !((GetWindowLongA( g_hwndTestDlgBut1, GWL_STYLE)) & BS_DEFPUSHBUTTON),
663 "Button1's style not changed to BS_PUSHBUTTON\n" );
667 * Move focus to Edit control using "WM_NEXTDLGCTL"
669 DefDlgProcA( g_hwndTestDlg, WM_NEXTDLGCTL, 0, 0 );
670 ok ((GetFocus() == g_hwndTestDlgEdit), "Focus didn't move to Edit control\n");
673 * Check whether the default button ID got changed by sending message "WM_NEXTDLGCTL"
675 dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
676 ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
679 /* test nested default buttons */
681 child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 50, 50,
682 g_hwndTestDlg, (HMENU)100, g_hinst, NULL);
683 ok(child1 != NULL, "failed to create first child\n");
684 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 60, 60, 30, 30,
685 g_hwndTestDlg, (HMENU)200, g_hinst, NULL);
686 ok(child2 != NULL, "failed to create second child\n");
687 /* create nested child */
688 child3 = CreateWindowA("button", "child3", WS_VISIBLE|WS_CHILD, 10, 10, 10, 10,
689 child1, (HMENU)300, g_hinst, NULL);
690 ok(child3 != NULL, "failed to create subchild\n");
692 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 200, 0);
693 dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
694 ok(LOWORD(dwVal) == 200, "expected 200, got %x\n", dwVal);
696 DefDlgProcA( g_hwndTestDlg, DM_SETDEFID, 300, 0);
697 dwVal = DefDlgProcA( g_hwndTestDlg, DM_GETDEFID, 0, 0);
698 ok(LOWORD(dwVal) == 300, "expected 300, got %x\n", dwVal);
699 ok(SendMessageW( child3, WM_GETDLGCODE, 0, 0) != DLGC_DEFPUSHBUTTON,
700 "expected child3 not to be marked as DLGC_DEFPUSHBUTTON\n");
702 g_bReceivedCommand = FALSE;
703 FormEnterMsg (&msg, child3);
704 ok(IsDialogMessageA(g_hwndTestDlg, &msg), "Did not handle the ENTER\n");
705 ok(g_bReceivedCommand, "Did not trigger the default Button action\n");
707 DestroyWindow(child3);
708 DestroyWindow(child2);
709 DestroyWindow(child1);
710 DestroyWindow(g_hwndTestDlg);
713 static LRESULT CALLBACK hook_proc(INT code, WPARAM wParam, LPARAM lParam)
715 ok(0, "unexpected hook called, code %d\n", code);
716 return CallNextHookEx(NULL, code, wParam, lParam);
719 static BOOL g_MSGF_DIALOGBOX;
720 static LRESULT CALLBACK hook_proc2(INT code, WPARAM wParam, LPARAM lParam)
722 ok(code == MSGF_DIALOGBOX, "unexpected hook called, code %d\n", code);
723 g_MSGF_DIALOGBOX = code == MSGF_DIALOGBOX;
724 return CallNextHookEx(NULL, code, wParam, lParam);
727 static void test_IsDialogMessage(void)
729 HHOOK hook;
730 MSG msg;
732 g_hwndMain = CreateWindowA("IsDialogMessageWindowClass", "IsDialogMessageWindowClass",
733 WS_OVERLAPPEDWINDOW,
734 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
735 NULL, NULL, g_hinst, 0);
737 assert (g_hwndMain);
738 assert (g_hwndButton1);
739 assert (g_hwndButtonCancel);
741 if (0)
743 /* crashes on Windows */
744 IsDialogMessageA(NULL, NULL);
745 IsDialogMessageA(g_hwndMain, NULL);
748 /* The focus should initially be nowhere. The first TAB should take it
749 * to the first button. The second TAB should take it to the Cancel
750 * button.
753 /* valid window, invalid message window */
754 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc2, NULL, GetCurrentThreadId());
755 FormTabMsg (&msg, (HWND)0xbeefbeef);
756 ok (!IsDialogMessageA(g_hwndMain, &msg), "expected failure\n");
757 ok(g_MSGF_DIALOGBOX, "hook wasn't called\n");
758 g_MSGF_DIALOGBOX = FALSE;
759 UnhookWindowsHookEx(hook);
761 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
762 FormTabMsg (&msg, g_hwndMain);
764 ok (!IsDialogMessageA(NULL, &msg), "expected failure\n");
765 ok (!IsDialogMessageA((HWND)0xbeefbeef, &msg), "expected failure\n");
767 UnhookWindowsHookEx(hook);
769 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle first TAB\n");
770 ok ((GetFocus() == g_hwndButton1), "Focus did not move to first button\n");
771 FormTabMsg (&msg, g_hwndButton1);
772 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle second TAB\n");
773 ok ((GetFocus() == g_hwndButtonCancel),
774 "Focus did not move to cancel button\n");
775 FormEnterMsg (&msg, g_hwndButtonCancel);
776 ok (IsDialogMessageA(g_hwndMain, &msg), "Did not handle the ENTER\n");
777 ok (g_terminated, "ENTER did not terminate\n");
779 /* matching but invalid window handles, NULL */
780 hook = SetWindowsHookExA(WH_MSGFILTER, hook_proc, NULL, GetCurrentThreadId());
782 FormTabMsg (&msg, NULL);
783 ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
785 /* matching but invalid window handles, not NULL */
786 FormTabMsg (&msg, (HWND)0xbeefbeef);
787 ok (!IsDialogMessageA(msg.hwnd, &msg), "expected failure\n");
789 UnhookWindowsHookEx(hook);
793 static INT_PTR CALLBACK delayFocusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
794 LPARAM lParam)
796 switch (uiMsg)
798 case WM_INITDIALOG:
799 g_hwndMain = hDlg;
800 g_hwndInitialFocusGroupBox = GetDlgItem(hDlg,100);
801 g_hwndButton1 = GetDlgItem(hDlg,200);
802 g_hwndButton2 = GetDlgItem(hDlg,201);
803 g_hwndButtonCancel = GetDlgItem(hDlg,IDCANCEL);
804 g_styleInitialFocusT1 = GetWindowLongA(g_hwndInitialFocusGroupBox, GWL_STYLE);
806 /* Initially check the second radio button */
807 SendMessageA(g_hwndButton1, BM_SETCHECK, BST_UNCHECKED, 0);
808 SendMessageA(g_hwndButton2, BM_SETCHECK, BST_CHECKED , 0);
809 /* Continue testing after dialog initialization */
810 PostMessageA(hDlg, WM_USER, 0, 0);
811 return g_bInitialFocusInitDlgResult;
813 case WM_COMMAND:
814 if (LOWORD(wParam) == IDCANCEL)
816 EndDialog(hDlg, LOWORD(wParam));
817 return TRUE;
819 return FALSE;
821 case WM_USER:
822 g_styleInitialFocusT2 = GetWindowLongA(hDlg, GWL_STYLE);
823 g_hwndInitialFocusT1 = GetFocus();
824 SetFocus(hDlg);
825 g_hwndInitialFocusT2 = GetFocus();
826 PostMessageA(hDlg, WM_COMMAND, IDCANCEL, 0);
827 return TRUE;
830 return FALSE;
833 static INT_PTR CALLBACK focusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
834 LPARAM lParam)
836 switch (uiMsg)
838 case WM_INITDIALOG:
839 SetWindowTextA(GetDlgItem(hDlg, 200), "new caption");
840 return TRUE;
842 case WM_COMMAND:
843 if (LOWORD(wParam) == 200)
845 if (HIWORD(wParam) == EN_SETFOCUS)
846 g_hwndInitialFocusT1 = (HWND)lParam;
848 return FALSE;
851 return FALSE;
854 /* Helper for InitialFocusTest */
855 static const char * GetHwndString(HWND hw)
857 if (hw == NULL)
858 return "a null handle";
859 if (hw == g_hwndMain)
860 return "the dialog handle";
861 if (hw == g_hwndInitialFocusGroupBox)
862 return "the group box control";
863 if (hw == g_hwndButton1)
864 return "the first button";
865 if (hw == g_hwndButton2)
866 return "the second button";
867 if (hw == g_hwndButtonCancel)
868 return "the cancel button";
870 return "unknown handle";
873 static void test_focus(void)
875 /* Test 1:
876 * This test intentionally returns FALSE in response to WM_INITDIALOG
877 * without setting focus to a control. This is what MFC's CFormView does.
879 * Since the WM_INITDIALOG handler returns FALSE without setting the focus,
880 * the focus should initially be NULL. Later, when we manually set focus to
881 * the dialog, the default handler should set focus to the first control that
882 * is "visible, not disabled, and has the WS_TABSTOP style" (MSDN). Because the
883 * second radio button has been checked, it should be the first control
884 * that meets these criteria and should receive the focus.
887 g_bInitialFocusInitDlgResult = FALSE;
888 g_hwndInitialFocusT1 = (HWND) -1;
889 g_hwndInitialFocusT2 = (HWND) -1;
890 g_styleInitialFocusT1 = -1;
891 g_styleInitialFocusT2 = -1;
893 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
895 ok (((g_styleInitialFocusT1 & WS_TABSTOP) == 0),
896 "Error in wrc - Detected WS_TABSTOP as default style for GROUPBOX\n");
898 ok (((g_styleInitialFocusT2 & WS_VISIBLE) == 0),
899 "Modal dialogs should not be shown until the message queue first goes empty\n");
901 ok ((g_hwndInitialFocusT1 == NULL),
902 "Error in initial focus when WM_INITDIALOG returned FALSE: "
903 "Expected NULL focus, got %s (%p).\n",
904 GetHwndString(g_hwndInitialFocusT1), g_hwndInitialFocusT1);
906 ok ((g_hwndInitialFocusT2 == g_hwndButton2),
907 "Error after first SetFocus() when WM_INITDIALOG returned FALSE: "
908 "Expected the second button (%p), got %s (%p).\n",
909 g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
910 g_hwndInitialFocusT2);
912 /* Test 2:
913 * This is the same as above, except WM_INITDIALOG is made to return TRUE.
914 * This should cause the focus to go to the second radio button right away
915 * and stay there (until the user indicates otherwise).
918 g_bInitialFocusInitDlgResult = TRUE;
919 g_hwndInitialFocusT1 = (HWND) -1;
920 g_hwndInitialFocusT2 = (HWND) -1;
921 g_styleInitialFocusT1 = -1;
922 g_styleInitialFocusT2 = -1;
924 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, delayFocusDlgWinProc);
926 ok ((g_hwndInitialFocusT1 == g_hwndButton2),
927 "Error in initial focus when WM_INITDIALOG returned TRUE: "
928 "Expected the second button (%p), got %s (%p).\n",
929 g_hwndButton2, GetHwndString(g_hwndInitialFocusT1),
930 g_hwndInitialFocusT1);
932 ok ((g_hwndInitialFocusT2 == g_hwndButton2),
933 "Error after first SetFocus() when WM_INITDIALOG returned TRUE: "
934 "Expected the second button (%p), got %s (%p).\n",
935 g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
936 g_hwndInitialFocusT2);
938 /* Test 3:
939 * If the dialog has DS_CONTROL and it's not visible then we shouldn't change focus */
941 HWND hDlg;
942 HRSRC hResource;
943 HANDLE hTemplate;
944 DLGTEMPLATE* pTemplate;
945 HWND hTextbox;
946 DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
948 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", (LPCSTR)RT_DIALOG);
949 hTemplate = LoadResource(g_hinst, hResource);
950 pTemplate = LockResource(hTemplate);
952 g_hwndInitialFocusT1 = 0;
953 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
954 ok (hDlg != 0, "Failed to create test dialog.\n");
956 ok ((g_hwndInitialFocusT1 == 0),
957 "Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
959 /* Also make sure that WM_SETFOCUS selects the textbox's text */
960 hTextbox = GetDlgItem(hDlg, 200);
961 SendMessageA(hTextbox, WM_SETTEXT, 0, (LPARAM)"Hello world");
963 SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
964 SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
965 ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd);
967 /* but WM_ACTIVATE does not */
968 SendMessageA(hTextbox, EM_SETSEL, 0, 0);
969 SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
970 SendMessageA(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
971 ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd);
973 DestroyWindow(hDlg);
976 /* Test 4:
977 * If the dialog has no tab-accessible controls, set focus to first control */
979 HWND hDlg;
980 HRSRC hResource;
981 HANDLE hTemplate;
982 DLGTEMPLATE* pTemplate;
983 HWND hLabel;
985 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_2", (LPCSTR)RT_DIALOG);
986 hTemplate = LoadResource(g_hinst, hResource);
987 pTemplate = LockResource(hTemplate);
989 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
990 ok(hDlg != 0, "Failed to create test dialog.\n");
991 hLabel = GetDlgItem(hDlg, 200);
993 ok(GetFocus() == hLabel, "Focus not set to label, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
995 DestroyWindow(hDlg);
997 /* Also check focus after WM_ACTIVATE and WM_SETFOCUS */
998 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, NULL, 0);
999 ok(hDlg != 0, "Failed to create test dialog.\n");
1000 hLabel = GetDlgItem(hDlg, 200);
1002 SetFocus(NULL);
1003 SendMessageA(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
1004 ok(GetFocus() == NULL, "Focus set on WM_ACTIVATE, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1006 SetFocus(NULL);
1007 SendMessageA(hDlg, WM_SETFOCUS, 0, 0);
1008 ok(GetFocus() == hLabel, "Focus not set to label on WM_SETFOCUS, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
1010 DestroyWindow(hDlg);
1013 /* Test 5:
1014 * Select textbox's text on creation */
1016 HWND hDlg;
1017 HRSRC hResource;
1018 HANDLE hTemplate;
1019 DLGTEMPLATE* pTemplate;
1020 HWND edit;
1021 DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
1023 hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG_3", (LPCSTR)RT_DIALOG);
1024 hTemplate = LoadResource(g_hinst, hResource);
1025 pTemplate = LockResource(hTemplate);
1027 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
1028 ok(hDlg != 0, "Failed to create test dialog.\n");
1029 edit = GetDlgItem(hDlg, 200);
1031 ok(GetFocus() == edit, "Focus not set to edit, focus=%p, dialog=%p, edit=%p\n",
1032 GetFocus(), hDlg, edit);
1033 SendMessageA(edit, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
1034 ok(selectionStart == 0 && selectionEnd == 11,
1035 "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n",
1036 selectionStart, selectionEnd);
1038 DestroyWindow(hDlg);
1042 static void test_GetDlgItemText(void)
1044 char string[64];
1045 BOOL ret;
1047 strcpy(string, "Overwrite Me");
1048 ret = GetDlgItemTextA(NULL, 0, string, sizeof(string)/sizeof(string[0]));
1049 ok(!ret, "GetDlgItemText(NULL) shouldn't have succeeded\n");
1051 ok(string[0] == '\0' || broken(!strcmp(string, "Overwrite Me")),
1052 "string retrieved using GetDlgItemText should have been NULL terminated\n");
1055 static void test_GetDlgItem(void)
1057 HWND hwnd, child1, child2, hwnd2;
1058 BOOL ret;
1060 hwnd = CreateWindowA("button", "parent", WS_VISIBLE, 0, 0, 100, 100, NULL, 0, g_hinst, NULL);
1061 ok(hwnd != NULL, "failed to created window\n");
1063 /* created with the same ID */
1064 child1 = CreateWindowA("button", "child1", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1065 ok(child1 != NULL, "failed to create first child\n");
1066 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, hwnd, 0, g_hinst, NULL);
1067 ok(child2 != NULL, "failed to create second child\n");
1069 hwnd2 = GetDlgItem(hwnd, 0);
1070 ok(hwnd2 == child1, "expected first child, got %p\n", hwnd2);
1072 hwnd2 = GetTopWindow(hwnd);
1073 ok(hwnd2 == child1, "expected first child to be top, got %p\n", hwnd2);
1075 ret = SetWindowPos(child1, child2, 0, 0, 0, 0, SWP_NOMOVE);
1076 ok(ret, "got %d\n", ret);
1077 hwnd2 = GetTopWindow(hwnd);
1078 ok(hwnd2 == child2, "expected second child to be top, got %p\n", hwnd2);
1080 /* top window from child list is picked */
1081 hwnd2 = GetDlgItem(hwnd, 0);
1082 ok(hwnd2 == child2, "expected second child, got %p\n", hwnd2);
1084 /* Now test how GetDlgItem searches */
1085 DestroyWindow(child2);
1086 child2 = CreateWindowA("button", "child2", WS_VISIBLE|WS_CHILD, 0, 0, 10, 10, child1, 0, g_hinst, NULL);
1087 ok(child2 != NULL, "failed to create second child\n");
1089 /* give child2 an ID */
1090 SetWindowLongA(child2, GWLP_ID, 100);
1092 hwnd2 = GetDlgItem(hwnd, 100);
1093 ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1095 /* make the ID of child2 public with a WS_EX_CONTROLPARENT parent */
1096 SetWindowLongA(child1, GWL_EXSTYLE, WS_EX_CONTROLPARENT);
1098 hwnd2 = GetDlgItem(hwnd, 100);
1099 ok(!hwnd2, "expected child to not be found, got %p\n", hwnd2);
1101 DestroyWindow(child1);
1102 DestroyWindow(child2);
1103 DestroyWindow(hwnd);
1106 static INT_PTR CALLBACK DestroyDlgWinProc (HWND hDlg, UINT uiMsg,
1107 WPARAM wParam, LPARAM lParam)
1109 if (uiMsg == WM_INITDIALOG)
1111 DestroyWindow(hDlg);
1112 return TRUE;
1114 return FALSE;
1117 static INT_PTR CALLBACK DestroyOnCloseDlgWinProc (HWND hDlg, UINT uiMsg,
1118 WPARAM wParam, LPARAM lParam)
1120 switch (uiMsg)
1122 case WM_INITDIALOG:
1123 PostMessageA(hDlg, WM_CLOSE, 0, 0);
1124 return TRUE;
1125 case WM_CLOSE:
1126 DestroyWindow(hDlg);
1127 return TRUE;
1128 case WM_DESTROY:
1129 PostQuitMessage(0);
1130 return TRUE;
1132 return FALSE;
1135 static INT_PTR CALLBACK TestInitDialogHandleProc (HWND hDlg, UINT uiMsg,
1136 WPARAM wParam, LPARAM lParam)
1138 if (uiMsg == WM_INITDIALOG)
1140 HWND expected = GetNextDlgTabItem(hDlg, NULL, FALSE);
1141 ok(expected == (HWND)wParam,
1142 "Expected wParam to be the handle to the first tabstop control (%p), got %p\n",
1143 expected, (HWND)wParam);
1145 EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1146 return TRUE;
1148 return FALSE;
1151 static INT_PTR CALLBACK TestDefButtonDlgProc (HWND hDlg, UINT uiMsg,
1152 WPARAM wParam, LPARAM lParam)
1154 switch (uiMsg)
1156 case WM_INITDIALOG:
1157 EndDialog(hDlg, LOWORD(SendMessageA(hDlg, DM_GETDEFID, 0, 0)));
1158 return TRUE;
1160 return FALSE;
1163 static INT_PTR CALLBACK TestReturnKeyDlgProc (HWND hDlg, UINT uiMsg,
1164 WPARAM wParam, LPARAM lParam)
1166 static int received_idok;
1168 switch (uiMsg)
1170 case WM_INITDIALOG:
1172 MSG msg = {hDlg, WM_KEYDOWN, VK_RETURN, 0x011c0001};
1174 received_idok = -1;
1175 IsDialogMessageA(hDlg, &msg);
1176 ok(received_idok == 0xdead, "WM_COMMAND/0xdead not received\n");
1178 received_idok = -2;
1179 IsDialogMessageA(hDlg, &msg);
1180 ok(received_idok == IDOK, "WM_COMMAND/IDOK not received\n");
1182 EndDialog(hDlg, 0);
1183 return TRUE;
1186 case DM_GETDEFID:
1187 if (received_idok == -1)
1189 HWND hwnd = GetDlgItem(hDlg, 0xdead);
1190 ok(!hwnd, "dialog item with ID 0xdead should not exist\n");
1191 SetWindowLongA(hDlg, DWLP_MSGRESULT, MAKELRESULT(0xdead, DC_HASDEFID));
1192 return TRUE;
1194 return FALSE;
1196 case WM_COMMAND:
1197 received_idok = wParam;
1198 return TRUE;
1200 return FALSE;
1203 static INT_PTR CALLBACK TestControlStyleDlgProc(HWND hdlg, UINT msg,
1204 WPARAM wparam, LPARAM lparam)
1206 HWND control;
1207 DWORD style, exstyle;
1208 char buf[256];
1210 switch (msg)
1212 case WM_INITDIALOG:
1213 control = GetDlgItem(hdlg, 7);
1214 ok(control != 0, "dialog control with id 7 not found\n");
1215 style = GetWindowLongA(control, GWL_STYLE);
1216 ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1217 exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1218 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);
1219 buf[0] = 0;
1220 GetWindowTextA(control, buf, sizeof(buf));
1221 ok(strcmp(buf, "bump7") == 0, "expected bump7, got %s\n", buf);
1223 control = GetDlgItem(hdlg, 8);
1224 ok(control != 0, "dialog control with id 8 not found\n");
1225 style = GetWindowLongA(control, GWL_STYLE);
1226 ok(style == (WS_CHILD|WS_VISIBLE), "expected WS_CHILD|WS_VISIBLE, got %#x\n", style);
1227 exstyle = GetWindowLongA(control, GWL_EXSTYLE);
1228 ok(exstyle == (WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT), "expected WS_EX_NOPARENTNOTIFY|WS_EX_TRANSPARENT, got %#x\n", exstyle);
1229 buf[0] = 0;
1230 GetWindowTextA(control, buf, sizeof(buf));
1231 ok(strcmp(buf, "bump8") == 0, "expected bump8, got %s\n", buf);
1233 EndDialog(hdlg, -7);
1234 return TRUE;
1236 return FALSE;
1239 static const WCHAR testtextW[] = {'W','n','d','T','e','x','t',0};
1240 static const char *testtext = "WndText";
1242 enum defdlgproc_text
1244 DLGPROCTEXT_SNDMSGA = 0,
1245 DLGPROCTEXT_SNDMSGW,
1246 DLGPROCTEXT_DLGPROCA,
1247 DLGPROCTEXT_DLGPROCW,
1248 DLGPROCTEXT_SETTEXTA,
1249 DLGPROCTEXT_SETTEXTW,
1252 static const char *testmodes[] =
1254 "SNDMSGA",
1255 "SNDMSGW",
1256 "DLGPROCA",
1257 "DLGPROCW",
1258 "SETTEXTA",
1259 "SETTEXTW",
1262 static INT_PTR CALLBACK test_aw_conversion_dlgprocA(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1264 int mode = HandleToULong(GetPropA(hdlg, "test_mode"));
1265 WCHAR *text = (WCHAR *)lparam;
1266 char *textA = (char *)lparam;
1268 switch (msg)
1270 case WM_SETTEXT:
1271 case WM_WININICHANGE:
1272 case WM_DEVMODECHANGE:
1273 case CB_DIR:
1274 case LB_DIR:
1275 case LB_ADDFILE:
1276 case EM_REPLACESEL:
1277 switch (mode)
1279 case DLGPROCTEXT_DLGPROCA:
1280 ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A",
1281 testmodes[mode], textA);
1282 break;
1283 case DLGPROCTEXT_DLGPROCW:
1284 ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A", testmodes[mode],
1285 wine_dbgstr_w(text));
1286 break;
1287 case DLGPROCTEXT_SNDMSGA:
1288 case DLGPROCTEXT_SETTEXTA:
1289 if (IsWindowUnicode(hdlg))
1291 ok(text != testtextW && !lstrcmpW(text, testtextW),
1292 "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1294 else
1295 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1296 break;
1297 case DLGPROCTEXT_SNDMSGW:
1298 case DLGPROCTEXT_SETTEXTW:
1299 if (IsWindowUnicode(hdlg))
1300 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1301 else
1302 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1303 testmodes[mode], textA);
1304 break;
1306 break;
1309 return DefWindowProcW(hdlg, msg, wparam, lparam);
1312 static INT_PTR CALLBACK test_aw_conversion_dlgprocW(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1314 int mode = HandleToULong(GetPropA(hdlg, "test_mode"));
1315 WCHAR *text = (WCHAR *)lparam;
1316 char *textA = (char *)lparam;
1318 switch (msg)
1320 case WM_SETTEXT:
1321 case WM_WININICHANGE:
1322 case WM_DEVMODECHANGE:
1323 case CB_DIR:
1324 case LB_DIR:
1325 case LB_ADDFILE:
1326 case EM_REPLACESEL:
1327 switch (mode)
1329 case DLGPROCTEXT_DLGPROCA:
1330 ok(textA == testtext, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A",
1331 testmodes[mode], textA);
1332 break;
1333 case DLGPROCTEXT_DLGPROCW:
1334 ok(text == testtextW, "%s: %s, unexpected text %s.\n", IsWindowUnicode(hdlg) ? "U" : "A", testmodes[mode],
1335 wine_dbgstr_w(text));
1336 break;
1337 case DLGPROCTEXT_SNDMSGA:
1338 case DLGPROCTEXT_SETTEXTA:
1339 if (IsWindowUnicode(hdlg))
1340 ok(text != testtextW && !lstrcmpW(text, testtextW),
1341 "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1342 else
1343 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1344 break;
1345 case DLGPROCTEXT_SNDMSGW:
1346 case DLGPROCTEXT_SETTEXTW:
1347 if (IsWindowUnicode(hdlg))
1348 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1349 else
1350 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1351 testmodes[mode], textA);
1352 break;
1354 break;
1357 return DefWindowProcA(hdlg, msg, wparam, lparam);
1360 static void dlg_test_aw_message(HWND hdlg, UINT msg)
1362 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SNDMSGA));
1363 SendMessageA(hdlg, msg, 0, (LPARAM)testtext);
1365 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SNDMSGW));
1366 SendMessageW(hdlg, msg, 0, (LPARAM)testtextW);
1368 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_DLGPROCA));
1369 DefDlgProcA(hdlg, msg, 0, (LPARAM)testtext);
1371 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_DLGPROCW));
1372 DefDlgProcW(hdlg, msg, 0, (LPARAM)testtextW);
1375 static INT_PTR CALLBACK test_aw_conversion_dlgproc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1377 ULONG_PTR dlgproc, originalproc;
1378 WCHAR buffW[64];
1379 char buff[64];
1380 BOOL ret;
1381 INT len;
1383 switch (msg)
1385 case WM_INITDIALOG:
1386 ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1388 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1389 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1390 dlg_test_aw_message(hdlg, CB_DIR);
1391 dlg_test_aw_message(hdlg, LB_DIR);
1392 dlg_test_aw_message(hdlg, LB_ADDFILE);
1393 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1394 dlg_test_aw_message(hdlg, WM_SETTEXT);
1396 /* WM_SETTEXT/WM_GETTEXT */
1397 originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1398 ok(originalproc == (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", originalproc);
1400 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1401 ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgproc, "Unexpected dlg proc %#lx.\n", dlgproc);
1403 dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocA);
1404 ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1406 dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1407 ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1409 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1410 ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1412 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1413 ret = SetWindowTextA(hdlg, testtext);
1414 todo_wine
1415 ok(ret, "Failed to set window text.\n");
1417 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1418 ret = SetWindowTextW(hdlg, testtextW);
1419 todo_wine
1420 ok(ret, "Failed to set window text.\n");
1422 memset(buff, 'A', sizeof(buff));
1423 len = GetWindowTextA(hdlg, buff, sizeof(buff));
1424 ok(buff[0] == 0 && buff[1] == 'A' && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1425 (BYTE)buff[0], (BYTE)buff[1], len);
1427 memset(buffW, 0xff, sizeof(buffW));
1428 len = GetWindowTextW(hdlg, buffW, 64);
1429 ok(!lstrcmpW(buffW, testtextW) && len == 0, "Unexpected window text %s, len %d\n", wine_dbgstr_w(buffW), len);
1431 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1432 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1433 dlg_test_aw_message(hdlg, CB_DIR);
1434 dlg_test_aw_message(hdlg, LB_DIR);
1435 dlg_test_aw_message(hdlg, LB_ADDFILE);
1436 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1437 dlg_test_aw_message(hdlg, WM_SETTEXT);
1439 dlgproc = SetWindowLongPtrW(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocW);
1440 ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1442 dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1443 ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1445 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1446 ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1448 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1449 ret = SetWindowTextA(hdlg, testtext);
1450 todo_wine
1451 ok(ret, "Failed to set window text.\n");
1453 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1454 ret = SetWindowTextW(hdlg, testtextW);
1455 todo_wine
1456 ok(ret, "Failed to set window text.\n");
1458 memset(buff, 'A', sizeof(buff));
1459 len = GetWindowTextA(hdlg, buff, sizeof(buff));
1460 ok(buff[0] == 0 && buff[1] == 'A' && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1461 (BYTE)buff[0], (BYTE)buff[1], len);
1463 memset(buffW, 0xff, sizeof(buffW));
1464 len = GetWindowTextW(hdlg, buffW, sizeof(buffW)/sizeof(buffW[0]));
1465 ok(buffW[0] == 'W' && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1466 buffW[0], buffW[1], len);
1468 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1469 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1470 dlg_test_aw_message(hdlg, CB_DIR);
1471 dlg_test_aw_message(hdlg, LB_DIR);
1472 dlg_test_aw_message(hdlg, LB_ADDFILE);
1473 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1474 dlg_test_aw_message(hdlg, WM_SETTEXT);
1476 SetWindowLongPtrA(hdlg, DWLP_DLGPROC, originalproc);
1477 EndDialog(hdlg, -123);
1478 return TRUE;
1480 return FALSE;
1483 static INT_PTR CALLBACK test_aw_conversion_dlgproc2(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1485 ULONG_PTR dlgproc, originalproc;
1486 WCHAR buffW[64];
1487 char buff[64];
1488 BOOL ret;
1489 INT len;
1491 switch (msg)
1493 case WM_INITDIALOG:
1494 ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1496 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1497 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1498 dlg_test_aw_message(hdlg, CB_DIR);
1499 dlg_test_aw_message(hdlg, LB_DIR);
1500 dlg_test_aw_message(hdlg, LB_ADDFILE);
1501 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1502 dlg_test_aw_message(hdlg, WM_SETTEXT);
1504 originalproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1505 ok(originalproc != (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", originalproc);
1507 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1508 ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgproc2, "Unexpected dlg proc %#lx.\n", dlgproc);
1510 dlgproc = SetWindowLongPtrA(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocW);
1511 ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1513 dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1514 ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1516 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1517 ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocW, "Unexpected dlg proc %#lx.\n", dlgproc);
1519 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1520 ret = SetWindowTextA(hdlg, testtext);
1521 todo_wine
1522 ok(ret, "Failed to set window text.\n");
1524 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1525 ret = SetWindowTextW(hdlg, testtextW);
1526 todo_wine
1527 ok(ret, "Failed to set window text.\n");
1529 memset(buff, 'A', sizeof(buff));
1530 len = GetWindowTextA(hdlg, buff, sizeof(buff));
1531 ok(!strcmp(buff, testtext) && len == 0, "Unexpected window text %s, len %d\n", buff, len);
1533 memset(buffW, 0xff, sizeof(buffW));
1534 len = GetWindowTextW(hdlg, buffW, 64);
1535 ok(buffW[0] == 0 && buffW[1] == 0xffff && len == 0, "Unexpected window text %s, len %d\n",
1536 wine_dbgstr_w(buffW), len);
1538 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1539 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1540 dlg_test_aw_message(hdlg, CB_DIR);
1541 dlg_test_aw_message(hdlg, LB_DIR);
1542 dlg_test_aw_message(hdlg, LB_ADDFILE);
1543 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1544 dlg_test_aw_message(hdlg, WM_SETTEXT);
1546 dlgproc = SetWindowLongPtrW(hdlg, DWLP_DLGPROC, (UINT_PTR)test_aw_conversion_dlgprocA);
1547 ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
1549 dlgproc = GetWindowLongPtrW(hdlg, DWLP_DLGPROC);
1550 ok(dlgproc == (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1552 dlgproc = GetWindowLongPtrA(hdlg, DWLP_DLGPROC);
1553 ok(dlgproc != (ULONG_PTR)test_aw_conversion_dlgprocA, "Unexpected dlg proc %#lx.\n", dlgproc);
1555 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTA));
1556 ret = SetWindowTextA(hdlg, testtext);
1557 todo_wine
1558 ok(ret, "Failed to set window text.\n");
1560 SetPropA(hdlg, "test_mode", ULongToHandle(DLGPROCTEXT_SETTEXTW));
1561 ret = SetWindowTextW(hdlg, testtextW);
1562 todo_wine
1563 ok(ret, "Failed to set window text.\n");
1565 memset(buff, 'A', sizeof(buff));
1566 len = GetWindowTextA(hdlg, buff, sizeof(buff));
1567 ok(!strcmp(buff, testtext) && len == 0, "Unexpected window text %s, len %d\n", buff, len);
1569 memset(buffW, 0xff, sizeof(buffW));
1570 len = GetWindowTextW(hdlg, buffW, sizeof(buffW)/sizeof(buffW[0]));
1571 ok(buffW[0] == 0 && buffW[1] == 0xffff && len == 0, "Unexpected window text %#x, %#x, len %d\n",
1572 buffW[0], buffW[1], len);
1574 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1575 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1576 dlg_test_aw_message(hdlg, CB_DIR);
1577 dlg_test_aw_message(hdlg, LB_DIR);
1578 dlg_test_aw_message(hdlg, LB_ADDFILE);
1579 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1580 dlg_test_aw_message(hdlg, WM_SETTEXT);
1582 SetWindowLongPtrA(hdlg, DWLP_DLGPROC, originalproc);
1583 EndDialog(hdlg, -123);
1584 return TRUE;
1586 return FALSE;
1589 static LRESULT CALLBACK test_aw_conversion_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1591 WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
1592 int mode = HandleToULong(GetPropA(hwnd, "test_mode"));
1593 WCHAR *text = (WCHAR *)lparam;
1594 char *textA = (char *)lparam;
1596 switch (msg)
1598 case WM_SETTEXT:
1599 case WM_WININICHANGE:
1600 case WM_DEVMODECHANGE:
1601 case CB_DIR:
1602 case LB_DIR:
1603 case LB_ADDFILE:
1604 case EM_REPLACESEL:
1605 switch (mode)
1607 case DLGPROCTEXT_SNDMSGA:
1608 if (IsWindowUnicode(hwnd))
1609 ok(text != testtextW && !lstrcmpW(text, testtextW),
1610 "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1611 else
1612 ok(textA == testtext, "A: %s, unexpected text %s.\n", testmodes[mode], textA);
1613 break;
1614 case DLGPROCTEXT_SNDMSGW:
1615 if (IsWindowUnicode(hwnd))
1616 ok(text == testtextW, "U: %s, unexpected text %s.\n", testmodes[mode], wine_dbgstr_w(text));
1617 else
1618 ok(textA != testtext && !strcmp(textA, testtext), "A: %s, unexpected text %s.\n",
1619 testmodes[mode], textA);
1620 break;
1621 default:
1622 ok(0, "Unexpected test mode %d.\n", mode);
1624 break;
1627 return IsWindowUnicode(hwnd) ? CallWindowProcW(oldproc, hwnd, msg, wparam, lparam) :
1628 CallWindowProcA(oldproc, hwnd, msg, wparam, lparam);
1631 static INT_PTR CALLBACK test_aw_conversion_dlgproc3(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam)
1633 BOOL is_unicode = !!lparam;
1634 LONG_PTR oldproc;
1636 switch (msg)
1638 case WM_INITDIALOG:
1639 ok(is_unicode == IsWindowUnicode(hdlg), "Unexpected unicode window property.\n");
1641 oldproc = SetWindowLongPtrA(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
1642 SetWindowLongPtrA(hdlg, GWLP_USERDATA, oldproc);
1643 ok(!IsWindowUnicode(hdlg), "Unexpected unicode window.\n");
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);
1653 SetWindowLongPtrW(hdlg, GWLP_WNDPROC, (LONG_PTR)test_aw_conversion_wndproc);
1654 ok(IsWindowUnicode(hdlg), "Expected unicode window.\n");
1656 dlg_test_aw_message(hdlg, WM_WININICHANGE);
1657 dlg_test_aw_message(hdlg, WM_DEVMODECHANGE);
1658 dlg_test_aw_message(hdlg, CB_DIR);
1659 dlg_test_aw_message(hdlg, LB_DIR);
1660 dlg_test_aw_message(hdlg, LB_ADDFILE);
1661 dlg_test_aw_message(hdlg, EM_REPLACESEL);
1662 dlg_test_aw_message(hdlg, WM_SETTEXT);
1664 SetWindowLongPtrA(hdlg, GWLP_WNDPROC, oldproc);
1665 EndDialog(hdlg, -123);
1666 return TRUE;
1668 return FALSE;
1671 static void test_DialogBoxParam(void)
1673 static const WCHAR nameW[] = {'T','E','S','T','_','E','M','P','T','Y','_','D','I','A','L','O','G',0};
1674 INT_PTR ret;
1675 HWND hwnd_invalid = (HWND)0x4444;
1677 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DLG_CHILD_POPUP", 0, TestControlStyleDlgProc, 0);
1678 ok(ret == -7, "expected -7, got %ld\n", ret);
1680 SetLastError(0xdeadbeef);
1681 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG" , hwnd_invalid, 0 , 0);
1682 ok(0 == ret || broken(ret == -1), "DialogBoxParamA returned %ld, expected 0\n", ret);
1683 ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1684 broken(GetLastError() == 0xdeadbeef),
1685 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1687 /* Test a dialog which destroys itself on WM_INITDIALOG. */
1688 SetLastError(0xdeadbeef);
1689 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyDlgWinProc, 0);
1690 ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1691 ok(ERROR_INVALID_WINDOW_HANDLE == GetLastError() ||
1692 GetLastError() == ERROR_SUCCESS ||
1693 broken(GetLastError() == 0xdeadbeef),
1694 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n",GetLastError());
1696 /* Test a dialog which destroys itself on WM_CLOSE. */
1697 ret = DialogBoxParamA(GetModuleHandleA(NULL), "IDD_DIALOG", 0, DestroyOnCloseDlgWinProc, 0);
1698 ok(0 == ret, "DialogBoxParamA returned %ld, expected 0\n", ret);
1700 SetLastError(0xdeadbeef);
1701 ret = DialogBoxParamA(GetModuleHandleA(NULL), "RESOURCE_INVALID" , 0, 0, 0);
1702 ok(-1 == ret, "DialogBoxParamA returned %ld, expected -1\n", ret);
1703 ok(ERROR_RESOURCE_NAME_NOT_FOUND == GetLastError() ||
1704 broken(GetLastError() == 0xdeadbeef),
1705 "got %d, expected ERROR_RESOURCE_NAME_NOT_FOUND\n",GetLastError());
1707 SetLastError(0xdeadbeef);
1708 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_DIALOG_INVALID_CLASS", 0, DestroyDlgWinProc, 0);
1709 ok(ret == -1, "DialogBoxParamA returned %ld, expected -1\n", ret);
1710 ok(GetLastError() == 0, "got %d\n", GetLastError());
1712 SetLastError(0xdeadbeef);
1713 ret = DefDlgProcA(0, WM_ERASEBKGND, 0, 0);
1714 ok(ret == 0, "DefDlgProcA returned %ld, expected 0\n", ret);
1715 ok(GetLastError() == ERROR_INVALID_WINDOW_HANDLE ||
1716 broken(GetLastError() == 0xdeadbeef),
1717 "got %d, expected ERROR_INVALID_WINDOW_HANDLE\n", GetLastError());
1719 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestInitDialogHandleProc, 0);
1720 ok(ret == IDOK, "Expected IDOK\n");
1722 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestDefButtonDlgProc, 0);
1723 ok(ret == IDOK, "Expected IDOK\n");
1725 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, TestReturnKeyDlgProc, 0);
1726 ok(ret == 0, "Unexpected ret value %ld.\n", ret);
1728 /* WM_SETTEXT handling in case of A/W dialog procedures vs A/W dialog window. */
1729 ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc, 0);
1730 ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1732 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc2, 0);
1733 ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1735 ret = DialogBoxParamW(GetModuleHandleA(NULL), nameW, 0, test_aw_conversion_dlgproc3, 1);
1736 ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1738 ret = DialogBoxParamA(GetModuleHandleA(NULL), "TEST_EMPTY_DIALOG", 0, test_aw_conversion_dlgproc3, 0);
1739 ok(ret == -123, "Unexpected ret value %ld.\n", ret);
1742 static void test_DisabledDialogTest(void)
1744 g_terminated = FALSE;
1745 DialogBoxParamA(g_hinst, "IDD_DIALOG", NULL, disabled_test_proc, 0);
1746 ok(FALSE == g_terminated, "dialog with disabled ok button has been terminated\n");
1749 static INT_PTR CALLBACK messageBoxFontDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
1750 LPARAM lParam)
1752 if (uiMsg == WM_INITDIALOG) {
1753 SetFocus(hDlg);
1754 return 1;
1757 return 0;
1760 static void test_MessageBoxFontTest(void)
1762 /* This dialog template defines a dialog template which got 0x7fff as its
1763 * font size and omits the other font members. On WinNT, passing such a
1764 * dialog template to CreateDialogIndirectParamW will result in a dialog
1765 * being created which uses the message box font. We test that here.
1768 static unsigned char dlgTemplate[] =
1770 /* Dialog header */
1771 0x01,0x00, /* Version */
1772 0xff,0xff, /* Extended template marker */
1773 0x00,0x00,0x00,0x00, /* Context Help ID */
1774 0x00,0x00,0x00,0x00, /* Extended style */
1775 0xc0,0x00,0xc8,0x80, /* Style (WS_SYSMENU|WS_CAPTION|WS_POPUP|DS_SETFONT|DS_MODALFRAME) */
1776 0x01,0x00, /* Control count */
1777 0x00,0x00, /* X */
1778 0x00,0x00, /* Y */
1779 0x80,0x00, /* Width */
1780 0x80,0x00, /* Height */
1781 0x00,0x00, /* Menu name */
1782 0x00,0x00, /* Class name */
1783 'T',0x00,'e',0x00, /* Caption (unicode) */
1784 's',0x00,'t',0x00,
1785 0x00,0x00,
1786 0xff,0x7f, /* Font height (0x7fff = message box font) */
1788 /* Control #1 */
1789 0x00,0x00, /* Align to DWORD (header is 42 bytes) */
1790 0x00,0x00,0x00,0x00, /* Context Help ID */
1791 0x00,0x00,0x00,0x00, /* Extended style */
1792 0x00,0x00,0x00,0x50, /* Style (WS_CHILD|WS_VISIBLE) */
1793 0x00,0x00, /* X */
1794 0x00,0x00, /* Y */
1795 0x80,0x00, /* Width */
1796 0x80,0x00, /* Height */
1797 0x00,0x01,0x00,0x00, /* Control ID (256) */
1798 0xff,0xff,0x82,0x00, /* Class (Static) */
1799 'W',0x00,'I',0x00, /* Caption (unicode) */
1800 'N',0x00,'E',0x00,
1801 ' ',0x00,'d',0x00,
1802 'i',0x00,'a',0x00,
1803 'l',0x00,'o',0x00,
1804 'g',0x00,' ',0x00,
1805 't',0x00,'e',0x00,
1806 's',0x00,'t',0x00,
1807 '.',0x00,0x00,0x00,
1808 0x00,0x00, /* Size of extended data */
1810 0x00,0x00 /* Align to DWORD */
1813 HWND hDlg;
1814 HFONT hFont;
1815 LOGFONTW lfStaticFont;
1816 NONCLIENTMETRICSW ncMetrics;
1818 /* Check if the dialog can be created from the template. On Win9x, this should fail
1819 * because we are calling the W function which is not implemented, but that's what
1820 * we want, because passing such a template to CreateDialogIndirectParamA would crash
1821 * anyway.
1823 hDlg = CreateDialogIndirectParamW(g_hinst, (LPCDLGTEMPLATEW)dlgTemplate, NULL, messageBoxFontDlgWinProc, 0);
1824 if (!hDlg)
1826 win_skip("dialog wasn't created\n");
1827 return;
1830 hFont = (HFONT) SendDlgItemMessageW(hDlg, 256, WM_GETFONT, 0, 0);
1831 if (!hFont)
1833 skip("dialog uses system font\n");
1834 DestroyWindow(hDlg);
1835 return;
1837 GetObjectW(hFont, sizeof(LOGFONTW), &lfStaticFont);
1839 ncMetrics.cbSize = FIELD_OFFSET(NONCLIENTMETRICSW, iPaddedBorderWidth);
1840 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncMetrics, 0);
1841 ok( !memcmp(&lfStaticFont, &ncMetrics.lfMessageFont, FIELD_OFFSET(LOGFONTW, lfFaceName)) &&
1842 !lstrcmpW(lfStaticFont.lfFaceName, ncMetrics.lfMessageFont.lfFaceName),
1843 "dialog doesn't use message box font\n");
1844 DestroyWindow(hDlg);
1847 static void test_SaveRestoreFocus(void)
1849 HWND hDlg;
1850 HRSRC hResource;
1851 HANDLE hTemplate;
1852 DLGTEMPLATE* pTemplate;
1853 LONG_PTR foundId;
1854 HWND foundHwnd;
1856 /* create the dialog */
1857 hResource = FindResourceA(g_hinst, "MULTI_EDIT_DIALOG", (LPCSTR)RT_DIALOG);
1858 hTemplate = LoadResource(g_hinst, hResource);
1859 pTemplate = LockResource(hTemplate);
1861 hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, messageBoxFontDlgWinProc, 0);
1862 ok (hDlg != 0, "Failed to create test dialog.\n");
1864 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1865 ok (foundId == 1000, "First edit box should have gained focus on dialog creation. Expected: %d, Found: %ld\n", 1000, foundId);
1867 SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
1868 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1869 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1870 ok (foundId == 1001, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
1871 SetFocus(GetNextDlgTabItem(hDlg, NULL, FALSE));
1873 /* de- then reactivate the dialog */
1874 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1875 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1877 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1878 ok (foundId == 1000, "First edit box should have regained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1000, foundId);
1880 /* select the next tabbable item */
1881 SetFocus(GetNextDlgTabItem(hDlg, GetFocus(), FALSE));
1883 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1884 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1886 /* de- then reactivate the dialog */
1887 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1888 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1890 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1891 ok (foundId == 1001, "Second edit box should have gained focus after dialog reactivation. Expected: %d, Found: %ld\n", 1001, foundId);
1893 /* set focus to the dialog */
1894 SetFocus(hDlg);
1896 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1897 ok (foundId == 1000, "First edit box should have gained focus on dialog focus. Expected: %d, Found: %ld\n", 1000, foundId);
1899 /* select second tabbable item */
1900 SetFocus(GetNextDlgTabItem(hDlg, GetNextDlgTabItem(hDlg, NULL, FALSE), FALSE));
1902 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1903 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1905 /* send WM_ACTIVATE message to already active dialog */
1906 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1908 foundId = GetWindowLongPtrA(GetFocus(), GWLP_ID);
1909 ok (foundId == 1001, "Second edit box should have gained focus. Expected: %d, Found: %ld\n", 1001, foundId);
1911 /* disable the 2nd box */
1912 EnableWindow(GetFocus(), FALSE);
1914 foundHwnd = GetFocus();
1915 ok (foundHwnd == NULL, "Second edit box should have lost focus after being disabled. Expected: %p, Found: %p\n", NULL, foundHwnd);
1917 /* de- then reactivate the dialog */
1918 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), 0);
1919 SendMessageA(hDlg, WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), 0);
1921 foundHwnd = GetFocus();
1922 ok (foundHwnd == NULL, "No controls should have gained focus after dialog reactivation. Expected: %p, Found: %p\n", NULL, foundHwnd);
1924 /* clean up */
1925 DestroyWindow(hDlg);
1928 static INT_PTR CALLBACK timer_message_dlg_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
1930 static int count;
1931 BOOL visible;
1933 switch (msg)
1935 case WM_INITDIALOG:
1936 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1937 ok(!visible, "Dialog should not be visible.\n");
1938 SetTimer(wnd, 1, 100, NULL);
1939 Sleep(200);
1940 return FALSE;
1942 case WM_COMMAND:
1943 if (LOWORD(wparam) != IDCANCEL) return FALSE;
1944 EndDialog(wnd, LOWORD(wparam));
1945 return TRUE;
1947 case WM_TIMER:
1948 if (wparam != 1) return FALSE;
1949 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1950 if (!count++)
1952 ok(!visible, "Dialog should not be visible.\n");
1953 PostMessageA(wnd, WM_USER, 0, 0);
1955 else
1957 ok(visible, "Dialog should be visible.\n");
1958 PostMessageA(wnd, WM_COMMAND, IDCANCEL, 0);
1960 return TRUE;
1962 case WM_USER:
1963 visible = GetWindowLongA(wnd, GWL_STYLE) & WS_VISIBLE;
1964 ok(visible, "Dialog should be visible.\n");
1965 return TRUE;
1967 default:
1968 return FALSE;
1972 static void test_timer_message(void)
1974 DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, timer_message_dlg_proc);
1977 static LRESULT CALLBACK msgbox_hook_proc(INT code, WPARAM wParam, LPARAM lParam)
1979 if (code == HCBT_ACTIVATE)
1981 HWND msgbox = (HWND)wParam, msghwnd;
1982 char text[64];
1984 if (msgbox)
1986 text[0] = 0;
1987 GetWindowTextA(msgbox, text, sizeof(text));
1988 ok(!strcmp(text, "MSGBOX caption"), "Unexpected window text \"%s\"\n", text);
1990 msghwnd = GetDlgItem(msgbox, 0xffff);
1991 ok(msghwnd != NULL, "Expected static control\n");
1993 text[0] = 0;
1994 GetWindowTextA(msghwnd, text, sizeof(text));
1995 ok(!strcmp(text, "Text"), "Unexpected window text \"%s\"\n", text);
1997 SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONDOWN, 0, 0);
1998 SendDlgItemMessageA(msgbox, IDCANCEL, WM_LBUTTONUP, 0, 0);
2002 return CallNextHookEx(NULL, code, wParam, lParam);
2005 static void test_MessageBox(void)
2007 HHOOK hook;
2008 int ret;
2010 hook = SetWindowsHookExA(WH_CBT, msgbox_hook_proc, NULL, GetCurrentThreadId());
2012 ret = MessageBoxA(NULL, "Text", "MSGBOX caption", MB_OKCANCEL);
2013 ok(ret == IDCANCEL, "got %d\n", ret);
2015 UnhookWindowsHookEx(hook);
2018 START_TEST(dialog)
2020 g_hinst = GetModuleHandleA (0);
2022 if (!RegisterWindowClasses()) assert(0);
2024 test_GetNextDlgItem();
2025 test_IsDialogMessage();
2026 test_WM_NEXTDLGCTL();
2027 test_focus();
2028 test_GetDlgItem();
2029 test_GetDlgItemText();
2030 test_DialogBoxParam();
2031 test_DisabledDialogTest();
2032 test_MessageBoxFontTest();
2033 test_SaveRestoreFocus();
2034 test_timer_message();
2035 test_MessageBox();