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
50 PROPSHEETHEADERA ppshheader;
51 LPSTR strPropertiesFor;
61 PropPageInfo* proppage;
66 HIMAGELIST hImageList;
75 /******************************************************************************
76 * Defines and global variables
79 const char * PropSheetInfoStr = "PropertySheetInfo";
81 #define MAX_CAPTION_LENGTH 255
82 #define MAX_TABTEXT_LENGTH 255
83 #define MAX_BUTTONTEXT_LENGTH 64
85 /******************************************************************************
88 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
89 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
90 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
91 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
92 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
93 PropSheetInfo * psInfo);
94 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
95 PropSheetInfo * psInfo,
97 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
98 PropSheetInfo * psInfo);
99 static int PROPSHEET_CreatePage(HWND hwndParent, int index,
100 const PropSheetInfo * psInfo,
101 LPCPROPSHEETPAGEA ppshpage);
102 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
103 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
104 static BOOL PROPSHEET_Back(HWND hwndDlg);
105 static BOOL PROPSHEET_Next(HWND hwndDlg);
106 static BOOL PROPSHEET_Finish(HWND hwndDlg);
107 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
108 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
109 static void PROPSHEET_Help(HWND hwndDlg);
110 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
111 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
112 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
113 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
114 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
115 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
116 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
118 HPROPSHEETPAGE hpage);
119 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
120 WPARAM wParam, LPARAM lParam);
121 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
122 HPROPSHEETPAGE hpage);
124 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
126 HPROPSHEETPAGE hpage);
127 static void PROPSHEET_CleanUp();
128 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
129 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
130 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg);
131 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
132 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner);
135 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
137 DEFAULT_DEBUG_CHANNEL(propsheet)
139 /******************************************************************************
140 * PROPSHEET_CollectSheetInfo
142 * Collect relevant data.
144 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
145 PropSheetInfo * psInfo)
147 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
148 DWORD dwFlags = lppsh->dwFlags;
150 psInfo->hasHelp = dwFlags & PSH_HASHELP;
151 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
152 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
153 psInfo->isModeless = dwFlags & PSH_MODELESS;
155 memcpy(&psInfo->ppshheader,lppsh,dwSize);
157 if (HIWORD(lppsh->pszCaption))
158 psInfo->ppshheader.pszCaption = HEAP_strdupA( GetProcessHeap(),
159 0, lppsh->pszCaption );
161 psInfo->nPages = lppsh->nPages;
163 if (dwFlags & PSH_USEPSTARTPAGE)
165 TRACE("PSH_USEPSTARTPAGE is on");
166 psInfo->active_page = 0;
169 psInfo->active_page = lppsh->u2.nStartPage;
171 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
172 psInfo->active_page = 0;
174 psInfo->restartWindows = FALSE;
175 psInfo->rebootSystem = FALSE;
176 psInfo->hImageList = 0;
177 psInfo->activeValid = FALSE;
182 /******************************************************************************
183 * PROPSHEET_CollectPageInfo
185 * Collect property sheet data.
186 * With code taken from DIALOG_ParseTemplate32.
188 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
189 PropSheetInfo * psInfo,
192 DLGTEMPLATE* pTemplate;
197 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
198 psInfo->proppage[index].hwndPage = 0;
199 psInfo->proppage[index].isDirty = FALSE;
202 * Process property page flags.
204 dwFlags = lppsp->dwFlags;
205 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
206 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
207 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
209 /* as soon as we have a page with the help flag, set the sheet flag on */
210 if (psInfo->proppage[index].hasHelp)
211 psInfo->hasHelp = TRUE;
214 * Process page template.
216 if (dwFlags & PSP_DLGINDIRECT)
217 pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
220 HRSRC hResource = FindResourceA(lppsp->hInstance,
221 lppsp->u1.pszTemplate,
223 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
225 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
229 * Extract the size of the page and the caption.
234 p = (const WORD *)pTemplate;
236 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
238 /* DIALOGEX template */
242 p += 2; /* help ID */
243 p += 2; /* ext style */
248 /* DIALOG template */
251 p += 2; /* ext style */
257 width = (WORD)*p; p++;
258 height = (WORD)*p; p++;
260 /* remember the largest width and height */
261 if (width > psInfo->width)
262 psInfo->width = width;
264 if (height > psInfo->height)
265 psInfo->height = height;
277 p += lstrlenW( (LPCWSTR)p ) + 1;
291 p += lstrlenW( (LPCWSTR)p ) + 1;
295 /* Extract the caption */
296 psInfo->proppage[index].pszText = (LPCWSTR)p;
297 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
298 p += lstrlenW((LPCWSTR)p) + 1;
300 if (dwFlags & PSP_USETITLE)
302 if ( !HIWORD( lppsp->pszTitle ) )
306 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
309 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
313 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
319 * Build the image list for icons
321 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
324 int icon_cx = GetSystemMetrics(SM_CXSMICON);
325 int icon_cy = GetSystemMetrics(SM_CYSMICON);
327 if (dwFlags & PSP_USEICONID)
328 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
329 icon_cx, icon_cy, LR_DEFAULTCOLOR);
331 hIcon = lppsp->u2.hIcon;
335 if (psInfo->hImageList == 0 )
336 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
338 ImageList_AddIcon(psInfo->hImageList, hIcon);
346 /******************************************************************************
347 * PROPSHEET_DoDialogBox
349 * Copied from windows/dialog.c:DIALOG_DoDialogBox
351 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner)
354 DIALOGINFO * dlgInfo;
358 /* Owner must be a top-level window */
359 owner = WIN_GetTopParent( owner );
360 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
361 dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
363 if (!dlgInfo->flags & DF_END) /* was EndDialog called in WM_INITDIALOG ? */
365 EnableWindow( owner, FALSE );
366 ShowWindow( hwnd, SW_SHOW );
367 while (GetMessageA(&msg, 0, 0, 0))
369 if (!PROPSHEET_IsDialogMessage( hwnd, &msg))
371 TranslateMessage( &msg );
372 DispatchMessageA( &msg );
374 if (dlgInfo->flags & DF_END) break;
376 EnableWindow( owner, TRUE );
378 retval = dlgInfo->idResult;
379 WIN_ReleaseWndPtr(wndPtr);
380 DestroyWindow( hwnd );
385 /******************************************************************************
386 * PROPSHEET_CreateDialog
388 * Creates the actual property sheet.
390 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
397 WORD resID = IDD_PROPSHEET;
399 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
402 if(!(hRes = FindResourceA(COMCTL32_hModule,
403 MAKEINTRESOURCEA(resID),
407 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
411 * Make a copy of the dialog template.
413 resSize = SizeofResource(COMCTL32_hModule, hRes);
415 temp = COMCTL32_Alloc(resSize);
420 memcpy(temp, template, resSize);
422 if (psInfo->useCallback)
423 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
425 ret = CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
426 (LPDLGTEMPLATEA) temp,
427 psInfo->ppshheader.hwndParent,
428 (DLGPROC) PROPSHEET_DialogProc,
431 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
432 ret = PROPSHEET_DoDialogBox((HWND)ret, psInfo->ppshheader.hwndParent);
439 /******************************************************************************
440 * PROPSHEET_SizeMismatch
442 * Verify that the tab control and the "largest" property sheet page dlg. template
445 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
447 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
448 RECT rcOrigTab, rcPage;
453 GetClientRect(hwndTabCtrl, &rcOrigTab);
454 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
455 rcOrigTab.right, rcOrigTab.bottom);
460 rcPage.left = psInfo->x;
461 rcPage.top = psInfo->y;
462 rcPage.right = psInfo->width;
463 rcPage.bottom = psInfo->height;
465 MapDialogRect(hwndDlg, &rcPage);
466 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
467 rcPage.right, rcPage.bottom);
469 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
471 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
477 /******************************************************************************
478 * PROPSHEET_IsTooSmallWizard
480 * Verify that the default property sheet is big enough.
482 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
484 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
485 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
486 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
488 GetClientRect(hwndDlg, &rcSheetClient);
489 GetWindowRect(hwndDlg, &rcSheetRect);
490 GetWindowRect(hwndLine, &rcLine);
492 /* Remove the space below the sunken line */
493 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
495 /* Remove the buffer zone all around the edge */
496 rcSheetClient.bottom -= (padding.y * 2);
497 rcSheetClient.right -= (padding.x * 2);
502 rcPage.left = psInfo->x;
503 rcPage.top = psInfo->y;
504 rcPage.right = psInfo->width;
505 rcPage.bottom = psInfo->height;
507 MapDialogRect(hwndDlg, &rcPage);
508 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
509 rcPage.right, rcPage.bottom);
511 if (rcPage.right > rcSheetClient.right)
514 if (rcPage.bottom > rcSheetClient.bottom)
520 /******************************************************************************
521 * PROPSHEET_AdjustSize
523 * Resizes the property sheet and the tab control to fit the largest page.
525 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
527 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
528 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
530 int tabOffsetX, tabOffsetY, buttonHeight;
531 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
532 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
533 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
535 /* Get the height of buttons */
536 GetClientRect(hwndButton, &rc);
537 buttonHeight = rc.bottom;
544 rc.right = psInfo->width;
545 rc.bottom = psInfo->height;
547 MapDialogRect(hwndDlg, &rc);
550 * Resize the tab control.
552 GetClientRect(hwndTabCtrl,&tabRect);
554 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
556 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
558 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
559 psInfo->height = MulDiv((rc.bottom - rc.top),8,dlgInfo->yBaseUnit);
562 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
564 rc.right = rc.left + tabRect.right - tabRect.left;
565 psInfo->width = MulDiv((rc.right - rc.left),4,dlgInfo->xBaseUnit);
568 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
570 tabOffsetX = -(rc.left);
571 tabOffsetY = -(rc.top);
575 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
576 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
578 GetClientRect(hwndTabCtrl, &rc);
580 TRACE("tab client rc %d %d %d %d\n",
581 rc.left, rc.top, rc.right, rc.bottom);
583 rc.right += ((padding.x * 2) + tabOffsetX);
584 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
587 * Resize the property sheet.
589 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
590 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
592 WIN_ReleaseWndPtr(wndPtr);
596 /******************************************************************************
597 * PROPSHEET_AdjustSizeWizard
599 * Resizes the property sheet to fit the largest page.
601 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
603 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
604 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
605 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
607 int buttonHeight, lineHeight;
608 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
609 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
610 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
612 /* Get the height of buttons */
613 GetClientRect(hwndButton, &rc);
614 buttonHeight = rc.bottom;
616 GetClientRect(hwndLine, &rc);
617 lineHeight = rc.bottom;
624 rc.right = psInfo->width;
625 rc.bottom = psInfo->height;
627 MapDialogRect(hwndDlg, &rc);
629 GetClientRect(hwndTabCtrl,&tabRect);
631 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
633 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
634 psInfo->height = MulDiv((rc.bottom - rc.top), 8, dlgInfo->yBaseUnit);
637 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
639 rc.right = rc.left + tabRect.right - tabRect.left;
640 psInfo->width = MulDiv((rc.right - rc.left), 4, dlgInfo->xBaseUnit);
643 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
646 rc.right += (padding.x * 2);
647 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
650 * Resize the property sheet.
652 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
653 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
655 WIN_ReleaseWndPtr(wndPtr);
659 /******************************************************************************
660 * PROPSHEET_AdjustButtons
662 * Adjusts the buttons' positions.
664 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
666 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
670 int buttonWidth, buttonHeight;
671 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
673 if (psInfo->hasApply)
680 * Obtain the size of the buttons.
682 GetClientRect(hwndButton, &rcSheet);
683 buttonWidth = rcSheet.right;
684 buttonHeight = rcSheet.bottom;
687 * Get the size of the property sheet.
689 GetClientRect(hwndParent, &rcSheet);
692 * All buttons will be at this y coordinate.
694 y = rcSheet.bottom - (padding.y + buttonHeight);
697 * Position OK button.
699 hwndButton = GetDlgItem(hwndParent, IDOK);
701 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
703 SetWindowPos(hwndButton, 0, x, y, 0, 0,
704 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
707 * Position Cancel button.
709 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
711 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
713 SetWindowPos(hwndButton, 0, x, y, 0, 0,
714 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
717 * Position Apply button.
719 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
721 if (psInfo->hasApply)
724 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
726 x = rcSheet.right - (padding.x + buttonWidth);
728 SetWindowPos(hwndButton, 0, x, y, 0, 0,
729 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
731 EnableWindow(hwndButton, FALSE);
734 ShowWindow(hwndButton, SW_HIDE);
737 * Position Help button.
739 hwndButton = GetDlgItem(hwndParent, IDHELP);
743 x = rcSheet.right - (padding.x + buttonWidth);
745 SetWindowPos(hwndButton, 0, x, y, 0, 0,
746 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
749 ShowWindow(hwndButton, SW_HIDE);
754 /******************************************************************************
755 * PROPSHEET_AdjustButtonsWizard
757 * Adjusts the buttons' positions.
759 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
760 PropSheetInfo* psInfo)
762 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
763 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
767 int buttonWidth, buttonHeight, lineHeight, lineWidth;
768 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
774 * Obtain the size of the buttons.
776 GetClientRect(hwndButton, &rcSheet);
777 buttonWidth = rcSheet.right;
778 buttonHeight = rcSheet.bottom;
780 GetClientRect(hwndLine, &rcSheet);
781 lineHeight = rcSheet.bottom;
784 * Get the size of the property sheet.
786 GetClientRect(hwndParent, &rcSheet);
789 * All buttons will be at this y coordinate.
791 y = rcSheet.bottom - (padding.y + buttonHeight);
794 * Position the Next and the Finish buttons.
796 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
798 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
800 SetWindowPos(hwndButton, 0, x, y, 0, 0,
801 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
803 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
805 SetWindowPos(hwndButton, 0, x, y, 0, 0,
806 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
808 ShowWindow(hwndButton, SW_HIDE);
811 * Position the Back button.
813 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
817 SetWindowPos(hwndButton, 0, x, y, 0, 0,
818 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
821 * Position the Cancel button.
823 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
825 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
827 SetWindowPos(hwndButton, 0, x, y, 0, 0,
828 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
831 * Position Help button.
833 hwndButton = GetDlgItem(hwndParent, IDHELP);
837 x = rcSheet.right - (padding.x + buttonWidth);
839 SetWindowPos(hwndButton, 0, x, y, 0, 0,
840 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
843 ShowWindow(hwndButton, SW_HIDE);
846 * Position and resize the sunken line.
849 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
851 GetClientRect(hwndParent, &rcSheet);
852 lineWidth = rcSheet.right - (padding.x * 2);
854 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
855 SWP_NOZORDER | SWP_NOACTIVATE);
860 /******************************************************************************
861 * PROPSHEET_GetPaddingInfo
863 * Returns the layout information.
865 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
867 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
870 PADDING_INFO padding;
872 GetWindowRect(hwndTab, &rcTab);
877 ScreenToClient(hwndDlg, &tl);
885 /******************************************************************************
886 * PROPSHEET_GetPaddingInfoWizard
888 * Returns the layout information.
889 * Horizontal spacing is the distance between the Cancel and Help buttons.
890 * Vertical spacing is the distance between the line and the buttons.
892 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
894 PADDING_INFO padding;
897 POINT ptHelp, ptCancel, ptLine;
900 hwndControl = GetDlgItem(hwndDlg, IDHELP);
901 GetWindowRect(hwndControl, &rc);
906 ScreenToClient(hwndDlg, &ptHelp);
909 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
910 GetWindowRect(hwndControl, &rc);
912 ptCancel.x = rc.right;
915 ScreenToClient(hwndDlg, &ptCancel);
918 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
919 GetWindowRect(hwndControl, &rc);
922 ptLine.y = rc.bottom;
924 ScreenToClient(hwndDlg, &ptLine);
926 padding.x = ptHelp.x - ptCancel.x;
927 padding.y = ptHelp.y - ptLine.y;
932 /******************************************************************************
933 * PROPSHEET_CreateTabControl
935 * Insert the tabs in the tab control.
937 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
938 PropSheetInfo * psInfo)
940 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
944 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
946 item.mask = TCIF_TEXT;
947 item.pszText = tabtext;
948 item.cchTextMax = MAX_TABTEXT_LENGTH;
950 nTabs = psInfo->nPages;
953 * Set the image list for icons.
955 if (psInfo->hImageList)
957 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
960 for (i = 0; i < nTabs; i++)
962 if ( psInfo->proppage[i].hasIcon )
964 item.mask |= TCIF_IMAGE;
965 item.iImage = iImage++;
969 item.mask &= ~TCIF_IMAGE;
972 WideCharToMultiByte(CP_ACP, 0,
973 (LPCWSTR)psInfo->proppage[i].pszText,
974 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
976 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
982 /******************************************************************************
983 * PROPSHEET_CreatePage
987 static int PROPSHEET_CreatePage(HWND hwndParent,
989 const PropSheetInfo * psInfo,
990 LPCPROPSHEETPAGEA ppshpage)
992 DLGTEMPLATE* pTemplate;
995 PropPageInfo* ppInfo = psInfo->proppage;
996 PADDING_INFO padding;
997 UINT pageWidth,pageHeight;
999 TRACE("index %d\n", index);
1001 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1002 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
1005 HRSRC hResource = FindResourceA(ppshpage->hInstance,
1006 ppshpage->u1.pszTemplate,
1008 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
1009 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1012 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1014 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1015 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1016 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1017 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1018 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1019 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1020 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1024 pTemplate->style |= WS_CHILD | DS_CONTROL;
1025 pTemplate->style &= ~DS_MODALFRAME;
1026 pTemplate->style &= ~WS_CAPTION;
1027 pTemplate->style &= ~WS_SYSMENU;
1028 pTemplate->style &= ~WS_POPUP;
1029 pTemplate->style &= ~WS_DISABLED;
1030 pTemplate->style &= ~WS_VISIBLE;
1033 if (psInfo->proppage[index].useCallback)
1034 (*(ppshpage->pfnCallback))(hwndParent,
1036 (LPPROPSHEETPAGEA)ppshpage);
1038 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1041 ppshpage->pfnDlgProc,
1044 ppInfo[index].hwndPage = hwndPage;
1046 rc.left = psInfo->x;
1048 rc.right = psInfo->width;
1049 rc.bottom = psInfo->height;
1051 MapDialogRect(hwndParent, &rc);
1053 pageWidth = rc.right - rc.left;
1054 pageHeight = rc.bottom - rc.top;
1056 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1057 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
1061 * Ask the Tab control to fit this page in.
1064 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1065 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1066 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1069 SetWindowPos(hwndPage, HWND_TOP,
1070 rc.left + padding.x,
1072 pageWidth, pageHeight, 0);
1077 /******************************************************************************
1078 * PROPSHEET_ShowPage
1080 * Displays or creates the specified page.
1082 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1084 if (index == psInfo->active_page)
1086 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1087 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1091 if (psInfo->proppage[index].hwndPage == 0)
1093 LPCPROPSHEETPAGEA ppshpage;
1096 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1097 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1099 psn.hdr.hwndFrom = hwndDlg;
1100 psn.hdr.code = PSN_SETACTIVE;
1104 /* Send the notification before showing the page. */
1105 SendMessageA(psInfo->proppage[index].hwndPage,
1106 WM_NOTIFY, 0, (LPARAM) &psn);
1109 * TODO: check return value.
1113 if (psInfo->active_page != -1)
1114 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1116 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1118 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1122 /* Synchronize current selection with tab control */
1123 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1124 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1127 psInfo->active_page = index;
1128 psInfo->activeValid = TRUE;
1133 /******************************************************************************
1136 static BOOL PROPSHEET_Back(HWND hwndDlg)
1141 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1144 if (psInfo->active_page < 0)
1147 psn.hdr.code = PSN_WIZBACK;
1148 psn.hdr.hwndFrom = hwndDlg;
1152 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1154 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1157 if (psInfo->active_page > 0)
1159 res = PROPSHEET_CanSetCurSel(hwndDlg);
1162 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1169 /******************************************************************************
1172 static BOOL PROPSHEET_Next(HWND hwndDlg)
1176 LRESULT msgResult = 0;
1177 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1180 if (psInfo->active_page < 0)
1183 psn.hdr.code = PSN_WIZNEXT;
1184 psn.hdr.hwndFrom = hwndDlg;
1188 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1190 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1192 TRACE("msg result %ld\n", msgResult);
1194 if (msgResult == -1)
1197 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1199 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1205 /******************************************************************************
1208 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1212 LRESULT msgResult = 0;
1213 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1216 if (psInfo->active_page < 0)
1219 psn.hdr.code = PSN_WIZFINISH;
1220 psn.hdr.hwndFrom = hwndDlg;
1224 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1226 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1228 TRACE("msg result %ld\n", msgResult);
1233 if (psInfo->isModeless)
1234 psInfo->activeValid = FALSE;
1236 EndDialog(hwndDlg, TRUE);
1241 /******************************************************************************
1244 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1250 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1253 if (psInfo->active_page < 0)
1256 psn.hdr.hwndFrom = hwndDlg;
1262 * Send PSN_KILLACTIVE to the current page.
1264 psn.hdr.code = PSN_KILLACTIVE;
1266 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1268 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1272 * Send PSN_APPLY to all pages.
1274 psn.hdr.code = PSN_APPLY;
1275 psn.lParam = lParam;
1277 for (i = 0; i < psInfo->nPages; i++)
1279 hwndPage = psInfo->proppage[i].hwndPage;
1282 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1283 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1290 psInfo->activeValid = FALSE;
1292 else if(psInfo->active_page >= 0)
1294 psn.hdr.code = PSN_SETACTIVE;
1296 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1297 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1303 /******************************************************************************
1306 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1308 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1314 if (psInfo->active_page < 0)
1317 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1318 psn.hdr.code = PSN_QUERYCANCEL;
1319 psn.hdr.hwndFrom = hwndDlg;
1323 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1326 psn.hdr.code = PSN_RESET;
1327 psn.lParam = lParam;
1329 for (i = 0; i < psInfo->nPages; i++)
1331 hwndPage = psInfo->proppage[i].hwndPage;
1334 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1337 if (psInfo->isModeless)
1339 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1340 psInfo->activeValid = FALSE;
1343 EndDialog(hwndDlg, FALSE);
1346 /******************************************************************************
1349 static void PROPSHEET_Help(HWND hwndDlg)
1351 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1356 if (psInfo->active_page < 0)
1359 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1360 psn.hdr.code = PSN_HELP;
1361 psn.hdr.hwndFrom = hwndDlg;
1365 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1368 /******************************************************************************
1371 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1374 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1377 if (!psInfo) return;
1379 * Set the dirty flag of this page.
1381 for (i = 0; i < psInfo->nPages; i++)
1383 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1384 psInfo->proppage[i].isDirty = TRUE;
1388 * Enable the Apply button.
1390 if (psInfo->hasApply)
1392 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1394 EnableWindow(hwndApplyBtn, TRUE);
1398 /******************************************************************************
1399 * PROPSHEET_UnChanged
1401 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1404 BOOL noPageDirty = TRUE;
1405 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1406 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1409 if ( !psInfo ) return;
1410 for (i = 0; i < psInfo->nPages; i++)
1412 /* set the specified page as clean */
1413 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1414 psInfo->proppage[i].isDirty = FALSE;
1416 /* look to see if there's any dirty pages */
1417 if (psInfo->proppage[i].isDirty)
1418 noPageDirty = FALSE;
1422 * Disable Apply button.
1425 EnableWindow(hwndApplyBtn, FALSE);
1428 /******************************************************************************
1429 * PROPSHEET_PressButton
1431 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1435 case PSBTN_APPLYNOW:
1436 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1439 PROPSHEET_Back(hwndDlg);
1442 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1445 PROPSHEET_Finish(hwndDlg);
1448 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1451 PROPSHEET_Next(hwndDlg);
1454 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1457 FIXME("Invalid button index %d\n", buttonID);
1462 /*************************************************************************
1463 * BOOL PROPSHEET_CanSetCurSel [Internal]
1465 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1468 * hwndDlg [I] handle to a Dialog hWnd
1471 * TRUE if Current Selection can change
1475 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1477 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1485 if (psInfo->active_page < 0)
1489 * Notify the current page.
1491 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1492 psn.hdr.code = PSN_KILLACTIVE;
1493 psn.hdr.hwndFrom = hwndDlg;
1497 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1500 /******************************************************************************
1501 * PROPSHEET_SetCurSel
1503 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1505 HPROPSHEETPAGE hpage)
1507 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1510 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1512 /* hpage takes precedence over index */
1514 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1516 if (index < 0 || index >= psInfo->nPages)
1518 TRACE("Could not find page to select!\n");
1522 hwndPage = psInfo->proppage[index].hwndPage;
1525 * Notify the new page if it's already created.
1526 * If not it will get created and notified in PROPSHEET_ShowPage.
1533 psn.hdr.code = PSN_SETACTIVE;
1534 psn.hdr.hwndFrom = hwndDlg;
1538 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1541 * TODO: check return value.
1546 * Display the new page.
1548 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1550 if (psInfo->proppage[index].hasHelp)
1551 EnableWindow(hwndHelp, TRUE);
1553 EnableWindow(hwndHelp, FALSE);
1558 /******************************************************************************
1559 * PROPSHEET_SetTitleA
1561 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1563 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1566 if (HIWORD(lpszText) == 0) {
1567 if (!LoadStringA(psInfo->ppshheader.hInstance,
1568 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1572 if (dwStyle & PSH_PROPTITLE)
1575 int lentitle = strlen(lpszText);
1576 int lenprop = strlen(psInfo->strPropertiesFor);
1578 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1579 strcpy(dest, psInfo->strPropertiesFor);
1580 strcat(dest, lpszText);
1582 SetWindowTextA(hwndDlg, dest);
1583 COMCTL32_Free(dest);
1586 SetWindowTextA(hwndDlg, lpszText);
1589 /******************************************************************************
1590 * PROPSHEET_SetFinishTextA
1592 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1594 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1596 /* Set text, show and enable the Finish button */
1597 SetWindowTextA(hwndButton, lpszText);
1598 ShowWindow(hwndButton, SW_SHOW);
1599 EnableWindow(hwndButton, TRUE);
1601 /* Make it default pushbutton */
1602 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1604 /* Hide Back button */
1605 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1606 ShowWindow(hwndButton, SW_HIDE);
1608 /* Hide Next button */
1609 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1610 ShowWindow(hwndButton, SW_HIDE);
1613 /******************************************************************************
1614 * PROPSHEET_QuerySiblings
1616 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1617 WPARAM wParam, LPARAM lParam)
1621 LRESULT msgResult = 0;
1622 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1625 while ((i < psInfo->nPages) && (msgResult == 0))
1627 hwndPage = psInfo->proppage[i].hwndPage;
1628 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1636 /******************************************************************************
1639 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1640 HPROPSHEETPAGE hpage)
1642 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1644 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1646 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1647 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1650 * Allocate and fill in a new PropPageInfo entry.
1652 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1653 sizeof(PropPageInfo) *
1654 (psInfo->nPages + 1));
1655 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1658 psInfo->proppage[psInfo->nPages].hpage = hpage;
1660 if (ppsp->dwFlags & PSP_PREMATURE)
1662 /* Create the page but don't show it */
1663 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1667 * Add a new tab to the tab control.
1669 item.mask = TCIF_TEXT;
1670 item.pszText = tabtext;
1671 item.cchTextMax = MAX_TABTEXT_LENGTH;
1673 WideCharToMultiByte(CP_ACP, 0,
1674 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1675 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1677 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1682 /* If it is the only page - show it */
1683 if(psInfo->nPages == 1)
1684 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1689 /******************************************************************************
1690 * PROPSHEET_RemovePage
1692 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1694 HPROPSHEETPAGE hpage)
1696 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1698 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1699 PropPageInfo* oldPages;
1704 oldPages = psInfo->proppage;
1706 * hpage takes precedence over index.
1710 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1713 /* Make shure that index is within range */
1714 if (index < 0 || index >= psInfo->nPages)
1716 TRACE("Could not find page to remove!\n");
1720 TRACE("total pages %d removing page %d active page %d\n",
1721 psInfo->nPages, index, psInfo->active_page);
1723 * Check if we're removing the active page.
1725 if (index == psInfo->active_page)
1727 if (psInfo->nPages > 1)
1731 /* activate previous page */
1732 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1736 /* activate the next page */
1737 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1738 psInfo->active_page = index;
1743 psInfo->active_page = -1;
1744 if (!psInfo->isModeless)
1746 EndDialog(hwndDlg, FALSE);
1751 else if (index < psInfo->active_page)
1752 psInfo->active_page--;
1754 /* Destroy page dialog window */
1755 DestroyWindow(psInfo->proppage[index].hwndPage);
1757 /* Free page resources */
1758 if(psInfo->proppage[index].hpage)
1760 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1762 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1763 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1765 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1768 /* Remove the tab */
1769 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1772 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1775 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1777 if (index < psInfo->nPages)
1778 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1779 (psInfo->nPages - index) * sizeof(PropPageInfo));
1781 COMCTL32_Free(oldPages);
1786 /******************************************************************************
1787 * PROPSHEET_SetWizButtons
1789 * This code will work if (and assumes that) the Next button is on top of the
1790 * Finish button. ie. Finish comes after Next in the Z order.
1791 * This means make sure the dialog template reflects this.
1794 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1796 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1797 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1798 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1800 TRACE("%ld\n", dwFlags);
1802 EnableWindow(hwndBack, FALSE);
1803 EnableWindow(hwndNext, FALSE);
1804 EnableWindow(hwndFinish, FALSE);
1806 if (dwFlags & PSWIZB_BACK)
1807 EnableWindow(hwndBack, TRUE);
1809 if (dwFlags & PSWIZB_NEXT)
1811 /* Hide the Finish button */
1812 ShowWindow(hwndFinish, SW_HIDE);
1814 /* Show and enable the Next button */
1815 ShowWindow(hwndNext, SW_SHOW);
1816 EnableWindow(hwndNext, TRUE);
1818 /* Set the Next button as the default pushbutton */
1819 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1822 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1824 /* Hide the Next button */
1825 ShowWindow(hwndNext, SW_HIDE);
1827 /* Show the Finish button */
1828 ShowWindow(hwndFinish, SW_SHOW);
1830 if (dwFlags & PSWIZB_FINISH)
1831 EnableWindow(hwndFinish, TRUE);
1833 /* Set the Finish button as the default pushbutton */
1834 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1838 /******************************************************************************
1839 * PROPSHEET_GetPageIndex
1841 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1842 * the array of PropPageInfo.
1844 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1849 while ((index < psInfo->nPages) && (found == FALSE))
1851 if (psInfo->proppage[index].hpage == hpage)
1863 /******************************************************************************
1866 static void PROPSHEET_CleanUp(HWND hwndDlg)
1869 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1873 if (HIWORD(psInfo->ppshheader.pszCaption))
1874 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
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 * PropertySheetW (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 * psInfo->hwnd is not being used by WINE code - it exists
2082 * for compatibility with "real" Windoze. The same about
2083 * SetWindowLong - WINE is only using the PropSheetInfoStr
2086 psInfo->hwnd = hwnd;
2087 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2090 * Small icon in the title bar.
2092 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2093 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2096 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2097 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2099 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2100 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2101 psInfo->ppshheader.u1.pszIcon,
2106 hIcon = psInfo->ppshheader.u1.hIcon;
2108 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2111 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2112 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u1.hIcon);
2114 psInfo->strPropertiesFor = strCaption;
2116 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2118 PROPSHEET_CreateTabControl(hwnd, psInfo);
2120 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2122 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2124 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2125 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2130 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2132 PROPSHEET_AdjustSize(hwnd, psInfo);
2133 PROPSHEET_AdjustButtons(hwnd, psInfo);
2137 if (psInfo->useCallback)
2138 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2139 PSCB_INITIALIZED, (LPARAM)0);
2141 idx = psInfo->active_page;
2142 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2143 psInfo->active_page = -1;
2145 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2147 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2148 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2150 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2151 psInfo->ppshheader.hInstance)
2155 if (LoadStringA(psInfo->ppshheader.hInstance,
2156 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2157 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2161 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2162 psInfo->ppshheader.pszCaption);
2169 PROPSHEET_CleanUp(hwnd);
2173 PROPSHEET_Cancel(hwnd, 1);
2178 WORD wID = LOWORD(wParam);
2183 case IDC_APPLY_BUTTON:
2185 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2187 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2192 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2196 if (psInfo->restartWindows)
2197 result = ID_PSRESTARTWINDOWS;
2199 /* reboot system takes precedence over restart windows */
2200 if (psInfo->rebootSystem)
2201 result = ID_PSREBOOTSYSTEM;
2203 if (psInfo->isModeless)
2204 psInfo->activeValid = FALSE;
2206 EndDialog(hwnd, result);
2209 EnableWindow(hwndApplyBtn, FALSE);
2214 case IDC_BACK_BUTTON:
2215 PROPSHEET_Back(hwnd);
2218 case IDC_NEXT_BUTTON:
2219 PROPSHEET_Next(hwnd);
2222 case IDC_FINISH_BUTTON:
2223 PROPSHEET_Finish(hwnd);
2227 PROPSHEET_Cancel(hwnd, 0);
2231 PROPSHEET_Help(hwnd);
2240 NMHDR* pnmh = (LPNMHDR) lParam;
2242 if (pnmh->code == TCN_SELCHANGE)
2244 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2245 PROPSHEET_SetCurSel(hwnd, index, 0);
2248 if(pnmh->code == TCN_SELCHANGING)
2250 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2251 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2259 case PSM_GETCURRENTPAGEHWND:
2261 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2265 if (psInfo->activeValid && psInfo->active_page != -1)
2266 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2268 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2274 PROPSHEET_Changed(hwnd, (HWND)wParam);
2278 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2281 case PSM_GETTABCONTROL:
2283 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2285 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2294 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2295 if(msgResult != FALSE)
2297 msgResult = PROPSHEET_SetCurSel(hwnd,
2299 (HPROPSHEETPAGE)lParam);
2302 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2307 case PSM_CANCELTOCLOSE:
2309 char buf[MAX_BUTTONTEXT_LENGTH];
2310 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2311 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2313 EnableWindow(hwndCancel, FALSE);
2314 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2315 SetWindowTextA(hwndOK, buf);
2320 case PSM_RESTARTWINDOWS:
2322 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2325 psInfo->restartWindows = TRUE;
2329 case PSM_REBOOTSYSTEM:
2331 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2334 psInfo->rebootSystem = TRUE;
2339 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2344 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2346 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2351 case PSM_QUERYSIBLINGS:
2353 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2355 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2363 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2364 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2365 * on success or FALSE otherwise, as specified on MSDN Online.
2366 * Also see the MFC code for
2367 * CPropertySheet::AddPage(CPropertyPage* pPage).
2370 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2372 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2377 case PSM_REMOVEPAGE:
2378 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2381 case PSM_ISDIALOGMESSAGE:
2383 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2384 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2388 case PSM_PRESSBUTTON:
2389 PROPSHEET_PressButton(hwnd, (int)wParam);
2392 case PSM_SETFINISHTEXTA:
2393 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2396 case PSM_SETWIZBUTTONS:
2397 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2401 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2403 case PSM_SETCURSELID:
2404 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2406 case PSM_SETFINISHTEXTW:
2407 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");