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