1 /* Unit test suite for property sheet control. 2 * 3 * Copyright 2006 Huw Davies 4 * Copyright 2009 Jan de Mooij 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "precomp.h" 22 23 #include <reactos/undocuser.h> 24 25 static HWND parenthwnd; 26 static HWND sheethwnd; 27 28 static BOOL rtl; 29 static LONG active_page = -1; 30 31 #define IDC_APPLY_BUTTON 12321 32 33 34 static void detect_locale(void) 35 { 36 DWORD reading_layout; 37 rtl = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IREADINGLAYOUT | LOCALE_RETURN_NUMBER, 38 (void *)&reading_layout, sizeof(reading_layout)) && reading_layout == 1; 39 } 40 41 /* try to make sure pending X events have been processed before continuing */ 42 static void flush_events(void) 43 { 44 MSG msg; 45 int diff = 200; 46 int min_timeout = 100; 47 DWORD time = GetTickCount() + diff; 48 49 while (diff > 0) 50 { 51 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min_timeout, QS_ALLINPUT ) == WAIT_TIMEOUT) break; 52 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); 53 diff = time - GetTickCount(); 54 } 55 } 56 57 58 static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam) 59 { 60 switch(msg) 61 { 62 case PSCB_PRECREATE: 63 { 64 HMODULE module = GetModuleHandleA("comctl32.dll"); 65 DWORD size, buffer_size; 66 HRSRC hrsrc; 67 68 hrsrc = FindResourceA(module, MAKEINTRESOURCEA(1006 /* IDD_PROPSHEET */), 69 (LPSTR)RT_DIALOG); 70 size = SizeofResource(module, hrsrc); 71 ok(size != 0, "Failed to get size of propsheet dialog resource\n"); 72 buffer_size = HeapSize(GetProcessHeap(), 0, (void *)lparam); 73 ok(buffer_size == 2 * size, "Unexpected template buffer size %u, resource size %u\n", 74 buffer_size, size); 75 break; 76 } 77 case PSCB_INITIALIZED: 78 { 79 char caption[256]; 80 GetWindowTextA(hwnd, caption, sizeof(caption)); 81 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption); 82 sheethwnd = hwnd; 83 return 0; 84 } 85 } 86 return 0; 87 } 88 89 static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, 90 LPARAM lparam) 91 { 92 switch(msg) 93 { 94 case WM_INITDIALOG: 95 { 96 HWND sheet = GetParent(hwnd); 97 char caption[256]; 98 GetWindowTextA(sheet, caption, sizeof(caption)); 99 ok(!strcmp(caption,"test caption"), "caption: %s\n", caption); 100 return TRUE; 101 } 102 103 case WM_NOTIFY: 104 { 105 NMHDR *nmhdr = (NMHDR *)lparam; 106 switch(nmhdr->code) 107 { 108 case PSN_APPLY: 109 return TRUE; 110 default: 111 return FALSE; 112 } 113 } 114 case WM_NCDESTROY: 115 ok(!SendMessageA(sheethwnd, PSM_INDEXTOHWND, 400, 0),"Should always be 0\n"); 116 return TRUE; 117 118 default: 119 return FALSE; 120 } 121 } 122 123 static void test_title(void) 124 { 125 HPROPSHEETPAGE hpsp[1]; 126 PROPSHEETPAGEA psp; 127 PROPSHEETHEADERA psh; 128 HWND hdlg; 129 DWORD style; 130 131 memset(&psp, 0, sizeof(psp)); 132 psp.dwSize = sizeof(psp); 133 psp.dwFlags = 0; 134 psp.hInstance = GetModuleHandleA(NULL); 135 U(psp).pszTemplate = "prop_page1"; 136 U2(psp).pszIcon = NULL; 137 psp.pfnDlgProc = page_dlg_proc; 138 psp.lParam = 0; 139 140 hpsp[0] = CreatePropertySheetPageA(&psp); 141 142 memset(&psh, 0, sizeof(psh)); 143 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 144 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; 145 psh.pszCaption = "test caption"; 146 psh.nPages = 1; 147 psh.hwndParent = GetDesktopWindow(); 148 U3(psh).phpage = hpsp; 149 psh.pfnCallback = sheet_callback; 150 151 hdlg = (HWND)PropertySheetA(&psh); 152 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg); 153 154 style = GetWindowLongA(hdlg, GWL_STYLE); 155 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU| 156 DS_CONTEXTHELP|DS_MODALFRAME|DS_SETFONT|DS_3DLOOK), 157 "got unexpected style: %x\n", style); 158 159 DestroyWindow(hdlg); 160 } 161 162 static void test_nopage(void) 163 { 164 HPROPSHEETPAGE hpsp[1]; 165 PROPSHEETPAGEA psp; 166 PROPSHEETHEADERA psh; 167 HWND hdlg, hpage; 168 MSG msg; 169 170 memset(&psp, 0, sizeof(psp)); 171 psp.dwSize = sizeof(psp); 172 psp.dwFlags = 0; 173 psp.hInstance = GetModuleHandleA(NULL); 174 U(psp).pszTemplate = "prop_page1"; 175 U2(psp).pszIcon = NULL; 176 psp.pfnDlgProc = page_dlg_proc; 177 psp.lParam = 0; 178 179 hpsp[0] = CreatePropertySheetPageA(&psp); 180 181 memset(&psh, 0, sizeof(psh)); 182 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 183 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; 184 psh.pszCaption = "test caption"; 185 psh.nPages = 1; 186 psh.hwndParent = GetDesktopWindow(); 187 U3(psh).phpage = hpsp; 188 psh.pfnCallback = sheet_callback; 189 190 hdlg = (HWND)PropertySheetA(&psh); 191 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle value %p\n", hdlg); 192 193 ShowWindow(hdlg,SW_NORMAL); 194 SendMessageA(hdlg, PSM_REMOVEPAGE, 0, 0); 195 hpage = /* PropSheet_GetCurrentPageHwnd(hdlg); */ 196 (HWND)SendMessageA(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0); 197 active_page = /* PropSheet_HwndToIndex(hdlg, hpage)); */ 198 (int)SendMessageA(hdlg, PSM_HWNDTOINDEX, (WPARAM)hpage, 0); 199 ok(hpage == NULL, "expected no current page, got %p, index=%d\n", hpage, active_page); 200 flush_events(); 201 RedrawWindow(hdlg,NULL,NULL,RDW_UPDATENOW|RDW_ERASENOW); 202 203 /* Check that the property sheet was fully redrawn */ 204 ok(!PeekMessageA(&msg, 0, WM_PAINT, WM_PAINT, PM_NOREMOVE), 205 "expected no pending WM_PAINT messages\n"); 206 DestroyWindow(hdlg); 207 } 208 209 static int CALLBACK disableowner_callback(HWND hwnd, UINT msg, LPARAM lparam) 210 { 211 switch(msg) 212 { 213 case PSCB_INITIALIZED: 214 { 215 ok(IsWindowEnabled(parenthwnd) == 0, "parent window should be disabled\n"); 216 PostQuitMessage(0); 217 return FALSE; 218 } 219 } 220 return FALSE; 221 } 222 223 static void register_parent_wnd_class(void) 224 { 225 WNDCLASSA cls; 226 227 cls.style = 0; 228 cls.lpfnWndProc = DefWindowProcA; 229 cls.cbClsExtra = 0; 230 cls.cbWndExtra = 0; 231 cls.hInstance = GetModuleHandleA(NULL); 232 cls.hIcon = 0; 233 cls.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW); 234 cls.hbrBackground = GetStockObject(WHITE_BRUSH); 235 cls.lpszMenuName = NULL; 236 cls.lpszClassName = "parent class"; 237 RegisterClassA(&cls); 238 } 239 240 static void test_disableowner(void) 241 { 242 HPROPSHEETPAGE hpsp[1]; 243 PROPSHEETPAGEA psp; 244 PROPSHEETHEADERA psh; 245 INT_PTR p; 246 247 register_parent_wnd_class(); 248 parenthwnd = CreateWindowA("parent class", "", WS_CAPTION | WS_SYSMENU | WS_VISIBLE, 100, 100, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), 0); 249 250 memset(&psp, 0, sizeof(psp)); 251 psp.dwSize = sizeof(psp); 252 psp.dwFlags = 0; 253 psp.hInstance = GetModuleHandleA(NULL); 254 U(psp).pszTemplate = "prop_page1"; 255 U2(psp).pszIcon = NULL; 256 psp.pfnDlgProc = NULL; 257 psp.lParam = 0; 258 259 hpsp[0] = CreatePropertySheetPageA(&psp); 260 261 memset(&psh, 0, sizeof(psh)); 262 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 263 psh.dwFlags = PSH_USECALLBACK; 264 psh.pszCaption = "test caption"; 265 psh.nPages = 1; 266 psh.hwndParent = parenthwnd; 267 U3(psh).phpage = hpsp; 268 psh.pfnCallback = disableowner_callback; 269 270 p = PropertySheetA(&psh); 271 todo_wine 272 ok(p == 0, "Expected 0, got %ld\n", p); 273 ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n"); 274 DestroyWindow(parenthwnd); 275 } 276 277 static INT_PTR CALLBACK nav_page_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 278 { 279 switch(msg){ 280 case WM_NOTIFY: 281 { 282 LPNMHDR hdr = (LPNMHDR)lparam; 283 switch(hdr->code){ 284 case PSN_SETACTIVE: 285 active_page = /* PropSheet_HwndToIndex(hdr->hwndFrom, hwnd); */ 286 (int)SendMessageA(hdr->hwndFrom, PSM_HWNDTOINDEX, (WPARAM)hwnd, 0); 287 return TRUE; 288 case PSN_KILLACTIVE: 289 /* prevent navigation away from the fourth page */ 290 if(active_page == 3){ 291 SetWindowLongPtrA(hwnd, DWLP_MSGRESULT, TRUE); 292 return TRUE; 293 } 294 } 295 break; 296 } 297 } 298 return FALSE; 299 } 300 301 static WNDPROC old_nav_dialog_proc; 302 303 static LRESULT CALLBACK new_nav_dialog_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) 304 { 305 switch (msg) 306 { 307 case DM_SETDEFID: 308 ok( IsWindowEnabled( GetDlgItem(hwnd, wp) ), "button is not enabled\n" ); 309 break; 310 } 311 return CallWindowProcW( old_nav_dialog_proc, hwnd, msg, wp, lp ); 312 } 313 314 static LRESULT CALLBACK hook_proc( int code, WPARAM wp, LPARAM lp ) 315 { 316 static BOOL done; 317 if (code == HCBT_CREATEWND) 318 { 319 CBT_CREATEWNDW *c = (CBT_CREATEWNDW *)lp; 320 321 /* The first dialog created will be the parent dialog */ 322 if (!done && c->lpcs->lpszClass == (LPWSTR)WC_DIALOG) 323 { 324 old_nav_dialog_proc = (WNDPROC)SetWindowLongPtrW( (HWND)wp, GWLP_WNDPROC, (LONG_PTR)new_nav_dialog_proc ); 325 done = TRUE; 326 } 327 } 328 329 return CallNextHookEx( NULL, code, wp, lp ); 330 } 331 332 static void test_wiznavigation(void) 333 { 334 HPROPSHEETPAGE hpsp[4]; 335 PROPSHEETPAGEA psp[4]; 336 PROPSHEETHEADERA psh; 337 HWND hdlg, control; 338 LONG_PTR controlID; 339 DWORD style; 340 LRESULT defidres; 341 BOOL hwndtoindex_supported = TRUE; 342 const INT nextID = 12324; 343 const INT backID = 12323; 344 HHOOK hook; 345 346 /* set up a hook proc in order to subclass the main dialog early on */ 347 hook = SetWindowsHookExW( WH_CBT, hook_proc, NULL, GetCurrentThreadId() ); 348 349 /* create the property sheet pages */ 350 memset(psp, 0, sizeof(PROPSHEETPAGEA) * 4); 351 352 psp[0].dwSize = sizeof(PROPSHEETPAGEA); 353 psp[0].hInstance = GetModuleHandleA(NULL); 354 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_INTRO); 355 psp[0].pfnDlgProc = nav_page_proc; 356 hpsp[0] = CreatePropertySheetPageA(&psp[0]); 357 358 psp[1].dwSize = sizeof(PROPSHEETPAGEA); 359 psp[1].hInstance = GetModuleHandleA(NULL); 360 U(psp[1]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EDIT); 361 psp[1].pfnDlgProc = nav_page_proc; 362 hpsp[1] = CreatePropertySheetPageA(&psp[1]); 363 364 psp[2].dwSize = sizeof(PROPSHEETPAGEA); 365 psp[2].hInstance = GetModuleHandleA(NULL); 366 U(psp[2]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_RADIO); 367 psp[2].pfnDlgProc = nav_page_proc; 368 hpsp[2] = CreatePropertySheetPageA(&psp[2]); 369 370 psp[3].dwSize = sizeof(PROPSHEETPAGEA); 371 psp[3].hInstance = GetModuleHandleA(NULL); 372 U(psp[3]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_EXIT); 373 psp[3].pfnDlgProc = nav_page_proc; 374 hpsp[3] = CreatePropertySheetPageA(&psp[3]); 375 376 /* set up the property sheet dialog */ 377 memset(&psh, 0, sizeof(psh)); 378 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 379 psh.dwFlags = PSH_MODELESS | PSH_WIZARD; 380 psh.pszCaption = "A Wizard"; 381 psh.nPages = 4; 382 psh.hwndParent = GetDesktopWindow(); 383 U3(psh).phpage = hpsp; 384 hdlg = (HWND)PropertySheetA(&psh); 385 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); 386 387 ok(active_page == 0, "Active page should be 0. Is: %d\n", active_page); 388 389 style = GetWindowLongA(hdlg, GWL_STYLE) & ~(DS_CONTEXTHELP|WS_SYSMENU); 390 ok(style == (WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION| 391 DS_MODALFRAME|DS_SETFONT|DS_3DLOOK), 392 "got unexpected style: %x\n", style); 393 394 control = GetFocus(); 395 controlID = GetWindowLongPtrA(control, GWLP_ID); 396 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); 397 398 /* simulate pressing the Next button */ 399 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); 400 if (!active_page) hwndtoindex_supported = FALSE; 401 if (hwndtoindex_supported) 402 ok(active_page == 1, "Active page should be 1 after pressing Next. Is: %d\n", active_page); 403 404 control = GetFocus(); 405 controlID = GetWindowLongPtrA(control, GWLP_ID); 406 ok(controlID == IDC_PS_EDIT1, "Focus should be set to the first item on the second page. Expected: %d, Found: %ld\n", IDC_PS_EDIT1, controlID); 407 408 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); 409 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); 410 411 /* set the focus to the second edit box on this page */ 412 SetFocus(GetNextDlgTabItem(hdlg, control, FALSE)); 413 414 /* press next again */ 415 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); 416 if (hwndtoindex_supported) 417 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); 418 419 control = GetFocus(); 420 controlID = GetWindowLongPtrA(control, GWLP_ID); 421 ok(controlID == IDC_PS_RADIO1, "Focus should have been set to item on third page. Expected: %d, Found %ld\n", IDC_PS_RADIO1, controlID); 422 423 /* back button */ 424 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); 425 if (hwndtoindex_supported) 426 ok(active_page == 1, "Active page should be 1 after pressing Back. Is: %d\n", active_page); 427 428 control = GetFocus(); 429 controlID = GetWindowLongPtrA(control, GWLP_ID); 430 ok(controlID == IDC_PS_EDIT1, "Focus should have been set to the first item on second page. Expected: %d, Found %ld\n", IDC_PS_EDIT1, controlID); 431 432 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); 433 ok(defidres == MAKELRESULT(backID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", backID, LOWORD(defidres)); 434 435 /* press next twice */ 436 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); 437 if (hwndtoindex_supported) 438 ok(active_page == 2, "Active page should be 2 after pressing Next. Is: %d\n", active_page); 439 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_NEXT, 0); 440 if (hwndtoindex_supported) 441 ok(active_page == 3, "Active page should be 3 after pressing Next. Is: %d\n", active_page); 442 else 443 active_page = 3; 444 445 control = GetFocus(); 446 controlID = GetWindowLongPtrA(control, GWLP_ID); 447 ok(controlID == nextID, "Focus should have been set to the Next button. Expected: %d, Found: %ld\n", nextID, controlID); 448 449 /* try to navigate away, but shouldn't be able to */ 450 SendMessageA(hdlg, PSM_PRESSBUTTON, PSBTN_BACK, 0); 451 ok(active_page == 3, "Active page should still be 3 after pressing Back. Is: %d\n", active_page); 452 453 defidres = SendMessageA(hdlg, DM_GETDEFID, 0, 0); 454 ok(defidres == MAKELRESULT(nextID, DC_HASDEFID), "Expected default button ID to be %d, is %d\n", nextID, LOWORD(defidres)); 455 456 DestroyWindow(hdlg); 457 UnhookWindowsHookEx( hook ); 458 } 459 460 static void test_buttons(void) 461 { 462 HPROPSHEETPAGE hpsp[1]; 463 PROPSHEETPAGEA psp; 464 PROPSHEETHEADERA psh; 465 HWND hdlg; 466 HWND button; 467 RECT rc; 468 int prevRight, top; 469 470 memset(&psp, 0, sizeof(psp)); 471 psp.dwSize = sizeof(psp); 472 psp.dwFlags = 0; 473 psp.hInstance = GetModuleHandleA(NULL); 474 U(psp).pszTemplate = "prop_page1"; 475 U2(psp).pszIcon = NULL; 476 psp.pfnDlgProc = page_dlg_proc; 477 psp.lParam = 0; 478 479 hpsp[0] = CreatePropertySheetPageA(&psp); 480 481 memset(&psh, 0, sizeof(psh)); 482 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 483 psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK; 484 psh.pszCaption = "test caption"; 485 psh.nPages = 1; 486 psh.hwndParent = GetDesktopWindow(); 487 U3(psh).phpage = hpsp; 488 psh.pfnCallback = sheet_callback; 489 490 hdlg = (HWND)PropertySheetA(&psh); 491 ok(hdlg != INVALID_HANDLE_VALUE, "got null handle\n"); 492 493 /* OK button */ 494 button = GetDlgItem(hdlg, IDOK); 495 GetWindowRect(button, &rc); 496 prevRight = rc.right; 497 top = rc.top; 498 499 /* Cancel button */ 500 button = GetDlgItem(hdlg, IDCANCEL); 501 GetWindowRect(button, &rc); 502 ok(rc.top == top, "Cancel button should have same top as OK button\n"); 503 if (rtl) 504 ok(rc.left < prevRight, "Cancel button should be to the left of OK button\n"); 505 else 506 ok(rc.left > prevRight, "Cancel button should be to the right of OK button\n"); 507 prevRight = rc.right; 508 509 button = GetDlgItem(hdlg, IDC_APPLY_BUTTON); 510 GetWindowRect(button, &rc); 511 ok(rc.top == top, "Apply button should have same top as OK button\n"); 512 if (rtl) 513 ok(rc.left < prevRight, "Apply button should be to the left of Cancel button\n"); 514 else 515 ok(rc.left > prevRight, "Apply button should be to the right of Cancel button\n"); 516 prevRight = rc.right; 517 518 button = GetDlgItem(hdlg, IDHELP); 519 GetWindowRect(button, &rc); 520 ok(rc.top == top, "Help button should have same top as OK button\n"); 521 if (rtl) 522 ok(rc.left < prevRight, "Help button should be to the left of Apply button\n"); 523 else 524 ok(rc.left > prevRight, "Help button should be to the right of Apply button\n"); 525 526 DestroyWindow(hdlg); 527 } 528 529 static BOOL add_button_has_been_pressed; 530 531 static INT_PTR CALLBACK 532 page_with_custom_default_button_dlg_proc(HWND hdlg, UINT msg, WPARAM wparam, LPARAM lparam) 533 { 534 switch (msg) 535 { 536 case WM_COMMAND: 537 switch(LOWORD(wparam)) 538 { 539 case IDC_PS_PUSHBUTTON1: 540 switch(HIWORD(wparam)) 541 { 542 case BN_CLICKED: 543 add_button_has_been_pressed = TRUE; 544 return TRUE; 545 } 546 break; 547 } 548 break; 549 } 550 return FALSE; 551 } 552 553 static void test_custom_default_button(void) 554 { 555 HWND hdlg, page; 556 PROPSHEETPAGEA psp[1]; 557 PROPSHEETHEADERA psh; 558 MSG msg; 559 LRESULT result; 560 561 psp[0].dwSize = sizeof (PROPSHEETPAGEA); 562 psp[0].dwFlags = PSP_USETITLE; 563 psp[0].hInstance = GetModuleHandleA(NULL); 564 U(psp[0]).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON); 565 U2(psp[0]).pszIcon = NULL; 566 psp[0].pfnDlgProc = page_with_custom_default_button_dlg_proc; 567 psp[0].pszTitle = "Page1"; 568 psp[0].lParam = 0; 569 570 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 571 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS; 572 psh.hwndParent = GetDesktopWindow(); 573 psh.hInstance = GetModuleHandleA(NULL); 574 U(psh).pszIcon = NULL; 575 psh.pszCaption = "PropertySheet1"; 576 psh.nPages = 1; 577 U3(psh).ppsp = psp; 578 U2(psh).nStartPage = 0; 579 580 /* The goal of the test is to make sure that the Add button is pressed 581 * when the ENTER key is pressed and a different control, a combobox, 582 * has the keyboard focus. */ 583 add_button_has_been_pressed = FALSE; 584 585 /* Create the modeless property sheet. */ 586 hdlg = (HWND)PropertySheetA(&psh); 587 ok(hdlg != INVALID_HANDLE_VALUE, "Cannot create the property sheet\n"); 588 589 /* Set the Add button as the default button. */ 590 SendMessageA(hdlg, DM_SETDEFID, (WPARAM)IDC_PS_PUSHBUTTON1, 0); 591 592 /* Make sure the default button is the Add button. */ 593 result = SendMessageA(hdlg, DM_GETDEFID, 0, 0); 594 ok(DC_HASDEFID == HIWORD(result), "The property sheet does not have a default button\n"); 595 ok(IDC_PS_PUSHBUTTON1 == LOWORD(result), "The default button is not the Add button\n"); 596 597 /* At this point, the combobox should have keyboard focus, so we press ENTER. 598 * Pull the lever, Kronk! */ 599 page = (HWND)SendMessageW(hdlg, PSM_GETCURRENTPAGEHWND, 0, 0); 600 PostMessageW(GetDlgItem(page, IDC_PS_COMBO1), WM_KEYDOWN, VK_RETURN, 0); 601 602 /* Process all the messages in the queue for this thread. */ 603 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) 604 { 605 /* (!PropSheet_IsDialogMessage(hdlg, &msg)) */ 606 if (!((BOOL)SendMessageA(hdlg, PSM_ISDIALOGMESSAGE, 0, (LPARAM)&msg))) 607 { 608 TranslateMessage(&msg); 609 DispatchMessageA(&msg); 610 } 611 } 612 613 ok(add_button_has_been_pressed, "The Add button has not been pressed!\n"); 614 615 DestroyWindow(hdlg); 616 } 617 618 #define RECEIVER_SHEET_CALLBACK 0 619 #define RECEIVER_SHEET_WINPROC 1 620 #define RECEIVER_PAGE 2 621 622 #define NUM_MSG_SEQUENCES 1 623 #define PROPSHEET_SEQ_INDEX 0 624 625 static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; 626 static WNDPROC oldWndProc; 627 628 static const struct message property_sheet_seq[] = { 629 { PSCB_PRECREATE, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK }, 630 { PSCB_INITIALIZED, sent|id, 0, 0, RECEIVER_SHEET_CALLBACK }, 631 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 632 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 633 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 634 { WM_MOVE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 635 { WM_SIZE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 636 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 637 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 638 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 639 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 640 { WM_NCCALCSIZE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 641 { DM_REPOSITION, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 642 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 643 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 644 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 645 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 646 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 647 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 648 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 649 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 650 { WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 651 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 652 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 653 { WM_IME_NOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 654 { WM_SETFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 655 { WM_KILLFOCUS, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 656 /*{ WM_IME_SETCONTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 657 { WM_PARENTNOTIFY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 658 { WM_INITDIALOG, sent|id, 0, 0, RECEIVER_PAGE }, 659 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_PAGE }, 660 /*{ WM_NCCALCSIZE, sent|id, 0, 0, RECEIVER_PAGE },*/ 661 { WM_CHILDACTIVATE, sent|id, 0, 0, RECEIVER_PAGE }, 662 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_PAGE }, 663 { WM_MOVE, sent|id, 0, 0, RECEIVER_PAGE }, 664 { WM_SIZE, sent|id, 0, 0, RECEIVER_PAGE }, 665 { WM_NOTIFY, sent|id, 0, 0, RECEIVER_PAGE }, 666 { WM_STYLECHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 667 { WM_STYLECHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 668 /*{ WM_GETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 669 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 670 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 671 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 672 { WM_SETTEXT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 673 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_PAGE }, 674 /*{ 0x00000401, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 675 { 0x00000400, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 676 { WM_CHANGEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 677 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 678 { WM_UPDATEUISTATE, sent|id|optional, 0, 0, RECEIVER_PAGE }, 679 { WM_SHOWWINDOW, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 680 { WM_WINDOWPOSCHANGING, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 681 /*{ WM_NCPAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 682 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 683 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 684 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 685 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 686 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 687 { WM_WINDOWPOSCHANGED, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 688 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 689 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 690 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 691 { WM_PAINT, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 692 { WM_PAINT, sent|id, 0, 0, RECEIVER_PAGE }, 693 { WM_NCPAINT, sent|id, 0, 0, RECEIVER_PAGE }, 694 { WM_ERASEBKGND, sent|id, 0, 0, RECEIVER_PAGE },*/ 695 { WM_CTLCOLORDLG, sent|id, 0, 0, RECEIVER_PAGE }, 696 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_PAGE }, 697 { WM_CTLCOLORSTATIC, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 698 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 699 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 700 { WM_CTLCOLORBTN, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 701 /*{ WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 702 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 703 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 704 { WM_COMMAND, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 705 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE }, 706 { WM_NOTIFY, sent|id|optional, 0, 0, RECEIVER_PAGE }, 707 { WM_WINDOWPOSCHANGING, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 708 { WM_WINDOWPOSCHANGED, sent|id|optional, 0, 0, RECEIVER_SHEET_WINPROC }, 709 /*{ WM_NCACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 710 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 711 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 712 { WM_GETICON, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 713 /*{ WM_ACTIVATE, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 714 { WM_ACTIVATE, sent|id, 0, 0, RECEIVER_PAGE }, 715 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 716 { WM_ACTIVATEAPP, sent|id, 0, 0, RECEIVER_PAGE }, 717 { WM_DESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC }, 718 { WM_DESTROY, sent|id, 0, 0, RECEIVER_PAGE },*/ 719 /*{ WM_NCDESTROY, sent|id, 0, 0, RECEIVER_PAGE }, 720 { WM_NCDESTROY, sent|id, 0, 0, RECEIVER_SHEET_WINPROC },*/ 721 { 0 } 722 }; 723 724 static void save_message(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, INT receiver) 725 { 726 struct message msg = { 0 }; 727 728 if (message < WM_USER && 729 message != WM_GETICON && 730 message != WM_GETTEXT && 731 message != WM_IME_SETCONTEXT && 732 message != WM_IME_NOTIFY && 733 message != WM_PAINT && 734 message != WM_ERASEBKGND && 735 message != WM_SETCURSOR && 736 (message < WM_NCCREATE || message > WM_NCMBUTTONDBLCLK) && 737 (message < WM_MOUSEFIRST || message > WM_MOUSEHWHEEL) && 738 message != 0x90) 739 { 740 msg.message = message; 741 msg.flags = sent|wparam|lparam|id; 742 msg.wParam = wParam; 743 msg.lParam = lParam; 744 msg.id = receiver; 745 add_message(sequences, PROPSHEET_SEQ_INDEX, &msg); 746 } 747 } 748 749 static LRESULT CALLBACK sheet_callback_messages_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 750 { 751 save_message(hwnd, msg, wParam, lParam, RECEIVER_SHEET_WINPROC); 752 753 return CallWindowProcA(oldWndProc, hwnd, msg, wParam, lParam); 754 } 755 756 static int CALLBACK sheet_callback_messages(HWND hwnd, UINT msg, LPARAM lParam) 757 { 758 save_message(hwnd, msg, 0, lParam, RECEIVER_SHEET_CALLBACK); 759 760 switch (msg) 761 { 762 case PSCB_INITIALIZED: 763 oldWndProc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); 764 SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)&sheet_callback_messages_proc); 765 return TRUE; 766 } 767 768 return TRUE; 769 } 770 771 static INT_PTR CALLBACK page_dlg_proc_messages(HWND hwnd, UINT msg, WPARAM wParam, 772 LPARAM lParam) 773 { 774 save_message(hwnd, msg, wParam, lParam, RECEIVER_PAGE); 775 776 return FALSE; 777 } 778 779 static void test_messages(void) 780 { 781 HPROPSHEETPAGE hpsp[1]; 782 PROPSHEETPAGEA psp; 783 PROPSHEETHEADERA psh; 784 HWND hdlg; 785 786 init_msg_sequences(sequences, NUM_MSG_SEQUENCES); 787 788 memset(&psp, 0, sizeof(psp)); 789 psp.dwSize = sizeof(psp); 790 psp.dwFlags = 0; 791 psp.hInstance = GetModuleHandleA(NULL); 792 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST); 793 U2(psp).pszIcon = NULL; 794 psp.pfnDlgProc = page_dlg_proc_messages; 795 psp.lParam = 0; 796 797 hpsp[0] = CreatePropertySheetPageA(&psp); 798 799 memset(&psh, 0, sizeof(psh)); 800 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 801 psh.dwFlags = PSH_NOAPPLYNOW | PSH_WIZARD | PSH_USECALLBACK 802 | PSH_MODELESS | PSH_USEICONID; 803 psh.pszCaption = "test caption"; 804 psh.nPages = 1; 805 psh.hwndParent = GetDesktopWindow(); 806 U3(psh).phpage = hpsp; 807 psh.pfnCallback = sheet_callback_messages; 808 809 hdlg = (HWND)PropertySheetA(&psh); 810 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); 811 812 ShowWindow(hdlg,SW_NORMAL); 813 814 ok_sequence(sequences, PROPSHEET_SEQ_INDEX, property_sheet_seq, "property sheet with custom window proc", TRUE); 815 816 DestroyWindow(hdlg); 817 } 818 819 static void test_PSM_ADDPAGE(void) 820 { 821 HPROPSHEETPAGE hpsp[5]; 822 PROPSHEETPAGEA psp; 823 PROPSHEETHEADERA psh; 824 HWND hdlg, tab; 825 BOOL ret; 826 DWORD r; 827 828 memset(&psp, 0, sizeof(psp)); 829 psp.dwSize = sizeof(psp); 830 psp.dwFlags = 0; 831 psp.hInstance = GetModuleHandleA(NULL); 832 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST); 833 U2(psp).pszIcon = NULL; 834 psp.pfnDlgProc = page_dlg_proc_messages; 835 psp.lParam = 0; 836 837 /* multiple pages with the same data */ 838 hpsp[0] = CreatePropertySheetPageA(&psp); 839 hpsp[1] = CreatePropertySheetPageA(&psp); 840 hpsp[2] = CreatePropertySheetPageA(&psp); 841 842 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR); 843 hpsp[3] = CreatePropertySheetPageA(&psp); 844 845 psp.dwFlags = PSP_PREMATURE; 846 hpsp[4] = CreatePropertySheetPageA(&psp); 847 848 memset(&psh, 0, sizeof(psh)); 849 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 850 psh.dwFlags = PSH_MODELESS; 851 psh.pszCaption = "test caption"; 852 psh.nPages = 1; 853 psh.hwndParent = GetDesktopWindow(); 854 U3(psh).phpage = hpsp; 855 856 hdlg = (HWND)PropertySheetA(&psh); 857 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); 858 859 /* add pages one by one */ 860 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[1]); 861 ok(ret == TRUE, "got %d\n", ret); 862 863 /* try with null and invalid value */ 864 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, 0); 865 ok(ret == FALSE, "got %d\n", ret); 866 867 if (0) 868 { 869 /* crashes on native */ 870 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE); 871 } 872 /* check item count */ 873 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0); 874 875 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 876 ok(r == 2, "got %d\n", r); 877 878 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[2]); 879 ok(ret == TRUE, "got %d\n", ret); 880 881 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 882 ok(r == 3, "got %d\n", r); 883 884 /* add property sheet page that can't be created */ 885 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[3]); 886 ok(ret == TRUE, "got %d\n", ret); 887 888 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 889 ok(r == 4, "got %d\n", r); 890 891 /* select page that can't be created */ 892 ret = SendMessageA(hdlg, PSM_SETCURSEL, 3, 1); 893 ok(ret == TRUE, "got %d\n", ret); 894 895 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 896 ok(r == 3, "got %d\n", r); 897 898 /* test PSP_PREMATURE flag with incorrect property sheet page */ 899 ret = SendMessageA(hdlg, PSM_ADDPAGE, 0, (LPARAM)hpsp[4]); 900 ok(ret == FALSE, "got %d\n", ret); 901 902 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 903 ok(r == 3, "got %d\n", r); 904 905 DestroyPropertySheetPage(hpsp[4]); 906 DestroyWindow(hdlg); 907 } 908 909 static void test_PSM_INSERTPAGE(void) 910 { 911 HPROPSHEETPAGE hpsp[5]; 912 PROPSHEETPAGEA psp; 913 PROPSHEETHEADERA psh; 914 HWND hdlg, tab; 915 BOOL ret; 916 DWORD r; 917 918 memset(&psp, 0, sizeof(psp)); 919 psp.dwSize = sizeof(psp); 920 psp.dwFlags = 0; 921 psp.hInstance = GetModuleHandleA(NULL); 922 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_MESSAGE_TEST); 923 U2(psp).pszIcon = NULL; 924 psp.pfnDlgProc = page_dlg_proc_messages; 925 psp.lParam = 0; 926 927 /* multiple pages with the same data */ 928 hpsp[0] = CreatePropertySheetPageA(&psp); 929 hpsp[1] = CreatePropertySheetPageA(&psp); 930 hpsp[2] = CreatePropertySheetPageA(&psp); 931 932 U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_ERROR); 933 hpsp[3] = CreatePropertySheetPageA(&psp); 934 935 psp.dwFlags = PSP_PREMATURE; 936 hpsp[4] = CreatePropertySheetPageA(&psp); 937 938 memset(&psh, 0, sizeof(psh)); 939 psh.dwSize = PROPSHEETHEADERA_V1_SIZE; 940 psh.dwFlags = PSH_MODELESS; 941 psh.pszCaption = "test caption"; 942 psh.nPages = 1; 943 psh.hwndParent = GetDesktopWindow(); 944 U3(psh).phpage = hpsp; 945 946 hdlg = (HWND)PropertySheetA(&psh); 947 ok(hdlg != INVALID_HANDLE_VALUE, "got invalid handle %p\n", hdlg); 948 949 /* add pages one by one */ 950 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 5, (LPARAM)hpsp[1]); 951 ok(ret == TRUE, "got %d\n", ret); 952 953 /* try with invalid values */ 954 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, 0); 955 ok(ret == FALSE, "got %d\n", ret); 956 957 if (0) 958 { 959 /* crashes on native */ 960 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)INVALID_HANDLE_VALUE); 961 } 962 963 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)INVALID_HANDLE_VALUE, (LPARAM)hpsp[2]); 964 ok(ret == FALSE, "got %d\n", ret); 965 966 /* check item count */ 967 tab = (HWND)SendMessageA(hdlg, PSM_GETTABCONTROL, 0, 0); 968 969 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 970 ok(r == 2, "got %d\n", r); 971 972 ret = SendMessageA(hdlg, PSM_INSERTPAGE, (WPARAM)hpsp[1], (LPARAM)hpsp[2]); 973 ok(ret == TRUE, "got %d\n", ret); 974 975 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 976 ok(r == 3, "got %d\n", r); 977 978 /* add property sheet page that can't be created */ 979 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 1, (LPARAM)hpsp[3]); 980 ok(ret == TRUE, "got %d\n", ret); 981 982 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 983 ok(r == 4, "got %d\n", r); 984 985 /* select page that can't be created */ 986 ret = SendMessageA(hdlg, PSM_SETCURSEL, 1, 0); 987 ok(ret == TRUE, "got %d\n", ret); 988 989 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 990 ok(r == 3, "got %d\n", r); 991 992 /* test PSP_PREMATURE flag with incorrect property sheet page */ 993 ret = SendMessageA(hdlg, PSM_INSERTPAGE, 0, (LPARAM)hpsp[4]); 994 ok(ret == FALSE, "got %d\n", ret); 995 996 r = SendMessageA(tab, TCM_GETITEMCOUNT, 0, 0); 997 ok(r == 3, "got %d\n", r); 998 999 DestroyPropertySheetPage(hpsp[4]); 1000 DestroyWindow(hdlg); 1001 } 1002 1003 struct custom_proppage 1004 { 1005 union 1006 { 1007 PROPSHEETPAGEA pageA; 1008 PROPSHEETPAGEW pageW; 1009 } u; 1010 unsigned int addref_called; 1011 unsigned int release_called; 1012 }; 1013 1014 static UINT CALLBACK proppage_callback_a(HWND hwnd, UINT msg, PROPSHEETPAGEA *psp) 1015 { 1016 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam; 1017 PROPSHEETPAGEA *psp_orig = &cpage->u.pageA; 1018 1019 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd); 1020 1021 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n", 1022 psp->lParam, psp); 1023 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n"); 1024 ok(!lstrcmpA(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n"); 1025 1026 switch (msg) 1027 { 1028 case PSPCB_ADDREF: 1029 ok(psp->dwSize > PROPSHEETPAGEA_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize); 1030 cpage->addref_called++; 1031 break; 1032 case PSPCB_RELEASE: 1033 ok(psp->dwSize >= PROPSHEETPAGEA_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize); 1034 cpage->release_called++; 1035 break; 1036 default: 1037 ok(0, "Unexpected message %u\n", msg); 1038 } 1039 1040 return 1; 1041 } 1042 1043 static UINT CALLBACK proppage_callback_w(HWND hwnd, UINT msg, PROPSHEETPAGEW *psp) 1044 { 1045 struct custom_proppage *cpage = (struct custom_proppage *)psp->lParam; 1046 PROPSHEETPAGEW *psp_orig = &cpage->u.pageW; 1047 1048 ok(hwnd == NULL, "Expected NULL hwnd, got %p\n", hwnd); 1049 ok(psp->lParam && psp->lParam != (LPARAM)psp, "Expected newly allocated page description, got %lx, %p\n", 1050 psp->lParam, psp); 1051 ok(psp_orig->pszTitle == psp->pszTitle, "Expected same page title pointer\n"); 1052 ok(!lstrcmpW(psp_orig->pszTitle, psp->pszTitle), "Expected same page title string\n"); 1053 1054 switch (msg) 1055 { 1056 case PSPCB_ADDREF: 1057 ok(psp->dwSize > PROPSHEETPAGEW_V1_SIZE, "Expected ADDREF for V2+ only, got size %u\n", psp->dwSize); 1058 cpage->addref_called++; 1059 break; 1060 case PSPCB_RELEASE: 1061 ok(psp->dwSize >= PROPSHEETPAGEW_V1_SIZE, "Unexpected RELEASE, got size %u\n", psp->dwSize); 1062 cpage->release_called++; 1063 break; 1064 default: 1065 ok(0, "Unexpected message %u\n", msg); 1066 } 1067 1068 return 1; 1069 } 1070 1071 static void test_CreatePropertySheetPage(void) 1072 { 1073 static const WCHAR titleW[] = {'T','i','t','l','e',0}; 1074 struct custom_proppage page; 1075 HPROPSHEETPAGE hpsp; 1076 BOOL ret; 1077 1078 memset(&page.u.pageA, 0, sizeof(page.u.pageA)); 1079 page.u.pageA.dwFlags = PSP_USECALLBACK; 1080 page.u.pageA.pfnDlgProc = page_dlg_proc_messages; 1081 page.u.pageA.pfnCallback = proppage_callback_a; 1082 page.u.pageA.lParam = (LPARAM)&page; 1083 page.u.pageA.pszTitle = "Title"; 1084 1085 /* Only minimal size validation is performed */ 1086 for (page.u.pageA.dwSize = PROPSHEETPAGEA_V1_SIZE - 1; page.u.pageA.dwSize <= PROPSHEETPAGEA_V4_SIZE + 1; page.u.pageA.dwSize++) 1087 { 1088 page.addref_called = 0; 1089 hpsp = CreatePropertySheetPageA(&page.u.pageA); 1090 1091 if (page.u.pageA.dwSize < PROPSHEETPAGEA_V1_SIZE) 1092 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageA.dwSize); 1093 else 1094 { 1095 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageA.dwSize); 1096 ok(page.addref_called == (page.u.pageA.dwSize > PROPSHEETPAGEA_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n"); 1097 } 1098 1099 if (hpsp) 1100 { 1101 page.release_called = 0; 1102 ret = DestroyPropertySheetPage(hpsp); 1103 ok(ret, "Failed to destroy a page\n"); 1104 ok(page.release_called == 1, "Expected RELEASE callback message\n"); 1105 } 1106 } 1107 1108 memset(&page.u.pageW, 0, sizeof(page.u.pageW)); 1109 page.u.pageW.dwFlags = PSP_USECALLBACK; 1110 page.u.pageW.pfnDlgProc = page_dlg_proc_messages; 1111 page.u.pageW.pfnCallback = proppage_callback_w; 1112 page.u.pageW.lParam = (LPARAM)&page; 1113 page.u.pageW.pszTitle = titleW; 1114 1115 for (page.u.pageW.dwSize = PROPSHEETPAGEW_V1_SIZE - 1; page.u.pageW.dwSize <= PROPSHEETPAGEW_V4_SIZE + 1; page.u.pageW.dwSize++) 1116 { 1117 page.addref_called = 0; 1118 hpsp = CreatePropertySheetPageW(&page.u.pageW); 1119 1120 if (page.u.pageW.dwSize < PROPSHEETPAGEW_V1_SIZE) 1121 ok(hpsp == NULL, "Expected failure, size %u\n", page.u.pageW.dwSize); 1122 else 1123 { 1124 ok(hpsp != NULL, "Failed to create a page, size %u\n", page.u.pageW.dwSize); 1125 ok(page.addref_called == (page.u.pageW.dwSize > PROPSHEETPAGEW_V1_SIZE) ? 1 : 0, "Expected ADDREF callback message\n"); 1126 } 1127 1128 if (hpsp) 1129 { 1130 page.release_called = 0; 1131 ret = DestroyPropertySheetPage(hpsp); 1132 ok(ret, "Failed to destroy a page\n"); 1133 ok(page.release_called == 1, "Expected RELEASE callback message\n"); 1134 } 1135 } 1136 } 1137 1138 START_TEST(propsheet) 1139 { 1140 detect_locale(); 1141 if (rtl) 1142 { 1143 /* use locale-specific RTL resources when on an RTL locale */ 1144 /* without this, propsheets on RTL locales use English LTR resources */ 1145 trace("RTL locale detected\n"); 1146 SetProcessDefaultLayout(LAYOUT_RTL); 1147 } 1148 1149 test_title(); 1150 test_nopage(); 1151 test_disableowner(); 1152 test_wiznavigation(); 1153 test_buttons(); 1154 test_custom_default_button(); 1155 test_messages(); 1156 test_PSM_ADDPAGE(); 1157 test_PSM_INSERTPAGE(); 1158 test_CreatePropertySheetPage(); 1159 } 1160