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_CollectPageInfo(LPCPROPSHEETPAGEW lppsp
,
114 PropSheetInfo
* psInfo
,
116 static BOOL
PROPSHEET_CreateTabControl(HWND hwndParent
,
117 PropSheetInfo
* psInfo
);
118 static BOOL
PROPSHEET_CreatePage(HWND hwndParent
, int index
,
119 const PropSheetInfo
* psInfo
,
120 LPCPROPSHEETPAGEW ppshpage
);
121 static BOOL
PROPSHEET_ShowPage(HWND hwndDlg
, int index
, PropSheetInfo
* psInfo
);
122 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
);
123 static BOOL
PROPSHEET_Back(HWND hwndDlg
);
124 static BOOL
PROPSHEET_Next(HWND hwndDlg
);
125 static BOOL
PROPSHEET_Finish(HWND hwndDlg
);
126 static BOOL
PROPSHEET_Apply(HWND hwndDlg
, LPARAM lParam
);
127 static void PROPSHEET_Cancel(HWND hwndDlg
, LPARAM lParam
);
128 static void PROPSHEET_Help(HWND hwndDlg
);
129 static void PROPSHEET_Changed(HWND hwndDlg
, HWND hwndDirtyPage
);
130 static void PROPSHEET_UnChanged(HWND hwndDlg
, HWND hwndCleanPage
);
131 static void PROPSHEET_PressButton(HWND hwndDlg
, int buttonID
);
132 static void PROPSHEET_SetFinishTextA(HWND hwndDlg
, LPCSTR lpszText
);
133 static void PROPSHEET_SetFinishTextW(HWND hwndDlg
, LPCWSTR lpszText
);
134 static void PROPSHEET_SetTitleA(HWND hwndDlg
, DWORD dwStyle
, LPCSTR lpszText
);
135 static void PROPSHEET_SetTitleW(HWND hwndDlg
, DWORD dwStyle
, LPCWSTR lpszText
);
136 static BOOL
PROPSHEET_CanSetCurSel(HWND hwndDlg
);
137 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
140 HPROPSHEETPAGE hpage
);
141 static LRESULT
PROPSHEET_QuerySiblings(HWND hwndDlg
,
142 WPARAM wParam
, LPARAM lParam
);
143 static BOOL
PROPSHEET_AddPage(HWND hwndDlg
,
144 HPROPSHEETPAGE hpage
);
146 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
,
148 HPROPSHEETPAGE hpage
);
149 static void PROPSHEET_CleanUp();
150 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage
, PropSheetInfo
* psInfo
);
151 static void PROPSHEET_SetWizButtons(HWND hwndDlg
, DWORD dwFlags
);
152 static PADDING_INFO
PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg
, const PropSheetInfo
* psInfo
);
153 static BOOL
PROPSHEET_IsDialogMessage(HWND hwnd
, LPMSG lpMsg
);
154 static BOOL
PROPSHEET_DoCommand(HWND hwnd
, WORD wID
);
157 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
159 WINE_DEFAULT_DEBUG_CHANNEL(propsheet
);
161 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
162 /******************************************************************************
163 * PROPSHEET_UnImplementedFlags
165 * Document use of flags we don't implement yet.
167 static VOID
PROPSHEET_UnImplementedFlags(DWORD dwFlags
)
174 * unhandled header flags:
175 * PSH_DEFAULT 0x00000000
176 * PSH_WIZARDHASFINISH 0x00000010
177 * PSH_RTLREADING 0x00000800
178 * PSH_WIZARDCONTEXTHELP 0x00001000
179 * PSH_WIZARD97 0x00002000 (pre IE 5)
180 * PSH_WATERMARK 0x00008000
181 * PSH_USEHBMWATERMARK 0x00010000
182 * PSH_USEHPLWATERMARK 0x00020000
183 * PSH_STRETCHWATERMARK 0x00040000
184 * PSH_HEADER 0x00080000
185 * PSH_USEHBMHEADER 0x00100000
186 * PSH_USEPAGELANG 0x00200000
187 * PSH_WIZARD_LITE 0x00400000 also not in .h
188 * PSH_WIZARD97 0x01000000 (IE 5 and above)
189 * PSH_NOCONTEXTHELP 0x02000000 also not in .h
192 add_flag(PSH_WIZARDHASFINISH
);
193 add_flag(PSH_RTLREADING
);
194 add_flag(PSH_WIZARDCONTEXTHELP
);
195 add_flag(PSH_WIZARD97_OLD
);
196 add_flag(PSH_WATERMARK
);
197 add_flag(PSH_USEHBMWATERMARK
);
198 add_flag(PSH_USEHPLWATERMARK
);
199 add_flag(PSH_STRETCHWATERMARK
);
200 add_flag(PSH_HEADER
);
201 add_flag(PSH_USEHBMHEADER
);
202 add_flag(PSH_USEPAGELANG
);
203 add_flag(PSH_WIZARD_LITE
);
204 add_flag(PSH_WIZARD97_NEW
);
205 add_flag(PSH_NOCONTEXTHELP
);
206 if (string
[0] != '\0')
207 FIXME("%s\n", string
);
211 /******************************************************************************
212 * PROPSHEET_FindPageByResId
214 * Find page index corresponding to page resource id.
216 INT
PROPSHEET_FindPageByResId(PropSheetInfo
* psInfo
, LRESULT resId
)
220 for (i
= 0; i
< psInfo
->nPages
; i
++)
222 LPCPROPSHEETPAGEA lppsp
= (LPCPROPSHEETPAGEA
)psInfo
->proppage
[i
].hpage
;
224 /* Fixme: if resource ID is a string shall we use strcmp ??? */
225 if (lppsp
->u
.pszTemplate
== (LPVOID
)resId
)
232 /******************************************************************************
235 * Convert ASCII to Unicode since all data is saved as Unicode.
237 static void PROPSHEET_AtoW(LPCWSTR
*tostr
, LPCSTR frstr
)
241 TRACE("<%s>\n", frstr
);
242 len
= MultiByteToWideChar(CP_ACP
, 0, frstr
, -1, 0, 0);
243 *tostr
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
244 MultiByteToWideChar(CP_ACP
, 0, frstr
, -1, (LPWSTR
)*tostr
, len
);
247 /******************************************************************************
248 * PROPSHEET_CollectSheetInfoA
250 * Collect relevant data.
252 static BOOL
PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh
,
253 PropSheetInfo
* psInfo
)
255 DWORD dwSize
= min(lppsh
->dwSize
,sizeof(PROPSHEETHEADERA
));
256 DWORD dwFlags
= lppsh
->dwFlags
;
258 psInfo
->hasHelp
= dwFlags
& PSH_HASHELP
;
259 psInfo
->hasApply
= !(dwFlags
& PSH_NOAPPLYNOW
);
260 psInfo
->useCallback
= dwFlags
& PSH_USECALLBACK
;
261 psInfo
->isModeless
= dwFlags
& PSH_MODELESS
;
263 memcpy(&psInfo
->ppshheader
,lppsh
,dwSize
);
264 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",
265 lppsh
->dwSize
, lppsh
->dwFlags
, lppsh
->hwndParent
, lppsh
->hInstance
,
266 debugstr_a(lppsh
->pszCaption
), lppsh
->nPages
, lppsh
->pfnCallback
);
268 PROPSHEET_UnImplementedFlags(lppsh
->dwFlags
);
270 if (HIWORD(lppsh
->pszCaption
))
272 int len
= strlen(lppsh
->pszCaption
);
273 psInfo
->ppshheader
.pszCaption
= HeapAlloc( GetProcessHeap(), 0, (len
+1)*sizeof (WCHAR
) );
274 MultiByteToWideChar(CP_ACP
, 0, lppsh
->pszCaption
, -1, (LPWSTR
) psInfo
->ppshheader
.pszCaption
, len
+1);
275 /* strcpy( (char *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); */
277 psInfo
->nPages
= lppsh
->nPages
;
279 if (dwFlags
& PSH_USEPSTARTPAGE
)
281 TRACE("PSH_USEPSTARTPAGE is on");
282 psInfo
->active_page
= 0;
285 psInfo
->active_page
= lppsh
->u2
.nStartPage
;
287 if (psInfo
->active_page
< 0 || psInfo
->active_page
>= psInfo
->nPages
)
288 psInfo
->active_page
= 0;
290 psInfo
->restartWindows
= FALSE
;
291 psInfo
->rebootSystem
= FALSE
;
292 psInfo
->hImageList
= 0;
293 psInfo
->activeValid
= FALSE
;
298 /******************************************************************************
299 * PROPSHEET_CollectSheetInfoW
301 * Collect relevant data.
303 static BOOL
PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh
,
304 PropSheetInfo
* psInfo
)
306 DWORD dwSize
= min(lppsh
->dwSize
,sizeof(PROPSHEETHEADERW
));
307 DWORD dwFlags
= lppsh
->dwFlags
;
309 psInfo
->hasHelp
= dwFlags
& PSH_HASHELP
;
310 psInfo
->hasApply
= !(dwFlags
& PSH_NOAPPLYNOW
);
311 psInfo
->useCallback
= dwFlags
& PSH_USECALLBACK
;
312 psInfo
->isModeless
= dwFlags
& PSH_MODELESS
;
314 memcpy(&psInfo
->ppshheader
,lppsh
,dwSize
);
315 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",
316 lppsh
->dwSize
, lppsh
->dwFlags
, lppsh
->hwndParent
, lppsh
->hInstance
, debugstr_w(lppsh
->pszCaption
), lppsh
->nPages
, lppsh
->pfnCallback
);
318 PROPSHEET_UnImplementedFlags(lppsh
->dwFlags
);
320 if (HIWORD(lppsh
->pszCaption
))
322 int len
= strlenW(lppsh
->pszCaption
);
323 psInfo
->ppshheader
.pszCaption
= HeapAlloc( GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
) );
324 strcpyW( (WCHAR
*)psInfo
->ppshheader
.pszCaption
, lppsh
->pszCaption
);
326 psInfo
->nPages
= lppsh
->nPages
;
328 if (dwFlags
& PSH_USEPSTARTPAGE
)
330 TRACE("PSH_USEPSTARTPAGE is on");
331 psInfo
->active_page
= 0;
334 psInfo
->active_page
= lppsh
->u2
.nStartPage
;
336 if (psInfo
->active_page
< 0 || psInfo
->active_page
>= psInfo
->nPages
)
337 psInfo
->active_page
= 0;
339 psInfo
->restartWindows
= FALSE
;
340 psInfo
->rebootSystem
= FALSE
;
341 psInfo
->hImageList
= 0;
342 psInfo
->activeValid
= FALSE
;
347 /******************************************************************************
348 * PROPSHEET_CollectPageInfo
350 * Collect property sheet data.
351 * With code taken from DIALOG_ParseTemplate32.
353 BOOL
PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp
,
354 PropSheetInfo
* psInfo
,
357 DLGTEMPLATE
* pTemplate
;
363 psInfo
->proppage
[index
].hpage
= (HPROPSHEETPAGE
)lppsp
;
364 psInfo
->proppage
[index
].hwndPage
= 0;
365 psInfo
->proppage
[index
].isDirty
= FALSE
;
368 * Process property page flags.
370 dwFlags
= lppsp
->dwFlags
;
371 psInfo
->proppage
[index
].useCallback
= (dwFlags
& PSP_USECALLBACK
) && (lppsp
->pfnCallback
);
372 psInfo
->proppage
[index
].hasHelp
= dwFlags
& PSP_HASHELP
;
373 psInfo
->proppage
[index
].hasIcon
= dwFlags
& (PSP_USEHICON
| PSP_USEICONID
);
375 /* as soon as we have a page with the help flag, set the sheet flag on */
376 if (psInfo
->proppage
[index
].hasHelp
)
377 psInfo
->hasHelp
= TRUE
;
380 * Process page template.
382 if (dwFlags
& PSP_DLGINDIRECT
)
383 pTemplate
= (DLGTEMPLATE
*)lppsp
->u
.pResource
;
386 HRSRC hResource
= FindResourceW(lppsp
->hInstance
,
387 lppsp
->u
.pszTemplate
,
389 HGLOBAL hTemplate
= LoadResource(lppsp
->hInstance
,
391 pTemplate
= (LPDLGTEMPLATEW
)LockResource(hTemplate
);
395 * Extract the size of the page and the caption.
400 p
= (const WORD
*)pTemplate
;
402 if (((MyDLGTEMPLATEEX
*)pTemplate
)->signature
== 0xFFFF)
404 /* DIALOGEX template */
408 p
+= 2; /* help ID */
409 p
+= 2; /* ext style */
414 /* DIALOG template */
417 p
+= 2; /* ext style */
423 width
= (WORD
)*p
; p
++;
424 height
= (WORD
)*p
; p
++;
426 /* remember the largest width and height */
427 if (width
> psInfo
->width
)
428 psInfo
->width
= width
;
430 if (height
> psInfo
->height
)
431 psInfo
->height
= height
;
443 p
+= lstrlenW( (LPCWSTR
)p
) + 1;
457 p
+= lstrlenW( (LPCWSTR
)p
) + 1;
461 /* Extract the caption */
462 psInfo
->proppage
[index
].pszText
= (LPCWSTR
)p
;
463 TRACE("Tab %d %s\n",index
,debugstr_w((LPCWSTR
)p
));
464 p
+= lstrlenW((LPCWSTR
)p
) + 1;
466 if (dwFlags
& PSP_USETITLE
)
470 static WCHAR pszNull
[] = { '(','n','u','l','l',')',0 };
473 if ( !HIWORD( lppsp
->pszTitle
) )
475 if (!LoadStringW( lppsp
->hInstance
, (UINT
)lppsp
->pszTitle
,szTitle
,sizeof szTitle
))
478 FIXME("Could not load resource #%04x?\n",LOWORD(lppsp
->pszTitle
));
484 pTitle
= lppsp
->pszTitle
;
486 len
= strlenW(szTitle
);
487 psInfo
->proppage
[index
].pszText
= COMCTL32_Alloc( (len
+1)*sizeof (WCHAR
) );
488 strcpyW( (LPWSTR
)psInfo
->proppage
[index
].pszText
,pTitle
);
492 * Build the image list for icons
494 if ((dwFlags
& PSP_USEHICON
) || (dwFlags
& PSP_USEICONID
))
497 int icon_cx
= GetSystemMetrics(SM_CXSMICON
);
498 int icon_cy
= GetSystemMetrics(SM_CYSMICON
);
500 if (dwFlags
& PSP_USEICONID
)
501 hIcon
= LoadImageW(lppsp
->hInstance
, lppsp
->u2
.pszIcon
, IMAGE_ICON
,
502 icon_cx
, icon_cy
, LR_DEFAULTCOLOR
);
504 hIcon
= lppsp
->u2
.hIcon
;
508 if (psInfo
->hImageList
== 0 )
509 psInfo
->hImageList
= ImageList_Create(icon_cx
, icon_cy
, ILC_COLOR
, 1, 1);
511 ImageList_AddIcon(psInfo
->hImageList
, hIcon
);
519 /******************************************************************************
520 * PROPSHEET_CreateDialog
522 * Creates the actual property sheet.
524 BOOL
PROPSHEET_CreateDialog(PropSheetInfo
* psInfo
)
531 WORD resID
= IDD_PROPSHEET
;
534 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
537 if(!(hRes
= FindResourceW(COMCTL32_hModule
,
538 MAKEINTRESOURCEW(resID
),
542 if(!(template = (LPVOID
)LoadResource(COMCTL32_hModule
, hRes
)))
546 * Make a copy of the dialog template.
548 resSize
= SizeofResource(COMCTL32_hModule
, hRes
);
550 temp
= COMCTL32_Alloc(resSize
);
555 memcpy(temp
, template, resSize
);
557 if (psInfo
->useCallback
)
558 (*(psInfo
->ppshheader
.pfnCallback
))(0, PSCB_PRECREATE
, (LPARAM
)temp
);
560 if (!(psInfo
->ppshheader
.dwFlags
& PSH_MODELESS
))
561 ret
= DialogBoxIndirectParamW(psInfo
->ppshheader
.hInstance
,
562 (LPDLGTEMPLATEW
) temp
,
563 psInfo
->ppshheader
.hwndParent
,
564 (DLGPROC
) PROPSHEET_DialogProc
,
567 ret
= CreateDialogIndirectParamW(psInfo
->ppshheader
.hInstance
,
568 (LPDLGTEMPLATEW
) temp
,
569 psInfo
->ppshheader
.hwndParent
,
570 (DLGPROC
) PROPSHEET_DialogProc
,
578 /******************************************************************************
579 * PROPSHEET_SizeMismatch
581 * Verify that the tab control and the "largest" property sheet page dlg. template
584 static BOOL
PROPSHEET_SizeMismatch(HWND hwndDlg
, PropSheetInfo
* psInfo
)
586 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
587 RECT rcOrigTab
, rcPage
;
592 GetClientRect(hwndTabCtrl
, &rcOrigTab
);
593 TRACE("orig tab %d %d %d %d\n", rcOrigTab
.left
, rcOrigTab
.top
,
594 rcOrigTab
.right
, rcOrigTab
.bottom
);
599 rcPage
.left
= psInfo
->x
;
600 rcPage
.top
= psInfo
->y
;
601 rcPage
.right
= psInfo
->width
;
602 rcPage
.bottom
= psInfo
->height
;
604 MapDialogRect(hwndDlg
, &rcPage
);
605 TRACE("biggest page %d %d %d %d\n", rcPage
.left
, rcPage
.top
,
606 rcPage
.right
, rcPage
.bottom
);
608 if ( (rcPage
.right
- rcPage
.left
) != (rcOrigTab
.right
- rcOrigTab
.left
) )
610 if ( (rcPage
.bottom
- rcPage
.top
) != (rcOrigTab
.bottom
- rcOrigTab
.top
) )
616 /******************************************************************************
617 * PROPSHEET_IsTooSmallWizard
619 * Verify that the default property sheet is big enough.
621 static BOOL
PROPSHEET_IsTooSmallWizard(HWND hwndDlg
, PropSheetInfo
* psInfo
)
623 RECT rcSheetRect
, rcPage
, rcLine
, rcSheetClient
;
624 HWND hwndLine
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINE
);
625 PADDING_INFO padding
= PROPSHEET_GetPaddingInfoWizard(hwndDlg
, psInfo
);
627 GetClientRect(hwndDlg
, &rcSheetClient
);
628 GetWindowRect(hwndDlg
, &rcSheetRect
);
629 GetWindowRect(hwndLine
, &rcLine
);
631 /* Remove the space below the sunken line */
632 rcSheetClient
.bottom
-= (rcSheetRect
.bottom
- rcLine
.top
);
634 /* Remove the buffer zone all around the edge */
635 rcSheetClient
.bottom
-= (padding
.y
* 2);
636 rcSheetClient
.right
-= (padding
.x
* 2);
641 rcPage
.left
= psInfo
->x
;
642 rcPage
.top
= psInfo
->y
;
643 rcPage
.right
= psInfo
->width
;
644 rcPage
.bottom
= psInfo
->height
;
646 MapDialogRect(hwndDlg
, &rcPage
);
647 TRACE("biggest page %d %d %d %d\n", rcPage
.left
, rcPage
.top
,
648 rcPage
.right
, rcPage
.bottom
);
650 if (rcPage
.right
> rcSheetClient
.right
)
653 if (rcPage
.bottom
> rcSheetClient
.bottom
)
659 /******************************************************************************
660 * PROPSHEET_AdjustSize
662 * Resizes the property sheet and the tab control to fit the largest page.
664 static BOOL
PROPSHEET_AdjustSize(HWND hwndDlg
, PropSheetInfo
* psInfo
)
666 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
667 HWND hwndButton
= GetDlgItem(hwndDlg
, IDOK
);
669 int tabOffsetX
, tabOffsetY
, buttonHeight
;
670 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndDlg
);
673 /* Get the height of buttons */
674 GetClientRect(hwndButton
, &rc
);
675 buttonHeight
= rc
.bottom
;
682 rc
.right
= psInfo
->width
;
683 rc
.bottom
= psInfo
->height
;
685 MapDialogRect(hwndDlg
, &rc
);
687 /* retrieve the dialog units */
688 units
.left
= units
.right
= 4;
689 units
.top
= units
.bottom
= 8;
690 MapDialogRect(hwndDlg
, &units
);
693 * Resize the tab control.
695 GetClientRect(hwndTabCtrl
,&tabRect
);
697 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, FALSE
, (LPARAM
)&tabRect
);
699 if ((rc
.bottom
- rc
.top
) < (tabRect
.bottom
- tabRect
.top
))
701 rc
.bottom
= rc
.top
+ tabRect
.bottom
- tabRect
.top
;
702 psInfo
->height
= MulDiv((rc
.bottom
- rc
.top
),8,units
.top
);
705 if ((rc
.right
- rc
.left
) < (tabRect
.right
- tabRect
.left
))
707 rc
.right
= rc
.left
+ tabRect
.right
- tabRect
.left
;
708 psInfo
->width
= MulDiv((rc
.right
- rc
.left
),4,units
.left
);
711 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, TRUE
, (LPARAM
)&rc
);
713 tabOffsetX
= -(rc
.left
);
714 tabOffsetY
= -(rc
.top
);
718 SetWindowPos(hwndTabCtrl
, 0, 0, 0, rc
.right
, rc
.bottom
,
719 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
721 GetClientRect(hwndTabCtrl
, &rc
);
723 TRACE("tab client rc %d %d %d %d\n",
724 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
726 rc
.right
+= ((padding
.x
* 2) + tabOffsetX
);
727 rc
.bottom
+= (buttonHeight
+ (3 * padding
.y
) + tabOffsetY
);
730 * Resize the property sheet.
732 SetWindowPos(hwndDlg
, 0, 0, 0, rc
.right
, rc
.bottom
,
733 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
737 /******************************************************************************
738 * PROPSHEET_AdjustSizeWizard
740 * Resizes the property sheet to fit the largest page.
742 static BOOL
PROPSHEET_AdjustSizeWizard(HWND hwndDlg
, PropSheetInfo
* psInfo
)
744 HWND hwndButton
= GetDlgItem(hwndDlg
, IDCANCEL
);
745 HWND hwndLine
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINE
);
746 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
748 int buttonHeight
, lineHeight
;
749 PADDING_INFO padding
= PROPSHEET_GetPaddingInfoWizard(hwndDlg
, psInfo
);
752 /* Get the height of buttons */
753 GetClientRect(hwndButton
, &rc
);
754 buttonHeight
= rc
.bottom
;
756 GetClientRect(hwndLine
, &rc
);
757 lineHeight
= rc
.bottom
;
759 /* retrieve the dialog units */
760 units
.left
= units
.right
= 4;
761 units
.top
= units
.bottom
= 8;
762 MapDialogRect(hwndDlg
, &units
);
769 rc
.right
= psInfo
->width
;
770 rc
.bottom
= psInfo
->height
;
772 MapDialogRect(hwndDlg
, &rc
);
774 GetClientRect(hwndTabCtrl
,&tabRect
);
776 if ((rc
.bottom
- rc
.top
) < (tabRect
.bottom
- tabRect
.top
))
778 rc
.bottom
= rc
.top
+ tabRect
.bottom
- tabRect
.top
;
779 psInfo
->height
= MulDiv((rc
.bottom
- rc
.top
), 8, units
.top
);
782 if ((rc
.right
- rc
.left
) < (tabRect
.right
- tabRect
.left
))
784 rc
.right
= rc
.left
+ tabRect
.right
- tabRect
.left
;
785 psInfo
->width
= MulDiv((rc
.right
- rc
.left
), 4, units
.left
);
788 TRACE("Biggest page %d %d %d %d\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
791 rc
.right
+= (padding
.x
* 2);
792 rc
.bottom
+= (buttonHeight
+ (5 * padding
.y
) + lineHeight
);
795 * Resize the property sheet.
797 SetWindowPos(hwndDlg
, 0, 0, 0, rc
.right
, rc
.bottom
,
798 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
802 /******************************************************************************
803 * PROPSHEET_AdjustButtons
805 * Adjusts the buttons' positions.
807 static BOOL
PROPSHEET_AdjustButtons(HWND hwndParent
, PropSheetInfo
* psInfo
)
809 HWND hwndButton
= GetDlgItem(hwndParent
, IDOK
);
813 int buttonWidth
, buttonHeight
;
814 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndParent
);
816 if (psInfo
->hasApply
)
823 * Obtain the size of the buttons.
825 GetClientRect(hwndButton
, &rcSheet
);
826 buttonWidth
= rcSheet
.right
;
827 buttonHeight
= rcSheet
.bottom
;
830 * Get the size of the property sheet.
832 GetClientRect(hwndParent
, &rcSheet
);
835 * All buttons will be at this y coordinate.
837 y
= rcSheet
.bottom
- (padding
.y
+ buttonHeight
);
840 * Position OK button.
842 hwndButton
= GetDlgItem(hwndParent
, IDOK
);
844 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * num_buttons
);
846 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
847 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
850 * Position Cancel button.
852 hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
854 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * (num_buttons
- 1));
856 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
857 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
860 * Position Apply button.
862 hwndButton
= GetDlgItem(hwndParent
, IDC_APPLY_BUTTON
);
864 if (psInfo
->hasApply
)
867 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * 2);
869 x
= rcSheet
.right
- (padding
.x
+ buttonWidth
);
871 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
872 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
874 EnableWindow(hwndButton
, FALSE
);
877 ShowWindow(hwndButton
, SW_HIDE
);
880 * Position Help button.
882 hwndButton
= GetDlgItem(hwndParent
, IDHELP
);
886 x
= rcSheet
.right
- (padding
.x
+ buttonWidth
);
888 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
889 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
892 ShowWindow(hwndButton
, SW_HIDE
);
897 /******************************************************************************
898 * PROPSHEET_AdjustButtonsWizard
900 * Adjusts the buttons' positions.
902 static BOOL
PROPSHEET_AdjustButtonsWizard(HWND hwndParent
,
903 PropSheetInfo
* psInfo
)
905 HWND hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
906 HWND hwndLine
= GetDlgItem(hwndParent
, IDC_SUNKEN_LINE
);
910 int buttonWidth
, buttonHeight
, lineHeight
, lineWidth
;
911 PADDING_INFO padding
= PROPSHEET_GetPaddingInfoWizard(hwndParent
, psInfo
);
917 * Obtain the size of the buttons.
919 GetClientRect(hwndButton
, &rcSheet
);
920 buttonWidth
= rcSheet
.right
;
921 buttonHeight
= rcSheet
.bottom
;
923 GetClientRect(hwndLine
, &rcSheet
);
924 lineHeight
= rcSheet
.bottom
;
927 * Get the size of the property sheet.
929 GetClientRect(hwndParent
, &rcSheet
);
932 * All buttons will be at this y coordinate.
934 y
= rcSheet
.bottom
- (padding
.y
+ buttonHeight
);
937 * Position the Next and the Finish buttons.
939 hwndButton
= GetDlgItem(hwndParent
, IDC_NEXT_BUTTON
);
941 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * (num_buttons
- 1));
943 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
944 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
946 hwndButton
= GetDlgItem(hwndParent
, IDC_FINISH_BUTTON
);
948 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
949 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
951 ShowWindow(hwndButton
, SW_HIDE
);
954 * Position the Back button.
956 hwndButton
= GetDlgItem(hwndParent
, IDC_BACK_BUTTON
);
960 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
961 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
964 * Position the Cancel button.
966 hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
968 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * (num_buttons
- 2));
970 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
971 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
974 * Position Help button.
976 hwndButton
= GetDlgItem(hwndParent
, IDHELP
);
980 x
= rcSheet
.right
- (padding
.x
+ buttonWidth
);
982 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
983 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
986 ShowWindow(hwndButton
, SW_HIDE
);
989 * Position and resize the sunken line.
992 y
= rcSheet
.bottom
- ((padding
.y
* 2) + buttonHeight
+ lineHeight
);
994 GetClientRect(hwndParent
, &rcSheet
);
995 lineWidth
= rcSheet
.right
- (padding
.x
* 2);
997 SetWindowPos(hwndLine
, 0, x
, y
, lineWidth
, 2,
998 SWP_NOZORDER
| SWP_NOACTIVATE
);
1003 /******************************************************************************
1004 * PROPSHEET_GetPaddingInfo
1006 * Returns the layout information.
1008 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
)
1010 HWND hwndTab
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1013 PADDING_INFO padding
;
1015 GetWindowRect(hwndTab
, &rcTab
);
1020 ScreenToClient(hwndDlg
, &tl
);
1028 /******************************************************************************
1029 * PROPSHEET_GetPaddingInfoWizard
1031 * Returns the layout information.
1032 * Vertical spacing is the distance between the line and the buttons.
1033 * Do NOT use the Help button to gather padding information when it isn't mapped
1034 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
1035 * for it in this case !
1036 * FIXME: I'm not sure about any other coordinate problems with these evil
1037 * buttons. Fix it in case additional problems appear or maybe calculate
1038 * a padding in a completely different way, as this is somewhat messy.
1040 static PADDING_INFO
PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg
, const PropSheetInfo
*
1043 PADDING_INFO padding
;
1047 POINT ptButton
, ptLine
;
1050 if (psInfo
->hasHelp
)
1056 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
1058 idButton
= IDC_NEXT_BUTTON
;
1062 /* hopefully this is ok */
1063 idButton
= IDCANCEL
;
1067 hwndControl
= GetDlgItem(hwndDlg
, idButton
);
1068 GetWindowRect(hwndControl
, &rc
);
1070 ptButton
.x
= rc
.left
;
1071 ptButton
.y
= rc
.top
;
1073 ScreenToClient(hwndDlg
, &ptButton
);
1076 hwndControl
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINE
);
1077 GetWindowRect(hwndControl
, &rc
);
1080 ptLine
.y
= rc
.bottom
;
1082 ScreenToClient(hwndDlg
, &ptLine
);
1084 padding
.y
= ptButton
.y
- ptLine
.y
;
1087 ERR("padding negative ! Please report this !\n");
1089 /* this is most probably not correct, but the best we have now */
1090 padding
.x
= padding
.y
;
1094 /******************************************************************************
1095 * PROPSHEET_CreateTabControl
1097 * Insert the tabs in the tab control.
1099 static BOOL
PROPSHEET_CreateTabControl(HWND hwndParent
,
1100 PropSheetInfo
* psInfo
)
1102 HWND hwndTabCtrl
= GetDlgItem(hwndParent
, IDC_TABCONTROL
);
1108 item
.mask
= TCIF_TEXT
;
1109 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
1111 nTabs
= psInfo
->nPages
;
1114 * Set the image list for icons.
1116 if (psInfo
->hImageList
)
1118 SendMessageW(hwndTabCtrl
, TCM_SETIMAGELIST
, 0, (LPARAM
)psInfo
->hImageList
);
1121 for (i
= 0; i
< nTabs
; i
++)
1123 if ( psInfo
->proppage
[i
].hasIcon
)
1125 item
.mask
|= TCIF_IMAGE
;
1126 item
.iImage
= iImage
++;
1130 item
.mask
&= ~TCIF_IMAGE
;
1133 item
.pszText
= (LPWSTR
) psInfo
->proppage
[i
].pszText
;
1134 SendMessageW(hwndTabCtrl
, TCM_INSERTITEMW
, (WPARAM
)i
, (LPARAM
)&item
);
1140 /******************************************************************************
1141 * PROPSHEET_CreatePage
1145 static BOOL
PROPSHEET_CreatePage(HWND hwndParent
,
1147 const PropSheetInfo
* psInfo
,
1148 LPCPROPSHEETPAGEW ppshpage
)
1150 DLGTEMPLATE
* pTemplate
;
1153 PropPageInfo
* ppInfo
= psInfo
->proppage
;
1154 PADDING_INFO padding
;
1155 UINT pageWidth
,pageHeight
;
1159 TRACE("index %d\n", index
);
1161 if (ppshpage
== NULL
)
1166 if (ppshpage
->dwFlags
& PSP_DLGINDIRECT
)
1167 pTemplate
= (DLGTEMPLATE
*)ppshpage
->u
.pResource
;
1173 hResource
= FindResourceW(ppshpage
->hInstance
,
1174 ppshpage
->u
.pszTemplate
,
1179 resSize
= SizeofResource(ppshpage
->hInstance
, hResource
);
1181 hTemplate
= LoadResource(ppshpage
->hInstance
, hResource
);
1185 pTemplate
= (LPDLGTEMPLATEW
)LockResource(hTemplate
);
1187 * Make a copy of the dialog template to make it writable
1189 temp
= COMCTL32_Alloc(resSize
);
1193 memcpy(temp
, pTemplate
, resSize
);
1197 if (((MyDLGTEMPLATEEX
*)pTemplate
)->signature
== 0xFFFF)
1199 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
|= WS_CHILD
| DS_CONTROL
;
1200 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~DS_MODALFRAME
;
1201 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_CAPTION
;
1202 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_SYSMENU
;
1203 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_POPUP
;
1204 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_DISABLED
;
1205 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_VISIBLE
;
1206 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_THICKFRAME
;
1210 pTemplate
->style
|= WS_CHILD
| DS_CONTROL
;
1211 pTemplate
->style
&= ~DS_MODALFRAME
;
1212 pTemplate
->style
&= ~WS_CAPTION
;
1213 pTemplate
->style
&= ~WS_SYSMENU
;
1214 pTemplate
->style
&= ~WS_POPUP
;
1215 pTemplate
->style
&= ~WS_DISABLED
;
1216 pTemplate
->style
&= ~WS_VISIBLE
;
1217 pTemplate
->style
&= ~WS_THICKFRAME
;
1220 if (psInfo
->proppage
[index
].useCallback
)
1221 (*(ppshpage
->pfnCallback
))(hwndParent
,
1223 (LPPROPSHEETPAGEW
)ppshpage
);
1225 hwndPage
= CreateDialogIndirectParamW(ppshpage
->hInstance
,
1228 ppshpage
->pfnDlgProc
,
1230 /* Free a no more needed copy */
1232 COMCTL32_Free(temp
);
1234 ppInfo
[index
].hwndPage
= hwndPage
;
1236 rc
.left
= psInfo
->x
;
1238 rc
.right
= psInfo
->width
;
1239 rc
.bottom
= psInfo
->height
;
1241 MapDialogRect(hwndParent
, &rc
);
1243 pageWidth
= rc
.right
- rc
.left
;
1244 pageHeight
= rc
.bottom
- rc
.top
;
1246 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
1247 padding
= PROPSHEET_GetPaddingInfoWizard(hwndParent
, psInfo
);
1251 * Ask the Tab control to fit this page in.
1254 HWND hwndTabCtrl
= GetDlgItem(hwndParent
, IDC_TABCONTROL
);
1255 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, FALSE
, (LPARAM
)&rc
);
1256 padding
= PROPSHEET_GetPaddingInfo(hwndParent
);
1259 SetWindowPos(hwndPage
, HWND_TOP
,
1260 rc
.left
+ padding
.x
/2,
1261 rc
.top
+ padding
.y
/2,
1262 pageWidth
, pageHeight
, 0);
1267 /******************************************************************************
1268 * PROPSHEET_ShowPage
1270 * Displays or creates the specified page.
1272 static BOOL
PROPSHEET_ShowPage(HWND hwndDlg
, int index
, PropSheetInfo
* psInfo
)
1276 TRACE("active_page %d, index %d\n", psInfo
->active_page
, index
);
1277 if (index
== psInfo
->active_page
)
1279 if (GetTopWindow(hwndDlg
) != psInfo
->proppage
[index
].hwndPage
)
1280 SetWindowPos(psInfo
->proppage
[index
].hwndPage
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
);
1284 if (psInfo
->proppage
[index
].hwndPage
== 0)
1286 LPCPROPSHEETPAGEW ppshpage
;
1288 ppshpage
= (LPCPROPSHEETPAGEW
)psInfo
->proppage
[index
].hpage
;
1289 PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, ppshpage
);
1292 if (psInfo
->active_page
!= -1)
1293 ShowWindow(psInfo
->proppage
[psInfo
->active_page
].hwndPage
, SW_HIDE
);
1295 ShowWindow(psInfo
->proppage
[index
].hwndPage
, SW_SHOW
);
1297 /* Synchronize current selection with tab control
1298 * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1299 hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1300 SendMessageW(hwndTabCtrl
, TCM_SETCURSEL
, index
, 0);
1302 psInfo
->active_page
= index
;
1303 psInfo
->activeValid
= TRUE
;
1308 /******************************************************************************
1311 static BOOL
PROPSHEET_Back(HWND hwndDlg
)
1316 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1321 TRACE("active_page %d\n", psInfo
->active_page
);
1322 if (psInfo
->active_page
< 0)
1325 psn
.hdr
.code
= PSN_WIZBACK
;
1326 psn
.hdr
.hwndFrom
= hwndDlg
;
1330 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1332 result
= SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1335 else if (result
== 0)
1336 idx
= psInfo
->active_page
- 1;
1338 idx
= PROPSHEET_FindPageByResId(psInfo
, result
);
1340 if (idx
>= 0 && idx
< psInfo
->nPages
)
1342 if (PROPSHEET_CanSetCurSel(hwndDlg
))
1343 PROPSHEET_SetCurSel(hwndDlg
, idx
, -1, 0);
1348 /******************************************************************************
1351 static BOOL
PROPSHEET_Next(HWND hwndDlg
)
1355 LRESULT msgResult
= 0;
1356 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1360 TRACE("active_page %d\n", psInfo
->active_page
);
1361 if (psInfo
->active_page
< 0)
1364 psn
.hdr
.code
= PSN_WIZNEXT
;
1365 psn
.hdr
.hwndFrom
= hwndDlg
;
1369 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1371 msgResult
= SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1372 if (msgResult
== -1)
1374 else if (msgResult
== 0)
1375 idx
= psInfo
->active_page
+ 1;
1377 idx
= PROPSHEET_FindPageByResId(psInfo
, msgResult
);
1379 if (idx
< psInfo
->nPages
)
1381 if (PROPSHEET_CanSetCurSel(hwndDlg
) != FALSE
)
1382 PROPSHEET_SetCurSel(hwndDlg
, idx
, 1, 0);
1388 /******************************************************************************
1391 static BOOL
PROPSHEET_Finish(HWND hwndDlg
)
1395 LRESULT msgResult
= 0;
1396 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1399 TRACE("active_page %d\n", psInfo
->active_page
);
1400 if (psInfo
->active_page
< 0)
1403 psn
.hdr
.code
= PSN_WIZFINISH
;
1404 psn
.hdr
.hwndFrom
= hwndDlg
;
1408 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1410 msgResult
= SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1412 TRACE("msg result %ld\n", msgResult
);
1417 if (psInfo
->isModeless
)
1418 psInfo
->activeValid
= FALSE
;
1420 EndDialog(hwndDlg
, TRUE
);
1425 /******************************************************************************
1428 static BOOL
PROPSHEET_Apply(HWND hwndDlg
, LPARAM lParam
)
1434 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1437 TRACE("active_page %d\n", psInfo
->active_page
);
1438 if (psInfo
->active_page
< 0)
1441 psn
.hdr
.hwndFrom
= hwndDlg
;
1447 * Send PSN_KILLACTIVE to the current page.
1449 psn
.hdr
.code
= PSN_KILLACTIVE
;
1451 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1453 if (SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
) != FALSE
)
1457 * Send PSN_APPLY to all pages.
1459 psn
.hdr
.code
= PSN_APPLY
;
1460 psn
.lParam
= lParam
;
1462 for (i
= 0; i
< psInfo
->nPages
; i
++)
1464 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
1467 msgResult
= SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1468 if (msgResult
== PSNRET_INVALID_NOCHANGEPAGE
)
1475 psInfo
->activeValid
= FALSE
;
1477 else if(psInfo
->active_page
>= 0)
1479 psn
.hdr
.code
= PSN_SETACTIVE
;
1481 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1482 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1488 /******************************************************************************
1491 static void PROPSHEET_Cancel(HWND hwndDlg
, LPARAM lParam
)
1493 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1499 TRACE("active_page %d\n", psInfo
->active_page
);
1500 if (psInfo
->active_page
< 0)
1503 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1504 psn
.hdr
.code
= PSN_QUERYCANCEL
;
1505 psn
.hdr
.hwndFrom
= hwndDlg
;
1509 if (SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
))
1512 psn
.hdr
.code
= PSN_RESET
;
1513 psn
.lParam
= lParam
;
1515 for (i
= 0; i
< psInfo
->nPages
; i
++)
1517 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
1520 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1523 if (psInfo
->isModeless
)
1525 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1526 psInfo
->activeValid
= FALSE
;
1529 EndDialog(hwndDlg
, FALSE
);
1532 /******************************************************************************
1535 static void PROPSHEET_Help(HWND hwndDlg
)
1537 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1542 TRACE("active_page %d\n", psInfo
->active_page
);
1543 if (psInfo
->active_page
< 0)
1546 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1547 psn
.hdr
.code
= PSN_HELP
;
1548 psn
.hdr
.hwndFrom
= hwndDlg
;
1552 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1555 /******************************************************************************
1558 static void PROPSHEET_Changed(HWND hwndDlg
, HWND hwndDirtyPage
)
1561 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1565 if (!psInfo
) return;
1567 * Set the dirty flag of this page.
1569 for (i
= 0; i
< psInfo
->nPages
; i
++)
1571 if (psInfo
->proppage
[i
].hwndPage
== hwndDirtyPage
)
1572 psInfo
->proppage
[i
].isDirty
= TRUE
;
1576 * Enable the Apply button.
1578 if (psInfo
->hasApply
)
1580 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
1582 EnableWindow(hwndApplyBtn
, TRUE
);
1586 /******************************************************************************
1587 * PROPSHEET_UnChanged
1589 static void PROPSHEET_UnChanged(HWND hwndDlg
, HWND hwndCleanPage
)
1592 BOOL noPageDirty
= TRUE
;
1593 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
1594 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1598 if ( !psInfo
) return;
1599 for (i
= 0; i
< psInfo
->nPages
; i
++)
1601 /* set the specified page as clean */
1602 if (psInfo
->proppage
[i
].hwndPage
== hwndCleanPage
)
1603 psInfo
->proppage
[i
].isDirty
= FALSE
;
1605 /* look to see if there's any dirty pages */
1606 if (psInfo
->proppage
[i
].isDirty
)
1607 noPageDirty
= FALSE
;
1611 * Disable Apply button.
1614 EnableWindow(hwndApplyBtn
, FALSE
);
1617 /******************************************************************************
1618 * PROPSHEET_PressButton
1620 static void PROPSHEET_PressButton(HWND hwndDlg
, int buttonID
)
1622 TRACE("buttonID %d\n", buttonID
);
1625 case PSBTN_APPLYNOW
:
1626 PROPSHEET_DoCommand(hwndDlg
, IDC_APPLY_BUTTON
);
1629 PROPSHEET_Back(hwndDlg
);
1632 PROPSHEET_DoCommand(hwndDlg
, IDCANCEL
);
1635 PROPSHEET_Finish(hwndDlg
);
1638 PROPSHEET_DoCommand(hwndDlg
, IDHELP
);
1641 PROPSHEET_Next(hwndDlg
);
1644 PROPSHEET_DoCommand(hwndDlg
, IDOK
);
1647 FIXME("Invalid button index %d\n", buttonID
);
1652 /*************************************************************************
1653 * BOOL PROPSHEET_CanSetCurSel [Internal]
1655 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1658 * hwndDlg [I] handle to a Dialog hWnd
1661 * TRUE if Current Selection can change
1665 static BOOL
PROPSHEET_CanSetCurSel(HWND hwndDlg
)
1667 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1673 TRACE("active_page %d\n", psInfo
->active_page
);
1680 if (psInfo
->active_page
< 0)
1687 * Notify the current page.
1689 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1690 psn
.hdr
.code
= PSN_KILLACTIVE
;
1691 psn
.hdr
.hwndFrom
= hwndDlg
;
1695 res
= !SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1698 TRACE("<-- %d\n", res
);
1702 /******************************************************************************
1703 * PROPSHEET_SetCurSel
1705 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
1708 HPROPSHEETPAGE hpage
1711 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
, PropSheetInfoStr
);
1712 HWND hwndHelp
= GetDlgItem(hwndDlg
, IDHELP
);
1714 TRACE("index %d, skipdir %d, hpage %p\n", index
, skipdir
, hpage
);
1715 /* hpage takes precedence over index */
1717 index
= PROPSHEET_GetPageIndex(hpage
, psInfo
);
1719 if (index
< 0 || index
>= psInfo
->nPages
)
1721 TRACE("Could not find page to select!\n");
1729 psn
.hdr
.code
= PSN_SETACTIVE
;
1730 psn
.hdr
.hwndFrom
= hwndDlg
;
1734 if (!psInfo
->proppage
[index
].hwndPage
) {
1735 LPCPROPSHEETPAGEW ppshpage
= (LPCPROPSHEETPAGEW
)psInfo
->proppage
[index
].hpage
;
1736 PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, ppshpage
);
1739 result
= SendMessageW(psInfo
->proppage
[index
].hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1746 FIXME("Tried to skip before first property sheet page!\n");
1749 if (index
>= psInfo
->nPages
) {
1750 FIXME("Tried to skip after last property sheet page!\n");
1751 index
= psInfo
->nPages
-1;
1755 else if (result
!= 0)
1757 index
= PROPSHEET_FindPageByResId(psInfo
, result
);
1762 * Display the new page.
1764 PROPSHEET_ShowPage(hwndDlg
, index
, psInfo
);
1766 if (psInfo
->proppage
[index
].hasHelp
)
1767 EnableWindow(hwndHelp
, TRUE
);
1769 EnableWindow(hwndHelp
, FALSE
);
1774 /******************************************************************************
1775 * PROPSHEET_SetTitleA
1777 static void PROPSHEET_SetTitleA(HWND hwndDlg
, DWORD dwStyle
, LPCSTR lpszText
)
1779 if(HIWORD(lpszText
))
1782 MultiByteToWideChar(CP_ACP
, 0, lpszText
, -1,
1783 szTitle
, sizeof szTitle
);
1784 PROPSHEET_SetTitleW(hwndDlg
, dwStyle
, szTitle
);
1788 PROPSHEET_SetTitleW(hwndDlg
, dwStyle
, (LPCWSTR
)lpszText
);
1792 /******************************************************************************
1793 * PROPSHEET_SetTitleW
1795 static void PROPSHEET_SetTitleW(HWND hwndDlg
, DWORD dwStyle
, LPCWSTR lpszText
)
1797 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
, PropSheetInfoStr
);
1800 TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText
), dwStyle
);
1801 if (HIWORD(lpszText
) == 0) {
1802 if (!LoadStringW(psInfo
->ppshheader
.hInstance
,
1803 LOWORD(lpszText
), szTitle
, sizeof(szTitle
)-sizeof(WCHAR
)))
1807 if (dwStyle
& PSH_PROPTITLE
)
1810 int lentitle
= strlenW(lpszText
);
1811 int lenprop
= strlenW(psInfo
->strPropertiesFor
);
1813 dest
= COMCTL32_Alloc( (lentitle
+ lenprop
+ 1)*sizeof (WCHAR
));
1814 strcpyW(dest
, psInfo
->strPropertiesFor
);
1815 strcatW(dest
, lpszText
);
1817 SetWindowTextW(hwndDlg
, dest
);
1818 COMCTL32_Free(dest
);
1821 SetWindowTextW(hwndDlg
, lpszText
);
1824 /******************************************************************************
1825 * PROPSHEET_SetFinishTextA
1827 static void PROPSHEET_SetFinishTextA(HWND hwndDlg
, LPCSTR lpszText
)
1829 HWND hwndButton
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
1831 TRACE("'%s'\n", lpszText
);
1832 /* Set text, show and enable the Finish button */
1833 SetWindowTextA(hwndButton
, lpszText
);
1834 ShowWindow(hwndButton
, SW_SHOW
);
1835 EnableWindow(hwndButton
, TRUE
);
1837 /* Make it default pushbutton */
1838 SendMessageA(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
1840 /* Hide Back button */
1841 hwndButton
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
1842 ShowWindow(hwndButton
, SW_HIDE
);
1844 /* Hide Next button */
1845 hwndButton
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
1846 ShowWindow(hwndButton
, SW_HIDE
);
1849 /******************************************************************************
1850 * PROPSHEET_SetFinishTextW
1852 static void PROPSHEET_SetFinishTextW(HWND hwndDlg
, LPCWSTR lpszText
)
1854 HWND hwndButton
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
1856 TRACE("'%s'\n", debugstr_w(lpszText
));
1857 /* Set text, show and enable the Finish button */
1858 SetWindowTextW(hwndButton
, lpszText
);
1859 ShowWindow(hwndButton
, SW_SHOW
);
1860 EnableWindow(hwndButton
, TRUE
);
1862 /* Make it default pushbutton */
1863 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
1865 /* Hide Back button */
1866 hwndButton
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
1867 ShowWindow(hwndButton
, SW_HIDE
);
1869 /* Hide Next button */
1870 hwndButton
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
1871 ShowWindow(hwndButton
, SW_HIDE
);
1874 /******************************************************************************
1875 * PROPSHEET_QuerySiblings
1877 static LRESULT
PROPSHEET_QuerySiblings(HWND hwndDlg
,
1878 WPARAM wParam
, LPARAM lParam
)
1882 LRESULT msgResult
= 0;
1883 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1886 while ((i
< psInfo
->nPages
) && (msgResult
== 0))
1888 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
1889 msgResult
= SendMessageA(hwndPage
, PSM_QUERYSIBLINGS
, wParam
, lParam
);
1897 /******************************************************************************
1900 static BOOL
PROPSHEET_AddPage(HWND hwndDlg
,
1901 HPROPSHEETPAGE hpage
)
1903 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1905 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1907 LPCPROPSHEETPAGEW ppsp
= (LPCPROPSHEETPAGEW
)hpage
;
1909 TRACE("hpage %p\n", hpage
);
1911 * Allocate and fill in a new PropPageInfo entry.
1913 psInfo
->proppage
= (PropPageInfo
*) COMCTL32_ReAlloc(psInfo
->proppage
,
1914 sizeof(PropPageInfo
) *
1915 (psInfo
->nPages
+ 1));
1916 if (!PROPSHEET_CollectPageInfo(ppsp
, psInfo
, psInfo
->nPages
))
1919 psInfo
->proppage
[psInfo
->nPages
].hpage
= hpage
;
1921 if (ppsp
->dwFlags
& PSP_PREMATURE
)
1923 /* Create the page but don't show it */
1924 PROPSHEET_CreatePage(hwndDlg
, psInfo
->nPages
, psInfo
, ppsp
);
1928 * Add a new tab to the tab control.
1930 item
.mask
= TCIF_TEXT
;
1931 item
.pszText
= (LPWSTR
) psInfo
->proppage
[psInfo
->nPages
].pszText
;
1932 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
1934 SendMessageW(hwndTabControl
, TCM_INSERTITEMW
, psInfo
->nPages
+ 1,
1939 /* If it is the only page - show it */
1940 if(psInfo
->nPages
== 1)
1941 PROPSHEET_SetCurSel(hwndDlg
, 0, 1, 0);
1945 /******************************************************************************
1946 * PROPSHEET_RemovePage
1948 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
,
1950 HPROPSHEETPAGE hpage
)
1952 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwndDlg
,
1954 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1955 PropPageInfo
* oldPages
;
1957 TRACE("index %d, hpage %p\n", index
, hpage
);
1961 oldPages
= psInfo
->proppage
;
1963 * hpage takes precedence over index.
1967 index
= PROPSHEET_GetPageIndex(hpage
, psInfo
);
1970 /* Make sure that index is within range */
1971 if (index
< 0 || index
>= psInfo
->nPages
)
1973 TRACE("Could not find page to remove!\n");
1977 TRACE("total pages %d removing page %d active page %d\n",
1978 psInfo
->nPages
, index
, psInfo
->active_page
);
1980 * Check if we're removing the active page.
1982 if (index
== psInfo
->active_page
)
1984 if (psInfo
->nPages
> 1)
1988 /* activate previous page */
1989 PROPSHEET_SetCurSel(hwndDlg
, index
- 1, -1, 0);
1993 /* activate the next page */
1994 PROPSHEET_SetCurSel(hwndDlg
, index
+ 1, 1, 0);
1995 psInfo
->active_page
= index
;
2000 psInfo
->active_page
= -1;
2001 if (!psInfo
->isModeless
)
2003 EndDialog(hwndDlg
, FALSE
);
2008 else if (index
< psInfo
->active_page
)
2009 psInfo
->active_page
--;
2011 /* Destroy page dialog window */
2012 DestroyWindow(psInfo
->proppage
[index
].hwndPage
);
2014 /* Free page resources */
2015 if(psInfo
->proppage
[index
].hpage
)
2017 PROPSHEETPAGEW
* psp
= (PROPSHEETPAGEW
*)psInfo
->proppage
[index
].hpage
;
2019 if ((psp
->dwFlags
& PSP_USETITLE
) && psInfo
->proppage
[index
].pszText
)
2020 HeapFree(GetProcessHeap(), 0, (LPVOID
)psInfo
->proppage
[index
].pszText
);
2022 DestroyPropertySheetPage(psInfo
->proppage
[index
].hpage
);
2025 /* Remove the tab */
2026 SendMessageW(hwndTabControl
, TCM_DELETEITEM
, index
, 0);
2029 psInfo
->proppage
= COMCTL32_Alloc(sizeof(PropPageInfo
) * psInfo
->nPages
);
2032 memcpy(&psInfo
->proppage
[0], &oldPages
[0], index
* sizeof(PropPageInfo
));
2034 if (index
< psInfo
->nPages
)
2035 memcpy(&psInfo
->proppage
[index
], &oldPages
[index
+ 1],
2036 (psInfo
->nPages
- index
) * sizeof(PropPageInfo
));
2038 COMCTL32_Free(oldPages
);
2043 /******************************************************************************
2044 * PROPSHEET_SetWizButtons
2046 * This code will work if (and assumes that) the Next button is on top of the
2047 * Finish button. ie. Finish comes after Next in the Z order.
2048 * This means make sure the dialog template reflects this.
2051 static void PROPSHEET_SetWizButtons(HWND hwndDlg
, DWORD dwFlags
)
2053 HWND hwndBack
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
2054 HWND hwndNext
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
2055 HWND hwndFinish
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
2057 TRACE("%ld\n", dwFlags
);
2059 EnableWindow(hwndBack
, FALSE
);
2060 EnableWindow(hwndNext
, FALSE
);
2061 EnableWindow(hwndFinish
, FALSE
);
2063 if (dwFlags
& PSWIZB_BACK
)
2064 EnableWindow(hwndBack
, TRUE
);
2066 if (dwFlags
& PSWIZB_NEXT
)
2068 /* Hide the Finish button */
2069 ShowWindow(hwndFinish
, SW_HIDE
);
2071 /* Show and enable the Next button */
2072 ShowWindow(hwndNext
, SW_SHOW
);
2073 EnableWindow(hwndNext
, TRUE
);
2075 /* Set the Next button as the default pushbutton */
2076 SendMessageA(hwndDlg
, DM_SETDEFID
, IDC_NEXT_BUTTON
, 0);
2079 if ((dwFlags
& PSWIZB_FINISH
) || (dwFlags
& PSWIZB_DISABLEDFINISH
))
2081 /* Hide the Next button */
2082 ShowWindow(hwndNext
, SW_HIDE
);
2084 /* Show the Finish button */
2085 ShowWindow(hwndFinish
, SW_SHOW
);
2087 if (dwFlags
& PSWIZB_FINISH
)
2088 EnableWindow(hwndFinish
, TRUE
);
2090 /* Set the Finish button as the default pushbutton */
2091 SendMessageA(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
2095 /******************************************************************************
2096 * PROPSHEET_GetPageIndex
2098 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
2099 * the array of PropPageInfo.
2101 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage
, PropSheetInfo
* psInfo
)
2106 TRACE("hpage %p\n", hpage
);
2107 while ((index
< psInfo
->nPages
) && (found
== FALSE
))
2109 if (psInfo
->proppage
[index
].hpage
== hpage
)
2121 /******************************************************************************
2124 static void PROPSHEET_CleanUp(HWND hwndDlg
)
2127 PropSheetInfo
* psInfo
= (PropSheetInfo
*) RemovePropW(hwndDlg
,
2131 if (!psInfo
) return;
2132 if (HIWORD(psInfo
->ppshheader
.pszCaption
))
2133 HeapFree(GetProcessHeap(), 0, (LPVOID
)psInfo
->ppshheader
.pszCaption
);
2135 for (i
= 0; i
< psInfo
->nPages
; i
++)
2137 PROPSHEETPAGEA
* psp
= (PROPSHEETPAGEA
*)psInfo
->proppage
[i
].hpage
;
2139 if(psInfo
->proppage
[i
].hwndPage
)
2140 DestroyWindow(psInfo
->proppage
[i
].hwndPage
);
2144 if ((psp
->dwFlags
& PSP_USETITLE
) && psInfo
->proppage
[i
].pszText
)
2145 HeapFree(GetProcessHeap(), 0, (LPVOID
)psInfo
->proppage
[i
].pszText
);
2147 DestroyPropertySheetPage(psInfo
->proppage
[i
].hpage
);
2151 COMCTL32_Free(psInfo
->proppage
);
2152 COMCTL32_Free(psInfo
->strPropertiesFor
);
2153 ImageList_Destroy(psInfo
->hImageList
);
2155 GlobalFree((HGLOBAL
)psInfo
);
2158 /******************************************************************************
2159 * PropertySheet (COMCTL32.87)
2160 * PropertySheetA (COMCTL32.88)
2162 INT WINAPI
PropertySheetA(LPCPROPSHEETHEADERA lppsh
)
2165 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GlobalAlloc(GPTR
,
2166 sizeof(PropSheetInfo
));
2170 TRACE("(%p)\n", lppsh
);
2172 PROPSHEET_CollectSheetInfoA(lppsh
, psInfo
);
2174 psInfo
->proppage
= (PropPageInfo
*) COMCTL32_Alloc(sizeof(PropPageInfo
) *
2176 pByte
= (BYTE
*) psInfo
->ppshheader
.u3
.ppsp
;
2178 for (n
= i
= 0; i
< lppsh
->nPages
; i
++, n
++)
2180 if (!(lppsh
->dwFlags
& PSH_PROPSHEETPAGE
))
2181 psInfo
->proppage
[n
].hpage
= psInfo
->ppshheader
.u3
.phpage
[i
];
2184 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageA((LPCPROPSHEETPAGEA
)pByte
);
2185 pByte
+= ((LPPROPSHEETPAGEA
)pByte
)->dwSize
;
2188 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW
)psInfo
->proppage
[n
].hpage
,
2191 if (lppsh
->dwFlags
& PSH_PROPSHEETPAGE
)
2192 DestroyPropertySheetPage(psInfo
->proppage
[n
].hpage
);
2198 bRet
= PROPSHEET_CreateDialog(psInfo
);
2203 /******************************************************************************
2204 * PropertySheetW (COMCTL32.89)
2206 INT WINAPI
PropertySheetW(LPCPROPSHEETHEADERW lppsh
)
2209 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GlobalAlloc(GPTR
,
2210 sizeof(PropSheetInfo
));
2214 TRACE("(%p)\n", lppsh
);
2216 PROPSHEET_CollectSheetInfoW(lppsh
, psInfo
);
2218 psInfo
->proppage
= (PropPageInfo
*) COMCTL32_Alloc(sizeof(PropPageInfo
) *
2220 pByte
= (BYTE
*) psInfo
->ppshheader
.u3
.ppsp
;
2222 for (n
= i
= 0; i
< lppsh
->nPages
; i
++, n
++)
2224 if (!(lppsh
->dwFlags
& PSH_PROPSHEETPAGE
))
2225 psInfo
->proppage
[n
].hpage
= psInfo
->ppshheader
.u3
.phpage
[i
];
2228 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageW((LPCPROPSHEETPAGEW
)pByte
);
2229 pByte
+= ((LPPROPSHEETPAGEW
)pByte
)->dwSize
;
2232 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW
)psInfo
->proppage
[n
].hpage
,
2235 if (lppsh
->dwFlags
& PSH_PROPSHEETPAGE
)
2236 DestroyPropertySheetPage(psInfo
->proppage
[n
].hpage
);
2242 bRet
= PROPSHEET_CreateDialog(psInfo
);
2247 /******************************************************************************
2248 * CreatePropertySheetPage (COMCTL32.18)
2249 * CreatePropertySheetPageA (COMCTL32.19)
2251 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageA(
2252 LPCPROPSHEETPAGEA lpPropSheetPage
)
2254 PROPSHEETPAGEW
* ppsp
= COMCTL32_Alloc(sizeof(PROPSHEETPAGEW
));
2256 memcpy(ppsp
,lpPropSheetPage
,min(lpPropSheetPage
->dwSize
,sizeof(PROPSHEETPAGEA
)));
2258 if ( !(ppsp
->dwFlags
& PSP_DLGINDIRECT
) && HIWORD( ppsp
->u
.pszTemplate
) )
2260 PROPSHEET_AtoW(&ppsp
->u
.pszTemplate
, lpPropSheetPage
->u
.pszTemplate
);
2262 if ( (ppsp
->dwFlags
& PSP_USEICONID
) && HIWORD( ppsp
->u2
.pszIcon
) )
2264 PROPSHEET_AtoW(&ppsp
->u2
.pszIcon
, lpPropSheetPage
->u2
.pszIcon
);
2267 if ((ppsp
->dwFlags
& PSP_USETITLE
) && HIWORD( ppsp
->pszTitle
))
2269 PROPSHEET_AtoW(&ppsp
->pszTitle
, lpPropSheetPage
->pszTitle
);
2271 else if ( !(ppsp
->dwFlags
& PSP_USETITLE
) )
2272 ppsp
->pszTitle
= NULL
;
2274 return (HPROPSHEETPAGE
)ppsp
;
2277 /******************************************************************************
2278 * CreatePropertySheetPageW (COMCTL32.20)
2280 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage
)
2282 PROPSHEETPAGEW
* ppsp
= COMCTL32_Alloc(sizeof(PROPSHEETPAGEW
));
2284 memcpy(ppsp
,lpPropSheetPage
,min(lpPropSheetPage
->dwSize
,sizeof(PROPSHEETPAGEW
)));
2286 if ( !(ppsp
->dwFlags
& PSP_DLGINDIRECT
) && HIWORD( ppsp
->u
.pszTemplate
) )
2288 int len
= strlenW(lpPropSheetPage
->u
.pszTemplate
);
2290 ppsp
->u
.pszTemplate
= HeapAlloc( GetProcessHeap(),0,(len
+1)*sizeof (WCHAR
) );
2291 strcpyW( (WCHAR
*)ppsp
->u
.pszTemplate
, lpPropSheetPage
->u
.pszTemplate
);
2293 if ( (ppsp
->dwFlags
& PSP_USEICONID
) && HIWORD( ppsp
->u2
.pszIcon
) )
2295 int len
= strlenW(lpPropSheetPage
->u2
.pszIcon
);
2296 ppsp
->u2
.pszIcon
= HeapAlloc( GetProcessHeap(), 0, (len
+1)*sizeof (WCHAR
) );
2297 strcpyW( (WCHAR
*)ppsp
->u2
.pszIcon
, lpPropSheetPage
->u2
.pszIcon
);
2300 if ((ppsp
->dwFlags
& PSP_USETITLE
) && HIWORD( ppsp
->pszTitle
))
2302 int len
= strlenW(lpPropSheetPage
->pszTitle
);
2303 ppsp
->pszTitle
= HeapAlloc( GetProcessHeap(), 0, (len
+1)*sizeof (WCHAR
) );
2304 strcpyW( (WCHAR
*)ppsp
->pszTitle
, lpPropSheetPage
->pszTitle
);
2306 else if ( !(ppsp
->dwFlags
& PSP_USETITLE
) )
2307 ppsp
->pszTitle
= NULL
;
2309 return (HPROPSHEETPAGE
)ppsp
;
2312 /******************************************************************************
2313 * DestroyPropertySheetPage (COMCTL32.24)
2315 BOOL WINAPI
DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage
)
2317 PROPSHEETPAGEW
*psp
= (PROPSHEETPAGEW
*)hPropPage
;
2322 if ( !(psp
->dwFlags
& PSP_DLGINDIRECT
) && HIWORD( psp
->u
.pszTemplate
) )
2323 HeapFree(GetProcessHeap(), 0, (LPVOID
)psp
->u
.pszTemplate
);
2325 if ( (psp
->dwFlags
& PSP_USEICONID
) && HIWORD( psp
->u2
.pszIcon
) )
2326 HeapFree(GetProcessHeap(), 0, (LPVOID
)psp
->u2
.pszIcon
);
2328 if ((psp
->dwFlags
& PSP_USETITLE
) && HIWORD( psp
->pszTitle
))
2329 HeapFree(GetProcessHeap(), 0, (LPVOID
)psp
->pszTitle
);
2331 COMCTL32_Free(hPropPage
);
2336 /******************************************************************************
2337 * PROPSHEET_IsDialogMessage
2339 static BOOL
PROPSHEET_IsDialogMessage(HWND hwnd
, LPMSG lpMsg
)
2341 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwnd
, PropSheetInfoStr
);
2344 if (!psInfo
|| (hwnd
!= lpMsg
->hwnd
&& !IsChild(hwnd
, lpMsg
->hwnd
)))
2347 if (lpMsg
->message
== WM_KEYDOWN
&& (GetKeyState(VK_CONTROL
) & 0x8000))
2350 INT dlgCode
= SendMessageA(lpMsg
->hwnd
, WM_GETDLGCODE
, 0, (LPARAM
)lpMsg
);
2352 if (!(dlgCode
& DLGC_WANTMESSAGE
))
2354 switch (lpMsg
->wParam
)
2357 if (GetKeyState(VK_SHIFT
) & 0x8000)
2363 case VK_NEXT
: new_page
= 1; break;
2364 case VK_PRIOR
: new_page
= -1; break;
2370 if (PROPSHEET_CanSetCurSel(hwnd
) != FALSE
)
2372 new_page
+= psInfo
->active_page
;
2375 new_page
= psInfo
->nPages
- 1;
2376 else if (new_page
>= psInfo
->nPages
)
2379 PROPSHEET_SetCurSel(hwnd
, new_page
, 1, 0);
2386 return IsDialogMessageA(hwnd
, lpMsg
);
2389 /******************************************************************************
2390 * PROPSHEET_DoCommand
2392 static BOOL
PROPSHEET_DoCommand(HWND hwnd
, WORD wID
)
2398 case IDC_APPLY_BUTTON
:
2400 HWND hwndApplyBtn
= GetDlgItem(hwnd
, IDC_APPLY_BUTTON
);
2402 if (PROPSHEET_Apply(hwnd
, wID
== IDOK
? 1: 0) == FALSE
)
2407 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwnd
,
2411 if (psInfo
->restartWindows
)
2412 result
= ID_PSRESTARTWINDOWS
;
2414 /* reboot system takes precedence over restart windows */
2415 if (psInfo
->rebootSystem
)
2416 result
= ID_PSREBOOTSYSTEM
;
2418 if (psInfo
->isModeless
)
2419 psInfo
->activeValid
= FALSE
;
2421 EndDialog(hwnd
, result
);
2424 EnableWindow(hwndApplyBtn
, FALSE
);
2429 case IDC_BACK_BUTTON
:
2430 PROPSHEET_Back(hwnd
);
2433 case IDC_NEXT_BUTTON
:
2434 PROPSHEET_Next(hwnd
);
2437 case IDC_FINISH_BUTTON
:
2438 PROPSHEET_Finish(hwnd
);
2442 PROPSHEET_Cancel(hwnd
, 0);
2446 PROPSHEET_Help(hwnd
);
2453 /******************************************************************************
2454 * PROPSHEET_DialogProc
2457 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
2459 TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n",
2460 hwnd
, uMsg
, wParam
, lParam
);
2466 PropSheetInfo
* psInfo
= (PropSheetInfo
*) lParam
;
2467 WCHAR
* strCaption
= (WCHAR
*)COMCTL32_Alloc(MAX_CAPTION_LENGTH
*sizeof(WCHAR
));
2468 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
2469 LPCPROPSHEETPAGEW ppshpage
;
2472 SetPropW(hwnd
, PropSheetInfoStr
, (HANDLE
)psInfo
);
2475 * psInfo->hwnd is not being used by WINE code - it exists
2476 * for compatibility with "real" Windoze. The same about
2477 * SetWindowLong - WINE is only using the PropSheetInfoStr
2480 psInfo
->hwnd
= hwnd
;
2481 SetWindowLongW(hwnd
,DWL_USER
,(LONG
)psInfo
);
2484 * Small icon in the title bar.
2486 if ((psInfo
->ppshheader
.dwFlags
& PSH_USEICONID
) ||
2487 (psInfo
->ppshheader
.dwFlags
& PSH_USEHICON
))
2490 int icon_cx
= GetSystemMetrics(SM_CXSMICON
);
2491 int icon_cy
= GetSystemMetrics(SM_CYSMICON
);
2493 if (psInfo
->ppshheader
.dwFlags
& PSH_USEICONID
)
2494 hIcon
= LoadImageW(psInfo
->ppshheader
.hInstance
,
2495 psInfo
->ppshheader
.u
.pszIcon
,
2500 hIcon
= psInfo
->ppshheader
.u
.hIcon
;
2502 SendMessageW(hwnd
, WM_SETICON
, 0, hIcon
);
2505 if (psInfo
->ppshheader
.dwFlags
& PSH_USEHICON
)
2506 SendMessageW(hwnd
, WM_SETICON
, 0, psInfo
->ppshheader
.u
.hIcon
);
2508 psInfo
->strPropertiesFor
= strCaption
;
2510 GetWindowTextW(hwnd
, psInfo
->strPropertiesFor
, MAX_CAPTION_LENGTH
);
2512 PROPSHEET_CreateTabControl(hwnd
, psInfo
);
2514 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
2516 if (PROPSHEET_IsTooSmallWizard(hwnd
, psInfo
))
2518 PROPSHEET_AdjustSizeWizard(hwnd
, psInfo
);
2519 PROPSHEET_AdjustButtonsWizard(hwnd
, psInfo
);
2524 if (PROPSHEET_SizeMismatch(hwnd
, psInfo
))
2526 PROPSHEET_AdjustSize(hwnd
, psInfo
);
2527 PROPSHEET_AdjustButtons(hwnd
, psInfo
);
2531 if (psInfo
->useCallback
)
2532 (*(psInfo
->ppshheader
.pfnCallback
))(hwnd
,
2533 PSCB_INITIALIZED
, (LPARAM
)0);
2535 idx
= psInfo
->active_page
;
2536 ppshpage
= (LPCPROPSHEETPAGEW
)psInfo
->proppage
[idx
].hpage
;
2537 psInfo
->active_page
= -1;
2539 PROPSHEET_SetCurSel(hwnd
, idx
, 1, psInfo
->proppage
[idx
].hpage
);
2541 /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
2542 * as some programs call TCM_GETCURSEL to get the current selection
2543 * from which to switch to the next page */
2544 SendMessageW(hwndTabCtrl
, TCM_SETCURSEL
, psInfo
->active_page
, 0);
2546 if (!HIWORD(psInfo
->ppshheader
.pszCaption
) &&
2547 psInfo
->ppshheader
.hInstance
)
2551 if (LoadStringW(psInfo
->ppshheader
.hInstance
,
2552 (UINT
)psInfo
->ppshheader
.pszCaption
, szText
, 255))
2553 PROPSHEET_SetTitleW(hwnd
, psInfo
->ppshheader
.dwFlags
, szText
);
2557 PROPSHEET_SetTitleW(hwnd
, psInfo
->ppshheader
.dwFlags
,
2558 psInfo
->ppshheader
.pszCaption
);
2565 PROPSHEET_CleanUp(hwnd
);
2569 PROPSHEET_Cancel(hwnd
, 1);
2573 return PROPSHEET_DoCommand(hwnd
, LOWORD(wParam
));
2577 NMHDR
* pnmh
= (LPNMHDR
) lParam
;
2579 if (pnmh
->code
== TCN_SELCHANGE
)
2581 int index
= SendMessageW(pnmh
->hwndFrom
, TCM_GETCURSEL
, 0, 0);
2582 PROPSHEET_SetCurSel(hwnd
, index
, 1, 0);
2585 if(pnmh
->code
== TCN_SELCHANGING
)
2587 BOOL bRet
= PROPSHEET_CanSetCurSel(hwnd
);
2588 SetWindowLongW(hwnd
, DWL_MSGRESULT
, !bRet
);
2595 case PSM_GETCURRENTPAGEHWND
:
2597 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwnd
,
2601 if (psInfo
->activeValid
&& psInfo
->active_page
!= -1)
2602 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
2604 SetWindowLongW(hwnd
, DWL_MSGRESULT
, hwndPage
);
2610 PROPSHEET_Changed(hwnd
, (HWND
)wParam
);
2614 PROPSHEET_UnChanged(hwnd
, (HWND
)wParam
);
2617 case PSM_GETTABCONTROL
:
2619 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
2621 SetWindowLongW(hwnd
, DWL_MSGRESULT
, hwndTabCtrl
);
2630 msgResult
= PROPSHEET_CanSetCurSel(hwnd
);
2631 if(msgResult
!= FALSE
)
2633 msgResult
= PROPSHEET_SetCurSel(hwnd
,
2636 (HPROPSHEETPAGE
)lParam
);
2639 SetWindowLongW(hwnd
, DWL_MSGRESULT
, msgResult
);
2644 case PSM_CANCELTOCLOSE
:
2646 WCHAR buf
[MAX_BUTTONTEXT_LENGTH
];
2647 HWND hwndOK
= GetDlgItem(hwnd
, IDOK
);
2648 HWND hwndCancel
= GetDlgItem(hwnd
, IDCANCEL
);
2650 EnableWindow(hwndCancel
, FALSE
);
2651 if (LoadStringW(COMCTL32_hModule
, IDS_CLOSE
, buf
, sizeof(buf
)))
2652 SetWindowTextW(hwndOK
, buf
);
2657 case PSM_RESTARTWINDOWS
:
2659 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwnd
,
2662 psInfo
->restartWindows
= TRUE
;
2666 case PSM_REBOOTSYSTEM
:
2668 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropW(hwnd
,
2671 psInfo
->rebootSystem
= TRUE
;
2676 PROPSHEET_SetTitleA(hwnd
, (DWORD
) wParam
, (LPCSTR
) lParam
);
2680 PROPSHEET_SetTitleW(hwnd
, (DWORD
) wParam
, (LPCWSTR
) lParam
);
2685 BOOL msgResult
= PROPSHEET_Apply(hwnd
, 0);
2687 SetWindowLongW(hwnd
, DWL_MSGRESULT
, msgResult
);
2692 case PSM_QUERYSIBLINGS
:
2694 LRESULT msgResult
= PROPSHEET_QuerySiblings(hwnd
, wParam
, lParam
);
2696 SetWindowLongW(hwnd
, DWL_MSGRESULT
, msgResult
);
2704 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2705 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2706 * on success or FALSE otherwise, as specified on MSDN Online.
2707 * Also see the MFC code for
2708 * CPropertySheet::AddPage(CPropertyPage* pPage).
2711 BOOL msgResult
= PROPSHEET_AddPage(hwnd
, (HPROPSHEETPAGE
)lParam
);
2713 SetWindowLongW(hwnd
, DWL_MSGRESULT
, msgResult
);
2718 case PSM_REMOVEPAGE
:
2719 PROPSHEET_RemovePage(hwnd
, (int)wParam
, (HPROPSHEETPAGE
)lParam
);
2722 case PSM_ISDIALOGMESSAGE
:
2724 BOOL msgResult
= PROPSHEET_IsDialogMessage(hwnd
, (LPMSG
)lParam
);
2725 SetWindowLongA(hwnd
, DWL_MSGRESULT
, msgResult
);
2729 case PSM_PRESSBUTTON
:
2730 PROPSHEET_PressButton(hwnd
, (int)wParam
);
2733 case PSM_SETFINISHTEXTA
:
2734 PROPSHEET_SetFinishTextA(hwnd
, (LPCSTR
) lParam
);
2737 case PSM_SETWIZBUTTONS
:
2738 PROPSHEET_SetWizButtons(hwnd
, (DWORD
)lParam
);
2741 case PSM_SETCURSELID
:
2742 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2745 case PSM_SETFINISHTEXTW
:
2746 PROPSHEET_SetFinishTextW(hwnd
, (LPCWSTR
) lParam
);