4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
9 * - Unicode property sheets
20 #include "debugtools.h"
24 /******************************************************************************
36 typedef struct tagPropPageInfo
38 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
47 typedef struct tagPropSheetInfo
49 LPSTR strPropertiesFor;
52 LPPROPSHEETHEADERA ppshheader;
60 PropPageInfo* proppage;
65 HIMAGELIST hImageList;
74 /******************************************************************************
75 * Defines and global variables
78 const char * PropSheetInfoStr = "PropertySheetInfo";
80 #define MAX_CAPTION_LENGTH 255
81 #define MAX_TABTEXT_LENGTH 255
82 #define MAX_BUTTONTEXT_LENGTH 64
84 /******************************************************************************
87 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
88 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
89 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
90 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
91 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
92 PropSheetInfo * psInfo);
93 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
94 PropSheetInfo * psInfo,
96 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
97 PropSheetInfo * psInfo);
98 static int PROPSHEET_CreatePage(HWND hwndParent, int index,
99 const PropSheetInfo * psInfo,
100 LPCPROPSHEETPAGEA ppshpage);
101 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
102 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
103 static BOOL PROPSHEET_Back(HWND hwndDlg);
104 static BOOL PROPSHEET_Next(HWND hwndDlg);
105 static BOOL PROPSHEET_Finish(HWND hwndDlg);
106 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
107 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
108 static void PROPSHEET_Help(HWND hwndDlg);
109 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
110 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
111 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
112 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
113 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
114 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
115 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
117 HPROPSHEETPAGE hpage);
118 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
119 WPARAM wParam, LPARAM lParam);
120 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
121 HPROPSHEETPAGE hpage);
123 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
125 HPROPSHEETPAGE hpage);
126 static void PROPSHEET_CleanUp();
127 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
128 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
129 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg);
130 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
131 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner);
134 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
136 DEFAULT_DEBUG_CHANNEL(propsheet)
138 /******************************************************************************
139 * PROPSHEET_CollectSheetInfo
141 * Collect relevant data.
143 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
144 PropSheetInfo * psInfo)
146 DWORD dwFlags = lppsh->dwFlags;
148 psInfo->hasHelp = dwFlags & PSH_HASHELP;
149 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
150 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
151 psInfo->isModeless = dwFlags & PSH_MODELESS;
153 psInfo->ppshheader = COMCTL32_Alloc(sizeof(PROPSHEETHEADERA));
154 *psInfo->ppshheader = *lppsh;
156 if (HIWORD(lppsh->pszCaption))
157 psInfo->ppshheader->pszCaption = HEAP_strdupA( GetProcessHeap(),
158 0, lppsh->pszCaption );
160 psInfo->nPages = lppsh->nPages;
162 if (dwFlags & PSH_USEPSTARTPAGE)
164 TRACE("PSH_USEPSTARTPAGE is on");
165 psInfo->active_page = 0;
168 psInfo->active_page = lppsh->u2.nStartPage;
170 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
171 psInfo->active_page = 0;
173 psInfo->restartWindows = FALSE;
174 psInfo->rebootSystem = FALSE;
175 psInfo->hImageList = 0;
176 psInfo->activeValid = FALSE;
181 /******************************************************************************
182 * PROPSHEET_CollectPageInfo
184 * Collect property sheet data.
185 * With code taken from DIALOG_ParseTemplate32.
187 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
188 PropSheetInfo * psInfo,
191 DLGTEMPLATE* pTemplate;
196 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
197 psInfo->proppage[index].hwndPage = 0;
198 psInfo->proppage[index].isDirty = FALSE;
201 * Process property page flags.
203 dwFlags = lppsp->dwFlags;
204 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
205 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
206 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
208 /* as soon as we have a page with the help flag, set the sheet flag on */
209 if (psInfo->proppage[index].hasHelp)
210 psInfo->hasHelp = TRUE;
213 * Process page template.
215 if (dwFlags & PSP_DLGINDIRECT)
216 pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
219 HRSRC hResource = FindResourceA(lppsp->hInstance,
220 lppsp->u1.pszTemplate,
222 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
224 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
228 * Extract the size of the page and the caption.
233 p = (const WORD *)pTemplate;
235 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
237 /* DIALOGEX template */
241 p += 2; /* help ID */
242 p += 2; /* ext style */
247 /* DIALOG template */
250 p += 2; /* ext style */
256 width = (WORD)*p; p++;
257 height = (WORD)*p; p++;
259 /* remember the largest width and height */
260 if (width > psInfo->width)
261 psInfo->width = width;
263 if (height > psInfo->height)
264 psInfo->height = height;
276 p += lstrlenW( (LPCWSTR)p ) + 1;
290 p += lstrlenW( (LPCWSTR)p ) + 1;
294 /* Extract the caption */
295 psInfo->proppage[index].pszText = (LPCWSTR)p;
296 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
297 p += lstrlenW((LPCWSTR)p) + 1;
299 if (dwFlags & PSP_USETITLE)
301 if ( !HIWORD( lppsp->pszTitle ) )
305 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
308 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
312 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
318 * Build the image list for icons
320 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
323 int icon_cx = GetSystemMetrics(SM_CXSMICON);
324 int icon_cy = GetSystemMetrics(SM_CYSMICON);
326 if (dwFlags & PSP_USEICONID)
327 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
328 icon_cx, icon_cy, LR_DEFAULTCOLOR);
330 hIcon = lppsp->u2.hIcon;
334 if (psInfo->hImageList == 0 )
335 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
337 ImageList_AddIcon(psInfo->hImageList, hIcon);
345 /******************************************************************************
346 * PROPSHEET_DoDialogBox
348 * Copied from windows/dialog.c:DIALOG_DoDialogBox
350 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner)
353 DIALOGINFO * dlgInfo;
357 /* Owner must be a top-level window */
358 owner = WIN_GetTopParent( owner );
359 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
360 dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
362 if (!dlgInfo->flags & DF_END) /* was EndDialog called in WM_INITDIALOG ? */
364 EnableWindow( owner, FALSE );
365 ShowWindow( hwnd, SW_SHOW );
366 while (GetMessageA(&msg, 0, 0, 0))
368 if (!PROPSHEET_IsDialogMessage( hwnd, &msg))
370 TranslateMessage( &msg );
371 DispatchMessageA( &msg );
373 if (dlgInfo->flags & DF_END) break;
375 EnableWindow( owner, TRUE );
377 retval = dlgInfo->idResult;
378 WIN_ReleaseWndPtr(wndPtr);
379 DestroyWindow( hwnd );
384 /******************************************************************************
385 * PROPSHEET_CreateDialog
387 * Creates the actual property sheet.
389 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
396 WORD resID = IDD_PROPSHEET;
398 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
401 if(!(hRes = FindResourceA(COMCTL32_hModule,
402 MAKEINTRESOURCEA(resID),
406 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
410 * Make a copy of the dialog template.
412 resSize = SizeofResource(COMCTL32_hModule, hRes);
414 temp = COMCTL32_Alloc(resSize);
419 memcpy(temp, template, resSize);
421 if (psInfo->useCallback)
422 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
424 ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
425 (LPDLGTEMPLATEA) temp,
426 psInfo->ppshheader->hwndParent,
427 (DLGPROC) PROPSHEET_DialogProc,
430 if (!(psInfo->ppshheader->dwFlags & PSH_MODELESS))
431 ret = PROPSHEET_DoDialogBox((HWND)ret, psInfo->ppshheader->hwndParent);
438 /******************************************************************************
439 * PROPSHEET_SizeMismatch
441 * Verify that the tab control and the "largest" property sheet page dlg. template
444 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
446 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
447 RECT rcOrigTab, rcPage;
452 GetClientRect(hwndTabCtrl, &rcOrigTab);
453 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
454 rcOrigTab.right, rcOrigTab.bottom);
459 rcPage.left = psInfo->x;
460 rcPage.top = psInfo->y;
461 rcPage.right = psInfo->width;
462 rcPage.bottom = psInfo->height;
464 MapDialogRect(hwndDlg, &rcPage);
465 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
466 rcPage.right, rcPage.bottom);
468 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
470 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
476 /******************************************************************************
477 * PROPSHEET_IsTooSmallWizard
479 * Verify that the default property sheet is big enough.
481 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
483 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
484 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
485 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
487 GetClientRect(hwndDlg, &rcSheetClient);
488 GetWindowRect(hwndDlg, &rcSheetRect);
489 GetWindowRect(hwndLine, &rcLine);
491 /* Remove the space below the sunken line */
492 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
494 /* Remove the buffer zone all around the edge */
495 rcSheetClient.bottom -= (padding.y * 2);
496 rcSheetClient.right -= (padding.x * 2);
501 rcPage.left = psInfo->x;
502 rcPage.top = psInfo->y;
503 rcPage.right = psInfo->width;
504 rcPage.bottom = psInfo->height;
506 MapDialogRect(hwndDlg, &rcPage);
507 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
508 rcPage.right, rcPage.bottom);
510 if (rcPage.right > rcSheetClient.right)
513 if (rcPage.bottom > rcSheetClient.bottom)
519 /******************************************************************************
520 * PROPSHEET_AdjustSize
522 * Resizes the property sheet and the tab control to fit the largest page.
524 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
526 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
527 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
529 int tabOffsetX, tabOffsetY, buttonHeight;
530 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
531 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
532 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
534 /* Get the height of buttons */
535 GetClientRect(hwndButton, &rc);
536 buttonHeight = rc.bottom;
543 rc.right = psInfo->width;
544 rc.bottom = psInfo->height;
546 MapDialogRect(hwndDlg, &rc);
549 * Resize the tab control.
551 GetClientRect(hwndTabCtrl,&tabRect);
553 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
555 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
557 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
558 psInfo->height = MulDiv((rc.bottom - rc.top),8,dlgInfo->yBaseUnit);
561 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
563 rc.right = rc.left + tabRect.right - tabRect.left;
564 psInfo->width = MulDiv((rc.right - rc.left),4,dlgInfo->xBaseUnit);
567 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
569 tabOffsetX = -(rc.left);
570 tabOffsetY = -(rc.top);
574 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
575 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
577 GetClientRect(hwndTabCtrl, &rc);
579 TRACE("tab client rc %d %d %d %d\n",
580 rc.left, rc.top, rc.right, rc.bottom);
582 rc.right += ((padding.x * 2) + tabOffsetX);
583 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
586 * Resize the property sheet.
588 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
589 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
591 WIN_ReleaseWndPtr(wndPtr);
595 /******************************************************************************
596 * PROPSHEET_AdjustSizeWizard
598 * Resizes the property sheet to fit the largest page.
600 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
602 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
603 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
604 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
606 int buttonHeight, lineHeight;
607 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
608 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
609 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
611 /* Get the height of buttons */
612 GetClientRect(hwndButton, &rc);
613 buttonHeight = rc.bottom;
615 GetClientRect(hwndLine, &rc);
616 lineHeight = rc.bottom;
623 rc.right = psInfo->width;
624 rc.bottom = psInfo->height;
626 MapDialogRect(hwndDlg, &rc);
628 GetClientRect(hwndTabCtrl,&tabRect);
630 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
632 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
633 psInfo->height = MulDiv((rc.bottom - rc.top), 8, dlgInfo->yBaseUnit);
636 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
638 rc.right = rc.left + tabRect.right - tabRect.left;
639 psInfo->width = MulDiv((rc.right - rc.left), 4, dlgInfo->xBaseUnit);
642 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
645 rc.right += (padding.x * 2);
646 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
649 * Resize the property sheet.
651 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
652 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
654 WIN_ReleaseWndPtr(wndPtr);
658 /******************************************************************************
659 * PROPSHEET_AdjustButtons
661 * Adjusts the buttons' positions.
663 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
665 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
669 int buttonWidth, buttonHeight;
670 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
672 if (psInfo->hasApply)
679 * Obtain the size of the buttons.
681 GetClientRect(hwndButton, &rcSheet);
682 buttonWidth = rcSheet.right;
683 buttonHeight = rcSheet.bottom;
686 * Get the size of the property sheet.
688 GetClientRect(hwndParent, &rcSheet);
691 * All buttons will be at this y coordinate.
693 y = rcSheet.bottom - (padding.y + buttonHeight);
696 * Position OK button.
698 hwndButton = GetDlgItem(hwndParent, IDOK);
700 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
702 SetWindowPos(hwndButton, 0, x, y, 0, 0,
703 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
706 * Position Cancel button.
708 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
710 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
712 SetWindowPos(hwndButton, 0, x, y, 0, 0,
713 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
716 * Position Apply button.
718 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
720 if (psInfo->hasApply)
723 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
725 x = rcSheet.right - (padding.x + buttonWidth);
727 SetWindowPos(hwndButton, 0, x, y, 0, 0,
728 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
730 EnableWindow(hwndButton, FALSE);
733 ShowWindow(hwndButton, SW_HIDE);
736 * Position Help button.
738 hwndButton = GetDlgItem(hwndParent, IDHELP);
742 x = rcSheet.right - (padding.x + buttonWidth);
744 SetWindowPos(hwndButton, 0, x, y, 0, 0,
745 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
748 ShowWindow(hwndButton, SW_HIDE);
753 /******************************************************************************
754 * PROPSHEET_AdjustButtonsWizard
756 * Adjusts the buttons' positions.
758 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
759 PropSheetInfo* psInfo)
761 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
762 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
766 int buttonWidth, buttonHeight, lineHeight, lineWidth;
767 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
773 * Obtain the size of the buttons.
775 GetClientRect(hwndButton, &rcSheet);
776 buttonWidth = rcSheet.right;
777 buttonHeight = rcSheet.bottom;
779 GetClientRect(hwndLine, &rcSheet);
780 lineHeight = rcSheet.bottom;
783 * Get the size of the property sheet.
785 GetClientRect(hwndParent, &rcSheet);
788 * All buttons will be at this y coordinate.
790 y = rcSheet.bottom - (padding.y + buttonHeight);
793 * Position the Next and the Finish buttons.
795 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
797 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
799 SetWindowPos(hwndButton, 0, x, y, 0, 0,
800 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
802 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
804 SetWindowPos(hwndButton, 0, x, y, 0, 0,
805 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
807 ShowWindow(hwndButton, SW_HIDE);
810 * Position the Back button.
812 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
816 SetWindowPos(hwndButton, 0, x, y, 0, 0,
817 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
820 * Position the Cancel button.
822 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
824 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
826 SetWindowPos(hwndButton, 0, x, y, 0, 0,
827 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
830 * Position Help button.
832 hwndButton = GetDlgItem(hwndParent, IDHELP);
836 x = rcSheet.right - (padding.x + buttonWidth);
838 SetWindowPos(hwndButton, 0, x, y, 0, 0,
839 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
842 ShowWindow(hwndButton, SW_HIDE);
845 * Position and resize the sunken line.
848 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
850 GetClientRect(hwndParent, &rcSheet);
851 lineWidth = rcSheet.right - (padding.x * 2);
853 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
854 SWP_NOZORDER | SWP_NOACTIVATE);
859 /******************************************************************************
860 * PROPSHEET_GetPaddingInfo
862 * Returns the layout information.
864 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
866 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
869 PADDING_INFO padding;
871 GetWindowRect(hwndTab, &rcTab);
876 ScreenToClient(hwndDlg, &tl);
884 /******************************************************************************
885 * PROPSHEET_GetPaddingInfoWizard
887 * Returns the layout information.
888 * Horizontal spacing is the distance between the Cancel and Help buttons.
889 * Vertical spacing is the distance between the line and the buttons.
891 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
893 PADDING_INFO padding;
896 POINT ptHelp, ptCancel, ptLine;
899 hwndControl = GetDlgItem(hwndDlg, IDHELP);
900 GetWindowRect(hwndControl, &rc);
905 ScreenToClient(hwndDlg, &ptHelp);
908 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
909 GetWindowRect(hwndControl, &rc);
911 ptCancel.x = rc.right;
914 ScreenToClient(hwndDlg, &ptCancel);
917 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
918 GetWindowRect(hwndControl, &rc);
921 ptLine.y = rc.bottom;
923 ScreenToClient(hwndDlg, &ptLine);
925 padding.x = ptHelp.x - ptCancel.x;
926 padding.y = ptHelp.y - ptLine.y;
931 /******************************************************************************
932 * PROPSHEET_CreateTabControl
934 * Insert the tabs in the tab control.
936 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
937 PropSheetInfo * psInfo)
939 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
943 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
945 item.mask = TCIF_TEXT;
946 item.pszText = tabtext;
947 item.cchTextMax = MAX_TABTEXT_LENGTH;
949 nTabs = psInfo->nPages;
952 * Set the image list for icons.
954 if (psInfo->hImageList)
956 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
959 for (i = 0; i < nTabs; i++)
961 if ( psInfo->proppage[i].hasIcon )
963 item.mask |= TCIF_IMAGE;
964 item.iImage = iImage++;
968 item.mask &= ~TCIF_IMAGE;
971 WideCharToMultiByte(CP_ACP, 0,
972 (LPCWSTR)psInfo->proppage[i].pszText,
973 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
975 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
981 /******************************************************************************
982 * PROPSHEET_CreatePage
986 static int PROPSHEET_CreatePage(HWND hwndParent,
988 const PropSheetInfo * psInfo,
989 LPCPROPSHEETPAGEA ppshpage)
991 DLGTEMPLATE* pTemplate;
994 PropPageInfo* ppInfo = psInfo->proppage;
995 PADDING_INFO padding;
996 UINT pageWidth,pageHeight;
998 TRACE("index %d\n", index);
1000 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1001 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
1004 HRSRC hResource = FindResourceA(ppshpage->hInstance,
1005 ppshpage->u1.pszTemplate,
1007 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
1008 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1011 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1013 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1014 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1015 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1016 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1017 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1018 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1019 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1023 pTemplate->style |= WS_CHILD | DS_CONTROL;
1024 pTemplate->style &= ~DS_MODALFRAME;
1025 pTemplate->style &= ~WS_CAPTION;
1026 pTemplate->style &= ~WS_SYSMENU;
1027 pTemplate->style &= ~WS_POPUP;
1028 pTemplate->style &= ~WS_DISABLED;
1029 pTemplate->style &= ~WS_VISIBLE;
1032 if (psInfo->proppage[index].useCallback)
1033 (*(ppshpage->pfnCallback))(hwndParent,
1035 (LPPROPSHEETPAGEA)ppshpage);
1037 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1040 ppshpage->pfnDlgProc,
1043 ppInfo[index].hwndPage = hwndPage;
1045 rc.left = psInfo->x;
1047 rc.right = psInfo->width;
1048 rc.bottom = psInfo->height;
1050 MapDialogRect(hwndParent, &rc);
1052 pageWidth = rc.right - rc.left;
1053 pageHeight = rc.bottom - rc.top;
1055 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1056 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
1060 * Ask the Tab control to fit this page in.
1063 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1064 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1065 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1068 SetWindowPos(hwndPage, HWND_TOP,
1069 rc.left + padding.x,
1071 pageWidth, pageHeight, 0);
1076 /******************************************************************************
1077 * PROPSHEET_ShowPage
1079 * Displays or creates the specified page.
1081 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1083 if (index == psInfo->active_page)
1085 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1086 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1090 if (psInfo->proppage[index].hwndPage == 0)
1092 LPCPROPSHEETPAGEA ppshpage;
1095 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1096 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1098 psn.hdr.hwndFrom = hwndDlg;
1099 psn.hdr.code = PSN_SETACTIVE;
1103 /* Send the notification before showing the page. */
1104 SendMessageA(psInfo->proppage[index].hwndPage,
1105 WM_NOTIFY, 0, (LPARAM) &psn);
1108 * TODO: check return value.
1112 if (psInfo->active_page != -1)
1113 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1115 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1117 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1121 /* Synchronize current selection with tab control */
1122 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1123 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1126 psInfo->active_page = index;
1127 psInfo->activeValid = TRUE;
1132 /******************************************************************************
1135 static BOOL PROPSHEET_Back(HWND hwndDlg)
1140 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1143 if (psInfo->active_page < 0)
1146 psn.hdr.code = PSN_WIZBACK;
1147 psn.hdr.hwndFrom = hwndDlg;
1151 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1153 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1156 if (psInfo->active_page > 0)
1158 res = PROPSHEET_CanSetCurSel(hwndDlg);
1161 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1168 /******************************************************************************
1171 static BOOL PROPSHEET_Next(HWND hwndDlg)
1175 LRESULT msgResult = 0;
1176 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1179 if (psInfo->active_page < 0)
1182 psn.hdr.code = PSN_WIZNEXT;
1183 psn.hdr.hwndFrom = hwndDlg;
1187 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1189 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1191 TRACE("msg result %ld\n", msgResult);
1193 if (msgResult == -1)
1196 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1198 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1204 /******************************************************************************
1207 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1211 LRESULT msgResult = 0;
1212 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1215 if (psInfo->active_page < 0)
1218 psn.hdr.code = PSN_WIZFINISH;
1219 psn.hdr.hwndFrom = hwndDlg;
1223 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1225 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1227 TRACE("msg result %ld\n", msgResult);
1232 if (psInfo->isModeless)
1233 psInfo->activeValid = FALSE;
1235 EndDialog(hwndDlg, TRUE);
1240 /******************************************************************************
1243 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1249 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1252 if (psInfo->active_page < 0)
1255 psn.hdr.hwndFrom = hwndDlg;
1261 * Send PSN_KILLACTIVE to the current page.
1263 psn.hdr.code = PSN_KILLACTIVE;
1265 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1267 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1271 * Send PSN_APPLY to all pages.
1273 psn.hdr.code = PSN_APPLY;
1274 psn.lParam = lParam;
1276 for (i = 0; i < psInfo->nPages; i++)
1278 hwndPage = psInfo->proppage[i].hwndPage;
1281 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1282 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1289 psInfo->activeValid = FALSE;
1291 else if(psInfo->active_page >= 0)
1293 psn.hdr.code = PSN_SETACTIVE;
1295 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1296 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1302 /******************************************************************************
1305 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1307 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1313 if (psInfo->active_page < 0)
1316 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1317 psn.hdr.code = PSN_QUERYCANCEL;
1318 psn.hdr.hwndFrom = hwndDlg;
1322 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1325 psn.hdr.code = PSN_RESET;
1326 psn.lParam = lParam;
1328 for (i = 0; i < psInfo->nPages; i++)
1330 hwndPage = psInfo->proppage[i].hwndPage;
1333 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1336 if (psInfo->isModeless)
1338 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1339 psInfo->activeValid = FALSE;
1342 EndDialog(hwndDlg, FALSE);
1345 /******************************************************************************
1348 static void PROPSHEET_Help(HWND hwndDlg)
1350 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1355 if (psInfo->active_page < 0)
1358 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1359 psn.hdr.code = PSN_HELP;
1360 psn.hdr.hwndFrom = hwndDlg;
1364 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1367 /******************************************************************************
1370 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1373 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1376 if (!psInfo) return;
1378 * Set the dirty flag of this page.
1380 for (i = 0; i < psInfo->nPages; i++)
1382 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1383 psInfo->proppage[i].isDirty = TRUE;
1387 * Enable the Apply button.
1389 if (psInfo->hasApply)
1391 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1393 EnableWindow(hwndApplyBtn, TRUE);
1397 /******************************************************************************
1398 * PROPSHEET_UnChanged
1400 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1403 BOOL noPageDirty = TRUE;
1404 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1405 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1408 if ( !psInfo ) return;
1409 for (i = 0; i < psInfo->nPages; i++)
1411 /* set the specified page as clean */
1412 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1413 psInfo->proppage[i].isDirty = FALSE;
1415 /* look to see if there's any dirty pages */
1416 if (psInfo->proppage[i].isDirty)
1417 noPageDirty = FALSE;
1421 * Disable Apply button.
1424 EnableWindow(hwndApplyBtn, FALSE);
1427 /******************************************************************************
1428 * PROPSHEET_PressButton
1430 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1434 case PSBTN_APPLYNOW:
1435 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1438 PROPSHEET_Back(hwndDlg);
1441 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1444 PROPSHEET_Finish(hwndDlg);
1447 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1450 PROPSHEET_Next(hwndDlg);
1453 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1456 FIXME("Invalid button index %d\n", buttonID);
1461 /*************************************************************************
1462 * BOOL PROPSHEET_CanSetCurSel [Internal]
1464 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1467 * hwndDlg [I] handle to a Dialog hWnd
1470 * TRUE if Current Selection can change
1474 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1476 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1484 if (psInfo->active_page < 0)
1488 * Notify the current page.
1490 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1491 psn.hdr.code = PSN_KILLACTIVE;
1492 psn.hdr.hwndFrom = hwndDlg;
1496 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1499 /******************************************************************************
1500 * PROPSHEET_SetCurSel
1502 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1504 HPROPSHEETPAGE hpage)
1506 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1509 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1511 /* hpage takes precedence over index */
1513 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1515 if (index < 0 || index >= psInfo->nPages)
1517 TRACE("Could not find page to select!\n");
1521 hwndPage = psInfo->proppage[index].hwndPage;
1524 * Notify the new page if it's already created.
1525 * If not it will get created and notified in PROPSHEET_ShowPage.
1532 psn.hdr.code = PSN_SETACTIVE;
1533 psn.hdr.hwndFrom = hwndDlg;
1537 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1540 * TODO: check return value.
1545 * Display the new page.
1547 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1549 if (psInfo->proppage[index].hasHelp)
1550 EnableWindow(hwndHelp, TRUE);
1552 EnableWindow(hwndHelp, FALSE);
1557 /******************************************************************************
1558 * PROPSHEET_SetTitleA
1560 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1562 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1565 if (HIWORD(lpszText) == 0) {
1566 if (!LoadStringA(psInfo->ppshheader->hInstance,
1567 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1571 if (dwStyle & PSH_PROPTITLE)
1574 int lentitle = strlen(lpszText);
1575 int lenprop = strlen(psInfo->strPropertiesFor);
1577 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1578 strcpy(dest, psInfo->strPropertiesFor);
1579 strcat(dest, lpszText);
1581 SetWindowTextA(hwndDlg, dest);
1582 COMCTL32_Free(dest);
1585 SetWindowTextA(hwndDlg, lpszText);
1588 /******************************************************************************
1589 * PROPSHEET_SetFinishTextA
1591 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1593 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1595 /* Set text, show and enable the Finish button */
1596 SetWindowTextA(hwndButton, lpszText);
1597 ShowWindow(hwndButton, SW_SHOW);
1598 EnableWindow(hwndButton, TRUE);
1600 /* Make it default pushbutton */
1601 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1603 /* Hide Back button */
1604 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1605 ShowWindow(hwndButton, SW_HIDE);
1607 /* Hide Next button */
1608 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1609 ShowWindow(hwndButton, SW_HIDE);
1612 /******************************************************************************
1613 * PROPSHEET_QuerySiblings
1615 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1616 WPARAM wParam, LPARAM lParam)
1620 LRESULT msgResult = 0;
1621 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1624 while ((i < psInfo->nPages) && (msgResult == 0))
1626 hwndPage = psInfo->proppage[i].hwndPage;
1627 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1635 /******************************************************************************
1638 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1639 HPROPSHEETPAGE hpage)
1641 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1643 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1645 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1646 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1649 * Allocate and fill in a new PropPageInfo entry.
1651 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1652 sizeof(PropPageInfo) *
1653 (psInfo->nPages + 1));
1654 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1657 psInfo->proppage[psInfo->nPages].hpage = hpage;
1659 if (ppsp->dwFlags & PSP_PREMATURE)
1661 /* Create the page but don't show it */
1662 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1666 * Add a new tab to the tab control.
1668 item.mask = TCIF_TEXT;
1669 item.pszText = tabtext;
1670 item.cchTextMax = MAX_TABTEXT_LENGTH;
1672 WideCharToMultiByte(CP_ACP, 0,
1673 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1674 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1676 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1681 /* If it is the only page - show it */
1682 if(psInfo->nPages == 1)
1683 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1688 /******************************************************************************
1689 * PROPSHEET_RemovePage
1691 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1693 HPROPSHEETPAGE hpage)
1695 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1697 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1698 PropPageInfo* oldPages;
1703 oldPages = psInfo->proppage;
1705 * hpage takes precedence over index.
1709 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1712 /* Make shure that index is within range */
1713 if (index < 0 || index >= psInfo->nPages)
1715 TRACE("Could not find page to remove!\n");
1719 TRACE("total pages %d removing page %d active page %d\n",
1720 psInfo->nPages, index, psInfo->active_page);
1722 * Check if we're removing the active page.
1724 if (index == psInfo->active_page)
1726 if (psInfo->nPages > 1)
1730 /* activate previous page */
1731 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1735 /* activate the next page */
1736 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1741 psInfo->active_page = -1;
1742 if (!psInfo->isModeless)
1744 EndDialog(hwndDlg, FALSE);
1749 else if (index < psInfo->active_page)
1750 psInfo->active_page--;
1752 /* Destroy page dialog window */
1753 DestroyWindow(psInfo->proppage[index].hwndPage);
1755 /* Free page resources */
1756 if(psInfo->proppage[index].hpage)
1758 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1760 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1761 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1763 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1766 /* Remove the tab */
1767 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1770 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1773 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1775 if (index < psInfo->nPages)
1776 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1777 (psInfo->nPages - index) * sizeof(PropPageInfo));
1779 COMCTL32_Free(oldPages);
1784 /******************************************************************************
1785 * PROPSHEET_SetWizButtons
1787 * This code will work if (and assumes that) the Next button is on top of the
1788 * Finish button. ie. Finish comes after Next in the Z order.
1789 * This means make sure the dialog template reflects this.
1792 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1794 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1795 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1796 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1798 TRACE("%ld\n", dwFlags);
1800 EnableWindow(hwndBack, FALSE);
1801 EnableWindow(hwndNext, FALSE);
1802 EnableWindow(hwndFinish, FALSE);
1804 if (dwFlags & PSWIZB_BACK)
1805 EnableWindow(hwndBack, TRUE);
1807 if (dwFlags & PSWIZB_NEXT)
1809 /* Hide the Finish button */
1810 ShowWindow(hwndFinish, SW_HIDE);
1812 /* Show and enable the Next button */
1813 ShowWindow(hwndNext, SW_SHOW);
1814 EnableWindow(hwndNext, TRUE);
1816 /* Set the Next button as the default pushbutton */
1817 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1820 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1822 /* Hide the Next button */
1823 ShowWindow(hwndNext, SW_HIDE);
1825 /* Show the Finish button */
1826 ShowWindow(hwndFinish, SW_SHOW);
1828 if (dwFlags & PSWIZB_FINISH)
1829 EnableWindow(hwndFinish, TRUE);
1831 /* Set the Finish button as the default pushbutton */
1832 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1836 /******************************************************************************
1837 * PROPSHEET_GetPageIndex
1839 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1840 * the array of PropPageInfo.
1842 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1847 while ((index < psInfo->nPages) && (found == FALSE))
1849 if (psInfo->proppage[index].hpage == hpage)
1861 /******************************************************************************
1864 static void PROPSHEET_CleanUp(HWND hwndDlg)
1867 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1871 if (HIWORD(psInfo->ppshheader->pszCaption))
1872 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader->pszCaption);
1874 COMCTL32_Free((LPVOID)psInfo->ppshheader);
1876 for (i = 0; i < psInfo->nPages; i++)
1878 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1880 if(psInfo->proppage[i].hwndPage)
1881 DestroyWindow(psInfo->proppage[i].hwndPage);
1885 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1886 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1888 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1892 COMCTL32_Free(psInfo->proppage);
1893 COMCTL32_Free(psInfo->strPropertiesFor);
1894 ImageList_Destroy(psInfo->hImageList);
1896 GlobalFree((HGLOBAL)psInfo);
1899 /******************************************************************************
1900 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1902 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1905 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1906 sizeof(PropSheetInfo));
1910 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1912 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1914 pByte = (BYTE*) psInfo->ppshheader->u3.ppsp;
1916 for (n = i = 0; i < lppsh->nPages; i++, n++)
1918 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1919 psInfo->proppage[n].hpage = psInfo->ppshheader->u3.phpage[i];
1922 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1923 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1926 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1929 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1930 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1936 bRet = PROPSHEET_CreateDialog(psInfo);
1941 /******************************************************************************
1942 * PropertySheet32W (COMCTL32.85)
1944 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1946 FIXME("(%p): stub\n", propertySheetHeader);
1951 /******************************************************************************
1952 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1954 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1955 LPCPROPSHEETPAGEA lpPropSheetPage)
1957 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1959 *ppsp = *lpPropSheetPage;
1961 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u1.pszTemplate ) )
1962 ppsp->u1.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u1.pszTemplate );
1964 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1965 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
1968 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1969 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
1970 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1971 ppsp->pszTitle = NULL;
1973 return (HPROPSHEETPAGE)ppsp;
1976 /******************************************************************************
1977 * CreatePropertySheetPageW (COMCTL32.20)
1979 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1981 FIXME("(%p): stub\n", lpPropSheetPage);
1986 /******************************************************************************
1987 * DestroyPropertySheetPage (COMCTL32.24)
1989 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1991 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
1996 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u1.pszTemplate ) )
1997 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u1.pszTemplate);
1999 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2000 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2002 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2003 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2005 COMCTL32_Free(hPropPage);
2010 /******************************************************************************
2011 * PROPSHEET_IsDialogMessage
2013 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2015 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2017 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2020 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2023 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2025 if (!(dlgCode & DLGC_WANTMESSAGE))
2027 switch (lpMsg->wParam)
2030 if (GetKeyState(VK_SHIFT) & 0x8000)
2036 case VK_NEXT: new_page = 1; break;
2037 case VK_PRIOR: new_page = -1; break;
2043 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2045 new_page += psInfo->active_page;
2048 new_page = psInfo->nPages - 1;
2049 else if (new_page >= psInfo->nPages)
2052 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2059 return IsDialogMessageA(hwnd, lpMsg);
2062 /******************************************************************************
2063 * PROPSHEET_DialogProc
2066 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2072 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2073 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2074 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2075 LPCPROPSHEETPAGEA ppshpage;
2078 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2081 * Small icon in the title bar.
2083 if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
2084 (psInfo->ppshheader->dwFlags & PSH_USEHICON))
2087 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2088 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2090 if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
2091 hIcon = LoadImageA(psInfo->ppshheader->hInstance,
2092 psInfo->ppshheader->u1.pszIcon,
2097 hIcon = psInfo->ppshheader->u1.hIcon;
2099 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2102 if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
2103 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->u1.hIcon);
2105 psInfo->strPropertiesFor = strCaption;
2107 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2109 PROPSHEET_CreateTabControl(hwnd, psInfo);
2111 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
2113 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2115 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2116 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2121 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2123 PROPSHEET_AdjustSize(hwnd, psInfo);
2124 PROPSHEET_AdjustButtons(hwnd, psInfo);
2128 if (psInfo->useCallback)
2129 (*(psInfo->ppshheader->pfnCallback))(hwnd,
2130 PSCB_INITIALIZED, (LPARAM)0);
2132 idx = psInfo->active_page;
2133 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2134 psInfo->active_page = -1;
2136 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2138 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
2139 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2141 if (!HIWORD(psInfo->ppshheader->pszCaption) &&
2142 psInfo->ppshheader->hInstance)
2146 if (LoadStringA(psInfo->ppshheader->hInstance,
2147 (UINT)psInfo->ppshheader->pszCaption, szText, 255))
2148 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags, szText);
2152 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags,
2153 psInfo->ppshheader->pszCaption);
2160 PROPSHEET_CleanUp(hwnd);
2164 PROPSHEET_Cancel(hwnd, 1);
2169 WORD wID = LOWORD(wParam);
2174 case IDC_APPLY_BUTTON:
2176 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2178 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2183 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2187 if (psInfo->restartWindows)
2188 result = ID_PSRESTARTWINDOWS;
2190 /* reboot system takes precedence over restart windows */
2191 if (psInfo->rebootSystem)
2192 result = ID_PSREBOOTSYSTEM;
2194 if (psInfo->isModeless)
2195 psInfo->activeValid = FALSE;
2197 EndDialog(hwnd, result);
2200 EnableWindow(hwndApplyBtn, FALSE);
2205 case IDC_BACK_BUTTON:
2206 PROPSHEET_Back(hwnd);
2209 case IDC_NEXT_BUTTON:
2210 PROPSHEET_Next(hwnd);
2213 case IDC_FINISH_BUTTON:
2214 PROPSHEET_Finish(hwnd);
2218 PROPSHEET_Cancel(hwnd, 0);
2222 PROPSHEET_Help(hwnd);
2231 NMHDR* pnmh = (LPNMHDR) lParam;
2233 if (pnmh->code == TCN_SELCHANGE)
2235 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2236 PROPSHEET_SetCurSel(hwnd, index, 0);
2239 if(pnmh->code == TCN_SELCHANGING)
2241 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2242 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2250 case PSM_GETCURRENTPAGEHWND:
2252 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2256 if (psInfo->activeValid && psInfo->active_page != -1)
2257 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2259 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2265 PROPSHEET_Changed(hwnd, (HWND)wParam);
2269 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2272 case PSM_GETTABCONTROL:
2274 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2276 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2285 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2286 if(msgResult != FALSE)
2288 msgResult = PROPSHEET_SetCurSel(hwnd,
2290 (HPROPSHEETPAGE)lParam);
2293 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2298 case PSM_CANCELTOCLOSE:
2300 char buf[MAX_BUTTONTEXT_LENGTH];
2301 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2302 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2304 EnableWindow(hwndCancel, FALSE);
2305 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2306 SetWindowTextA(hwndOK, buf);
2311 case PSM_RESTARTWINDOWS:
2313 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2316 psInfo->restartWindows = TRUE;
2320 case PSM_REBOOTSYSTEM:
2322 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2325 psInfo->rebootSystem = TRUE;
2330 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2335 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2337 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2342 case PSM_QUERYSIBLINGS:
2344 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2346 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2354 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2355 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2356 * on success or FALSE otherwise, as specified on MSDN Online.
2357 * Also see the MFC code for
2358 * CPropertySheet::AddPage(CPropertyPage* pPage).
2361 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2363 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2368 case PSM_REMOVEPAGE:
2369 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2372 case PSM_ISDIALOGMESSAGE:
2374 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2375 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2379 case PSM_PRESSBUTTON:
2380 PROPSHEET_PressButton(hwnd, (int)wParam);
2383 case PSM_SETFINISHTEXTA:
2384 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2387 case PSM_SETWIZBUTTONS:
2388 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2392 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2394 case PSM_SETCURSELID:
2395 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2397 case PSM_SETFINISHTEXTW:
2398 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");