4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * - Unicode property sheets
32 #include "wine/debug.h"
36 /******************************************************************************
48 typedef struct tagPropPageInfo
50 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
59 typedef struct tagPropSheetInfo
62 PROPSHEETHEADERW ppshheader;
63 LPWSTR strPropertiesFor;
73 PropPageInfo* proppage;
78 HIMAGELIST hImageList;
87 /******************************************************************************
88 * Defines and global variables
91 const WCHAR PropSheetInfoStr[] =
92 {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };
94 #define MAX_CAPTION_LENGTH 255
95 #define MAX_TABTEXT_LENGTH 255
96 #define MAX_BUTTONTEXT_LENGTH 64
98 #define PSH_WIZARD97_OLD 0x00002000
99 #define PSH_WIZARD97_NEW 0x01000000
100 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
102 /******************************************************************************
105 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
106 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
107 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
108 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
109 static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
110 PropSheetInfo * psInfo);
111 static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
112 PropSheetInfo * psInfo);
113 static BOOL PROPSHEET_CollectPageInfoA(LPCPROPSHEETPAGEA lppsp,
114 PropSheetInfo * psInfo,
116 static BOOL PROPSHEET_CollectPageInfoW(LPCPROPSHEETPAGEW lppsp,
117 PropSheetInfo * psInfo,
119 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
120 PropSheetInfo * psInfo);
121 static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index,
122 const PropSheetInfo * psInfo,
123 LPCPROPSHEETPAGEW ppshpage);
124 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
125 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
126 static BOOL PROPSHEET_Back(HWND hwndDlg);
127 static BOOL PROPSHEET_Next(HWND hwndDlg);
128 static BOOL PROPSHEET_Finish(HWND hwndDlg);
129 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
130 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
131 static void PROPSHEET_Help(HWND hwndDlg);
132 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
133 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
134 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
135 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
136 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText);
137 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
138 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);
139 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
140 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
143 HPROPSHEETPAGE hpage);
144 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
145 WPARAM wParam, LPARAM lParam);
146 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
147 HPROPSHEETPAGE hpage);
149 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
151 HPROPSHEETPAGE hpage);
152 static void PROPSHEET_CleanUp();
153 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
154 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
155 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
156 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
157 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
160 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
162 WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
164 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
165 /******************************************************************************
166 * PROPSHEET_UnImplementedFlags
168 * Document use of flags we don't implement yet.
170 static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)
177 * unhandled header flags:
178 * PSH_DEFAULT 0x00000000
179 * PSH_WIZARDHASFINISH 0x00000010
180 * PSH_RTLREADING 0x00000800
181 * PSH_WIZARDCONTEXTHELP 0x00001000
182 * PSH_WIZARD97 0x00002000 (pre IE 5)
183 * PSH_WATERMARK 0x00008000
184 * PSH_USEHBMWATERMARK 0x00010000
185 * PSH_USEHPLWATERMARK 0x00020000
186 * PSH_STRETCHWATERMARK 0x00040000
187 * PSH_HEADER 0x00080000
188 * PSH_USEHBMHEADER 0x00100000
189 * PSH_USEPAGELANG 0x00200000
190 * PSH_WIZARD_LITE 0x00400000 also not in .h
191 * PSH_WIZARD97 0x01000000 (IE 5 and above)
192 * PSH_NOCONTEXTHELP 0x02000000 also not in .h
195 add_flag(PSH_WIZARDHASFINISH);
196 add_flag(PSH_RTLREADING);
197 add_flag(PSH_WIZARDCONTEXTHELP);
198 add_flag(PSH_WIZARD97_OLD);
199 add_flag(PSH_WATERMARK);
200 add_flag(PSH_USEHBMWATERMARK);
201 add_flag(PSH_USEHPLWATERMARK);
202 add_flag(PSH_STRETCHWATERMARK);
203 add_flag(PSH_HEADER);
204 add_flag(PSH_USEHBMHEADER);
205 add_flag(PSH_USEPAGELANG);
206 add_flag(PSH_WIZARD_LITE);
207 add_flag(PSH_WIZARD97_NEW);
208 add_flag(PSH_NOCONTEXTHELP);
209 if (string[0] != '\0')
210 FIXME("%s\n", string);
214 /******************************************************************************
215 * PROPSHEET_CollectSheetInfoA
217 * Collect relevant data.
219 static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
220 PropSheetInfo * psInfo)
222 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
223 DWORD dwFlags = lppsh->dwFlags;
225 psInfo->hasHelp = dwFlags & PSH_HASHELP;
226 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
227 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
228 psInfo->isModeless = dwFlags & PSH_MODELESS;
230 memcpy(&psInfo->ppshheader,lppsh,dwSize);
231 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%04x\nhInstance\t%08x\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
232 lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,
233 debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
235 PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
237 if (HIWORD(lppsh->pszCaption))
239 int len = strlen(lppsh->pszCaption);
240 psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
241 MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len+1);
242 /* strcpy( (char *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); */
244 psInfo->nPages = lppsh->nPages;
246 if (dwFlags & PSH_USEPSTARTPAGE)
248 TRACE("PSH_USEPSTARTPAGE is on");
249 psInfo->active_page = 0;
252 psInfo->active_page = lppsh->u2.nStartPage;
254 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
255 psInfo->active_page = 0;
257 psInfo->restartWindows = FALSE;
258 psInfo->rebootSystem = FALSE;
259 psInfo->hImageList = 0;
260 psInfo->activeValid = FALSE;
265 /******************************************************************************
266 * PROPSHEET_CollectSheetInfoW
268 * Collect relevant data.
270 static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
271 PropSheetInfo * psInfo)
273 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));
274 DWORD dwFlags = lppsh->dwFlags;
276 psInfo->hasHelp = dwFlags & PSH_HASHELP;
277 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
278 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
279 psInfo->isModeless = dwFlags & PSH_MODELESS;
281 memcpy(&psInfo->ppshheader,lppsh,dwSize);
282 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%04x\nhInstance\t%08x\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
283 lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
285 PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
287 if (HIWORD(lppsh->pszCaption))
289 int len = strlenW(lppsh->pszCaption);
290 psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );
291 strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );
293 psInfo->nPages = lppsh->nPages;
295 if (dwFlags & PSH_USEPSTARTPAGE)
297 TRACE("PSH_USEPSTARTPAGE is on");
298 psInfo->active_page = 0;
301 psInfo->active_page = lppsh->u2.nStartPage;
303 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
304 psInfo->active_page = 0;
306 psInfo->restartWindows = FALSE;
307 psInfo->rebootSystem = FALSE;
308 psInfo->hImageList = 0;
309 psInfo->activeValid = FALSE;
314 /******************************************************************************
315 * PROPSHEET_CollectPageInfoA
317 * Collect property sheet data.
318 * With code taken from DIALOG_ParseTemplate32.
320 BOOL PROPSHEET_CollectPageInfoA(LPCPROPSHEETPAGEA lppsp,
321 PropSheetInfo * psInfo,
324 DLGTEMPLATE* pTemplate;
330 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
331 psInfo->proppage[index].hwndPage = 0;
332 psInfo->proppage[index].isDirty = FALSE;
335 * Process property page flags.
337 dwFlags = lppsp->dwFlags;
338 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
339 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
340 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
342 /* as soon as we have a page with the help flag, set the sheet flag on */
343 if (psInfo->proppage[index].hasHelp)
344 psInfo->hasHelp = TRUE;
347 * Process page template.
349 if (dwFlags & PSP_DLGINDIRECT)
350 pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
353 HRSRC hResource = FindResourceA(lppsp->hInstance,
354 lppsp->u.pszTemplate,
356 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
358 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
362 * Extract the size of the page and the caption.
367 p = (const WORD *)pTemplate;
369 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
371 /* DIALOGEX template */
375 p += 2; /* help ID */
376 p += 2; /* ext style */
381 /* DIALOG template */
384 p += 2; /* ext style */
390 width = (WORD)*p; p++;
391 height = (WORD)*p; p++;
393 /* remember the largest width and height */
394 if (width > psInfo->width)
395 psInfo->width = width;
397 if (height > psInfo->height)
398 psInfo->height = height;
410 p += lstrlenW( (LPCWSTR)p ) + 1;
424 p += lstrlenW( (LPCWSTR)p ) + 1;
428 /* Extract the caption */
429 psInfo->proppage[index].pszText = (LPCWSTR)p;
430 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
431 p += lstrlenW((LPCWSTR)p) + 1;
433 if (dwFlags & PSP_USETITLE)
435 if ( !HIWORD( lppsp->pszTitle ) )
439 if (LoadStringA( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,256 )) {
440 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(), 0, szTitle );
442 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(), 0, "(null)" );
443 FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
447 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
453 * Build the image list for icons
455 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
458 int icon_cx = GetSystemMetrics(SM_CXSMICON);
459 int icon_cy = GetSystemMetrics(SM_CYSMICON);
461 if (dwFlags & PSP_USEICONID)
462 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
463 icon_cx, icon_cy, LR_DEFAULTCOLOR);
465 hIcon = lppsp->u2.hIcon;
469 if (psInfo->hImageList == 0 )
470 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
472 ImageList_AddIcon(psInfo->hImageList, hIcon);
480 /******************************************************************************
481 * PROPSHEET_CollectPageInfoW
483 * Collect property sheet data.
484 * With code taken from DIALOG_ParseTemplate32.
486 BOOL PROPSHEET_CollectPageInfoW(LPCPROPSHEETPAGEW lppsp,
487 PropSheetInfo * psInfo,
490 DLGTEMPLATE* pTemplate;
496 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
497 psInfo->proppage[index].hwndPage = 0;
498 psInfo->proppage[index].isDirty = FALSE;
501 * Process property page flags.
503 dwFlags = lppsp->dwFlags;
504 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
505 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
506 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
508 /* as soon as we have a page with the help flag, set the sheet flag on */
509 if (psInfo->proppage[index].hasHelp)
510 psInfo->hasHelp = TRUE;
513 * Process page template.
515 if (dwFlags & PSP_DLGINDIRECT)
516 pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
519 HRSRC hResource = FindResourceW(lppsp->hInstance,
520 lppsp->u.pszTemplate,
522 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
524 pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
528 * Extract the size of the page and the caption.
533 p = (const WORD *)pTemplate;
535 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
537 /* DIALOGEX template */
541 p += 2; /* help ID */
542 p += 2; /* ext style */
547 /* DIALOG template */
550 p += 2; /* ext style */
556 width = (WORD)*p; p++;
557 height = (WORD)*p; p++;
559 /* remember the largest width and height */
560 if (width > psInfo->width)
561 psInfo->width = width;
563 if (height > psInfo->height)
564 psInfo->height = height;
576 p += lstrlenW( (LPCWSTR)p ) + 1;
590 p += lstrlenW( (LPCWSTR)p ) + 1;
594 /* Extract the caption */
595 psInfo->proppage[index].pszText = (LPCWSTR)p;
596 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
597 p += lstrlenW((LPCWSTR)p) + 1;
599 if (dwFlags & PSP_USETITLE)
603 static WCHAR pszNull[] = { '(','n','u','l','l',')',0 };
606 if ( !HIWORD( lppsp->pszTitle ) )
608 if (!LoadStringW( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,sizeof szTitle ))
611 FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
617 pTitle = lppsp->pszTitle;
619 len = strlenW(szTitle);
620 psInfo->proppage[index].pszText = COMCTL32_Alloc( (len+1)*sizeof (WCHAR) );
621 strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle);
625 * Build the image list for icons
627 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
630 int icon_cx = GetSystemMetrics(SM_CXSMICON);
631 int icon_cy = GetSystemMetrics(SM_CYSMICON);
633 if (dwFlags & PSP_USEICONID)
634 hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
635 icon_cx, icon_cy, LR_DEFAULTCOLOR);
637 hIcon = lppsp->u2.hIcon;
641 if (psInfo->hImageList == 0 )
642 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
644 ImageList_AddIcon(psInfo->hImageList, hIcon);
652 /******************************************************************************
653 * PROPSHEET_CreateDialog
655 * Creates the actual property sheet.
657 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
664 WORD resID = IDD_PROPSHEET;
667 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
670 if(!(hRes = FindResourceW(COMCTL32_hModule,
671 MAKEINTRESOURCEW(resID),
675 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
679 * Make a copy of the dialog template.
681 resSize = SizeofResource(COMCTL32_hModule, hRes);
683 temp = COMCTL32_Alloc(resSize);
688 memcpy(temp, template, resSize);
690 if (psInfo->useCallback)
691 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
693 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
694 ret = DialogBoxIndirectParamW(psInfo->ppshheader.hInstance,
695 (LPDLGTEMPLATEW) temp,
696 psInfo->ppshheader.hwndParent,
697 (DLGPROC) PROPSHEET_DialogProc,
700 ret = CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,
701 (LPDLGTEMPLATEW) temp,
702 psInfo->ppshheader.hwndParent,
703 (DLGPROC) PROPSHEET_DialogProc,
711 /******************************************************************************
712 * PROPSHEET_SizeMismatch
714 * Verify that the tab control and the "largest" property sheet page dlg. template
717 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
719 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
720 RECT rcOrigTab, rcPage;
725 GetClientRect(hwndTabCtrl, &rcOrigTab);
726 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
727 rcOrigTab.right, rcOrigTab.bottom);
732 rcPage.left = psInfo->x;
733 rcPage.top = psInfo->y;
734 rcPage.right = psInfo->width;
735 rcPage.bottom = psInfo->height;
737 MapDialogRect(hwndDlg, &rcPage);
738 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
739 rcPage.right, rcPage.bottom);
741 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
743 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
749 /******************************************************************************
750 * PROPSHEET_IsTooSmallWizard
752 * Verify that the default property sheet is big enough.
754 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
756 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
757 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
758 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
760 GetClientRect(hwndDlg, &rcSheetClient);
761 GetWindowRect(hwndDlg, &rcSheetRect);
762 GetWindowRect(hwndLine, &rcLine);
764 /* Remove the space below the sunken line */
765 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
767 /* Remove the buffer zone all around the edge */
768 rcSheetClient.bottom -= (padding.y * 2);
769 rcSheetClient.right -= (padding.x * 2);
774 rcPage.left = psInfo->x;
775 rcPage.top = psInfo->y;
776 rcPage.right = psInfo->width;
777 rcPage.bottom = psInfo->height;
779 MapDialogRect(hwndDlg, &rcPage);
780 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
781 rcPage.right, rcPage.bottom);
783 if (rcPage.right > rcSheetClient.right)
786 if (rcPage.bottom > rcSheetClient.bottom)
792 /******************************************************************************
793 * PROPSHEET_AdjustSize
795 * Resizes the property sheet and the tab control to fit the largest page.
797 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
799 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
800 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
802 int tabOffsetX, tabOffsetY, buttonHeight;
803 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
806 /* Get the height of buttons */
807 GetClientRect(hwndButton, &rc);
808 buttonHeight = rc.bottom;
815 rc.right = psInfo->width;
816 rc.bottom = psInfo->height;
818 MapDialogRect(hwndDlg, &rc);
820 /* retrieve the dialog units */
821 units.left = units.right = 4;
822 units.top = units.bottom = 8;
823 MapDialogRect(hwndDlg, &units);
826 * Resize the tab control.
828 GetClientRect(hwndTabCtrl,&tabRect);
830 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
832 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
834 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
835 psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
838 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
840 rc.right = rc.left + tabRect.right - tabRect.left;
841 psInfo->width = MulDiv((rc.right - rc.left),4,units.left);
844 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
846 tabOffsetX = -(rc.left);
847 tabOffsetY = -(rc.top);
851 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
852 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
854 GetClientRect(hwndTabCtrl, &rc);
856 TRACE("tab client rc %d %d %d %d\n",
857 rc.left, rc.top, rc.right, rc.bottom);
859 rc.right += ((padding.x * 2) + tabOffsetX);
860 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
863 * Resize the property sheet.
865 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
866 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
870 /******************************************************************************
871 * PROPSHEET_AdjustSizeWizard
873 * Resizes the property sheet to fit the largest page.
875 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
877 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
878 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
879 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
881 int buttonHeight, lineHeight;
882 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
885 /* Get the height of buttons */
886 GetClientRect(hwndButton, &rc);
887 buttonHeight = rc.bottom;
889 GetClientRect(hwndLine, &rc);
890 lineHeight = rc.bottom;
892 /* retrieve the dialog units */
893 units.left = units.right = 4;
894 units.top = units.bottom = 8;
895 MapDialogRect(hwndDlg, &units);
902 rc.right = psInfo->width;
903 rc.bottom = psInfo->height;
905 MapDialogRect(hwndDlg, &rc);
907 GetClientRect(hwndTabCtrl,&tabRect);
909 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
911 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
912 psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);
915 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
917 rc.right = rc.left + tabRect.right - tabRect.left;
918 psInfo->width = MulDiv((rc.right - rc.left), 4, units.left);
921 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
924 rc.right += (padding.x * 2);
925 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
928 * Resize the property sheet.
930 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
931 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
935 /******************************************************************************
936 * PROPSHEET_AdjustButtons
938 * Adjusts the buttons' positions.
940 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
942 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
946 int buttonWidth, buttonHeight;
947 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
949 if (psInfo->hasApply)
956 * Obtain the size of the buttons.
958 GetClientRect(hwndButton, &rcSheet);
959 buttonWidth = rcSheet.right;
960 buttonHeight = rcSheet.bottom;
963 * Get the size of the property sheet.
965 GetClientRect(hwndParent, &rcSheet);
968 * All buttons will be at this y coordinate.
970 y = rcSheet.bottom - (padding.y + buttonHeight);
973 * Position OK button.
975 hwndButton = GetDlgItem(hwndParent, IDOK);
977 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
979 SetWindowPos(hwndButton, 0, x, y, 0, 0,
980 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
983 * Position Cancel button.
985 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
987 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
989 SetWindowPos(hwndButton, 0, x, y, 0, 0,
990 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
993 * Position Apply button.
995 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
997 if (psInfo->hasApply)
1000 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
1002 x = rcSheet.right - (padding.x + buttonWidth);
1004 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1005 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1007 EnableWindow(hwndButton, FALSE);
1010 ShowWindow(hwndButton, SW_HIDE);
1013 * Position Help button.
1015 hwndButton = GetDlgItem(hwndParent, IDHELP);
1017 if (psInfo->hasHelp)
1019 x = rcSheet.right - (padding.x + buttonWidth);
1021 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1022 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1025 ShowWindow(hwndButton, SW_HIDE);
1030 /******************************************************************************
1031 * PROPSHEET_AdjustButtonsWizard
1033 * Adjusts the buttons' positions.
1035 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
1036 PropSheetInfo* psInfo)
1038 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
1039 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
1042 int num_buttons = 3;
1043 int buttonWidth, buttonHeight, lineHeight, lineWidth;
1044 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1046 if (psInfo->hasHelp)
1050 * Obtain the size of the buttons.
1052 GetClientRect(hwndButton, &rcSheet);
1053 buttonWidth = rcSheet.right;
1054 buttonHeight = rcSheet.bottom;
1056 GetClientRect(hwndLine, &rcSheet);
1057 lineHeight = rcSheet.bottom;
1060 * Get the size of the property sheet.
1062 GetClientRect(hwndParent, &rcSheet);
1065 * All buttons will be at this y coordinate.
1067 y = rcSheet.bottom - (padding.y + buttonHeight);
1070 * Position the Next and the Finish buttons.
1072 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
1074 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
1076 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1077 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1079 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
1081 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1082 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1084 ShowWindow(hwndButton, SW_HIDE);
1087 * Position the Back button.
1089 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
1093 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1094 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1097 * Position the Cancel button.
1099 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
1101 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
1103 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1104 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1107 * Position Help button.
1109 hwndButton = GetDlgItem(hwndParent, IDHELP);
1111 if (psInfo->hasHelp)
1113 x = rcSheet.right - (padding.x + buttonWidth);
1115 SetWindowPos(hwndButton, 0, x, y, 0, 0,
1116 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1119 ShowWindow(hwndButton, SW_HIDE);
1122 * Position and resize the sunken line.
1125 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
1127 GetClientRect(hwndParent, &rcSheet);
1128 lineWidth = rcSheet.right - (padding.x * 2);
1130 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
1131 SWP_NOZORDER | SWP_NOACTIVATE);
1136 /******************************************************************************
1137 * PROPSHEET_GetPaddingInfo
1139 * Returns the layout information.
1141 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
1143 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1146 PADDING_INFO padding;
1148 GetWindowRect(hwndTab, &rcTab);
1153 ScreenToClient(hwndDlg, &tl);
1161 /******************************************************************************
1162 * PROPSHEET_GetPaddingInfoWizard
1164 * Returns the layout information.
1165 * Vertical spacing is the distance between the line and the buttons.
1166 * Do NOT use the Help button to gather padding information when it isn't mapped
1167 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
1168 * for it in this case !
1169 * FIXME: I'm not sure about any other coordinate problems with these evil
1170 * buttons. Fix it in case additional problems appear or maybe calculate
1171 * a padding in a completely different way, as this is somewhat messy.
1173 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
1176 PADDING_INFO padding;
1180 POINT ptButton, ptLine;
1183 if (psInfo->hasHelp)
1189 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1191 idButton = IDC_NEXT_BUTTON;
1195 /* hopefully this is ok */
1196 idButton = IDCANCEL;
1200 hwndControl = GetDlgItem(hwndDlg, idButton);
1201 GetWindowRect(hwndControl, &rc);
1203 ptButton.x = rc.left;
1204 ptButton.y = rc.top;
1206 ScreenToClient(hwndDlg, &ptButton);
1209 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
1210 GetWindowRect(hwndControl, &rc);
1213 ptLine.y = rc.bottom;
1215 ScreenToClient(hwndDlg, &ptLine);
1217 padding.y = ptButton.y - ptLine.y;
1220 ERR("padding negative ! Please report this !\n");
1222 /* this is most probably not correct, but the best we have now */
1223 padding.x = padding.y;
1227 /******************************************************************************
1228 * PROPSHEET_CreateTabControl
1230 * Insert the tabs in the tab control.
1232 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
1233 PropSheetInfo * psInfo)
1235 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1241 item.mask = TCIF_TEXT;
1242 item.cchTextMax = MAX_TABTEXT_LENGTH;
1244 nTabs = psInfo->nPages;
1247 * Set the image list for icons.
1249 if (psInfo->hImageList)
1251 SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
1254 for (i = 0; i < nTabs; i++)
1256 if ( psInfo->proppage[i].hasIcon )
1258 item.mask |= TCIF_IMAGE;
1259 item.iImage = iImage++;
1263 item.mask &= ~TCIF_IMAGE;
1266 item.pszText = (LPWSTR) psInfo->proppage[i].pszText;
1267 SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item);
1273 /******************************************************************************
1274 * PROPSHEET_CreatePage
1278 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
1280 const PropSheetInfo * psInfo,
1281 LPCPROPSHEETPAGEW ppshpage)
1283 DLGTEMPLATE* pTemplate;
1286 PropPageInfo* ppInfo = psInfo->proppage;
1287 PADDING_INFO padding;
1288 UINT pageWidth,pageHeight;
1292 TRACE("index %d\n", index);
1294 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1295 pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
1301 hResource = FindResourceW(ppshpage->hInstance,
1302 ppshpage->u.pszTemplate,
1307 resSize = SizeofResource(ppshpage->hInstance, hResource);
1309 hTemplate = LoadResource(ppshpage->hInstance, hResource);
1313 pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
1315 * Make a copy of the dialog template to make it writable
1317 temp = COMCTL32_Alloc(resSize);
1321 memcpy(temp, pTemplate, resSize);
1325 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1327 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1328 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1329 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1330 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1331 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1332 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1333 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1337 pTemplate->style |= WS_CHILD | DS_CONTROL;
1338 pTemplate->style &= ~DS_MODALFRAME;
1339 pTemplate->style &= ~WS_CAPTION;
1340 pTemplate->style &= ~WS_SYSMENU;
1341 pTemplate->style &= ~WS_POPUP;
1342 pTemplate->style &= ~WS_DISABLED;
1343 pTemplate->style &= ~WS_VISIBLE;
1346 if (psInfo->proppage[index].useCallback)
1347 (*(ppshpage->pfnCallback))(hwndParent,
1349 (LPPROPSHEETPAGEW)ppshpage);
1351 hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,
1354 ppshpage->pfnDlgProc,
1356 /* Free a no more needed copy */
1358 COMCTL32_Free(temp);
1360 ppInfo[index].hwndPage = hwndPage;
1362 rc.left = psInfo->x;
1364 rc.right = psInfo->width;
1365 rc.bottom = psInfo->height;
1367 MapDialogRect(hwndParent, &rc);
1369 pageWidth = rc.right - rc.left;
1370 pageHeight = rc.bottom - rc.top;
1372 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1373 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1377 * Ask the Tab control to fit this page in.
1380 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1381 SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1382 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1385 SetWindowPos(hwndPage, HWND_TOP,
1386 rc.left + padding.x,
1388 pageWidth, pageHeight, 0);
1393 /******************************************************************************
1394 * PROPSHEET_ShowPage
1396 * Displays or creates the specified page.
1398 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1402 TRACE("active_page %d, index %d\n", psInfo->active_page, index);
1403 if (index == psInfo->active_page)
1405 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1406 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1410 if (psInfo->proppage[index].hwndPage == 0)
1412 LPCPROPSHEETPAGEW ppshpage;
1414 ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1415 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1418 if (psInfo->active_page != -1)
1419 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1421 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1423 /* Synchronize current selection with tab control
1424 * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1425 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1426 SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1428 psInfo->active_page = index;
1429 psInfo->activeValid = TRUE;
1434 /******************************************************************************
1437 static BOOL PROPSHEET_Back(HWND hwndDlg)
1442 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1446 TRACE("active_page %d\n", psInfo->active_page);
1447 if (psInfo->active_page < 0)
1450 psn.hdr.code = PSN_WIZBACK;
1451 psn.hdr.hwndFrom = hwndDlg;
1455 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1457 result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1461 if (psInfo->active_page > 0)
1463 res = PROPSHEET_CanSetCurSel(hwndDlg);
1466 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, -1, 0);
1473 /******************************************************************************
1476 static BOOL PROPSHEET_Next(HWND hwndDlg)
1480 LRESULT msgResult = 0;
1481 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1484 TRACE("active_page %d\n", psInfo->active_page);
1485 if (psInfo->active_page < 0)
1488 psn.hdr.code = PSN_WIZNEXT;
1489 psn.hdr.hwndFrom = hwndDlg;
1493 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1495 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1496 if (msgResult == -1)
1499 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1501 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 1, 0);
1507 /******************************************************************************
1510 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1514 LRESULT msgResult = 0;
1515 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1518 TRACE("active_page %d\n", psInfo->active_page);
1519 if (psInfo->active_page < 0)
1522 psn.hdr.code = PSN_WIZFINISH;
1523 psn.hdr.hwndFrom = hwndDlg;
1527 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1529 msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1531 TRACE("msg result %ld\n", msgResult);
1536 if (psInfo->isModeless)
1537 psInfo->activeValid = FALSE;
1539 EndDialog(hwndDlg, TRUE);
1544 /******************************************************************************
1547 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1553 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1556 TRACE("active_page %d\n", psInfo->active_page);
1557 if (psInfo->active_page < 0)
1560 psn.hdr.hwndFrom = hwndDlg;
1566 * Send PSN_KILLACTIVE to the current page.
1568 psn.hdr.code = PSN_KILLACTIVE;
1570 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1572 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1576 * Send PSN_APPLY to all pages.
1578 psn.hdr.code = PSN_APPLY;
1579 psn.lParam = lParam;
1581 for (i = 0; i < psInfo->nPages; i++)
1583 hwndPage = psInfo->proppage[i].hwndPage;
1586 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1587 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1594 psInfo->activeValid = FALSE;
1596 else if(psInfo->active_page >= 0)
1598 psn.hdr.code = PSN_SETACTIVE;
1600 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1601 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1607 /******************************************************************************
1610 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1612 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1618 TRACE("active_page %d\n", psInfo->active_page);
1619 if (psInfo->active_page < 0)
1622 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1623 psn.hdr.code = PSN_QUERYCANCEL;
1624 psn.hdr.hwndFrom = hwndDlg;
1628 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1631 psn.hdr.code = PSN_RESET;
1632 psn.lParam = lParam;
1634 for (i = 0; i < psInfo->nPages; i++)
1636 hwndPage = psInfo->proppage[i].hwndPage;
1639 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1642 if (psInfo->isModeless)
1644 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1645 psInfo->activeValid = FALSE;
1648 EndDialog(hwndDlg, FALSE);
1651 /******************************************************************************
1654 static void PROPSHEET_Help(HWND hwndDlg)
1656 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1661 TRACE("active_page %d\n", psInfo->active_page);
1662 if (psInfo->active_page < 0)
1665 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1666 psn.hdr.code = PSN_HELP;
1667 psn.hdr.hwndFrom = hwndDlg;
1671 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1674 /******************************************************************************
1677 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1680 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1684 if (!psInfo) return;
1686 * Set the dirty flag of this page.
1688 for (i = 0; i < psInfo->nPages; i++)
1690 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1691 psInfo->proppage[i].isDirty = TRUE;
1695 * Enable the Apply button.
1697 if (psInfo->hasApply)
1699 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1701 EnableWindow(hwndApplyBtn, TRUE);
1705 /******************************************************************************
1706 * PROPSHEET_UnChanged
1708 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1711 BOOL noPageDirty = TRUE;
1712 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1713 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1717 if ( !psInfo ) return;
1718 for (i = 0; i < psInfo->nPages; i++)
1720 /* set the specified page as clean */
1721 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1722 psInfo->proppage[i].isDirty = FALSE;
1724 /* look to see if there's any dirty pages */
1725 if (psInfo->proppage[i].isDirty)
1726 noPageDirty = FALSE;
1730 * Disable Apply button.
1733 EnableWindow(hwndApplyBtn, FALSE);
1736 /******************************************************************************
1737 * PROPSHEET_PressButton
1739 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1741 TRACE("buttonID %d\n", buttonID);
1744 case PSBTN_APPLYNOW:
1745 PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
1748 PROPSHEET_Back(hwndDlg);
1751 PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
1754 PROPSHEET_Finish(hwndDlg);
1757 PROPSHEET_DoCommand(hwndDlg, IDHELP);
1760 PROPSHEET_Next(hwndDlg);
1763 PROPSHEET_DoCommand(hwndDlg, IDOK);
1766 FIXME("Invalid button index %d\n", buttonID);
1771 /*************************************************************************
1772 * BOOL PROPSHEET_CanSetCurSel [Internal]
1774 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1777 * hwndDlg [I] handle to a Dialog hWnd
1780 * TRUE if Current Selection can change
1784 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1786 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1792 TRACE("active_page %d\n", psInfo->active_page);
1799 if (psInfo->active_page < 0)
1806 * Notify the current page.
1808 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1809 psn.hdr.code = PSN_KILLACTIVE;
1810 psn.hdr.hwndFrom = hwndDlg;
1814 res = !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1817 TRACE("<-- %d\n", res);
1821 /******************************************************************************
1822 * PROPSHEET_SetCurSel
1824 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1827 HPROPSHEETPAGE hpage
1830 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
1831 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1833 TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
1834 /* hpage takes precedence over index */
1836 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1838 if (index < 0 || index >= psInfo->nPages)
1840 TRACE("Could not find page to select!\n");
1848 psn.hdr.code = PSN_SETACTIVE;
1849 psn.hdr.hwndFrom = hwndDlg;
1853 if (!psInfo->proppage[index].hwndPage) {
1854 LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1855 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1858 result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1865 FIXME("Tried to skip before first property sheet page!\n");
1868 if (index >= psInfo->nPages) {
1869 FIXME("Tried to skip after last property sheet page!\n");
1870 index = psInfo->nPages-1;
1876 * Display the new page.
1878 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1880 if (psInfo->proppage[index].hasHelp)
1881 EnableWindow(hwndHelp, TRUE);
1883 EnableWindow(hwndHelp, FALSE);
1888 /******************************************************************************
1889 * PROPSHEET_SetTitleA
1891 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1893 if(HIWORD(lpszText))
1896 MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
1897 szTitle, sizeof szTitle);
1898 PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
1902 PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
1906 /******************************************************************************
1907 * PROPSHEET_SetTitleW
1909 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
1911 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
1914 TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText), dwStyle);
1915 if (HIWORD(lpszText) == 0) {
1916 if (!LoadStringW(psInfo->ppshheader.hInstance,
1917 LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))
1921 if (dwStyle & PSH_PROPTITLE)
1924 int lentitle = strlenW(lpszText);
1925 int lenprop = strlenW(psInfo->strPropertiesFor);
1927 dest = COMCTL32_Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
1928 strcpyW(dest, psInfo->strPropertiesFor);
1929 strcatW(dest, lpszText);
1931 SetWindowTextW(hwndDlg, dest);
1932 COMCTL32_Free(dest);
1935 SetWindowTextW(hwndDlg, lpszText);
1938 /******************************************************************************
1939 * PROPSHEET_SetFinishTextA
1941 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1943 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1945 TRACE("'%s'\n", lpszText);
1946 /* Set text, show and enable the Finish button */
1947 SetWindowTextA(hwndButton, lpszText);
1948 ShowWindow(hwndButton, SW_SHOW);
1949 EnableWindow(hwndButton, TRUE);
1951 /* Make it default pushbutton */
1952 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1954 /* Hide Back button */
1955 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1956 ShowWindow(hwndButton, SW_HIDE);
1958 /* Hide Next button */
1959 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1960 ShowWindow(hwndButton, SW_HIDE);
1963 /******************************************************************************
1964 * PROPSHEET_SetFinishTextW
1966 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
1968 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1970 TRACE("'%s'\n", debugstr_w(lpszText));
1971 /* Set text, show and enable the Finish button */
1972 SetWindowTextW(hwndButton, lpszText);
1973 ShowWindow(hwndButton, SW_SHOW);
1974 EnableWindow(hwndButton, TRUE);
1976 /* Make it default pushbutton */
1977 SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1979 /* Hide Back button */
1980 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1981 ShowWindow(hwndButton, SW_HIDE);
1983 /* Hide Next button */
1984 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1985 ShowWindow(hwndButton, SW_HIDE);
1988 /******************************************************************************
1989 * PROPSHEET_QuerySiblings
1991 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1992 WPARAM wParam, LPARAM lParam)
1996 LRESULT msgResult = 0;
1997 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2000 while ((i < psInfo->nPages) && (msgResult == 0))
2002 hwndPage = psInfo->proppage[i].hwndPage;
2003 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
2011 /******************************************************************************
2014 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
2015 HPROPSHEETPAGE hpage)
2017 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2019 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2021 LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
2023 TRACE("hpage %p\n", hpage);
2025 * Allocate and fill in a new PropPageInfo entry.
2027 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
2028 sizeof(PropPageInfo) *
2029 (psInfo->nPages + 1));
2030 if (!PROPSHEET_CollectPageInfoW(ppsp, psInfo, psInfo->nPages))
2033 psInfo->proppage[psInfo->nPages].hpage = hpage;
2035 if (ppsp->dwFlags & PSP_PREMATURE)
2037 /* Create the page but don't show it */
2038 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
2042 * Add a new tab to the tab control.
2044 item.mask = TCIF_TEXT;
2045 item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
2046 item.cchTextMax = MAX_TABTEXT_LENGTH;
2048 SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
2053 /* If it is the only page - show it */
2054 if(psInfo->nPages == 1)
2055 PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
2059 /******************************************************************************
2060 * PROPSHEET_RemovePage
2062 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
2064 HPROPSHEETPAGE hpage)
2066 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2068 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2069 PropPageInfo* oldPages;
2071 TRACE("index %d, hpage %p\n", index, hpage);
2075 oldPages = psInfo->proppage;
2077 * hpage takes precedence over index.
2081 index = PROPSHEET_GetPageIndex(hpage, psInfo);
2084 /* Make sure that index is within range */
2085 if (index < 0 || index >= psInfo->nPages)
2087 TRACE("Could not find page to remove!\n");
2091 TRACE("total pages %d removing page %d active page %d\n",
2092 psInfo->nPages, index, psInfo->active_page);
2094 * Check if we're removing the active page.
2096 if (index == psInfo->active_page)
2098 if (psInfo->nPages > 1)
2102 /* activate previous page */
2103 PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
2107 /* activate the next page */
2108 PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
2109 psInfo->active_page = index;
2114 psInfo->active_page = -1;
2115 if (!psInfo->isModeless)
2117 EndDialog(hwndDlg, FALSE);
2122 else if (index < psInfo->active_page)
2123 psInfo->active_page--;
2125 /* Destroy page dialog window */
2126 DestroyWindow(psInfo->proppage[index].hwndPage);
2128 /* Free page resources */
2129 if(psInfo->proppage[index].hpage)
2131 PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
2133 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
2134 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
2136 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
2139 /* Remove the tab */
2140 SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
2143 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
2146 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
2148 if (index < psInfo->nPages)
2149 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
2150 (psInfo->nPages - index) * sizeof(PropPageInfo));
2152 COMCTL32_Free(oldPages);
2157 /******************************************************************************
2158 * PROPSHEET_SetWizButtons
2160 * This code will work if (and assumes that) the Next button is on top of the
2161 * Finish button. ie. Finish comes after Next in the Z order.
2162 * This means make sure the dialog template reflects this.
2165 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
2167 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2168 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2169 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2171 TRACE("%ld\n", dwFlags);
2173 EnableWindow(hwndBack, FALSE);
2174 EnableWindow(hwndNext, FALSE);
2175 EnableWindow(hwndFinish, FALSE);
2177 if (dwFlags & PSWIZB_BACK)
2178 EnableWindow(hwndBack, TRUE);
2180 if (dwFlags & PSWIZB_NEXT)
2182 /* Hide the Finish button */
2183 ShowWindow(hwndFinish, SW_HIDE);
2185 /* Show and enable the Next button */
2186 ShowWindow(hwndNext, SW_SHOW);
2187 EnableWindow(hwndNext, TRUE);
2189 /* Set the Next button as the default pushbutton */
2190 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
2193 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
2195 /* Hide the Next button */
2196 ShowWindow(hwndNext, SW_HIDE);
2198 /* Show the Finish button */
2199 ShowWindow(hwndFinish, SW_SHOW);
2201 if (dwFlags & PSWIZB_FINISH)
2202 EnableWindow(hwndFinish, TRUE);
2204 /* Set the Finish button as the default pushbutton */
2205 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2209 /******************************************************************************
2210 * PROPSHEET_GetPageIndex
2212 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
2213 * the array of PropPageInfo.
2215 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
2220 TRACE("hpage %p\n", hpage);
2221 while ((index < psInfo->nPages) && (found == FALSE))
2223 if (psInfo->proppage[index].hpage == hpage)
2235 /******************************************************************************
2238 static void PROPSHEET_CleanUp(HWND hwndDlg)
2241 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg,
2245 if (!psInfo) return;
2246 if (HIWORD(psInfo->ppshheader.pszCaption))
2247 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
2249 for (i = 0; i < psInfo->nPages; i++)
2251 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
2253 if(psInfo->proppage[i].hwndPage)
2254 DestroyWindow(psInfo->proppage[i].hwndPage);
2258 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
2259 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
2261 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
2265 COMCTL32_Free(psInfo->proppage);
2266 COMCTL32_Free(psInfo->strPropertiesFor);
2267 ImageList_Destroy(psInfo->hImageList);
2269 GlobalFree((HGLOBAL)psInfo);
2272 /******************************************************************************
2273 * PropertySheet (COMCTL32.87)
2274 * PropertySheetA (COMCTL32.88)
2276 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
2279 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2280 sizeof(PropSheetInfo));
2284 TRACE("(%p)\n", lppsh);
2286 PROPSHEET_CollectSheetInfoA(lppsh, psInfo);
2288 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
2290 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
2292 for (n = i = 0; i < lppsh->nPages; i++, n++)
2294 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2295 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2298 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
2299 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
2302 if (!PROPSHEET_CollectPageInfoA((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
2305 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2306 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2312 bRet = PROPSHEET_CreateDialog(psInfo);
2317 /******************************************************************************
2318 * PropertySheetW (COMCTL32.89)
2320 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
2323 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2324 sizeof(PropSheetInfo));
2328 TRACE("(%p)\n", lppsh);
2330 PROPSHEET_CollectSheetInfoW(lppsh, psInfo);
2332 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
2334 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
2336 for (n = i = 0; i < lppsh->nPages; i++, n++)
2338 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2339 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2342 psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);
2343 pByte += ((LPPROPSHEETPAGEW)pByte)->dwSize;
2346 if (!PROPSHEET_CollectPageInfoW((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
2349 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2350 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2356 bRet = PROPSHEET_CreateDialog(psInfo);
2361 /******************************************************************************
2362 * CreatePropertySheetPage (COMCTL32.18)
2363 * CreatePropertySheetPageA (COMCTL32.19)
2365 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
2366 LPCPROPSHEETPAGEA lpPropSheetPage)
2368 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
2370 memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
2372 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
2374 ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,strlen(lpPropSheetPage->u.pszTemplate)+1 );
2375 strcpy( (char *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );
2377 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
2379 ppsp->u2.pszIcon = HeapAlloc( GetProcessHeap(), 0, strlen(lpPropSheetPage->u2.pszIcon)+1 );
2380 strcpy( (char *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon );
2383 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
2385 ppsp->pszTitle = HeapAlloc( GetProcessHeap(), 0, strlen(lpPropSheetPage->pszTitle)+1 );
2386 strcpy( (char *)ppsp->pszTitle, lpPropSheetPage->pszTitle );
2388 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
2389 ppsp->pszTitle = NULL;
2391 return (HPROPSHEETPAGE)ppsp;
2394 /******************************************************************************
2395 * CreatePropertySheetPageW (COMCTL32.20)
2397 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
2399 PROPSHEETPAGEW* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEW));
2401 memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));
2403 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
2405 int len = strlenW(lpPropSheetPage->u.pszTemplate);
2407 ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,(len+1)*sizeof (WCHAR) );
2408 strcpyW( (WCHAR *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );
2410 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
2412 int len = strlenW(lpPropSheetPage->u2.pszIcon);
2413 ppsp->u2.pszIcon = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
2414 strcpyW( (WCHAR *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon );
2417 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
2419 int len = strlenW(lpPropSheetPage->pszTitle);
2420 ppsp->pszTitle = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof (WCHAR) );
2421 strcpyW( (WCHAR *)ppsp->pszTitle, lpPropSheetPage->pszTitle );
2423 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
2424 ppsp->pszTitle = NULL;
2426 return (HPROPSHEETPAGE)ppsp;
2429 /******************************************************************************
2430 * DestroyPropertySheetPage (COMCTL32.24)
2432 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
2434 PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;
2439 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
2440 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
2442 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2443 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2445 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2446 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2448 COMCTL32_Free(hPropPage);
2453 /******************************************************************************
2454 * PROPSHEET_IsDialogMessage
2456 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2458 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
2461 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2464 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2467 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2469 if (!(dlgCode & DLGC_WANTMESSAGE))
2471 switch (lpMsg->wParam)
2474 if (GetKeyState(VK_SHIFT) & 0x8000)
2480 case VK_NEXT: new_page = 1; break;
2481 case VK_PRIOR: new_page = -1; break;
2487 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2489 new_page += psInfo->active_page;
2492 new_page = psInfo->nPages - 1;
2493 else if (new_page >= psInfo->nPages)
2496 PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
2503 return IsDialogMessageA(hwnd, lpMsg);
2506 /******************************************************************************
2507 * PROPSHEET_DoCommand
2509 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)
2515 case IDC_APPLY_BUTTON:
2517 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2519 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2524 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
2528 if (psInfo->restartWindows)
2529 result = ID_PSRESTARTWINDOWS;
2531 /* reboot system takes precedence over restart windows */
2532 if (psInfo->rebootSystem)
2533 result = ID_PSREBOOTSYSTEM;
2535 if (psInfo->isModeless)
2536 psInfo->activeValid = FALSE;
2538 EndDialog(hwnd, result);
2541 EnableWindow(hwndApplyBtn, FALSE);
2546 case IDC_BACK_BUTTON:
2547 PROPSHEET_Back(hwnd);
2550 case IDC_NEXT_BUTTON:
2551 PROPSHEET_Next(hwnd);
2554 case IDC_FINISH_BUTTON:
2555 PROPSHEET_Finish(hwnd);
2559 PROPSHEET_Cancel(hwnd, 0);
2563 PROPSHEET_Help(hwnd);
2570 /******************************************************************************
2571 * PROPSHEET_DialogProc
2574 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2576 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n",
2577 hwnd, uMsg, wParam, lParam);
2583 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2584 WCHAR* strCaption = (WCHAR*)COMCTL32_Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));
2585 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2586 LPCPROPSHEETPAGEW ppshpage;
2589 SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2592 * psInfo->hwnd is not being used by WINE code - it exists
2593 * for compatibility with "real" Windoze. The same about
2594 * SetWindowLong - WINE is only using the PropSheetInfoStr
2597 psInfo->hwnd = hwnd;
2598 SetWindowLongW(hwnd,DWL_USER,(LONG)psInfo);
2601 * Small icon in the title bar.
2603 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2604 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2607 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2608 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2610 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2611 hIcon = LoadImageW(psInfo->ppshheader.hInstance,
2612 psInfo->ppshheader.u.pszIcon,
2617 hIcon = psInfo->ppshheader.u.hIcon;
2619 SendMessageW(hwnd, WM_SETICON, 0, hIcon);
2622 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2623 SendMessageW(hwnd, WM_SETICON, 0, psInfo->ppshheader.u.hIcon);
2625 psInfo->strPropertiesFor = strCaption;
2627 GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2629 PROPSHEET_CreateTabControl(hwnd, psInfo);
2631 if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
2633 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2635 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2636 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2641 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2643 PROPSHEET_AdjustSize(hwnd, psInfo);
2644 PROPSHEET_AdjustButtons(hwnd, psInfo);
2648 if (psInfo->useCallback)
2649 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2650 PSCB_INITIALIZED, (LPARAM)0);
2652 idx = psInfo->active_page;
2653 ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage;
2654 psInfo->active_page = -1;
2656 PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
2658 /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
2659 * as some programs call TCM_GETCURSEL to get the current selection
2660 * from which to switch to the next page */
2661 SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2663 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2664 psInfo->ppshheader.hInstance)
2668 if (LoadStringW(psInfo->ppshheader.hInstance,
2669 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2670 PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);
2674 PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,
2675 psInfo->ppshheader.pszCaption);
2682 PROPSHEET_CleanUp(hwnd);
2686 PROPSHEET_Cancel(hwnd, 1);
2690 return PROPSHEET_DoCommand(hwnd, LOWORD(wParam));
2694 NMHDR* pnmh = (LPNMHDR) lParam;
2696 if (pnmh->code == TCN_SELCHANGE)
2698 int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2699 PROPSHEET_SetCurSel(hwnd, index, 1, 0);
2702 if(pnmh->code == TCN_SELCHANGING)
2704 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2705 SetWindowLongW(hwnd, DWL_MSGRESULT, !bRet);
2712 case PSM_GETCURRENTPAGEHWND:
2714 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
2718 if (psInfo->activeValid && psInfo->active_page != -1)
2719 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2721 SetWindowLongW(hwnd, DWL_MSGRESULT, hwndPage);
2727 PROPSHEET_Changed(hwnd, (HWND)wParam);
2731 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2734 case PSM_GETTABCONTROL:
2736 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2738 SetWindowLongW(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2747 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2748 if(msgResult != FALSE)
2750 msgResult = PROPSHEET_SetCurSel(hwnd,
2753 (HPROPSHEETPAGE)lParam);
2756 SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
2761 case PSM_CANCELTOCLOSE:
2763 WCHAR buf[MAX_BUTTONTEXT_LENGTH];
2764 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2765 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2767 EnableWindow(hwndCancel, FALSE);
2768 if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2769 SetWindowTextW(hwndOK, buf);
2774 case PSM_RESTARTWINDOWS:
2776 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
2779 psInfo->restartWindows = TRUE;
2783 case PSM_REBOOTSYSTEM:
2785 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
2788 psInfo->rebootSystem = TRUE;
2793 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2797 PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);
2802 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2804 SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
2809 case PSM_QUERYSIBLINGS:
2811 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2813 SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
2821 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2822 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2823 * on success or FALSE otherwise, as specified on MSDN Online.
2824 * Also see the MFC code for
2825 * CPropertySheet::AddPage(CPropertyPage* pPage).
2828 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2830 SetWindowLongW(hwnd, DWL_MSGRESULT, msgResult);
2835 case PSM_REMOVEPAGE:
2836 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2839 case PSM_ISDIALOGMESSAGE:
2841 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2842 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2846 case PSM_PRESSBUTTON:
2847 PROPSHEET_PressButton(hwnd, (int)wParam);
2850 case PSM_SETFINISHTEXTA:
2851 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2854 case PSM_SETWIZBUTTONS:
2855 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2858 case PSM_SETCURSELID:
2859 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2862 case PSM_SETFINISHTEXTW:
2863 PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);