1 /* 2 * Property Sheets 3 * 4 * Copyright 1998 Francis Beaudet 5 * Copyright 1999 Thuy Nguyen 6 * Copyright 2004 Maxime Bellenge 7 * Copyright 2004 Filip Navara 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 * 23 * This code was audited for completeness against the documented features 24 * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara. 25 * 26 * Unless otherwise noted, we believe this code to be complete, as per 27 * the specification mentioned above. 28 * If you discover missing features, or bugs, please note them below. 29 * 30 * TODO: 31 * - Tab order 32 * - Wizard 97 header resizing 33 * - Enforcing of minimal wizard size 34 * - Messages: 35 * o PSM_RECALCPAGESIZES 36 * o WM_HELP 37 * o WM_CONTEXTMENU 38 * - Notifications: 39 * o PSN_GETOBJECT 40 * o PSN_QUERYINITIALFOCUS 41 * o PSN_TRANSLATEACCELERATOR 42 * - Styles: 43 * o PSH_RTLREADING 44 * o PSH_STRETCHWATERMARK 45 * o PSH_USEPAGELANG 46 * o PSH_USEPSTARTPAGE 47 * - Page styles: 48 * o PSP_USEFUSIONCONTEXT 49 * o PSP_USEREFPARENT 50 */ 51 52 #include <stdarg.h> 53 #include <string.h> 54 55 #define NONAMELESSUNION 56 57 #include "windef.h" 58 #include "winbase.h" 59 #include "wingdi.h" 60 #include "winuser.h" 61 #include "winnls.h" 62 #include "commctrl.h" 63 #include "prsht.h" 64 #include "comctl32.h" 65 #include "uxtheme.h" 66 67 #include "wine/debug.h" 68 69 /****************************************************************************** 70 * Data structures 71 */ 72 #include "pshpack2.h" 73 74 typedef struct 75 { 76 WORD dlgVer; 77 WORD signature; 78 DWORD helpID; 79 DWORD exStyle; 80 DWORD style; 81 } MyDLGTEMPLATEEX; 82 83 typedef struct 84 { 85 DWORD helpid; 86 DWORD exStyle; 87 DWORD style; 88 short x; 89 short y; 90 short cx; 91 short cy; 92 DWORD id; 93 } MyDLGITEMTEMPLATEEX; 94 #include "poppack.h" 95 96 typedef struct tagPropPageInfo 97 { 98 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */ 99 HWND hwndPage; 100 BOOL isDirty; 101 LPCWSTR pszText; 102 BOOL hasHelp; 103 BOOL useCallback; 104 BOOL hasIcon; 105 } PropPageInfo; 106 107 typedef struct tagPropSheetInfo 108 { 109 HWND hwnd; 110 PROPSHEETHEADERW ppshheader; 111 BOOL unicode; 112 LPWSTR strPropertiesFor; 113 int nPages; 114 int active_page; 115 BOOL isModeless; 116 BOOL hasHelp; 117 BOOL hasApply; 118 BOOL hasFinish; 119 BOOL usePropPage; 120 BOOL useCallback; 121 BOOL activeValid; 122 PropPageInfo* proppage; 123 HFONT hFont; 124 HFONT hFontBold; 125 int width; 126 int height; 127 HIMAGELIST hImageList; 128 BOOL ended; 129 INT result; 130 } PropSheetInfo; 131 132 typedef struct 133 { 134 int x; 135 int y; 136 } PADDING_INFO; 137 138 /****************************************************************************** 139 * Defines and global variables 140 */ 141 142 static const WCHAR PropSheetInfoStr[] = 143 {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 }; 144 145 #define PSP_INTERNAL_UNICODE 0x80000000 146 147 #define MAX_CAPTION_LENGTH 255 148 #define MAX_TABTEXT_LENGTH 255 149 #define MAX_BUTTONTEXT_LENGTH 64 150 151 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE) 152 153 /* Wizard metrics specified in DLUs */ 154 #define WIZARD_PADDING 7 155 #define WIZARD_HEADER_HEIGHT 36 156 157 /****************************************************************************** 158 * Prototypes 159 */ 160 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg); 161 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText); 162 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg); 163 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, 164 int index, 165 int skipdir, 166 HPROPSHEETPAGE hpage); 167 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, const PropSheetInfo* psInfo, int original_index); 168 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo); 169 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID); 170 static BOOL PROPSHEET_RemovePage(HWND hwndDlg, int index, HPROPSHEETPAGE hpage); 171 172 static INT_PTR CALLBACK 173 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 174 175 WINE_DEFAULT_DEBUG_CHANNEL(propsheet); 176 177 static WCHAR *heap_strdupW(const WCHAR *str) 178 { 179 int len = lstrlenW(str) + 1; 180 WCHAR *ret = Alloc(len * sizeof(WCHAR)); 181 lstrcpyW(ret, str); 182 return ret; 183 } 184 185 static WCHAR *heap_strdupAtoW(const char *str) 186 { 187 WCHAR *ret; 188 INT len; 189 190 len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0); 191 ret = Alloc(len * sizeof(WCHAR)); 192 MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); 193 194 return ret; 195 } 196 197 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");} 198 /****************************************************************************** 199 * PROPSHEET_UnImplementedFlags 200 * 201 * Document use of flags we don't implement yet. 202 */ 203 static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags) 204 { 205 CHAR string[256]; 206 207 string[0] = '\0'; 208 209 /* 210 * unhandled header flags: 211 * PSH_RTLREADING 0x00000800 212 * PSH_STRETCHWATERMARK 0x00040000 213 * PSH_USEPAGELANG 0x00200000 214 */ 215 216 add_flag(PSH_RTLREADING); 217 add_flag(PSH_STRETCHWATERMARK); 218 add_flag(PSH_USEPAGELANG); 219 if (string[0] != '\0') 220 FIXME("%s\n", string); 221 } 222 #undef add_flag 223 224 /****************************************************************************** 225 * PROPSHEET_GetPageRect 226 * 227 * Retrieve rect from tab control and map into the dialog for SetWindowPos 228 */ 229 static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg, 230 RECT *rc, LPCPROPSHEETPAGEW ppshpage) 231 { 232 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) { 233 HWND hwndChild; 234 RECT r; 235 236 if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && 237 (psInfo->ppshheader.dwFlags & PSH_HEADER) && 238 !(ppshpage->dwFlags & PSP_HIDEHEADER)) || 239 (psInfo->ppshheader.dwFlags & PSH_WIZARD)) 240 { 241 rc->left = rc->top = WIZARD_PADDING; 242 } 243 else 244 { 245 rc->left = rc->top = 0; 246 } 247 rc->right = psInfo->width - rc->left; 248 rc->bottom = psInfo->height - rc->top; 249 MapDialogRect(hwndDlg, rc); 250 251 if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && 252 (psInfo->ppshheader.dwFlags & PSH_HEADER) && 253 !(ppshpage->dwFlags & PSP_HIDEHEADER)) 254 { 255 hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); 256 GetClientRect(hwndChild, &r); 257 MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2); 258 rc->top += r.bottom + 1; 259 } 260 } else { 261 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 262 GetClientRect(hwndTabCtrl, rc); 263 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc); 264 MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2); 265 } 266 } 267 268 /****************************************************************************** 269 * PROPSHEET_FindPageByResId 270 * 271 * Find page index corresponding to page resource id. 272 */ 273 static INT PROPSHEET_FindPageByResId(const PropSheetInfo * psInfo, LRESULT resId) 274 { 275 INT i; 276 277 for (i = 0; i < psInfo->nPages; i++) 278 { 279 LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage; 280 281 /* Fixme: if resource ID is a string shall we use strcmp ??? */ 282 if (lppsp->u.pszTemplate == (LPVOID)resId) 283 break; 284 } 285 286 return i; 287 } 288 289 /****************************************************************************** 290 * PROPSHEET_CollectSheetInfoCommon 291 * 292 * Common code for PROPSHEET_CollectSheetInfoA/W 293 */ 294 static void PROPSHEET_CollectSheetInfoCommon(PropSheetInfo * psInfo, DWORD dwFlags) 295 { 296 PROPSHEET_UnImplementedFlags(dwFlags); 297 298 psInfo->hasHelp = dwFlags & PSH_HASHELP; 299 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW); 300 psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH; 301 psInfo->isModeless = dwFlags & PSH_MODELESS; 302 psInfo->usePropPage = dwFlags & PSH_PROPSHEETPAGE; 303 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages) 304 psInfo->active_page = 0; 305 306 psInfo->result = 0; 307 psInfo->hImageList = 0; 308 psInfo->activeValid = FALSE; 309 } 310 311 /****************************************************************************** 312 * PROPSHEET_CollectSheetInfoA 313 * 314 * Collect relevant data. 315 */ 316 static void PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh, 317 PropSheetInfo * psInfo) 318 { 319 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA)); 320 DWORD dwFlags = lppsh->dwFlags; 321 322 psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback); 323 324 memcpy(&psInfo->ppshheader,lppsh,dwSize); 325 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n", 326 lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, 327 debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); 328 329 if (lppsh->dwFlags & INTRNL_ANY_WIZARD) 330 psInfo->ppshheader.pszCaption = NULL; 331 else 332 { 333 if (!IS_INTRESOURCE(lppsh->pszCaption)) 334 { 335 int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0); 336 WCHAR *caption = Alloc( len*sizeof (WCHAR) ); 337 338 MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, caption, len); 339 psInfo->ppshheader.pszCaption = caption; 340 } 341 } 342 psInfo->nPages = lppsh->nPages; 343 344 if (dwFlags & PSH_USEPSTARTPAGE) 345 { 346 TRACE("PSH_USEPSTARTPAGE is on\n"); 347 psInfo->active_page = 0; 348 } 349 else 350 psInfo->active_page = lppsh->u2.nStartPage; 351 352 PROPSHEET_CollectSheetInfoCommon(psInfo, dwFlags); 353 } 354 355 /****************************************************************************** 356 * PROPSHEET_CollectSheetInfoW 357 * 358 * Collect relevant data. 359 */ 360 static void PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh, 361 PropSheetInfo * psInfo) 362 { 363 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW)); 364 DWORD dwFlags = lppsh->dwFlags; 365 366 psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback); 367 368 memcpy(&psInfo->ppshheader,lppsh,dwSize); 369 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t%s\nnPages\t\t%d\npfnCallback\t%p\n", 370 lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); 371 372 if (lppsh->dwFlags & INTRNL_ANY_WIZARD) 373 psInfo->ppshheader.pszCaption = NULL; 374 else 375 { 376 if (!IS_INTRESOURCE(lppsh->pszCaption)) 377 psInfo->ppshheader.pszCaption = heap_strdupW( lppsh->pszCaption ); 378 } 379 psInfo->nPages = lppsh->nPages; 380 381 if (dwFlags & PSH_USEPSTARTPAGE) 382 { 383 TRACE("PSH_USEPSTARTPAGE is on\n"); 384 psInfo->active_page = 0; 385 } 386 else 387 psInfo->active_page = lppsh->u2.nStartPage; 388 389 PROPSHEET_CollectSheetInfoCommon(psInfo, dwFlags); 390 } 391 392 /****************************************************************************** 393 * PROPSHEET_CollectPageInfo 394 * 395 * Collect property sheet data. 396 * With code taken from DIALOG_ParseTemplate32. 397 */ 398 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp, 399 PropSheetInfo * psInfo, 400 int index, BOOL resize) 401 { 402 const DLGTEMPLATE* pTemplate; 403 const WORD* p; 404 DWORD dwFlags; 405 int width, height; 406 407 if (!lppsp) 408 return FALSE; 409 410 TRACE("\n"); 411 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp; 412 psInfo->proppage[index].hwndPage = 0; 413 psInfo->proppage[index].isDirty = FALSE; 414 415 /* 416 * Process property page flags. 417 */ 418 dwFlags = lppsp->dwFlags; 419 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback); 420 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP; 421 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID); 422 423 /* as soon as we have a page with the help flag, set the sheet flag on */ 424 if (psInfo->proppage[index].hasHelp) 425 psInfo->hasHelp = TRUE; 426 427 /* 428 * Process page template. 429 */ 430 if (dwFlags & PSP_DLGINDIRECT) 431 pTemplate = lppsp->u.pResource; 432 else if(dwFlags & PSP_INTERNAL_UNICODE ) 433 { 434 HRSRC hResource = FindResourceW(lppsp->hInstance, 435 lppsp->u.pszTemplate, 436 (LPWSTR)RT_DIALOG); 437 HGLOBAL hTemplate = LoadResource(lppsp->hInstance, 438 hResource); 439 pTemplate = LockResource(hTemplate); 440 } 441 else 442 { 443 HRSRC hResource = FindResourceA(lppsp->hInstance, 444 (LPCSTR)lppsp->u.pszTemplate, 445 (LPSTR)RT_DIALOG); 446 HGLOBAL hTemplate = LoadResource(lppsp->hInstance, 447 hResource); 448 pTemplate = LockResource(hTemplate); 449 } 450 451 /* 452 * Extract the size of the page and the caption. 453 */ 454 if (!pTemplate) 455 return FALSE; 456 457 p = (const WORD *)pTemplate; 458 459 if (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF) 460 { 461 /* DLGTEMPLATEEX (not defined in any std. header file) */ 462 463 p++; /* dlgVer */ 464 p++; /* signature */ 465 p += 2; /* help ID */ 466 p += 2; /* ext style */ 467 p += 2; /* style */ 468 } 469 else 470 { 471 /* DLGTEMPLATE */ 472 473 p += 2; /* style */ 474 p += 2; /* ext style */ 475 } 476 477 p++; /* nb items */ 478 p++; /* x */ 479 p++; /* y */ 480 width = (WORD)*p; p++; 481 height = (WORD)*p; p++; 482 483 if (lppsp->dwFlags & (PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE)) 484 psInfo->ppshheader.dwFlags |= PSH_HEADER; 485 486 /* Special calculation for interior wizard pages so the largest page is 487 * calculated correctly. We need to add all the padding and space occupied 488 * by the header so the width and height sums up to the whole wizard client 489 * area. */ 490 if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && 491 (psInfo->ppshheader.dwFlags & PSH_HEADER) && 492 !(dwFlags & PSP_HIDEHEADER)) 493 { 494 height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT; 495 width += 2 * WIZARD_PADDING; 496 } 497 if (psInfo->ppshheader.dwFlags & PSH_WIZARD) 498 { 499 height += 2 * WIZARD_PADDING; 500 width += 2 * WIZARD_PADDING; 501 } 502 503 /* remember the largest width and height */ 504 if (resize) 505 { 506 if (width > psInfo->width) 507 psInfo->width = width; 508 509 if (height > psInfo->height) 510 psInfo->height = height; 511 } 512 513 /* menu */ 514 switch ((WORD)*p) 515 { 516 case 0x0000: 517 p++; 518 break; 519 case 0xffff: 520 p += 2; 521 break; 522 default: 523 p += lstrlenW( p ) + 1; 524 break; 525 } 526 527 /* class */ 528 switch ((WORD)*p) 529 { 530 case 0x0000: 531 p++; 532 break; 533 case 0xffff: 534 p += 2; 535 break; 536 default: 537 p += lstrlenW( p ) + 1; 538 break; 539 } 540 541 /* Extract the caption */ 542 psInfo->proppage[index].pszText = p; 543 TRACE("Tab %d %s\n",index,debugstr_w( p )); 544 545 if (dwFlags & PSP_USETITLE) 546 { 547 WCHAR szTitle[256]; 548 const WCHAR *pTitle; 549 static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 }; 550 551 if (IS_INTRESOURCE( lppsp->pszTitle )) 552 { 553 if (LoadStringW( lppsp->hInstance, (DWORD_PTR)lppsp->pszTitle, szTitle, ARRAY_SIZE(szTitle))) 554 pTitle = szTitle; 555 else if (*p) 556 pTitle = p; 557 else 558 pTitle = pszNull; 559 } 560 else 561 pTitle = lppsp->pszTitle; 562 563 psInfo->proppage[index].pszText = heap_strdupW( pTitle ); 564 } 565 566 /* 567 * Build the image list for icons 568 */ 569 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID)) 570 { 571 HICON hIcon; 572 int icon_cx = GetSystemMetrics(SM_CXSMICON); 573 int icon_cy = GetSystemMetrics(SM_CYSMICON); 574 575 if (dwFlags & PSP_USEICONID) 576 hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON, 577 icon_cx, icon_cy, LR_DEFAULTCOLOR); 578 else 579 hIcon = lppsp->u2.hIcon; 580 581 if ( hIcon ) 582 { 583 if (psInfo->hImageList == 0 ) 584 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1); 585 586 ImageList_AddIcon(psInfo->hImageList, hIcon); 587 } 588 589 } 590 591 return TRUE; 592 } 593 594 /****************************************************************************** 595 * PROPSHEET_CreateDialog 596 * 597 * Creates the actual property sheet. 598 */ 599 static INT_PTR PROPSHEET_CreateDialog(PropSheetInfo* psInfo) 600 { 601 LRESULT ret; 602 LPCVOID template; 603 LPVOID temp = 0; 604 HRSRC hRes; 605 DWORD resSize; 606 WORD resID = IDD_PROPSHEET; 607 608 TRACE("(%p)\n", psInfo); 609 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 610 resID = IDD_WIZARD; 611 612 if( psInfo->unicode ) 613 { 614 if(!(hRes = FindResourceW(COMCTL32_hModule, 615 MAKEINTRESOURCEW(resID), 616 (LPWSTR)RT_DIALOG))) 617 return -1; 618 } 619 else 620 { 621 if(!(hRes = FindResourceA(COMCTL32_hModule, 622 MAKEINTRESOURCEA(resID), 623 (LPSTR)RT_DIALOG))) 624 return -1; 625 } 626 627 if(!(template = LoadResource(COMCTL32_hModule, hRes))) 628 return -1; 629 630 /* 631 * Make a copy of the dialog template. 632 */ 633 resSize = SizeofResource(COMCTL32_hModule, hRes); 634 635 temp = Alloc(2 * resSize); 636 637 if (!temp) 638 return -1; 639 640 memcpy(temp, template, resSize); 641 642 if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP) 643 { 644 if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) 645 ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP; 646 else 647 ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP; 648 } 649 if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) && 650 (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP)) 651 { 652 if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) 653 ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP; 654 else 655 ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP; 656 } 657 658 if (psInfo->useCallback) 659 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp); 660 661 /* NOTE: MSDN states "Returns a positive value if successful, or -1 662 * otherwise for modal property sheets.", but this is wrong. The 663 * actual return value is either TRUE (success), FALSE (cancel) or 664 * -1 (error). */ 665 if( psInfo->unicode ) 666 { 667 ret = (INT_PTR)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance, 668 temp, psInfo->ppshheader.hwndParent, 669 PROPSHEET_DialogProc, (LPARAM)psInfo); 670 if ( !ret ) ret = -1; 671 } 672 else 673 { 674 ret = (INT_PTR)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance, 675 temp, psInfo->ppshheader.hwndParent, 676 PROPSHEET_DialogProc, (LPARAM)psInfo); 677 if ( !ret ) ret = -1; 678 } 679 680 Free(temp); 681 682 return ret; 683 } 684 685 /****************************************************************************** 686 * PROPSHEET_SizeMismatch 687 * 688 * Verify that the tab control and the "largest" property sheet page dlg. template 689 * match in size. 690 */ 691 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, const PropSheetInfo* psInfo) 692 { 693 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 694 RECT rcOrigTab, rcPage; 695 696 /* 697 * Original tab size. 698 */ 699 GetClientRect(hwndTabCtrl, &rcOrigTab); 700 TRACE("orig tab %s\n", wine_dbgstr_rect(&rcOrigTab)); 701 702 /* 703 * Biggest page size. 704 */ 705 SetRect(&rcPage, 0, 0, psInfo->width, psInfo->height); 706 MapDialogRect(hwndDlg, &rcPage); 707 TRACE("biggest page %s\n", wine_dbgstr_rect(&rcPage)); 708 709 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) ) 710 return TRUE; 711 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) ) 712 return TRUE; 713 714 return FALSE; 715 } 716 717 /****************************************************************************** 718 * PROPSHEET_AdjustSize 719 * 720 * Resizes the property sheet and the tab control to fit the largest page. 721 */ 722 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo) 723 { 724 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 725 HWND hwndButton = GetDlgItem(hwndDlg, IDOK); 726 RECT rc,tabRect; 727 int buttonHeight; 728 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg); 729 RECT units; 730 LONG style; 731 732 /* Get the height of buttons */ 733 GetClientRect(hwndButton, &rc); 734 buttonHeight = rc.bottom; 735 736 /* 737 * Biggest page size. 738 */ 739 SetRect(&rc, 0, 0, psInfo->width, psInfo->height); 740 MapDialogRect(hwndDlg, &rc); 741 742 /* retrieve the dialog units */ 743 units.left = units.right = 4; 744 units.top = units.bottom = 8; 745 MapDialogRect(hwndDlg, &units); 746 747 /* 748 * Resize the tab control. 749 */ 750 GetClientRect(hwndTabCtrl,&tabRect); 751 752 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect); 753 754 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top)) 755 { 756 rc.bottom = rc.top + tabRect.bottom - tabRect.top; 757 psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top); 758 } 759 760 if ((rc.right - rc.left) < (tabRect.right - tabRect.left)) 761 { 762 rc.right = rc.left + tabRect.right - tabRect.left; 763 psInfo->width = MulDiv((rc.right - rc.left),4,units.left); 764 } 765 766 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc); 767 768 rc.right -= rc.left; 769 rc.bottom -= rc.top; 770 TRACE("setting tab %p, rc (0,0)-(%d,%d)\n", 771 hwndTabCtrl, rc.right, rc.bottom); 772 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom, 773 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 774 775 GetClientRect(hwndTabCtrl, &rc); 776 777 TRACE("tab client rc %s\n", wine_dbgstr_rect(&rc)); 778 779 rc.right += (padding.x * 2); 780 rc.bottom += buttonHeight + (3 * padding.y); 781 782 style = GetWindowLongW(hwndDlg, GWL_STYLE); 783 if (!(style & WS_CHILD)) 784 AdjustWindowRect(&rc, style, FALSE); 785 786 rc.right -= rc.left; 787 rc.bottom -= rc.top; 788 789 /* 790 * Resize the property sheet. 791 */ 792 TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n", 793 hwndDlg, rc.right, rc.bottom); 794 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom, 795 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 796 return TRUE; 797 } 798 799 /****************************************************************************** 800 * PROPSHEET_AdjustSizeWizard 801 * 802 * Resizes the property sheet to fit the largest page. 803 */ 804 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, const PropSheetInfo* psInfo) 805 { 806 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); 807 RECT rc, lineRect, dialogRect; 808 809 /* Biggest page size */ 810 SetRect(&rc, 0, 0, psInfo->width, psInfo->height); 811 MapDialogRect(hwndDlg, &rc); 812 813 TRACE("Biggest page %s\n", wine_dbgstr_rect(&rc)); 814 815 /* Add space for the buttons row */ 816 GetWindowRect(hwndLine, &lineRect); 817 MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2); 818 GetClientRect(hwndDlg, &dialogRect); 819 rc.bottom += dialogRect.bottom - lineRect.top - 1; 820 821 /* Convert the client coordinates to window coordinates */ 822 AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE); 823 824 /* Resize the property sheet */ 825 TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n", 826 hwndDlg, rc.right, rc.bottom); 827 SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, 828 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 829 830 return TRUE; 831 } 832 833 /****************************************************************************** 834 * PROPSHEET_AdjustButtons 835 * 836 * Adjusts the buttons' positions. 837 */ 838 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, const PropSheetInfo* psInfo) 839 { 840 HWND hwndButton = GetDlgItem(hwndParent, IDOK); 841 RECT rcSheet; 842 int x, y; 843 int num_buttons = 2; 844 int buttonWidth, buttonHeight; 845 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent); 846 847 if (psInfo->hasApply) 848 num_buttons++; 849 850 if (psInfo->hasHelp) 851 num_buttons++; 852 853 /* 854 * Obtain the size of the buttons. 855 */ 856 GetClientRect(hwndButton, &rcSheet); 857 buttonWidth = rcSheet.right; 858 buttonHeight = rcSheet.bottom; 859 860 /* 861 * Get the size of the property sheet. 862 */ 863 GetClientRect(hwndParent, &rcSheet); 864 865 /* 866 * All buttons will be at this y coordinate. 867 */ 868 y = rcSheet.bottom - (padding.y + buttonHeight); 869 870 /* 871 * Position OK button and make it default. 872 */ 873 hwndButton = GetDlgItem(hwndParent, IDOK); 874 875 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons); 876 877 SetWindowPos(hwndButton, 0, x, y, 0, 0, 878 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 879 880 SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0); 881 882 883 /* 884 * Position Cancel button. 885 */ 886 hwndButton = GetDlgItem(hwndParent, IDCANCEL); 887 888 x += padding.x + buttonWidth; 889 890 SetWindowPos(hwndButton, 0, x, y, 0, 0, 891 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 892 893 /* 894 * Position Apply button. 895 */ 896 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON); 897 898 if(psInfo->hasApply) 899 x += padding.x + buttonWidth; 900 else 901 ShowWindow(hwndButton, SW_HIDE); 902 903 SetWindowPos(hwndButton, 0, x, y, 0, 0, 904 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 905 EnableWindow(hwndButton, FALSE); 906 907 /* 908 * Position Help button. 909 */ 910 hwndButton = GetDlgItem(hwndParent, IDHELP); 911 912 x += padding.x + buttonWidth; 913 SetWindowPos(hwndButton, 0, x, y, 0, 0, 914 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 915 916 if(!psInfo->hasHelp) 917 ShowWindow(hwndButton, SW_HIDE); 918 919 return TRUE; 920 } 921 922 /****************************************************************************** 923 * PROPSHEET_AdjustButtonsWizard 924 * 925 * Adjusts the buttons' positions. 926 */ 927 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent, 928 const PropSheetInfo* psInfo) 929 { 930 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL); 931 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE); 932 HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER); 933 RECT rcSheet; 934 int x, y; 935 int num_buttons = 3; 936 int buttonWidth, buttonHeight, lineHeight, lineWidth; 937 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo); 938 939 if (psInfo->hasHelp) 940 num_buttons++; 941 if (psInfo->hasFinish) 942 num_buttons++; 943 944 /* 945 * Obtain the size of the buttons. 946 */ 947 GetClientRect(hwndButton, &rcSheet); 948 buttonWidth = rcSheet.right; 949 buttonHeight = rcSheet.bottom; 950 951 GetClientRect(hwndLine, &rcSheet); 952 lineHeight = rcSheet.bottom; 953 954 /* 955 * Get the size of the property sheet. 956 */ 957 GetClientRect(hwndParent, &rcSheet); 958 959 /* 960 * All buttons will be at this y coordinate. 961 */ 962 y = rcSheet.bottom - (padding.y + buttonHeight); 963 964 /* 965 * Position the Back button. 966 */ 967 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON); 968 969 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)) - buttonWidth; 970 971 SetWindowPos(hwndButton, 0, x, y, 0, 0, 972 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 973 974 /* 975 * Position the Next button. 976 */ 977 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON); 978 979 x += buttonWidth; 980 981 SetWindowPos(hwndButton, 0, x, y, 0, 0, 982 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 983 984 /* 985 * Position the Finish button. 986 */ 987 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON); 988 989 if (psInfo->hasFinish) 990 x += padding.x + buttonWidth; 991 992 SetWindowPos(hwndButton, 0, x, y, 0, 0, 993 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 994 995 if (!psInfo->hasFinish) 996 ShowWindow(hwndButton, SW_HIDE); 997 998 /* 999 * Position the Cancel button. 1000 */ 1001 hwndButton = GetDlgItem(hwndParent, IDCANCEL); 1002 1003 x += padding.x + buttonWidth; 1004 1005 SetWindowPos(hwndButton, 0, x, y, 0, 0, 1006 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 1007 1008 /* 1009 * Position Help button. 1010 */ 1011 hwndButton = GetDlgItem(hwndParent, IDHELP); 1012 1013 if (psInfo->hasHelp) 1014 { 1015 x += padding.x + buttonWidth; 1016 1017 SetWindowPos(hwndButton, 0, x, y, 0, 0, 1018 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 1019 } 1020 else 1021 ShowWindow(hwndButton, SW_HIDE); 1022 1023 if (psInfo->ppshheader.dwFlags & 1024 (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) 1025 padding.x = 0; 1026 1027 /* 1028 * Position and resize the sunken line. 1029 */ 1030 x = padding.x; 1031 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight); 1032 1033 lineWidth = rcSheet.right - (padding.x * 2); 1034 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2, 1035 SWP_NOZORDER | SWP_NOACTIVATE); 1036 1037 /* 1038 * Position and resize the header sunken line. 1039 */ 1040 1041 SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2, 1042 SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); 1043 if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW))) 1044 ShowWindow(hwndLineHeader, SW_HIDE); 1045 1046 return TRUE; 1047 } 1048 1049 /****************************************************************************** 1050 * PROPSHEET_GetPaddingInfo 1051 * 1052 * Returns the layout information. 1053 */ 1054 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg) 1055 { 1056 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL); 1057 RECT rcTab; 1058 PADDING_INFO padding; 1059 1060 GetWindowRect(hwndTab, &rcTab); 1061 MapWindowPoints( 0, hwndDlg, (POINT *)&rcTab, 2 ); 1062 1063 padding.x = rcTab.left; 1064 padding.y = rcTab.top; 1065 1066 return padding; 1067 } 1068 1069 /****************************************************************************** 1070 * PROPSHEET_GetPaddingInfoWizard 1071 * 1072 * Returns the layout information. 1073 * Vertical spacing is the distance between the line and the buttons. 1074 * Do NOT use the Help button to gather padding information when it isn't mapped 1075 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates 1076 * for it in this case ! 1077 * FIXME: I'm not sure about any other coordinate problems with these evil 1078 * buttons. Fix it in case additional problems appear or maybe calculate 1079 * a padding in a completely different way, as this is somewhat messy. 1080 */ 1081 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* 1082 psInfo) 1083 { 1084 PADDING_INFO padding; 1085 RECT rc; 1086 HWND hwndControl; 1087 INT idButton; 1088 POINT ptButton, ptLine; 1089 1090 TRACE("\n"); 1091 if (psInfo->hasHelp) 1092 { 1093 idButton = IDHELP; 1094 } 1095 else 1096 { 1097 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 1098 { 1099 idButton = IDC_NEXT_BUTTON; 1100 } 1101 else 1102 { 1103 /* hopefully this is ok */ 1104 idButton = IDCANCEL; 1105 } 1106 } 1107 1108 hwndControl = GetDlgItem(hwndDlg, idButton); 1109 GetWindowRect(hwndControl, &rc); 1110 MapWindowPoints( 0, hwndDlg, (POINT *)&rc, 2 ); 1111 ptButton.x = rc.left; 1112 ptButton.y = rc.top; 1113 1114 /* Line */ 1115 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); 1116 GetWindowRect(hwndControl, &rc); 1117 MapWindowPoints( 0, hwndDlg, (POINT *)&rc, 2 ); 1118 ptLine.x = rc.left; 1119 ptLine.y = rc.bottom; 1120 1121 padding.y = ptButton.y - ptLine.y; 1122 1123 if (padding.y < 0) 1124 ERR("padding negative ! Please report this !\n"); 1125 1126 /* this is most probably not correct, but the best we have now */ 1127 padding.x = padding.y; 1128 return padding; 1129 } 1130 1131 /****************************************************************************** 1132 * PROPSHEET_CreateTabControl 1133 * 1134 * Insert the tabs in the tab control. 1135 */ 1136 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent, 1137 const PropSheetInfo * psInfo) 1138 { 1139 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL); 1140 TCITEMW item; 1141 int i, nTabs; 1142 int iImage = 0; 1143 1144 TRACE("\n"); 1145 item.mask = TCIF_TEXT; 1146 item.cchTextMax = MAX_TABTEXT_LENGTH; 1147 1148 nTabs = psInfo->nPages; 1149 1150 /* 1151 * Set the image list for icons. 1152 */ 1153 if (psInfo->hImageList) 1154 { 1155 SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); 1156 } 1157 1158 SendMessageW(hwndTabCtrl, WM_SETREDRAW, 0, 0); 1159 for (i = 0; i < nTabs; i++) 1160 { 1161 if ( psInfo->proppage[i].hasIcon ) 1162 { 1163 item.mask |= TCIF_IMAGE; 1164 item.iImage = iImage++; 1165 } 1166 else 1167 { 1168 item.mask &= ~TCIF_IMAGE; 1169 } 1170 1171 item.pszText = (LPWSTR) psInfo->proppage[i].pszText; 1172 SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, i, (LPARAM)&item); 1173 } 1174 SendMessageW(hwndTabCtrl, WM_SETREDRAW, 1, 0); 1175 1176 return TRUE; 1177 } 1178 1179 /****************************************************************************** 1180 * PROPSHEET_WizardSubclassProc 1181 * 1182 * Subclassing window procedure for wizard exterior pages to prevent drawing 1183 * background and so drawing above the watermark. 1184 */ 1185 static LRESULT CALLBACK 1186 PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) 1187 { 1188 switch (uMsg) 1189 { 1190 case WM_ERASEBKGND: 1191 return TRUE; 1192 1193 case WM_CTLCOLORSTATIC: 1194 SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); 1195 return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); 1196 } 1197 1198 return DefSubclassProc(hwnd, uMsg, wParam, lParam); 1199 } 1200 1201 /* 1202 * Get the size of an in-memory Template 1203 * 1204 *( Based on the code of PROPSHEET_CollectPageInfo) 1205 * See also dialog.c/DIALOG_ParseTemplate32(). 1206 */ 1207 1208 static UINT GetTemplateSize(const DLGTEMPLATE* pTemplate) 1209 1210 { 1211 const WORD* p = (const WORD *)pTemplate; 1212 BOOL istemplateex = (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF); 1213 WORD nrofitems; 1214 UINT ret; 1215 1216 if (istemplateex) 1217 { 1218 /* DLGTEMPLATEEX (not defined in any std. header file) */ 1219 1220 TRACE("is DLGTEMPLATEEX\n"); 1221 p++; /* dlgVer */ 1222 p++; /* signature */ 1223 p += 2; /* help ID */ 1224 p += 2; /* ext style */ 1225 p += 2; /* style */ 1226 } 1227 else 1228 { 1229 /* DLGTEMPLATE */ 1230 1231 TRACE("is DLGTEMPLATE\n"); 1232 p += 2; /* style */ 1233 p += 2; /* ext style */ 1234 } 1235 1236 nrofitems = (WORD)*p; p++; /* nb items */ 1237 p++; /* x */ 1238 p++; /* y */ 1239 p++; /* width */ 1240 p++; /* height */ 1241 1242 /* menu */ 1243 switch ((WORD)*p) 1244 { 1245 case 0x0000: 1246 p++; 1247 break; 1248 case 0xffff: 1249 p += 2; 1250 break; 1251 default: 1252 TRACE("menu %s\n",debugstr_w( p )); 1253 p += lstrlenW( p ) + 1; 1254 break; 1255 } 1256 1257 /* class */ 1258 switch ((WORD)*p) 1259 { 1260 case 0x0000: 1261 p++; 1262 break; 1263 case 0xffff: 1264 p += 2; /* 0xffff plus predefined window class ordinal value */ 1265 break; 1266 default: 1267 TRACE("class %s\n",debugstr_w( p )); 1268 p += lstrlenW( p ) + 1; 1269 break; 1270 } 1271 1272 /* title */ 1273 TRACE("title %s\n",debugstr_w( p )); 1274 p += lstrlenW( p ) + 1; 1275 1276 /* font, if DS_SETFONT set */ 1277 if ((DS_SETFONT & ((istemplateex)? ((const MyDLGTEMPLATEEX*)pTemplate)->style : 1278 pTemplate->style))) 1279 { 1280 p+=(istemplateex)?3:1; 1281 TRACE("font %s\n",debugstr_w( p )); 1282 p += lstrlenW( p ) + 1; /* the font name */ 1283 } 1284 1285 /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data) 1286 * that are following the DLGTEMPLATE(EX) data */ 1287 TRACE("%d items\n",nrofitems); 1288 while (nrofitems > 0) 1289 { 1290 p = (WORD*)(((DWORD_PTR)p + 3) & ~3); /* DWORD align */ 1291 1292 /* skip header */ 1293 p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD); 1294 1295 /* check class */ 1296 switch ((WORD)*p) 1297 { 1298 case 0x0000: 1299 p++; 1300 break; 1301 case 0xffff: 1302 TRACE("class ordinal 0x%08x\n",*(const DWORD*)p); 1303 p += 2; 1304 break; 1305 default: 1306 TRACE("class %s\n",debugstr_w( p )); 1307 p += lstrlenW( p ) + 1; 1308 break; 1309 } 1310 1311 /* check title text */ 1312 switch ((WORD)*p) 1313 { 1314 case 0x0000: 1315 p++; 1316 break; 1317 case 0xffff: 1318 TRACE("text ordinal 0x%08x\n",*(const DWORD*)p); 1319 p += 2; 1320 break; 1321 default: 1322 TRACE("text %s\n",debugstr_w( p )); 1323 p += lstrlenW( p ) + 1; 1324 break; 1325 } 1326 p += *p / sizeof(WORD) + 1; /* Skip extra data */ 1327 --nrofitems; 1328 } 1329 1330 ret = (p - (const WORD*)pTemplate) * sizeof(WORD); 1331 TRACE("%p %p size 0x%08x\n", p, pTemplate, ret); 1332 return ret; 1333 } 1334 1335 #ifdef __REACTOS__ 1336 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage); 1337 #endif 1338 /****************************************************************************** 1339 * PROPSHEET_CreatePage 1340 * 1341 * Creates a page. 1342 */ 1343 static BOOL PROPSHEET_CreatePage(HWND hwndParent, 1344 int index, 1345 const PropSheetInfo * psInfo, 1346 LPCPROPSHEETPAGEW ppshpage) 1347 { 1348 const DLGTEMPLATE* pTemplate; 1349 HWND hwndPage; 1350 DWORD resSize; 1351 DLGTEMPLATE* pTemplateCopy = NULL; 1352 1353 TRACE("index %d\n", index); 1354 1355 if (ppshpage == NULL) 1356 { 1357 return FALSE; 1358 } 1359 1360 if (ppshpage->dwFlags & PSP_DLGINDIRECT) 1361 { 1362 pTemplate = ppshpage->u.pResource; 1363 resSize = GetTemplateSize(pTemplate); 1364 } 1365 else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) 1366 { 1367 HRSRC hResource; 1368 HANDLE hTemplate; 1369 1370 hResource = FindResourceW(ppshpage->hInstance, 1371 ppshpage->u.pszTemplate, 1372 (LPWSTR)RT_DIALOG); 1373 if(!hResource) 1374 return FALSE; 1375 1376 resSize = SizeofResource(ppshpage->hInstance, hResource); 1377 1378 hTemplate = LoadResource(ppshpage->hInstance, hResource); 1379 if(!hTemplate) 1380 return FALSE; 1381 1382 pTemplate = LockResource(hTemplate); 1383 /* 1384 * Make a copy of the dialog template to make it writable 1385 */ 1386 } 1387 else 1388 { 1389 HRSRC hResource; 1390 HANDLE hTemplate; 1391 1392 hResource = FindResourceA(ppshpage->hInstance, 1393 (LPCSTR)ppshpage->u.pszTemplate, 1394 (LPSTR)RT_DIALOG); 1395 if(!hResource) 1396 return FALSE; 1397 1398 resSize = SizeofResource(ppshpage->hInstance, hResource); 1399 1400 hTemplate = LoadResource(ppshpage->hInstance, hResource); 1401 if(!hTemplate) 1402 return FALSE; 1403 1404 pTemplate = LockResource(hTemplate); 1405 /* 1406 * Make a copy of the dialog template to make it writable 1407 */ 1408 } 1409 pTemplateCopy = Alloc(resSize); 1410 if (!pTemplateCopy) 1411 return FALSE; 1412 1413 TRACE("copying pTemplate %p into pTemplateCopy %p (%d)\n", pTemplate, pTemplateCopy, resSize); 1414 memcpy(pTemplateCopy, pTemplate, resSize); 1415 1416 if (((MyDLGTEMPLATEEX*)pTemplateCopy)->signature == 0xFFFF) 1417 { 1418 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; 1419 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~DS_MODALFRAME; 1420 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_CAPTION; 1421 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_SYSMENU; 1422 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_POPUP; 1423 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_DISABLED; 1424 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_VISIBLE; 1425 ((MyDLGTEMPLATEEX*)pTemplateCopy)->style &= ~WS_THICKFRAME; 1426 1427 ((MyDLGTEMPLATEEX*)pTemplateCopy)->exStyle |= WS_EX_CONTROLPARENT; 1428 } 1429 else 1430 { 1431 pTemplateCopy->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; 1432 pTemplateCopy->style &= ~DS_MODALFRAME; 1433 pTemplateCopy->style &= ~WS_CAPTION; 1434 pTemplateCopy->style &= ~WS_SYSMENU; 1435 pTemplateCopy->style &= ~WS_POPUP; 1436 pTemplateCopy->style &= ~WS_DISABLED; 1437 pTemplateCopy->style &= ~WS_VISIBLE; 1438 pTemplateCopy->style &= ~WS_THICKFRAME; 1439 1440 pTemplateCopy->dwExtendedStyle |= WS_EX_CONTROLPARENT; 1441 } 1442 1443 if (psInfo->proppage[index].useCallback) 1444 (*(ppshpage->pfnCallback))(0, PSPCB_CREATE, 1445 (LPPROPSHEETPAGEW)ppshpage); 1446 1447 if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) 1448 hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance, 1449 pTemplateCopy, 1450 hwndParent, 1451 ppshpage->pfnDlgProc, 1452 (LPARAM)ppshpage); 1453 else 1454 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance, 1455 pTemplateCopy, 1456 hwndParent, 1457 ppshpage->pfnDlgProc, 1458 (LPARAM)ppshpage); 1459 /* Free a no more needed copy */ 1460 Free(pTemplateCopy); 1461 1462 if(!hwndPage) 1463 return FALSE; 1464 1465 psInfo->proppage[index].hwndPage = hwndPage; 1466 1467 /* Subclass exterior wizard pages */ 1468 if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && 1469 (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 1470 (ppshpage->dwFlags & PSP_HIDEHEADER)) 1471 { 1472 #ifdef __REACTOS__ 1473 if (psInfo->ppshheader.u4.hbmWatermark) 1474 #endif 1475 SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1, 1476 (DWORD_PTR)ppshpage); 1477 } 1478 if (!(psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)) 1479 EnableThemeDialogTexture (hwndPage, ETDT_ENABLETAB); 1480 1481 #ifdef __REACTOS__ 1482 PROPSHEET_UnChanged(hwndParent, hwndPage); 1483 #endif 1484 return TRUE; 1485 } 1486 1487 /****************************************************************************** 1488 * PROPSHEET_LoadWizardBitmaps 1489 * 1490 * Loads the watermark and header bitmaps for a wizard. 1491 */ 1492 static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo) 1493 { 1494 if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) 1495 { 1496 /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark 1497 and put the HBITMAP in hbmWatermark. Thus all the rest of the code always 1498 considers hbmWatermark as valid. */ 1499 if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 1500 !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) 1501 { 1502 psInfo->ppshheader.u4.hbmWatermark = 1503 CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0); 1504 } 1505 1506 /* Same behavior as for watermarks */ 1507 if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && 1508 !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) 1509 { 1510 psInfo->ppshheader.u5.hbmHeader = 1511 CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0); 1512 } 1513 } 1514 } 1515 1516 1517 /****************************************************************************** 1518 * PROPSHEET_ShowPage 1519 * 1520 * Displays or creates the specified page. 1521 */ 1522 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo) 1523 { 1524 HWND hwndTabCtrl; 1525 HWND hwndLineHeader; 1526 HWND control; 1527 LPCPROPSHEETPAGEW ppshpage; 1528 1529 TRACE("active_page %d, index %d\n", psInfo->active_page, index); 1530 if (index == psInfo->active_page) 1531 { 1532 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage) 1533 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 1534 return TRUE; 1535 } 1536 1537 ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; 1538 if (psInfo->proppage[index].hwndPage == 0) 1539 { 1540 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage); 1541 } 1542 1543 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 1544 { 1545 PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags, 1546 psInfo->proppage[index].pszText); 1547 1548 control = GetNextDlgTabItem(psInfo->proppage[index].hwndPage, NULL, FALSE); 1549 if(control != NULL) 1550 SetFocus(control); 1551 } 1552 1553 if (psInfo->active_page != -1) 1554 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); 1555 1556 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW); 1557 1558 /* Synchronize current selection with tab control 1559 * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */ 1560 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 1561 SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0); 1562 1563 psInfo->active_page = index; 1564 psInfo->activeValid = TRUE; 1565 1566 if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) ) 1567 { 1568 hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); 1569 ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; 1570 1571 if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) ) 1572 ShowWindow(hwndLineHeader, SW_HIDE); 1573 else 1574 ShowWindow(hwndLineHeader, SW_SHOW); 1575 } 1576 1577 return TRUE; 1578 } 1579 1580 /****************************************************************************** 1581 * PROPSHEET_Back 1582 */ 1583 static BOOL PROPSHEET_Back(HWND hwndDlg) 1584 { 1585 PSHNOTIFY psn; 1586 HWND hwndPage; 1587 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1588 LRESULT result; 1589 int idx; 1590 1591 TRACE("active_page %d\n", psInfo->active_page); 1592 if (psInfo->active_page < 0) 1593 return FALSE; 1594 1595 psn.hdr.code = PSN_WIZBACK; 1596 psn.hdr.hwndFrom = hwndDlg; 1597 psn.hdr.idFrom = 0; 1598 psn.lParam = 0; 1599 1600 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1601 1602 result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1603 if (result == -1) 1604 return FALSE; 1605 else if (result == 0) 1606 idx = psInfo->active_page - 1; 1607 else 1608 idx = PROPSHEET_FindPageByResId(psInfo, result); 1609 1610 if (idx >= 0 && idx < psInfo->nPages) 1611 { 1612 if (PROPSHEET_CanSetCurSel(hwndDlg)) 1613 { 1614 SetFocus(GetDlgItem(hwndDlg, IDC_BACK_BUTTON)); 1615 SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0); 1616 PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0); 1617 } 1618 } 1619 return TRUE; 1620 } 1621 1622 /****************************************************************************** 1623 * PROPSHEET_Next 1624 */ 1625 static BOOL PROPSHEET_Next(HWND hwndDlg) 1626 { 1627 PSHNOTIFY psn; 1628 HWND hwndPage; 1629 LRESULT msgResult = 0; 1630 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1631 int idx; 1632 1633 TRACE("active_page %d\n", psInfo->active_page); 1634 if (psInfo->active_page < 0) 1635 return FALSE; 1636 1637 psn.hdr.code = PSN_WIZNEXT; 1638 psn.hdr.hwndFrom = hwndDlg; 1639 psn.hdr.idFrom = 0; 1640 psn.lParam = 0; 1641 1642 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1643 1644 msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1645 if (msgResult == -1) 1646 return FALSE; 1647 else if (msgResult == 0) 1648 idx = psInfo->active_page + 1; 1649 else 1650 idx = PROPSHEET_FindPageByResId(psInfo, msgResult); 1651 1652 if (idx < psInfo->nPages ) 1653 { 1654 if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) 1655 { 1656 SetFocus(GetDlgItem(hwndDlg, IDC_NEXT_BUTTON)); 1657 SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0); 1658 PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); 1659 } 1660 } 1661 1662 return TRUE; 1663 } 1664 1665 /****************************************************************************** 1666 * PROPSHEET_Finish 1667 */ 1668 static BOOL PROPSHEET_Finish(HWND hwndDlg) 1669 { 1670 PSHNOTIFY psn; 1671 HWND hwndPage; 1672 LRESULT msgResult = 0; 1673 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1674 1675 TRACE("active_page %d\n", psInfo->active_page); 1676 if (psInfo->active_page < 0) 1677 return FALSE; 1678 1679 psn.hdr.code = PSN_WIZFINISH; 1680 psn.hdr.hwndFrom = hwndDlg; 1681 psn.hdr.idFrom = 0; 1682 psn.lParam = 0; 1683 1684 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1685 1686 msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1687 1688 TRACE("msg result %ld\n", msgResult); 1689 1690 if (msgResult != 0) 1691 return FALSE; 1692 1693 if (psInfo->result == 0) 1694 psInfo->result = IDOK; 1695 if (psInfo->isModeless) 1696 psInfo->activeValid = FALSE; 1697 else 1698 psInfo->ended = TRUE; 1699 1700 return TRUE; 1701 } 1702 1703 /****************************************************************************** 1704 * PROPSHEET_Apply 1705 */ 1706 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam) 1707 { 1708 int i; 1709 HWND hwndPage; 1710 PSHNOTIFY psn; 1711 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1712 1713 TRACE("active_page %d\n", psInfo->active_page); 1714 if (psInfo->active_page < 0) 1715 return FALSE; 1716 1717 psn.hdr.hwndFrom = hwndDlg; 1718 psn.hdr.idFrom = 0; 1719 psn.lParam = 0; 1720 1721 1722 /* 1723 * Send PSN_KILLACTIVE to the current page. 1724 */ 1725 psn.hdr.code = PSN_KILLACTIVE; 1726 1727 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1728 1729 if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE) 1730 return FALSE; 1731 1732 /* 1733 * Send PSN_APPLY to all pages. 1734 */ 1735 psn.hdr.code = PSN_APPLY; 1736 psn.lParam = lParam; 1737 1738 for (i = 0; i < psInfo->nPages; i++) 1739 { 1740 hwndPage = psInfo->proppage[i].hwndPage; 1741 if (hwndPage) 1742 { 1743 switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) 1744 { 1745 case PSNRET_INVALID: 1746 PROPSHEET_ShowPage(hwndDlg, i, psInfo); 1747 /* fall through */ 1748 case PSNRET_INVALID_NOCHANGEPAGE: 1749 return FALSE; 1750 } 1751 } 1752 } 1753 1754 if(lParam) 1755 { 1756 psInfo->activeValid = FALSE; 1757 } 1758 else if(psInfo->active_page >= 0) 1759 { 1760 psn.hdr.code = PSN_SETACTIVE; 1761 psn.lParam = 0; 1762 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1763 SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1764 } 1765 1766 return TRUE; 1767 } 1768 1769 /****************************************************************************** 1770 * PROPSHEET_Cancel 1771 */ 1772 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam) 1773 { 1774 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1775 HWND hwndPage; 1776 PSHNOTIFY psn; 1777 int i; 1778 1779 TRACE("active_page %d\n", psInfo->active_page); 1780 if (psInfo->active_page < 0) 1781 return; 1782 1783 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1784 psn.hdr.code = PSN_QUERYCANCEL; 1785 psn.hdr.hwndFrom = hwndDlg; 1786 psn.hdr.idFrom = 0; 1787 psn.lParam = 0; 1788 1789 if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) 1790 return; 1791 1792 psn.hdr.code = PSN_RESET; 1793 psn.lParam = lParam; 1794 1795 for (i = 0; i < psInfo->nPages; i++) 1796 { 1797 hwndPage = psInfo->proppage[i].hwndPage; 1798 1799 if (hwndPage) 1800 SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1801 } 1802 1803 if (psInfo->isModeless) 1804 { 1805 /* makes PSM_GETCURRENTPAGEHWND return NULL */ 1806 psInfo->activeValid = FALSE; 1807 } 1808 else 1809 psInfo->ended = TRUE; 1810 } 1811 1812 /****************************************************************************** 1813 * PROPSHEET_Help 1814 */ 1815 static void PROPSHEET_Help(HWND hwndDlg) 1816 { 1817 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1818 HWND hwndPage; 1819 PSHNOTIFY psn; 1820 1821 TRACE("active_page %d\n", psInfo->active_page); 1822 if (psInfo->active_page < 0) 1823 return; 1824 1825 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1826 psn.hdr.code = PSN_HELP; 1827 psn.hdr.hwndFrom = hwndDlg; 1828 psn.hdr.idFrom = 0; 1829 psn.lParam = 0; 1830 1831 SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1832 } 1833 1834 /****************************************************************************** 1835 * PROPSHEET_Changed 1836 */ 1837 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage) 1838 { 1839 int i; 1840 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1841 1842 TRACE("\n"); 1843 if (!psInfo) return; 1844 /* 1845 * Set the dirty flag of this page. 1846 */ 1847 for (i = 0; i < psInfo->nPages; i++) 1848 { 1849 if (psInfo->proppage[i].hwndPage == hwndDirtyPage) 1850 psInfo->proppage[i].isDirty = TRUE; 1851 } 1852 1853 /* 1854 * Enable the Apply button. 1855 */ 1856 if (psInfo->hasApply) 1857 { 1858 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); 1859 1860 EnableWindow(hwndApplyBtn, TRUE); 1861 } 1862 } 1863 1864 /****************************************************************************** 1865 * PROPSHEET_UnChanged 1866 */ 1867 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage) 1868 { 1869 int i; 1870 BOOL noPageDirty = TRUE; 1871 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); 1872 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1873 1874 TRACE("\n"); 1875 if ( !psInfo ) return; 1876 for (i = 0; i < psInfo->nPages; i++) 1877 { 1878 /* set the specified page as clean */ 1879 if (psInfo->proppage[i].hwndPage == hwndCleanPage) 1880 psInfo->proppage[i].isDirty = FALSE; 1881 1882 /* look to see if there are any dirty pages */ 1883 if (psInfo->proppage[i].isDirty) 1884 noPageDirty = FALSE; 1885 } 1886 1887 /* 1888 * Disable Apply button. 1889 */ 1890 if (noPageDirty) 1891 EnableWindow(hwndApplyBtn, FALSE); 1892 } 1893 1894 /****************************************************************************** 1895 * PROPSHEET_PressButton 1896 */ 1897 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID) 1898 { 1899 TRACE("buttonID %d\n", buttonID); 1900 switch (buttonID) 1901 { 1902 case PSBTN_APPLYNOW: 1903 PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON); 1904 break; 1905 case PSBTN_BACK: 1906 PROPSHEET_Back(hwndDlg); 1907 break; 1908 case PSBTN_CANCEL: 1909 PROPSHEET_DoCommand(hwndDlg, IDCANCEL); 1910 break; 1911 case PSBTN_FINISH: 1912 PROPSHEET_Finish(hwndDlg); 1913 break; 1914 case PSBTN_HELP: 1915 PROPSHEET_DoCommand(hwndDlg, IDHELP); 1916 break; 1917 case PSBTN_NEXT: 1918 PROPSHEET_Next(hwndDlg); 1919 break; 1920 case PSBTN_OK: 1921 PROPSHEET_DoCommand(hwndDlg, IDOK); 1922 break; 1923 default: 1924 FIXME("Invalid button index %d\n", buttonID); 1925 } 1926 } 1927 1928 1929 /************************************************************************* 1930 * BOOL PROPSHEET_CanSetCurSel [Internal] 1931 * 1932 * Test whether the current page can be changed by sending a PSN_KILLACTIVE 1933 * 1934 * PARAMS 1935 * hwndDlg [I] handle to a Dialog hWnd 1936 * 1937 * RETURNS 1938 * TRUE if Current Selection can change 1939 * 1940 * NOTES 1941 */ 1942 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg) 1943 { 1944 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1945 HWND hwndPage; 1946 PSHNOTIFY psn; 1947 BOOL res = FALSE; 1948 1949 if (!psInfo) 1950 { 1951 res = FALSE; 1952 goto end; 1953 } 1954 1955 TRACE("active_page %d\n", psInfo->active_page); 1956 if (psInfo->active_page < 0) 1957 { 1958 res = TRUE; 1959 goto end; 1960 } 1961 1962 /* 1963 * Notify the current page. 1964 */ 1965 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 1966 psn.hdr.code = PSN_KILLACTIVE; 1967 psn.hdr.hwndFrom = hwndDlg; 1968 psn.hdr.idFrom = 0; 1969 psn.lParam = 0; 1970 1971 res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 1972 1973 end: 1974 TRACE("<-- %d\n", res); 1975 return res; 1976 } 1977 1978 /****************************************************************************** 1979 * PROPSHEET_SetCurSel 1980 */ 1981 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, 1982 int index, 1983 int skipdir, 1984 HPROPSHEETPAGE hpage 1985 ) 1986 { 1987 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 1988 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP); 1989 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 1990 1991 TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage); 1992 1993 index = PROPSHEET_GetPageIndex(hpage, psInfo, index); 1994 1995 if (index < 0 || index >= psInfo->nPages) 1996 { 1997 TRACE("Could not find page to select!\n"); 1998 return FALSE; 1999 } 2000 2001 /* unset active page while doing this transition. */ 2002 if (psInfo->active_page != -1) 2003 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); 2004 psInfo->active_page = -1; 2005 2006 while (1) { 2007 int result; 2008 PSHNOTIFY psn; 2009 RECT rc; 2010 LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; 2011 2012 if (hwndTabControl) 2013 SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0); 2014 2015 psn.hdr.code = PSN_SETACTIVE; 2016 psn.hdr.hwndFrom = hwndDlg; 2017 psn.hdr.idFrom = 0; 2018 psn.lParam = 0; 2019 2020 if (!psInfo->proppage[index].hwndPage) { 2021 if(!PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage)) { 2022 PROPSHEET_RemovePage(hwndDlg, index, NULL); 2023 2024 if (!psInfo->isModeless) 2025 { 2026 DestroyWindow(hwndDlg); 2027 return FALSE; 2028 } 2029 2030 if(index >= psInfo->nPages) 2031 index--; 2032 if(index < 0) 2033 return FALSE; 2034 continue; 2035 } 2036 } 2037 2038 /* Resize the property sheet page to the fit in the Tab control 2039 * (for regular property sheets) or to fit in the client area (for 2040 * wizards). 2041 * NOTE: The resizing happens every time the page is selected and 2042 * not only when it's created (some applications depend on it). */ 2043 PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage); 2044 TRACE("setting page %p, rc (%s) w=%d, h=%d\n", 2045 psInfo->proppage[index].hwndPage, wine_dbgstr_rect(&rc), 2046 rc.right - rc.left, rc.bottom - rc.top); 2047 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 2048 rc.left, rc.top, 2049 rc.right - rc.left, rc.bottom - rc.top, 0); 2050 2051 result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); 2052 if (!result) 2053 break; 2054 if (result == -1) { 2055 index+=skipdir; 2056 if (index < 0) { 2057 index = 0; 2058 WARN("Tried to skip before first property sheet page!\n"); 2059 break; 2060 } 2061 if (index >= psInfo->nPages) { 2062 WARN("Tried to skip after last property sheet page!\n"); 2063 index = psInfo->nPages-1; 2064 break; 2065 } 2066 } 2067 else if (result != 0) 2068 { 2069 int old_index = index; 2070 index = PROPSHEET_FindPageByResId(psInfo, result); 2071 if(index >= psInfo->nPages) { 2072 index = old_index; 2073 WARN("Tried to skip to nonexistent page by res id\n"); 2074 break; 2075 } 2076 continue; 2077 } 2078 } 2079 2080 /* Invalidate the header area */ 2081 if ( (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && 2082 (psInfo->ppshheader.dwFlags & PSH_HEADER) ) 2083 { 2084 HWND hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); 2085 RECT r; 2086 2087 GetClientRect(hwndLineHeader, &r); 2088 MapWindowPoints(hwndLineHeader, hwndDlg, (LPPOINT) &r, 2); 2089 SetRect(&r, 0, 0, r.right + 1, r.top - 1); 2090 2091 InvalidateRect(hwndDlg, &r, TRUE); 2092 } 2093 2094 /* 2095 * Display the new page. 2096 */ 2097 PROPSHEET_ShowPage(hwndDlg, index, psInfo); 2098 2099 if (psInfo->proppage[index].hasHelp) 2100 EnableWindow(hwndHelp, TRUE); 2101 else 2102 EnableWindow(hwndHelp, FALSE); 2103 2104 return TRUE; 2105 } 2106 2107 /****************************************************************************** 2108 * PROPSHEET_SetCurSelId 2109 * 2110 * Selects the page, specified by resource id. 2111 */ 2112 static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id) 2113 { 2114 int idx; 2115 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2116 2117 idx = PROPSHEET_FindPageByResId(psInfo, id); 2118 if (idx < psInfo->nPages ) 2119 { 2120 if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) 2121 PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); 2122 } 2123 } 2124 2125 /****************************************************************************** 2126 * PROPSHEET_SetTitleA 2127 */ 2128 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText) 2129 { 2130 if(!IS_INTRESOURCE(lpszText)) 2131 { 2132 WCHAR szTitle[256]; 2133 MultiByteToWideChar(CP_ACP, 0, lpszText, -1, szTitle, ARRAY_SIZE(szTitle)); 2134 PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle); 2135 } 2136 else 2137 { 2138 PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText); 2139 } 2140 } 2141 2142 /****************************************************************************** 2143 * PROPSHEET_SetTitleW 2144 */ 2145 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText) 2146 { 2147 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2148 WCHAR szTitle[256]; 2149 2150 TRACE("%s (style %08x)\n", debugstr_w(lpszText), dwStyle); 2151 if (IS_INTRESOURCE(lpszText)) { 2152 if (!LoadStringW(psInfo->ppshheader.hInstance, LOWORD(lpszText), szTitle, ARRAY_SIZE(szTitle))) 2153 return; 2154 lpszText = szTitle; 2155 } 2156 if (dwStyle & PSH_PROPTITLE) 2157 { 2158 WCHAR* dest; 2159 int lentitle = lstrlenW(lpszText); 2160 int lenprop = lstrlenW(psInfo->strPropertiesFor); 2161 2162 dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR)); 2163 wsprintfW(dest, psInfo->strPropertiesFor, lpszText); 2164 2165 SetWindowTextW(hwndDlg, dest); 2166 Free(dest); 2167 } 2168 else 2169 SetWindowTextW(hwndDlg, lpszText); 2170 } 2171 2172 /****************************************************************************** 2173 * PROPSHEET_SetFinishTextA 2174 */ 2175 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText) 2176 { 2177 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2178 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); 2179 2180 TRACE("'%s'\n", lpszText); 2181 /* Set text, show and enable the Finish button */ 2182 SetWindowTextA(hwndButton, lpszText); 2183 ShowWindow(hwndButton, SW_SHOW); 2184 EnableWindow(hwndButton, TRUE); 2185 2186 /* Make it default pushbutton */ 2187 SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); 2188 2189 /* Hide Back button */ 2190 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); 2191 ShowWindow(hwndButton, SW_HIDE); 2192 2193 if (!psInfo->hasFinish) 2194 { 2195 /* Hide Next button */ 2196 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); 2197 ShowWindow(hwndButton, SW_HIDE); 2198 } 2199 } 2200 2201 /****************************************************************************** 2202 * PROPSHEET_SetFinishTextW 2203 */ 2204 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText) 2205 { 2206 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2207 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); 2208 2209 TRACE("%s\n", debugstr_w(lpszText)); 2210 /* Set text, show and enable the Finish button */ 2211 SetWindowTextW(hwndButton, lpszText); 2212 ShowWindow(hwndButton, SW_SHOW); 2213 EnableWindow(hwndButton, TRUE); 2214 2215 /* Make it default pushbutton */ 2216 SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); 2217 2218 /* Hide Back button */ 2219 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); 2220 ShowWindow(hwndButton, SW_HIDE); 2221 2222 if (!psInfo->hasFinish) 2223 { 2224 /* Hide Next button */ 2225 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); 2226 ShowWindow(hwndButton, SW_HIDE); 2227 } 2228 } 2229 2230 /****************************************************************************** 2231 * PROPSHEET_QuerySiblings 2232 */ 2233 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg, 2234 WPARAM wParam, LPARAM lParam) 2235 { 2236 int i = 0; 2237 HWND hwndPage; 2238 LRESULT msgResult = 0; 2239 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2240 2241 while ((i < psInfo->nPages) && (msgResult == 0)) 2242 { 2243 hwndPage = psInfo->proppage[i].hwndPage; 2244 msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam); 2245 i++; 2246 } 2247 2248 return msgResult; 2249 } 2250 2251 /****************************************************************************** 2252 * PROPSHEET_InsertPage 2253 */ 2254 static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage) 2255 { 2256 PropSheetInfo *psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2257 PropPageInfo *ppi, *prev_ppi = psInfo->proppage; 2258 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 2259 LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage; 2260 TCITEMW item; 2261 int index; 2262 2263 TRACE("hwndDlg %p, hpageInsertAfter %p, hpage %p\n", hwndDlg, hpageInsertAfter, hpage); 2264 2265 if (IS_INTRESOURCE(hpageInsertAfter)) 2266 index = LOWORD(hpageInsertAfter); 2267 else 2268 { 2269 index = PROPSHEET_GetPageIndex(hpageInsertAfter, psInfo, -1); 2270 if (index < 0) 2271 { 2272 TRACE("Could not find page to insert after!\n"); 2273 return FALSE; 2274 } 2275 index++; 2276 } 2277 2278 if (index > psInfo->nPages) 2279 index = psInfo->nPages; 2280 2281 ppi = Alloc(sizeof(PropPageInfo) * (psInfo->nPages + 1)); 2282 if (!ppi) 2283 return FALSE; 2284 2285 /* 2286 * Fill in a new PropPageInfo entry. 2287 */ 2288 if (index > 0) 2289 memcpy(ppi, prev_ppi, index * sizeof(PropPageInfo)); 2290 memset(&ppi[index], 0, sizeof(PropPageInfo)); 2291 if (index < psInfo->nPages) 2292 memcpy(&ppi[index + 1], &prev_ppi[index], (psInfo->nPages - index) * sizeof(PropPageInfo)); 2293 psInfo->proppage = ppi; 2294 2295 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, index, FALSE)) 2296 { 2297 psInfo->proppage = prev_ppi; 2298 Free(ppi); 2299 return FALSE; 2300 } 2301 2302 psInfo->proppage[index].hpage = hpage; 2303 2304 if (ppsp->dwFlags & PSP_PREMATURE) 2305 { 2306 /* Create the page but don't show it */ 2307 if (!PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppsp)) 2308 { 2309 psInfo->proppage = prev_ppi; 2310 Free(ppi); 2311 return FALSE; 2312 } 2313 } 2314 2315 Free(prev_ppi); 2316 psInfo->nPages++; 2317 if (index <= psInfo->active_page) 2318 psInfo->active_page++; 2319 2320 /* 2321 * Add a new tab to the tab control. 2322 */ 2323 item.mask = TCIF_TEXT; 2324 item.pszText = (LPWSTR) psInfo->proppage[index].pszText; 2325 item.cchTextMax = MAX_TABTEXT_LENGTH; 2326 2327 if (psInfo->hImageList) 2328 SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); 2329 2330 if (psInfo->proppage[index].hasIcon) 2331 { 2332 item.mask |= TCIF_IMAGE; 2333 item.iImage = index; 2334 } 2335 2336 SendMessageW(hwndTabControl, TCM_INSERTITEMW, index, (LPARAM)&item); 2337 2338 /* If it is the only page - show it */ 2339 if (psInfo->nPages == 1) 2340 PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0); 2341 2342 return TRUE; 2343 } 2344 2345 /****************************************************************************** 2346 * PROPSHEET_AddPage 2347 */ 2348 static BOOL PROPSHEET_AddPage(HWND hwndDlg, HPROPSHEETPAGE hpage) 2349 { 2350 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2351 TRACE("hwndDlg %p, hpage %p\n", hwndDlg, hpage); 2352 return PROPSHEET_InsertPage(hwndDlg, UlongToPtr(psInfo->nPages), hpage); 2353 } 2354 2355 /****************************************************************************** 2356 * PROPSHEET_RemovePage 2357 */ 2358 static BOOL PROPSHEET_RemovePage(HWND hwndDlg, 2359 int index, 2360 HPROPSHEETPAGE hpage) 2361 { 2362 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2363 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 2364 PropPageInfo* oldPages; 2365 2366 TRACE("index %d, hpage %p\n", index, hpage); 2367 if (!psInfo) { 2368 return FALSE; 2369 } 2370 2371 index = PROPSHEET_GetPageIndex(hpage, psInfo, index); 2372 2373 /* Make sure that index is within range */ 2374 if (index < 0 || index >= psInfo->nPages) 2375 { 2376 TRACE("Could not find page to remove!\n"); 2377 return FALSE; 2378 } 2379 2380 TRACE("total pages %d removing page %d active page %d\n", 2381 psInfo->nPages, index, psInfo->active_page); 2382 /* 2383 * Check if we're removing the active page. 2384 */ 2385 if (index == psInfo->active_page) 2386 { 2387 if (psInfo->nPages > 1) 2388 { 2389 if (index > 0) 2390 { 2391 /* activate previous page */ 2392 PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0); 2393 } 2394 else 2395 { 2396 /* activate the next page */ 2397 PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0); 2398 psInfo->active_page = index; 2399 } 2400 } 2401 else 2402 { 2403 psInfo->active_page = -1; 2404 if (!psInfo->isModeless) 2405 { 2406 psInfo->ended = TRUE; 2407 return TRUE; 2408 } 2409 } 2410 } 2411 else if (index < psInfo->active_page) 2412 psInfo->active_page--; 2413 2414 /* Unsubclass the page dialog window */ 2415 if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) && 2416 (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 2417 ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER)) 2418 { 2419 RemoveWindowSubclass(psInfo->proppage[index].hwndPage, 2420 PROPSHEET_WizardSubclassProc, 1); 2421 } 2422 2423 /* Destroy page dialog window */ 2424 DestroyWindow(psInfo->proppage[index].hwndPage); 2425 2426 /* Free page resources */ 2427 if(psInfo->proppage[index].hpage) 2428 { 2429 PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage; 2430 2431 if (psp->dwFlags & PSP_USETITLE) 2432 Free ((LPVOID)psInfo->proppage[index].pszText); 2433 2434 DestroyPropertySheetPage(psInfo->proppage[index].hpage); 2435 } 2436 2437 /* Remove the tab */ 2438 SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0); 2439 2440 oldPages = psInfo->proppage; 2441 psInfo->nPages--; 2442 psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages); 2443 2444 if (index > 0) 2445 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo)); 2446 2447 if (index < psInfo->nPages) 2448 memcpy(&psInfo->proppage[index], &oldPages[index + 1], 2449 (psInfo->nPages - index) * sizeof(PropPageInfo)); 2450 2451 Free(oldPages); 2452 2453 return FALSE; 2454 } 2455 2456 /****************************************************************************** 2457 * PROPSHEET_SetWizButtons 2458 * 2459 * This code will work if (and assumes that) the Next button is on top of the 2460 * Finish button. ie. Finish comes after Next in the Z order. 2461 * This means make sure the dialog template reflects this. 2462 * 2463 */ 2464 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags) 2465 { 2466 PropSheetInfo* psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2467 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); 2468 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); 2469 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); 2470 BOOL enable_finish = ((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH); 2471 2472 #ifdef __REACTOS__ 2473 HWND hwndCancel = GetDlgItem(hwndDlg, IDCANCEL); 2474 INT iDefItem = 0; 2475 HWND hwndFocus; 2476 #endif 2477 2478 TRACE("%d\n", dwFlags); 2479 2480 EnableWindow(hwndBack, dwFlags & PSWIZB_BACK); 2481 EnableWindow(hwndNext, dwFlags & PSWIZB_NEXT); 2482 EnableWindow(hwndFinish, enable_finish); 2483 2484 #ifndef __REACTOS__ 2485 /* set the default pushbutton to an enabled button */ 2486 if (enable_finish) 2487 SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); 2488 else if (dwFlags & PSWIZB_NEXT) 2489 SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0); 2490 else if (dwFlags & PSWIZB_BACK) 2491 SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0); 2492 else 2493 SendMessageW(hwndDlg, DM_SETDEFID, IDCANCEL, 0); 2494 #endif 2495 2496 if (!psInfo->hasFinish) 2497 { 2498 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH)) 2499 { 2500 /* Hide the Next button */ 2501 ShowWindow(hwndNext, SW_HIDE); 2502 2503 /* Show the Finish button */ 2504 ShowWindow(hwndFinish, SW_SHOW); 2505 } 2506 else 2507 { 2508 /* Hide the Finish button */ 2509 ShowWindow(hwndFinish, SW_HIDE); 2510 /* Show the Next button */ 2511 ShowWindow(hwndNext, SW_SHOW); 2512 } 2513 } 2514 2515 #ifdef __REACTOS__ 2516 /* set the default pushbutton to an enabled button */ 2517 if (((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH)) 2518 iDefItem = IDC_FINISH_BUTTON; 2519 else if (dwFlags & PSWIZB_NEXT) 2520 iDefItem = IDC_NEXT_BUTTON; 2521 else if (dwFlags & PSWIZB_BACK) 2522 iDefItem = IDC_BACK_BUTTON; 2523 else 2524 iDefItem = IDCANCEL; 2525 SendMessageW(hwndDlg, DM_SETDEFID, iDefItem, 0); 2526 2527 /* Set focus if no control has it */ 2528 hwndFocus = GetFocus(); 2529 if (!hwndFocus || hwndFocus == hwndCancel) 2530 SetFocus(GetDlgItem(hwndDlg, iDefItem)); 2531 #endif 2532 2533 } 2534 2535 /****************************************************************************** 2536 * PROPSHEET_SetHeaderTitleW 2537 */ 2538 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, UINT page_index, const WCHAR *title) 2539 { 2540 PropSheetInfo *psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2541 PROPSHEETPAGEW *page; 2542 2543 TRACE("(%p, %u, %s)\n", hwndDlg, page_index, debugstr_w(title)); 2544 2545 if (page_index >= psInfo->nPages) 2546 return; 2547 2548 page = (PROPSHEETPAGEW *)psInfo->proppage[page_index].hpage; 2549 2550 if (!IS_INTRESOURCE(page->pszHeaderTitle)) 2551 Free((void *)page->pszHeaderTitle); 2552 2553 page->pszHeaderTitle = heap_strdupW(title); 2554 page->dwFlags |= PSP_USEHEADERTITLE; 2555 } 2556 2557 /****************************************************************************** 2558 * PROPSHEET_SetHeaderTitleA 2559 */ 2560 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, UINT page_index, const char *title) 2561 { 2562 WCHAR *titleW; 2563 2564 TRACE("(%p, %u, %s)\n", hwndDlg, page_index, debugstr_a(title)); 2565 2566 titleW = heap_strdupAtoW(title); 2567 PROPSHEET_SetHeaderTitleW(hwndDlg, page_index, titleW); 2568 Free(titleW); 2569 } 2570 2571 /****************************************************************************** 2572 * PROPSHEET_SetHeaderSubTitleW 2573 */ 2574 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, UINT page_index, const WCHAR *subtitle) 2575 { 2576 PropSheetInfo *psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2577 PROPSHEETPAGEW *page; 2578 2579 TRACE("(%p, %u, %s)\n", hwndDlg, page_index, debugstr_w(subtitle)); 2580 2581 if (page_index >= psInfo->nPages) 2582 return; 2583 2584 page = (PROPSHEETPAGEW *)psInfo->proppage[page_index].hpage; 2585 2586 if (!IS_INTRESOURCE(page->pszHeaderSubTitle)) 2587 Free((void *)page->pszHeaderSubTitle); 2588 2589 page->pszHeaderSubTitle = heap_strdupW(subtitle); 2590 page->dwFlags |= PSP_USEHEADERSUBTITLE; 2591 } 2592 2593 /****************************************************************************** 2594 * PROPSHEET_SetHeaderSubTitleA 2595 */ 2596 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, UINT page_index, const char *subtitle) 2597 { 2598 WCHAR *subtitleW; 2599 2600 TRACE("(%p, %u, %s)\n", hwndDlg, page_index, debugstr_a(subtitle)); 2601 2602 subtitleW = heap_strdupAtoW(subtitle); 2603 PROPSHEET_SetHeaderSubTitleW(hwndDlg, page_index, subtitleW); 2604 Free(subtitleW); 2605 } 2606 2607 /****************************************************************************** 2608 * PROPSHEET_HwndToIndex 2609 */ 2610 static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg) 2611 { 2612 int index; 2613 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2614 2615 TRACE("(%p, %p)\n", hwndDlg, hPageDlg); 2616 2617 for (index = 0; index < psInfo->nPages; index++) 2618 if (psInfo->proppage[index].hwndPage == hPageDlg) 2619 return index; 2620 WARN("%p not found\n", hPageDlg); 2621 return -1; 2622 } 2623 2624 /****************************************************************************** 2625 * PROPSHEET_IndexToHwnd 2626 */ 2627 static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex) 2628 { 2629 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2630 TRACE("(%p, %d)\n", hwndDlg, iPageIndex); 2631 if (!psInfo) 2632 return 0; 2633 if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { 2634 WARN("%d out of range.\n", iPageIndex); 2635 return 0; 2636 } 2637 return (LRESULT)psInfo->proppage[iPageIndex].hwndPage; 2638 } 2639 2640 /****************************************************************************** 2641 * PROPSHEET_PageToIndex 2642 */ 2643 static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage) 2644 { 2645 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2646 2647 TRACE("(%p, %p)\n", hwndDlg, hPage); 2648 2649 return PROPSHEET_GetPageIndex(hPage, psInfo, -1); 2650 } 2651 2652 /****************************************************************************** 2653 * PROPSHEET_IndexToPage 2654 */ 2655 static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex) 2656 { 2657 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2658 TRACE("(%p, %d)\n", hwndDlg, iPageIndex); 2659 if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { 2660 WARN("%d out of range.\n", iPageIndex); 2661 return 0; 2662 } 2663 return (LRESULT)psInfo->proppage[iPageIndex].hpage; 2664 } 2665 2666 /****************************************************************************** 2667 * PROPSHEET_IdToIndex 2668 */ 2669 static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId) 2670 { 2671 int index; 2672 LPCPROPSHEETPAGEW psp; 2673 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2674 TRACE("(%p, %d)\n", hwndDlg, iPageId); 2675 for (index = 0; index < psInfo->nPages; index++) { 2676 psp = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; 2677 if (psp->u.pszTemplate == MAKEINTRESOURCEW(iPageId)) 2678 return index; 2679 } 2680 2681 return -1; 2682 } 2683 2684 /****************************************************************************** 2685 * PROPSHEET_IndexToId 2686 */ 2687 static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex) 2688 { 2689 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2690 LPCPROPSHEETPAGEW psp; 2691 TRACE("(%p, %d)\n", hwndDlg, iPageIndex); 2692 if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { 2693 WARN("%d out of range.\n", iPageIndex); 2694 return 0; 2695 } 2696 psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage; 2697 if (psp->dwFlags & PSP_DLGINDIRECT || !IS_INTRESOURCE(psp->u.pszTemplate)) { 2698 return 0; 2699 } 2700 return (LRESULT)psp->u.pszTemplate; 2701 } 2702 2703 /****************************************************************************** 2704 * PROPSHEET_GetResult 2705 */ 2706 static LRESULT PROPSHEET_GetResult(HWND hwndDlg) 2707 { 2708 PropSheetInfo * psInfo = GetPropW(hwndDlg, PropSheetInfoStr); 2709 return psInfo->result; 2710 } 2711 2712 /****************************************************************************** 2713 * PROPSHEET_RecalcPageSizes 2714 */ 2715 static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg) 2716 { 2717 FIXME("(%p): stub\n", hwndDlg); 2718 return FALSE; 2719 } 2720 2721 /****************************************************************************** 2722 * PROPSHEET_GetPageIndex 2723 * 2724 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from 2725 * the array of PropPageInfo. If page is not found original index is used 2726 * (page takes precedence over index). 2727 */ 2728 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE page, const PropSheetInfo* psInfo, int original_index) 2729 { 2730 int index; 2731 2732 TRACE("page %p index %d\n", page, original_index); 2733 2734 for (index = 0; index < psInfo->nPages; index++) 2735 if (psInfo->proppage[index].hpage == page) 2736 return index; 2737 2738 return original_index; 2739 } 2740 2741 /****************************************************************************** 2742 * PROPSHEET_CleanUp 2743 */ 2744 static void PROPSHEET_CleanUp(HWND hwndDlg) 2745 { 2746 int i; 2747 PropSheetInfo* psInfo = RemovePropW(hwndDlg, PropSheetInfoStr); 2748 2749 TRACE("\n"); 2750 if (!psInfo) return; 2751 if (!IS_INTRESOURCE(psInfo->ppshheader.pszCaption)) 2752 Free ((LPVOID)psInfo->ppshheader.pszCaption); 2753 2754 for (i = 0; i < psInfo->nPages; i++) 2755 { 2756 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage; 2757 2758 /* Unsubclass the page dialog window */ 2759 if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && 2760 (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 2761 (psp->dwFlags & PSP_HIDEHEADER)) 2762 { 2763 RemoveWindowSubclass(psInfo->proppage[i].hwndPage, 2764 PROPSHEET_WizardSubclassProc, 1); 2765 } 2766 2767 if(psInfo->proppage[i].hwndPage) 2768 DestroyWindow(psInfo->proppage[i].hwndPage); 2769 2770 if(psp) 2771 { 2772 if (psp->dwFlags & PSP_USETITLE) 2773 Free ((LPVOID)psInfo->proppage[i].pszText); 2774 2775 DestroyPropertySheetPage(psInfo->proppage[i].hpage); 2776 } 2777 } 2778 2779 DeleteObject(psInfo->hFont); 2780 DeleteObject(psInfo->hFontBold); 2781 /* If we created the bitmaps, destroy them */ 2782 if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 2783 (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) ) 2784 DeleteObject(psInfo->ppshheader.u4.hbmWatermark); 2785 if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && 2786 (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) ) 2787 DeleteObject(psInfo->ppshheader.u5.hbmHeader); 2788 2789 Free(psInfo->proppage); 2790 Free(psInfo->strPropertiesFor); 2791 ImageList_Destroy(psInfo->hImageList); 2792 2793 GlobalFree(psInfo); 2794 } 2795 2796 #ifdef __REACTOS__ 2797 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg); 2798 #endif 2799 2800 static INT do_loop(const PropSheetInfo *psInfo) 2801 { 2802 MSG msg = { 0 }; 2803 INT ret = 0; 2804 HWND hwnd = psInfo->hwnd; 2805 HWND parent = psInfo->ppshheader.hwndParent; 2806 2807 while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0))) 2808 { 2809 if(ret == -1) 2810 break; 2811 2812 #ifdef __REACTOS__ 2813 if (!PROPSHEET_IsDialogMessage(hwnd, &msg)) 2814 #else 2815 if(!IsDialogMessageW(hwnd, &msg)) 2816 #endif 2817 { 2818 TranslateMessage(&msg); 2819 DispatchMessageW(&msg); 2820 } 2821 } 2822 2823 if(ret == 0 && msg.message) 2824 PostQuitMessage(msg.wParam); 2825 2826 if(ret != -1) 2827 ret = psInfo->result; 2828 2829 if(parent) 2830 EnableWindow(parent, TRUE); 2831 2832 DestroyWindow(hwnd); 2833 return ret; 2834 } 2835 2836 /****************************************************************************** 2837 * PROPSHEET_PropertySheet 2838 * 2839 * Common code between PropertySheetA/W 2840 */ 2841 static INT_PTR PROPSHEET_PropertySheet(PropSheetInfo* psInfo, BOOL unicode) 2842 { 2843 INT_PTR bRet = 0; 2844 HWND parent = NULL; 2845 if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0; 2846 TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages); 2847 2848 psInfo->unicode = unicode; 2849 psInfo->ended = FALSE; 2850 2851 if(!psInfo->isModeless) 2852 { 2853 parent = psInfo->ppshheader.hwndParent; 2854 if (parent) EnableWindow(parent, FALSE); 2855 } 2856 bRet = PROPSHEET_CreateDialog(psInfo); 2857 if(!psInfo->isModeless) 2858 bRet = do_loop(psInfo); 2859 return bRet; 2860 } 2861 2862 /****************************************************************************** 2863 * PropertySheet (COMCTL32.@) 2864 * PropertySheetA (COMCTL32.@) 2865 * 2866 * Creates a property sheet in the specified property sheet header. 2867 * 2868 * RETURNS 2869 * Modal property sheets: Positive if successful or -1 otherwise. 2870 * Modeless property sheets: Property sheet handle. 2871 * Or: 2872 *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect. 2873 *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect. 2874 */ 2875 INT_PTR WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh) 2876 { 2877 PropSheetInfo* psInfo = GlobalAlloc(GPTR, sizeof(PropSheetInfo)); 2878 UINT i, n; 2879 const BYTE* pByte; 2880 2881 TRACE("(%p)\n", lppsh); 2882 2883 PROPSHEET_CollectSheetInfoA(lppsh, psInfo); 2884 2885 psInfo->proppage = Alloc(sizeof(PropPageInfo) * lppsh->nPages); 2886 pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp; 2887 2888 for (n = i = 0; i < lppsh->nPages; i++, n++) 2889 { 2890 if (!psInfo->usePropPage) 2891 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; 2892 else 2893 { 2894 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte); 2895 pByte += ((LPCPROPSHEETPAGEA)pByte)->dwSize; 2896 } 2897 2898 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, 2899 psInfo, n, TRUE)) 2900 { 2901 if (psInfo->usePropPage) 2902 DestroyPropertySheetPage(psInfo->proppage[n].hpage); 2903 n--; 2904 psInfo->nPages--; 2905 } 2906 } 2907 2908 return PROPSHEET_PropertySheet(psInfo, FALSE); 2909 } 2910 2911 /****************************************************************************** 2912 * PropertySheetW (COMCTL32.@) 2913 * 2914 * See PropertySheetA. 2915 */ 2916 INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh) 2917 { 2918 PropSheetInfo* psInfo = GlobalAlloc(GPTR, sizeof(PropSheetInfo)); 2919 UINT i, n; 2920 const BYTE* pByte; 2921 2922 TRACE("(%p)\n", lppsh); 2923 2924 PROPSHEET_CollectSheetInfoW(lppsh, psInfo); 2925 2926 psInfo->proppage = Alloc(sizeof(PropPageInfo) * lppsh->nPages); 2927 pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp; 2928 2929 for (n = i = 0; i < lppsh->nPages; i++, n++) 2930 { 2931 if (!psInfo->usePropPage) 2932 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; 2933 else 2934 { 2935 psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte); 2936 pByte += ((LPCPROPSHEETPAGEW)pByte)->dwSize; 2937 } 2938 2939 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, 2940 psInfo, n, TRUE)) 2941 { 2942 if (psInfo->usePropPage) 2943 DestroyPropertySheetPage(psInfo->proppage[n].hpage); 2944 n--; 2945 psInfo->nPages--; 2946 } 2947 } 2948 2949 return PROPSHEET_PropertySheet(psInfo, TRUE); 2950 } 2951 2952 static LPWSTR load_string( HINSTANCE instance, LPCWSTR str ) 2953 { 2954 LPWSTR ret; 2955 2956 if (IS_INTRESOURCE(str)) 2957 { 2958 HRSRC hrsrc; 2959 HGLOBAL hmem; 2960 WCHAR *ptr; 2961 WORD i, id = LOWORD(str); 2962 UINT len; 2963 2964 if (!(hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((id >> 4) + 1), (LPWSTR)RT_STRING ))) 2965 return NULL; 2966 if (!(hmem = LoadResource( instance, hrsrc ))) return NULL; 2967 if (!(ptr = LockResource( hmem ))) return NULL; 2968 for (i = id & 0x0f; i > 0; i--) ptr += *ptr + 1; 2969 len = *ptr; 2970 if (!len) return NULL; 2971 ret = Alloc( (len + 1) * sizeof(WCHAR) ); 2972 if (ret) 2973 { 2974 memcpy( ret, ptr + 1, len * sizeof(WCHAR) ); 2975 ret[len] = 0; 2976 } 2977 } 2978 else 2979 { 2980 int len = (lstrlenW(str) + 1) * sizeof(WCHAR); 2981 ret = Alloc( len ); 2982 if (ret) memcpy( ret, str, len ); 2983 } 2984 return ret; 2985 } 2986 2987 2988 /****************************************************************************** 2989 * CreatePropertySheetPage (COMCTL32.@) 2990 * CreatePropertySheetPageA (COMCTL32.@) 2991 * 2992 * Creates a new property sheet page. 2993 * 2994 * RETURNS 2995 * Success: Handle to new property sheet page. 2996 * Failure: NULL. 2997 * 2998 * NOTES 2999 * An application must use the PSM_ADDPAGE message to add the new page to 3000 * an existing property sheet. 3001 */ 3002 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA( 3003 LPCPROPSHEETPAGEA lpPropSheetPage) 3004 { 3005 PROPSHEETPAGEW *ppsp; 3006 3007 if (lpPropSheetPage->dwSize < PROPSHEETPAGEA_V1_SIZE) 3008 return NULL; 3009 3010 /* original data is used for callback notifications */ 3011 if ((lpPropSheetPage->dwFlags & PSP_USECALLBACK) && lpPropSheetPage->pfnCallback) 3012 { 3013 ppsp = Alloc(2 * sizeof(*ppsp)); 3014 memcpy(ppsp, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEA))); 3015 memcpy(ppsp + 1, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEA))); 3016 } 3017 else 3018 { 3019 ppsp = Alloc(sizeof(*ppsp)); 3020 memcpy(ppsp, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEA))); 3021 } 3022 3023 ppsp->dwFlags &= ~PSP_INTERNAL_UNICODE; 3024 3025 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) ) 3026 { 3027 if (!IS_INTRESOURCE( ppsp->u.pszTemplate )) 3028 { 3029 int len = strlen(lpPropSheetPage->u.pszTemplate) + 1; 3030 char *template = Alloc( len ); 3031 3032 ppsp->u.pszTemplate = (LPWSTR)strcpy( template, lpPropSheetPage->u.pszTemplate ); 3033 } 3034 } 3035 3036 if (ppsp->dwFlags & PSP_USEICONID) 3037 { 3038 if (!IS_INTRESOURCE( ppsp->u2.pszIcon )) 3039 ppsp->u2.pszIcon = heap_strdupAtoW( lpPropSheetPage->u2.pszIcon ); 3040 } 3041 3042 if (ppsp->dwFlags & PSP_USETITLE) 3043 { 3044 if (IS_INTRESOURCE( ppsp->pszTitle )) 3045 ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle ); 3046 else 3047 ppsp->pszTitle = heap_strdupAtoW( lpPropSheetPage->pszTitle ); 3048 } 3049 else 3050 ppsp->pszTitle = NULL; 3051 3052 if (ppsp->dwFlags & PSP_HIDEHEADER) 3053 ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE); 3054 3055 if (ppsp->dwFlags & PSP_USEHEADERTITLE) 3056 { 3057 if (IS_INTRESOURCE( ppsp->pszHeaderTitle )) 3058 ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle ); 3059 else 3060 ppsp->pszHeaderTitle = heap_strdupAtoW( lpPropSheetPage->pszHeaderTitle ); 3061 } 3062 else 3063 ppsp->pszHeaderTitle = NULL; 3064 3065 if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE) 3066 { 3067 if (IS_INTRESOURCE( ppsp->pszHeaderSubTitle )) 3068 ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle ); 3069 else 3070 ppsp->pszHeaderSubTitle = heap_strdupAtoW( lpPropSheetPage->pszHeaderSubTitle ); 3071 } 3072 else 3073 ppsp->pszHeaderSubTitle = NULL; 3074 3075 if ((ppsp->dwFlags & PSP_USECALLBACK) && ppsp->dwSize > PROPSHEETPAGEA_V1_SIZE && ppsp->pfnCallback) 3076 ppsp->pfnCallback(0, PSPCB_ADDREF, ppsp + 1); 3077 3078 return (HPROPSHEETPAGE)ppsp; 3079 } 3080 3081 /****************************************************************************** 3082 * CreatePropertySheetPageW (COMCTL32.@) 3083 * 3084 * See CreatePropertySheetA. 3085 */ 3086 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage) 3087 { 3088 PROPSHEETPAGEW *ppsp; 3089 3090 if (lpPropSheetPage->dwSize < PROPSHEETPAGEW_V1_SIZE) 3091 return NULL; 3092 3093 /* original data is used for callback notifications */ 3094 if ((lpPropSheetPage->dwFlags & PSP_USECALLBACK) && lpPropSheetPage->pfnCallback) 3095 { 3096 ppsp = Alloc(2 * sizeof(*ppsp)); 3097 memcpy(ppsp, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEW))); 3098 memcpy(ppsp + 1, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEW))); 3099 } 3100 else 3101 { 3102 ppsp = Alloc(sizeof(*ppsp)); 3103 memcpy(ppsp, lpPropSheetPage, min(lpPropSheetPage->dwSize, sizeof(PROPSHEETPAGEW))); 3104 } 3105 3106 ppsp->dwFlags |= PSP_INTERNAL_UNICODE; 3107 3108 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) ) 3109 { 3110 if (!IS_INTRESOURCE( ppsp->u.pszTemplate )) 3111 ppsp->u.pszTemplate = heap_strdupW( lpPropSheetPage->u.pszTemplate ); 3112 } 3113 3114 if ( ppsp->dwFlags & PSP_USEICONID ) 3115 { 3116 if (!IS_INTRESOURCE( ppsp->u2.pszIcon )) 3117 ppsp->u2.pszIcon = heap_strdupW( lpPropSheetPage->u2.pszIcon ); 3118 } 3119 3120 if (ppsp->dwFlags & PSP_USETITLE) 3121 ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle ); 3122 else 3123 ppsp->pszTitle = NULL; 3124 3125 if (ppsp->dwFlags & PSP_HIDEHEADER) 3126 ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE); 3127 3128 if (ppsp->dwFlags & PSP_USEHEADERTITLE) 3129 ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle ); 3130 else 3131 ppsp->pszHeaderTitle = NULL; 3132 3133 if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE) 3134 ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle ); 3135 else 3136 ppsp->pszHeaderSubTitle = NULL; 3137 3138 if ((ppsp->dwFlags & PSP_USECALLBACK) && ppsp->dwSize > PROPSHEETPAGEW_V1_SIZE && ppsp->pfnCallback) 3139 ppsp->pfnCallback(0, PSPCB_ADDREF, ppsp + 1); 3140 3141 return (HPROPSHEETPAGE)ppsp; 3142 } 3143 3144 /****************************************************************************** 3145 * DestroyPropertySheetPage (COMCTL32.@) 3146 * 3147 * Destroys a property sheet page previously created with 3148 * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated 3149 * memory. 3150 * 3151 * RETURNS 3152 * Success: TRUE 3153 * Failure: FALSE 3154 */ 3155 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage) 3156 { 3157 PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage; 3158 3159 if (!psp) 3160 return FALSE; 3161 3162 if ((psp->dwFlags & PSP_USECALLBACK) && psp->pfnCallback) 3163 psp->pfnCallback(0, PSPCB_RELEASE, psp + 1); 3164 3165 if (!(psp->dwFlags & PSP_DLGINDIRECT) && !IS_INTRESOURCE( psp->u.pszTemplate )) 3166 Free ((LPVOID)psp->u.pszTemplate); 3167 3168 if ((psp->dwFlags & PSP_USEICONID) && !IS_INTRESOURCE( psp->u2.pszIcon )) 3169 Free ((LPVOID)psp->u2.pszIcon); 3170 3171 if ((psp->dwFlags & PSP_USETITLE) && !IS_INTRESOURCE( psp->pszTitle )) 3172 Free ((LPVOID)psp->pszTitle); 3173 3174 if ((psp->dwFlags & PSP_USEHEADERTITLE) && !IS_INTRESOURCE( psp->pszHeaderTitle )) 3175 Free ((LPVOID)psp->pszHeaderTitle); 3176 3177 if ((psp->dwFlags & PSP_USEHEADERSUBTITLE) && !IS_INTRESOURCE( psp->pszHeaderSubTitle )) 3178 Free ((LPVOID)psp->pszHeaderSubTitle); 3179 3180 Free(hPropPage); 3181 3182 return TRUE; 3183 } 3184 3185 /****************************************************************************** 3186 * PROPSHEET_IsDialogMessage 3187 */ 3188 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg) 3189 { 3190 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3191 3192 TRACE("\n"); 3193 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd))) 3194 return FALSE; 3195 3196 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000)) 3197 { 3198 int new_page = 0; 3199 INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg); 3200 3201 if (!(dlgCode & DLGC_WANTMESSAGE)) 3202 { 3203 switch (lpMsg->wParam) 3204 { 3205 case VK_TAB: 3206 if (GetKeyState(VK_SHIFT) & 0x8000) 3207 new_page = -1; 3208 else 3209 new_page = 1; 3210 break; 3211 3212 case VK_NEXT: new_page = 1; break; 3213 case VK_PRIOR: new_page = -1; break; 3214 } 3215 } 3216 3217 if (new_page) 3218 { 3219 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE) 3220 { 3221 new_page += psInfo->active_page; 3222 3223 if (new_page < 0) 3224 new_page = psInfo->nPages - 1; 3225 else if (new_page >= psInfo->nPages) 3226 new_page = 0; 3227 3228 PROPSHEET_SetCurSel(hwnd, new_page, 1, 0); 3229 } 3230 3231 return TRUE; 3232 } 3233 } 3234 3235 return IsDialogMessageW(hwnd, lpMsg); 3236 } 3237 3238 /****************************************************************************** 3239 * PROPSHEET_DoCommand 3240 */ 3241 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID) 3242 { 3243 3244 switch (wID) { 3245 3246 case IDOK: 3247 case IDC_APPLY_BUTTON: 3248 { 3249 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON); 3250 3251 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE) 3252 break; 3253 3254 if (wID == IDOK) 3255 { 3256 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3257 3258 /* don't overwrite ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM */ 3259 if (psInfo->result == 0) 3260 psInfo->result = IDOK; 3261 3262 if (psInfo->isModeless) 3263 psInfo->activeValid = FALSE; 3264 else 3265 psInfo->ended = TRUE; 3266 } 3267 else 3268 EnableWindow(hwndApplyBtn, FALSE); 3269 3270 break; 3271 } 3272 3273 case IDC_BACK_BUTTON: 3274 PROPSHEET_Back(hwnd); 3275 break; 3276 3277 case IDC_NEXT_BUTTON: 3278 PROPSHEET_Next(hwnd); 3279 break; 3280 3281 case IDC_FINISH_BUTTON: 3282 PROPSHEET_Finish(hwnd); 3283 break; 3284 3285 case IDCANCEL: 3286 PROPSHEET_Cancel(hwnd, 0); 3287 break; 3288 3289 case IDHELP: 3290 PROPSHEET_Help(hwnd); 3291 break; 3292 3293 default: 3294 return FALSE; 3295 } 3296 3297 return TRUE; 3298 } 3299 3300 /****************************************************************************** 3301 * PROPSHEET_Paint 3302 */ 3303 static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam) 3304 { 3305 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3306 PAINTSTRUCT ps; 3307 HDC hdc, hdcSrc; 3308 BITMAP bm; 3309 HBITMAP hbmp; 3310 HPALETTE hOldPal = 0; 3311 int offsety = 0; 3312 HBRUSH hbr; 3313 RECT r, rzone; 3314 LPCPROPSHEETPAGEW ppshpage; 3315 WCHAR szBuffer[256]; 3316 int nLength; 3317 3318 hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps); 3319 if (!hdc) return 1; 3320 3321 hdcSrc = CreateCompatibleDC(0); 3322 3323 if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 3324 hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE); 3325 3326 if (psInfo->active_page < 0) 3327 ppshpage = NULL; 3328 else 3329 ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage; 3330 3331 if ( (ppshpage && !(ppshpage->dwFlags & PSP_HIDEHEADER)) && 3332 (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && 3333 (psInfo->ppshheader.dwFlags & PSH_HEADER) ) 3334 { 3335 HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER); 3336 HFONT hOldFont; 3337 COLORREF clrOld = 0; 3338 int oldBkMode = 0; 3339 3340 GetClientRect(hwndLineHeader, &r); 3341 MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2); 3342 SetRect(&rzone, 0, 0, r.right + 1, r.top - 1); 3343 3344 hOldFont = SelectObject(hdc, psInfo->hFontBold); 3345 3346 #ifdef __REACTOS__ 3347 if (psInfo->ppshheader.u5.hbmHeader) 3348 #else 3349 if (psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER) 3350 #endif 3351 { 3352 hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader); 3353 3354 GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), &bm); 3355 if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD) 3356 { 3357 /* Fill the unoccupied part of the header with color of the 3358 * left-top pixel, but do it only when needed. 3359 */ 3360 if (bm.bmWidth < r.right || bm.bmHeight < r.bottom) 3361 { 3362 hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); 3363 r = rzone; 3364 if (bm.bmWidth < r.right) 3365 { 3366 r.left = bm.bmWidth; 3367 FillRect(hdc, &r, hbr); 3368 } 3369 if (bm.bmHeight < r.bottom) 3370 { 3371 r.left = 0; 3372 r.top = bm.bmHeight; 3373 FillRect(hdc, &r, hbr); 3374 } 3375 DeleteObject(hbr); 3376 } 3377 3378 /* Draw the header itself. */ 3379 BitBlt(hdc, 0, 0, bm.bmWidth, min(bm.bmHeight, rzone.bottom), 3380 hdcSrc, 0, 0, SRCCOPY); 3381 } 3382 else 3383 { 3384 int margin; 3385 hbr = GetSysColorBrush(COLOR_WINDOW); 3386 FillRect(hdc, &rzone, hbr); 3387 3388 /* Draw the header bitmap. It's always centered like a 3389 * common 49 x 49 bitmap. */ 3390 margin = (rzone.bottom - 49) / 2; 3391 BitBlt(hdc, rzone.right - 49 - margin, margin, 3392 min(bm.bmWidth, 49), min(bm.bmHeight, 49), 3393 hdcSrc, 0, 0, SRCCOPY); 3394 3395 /* NOTE: Native COMCTL32 draws a white stripe over the bitmap 3396 * if its height is smaller than 49 pixels. Because the reason 3397 * for this bug is unknown the current code doesn't try to 3398 * replicate it. */ 3399 } 3400 3401 SelectObject(hdcSrc, hbmp); 3402 } 3403 3404 clrOld = SetTextColor (hdc, 0x00000000); 3405 oldBkMode = SetBkMode (hdc, TRANSPARENT); 3406 3407 if (ppshpage->dwFlags & PSP_USEHEADERTITLE) { 3408 SetRect(&r, 20, 10, 0, 0); 3409 if (!IS_INTRESOURCE(ppshpage->pszHeaderTitle)) 3410 DrawTextW(hdc, ppshpage->pszHeaderTitle, -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); 3411 else 3412 { 3413 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderTitle, 3414 szBuffer, 256); 3415 if (nLength != 0) 3416 { 3417 DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); 3418 } 3419 } 3420 } 3421 3422 if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) { 3423 SelectObject(hdc, psInfo->hFont); 3424 SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom); 3425 #ifdef __REACTOS__ 3426 if (!IS_INTRESOURCE(ppshpage->pszHeaderSubTitle)) 3427 #else 3428 if (!IS_INTRESOURCE(ppshpage->pszHeaderTitle)) 3429 #endif 3430 DrawTextW(hdc, ppshpage->pszHeaderSubTitle, -1, &r, DT_LEFT | DT_WORDBREAK); 3431 else 3432 { 3433 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderSubTitle, 3434 szBuffer, 256); 3435 if (nLength != 0) 3436 { 3437 DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_WORDBREAK); 3438 } 3439 } 3440 } 3441 3442 offsety = rzone.bottom + 2; 3443 3444 SetTextColor(hdc, clrOld); 3445 SetBkMode(hdc, oldBkMode); 3446 SelectObject(hdc, hOldFont); 3447 } 3448 3449 if ( (ppshpage && (ppshpage->dwFlags & PSP_HIDEHEADER)) && 3450 (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && 3451 #ifdef __REACTOS__ 3452 (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && 3453 (psInfo->ppshheader.u4.hbmWatermark) ) 3454 #else 3455 (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) 3456 #endif 3457 { 3458 HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE); 3459 3460 GetClientRect(hwndLine, &r); 3461 MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2); 3462 SetRect(&rzone, 0, 0, r.right, r.top - 1); 3463 3464 hbr = GetSysColorBrush(COLOR_WINDOW); 3465 FillRect(hdc, &rzone, hbr); 3466 3467 GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), &bm); 3468 hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark); 3469 3470 /* The watermark is truncated to a width of 164 pixels */ 3471 r.right = min(r.right, 164); 3472 BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right), 3473 min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY); 3474 3475 /* If the bitmap is not big enough, fill the remaining area 3476 with the color of pixel (0,0) of bitmap - see MSDN */ 3477 if (r.top > bm.bmHeight) { 3478 r.bottom = r.top - 1; 3479 r.top = bm.bmHeight; 3480 r.left = 0; 3481 r.right = bm.bmWidth; 3482 hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); 3483 FillRect(hdc, &r, hbr); 3484 DeleteObject(hbr); 3485 } 3486 3487 SelectObject(hdcSrc, hbmp); 3488 } 3489 3490 if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 3491 SelectPalette(hdc, hOldPal, FALSE); 3492 3493 DeleteDC(hdcSrc); 3494 3495 if (!hdcParam) EndPaint(hwnd, &ps); 3496 3497 return 0; 3498 } 3499 3500 /****************************************************************************** 3501 * PROPSHEET_DialogProc 3502 */ 3503 static INT_PTR CALLBACK 3504 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 3505 { 3506 TRACE("hwnd=%p msg=0x%04x wparam=%lx lparam=%lx\n", 3507 hwnd, uMsg, wParam, lParam); 3508 3509 switch (uMsg) 3510 { 3511 case WM_INITDIALOG: 3512 { 3513 PropSheetInfo* psInfo = (PropSheetInfo*) lParam; 3514 WCHAR* strCaption = Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR)); 3515 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); 3516 int idx; 3517 LOGFONTW logFont; 3518 3519 /* Using PropSheetInfoStr to store extra data doesn't match the native 3520 * common control: native uses TCM_[GS]ETITEM 3521 */ 3522 SetPropW(hwnd, PropSheetInfoStr, psInfo); 3523 3524 /* 3525 * psInfo->hwnd is not being used by WINE code - it exists 3526 * for compatibility with "real" Windoze. The same about 3527 * SetWindowLongPtr - WINE is only using the PropSheetInfoStr 3528 * property. 3529 */ 3530 psInfo->hwnd = hwnd; 3531 SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo); 3532 3533 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 3534 { 3535 /* set up the Next and Back buttons by default */ 3536 PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT); 3537 } 3538 3539 /* Set up fonts */ 3540 SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); 3541 psInfo->hFont = CreateFontIndirectW (&logFont); 3542 logFont.lfWeight = FW_BOLD; 3543 psInfo->hFontBold = CreateFontIndirectW (&logFont); 3544 3545 /* 3546 * Small icon in the title bar. 3547 */ 3548 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) || 3549 (psInfo->ppshheader.dwFlags & PSH_USEHICON)) 3550 { 3551 HICON hIcon; 3552 int icon_cx = GetSystemMetrics(SM_CXSMICON); 3553 int icon_cy = GetSystemMetrics(SM_CYSMICON); 3554 3555 if (psInfo->ppshheader.dwFlags & PSH_USEICONID) 3556 hIcon = LoadImageW(psInfo->ppshheader.hInstance, 3557 psInfo->ppshheader.u.pszIcon, 3558 IMAGE_ICON, 3559 icon_cx, icon_cy, 3560 LR_DEFAULTCOLOR); 3561 else 3562 hIcon = psInfo->ppshheader.u.hIcon; 3563 3564 SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon); 3565 } 3566 3567 if (psInfo->ppshheader.dwFlags & PSH_USEHICON) 3568 SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon); 3569 3570 psInfo->strPropertiesFor = strCaption; 3571 3572 GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH); 3573 3574 PROPSHEET_CreateTabControl(hwnd, psInfo); 3575 3576 PROPSHEET_LoadWizardBitmaps(psInfo); 3577 3578 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 3579 { 3580 ShowWindow(hwndTabCtrl, SW_HIDE); 3581 PROPSHEET_AdjustSizeWizard(hwnd, psInfo); 3582 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo); 3583 SetFocus(GetDlgItem(hwnd, IDC_NEXT_BUTTON)); 3584 } 3585 else 3586 { 3587 if (PROPSHEET_SizeMismatch(hwnd, psInfo)) 3588 { 3589 PROPSHEET_AdjustSize(hwnd, psInfo); 3590 PROPSHEET_AdjustButtons(hwnd, psInfo); 3591 } 3592 SetFocus(GetDlgItem(hwnd, IDOK)); 3593 } 3594 #ifdef __REACTOS__ 3595 /* Move the window position if necessary */ 3596 { 3597 INT dx, dy; 3598 RECT rcInit; 3599 HWND hwndParent = psInfo->ppshheader.hwndParent; 3600 BOOL bMove = FALSE; 3601 3602 GetWindowRect(hwnd, &rcInit); 3603 dx = rcInit.right - rcInit.left; 3604 dy = rcInit.bottom - rcInit.top; 3605 3606 if (IsWindow(hwndParent)) 3607 { 3608 WINDOWPLACEMENT wndpl = { sizeof(wndpl) }; 3609 bMove = TRUE; 3610 3611 /* hwndParent can be minimized (See Control_ShowAppletInTaskbar). 3612 Use normal position. */ 3613 GetWindowPlacement(hwndParent, &wndpl); 3614 rcInit = wndpl.rcNormalPosition; 3615 if (IsWindowVisible(hwndParent) && !IsIconic(hwndParent)) 3616 { 3617 /* Is it Right-to-Left layout? */ 3618 if (GetWindowLongPtrW(hwndParent, GWL_EXSTYLE) & WS_EX_RTLREADING) 3619 rcInit.left = rcInit.right - dx - GetSystemMetrics(SM_CXSMICON); 3620 else 3621 rcInit.left += GetSystemMetrics(SM_CXSMICON); 3622 3623 rcInit.top += GetSystemMetrics(SM_CYSMICON); 3624 } 3625 } 3626 else 3627 { 3628 /* We cannot foresee CW_USEDEFAULT's position without communicating with USER32. 3629 Use a top-level STATIC control to get the proper position. */ 3630 HWND hwndDummy = CreateWindowExW(0, WC_STATICW, NULL, 0, 3631 CW_USEDEFAULT, CW_USEDEFAULT, dx, dy, 3632 NULL, NULL, GetModuleHandleW(NULL), NULL); 3633 if (hwndDummy) 3634 { 3635 bMove = TRUE; 3636 GetWindowRect(hwndDummy, &rcInit); 3637 DestroyWindow(hwndDummy); 3638 } 3639 } 3640 3641 if (bMove) 3642 { 3643 MONITORINFO mi = { sizeof(mi) }; 3644 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); 3645 if (GetMonitorInfo(hMonitor, &mi)) 3646 { 3647 /* Try to fit it onto the desktop */ 3648 if (mi.rcWork.right < rcInit.left + dx) 3649 rcInit.left = mi.rcWork.right - dx; 3650 if (mi.rcWork.bottom < rcInit.top + dy) 3651 rcInit.top = mi.rcWork.bottom - dy; 3652 if (rcInit.left < mi.rcWork.left) 3653 rcInit.left = mi.rcWork.left; 3654 if (rcInit.top < mi.rcWork.top) 3655 rcInit.top = mi.rcWork.top; 3656 SetWindowPos(hwnd, NULL, rcInit.left, rcInit.top, 0, 0, 3657 SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER); 3658 } 3659 } 3660 } 3661 #endif 3662 3663 if (IS_INTRESOURCE(psInfo->ppshheader.pszCaption) && 3664 psInfo->ppshheader.hInstance) 3665 { 3666 WCHAR szText[256]; 3667 3668 if (LoadStringW(psInfo->ppshheader.hInstance, 3669 (UINT_PTR)psInfo->ppshheader.pszCaption, szText, 255)) 3670 PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText); 3671 } 3672 else 3673 { 3674 PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, 3675 psInfo->ppshheader.pszCaption); 3676 } 3677 3678 3679 if (psInfo->useCallback) 3680 (*(psInfo->ppshheader.pfnCallback))(hwnd, PSCB_INITIALIZED, 0); 3681 3682 idx = psInfo->active_page; 3683 psInfo->active_page = -1; 3684 3685 PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage); 3686 3687 /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD, 3688 * as some programs call TCM_GETCURSEL to get the current selection 3689 * from which to switch to the next page */ 3690 SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0); 3691 3692 PROPSHEET_UnChanged(hwnd, NULL); 3693 3694 /* wizards set their focus during init */ 3695 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) 3696 return FALSE; 3697 3698 return TRUE; 3699 } 3700 3701 case WM_PRINTCLIENT: 3702 case WM_PAINT: 3703 PROPSHEET_Paint(hwnd, (HDC)wParam); 3704 return TRUE; 3705 3706 case WM_DESTROY: 3707 PROPSHEET_CleanUp(hwnd); 3708 return TRUE; 3709 3710 case WM_CLOSE: 3711 PROPSHEET_Cancel(hwnd, 1); 3712 return FALSE; /* let DefDlgProc post us WM_COMMAND/IDCANCEL */ 3713 3714 case WM_COMMAND: 3715 if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam))) 3716 { 3717 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3718 3719 if (!psInfo) 3720 return FALSE; 3721 3722 /* No default handler, forward notification to active page */ 3723 if (psInfo->activeValid && psInfo->active_page != -1) 3724 { 3725 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 3726 SendMessageW(hwndPage, WM_COMMAND, wParam, lParam); 3727 } 3728 } 3729 return TRUE; 3730 3731 case WM_NOTIFY: 3732 { 3733 NMHDR* pnmh = (LPNMHDR) lParam; 3734 3735 if (pnmh->code == TCN_SELCHANGE) 3736 { 3737 int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0); 3738 PROPSHEET_SetCurSel(hwnd, index, 1, 0); 3739 } 3740 3741 if(pnmh->code == TCN_SELCHANGING) 3742 { 3743 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd); 3744 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet); 3745 return TRUE; 3746 } 3747 3748 return FALSE; 3749 } 3750 3751 case WM_SYSCOLORCHANGE: 3752 COMCTL32_RefreshSysColors(); 3753 return FALSE; 3754 3755 case PSM_GETCURRENTPAGEHWND: 3756 { 3757 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3758 HWND hwndPage = 0; 3759 3760 if (!psInfo) 3761 return FALSE; 3762 3763 if (psInfo->activeValid && psInfo->active_page != -1) 3764 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; 3765 3766 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage); 3767 3768 return TRUE; 3769 } 3770 3771 case PSM_CHANGED: 3772 PROPSHEET_Changed(hwnd, (HWND)wParam); 3773 return TRUE; 3774 3775 case PSM_UNCHANGED: 3776 PROPSHEET_UnChanged(hwnd, (HWND)wParam); 3777 return TRUE; 3778 3779 case PSM_GETTABCONTROL: 3780 { 3781 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); 3782 3783 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl); 3784 3785 return TRUE; 3786 } 3787 3788 case PSM_SETCURSEL: 3789 { 3790 BOOL msgResult; 3791 3792 msgResult = PROPSHEET_CanSetCurSel(hwnd); 3793 if(msgResult != FALSE) 3794 { 3795 msgResult = PROPSHEET_SetCurSel(hwnd, 3796 (int)wParam, 3797 1, 3798 (HPROPSHEETPAGE)lParam); 3799 } 3800 3801 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3802 3803 return TRUE; 3804 } 3805 3806 case PSM_CANCELTOCLOSE: 3807 { 3808 WCHAR buf[MAX_BUTTONTEXT_LENGTH]; 3809 HWND hwndOK = GetDlgItem(hwnd, IDOK); 3810 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL); 3811 3812 EnableWindow(hwndCancel, FALSE); 3813 if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, ARRAY_SIZE(buf))) 3814 SetWindowTextW(hwndOK, buf); 3815 3816 return FALSE; 3817 } 3818 3819 case PSM_RESTARTWINDOWS: 3820 { 3821 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3822 3823 if (!psInfo) 3824 return FALSE; 3825 3826 /* reboot system takes precedence over restart windows */ 3827 if (psInfo->result != ID_PSREBOOTSYSTEM) 3828 psInfo->result = ID_PSRESTARTWINDOWS; 3829 3830 return TRUE; 3831 } 3832 3833 case PSM_REBOOTSYSTEM: 3834 { 3835 PropSheetInfo* psInfo = GetPropW(hwnd, PropSheetInfoStr); 3836 3837 if (!psInfo) 3838 return FALSE; 3839 3840 psInfo->result = ID_PSREBOOTSYSTEM; 3841 3842 return TRUE; 3843 } 3844 3845 case PSM_SETTITLEA: 3846 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam); 3847 return TRUE; 3848 3849 case PSM_SETTITLEW: 3850 PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam); 3851 return TRUE; 3852 3853 case PSM_APPLY: 3854 { 3855 BOOL msgResult = PROPSHEET_Apply(hwnd, 0); 3856 3857 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3858 3859 return TRUE; 3860 } 3861 3862 case PSM_QUERYSIBLINGS: 3863 { 3864 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam); 3865 3866 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3867 3868 return TRUE; 3869 } 3870 3871 case PSM_ADDPAGE: 3872 { 3873 /* 3874 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have 3875 * a return value. This is not true. PSM_ADDPAGE returns TRUE 3876 * on success or FALSE otherwise, as specified on MSDN Online. 3877 * Also see the MFC code for 3878 * CPropertySheet::AddPage(CPropertyPage* pPage). 3879 */ 3880 3881 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam); 3882 3883 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3884 3885 return TRUE; 3886 } 3887 3888 case PSM_REMOVEPAGE: 3889 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam); 3890 return TRUE; 3891 3892 case PSM_ISDIALOGMESSAGE: 3893 { 3894 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam); 3895 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3896 return TRUE; 3897 } 3898 3899 case PSM_PRESSBUTTON: 3900 PROPSHEET_PressButton(hwnd, (int)wParam); 3901 return TRUE; 3902 3903 case PSM_SETFINISHTEXTA: 3904 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam); 3905 return TRUE; 3906 3907 case PSM_SETWIZBUTTONS: 3908 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam); 3909 return TRUE; 3910 3911 case PSM_SETCURSELID: 3912 PROPSHEET_SetCurSelId(hwnd, (int)lParam); 3913 return TRUE; 3914 3915 case PSM_SETFINISHTEXTW: 3916 PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam); 3917 return FALSE; 3918 3919 case PSM_INSERTPAGE: 3920 { 3921 BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam); 3922 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3923 return TRUE; 3924 } 3925 3926 case PSM_SETHEADERTITLEW: 3927 PROPSHEET_SetHeaderTitleW(hwnd, wParam, (LPCWSTR)lParam); 3928 return TRUE; 3929 3930 case PSM_SETHEADERTITLEA: 3931 PROPSHEET_SetHeaderTitleA(hwnd, wParam, (LPCSTR)lParam); 3932 return TRUE; 3933 3934 case PSM_SETHEADERSUBTITLEW: 3935 PROPSHEET_SetHeaderSubTitleW(hwnd, wParam, (LPCWSTR)lParam); 3936 return TRUE; 3937 3938 case PSM_SETHEADERSUBTITLEA: 3939 PROPSHEET_SetHeaderSubTitleA(hwnd, wParam, (LPCSTR)lParam); 3940 return TRUE; 3941 3942 case PSM_HWNDTOINDEX: 3943 { 3944 LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam); 3945 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3946 return TRUE; 3947 } 3948 3949 case PSM_INDEXTOHWND: 3950 { 3951 LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam); 3952 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3953 return TRUE; 3954 } 3955 3956 case PSM_PAGETOINDEX: 3957 { 3958 LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam); 3959 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3960 return TRUE; 3961 } 3962 3963 case PSM_INDEXTOPAGE: 3964 { 3965 LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam); 3966 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3967 return TRUE; 3968 } 3969 3970 case PSM_IDTOINDEX: 3971 { 3972 LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam); 3973 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3974 return TRUE; 3975 } 3976 3977 case PSM_INDEXTOID: 3978 { 3979 LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam); 3980 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3981 return TRUE; 3982 } 3983 3984 case PSM_GETRESULT: 3985 { 3986 LRESULT msgResult = PROPSHEET_GetResult(hwnd); 3987 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3988 return TRUE; 3989 } 3990 3991 case PSM_RECALCPAGESIZES: 3992 { 3993 LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd); 3994 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); 3995 return TRUE; 3996 } 3997 3998 default: 3999 return FALSE; 4000 } 4001 } 4002