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_IsTooSmall(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.
230 p = (const WORD *)pTemplate;
232 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
234 /* DIALOGEX template */
238 p += 2; /* help ID */
239 p += 2; /* ext style */
244 /* DIALOG template */
247 p += 2; /* ext style */
253 width = (WORD)*p; p++;
254 height = (WORD)*p; p++;
256 /* remember the largest width and height */
257 if (width > psInfo->width)
258 psInfo->width = width;
260 if (height > psInfo->height)
261 psInfo->height = height;
273 p += lstrlenW( (LPCWSTR)p ) + 1;
287 p += lstrlenW( (LPCWSTR)p ) + 1;
291 /* Extract the caption */
292 psInfo->proppage[index].pszText = (LPCWSTR)p;
293 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
294 p += lstrlenW((LPCWSTR)p) + 1;
296 if (dwFlags & PSP_USETITLE)
298 if ( !HIWORD( lppsp->pszTitle ) )
302 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
305 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
309 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
315 * Build the image list for icons
317 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
320 int icon_cx = GetSystemMetrics(SM_CXSMICON);
321 int icon_cy = GetSystemMetrics(SM_CYSMICON);
323 if (dwFlags & PSP_USEICONID)
324 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
325 icon_cx, icon_cy, LR_DEFAULTCOLOR);
327 hIcon = lppsp->u2.hIcon;
331 if (psInfo->hImageList == 0 )
332 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
334 ImageList_AddIcon(psInfo->hImageList, hIcon);
342 /******************************************************************************
343 * PROPSHEET_DoDialogBox
345 * Copied from windows/dialog.c:DIALOG_DoDialogBox
347 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner)
350 DIALOGINFO * dlgInfo;
354 /* Owner must be a top-level window */
355 owner = WIN_GetTopParent( owner );
356 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
357 dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
359 if (!dlgInfo->flags & DF_END) /* was EndDialog called in WM_INITDIALOG ? */
361 EnableWindow( owner, FALSE );
362 ShowWindow( hwnd, SW_SHOW );
363 while (GetMessageA(&msg, 0, 0, 0))
365 if (!PROPSHEET_IsDialogMessage( hwnd, &msg))
367 TranslateMessage( &msg );
368 DispatchMessageA( &msg );
370 if (dlgInfo->flags & DF_END) break;
372 EnableWindow( owner, TRUE );
374 retval = dlgInfo->idResult;
375 WIN_ReleaseWndPtr(wndPtr);
376 DestroyWindow( hwnd );
381 /******************************************************************************
382 * PROPSHEET_CreateDialog
384 * Creates the actual property sheet.
386 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
393 WORD resID = IDD_PROPSHEET;
395 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
398 if(!(hRes = FindResourceA(COMCTL32_hModule,
399 MAKEINTRESOURCEA(resID),
403 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
407 * Make a copy of the dialog template.
409 resSize = SizeofResource(COMCTL32_hModule, hRes);
411 temp = COMCTL32_Alloc(resSize);
416 memcpy(temp, template, resSize);
418 if (psInfo->useCallback)
419 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
421 ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
422 (LPDLGTEMPLATEA) temp,
423 psInfo->ppshheader->hwndParent,
424 (DLGPROC) PROPSHEET_DialogProc,
427 if (!(psInfo->ppshheader->dwFlags & PSH_MODELESS))
428 ret = PROPSHEET_DoDialogBox((HWND)ret, psInfo->ppshheader->hwndParent);
435 /******************************************************************************
436 * PROPSHEET_IsTooSmall
438 * Verify that the resource property sheet is big enough.
440 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
442 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
443 RECT rcOrigTab, rcPage;
448 GetClientRect(hwndTabCtrl, &rcOrigTab);
449 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
450 rcOrigTab.right, rcOrigTab.bottom);
455 rcPage.left = psInfo->x;
456 rcPage.top = psInfo->y;
457 rcPage.right = psInfo->width;
458 rcPage.bottom = psInfo->height;
460 MapDialogRect(hwndDlg, &rcPage);
461 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
462 rcPage.right, rcPage.bottom);
464 if (rcPage.right > rcOrigTab.right)
467 if (rcPage.bottom > rcOrigTab.bottom)
473 /******************************************************************************
474 * PROPSHEET_IsTooSmallWizard
476 * Verify that the default property sheet is big enough.
478 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
480 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
481 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
482 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
484 GetClientRect(hwndDlg, &rcSheetClient);
485 GetWindowRect(hwndDlg, &rcSheetRect);
486 GetWindowRect(hwndLine, &rcLine);
488 /* Remove the space below the sunken line */
489 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
491 /* Remove the buffer zone all around the edge */
492 rcSheetClient.bottom -= (padding.y * 2);
493 rcSheetClient.right -= (padding.x * 2);
498 rcPage.left = psInfo->x;
499 rcPage.top = psInfo->y;
500 rcPage.right = psInfo->width;
501 rcPage.bottom = psInfo->height;
503 MapDialogRect(hwndDlg, &rcPage);
504 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
505 rcPage.right, rcPage.bottom);
507 if (rcPage.right > rcSheetClient.right)
510 if (rcPage.bottom > rcSheetClient.bottom)
516 /******************************************************************************
517 * PROPSHEET_AdjustSize
519 * Resizes the property sheet and the tab control to fit the largest page.
521 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
523 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
524 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
526 int tabOffsetX, tabOffsetY, buttonHeight;
527 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
529 /* Get the height of buttons */
530 GetClientRect(hwndButton, &rc);
531 buttonHeight = rc.bottom;
538 rc.right = psInfo->width;
539 rc.bottom = psInfo->height;
541 MapDialogRect(hwndDlg, &rc);
544 * Resize the tab control.
546 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
548 tabOffsetX = -(rc.left);
549 tabOffsetY = -(rc.top);
553 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
554 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
556 GetClientRect(hwndTabCtrl, &rc);
558 TRACE("tab client rc %d %d %d %d\n",
559 rc.left, rc.top, rc.right, rc.bottom);
561 rc.right += ((padding.x * 2) + tabOffsetX);
562 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
565 * Resize the property sheet.
567 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
568 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
573 /******************************************************************************
574 * PROPSHEET_AdjustSizeWizard
576 * Resizes the property sheet to fit the largest page.
578 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
580 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
581 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
583 int buttonHeight, lineHeight;
584 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
586 /* Get the height of buttons */
587 GetClientRect(hwndButton, &rc);
588 buttonHeight = rc.bottom;
590 GetClientRect(hwndLine, &rc);
591 lineHeight = rc.bottom;
598 rc.right = psInfo->width;
599 rc.bottom = psInfo->height;
601 MapDialogRect(hwndDlg, &rc);
603 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
606 rc.right += (padding.x * 2);
607 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
610 * Resize the property sheet.
612 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
613 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
618 /******************************************************************************
619 * PROPSHEET_AdjustButtons
621 * Adjusts the buttons' positions.
623 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
625 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
629 int buttonWidth, buttonHeight;
630 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
632 if (psInfo->hasApply)
639 * Obtain the size of the buttons.
641 GetClientRect(hwndButton, &rcSheet);
642 buttonWidth = rcSheet.right;
643 buttonHeight = rcSheet.bottom;
646 * Get the size of the property sheet.
648 GetClientRect(hwndParent, &rcSheet);
651 * All buttons will be at this y coordinate.
653 y = rcSheet.bottom - (padding.y + buttonHeight);
656 * Position OK button.
658 hwndButton = GetDlgItem(hwndParent, IDOK);
660 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
662 SetWindowPos(hwndButton, 0, x, y, 0, 0,
663 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
666 * Position Cancel button.
668 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
670 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
672 SetWindowPos(hwndButton, 0, x, y, 0, 0,
673 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
676 * Position Apply button.
678 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
680 if (psInfo->hasApply)
683 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
685 x = rcSheet.right - (padding.x + buttonWidth);
687 SetWindowPos(hwndButton, 0, x, y, 0, 0,
688 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
690 EnableWindow(hwndButton, FALSE);
693 ShowWindow(hwndButton, SW_HIDE);
696 * Position Help button.
698 hwndButton = GetDlgItem(hwndParent, IDHELP);
702 x = rcSheet.right - (padding.x + buttonWidth);
704 SetWindowPos(hwndButton, 0, x, y, 0, 0,
705 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
708 ShowWindow(hwndButton, SW_HIDE);
713 /******************************************************************************
714 * PROPSHEET_AdjustButtonsWizard
716 * Adjusts the buttons' positions.
718 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
719 PropSheetInfo* psInfo)
721 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
722 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
726 int buttonWidth, buttonHeight, lineHeight, lineWidth;
727 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
733 * Obtain the size of the buttons.
735 GetClientRect(hwndButton, &rcSheet);
736 buttonWidth = rcSheet.right;
737 buttonHeight = rcSheet.bottom;
739 GetClientRect(hwndLine, &rcSheet);
740 lineHeight = rcSheet.bottom;
743 * Get the size of the property sheet.
745 GetClientRect(hwndParent, &rcSheet);
748 * All buttons will be at this y coordinate.
750 y = rcSheet.bottom - (padding.y + buttonHeight);
753 * Position the Next and the Finish buttons.
755 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
757 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
759 SetWindowPos(hwndButton, 0, x, y, 0, 0,
760 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
762 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
764 SetWindowPos(hwndButton, 0, x, y, 0, 0,
765 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
767 ShowWindow(hwndButton, SW_HIDE);
770 * Position the Back button.
772 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
776 SetWindowPos(hwndButton, 0, x, y, 0, 0,
777 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
780 * Position the Cancel button.
782 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
784 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
786 SetWindowPos(hwndButton, 0, x, y, 0, 0,
787 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
790 * Position Help button.
792 hwndButton = GetDlgItem(hwndParent, IDHELP);
796 x = rcSheet.right - (padding.x + buttonWidth);
798 SetWindowPos(hwndButton, 0, x, y, 0, 0,
799 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
802 ShowWindow(hwndButton, SW_HIDE);
805 * Position and resize the sunken line.
808 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
810 GetClientRect(hwndParent, &rcSheet);
811 lineWidth = rcSheet.right - (padding.x * 2);
813 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
814 SWP_NOZORDER | SWP_NOACTIVATE);
819 /******************************************************************************
820 * PROPSHEET_GetPaddingInfo
822 * Returns the layout information.
824 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
826 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
829 PADDING_INFO padding;
831 GetWindowRect(hwndTab, &rcTab);
836 ScreenToClient(hwndDlg, &tl);
844 /******************************************************************************
845 * PROPSHEET_GetPaddingInfoWizard
847 * Returns the layout information.
848 * Horizontal spacing is the distance between the Cancel and Help buttons.
849 * Vertical spacing is the distance between the line and the buttons.
851 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
853 PADDING_INFO padding;
856 POINT ptHelp, ptCancel, ptLine;
859 hwndControl = GetDlgItem(hwndDlg, IDHELP);
860 GetWindowRect(hwndControl, &rc);
865 ScreenToClient(hwndDlg, &ptHelp);
868 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
869 GetWindowRect(hwndControl, &rc);
871 ptCancel.x = rc.right;
874 ScreenToClient(hwndDlg, &ptCancel);
877 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
878 GetWindowRect(hwndControl, &rc);
881 ptLine.y = rc.bottom;
883 ScreenToClient(hwndDlg, &ptLine);
885 padding.x = ptHelp.x - ptCancel.x;
886 padding.y = ptHelp.y - ptLine.y;
891 /******************************************************************************
892 * PROPSHEET_CreateTabControl
894 * Insert the tabs in the tab control.
896 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
897 PropSheetInfo * psInfo)
899 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
903 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
905 item.mask = TCIF_TEXT;
906 item.pszText = tabtext;
907 item.cchTextMax = MAX_TABTEXT_LENGTH;
909 nTabs = psInfo->ppshheader->nPages;
912 * Set the image list for icons.
914 if (psInfo->hImageList)
916 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
919 for (i = 0; i < nTabs; i++)
921 if ( psInfo->proppage[i].hasIcon )
923 item.mask |= TCIF_IMAGE;
924 item.iImage = iImage++;
928 item.mask &= ~TCIF_IMAGE;
931 WideCharToMultiByte(CP_ACP, 0,
932 (LPCWSTR)psInfo->proppage[i].pszText,
933 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
935 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
941 /******************************************************************************
942 * PROPSHEET_CreatePage
946 static int PROPSHEET_CreatePage(HWND hwndParent,
948 const PropSheetInfo * psInfo,
949 LPCPROPSHEETPAGEA ppshpage)
951 DLGTEMPLATE* pTemplate;
954 PropPageInfo* ppInfo = psInfo->proppage;
955 PADDING_INFO padding;
957 TRACE("index %d\n", index);
959 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
960 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
963 HRSRC hResource = FindResourceA(ppshpage->hInstance,
964 ppshpage->u1.pszTemplate,
966 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
967 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
970 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
972 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
973 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
974 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
975 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
976 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
977 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
978 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
982 pTemplate->style |= WS_CHILD | DS_CONTROL;
983 pTemplate->style &= ~DS_MODALFRAME;
984 pTemplate->style &= ~WS_CAPTION;
985 pTemplate->style &= ~WS_SYSMENU;
986 pTemplate->style &= ~WS_POPUP;
987 pTemplate->style &= ~WS_DISABLED;
988 pTemplate->style &= ~WS_VISIBLE;
991 if (psInfo->proppage[index].useCallback)
992 (*(ppshpage->pfnCallback))(hwndParent,
994 (LPPROPSHEETPAGEA)ppshpage);
996 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
999 ppshpage->pfnDlgProc,
1002 ppInfo[index].hwndPage = hwndPage;
1004 rc.left = psInfo->x;
1006 rc.right = psInfo->width;
1007 rc.bottom = psInfo->height;
1009 MapDialogRect(hwndParent, &rc);
1011 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1012 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
1016 * Ask the Tab control to fit this page in.
1019 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1020 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1021 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1024 SetWindowPos(hwndPage, HWND_TOP,
1025 rc.left + padding.x,
1032 /******************************************************************************
1033 * PROPSHEET_ShowPage
1035 * Displays or creates the specified page.
1037 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1039 if (index == psInfo->active_page)
1041 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1042 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1046 if (psInfo->active_page != -1)
1047 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1049 if (psInfo->proppage[index].hwndPage == 0)
1051 LPCPROPSHEETPAGEA ppshpage;
1054 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1055 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1057 psn.hdr.hwndFrom = hwndDlg;
1058 psn.hdr.code = PSN_SETACTIVE;
1062 /* Send the notification before showing the page. */
1063 SendMessageA(psInfo->proppage[index].hwndPage,
1064 WM_NOTIFY, 0, (LPARAM) &psn);
1067 * TODO: check return value.
1071 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1073 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1077 /* Synchronize current selection with tab control */
1078 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1079 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1082 psInfo->active_page = index;
1083 psInfo->activeValid = TRUE;
1088 /******************************************************************************
1091 static BOOL PROPSHEET_Back(HWND hwndDlg)
1096 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1099 if (psInfo->active_page < 0)
1102 psn.hdr.code = PSN_WIZBACK;
1103 psn.hdr.hwndFrom = hwndDlg;
1107 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1109 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1112 if (psInfo->active_page > 0)
1114 res = PROPSHEET_CanSetCurSel(hwndDlg);
1117 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1124 /******************************************************************************
1127 static BOOL PROPSHEET_Next(HWND hwndDlg)
1131 LRESULT msgResult = 0;
1132 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1135 if (psInfo->active_page < 0)
1138 psn.hdr.code = PSN_WIZNEXT;
1139 psn.hdr.hwndFrom = hwndDlg;
1143 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1145 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1147 TRACE("msg result %ld\n", msgResult);
1149 if (msgResult == -1)
1152 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1154 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1160 /******************************************************************************
1163 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1167 LRESULT msgResult = 0;
1168 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1171 if (psInfo->active_page < 0)
1174 psn.hdr.code = PSN_WIZFINISH;
1175 psn.hdr.hwndFrom = hwndDlg;
1179 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1181 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1183 TRACE("msg result %ld\n", msgResult);
1188 if (psInfo->isModeless)
1189 psInfo->activeValid = FALSE;
1191 EndDialog(hwndDlg, TRUE);
1196 /******************************************************************************
1199 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1205 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1208 if (psInfo->active_page < 0)
1211 psn.hdr.hwndFrom = hwndDlg;
1217 * Send PSN_KILLACTIVE to the current page.
1219 psn.hdr.code = PSN_KILLACTIVE;
1221 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1223 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1227 * Send PSN_APPLY to all pages.
1229 psn.hdr.code = PSN_APPLY;
1230 psn.lParam = lParam;
1232 for (i = 0; i < psInfo->nPages; i++)
1234 hwndPage = psInfo->proppage[i].hwndPage;
1237 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1238 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1245 psInfo->activeValid = FALSE;
1247 else if(psInfo->active_page >= 0)
1249 psn.hdr.code = PSN_SETACTIVE;
1251 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1252 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1258 /******************************************************************************
1261 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1263 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1269 if (psInfo->active_page < 0)
1272 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1273 psn.hdr.code = PSN_QUERYCANCEL;
1274 psn.hdr.hwndFrom = hwndDlg;
1278 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1281 psn.hdr.code = PSN_RESET;
1282 psn.lParam = lParam;
1284 for (i = 0; i < psInfo->nPages; i++)
1286 hwndPage = psInfo->proppage[i].hwndPage;
1289 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1292 if (psInfo->isModeless)
1294 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1295 psInfo->activeValid = FALSE;
1298 EndDialog(hwndDlg, FALSE);
1301 /******************************************************************************
1304 static void PROPSHEET_Help(HWND hwndDlg)
1306 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1311 if (psInfo->active_page < 0)
1314 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1315 psn.hdr.code = PSN_HELP;
1316 psn.hdr.hwndFrom = hwndDlg;
1320 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1323 /******************************************************************************
1326 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1329 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1332 if (!psInfo) return;
1334 * Set the dirty flag of this page.
1336 for (i = 0; i < psInfo->nPages; i++)
1338 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1339 psInfo->proppage[i].isDirty = TRUE;
1343 * Enable the Apply button.
1345 if (psInfo->hasApply)
1347 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1349 EnableWindow(hwndApplyBtn, TRUE);
1353 /******************************************************************************
1354 * PROPSHEET_UnChanged
1356 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1359 BOOL noPageDirty = TRUE;
1360 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1361 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1364 if ( !psInfo ) return;
1365 for (i = 0; i < psInfo->nPages; i++)
1367 /* set the specified page as clean */
1368 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1369 psInfo->proppage[i].isDirty = FALSE;
1371 /* look to see if there's any dirty pages */
1372 if (psInfo->proppage[i].isDirty)
1373 noPageDirty = FALSE;
1377 * Disable Apply button.
1380 EnableWindow(hwndApplyBtn, FALSE);
1383 /******************************************************************************
1384 * PROPSHEET_PressButton
1386 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1390 case PSBTN_APPLYNOW:
1391 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1394 PROPSHEET_Back(hwndDlg);
1397 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1400 PROPSHEET_Finish(hwndDlg);
1403 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1406 PROPSHEET_Next(hwndDlg);
1409 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1412 FIXME("Invalid button index %d\n", buttonID);
1417 /*************************************************************************
1418 * BOOL PROPSHEET_CanSetCurSel [Internal]
1420 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1423 * hwndDlg [I] handle to a Dialog hWnd
1426 * TRUE if Current Selection can change
1430 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1432 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1440 if (psInfo->active_page < 0)
1444 * Notify the current page.
1446 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1447 psn.hdr.code = PSN_KILLACTIVE;
1448 psn.hdr.hwndFrom = hwndDlg;
1452 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1455 /******************************************************************************
1456 * PROPSHEET_SetCurSel
1458 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1460 HPROPSHEETPAGE hpage)
1462 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1465 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1467 /* hpage takes precedence over index */
1469 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1471 if (index < 0 || index >= psInfo->nPages)
1473 TRACE("Could not find page to select!\n");
1477 hwndPage = psInfo->proppage[index].hwndPage;
1480 * Notify the new page if it's already created.
1481 * If not it will get created and notified in PROPSHEET_ShowPage.
1488 psn.hdr.code = PSN_SETACTIVE;
1489 psn.hdr.hwndFrom = hwndDlg;
1493 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1496 * TODO: check return value.
1501 * Display the new page.
1503 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1505 if (psInfo->proppage[index].hasHelp)
1506 EnableWindow(hwndHelp, TRUE);
1508 EnableWindow(hwndHelp, FALSE);
1513 /******************************************************************************
1514 * PROPSHEET_SetTitleA
1516 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1518 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1521 if (HIWORD(lpszText) == 0) {
1522 if (!LoadStringA(psInfo->ppshheader->hInstance,
1523 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1527 if (dwStyle & PSH_PROPTITLE)
1530 int lentitle = strlen(lpszText);
1531 int lenprop = strlen(psInfo->strPropertiesFor);
1533 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1534 strcpy(dest, psInfo->strPropertiesFor);
1535 strcat(dest, lpszText);
1537 SetWindowTextA(hwndDlg, dest);
1538 COMCTL32_Free(dest);
1541 SetWindowTextA(hwndDlg, lpszText);
1544 /******************************************************************************
1545 * PROPSHEET_SetFinishTextA
1547 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1549 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1551 /* Set text, show and enable the Finish button */
1552 SetWindowTextA(hwndButton, lpszText);
1553 ShowWindow(hwndButton, SW_SHOW);
1554 EnableWindow(hwndButton, TRUE);
1556 /* Make it default pushbutton */
1557 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1559 /* Hide Back button */
1560 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1561 ShowWindow(hwndButton, SW_HIDE);
1563 /* Hide Next button */
1564 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1565 ShowWindow(hwndButton, SW_HIDE);
1568 /******************************************************************************
1569 * PROPSHEET_QuerySiblings
1571 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1572 WPARAM wParam, LPARAM lParam)
1576 LRESULT msgResult = 0;
1577 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1580 while ((i < psInfo->nPages) && (msgResult == 0))
1582 hwndPage = psInfo->proppage[i].hwndPage;
1583 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1591 /******************************************************************************
1594 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1595 HPROPSHEETPAGE hpage)
1597 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1599 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1601 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1602 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1605 * Allocate and fill in a new PropPageInfo entry.
1607 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1608 sizeof(PropPageInfo) *
1609 (psInfo->nPages + 1));
1611 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
1612 psInfo->proppage[psInfo->nPages].hpage = hpage;
1614 if (ppsp->dwFlags & PSP_PREMATURE)
1616 /* Create the page but don't show it */
1617 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1621 * Add a new tab to the tab control.
1623 item.mask = TCIF_TEXT;
1624 item.pszText = tabtext;
1625 item.cchTextMax = MAX_TABTEXT_LENGTH;
1627 WideCharToMultiByte(CP_ACP, 0,
1628 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1629 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1631 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1636 /* If it is the only page - show it */
1637 if(psInfo->nPages == 1)
1638 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1643 /******************************************************************************
1644 * PROPSHEET_RemovePage
1646 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1648 HPROPSHEETPAGE hpage)
1650 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1652 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1653 PropPageInfo* oldPages;
1658 oldPages = psInfo->proppage;
1660 * hpage takes precedence over index.
1664 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1667 /* Make shure that index is within range */
1668 if (index < 0 || index >= psInfo->nPages)
1670 TRACE("Could not find page to remove!\n");
1674 TRACE("total pages %d removing page %d active page %d\n",
1675 psInfo->nPages, index, psInfo->active_page);
1677 * Check if we're removing the active page.
1679 if (index == psInfo->active_page)
1681 if (psInfo->nPages > 1)
1685 /* activate previous page */
1686 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1690 /* activate the next page */
1691 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1696 psInfo->active_page = -1;
1697 if (!psInfo->isModeless)
1699 EndDialog(hwndDlg, FALSE);
1704 else if (index < psInfo->active_page)
1705 psInfo->active_page--;
1707 /* Destroy page dialog window */
1708 DestroyWindow(psInfo->proppage[index].hwndPage);
1710 /* Free page resources */
1711 if(psInfo->proppage[index].hpage)
1713 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1715 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1716 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1718 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1721 /* Remove the tab */
1722 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1725 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1728 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1730 if (index < psInfo->nPages)
1731 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1732 (psInfo->nPages - index) * sizeof(PropPageInfo));
1734 COMCTL32_Free(oldPages);
1739 /******************************************************************************
1740 * PROPSHEET_SetWizButtons
1742 * This code will work if (and assumes that) the Next button is on top of the
1743 * Finish button. ie. Finish comes after Next in the Z order.
1744 * This means make sure the dialog template reflects this.
1747 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1749 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1750 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1751 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1753 TRACE("%ld\n", dwFlags);
1755 EnableWindow(hwndBack, FALSE);
1756 EnableWindow(hwndNext, FALSE);
1757 EnableWindow(hwndFinish, FALSE);
1759 if (dwFlags & PSWIZB_BACK)
1760 EnableWindow(hwndBack, TRUE);
1762 if (dwFlags & PSWIZB_NEXT)
1764 /* Hide the Finish button */
1765 ShowWindow(hwndFinish, SW_HIDE);
1767 /* Show and enable the Next button */
1768 ShowWindow(hwndNext, SW_SHOW);
1769 EnableWindow(hwndNext, TRUE);
1771 /* Set the Next button as the default pushbutton */
1772 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1775 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1777 /* Hide the Next button */
1778 ShowWindow(hwndNext, SW_HIDE);
1780 /* Show the Finish button */
1781 ShowWindow(hwndFinish, SW_SHOW);
1783 if (dwFlags & PSWIZB_FINISH)
1784 EnableWindow(hwndFinish, TRUE);
1786 /* Set the Finish button as the default pushbutton */
1787 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1791 /******************************************************************************
1792 * PROPSHEET_GetPageIndex
1794 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1795 * the array of PropPageInfo.
1797 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1802 while ((index < psInfo->nPages) && (found == FALSE))
1804 if (psInfo->proppage[index].hpage == hpage)
1816 /******************************************************************************
1819 static void PROPSHEET_CleanUp(HWND hwndDlg)
1822 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1826 if (HIWORD(psInfo->ppshheader->pszCaption))
1827 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader->pszCaption);
1829 COMCTL32_Free((LPVOID)psInfo->ppshheader);
1831 for (i = 0; i < psInfo->nPages; i++)
1833 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1835 if(psInfo->proppage[i].hwndPage)
1836 DestroyWindow(psInfo->proppage[i].hwndPage);
1840 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1841 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1843 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1847 COMCTL32_Free(psInfo->proppage);
1848 COMCTL32_Free(psInfo->strPropertiesFor);
1849 ImageList_Destroy(psInfo->hImageList);
1851 GlobalFree((HGLOBAL)psInfo);
1854 /******************************************************************************
1855 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1857 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1860 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1861 sizeof(PropSheetInfo));
1865 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1867 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1869 pByte = (BYTE*) psInfo->ppshheader->u3.ppsp;
1871 for (i = 0; i < lppsh->nPages; i++)
1873 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1874 psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1877 psInfo->proppage[i].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1878 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1881 PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage,
1885 bRet = PROPSHEET_CreateDialog(psInfo);
1890 /******************************************************************************
1891 * PropertySheet32W (COMCTL32.85)
1893 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1895 FIXME("(%p): stub\n", propertySheetHeader);
1900 /******************************************************************************
1901 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1903 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1904 LPCPROPSHEETPAGEA lpPropSheetPage)
1906 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1908 *ppsp = *lpPropSheetPage;
1910 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u1.pszTemplate ) )
1911 ppsp->u1.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u1.pszTemplate );
1913 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1914 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
1917 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1918 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
1919 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1920 ppsp->pszTitle = NULL;
1922 return (HPROPSHEETPAGE)ppsp;
1925 /******************************************************************************
1926 * CreatePropertySheetPageW (COMCTL32.20)
1928 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1930 FIXME("(%p): stub\n", lpPropSheetPage);
1935 /******************************************************************************
1936 * DestroyPropertySheetPage (COMCTL32.24)
1938 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1940 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
1945 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u1.pszTemplate ) )
1946 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u1.pszTemplate);
1948 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
1949 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
1951 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
1952 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
1954 COMCTL32_Free(hPropPage);
1959 /******************************************************************************
1960 * PROPSHEET_IsDialogMessage
1962 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
1964 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
1966 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
1969 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
1972 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
1974 if (!(dlgCode & DLGC_WANTMESSAGE))
1976 switch (lpMsg->wParam)
1979 if (GetKeyState(VK_SHIFT) & 0x8000)
1985 case VK_NEXT: new_page = 1; break;
1986 case VK_PRIOR: new_page = -1; break;
1992 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
1994 new_page += psInfo->active_page;
1997 new_page = psInfo->nPages - 1;
1998 else if (new_page >= psInfo->nPages)
2001 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2008 return IsDialogMessageA(hwnd, lpMsg);
2011 /******************************************************************************
2012 * PROPSHEET_DialogProc
2015 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2021 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2022 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2023 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2024 LPCPROPSHEETPAGEA ppshpage;
2027 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2030 * Small icon in the title bar.
2032 if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
2033 (psInfo->ppshheader->dwFlags & PSH_USEHICON))
2036 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2037 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2039 if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
2040 hIcon = LoadImageA(psInfo->ppshheader->hInstance,
2041 psInfo->ppshheader->u1.pszIcon,
2046 hIcon = psInfo->ppshheader->u1.hIcon;
2048 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2051 if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
2052 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->u1.hIcon);
2054 psInfo->strPropertiesFor = strCaption;
2056 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2058 PROPSHEET_CreateTabControl(hwnd, psInfo);
2060 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
2062 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2064 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2065 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2070 if (PROPSHEET_IsTooSmall(hwnd, psInfo))
2072 PROPSHEET_AdjustSize(hwnd, psInfo);
2073 PROPSHEET_AdjustButtons(hwnd, psInfo);
2077 if (psInfo->useCallback)
2078 (*(psInfo->ppshheader->pfnCallback))(hwnd,
2079 PSCB_INITIALIZED, (LPARAM)0);
2081 idx = psInfo->active_page;
2082 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2083 psInfo->active_page = -1;
2085 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2087 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
2088 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2090 if (!HIWORD(psInfo->ppshheader->pszCaption) &&
2091 psInfo->ppshheader->hInstance)
2095 if (LoadStringA(psInfo->ppshheader->hInstance,
2096 (UINT)psInfo->ppshheader->pszCaption, szText, 255))
2097 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags, szText);
2101 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader->dwFlags,
2102 psInfo->ppshheader->pszCaption);
2109 PROPSHEET_CleanUp(hwnd);
2113 PROPSHEET_Cancel(hwnd, 1);
2118 WORD wID = LOWORD(wParam);
2123 case IDC_APPLY_BUTTON:
2125 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2127 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2132 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2136 if (psInfo->restartWindows)
2137 result = ID_PSRESTARTWINDOWS;
2139 /* reboot system takes precedence over restart windows */
2140 if (psInfo->rebootSystem)
2141 result = ID_PSREBOOTSYSTEM;
2143 if (psInfo->isModeless)
2144 psInfo->activeValid = FALSE;
2146 EndDialog(hwnd, result);
2149 EnableWindow(hwndApplyBtn, FALSE);
2154 case IDC_BACK_BUTTON:
2155 PROPSHEET_Back(hwnd);
2158 case IDC_NEXT_BUTTON:
2159 PROPSHEET_Next(hwnd);
2162 case IDC_FINISH_BUTTON:
2163 PROPSHEET_Finish(hwnd);
2167 PROPSHEET_Cancel(hwnd, 0);
2171 PROPSHEET_Help(hwnd);
2180 NMHDR* pnmh = (LPNMHDR) lParam;
2182 if (pnmh->code == TCN_SELCHANGE)
2184 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2185 PROPSHEET_SetCurSel(hwnd, index, 0);
2188 if(pnmh->code == TCN_SELCHANGING)
2190 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2191 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2199 case PSM_GETCURRENTPAGEHWND:
2201 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2205 if (psInfo->activeValid && psInfo->active_page != -1)
2206 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2208 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2214 PROPSHEET_Changed(hwnd, (HWND)wParam);
2218 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2221 case PSM_GETTABCONTROL:
2223 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2225 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2234 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2235 if(msgResult != FALSE)
2237 msgResult = PROPSHEET_SetCurSel(hwnd,
2239 (HPROPSHEETPAGE)lParam);
2242 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2247 case PSM_CANCELTOCLOSE:
2249 char buf[MAX_BUTTONTEXT_LENGTH];
2250 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2251 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2253 EnableWindow(hwndCancel, FALSE);
2254 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2255 SetWindowTextA(hwndOK, buf);
2260 case PSM_RESTARTWINDOWS:
2262 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2265 psInfo->restartWindows = TRUE;
2269 case PSM_REBOOTSYSTEM:
2271 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2274 psInfo->rebootSystem = TRUE;
2279 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2284 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2286 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2291 case PSM_QUERYSIBLINGS:
2293 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2295 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2303 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2304 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2305 * on success or FALSE otherwise, as specified on MSDN Online.
2306 * Also see the MFC code for
2307 * CPropertySheet::AddPage(CPropertyPage* pPage).
2310 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2312 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2317 case PSM_REMOVEPAGE:
2318 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2321 case PSM_ISDIALOGMESSAGE:
2323 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2324 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2328 case PSM_PRESSBUTTON:
2329 PROPSHEET_PressButton(hwnd, (int)wParam);
2332 case PSM_SETFINISHTEXTA:
2333 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2336 case PSM_SETWIZBUTTONS:
2337 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2341 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2343 case PSM_SETCURSELID:
2344 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2346 case PSM_SETFINISHTEXTW:
2347 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");