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