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