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