4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
10 * - Unicode property sheets
19 #include "debugtools.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("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("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("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("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("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("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 = CreateDialogIndirectParamA(ppshpage->hInstance,
617 ppshpage->pfnDlgProc,
620 ppInfo[index].hwndPage = hwndPage;
624 rc.right = psInfo->width;
625 rc.bottom = psInfo->height;
627 MapDialogRect(hwndParent, &rc);
630 * Ask the Tab control to fit this page in.
632 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
634 SetWindowPos(hwndPage, HWND_TOP,
640 ShowWindow(hwndPage, SW_SHOW);
642 ShowWindow(hwndPage, SW_HIDE);
647 /******************************************************************************
650 * Displays or creates the specified page.
652 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
654 if (index == psInfo->active_page)
657 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
659 if (psInfo->proppage[index].hwndPage != 0)
660 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
663 LPCPROPSHEETPAGEA ppshpage = PROPSHEET_GetPSPPage(psInfo, index);
664 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage, TRUE);
667 psInfo->active_page = index;
672 /******************************************************************************
675 static BOOL PROPSHEET_Apply(HWND hwndDlg)
681 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
684 hdr.hwndFrom = hwndDlg;
687 * Send PSN_KILLACTIVE to the current page.
689 hdr.code = PSN_KILLACTIVE;
691 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
693 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) != FALSE)
697 * Send PSN_APPLY to all pages.
699 hdr.code = PSN_APPLY;
701 for (i = 0; i < psInfo->nPages; i++)
703 hwndPage = psInfo->proppage[i].hwndPage;
704 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
706 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
713 /******************************************************************************
716 static void PROPSHEET_Cancel(HWND hwndDlg)
718 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
720 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
723 hdr.hwndFrom = hwndDlg;
724 hdr.code = PSN_QUERYCANCEL;
726 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
729 hdr.code = PSN_RESET;
731 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
733 if (psInfo->isModeless)
734 psInfo->active_page = -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
736 EndDialog(hwndDlg, FALSE);
739 /******************************************************************************
742 static void PROPSHEET_Help(HWND hwndDlg)
744 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
746 HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
749 hdr.hwndFrom = hwndDlg;
752 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
755 /******************************************************************************
758 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
761 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
765 * Set the dirty flag of this page.
767 for (i = 0; i < psInfo->nPages; i++)
769 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
770 psInfo->proppage[i].isDirty = TRUE;
774 * Enable the Apply button.
776 if (psInfo->hasApply)
778 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
780 EnableWindow(hwndApplyBtn, TRUE);
784 /******************************************************************************
785 * PROPSHEET_UnChanged
787 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
790 BOOL noPageDirty = TRUE;
791 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
792 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
795 for (i = 0; i < psInfo->nPages; i++)
797 /* set the specified page as clean */
798 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
799 psInfo->proppage[i].isDirty = FALSE;
801 /* look to see if there's any dirty pages */
802 if (psInfo->proppage[i].isDirty)
807 * Disable Apply button.
810 EnableWindow(hwndApplyBtn, FALSE);
813 /******************************************************************************
814 * PROPSHEET_PressButton
816 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
821 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
824 FIXME("Wizard mode not implemented.\n");
827 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
830 FIXME("Wizard mode not implemented.\n");
833 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
836 FIXME("Wizard mode not implemented.\n");
839 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
842 FIXME("Invalid button index %d\n", buttonID);
846 /******************************************************************************
847 * PROPSHEET_SetCurSel
849 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
851 HPROPSHEETPAGE hpage)
853 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
856 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
860 * Notify the current page.
862 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
864 hdr.hwndFrom = hwndDlg;
865 hdr.code = PSN_KILLACTIVE;
867 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
871 FIXME("Implement HPROPSHEETPAGE!\n");
873 hwndPage = psInfo->proppage[index].hwndPage;
876 * Notify the new page.
878 hdr.code = PSN_SETACTIVE;
880 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
883 * Display the new page.
885 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
887 if (psInfo->proppage[index].hasHelp)
888 EnableWindow(hwndHelp, TRUE);
890 EnableWindow(hwndHelp, FALSE);
895 /******************************************************************************
896 * PROPSHEET_SetTitleA
898 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
900 if (dwStyle & PSH_PROPTITLE)
902 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
905 int lentitle = strlen(lpszText);
906 int lenprop = strlen(psInfo->strPropertiesFor);
908 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
909 strcpy(dest, psInfo->strPropertiesFor);
910 strcat(dest, lpszText);
912 SetWindowTextA(hwndDlg, dest);
916 SetWindowTextA(hwndDlg, lpszText);
919 /******************************************************************************
920 * PROPSHEET_QuerySiblings
922 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
923 WPARAM wParam, LPARAM lParam)
927 LRESULT msgResult = 0;
928 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
931 while ((i < psInfo->nPages) && (msgResult == 0))
933 hwndPage = psInfo->proppage[i].hwndPage;
934 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
941 /******************************************************************************
942 * PROPSHEET_GetPSPPage
944 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
947 BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
948 LPCPROPSHEETPAGEA lppsp;
949 int realIndex = psInfo->proppage[index].index;
955 lppsp = psInfo->ppshheader->u3.ppsp;
957 pByte = (BYTE*) lppsp;
959 pByte += (lppsp->dwSize * realIndex);
960 lppsp = (LPCPROPSHEETPAGEA)pByte;
963 lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
968 /******************************************************************************
971 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
972 HPROPSHEETPAGE hpage)
974 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
976 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
978 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
979 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
982 * Allocate and fill in a new PropPageInfo entry.
984 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
985 sizeof(PropPageInfo) *
986 (psInfo->nPages + 1));
988 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
989 psInfo->proppage[psInfo->nPages].index = -1;
990 psInfo->proppage[psInfo->nPages].hpage = hpage;
993 * Create the page but don't show it.
995 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
998 * Add a new tab to the tab control.
1000 item.mask = TCIF_TEXT;
1001 item.pszText = tabtext;
1002 item.cchTextMax = MAX_TABTEXT_LENGTH;
1004 WideCharToMultiByte(CP_ACP, 0,
1005 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1006 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1008 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1016 /******************************************************************************
1017 * PROPSHEET_RemovePage
1019 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1021 HPROPSHEETPAGE hpage)
1023 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1025 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1026 PropPageInfo* oldPages = psInfo->proppage;
1029 * hpage takes precedence over index.
1033 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1037 TRACE("Could not find page to remove!\n");
1042 TRACE("total pages %d removing page %d active page %d\n",
1043 psInfo->nPages, index, psInfo->active_page);
1045 * Check if we're removing the active page.
1047 if (index == psInfo->active_page)
1049 if (psInfo->nPages > 1)
1053 /* activate previous page */
1054 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1058 /* activate the next page */
1059 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1064 TRACE("Removing the only page, close the dialog!\n");
1066 if (psInfo->isModeless)
1067 psInfo->active_page = -1;
1069 EndDialog(hwndDlg, FALSE);
1075 if (index < psInfo->active_page)
1076 psInfo->active_page--;
1078 /* Remove the tab */
1079 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1082 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1085 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1087 if (index < psInfo->nPages)
1088 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1089 (psInfo->nPages - index) * sizeof(PropPageInfo));
1091 COMCTL32_Free(oldPages);
1096 /******************************************************************************
1097 * PROPSHEET_GetPageIndex
1099 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1100 * the array of PropPageInfo.
1102 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1107 while ((index < psInfo->nPages) && (found == FALSE))
1109 if (psInfo->proppage[index].hpage == hpage)
1121 /******************************************************************************
1124 static void PROPSHEET_CleanUp(HWND hwndDlg)
1126 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1128 COMCTL32_Free(psInfo->proppage);
1129 COMCTL32_Free(psInfo->strPropertiesFor);
1131 GlobalFree((HGLOBAL)psInfo);
1134 /******************************************************************************
1135 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1137 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1140 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1141 sizeof(PropSheetInfo));
1142 LPCPROPSHEETPAGEA lppsp;
1145 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1147 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1150 for (i = 0; i < lppsh->nPages; i++)
1152 psInfo->proppage[i].index = i;
1153 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1154 psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1155 lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1156 PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1159 bRet = PROPSHEET_CreateDialog(psInfo);
1164 /******************************************************************************
1165 * PropertySheet32W (COMCTL32.85)
1167 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1169 FIXME("(%p): stub\n", propertySheetHeader);
1174 /******************************************************************************
1175 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1177 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1178 LPCPROPSHEETPAGEA lpPropSheetPage)
1180 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1182 *ppsp = *lpPropSheetPage;
1184 return (HPROPSHEETPAGE)ppsp;
1187 /******************************************************************************
1188 * CreatePropertySheetPageW (COMCTL32.20)
1190 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1192 FIXME("(%p): stub\n", lpPropSheetPage);
1197 /******************************************************************************
1198 * DestroyPropertySheetPage (COMCTL32.24)
1200 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1202 COMCTL32_Free(hPropPage);
1207 /******************************************************************************
1208 * PROPSHEET_DialogProc
1211 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1217 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1218 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1219 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1220 LPCPROPSHEETPAGEA ppshpage;
1222 psInfo->strPropertiesFor = strCaption;
1224 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1226 PROPSHEET_CreateTabControl(hwnd, psInfo);
1228 if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1230 PROPSHEET_AdjustSize(hwnd, psInfo);
1231 PROPSHEET_AdjustButtons(hwnd, psInfo);
1234 ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);
1235 PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1236 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1238 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1240 PROPSHEET_SetTitleA(hwnd,
1241 psInfo->ppshheader->dwFlags,
1242 psInfo->ppshheader->pszCaption);
1248 PROPSHEET_CleanUp(hwnd);
1252 PROPSHEET_Cancel(hwnd);
1257 WORD wID = LOWORD(wParam);
1262 case IDC_APPLY_BUTTON:
1264 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1266 if (PROPSHEET_Apply(hwnd) == FALSE)
1269 EnableWindow(hwndApplyBtn, FALSE);
1273 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1277 if (psInfo->restartWindows)
1278 result = ID_PSRESTARTWINDOWS;
1280 /* reboot system takes precedence over restart windows */
1281 if (psInfo->rebootSystem)
1282 result = ID_PSREBOOTSYSTEM;
1284 if (psInfo->isModeless)
1285 psInfo->active_page = -1;
1287 EndDialog(hwnd, result);
1294 PROPSHEET_Cancel(hwnd);
1298 PROPSHEET_Help(hwnd);
1307 NMHDR* pnmh = (LPNMHDR) lParam;
1309 if (pnmh->code == TCN_SELCHANGE)
1311 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1313 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1314 HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
1316 PROPSHEET_ShowPage(hwnd, index, psInfo);
1318 if (psInfo->proppage[index].hasHelp)
1319 EnableWindow(hwndHelp, TRUE);
1321 EnableWindow(hwndHelp, FALSE);
1327 case PSM_GETCURRENTPAGEHWND:
1329 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1333 if (psInfo->active_page != -1)
1334 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1336 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1342 PROPSHEET_Changed(hwnd, (HWND)wParam);
1346 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1349 case PSM_GETTABCONTROL:
1351 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1353 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1362 msgResult = PROPSHEET_SetCurSel(hwnd,
1364 (HPROPSHEETPAGE)lParam);
1366 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1371 case PSM_CANCELTOCLOSE:
1373 HWND hwndOK = GetDlgItem(hwnd, IDOK);
1374 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
1376 EnableWindow(hwndCancel, FALSE);
1377 SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
1382 case PSM_RESTARTWINDOWS:
1384 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1387 psInfo->restartWindows = TRUE;
1391 case PSM_REBOOTSYSTEM:
1393 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1396 psInfo->rebootSystem = TRUE;
1401 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
1406 BOOL msgResult = PROPSHEET_Apply(hwnd);
1408 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1413 case PSM_QUERYSIBLINGS:
1415 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
1417 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1423 PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
1426 case PSM_REMOVEPAGE:
1427 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
1430 case PSM_ISDIALOGMESSAGE:
1432 FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1436 case PSM_PRESSBUTTON:
1437 PROPSHEET_PressButton(hwnd, (int)wParam);
1441 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
1443 case PSM_SETWIZBUTTONS:
1444 FIXME("Unimplemented msg PSM_SETWIZBUTTONS\n");
1446 case PSM_SETCURSELID:
1447 FIXME("Unimplemented msg PSM_SETCURSELID\n");
1449 case PSM_SETFINISHTEXTA:
1450 FIXME("Unimplemented msg PSM_SETFINISHTEXT32A\n");
1452 case PSM_SETFINISHTEXTW:
1453 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");