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