4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
10 * - Unicode property sheets
18 #include "propsheet.h"
22 /******************************************************************************
34 typedef struct tagPropPageInfo
36 int index; /* corresponds to the index in ppshheader->ppsp */
37 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
45 typedef struct tagPropSheetInfo
47 LPSTR strPropertiesFor;
50 LPCPROPSHEETHEADERA ppshheader;
57 PropPageInfo* proppage;
70 /******************************************************************************
71 * Defines and global variables
74 const char * PropSheetInfoStr = "PropertySheetInfo";
76 #define MAX_CAPTION_LENGTH 255
77 #define MAX_TABTEXT_LENGTH 255
80 /******************************************************************************
83 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
84 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo);
85 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
86 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
87 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
88 PropSheetInfo * psInfo);
89 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
90 PropSheetInfo * psInfo,
92 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
93 PropSheetInfo * psInfo);
94 static int PROPSHEET_CreatePage(HWND hwndParent, int index,
95 const PropSheetInfo * psInfo,
96 LPCPROPSHEETPAGEA ppshpage,
98 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
99 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
100 static BOOL PROPSHEET_Apply(HWND hwndDlg);
101 static void PROPSHEET_Cancel(HWND hwndDlg);
102 static void PROPSHEET_Help(HWND hwndDlg);
103 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
104 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
105 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
106 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
107 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
109 HPROPSHEETPAGE hpage);
110 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
111 WPARAM wParam, LPARAM lParam);
112 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
114 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
115 HPROPSHEETPAGE hpage);
117 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
119 HPROPSHEETPAGE hpage);
120 static void PROPSHEET_CleanUp();
121 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
124 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
126 DEFAULT_DEBUG_CHANNEL(propsheet)
128 /******************************************************************************
129 * PROPSHEET_CollectSheetInfo
131 * Collect relevant data.
133 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
134 PropSheetInfo * psInfo)
136 DWORD dwFlags = lppsh->dwFlags;
138 psInfo->hasHelp = dwFlags & PSH_HASHELP;
139 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
140 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
141 psInfo->isModeless = dwFlags & PSH_MODELESS;
142 psInfo->ppshheader = lppsh;
143 psInfo->nPages = lppsh->nPages;
145 if (dwFlags & PSH_USEPSTARTPAGE)
147 TRACE(propsheet, "PSH_USEPSTARTPAGE is on");
148 psInfo->active_page = 0;
151 psInfo->active_page = lppsh->u2.nStartPage;
153 psInfo->restartWindows = FALSE;
154 psInfo->rebootSystem = FALSE;
159 /******************************************************************************
160 * PROPSHEET_CollectPageInfo
162 * Collect property sheet data.
163 * With code taken from DIALOG_ParseTemplate32.
165 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
166 PropSheetInfo * psInfo,
169 DLGTEMPLATE* pTemplate;
174 if (psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE)
175 psInfo->proppage[index].hpage = 0;
176 psInfo->proppage[index].hwndPage = 0;
177 psInfo->proppage[index].isDirty = FALSE;
180 * Process property page flags.
182 dwFlags = lppsp->dwFlags;
183 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
184 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
186 /* as soon as we have a page with the help flag, set the sheet flag on */
187 if (psInfo->proppage[index].hasHelp)
188 psInfo->hasHelp = TRUE;
191 * Process page template.
193 if (dwFlags & PSP_DLGINDIRECT)
194 pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
197 HRSRC hResource = FindResourceA(lppsp->hInstance,
198 lppsp->u1.pszTemplate,
200 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
202 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
206 * Extract the size of the page and the caption.
208 p = (const WORD *)pTemplate;
210 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
212 /* DIALOGEX template */
216 p += 2; /* help ID */
217 p += 2; /* ext style */
222 /* DIALOG template */
225 p += 2; /* ext style */
231 width = (WORD)*p; p++;
232 height = (WORD)*p; p++;
234 /* remember the largest width and height */
235 if (width > psInfo->width)
236 psInfo->width = width;
238 if (height > psInfo->height)
239 psInfo->height = height;
251 p += lstrlenW( (LPCWSTR)p ) + 1;
265 p += lstrlenW( (LPCWSTR)p ) + 1;
269 /* Extract the caption */
270 psInfo->proppage[index].pszText = (LPCWSTR)p;
271 TRACE(propsheet, "Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
272 p += lstrlenW((LPCWSTR)p) + 1;
277 /******************************************************************************
278 * PROPSHEET_CreateDialog
280 * Creates the actual property sheet.
282 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
288 if(!(hRes = FindResourceA(COMCTL32_hModule,
289 MAKEINTRESOURCEA(IDD_PROPSHEET),
293 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
296 if (psInfo->useCallback)
297 (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)template);
299 if (psInfo->ppshheader->dwFlags & PSH_MODELESS)
300 ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
301 (LPDLGTEMPLATEA) template,
302 psInfo->ppshheader->hwndParent,
303 (DLGPROC) PROPSHEET_DialogProc,
306 ret = DialogBoxIndirectParamA(psInfo->ppshheader->hInstance,
307 (LPDLGTEMPLATEA) template,
308 psInfo->ppshheader->hwndParent,
309 (DLGPROC) PROPSHEET_DialogProc,
315 /******************************************************************************
316 * PROPSHEET_IsTooSmall
318 * Verify that the resource property sheet is big enough.
320 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
322 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
323 RECT rcOrigTab, rcPage;
328 GetClientRect(hwndTabCtrl, &rcOrigTab);
329 TRACE(propsheet, "orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
330 rcOrigTab.right, rcOrigTab.bottom);
335 rcPage.left = psInfo->x;
336 rcPage.top = psInfo->y;
337 rcPage.right = psInfo->width;
338 rcPage.bottom = psInfo->height;
340 MapDialogRect(hwndDlg, &rcPage);
341 TRACE(propsheet, "biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
342 rcPage.right, rcPage.bottom);
344 if (rcPage.right > rcOrigTab.right)
347 if (rcPage.bottom > rcOrigTab.bottom)
353 /******************************************************************************
354 * PROPSHEET_AdjustSize
356 * Resizes the property sheet and the tab control to fit the largest page.
358 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
360 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
361 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
363 int tabOffsetX, tabOffsetY, buttonHeight;
364 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
366 /* Get the height of buttons */
367 GetClientRect(hwndButton, &rc);
368 buttonHeight = rc.bottom;
375 rc.right = psInfo->width;
376 rc.bottom = psInfo->height;
378 MapDialogRect(hwndDlg, &rc);
381 * Resize the tab control.
383 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
385 tabOffsetX = -(rc.left);
386 tabOffsetY = -(rc.top);
390 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
391 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
393 GetClientRect(hwndTabCtrl, &rc);
395 TRACE(propsheet, "tab client rc %d %d %d %d\n",
396 rc.left, rc.top, rc.right, rc.bottom);
398 rc.right += ((padding.x * 2) + tabOffsetX);
399 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
402 * Resize the property sheet.
404 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
405 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
410 /******************************************************************************
411 * PROPSHEET_AdjustButtons
413 * Adjusts the buttons' positions.
415 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
417 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
421 int buttonWidth, buttonHeight;
422 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
424 if (psInfo->hasApply)
431 * Obtain the size of the buttons.
433 GetClientRect(hwndButton, &rcSheet);
434 buttonWidth = rcSheet.right;
435 buttonHeight = rcSheet.bottom;
438 * Get the size of the property sheet.
440 GetClientRect(hwndParent, &rcSheet);
443 * All buttons will be at this y coordinate.
445 y = rcSheet.bottom - (padding.y + buttonHeight);
448 * Position OK button.
450 hwndButton = GetDlgItem(hwndParent, IDOK);
452 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
454 SetWindowPos(hwndButton, 0, x, y, 0, 0,
455 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
458 * Position Cancel button.
460 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
462 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
464 SetWindowPos(hwndButton, 0, x, y, 0, 0,
465 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
468 * Position Apply button.
470 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
472 if (psInfo->hasApply)
475 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
477 x = rcSheet.right - (padding.x + buttonWidth);
479 SetWindowPos(hwndButton, 0, x, y, 0, 0,
480 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
482 EnableWindow(hwndButton, FALSE);
485 ShowWindow(hwndButton, SW_HIDE);
488 * Position Help button.
490 hwndButton = GetDlgItem(hwndParent, IDHELP);
494 x = rcSheet.right - (padding.x + buttonWidth);
496 SetWindowPos(hwndButton, 0, x, y, 0, 0,
497 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
500 ShowWindow(hwndButton, SW_HIDE);
505 /******************************************************************************
506 * PROPSHEET_GetPaddingInfo
508 * Returns the layout information.
510 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
512 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
515 PADDING_INFO padding;
517 GetWindowRect(hwndTab, &rcTab);
522 ScreenToClient(hwndDlg, &tl);
530 /******************************************************************************
531 * PROPSHEET_CreateTabControl
533 * Insert the tabs in the tab control.
535 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
536 PropSheetInfo * psInfo)
538 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
541 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
543 item.mask = TCIF_TEXT;
544 item.pszText = tabtext;
545 item.cchTextMax = MAX_TABTEXT_LENGTH;
547 nTabs = psInfo->ppshheader->nPages;
549 for (i = 0; i < nTabs; i++)
551 WideCharToMultiByte(CP_ACP, 0,
552 (LPCWSTR)psInfo->proppage[i].pszText,
553 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
555 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
561 /******************************************************************************
562 * PROPSHEET_CreatePage
566 static int PROPSHEET_CreatePage(HWND hwndParent,
568 const PropSheetInfo * psInfo,
569 LPCPROPSHEETPAGEA ppshpage,
572 DLGTEMPLATE* pTemplate;
575 PropPageInfo* ppInfo = psInfo->proppage;
576 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
577 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
579 TRACE(propsheet, "index %d\n", index);
581 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
582 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
585 HRSRC hResource = FindResourceA(ppshpage->hInstance,
586 ppshpage->u1.pszTemplate,
588 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
589 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
592 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
594 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD;
595 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
596 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
597 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
598 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
602 pTemplate->style |= WS_CHILD;
603 pTemplate->style &= ~DS_MODALFRAME;
604 pTemplate->style &= ~WS_CAPTION;
605 pTemplate->style &= ~WS_SYSMENU;
606 pTemplate->style &= ~WS_POPUP;
609 if (psInfo->proppage[index].useCallback)
610 (*(ppshpage->pfnCallback))(hwndParent,
612 (LPPROPSHEETPAGEA)ppshpage);
614 hwndPage = CreateDialogIndirectA(ppshpage->hInstance,
617 ppshpage->pfnDlgProc);
619 ppInfo[index].hwndPage = hwndPage;
623 rc.right = psInfo->width;
624 rc.bottom = psInfo->height;
626 MapDialogRect(hwndParent, &rc);
629 * Ask the Tab control to fit this page in.
631 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
633 SetWindowPos(hwndPage, HWND_TOP,
639 ShowWindow(hwndPage, SW_SHOW);
641 ShowWindow(hwndPage, SW_HIDE);
646 /******************************************************************************
649 * Displays or creates the specified page.
651 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
653 if (index == psInfo->active_page)
656 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
658 if (psInfo->proppage[index].hwndPage != 0)
659 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
662 LPCPROPSHEETPAGEA ppshpage = PROPSHEET_GetPSPPage(psInfo, index);
663 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage, TRUE);
666 psInfo->active_page = index;
671 /******************************************************************************
674 static BOOL PROPSHEET_Apply(HWND hwndDlg)
680 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
683 hdr.hwndFrom = hwndDlg;
686 * Send PSN_KILLACTIVE to the current page.
688 hdr.code = PSN_KILLACTIVE;
690 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
692 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) != FALSE)
696 * Send PSN_APPLY to all pages.
698 hdr.code = PSN_APPLY;
700 for (i = 0; i < psInfo->nPages; i++)
702 hwndPage = psInfo->proppage[i].hwndPage;
703 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
705 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
712 /******************************************************************************
715 static void PROPSHEET_Cancel(HWND hwndDlg)
717 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
719 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
722 hdr.hwndFrom = hwndDlg;
723 hdr.code = PSN_QUERYCANCEL;
725 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
728 hdr.code = PSN_RESET;
730 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
732 if (psInfo->isModeless)
733 psInfo->active_page = -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
735 EndDialog(hwndDlg, FALSE);
738 /******************************************************************************
741 static void PROPSHEET_Help(HWND hwndDlg)
743 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
745 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
748 hdr.hwndFrom = hwndDlg;
751 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
754 /******************************************************************************
757 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
760 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
764 * Set the dirty flag of this page.
766 for (i = 0; i < psInfo->nPages; i++)
768 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
769 psInfo->proppage[i].isDirty = TRUE;
773 * Enable the Apply button.
775 if (psInfo->hasApply)
777 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
779 EnableWindow(hwndApplyBtn, TRUE);
783 /******************************************************************************
784 * PROPSHEET_UnChanged
786 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
789 BOOL noPageDirty = TRUE;
790 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
791 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
794 for (i = 0; i < psInfo->nPages; i++)
796 /* set the specified page as clean */
797 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
798 psInfo->proppage[i].isDirty = FALSE;
800 /* look to see if there's any dirty pages */
801 if (psInfo->proppage[i].isDirty)
806 * Disable Apply button.
809 EnableWindow(hwndApplyBtn, FALSE);
812 /******************************************************************************
813 * PROPSHEET_PressButton
815 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
820 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
823 FIXME(propsheet, "Wizard mode not implemented.\n");
826 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
829 FIXME(propsheet, "Wizard mode not implemented.\n");
832 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
835 FIXME(propsheet, "Wizard mode not implemented.\n");
838 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
841 FIXME(propsheet, "Invalid button index %d\n", buttonID);
845 /******************************************************************************
846 * PROPSHEET_SetCurSel
848 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
850 HPROPSHEETPAGE hpage)
852 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
855 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
859 * Notify the current page.
861 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
863 hdr.hwndFrom = hwndDlg;
864 hdr.code = PSN_KILLACTIVE;
866 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
870 FIXME(propsheet, "Implement HPROPSHEETPAGE!\n");
872 hwndPage = psInfo->proppage[index].hwndPage;
875 * Notify the new page.
877 hdr.code = PSN_SETACTIVE;
879 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
882 * Display the new page.
884 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
886 if (psInfo->proppage[index].hasHelp)
887 EnableWindow(hwndHelp, TRUE);
889 EnableWindow(hwndHelp, FALSE);
894 /******************************************************************************
895 * PROPSHEET_SetTitleA
897 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
899 if (dwStyle & PSH_PROPTITLE)
901 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
904 int lentitle = strlen(lpszText);
905 int lenprop = strlen(psInfo->strPropertiesFor);
907 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
908 strcpy(dest, psInfo->strPropertiesFor);
909 strcat(dest, lpszText);
911 SetWindowTextA(hwndDlg, dest);
915 SetWindowTextA(hwndDlg, lpszText);
918 /******************************************************************************
919 * PROPSHEET_QuerySiblings
921 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
922 WPARAM wParam, LPARAM lParam)
926 LRESULT msgResult = 0;
927 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
930 while ((i < psInfo->nPages) && (msgResult == 0))
932 hwndPage = psInfo->proppage[i].hwndPage;
933 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
940 /******************************************************************************
941 * PROPSHEET_GetPSPPage
943 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
946 BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
947 LPCPROPSHEETPAGEA lppsp;
948 int realIndex = psInfo->proppage[index].index;
954 lppsp = psInfo->ppshheader->u3.ppsp;
956 pByte = (BYTE*) lppsp;
958 pByte += (lppsp->dwSize * realIndex);
959 lppsp = (LPCPROPSHEETPAGEA)pByte;
962 lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
967 /******************************************************************************
970 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
971 HPROPSHEETPAGE hpage)
973 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
975 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
977 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
978 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
981 * Allocate and fill in a new PropPageInfo entry.
983 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
984 sizeof(PropPageInfo) *
985 (psInfo->nPages + 1));
987 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
988 psInfo->proppage[psInfo->nPages].index = -1;
989 psInfo->proppage[psInfo->nPages].hpage = hpage;
992 * Create the page but don't show it.
994 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
997 * Add a new tab to the tab control.
999 item.mask = TCIF_TEXT;
1000 item.pszText = tabtext;
1001 item.cchTextMax = MAX_TABTEXT_LENGTH;
1003 WideCharToMultiByte(CP_ACP, 0,
1004 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1005 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1007 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1015 /******************************************************************************
1016 * PROPSHEET_RemovePage
1018 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1020 HPROPSHEETPAGE hpage)
1022 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1024 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1025 PropPageInfo* oldPages = psInfo->proppage;
1028 * hpage takes precedence over index.
1032 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1036 TRACE(propsheet, "Could not find page to remove!\n");
1041 TRACE(propsheet, "total pages %d removing page %d active page %d\n",
1042 psInfo->nPages, index, psInfo->active_page);
1044 * Check if we're removing the active page.
1046 if (index == psInfo->active_page)
1048 if (psInfo->nPages > 1)
1052 /* activate previous page */
1053 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1057 /* activate the next page */
1058 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1063 TRACE(propsheet, "Removing the only page, close the dialog!\n");
1065 if (psInfo->isModeless)
1066 psInfo->active_page = -1;
1068 EndDialog(hwndDlg, FALSE);
1074 if (index < psInfo->active_page)
1075 psInfo->active_page--;
1077 /* Remove the tab */
1078 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1081 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1084 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1086 if (index < psInfo->nPages)
1087 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1088 (psInfo->nPages - index) * sizeof(PropPageInfo));
1090 COMCTL32_Free(oldPages);
1095 /******************************************************************************
1096 * PROPSHEET_GetPageIndex
1098 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1099 * the array of PropPageInfo.
1101 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1106 while ((index < psInfo->nPages) && (found == FALSE))
1108 if (psInfo->proppage[index].hpage == hpage)
1120 /******************************************************************************
1123 static void PROPSHEET_CleanUp(HWND hwndDlg)
1125 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1127 COMCTL32_Free(psInfo->proppage);
1128 COMCTL32_Free(psInfo->strPropertiesFor);
1130 GlobalFree((HGLOBAL)psInfo);
1133 /******************************************************************************
1134 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1136 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1139 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1140 sizeof(PropSheetInfo));
1141 LPCPROPSHEETPAGEA lppsp;
1144 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1146 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1149 for (i = 0; i < lppsh->nPages; i++)
1151 psInfo->proppage[i].index = i;
1152 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1153 psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1154 lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1155 PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1158 bRet = PROPSHEET_CreateDialog(psInfo);
1163 /******************************************************************************
1164 * PropertySheet32W (COMCTL32.85)
1166 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1168 FIXME(propsheet, "(%p): stub\n", propertySheetHeader);
1173 /******************************************************************************
1174 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1176 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1177 LPCPROPSHEETPAGEA lpPropSheetPage)
1179 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1181 *ppsp = *lpPropSheetPage;
1183 return (HPROPSHEETPAGE)ppsp;
1186 /******************************************************************************
1187 * CreatePropertySheetPageW (COMCTL32.20)
1189 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1191 FIXME(propsheet, "(%p): stub\n", lpPropSheetPage);
1196 /******************************************************************************
1197 * DestroyPropertySheetPage (COMCTL32.24)
1199 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1201 COMCTL32_Free(hPropPage);
1206 /******************************************************************************
1207 * PROPSHEET_DialogProc
1210 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1216 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1217 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1218 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1219 LPCPROPSHEETPAGEA ppshpage;
1221 psInfo->strPropertiesFor = strCaption;
1223 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1225 PROPSHEET_CreateTabControl(hwnd, psInfo);
1227 if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1229 PROPSHEET_AdjustSize(hwnd, psInfo);
1230 PROPSHEET_AdjustButtons(hwnd, psInfo);
1233 ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);
1234 PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1235 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1237 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1239 PROPSHEET_SetTitleA(hwnd,
1240 psInfo->ppshheader->dwFlags,
1241 psInfo->ppshheader->pszCaption);
1247 PROPSHEET_CleanUp(hwnd);
1251 PROPSHEET_Cancel(hwnd);
1256 WORD wID = LOWORD(wParam);
1261 case IDC_APPLY_BUTTON:
1263 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1265 if (PROPSHEET_Apply(hwnd) == FALSE)
1268 EnableWindow(hwndApplyBtn, FALSE);
1272 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1276 if (psInfo->restartWindows)
1277 result = ID_PSRESTARTWINDOWS;
1279 /* reboot system takes precedence over restart windows */
1280 if (psInfo->rebootSystem)
1281 result = ID_PSREBOOTSYSTEM;
1283 if (psInfo->isModeless)
1284 psInfo->active_page = -1;
1286 EndDialog(hwnd, result);
1293 PROPSHEET_Cancel(hwnd);
1297 PROPSHEET_Help(hwnd);
1306 NMHDR* pnmh = (LPNMHDR) lParam;
1308 if (pnmh->code == TCN_SELCHANGE)
1310 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1312 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1313 HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
1315 PROPSHEET_ShowPage(hwnd, index, psInfo);
1317 if (psInfo->proppage[index].hasHelp)
1318 EnableWindow(hwndHelp, TRUE);
1320 EnableWindow(hwndHelp, FALSE);
1326 case PSM_GETCURRENTPAGEHWND:
1328 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1332 if (psInfo->active_page != -1)
1333 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1335 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1341 PROPSHEET_Changed(hwnd, (HWND)wParam);
1345 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1348 case PSM_GETTABCONTROL:
1350 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1352 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1361 msgResult = PROPSHEET_SetCurSel(hwnd,
1363 (HPROPSHEETPAGE)lParam);
1365 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1370 case PSM_CANCELTOCLOSE:
1372 HWND hwndOK = GetDlgItem(hwnd, IDOK);
1373 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
1375 EnableWindow(hwndCancel, FALSE);
1376 SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
1381 case PSM_RESTARTWINDOWS:
1383 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1386 psInfo->restartWindows = TRUE;
1390 case PSM_REBOOTSYSTEM:
1392 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1395 psInfo->rebootSystem = TRUE;
1400 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
1405 BOOL msgResult = PROPSHEET_Apply(hwnd);
1407 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1412 case PSM_QUERYSIBLINGS:
1414 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
1416 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1422 PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
1425 case PSM_REMOVEPAGE:
1426 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
1429 case PSM_ISDIALOGMESSAGE:
1431 FIXME (propsheet, "Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1435 case PSM_PRESSBUTTON:
1436 PROPSHEET_PressButton(hwnd, (int)wParam);
1440 FIXME (propsheet, "Unimplemented msg PSM_SETTITLE32W\n");
1442 case PSM_SETWIZBUTTONS:
1443 FIXME (propsheet, "Unimplemented msg PSM_SETWIZBUTTONS\n");
1445 case PSM_SETCURSELID:
1446 FIXME (propsheet, "Unimplemented msg PSM_SETCURSELID\n");
1448 case PSM_SETFINISHTEXTA:
1449 FIXME (propsheet, "Unimplemented msg PSM_SETFINISHTEXT32A\n");
1451 case PSM_SETFINISHTEXTW:
1452 FIXME (propsheet, "Unimplemented msg PSM_SETFINISHTEXT32W\n");