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