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,
766 * Set the dirty flag of this page.
768 for (i = 0; i < psInfo->nPages; i++)
770 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
771 psInfo->proppage[i].isDirty = TRUE;
775 * Enable the Apply button.
777 if (psInfo->hasApply)
779 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
781 EnableWindow(hwndApplyBtn, TRUE);
785 /******************************************************************************
786 * PROPSHEET_UnChanged
788 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
791 BOOL noPageDirty = TRUE;
792 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
793 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
796 for (i = 0; i < psInfo->nPages; i++)
798 /* set the specified page as clean */
799 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
800 psInfo->proppage[i].isDirty = FALSE;
802 /* look to see if there's any dirty pages */
803 if (psInfo->proppage[i].isDirty)
808 * Disable Apply button.
811 EnableWindow(hwndApplyBtn, FALSE);
814 /******************************************************************************
815 * PROPSHEET_PressButton
817 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
822 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
825 FIXME("Wizard mode not implemented.\n");
828 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
831 FIXME("Wizard mode not implemented.\n");
834 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
837 FIXME("Wizard mode not implemented.\n");
840 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
843 FIXME("Invalid button index %d\n", buttonID);
847 /******************************************************************************
848 * PROPSHEET_SetCurSel
850 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
852 HPROPSHEETPAGE hpage)
854 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
857 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
861 * Notify the current page.
863 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
865 hdr.hwndFrom = hwndDlg;
866 hdr.code = PSN_KILLACTIVE;
868 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
872 FIXME("Implement HPROPSHEETPAGE!\n");
874 hwndPage = psInfo->proppage[index].hwndPage;
877 * Notify the new page.
879 hdr.code = PSN_SETACTIVE;
881 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
884 * Display the new page.
886 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
888 if (psInfo->proppage[index].hasHelp)
889 EnableWindow(hwndHelp, TRUE);
891 EnableWindow(hwndHelp, FALSE);
896 /******************************************************************************
897 * PROPSHEET_SetTitleA
899 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
901 if (dwStyle & PSH_PROPTITLE)
903 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
906 int lentitle = strlen(lpszText);
907 int lenprop = strlen(psInfo->strPropertiesFor);
909 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
910 strcpy(dest, psInfo->strPropertiesFor);
911 strcat(dest, lpszText);
913 SetWindowTextA(hwndDlg, dest);
917 SetWindowTextA(hwndDlg, lpszText);
920 /******************************************************************************
921 * PROPSHEET_QuerySiblings
923 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
924 WPARAM wParam, LPARAM lParam)
928 LRESULT msgResult = 0;
929 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
932 while ((i < psInfo->nPages) && (msgResult == 0))
934 hwndPage = psInfo->proppage[i].hwndPage;
935 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
942 /******************************************************************************
943 * PROPSHEET_GetPSPPage
945 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
948 BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
949 LPCPROPSHEETPAGEA lppsp;
950 int realIndex = psInfo->proppage[index].index;
956 lppsp = psInfo->ppshheader->u3.ppsp;
958 pByte = (BYTE*) lppsp;
960 pByte += (lppsp->dwSize * realIndex);
961 lppsp = (LPCPROPSHEETPAGEA)pByte;
964 lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
969 /******************************************************************************
972 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
973 HPROPSHEETPAGE hpage)
975 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
977 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
979 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
980 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
983 * Allocate and fill in a new PropPageInfo entry.
985 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
986 sizeof(PropPageInfo) *
987 (psInfo->nPages + 1));
989 PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
990 psInfo->proppage[psInfo->nPages].index = -1;
991 psInfo->proppage[psInfo->nPages].hpage = hpage;
994 * Create the page but don't show it.
996 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
999 * Add a new tab to the tab control.
1001 item.mask = TCIF_TEXT;
1002 item.pszText = tabtext;
1003 item.cchTextMax = MAX_TABTEXT_LENGTH;
1005 WideCharToMultiByte(CP_ACP, 0,
1006 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1007 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1009 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1017 /******************************************************************************
1018 * PROPSHEET_RemovePage
1020 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1022 HPROPSHEETPAGE hpage)
1024 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1026 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1027 PropPageInfo* oldPages = psInfo->proppage;
1030 * hpage takes precedence over index.
1034 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1038 TRACE("Could not find page to remove!\n");
1043 TRACE("total pages %d removing page %d active page %d\n",
1044 psInfo->nPages, index, psInfo->active_page);
1046 * Check if we're removing the active page.
1048 if (index == psInfo->active_page)
1050 if (psInfo->nPages > 1)
1054 /* activate previous page */
1055 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1059 /* activate the next page */
1060 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1065 TRACE("Removing the only page, close the dialog!\n");
1067 if (psInfo->isModeless)
1068 psInfo->active_page = -1;
1070 EndDialog(hwndDlg, FALSE);
1076 if (index < psInfo->active_page)
1077 psInfo->active_page--;
1079 /* Remove the tab */
1080 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1083 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1086 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1088 if (index < psInfo->nPages)
1089 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1090 (psInfo->nPages - index) * sizeof(PropPageInfo));
1092 COMCTL32_Free(oldPages);
1097 /******************************************************************************
1098 * PROPSHEET_GetPageIndex
1100 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1101 * the array of PropPageInfo.
1103 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1108 while ((index < psInfo->nPages) && (found == FALSE))
1110 if (psInfo->proppage[index].hpage == hpage)
1122 /******************************************************************************
1125 static void PROPSHEET_CleanUp(HWND hwndDlg)
1127 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1129 COMCTL32_Free(psInfo->proppage);
1130 COMCTL32_Free(psInfo->strPropertiesFor);
1132 GlobalFree((HGLOBAL)psInfo);
1135 /******************************************************************************
1136 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1138 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1141 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1142 sizeof(PropSheetInfo));
1143 LPCPROPSHEETPAGEA lppsp;
1146 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1148 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1151 for (i = 0; i < lppsh->nPages; i++)
1153 psInfo->proppage[i].index = i;
1154 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1155 psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1156 lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1157 PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1160 bRet = PROPSHEET_CreateDialog(psInfo);
1165 /******************************************************************************
1166 * PropertySheet32W (COMCTL32.85)
1168 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1170 FIXME("(%p): stub\n", propertySheetHeader);
1175 /******************************************************************************
1176 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1178 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1179 LPCPROPSHEETPAGEA lpPropSheetPage)
1181 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1183 *ppsp = *lpPropSheetPage;
1185 return (HPROPSHEETPAGE)ppsp;
1188 /******************************************************************************
1189 * CreatePropertySheetPageW (COMCTL32.20)
1191 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1193 FIXME("(%p): stub\n", lpPropSheetPage);
1198 /******************************************************************************
1199 * DestroyPropertySheetPage (COMCTL32.24)
1201 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1203 COMCTL32_Free(hPropPage);
1208 /******************************************************************************
1209 * PROPSHEET_DialogProc
1212 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1218 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1219 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1220 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1221 LPCPROPSHEETPAGEA ppshpage;
1223 psInfo->strPropertiesFor = strCaption;
1225 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1227 PROPSHEET_CreateTabControl(hwnd, psInfo);
1229 if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1231 PROPSHEET_AdjustSize(hwnd, psInfo);
1232 PROPSHEET_AdjustButtons(hwnd, psInfo);
1235 ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);
1236 PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1237 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1239 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1241 PROPSHEET_SetTitleA(hwnd,
1242 psInfo->ppshheader->dwFlags,
1243 psInfo->ppshheader->pszCaption);
1249 PROPSHEET_CleanUp(hwnd);
1253 PROPSHEET_Cancel(hwnd);
1258 WORD wID = LOWORD(wParam);
1263 case IDC_APPLY_BUTTON:
1265 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1267 if (PROPSHEET_Apply(hwnd) == FALSE)
1270 EnableWindow(hwndApplyBtn, FALSE);
1274 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1278 if (psInfo->restartWindows)
1279 result = ID_PSRESTARTWINDOWS;
1281 /* reboot system takes precedence over restart windows */
1282 if (psInfo->rebootSystem)
1283 result = ID_PSREBOOTSYSTEM;
1285 if (psInfo->isModeless)
1286 psInfo->active_page = -1;
1288 EndDialog(hwnd, result);
1295 PROPSHEET_Cancel(hwnd);
1299 PROPSHEET_Help(hwnd);
1308 NMHDR* pnmh = (LPNMHDR) lParam;
1310 if (pnmh->code == TCN_SELCHANGE)
1312 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1314 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1315 HWND hwndHelp = GetDlgItem(hwnd, IDHELP);
1317 PROPSHEET_ShowPage(hwnd, index, psInfo);
1319 if (psInfo->proppage[index].hasHelp)
1320 EnableWindow(hwndHelp, TRUE);
1322 EnableWindow(hwndHelp, FALSE);
1328 case PSM_GETCURRENTPAGEHWND:
1330 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1334 if (psInfo->active_page != -1)
1335 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1337 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1343 PROPSHEET_Changed(hwnd, (HWND)wParam);
1347 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1350 case PSM_GETTABCONTROL:
1352 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1354 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1363 msgResult = PROPSHEET_SetCurSel(hwnd,
1365 (HPROPSHEETPAGE)lParam);
1367 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1372 case PSM_CANCELTOCLOSE:
1374 HWND hwndOK = GetDlgItem(hwnd, IDOK);
1375 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
1377 EnableWindow(hwndCancel, FALSE);
1378 SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
1383 case PSM_RESTARTWINDOWS:
1385 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1388 psInfo->restartWindows = TRUE;
1392 case PSM_REBOOTSYSTEM:
1394 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1397 psInfo->rebootSystem = TRUE;
1402 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
1407 BOOL msgResult = PROPSHEET_Apply(hwnd);
1409 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1414 case PSM_QUERYSIBLINGS:
1416 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
1418 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1424 PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
1427 case PSM_REMOVEPAGE:
1428 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
1431 case PSM_ISDIALOGMESSAGE:
1433 FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1437 case PSM_PRESSBUTTON:
1438 PROPSHEET_PressButton(hwnd, (int)wParam);
1442 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
1444 case PSM_SETWIZBUTTONS:
1445 FIXME("Unimplemented msg PSM_SETWIZBUTTONS\n");
1447 case PSM_SETCURSELID:
1448 FIXME("Unimplemented msg PSM_SETCURSELID\n");
1450 case PSM_SETFINISHTEXTA:
1451 FIXME("Unimplemented msg PSM_SETFINISHTEXT32A\n");
1453 case PSM_SETFINISHTEXTW:
1454 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");