4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
6 * Copyright 2004 Maxime Bellenge
7 * Copyright 2004 Filip Navara
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * This code was audited for completeness against the documented features
24 * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara.
26 * Unless otherwise noted, we believe this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
32 * - Wizard 97 header resizing
33 * - Enforcing of minimal wizard size
35 * o PSM_RECALCPAGESIZES
40 * o PSN_QUERYINITIALFOCUS
41 * o PSN_TRANSLATEACCELERATOR
44 * o PSH_STRETCHWATERMARK
48 * o PSP_USEFUSIONCONTEXT
65 #include "wine/debug.h"
67 #define HPROPSHEETPAGE_MAGIC 0x5A9234E3
69 /******************************************************************************
93 } MyDLGITEMTEMPLATEEX
;
108 typedef struct tagPropPageInfo
110 HPROPSHEETPAGE hpage
; /* to keep track of pages not passed to PropertySheet */
118 typedef struct tagPropSheetInfo
121 PROPSHEETHEADERW ppshheader
;
123 LPWSTR strPropertiesFor
;
133 PropPageInfo
* proppage
;
138 HIMAGELIST hImageList
;
149 /******************************************************************************
150 * Defines and global variables
153 static const WCHAR PropSheetInfoStr
[] = L
"PropertySheetInfo";
155 #define MAX_CAPTION_LENGTH 255
156 #define MAX_TABTEXT_LENGTH 255
157 #define MAX_BUTTONTEXT_LENGTH 64
159 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
161 /* Wizard metrics specified in DLUs */
162 #define WIZARD_PADDING 7
163 #define WIZARD_HEADER_HEIGHT 36
165 /******************************************************************************
168 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
);
169 static void PROPSHEET_SetTitleW(HWND hwndDlg
, DWORD dwStyle
, LPCWSTR lpszText
);
170 static BOOL
PROPSHEET_CanSetCurSel(HWND hwndDlg
);
171 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
174 HPROPSHEETPAGE hpage
);
175 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage
, const PropSheetInfo
* psInfo
, int original_index
);
176 static PADDING_INFO
PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg
, const PropSheetInfo
* psInfo
);
177 static BOOL
PROPSHEET_DoCommand(HWND hwnd
, WORD wID
);
178 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
, int index
, HPROPSHEETPAGE hpage
);
180 static INT_PTR CALLBACK
181 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
183 WINE_DEFAULT_DEBUG_CHANNEL(propsheet
);
185 static char *heap_strdupA(const char *str
)
187 int len
= strlen(str
) + 1;
188 char *ret
= Alloc(len
);
189 return strcpy(ret
, str
);
192 static WCHAR
*heap_strdupW(const WCHAR
*str
)
194 int len
= lstrlenW(str
) + 1;
195 WCHAR
*ret
= Alloc(len
* sizeof(WCHAR
));
200 static WCHAR
*heap_strdupAtoW(const char *str
)
205 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, 0, 0);
206 ret
= Alloc(len
* sizeof(WCHAR
));
207 MultiByteToWideChar(CP_ACP
, 0, str
, -1, ret
, len
);
212 static char *heap_strdupWtoA(const WCHAR
*str
)
217 len
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, 0, 0, 0, 0);
219 WideCharToMultiByte(CP_ACP
, 0, str
, -1, ret
, len
, 0, 0);
225 * Get the size of an in-memory template
227 *( Based on the code of PROPSHEET_CollectPageInfo)
228 * See also dialog.c/DIALOG_ParseTemplate32().
231 static UINT
get_template_size(const DLGTEMPLATE
*template)
233 const WORD
*p
= (const WORD
*)template;
234 BOOL istemplateex
= ((const MyDLGTEMPLATEEX
*)template)->signature
== 0xFFFF;
240 /* DLGTEMPLATEEX (not defined in any std. header file) */
241 TRACE("is DLGTEMPLATEEX\n");
244 p
+= 2; /* help ID */
245 p
+= 2; /* ext style */
251 TRACE("is DLGTEMPLATE\n");
253 p
+= 2; /* ext style */
273 TRACE("menu %s\n", debugstr_w( p
));
274 p
+= lstrlenW( p
) + 1;
285 p
+= 2; /* 0xffff plus predefined window class ordinal value */
288 TRACE("class %s\n", debugstr_w( p
));
289 p
+= lstrlenW( p
) + 1;
294 TRACE("title %s\n", debugstr_w( p
));
295 p
+= lstrlenW( p
) + 1;
297 /* font, if DS_SETFONT set */
298 if ((DS_SETFONT
& ((istemplateex
) ? ((const MyDLGTEMPLATEEX
*)template)->style
:
301 p
+= istemplateex
? 3 : 1;
302 TRACE("font %s\n", debugstr_w( p
));
303 p
+= lstrlenW( p
) + 1; /* the font name */
306 /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)
307 * that are following the DLGTEMPLATE(EX) data */
308 TRACE("%d items\n", nitems
);
311 p
= (WORD
*)(((DWORD_PTR
)p
+ 3) & ~3); /* DWORD align */
314 p
+= (istemplateex
? sizeof(MyDLGITEMTEMPLATEEX
) : sizeof(DLGITEMTEMPLATE
))
324 TRACE("class ordinal %#lx\n", *(const DWORD
*)p
);
328 TRACE("class %s\n", debugstr_w( p
));
329 p
+= lstrlenW( p
) + 1;
333 /* check title text */
340 TRACE("text ordinal %#lx\n",*(const DWORD
*)p
);
344 TRACE("text %s\n",debugstr_w( p
));
345 p
+= lstrlenW( p
) + 1;
348 p
+= *p
/ sizeof(WORD
) + 1; /* Skip extra data */
352 ret
= (p
- (const WORD
*)template) * sizeof(WORD
);
353 TRACE("%p %p size 0x%08x\n", p
, template, ret
);
357 static DWORD
HPSP_get_flags(HPROPSHEETPAGE hpsp
)
360 return hpsp
->unicode
? hpsp
->pspW
.dwFlags
: hpsp
->pspA
.dwFlags
;
363 static void HPSP_call_callback(HPROPSHEETPAGE hpsp
, UINT msg
)
367 if (!(hpsp
->pspW
.dwFlags
& PSP_USECALLBACK
) || !hpsp
->pspW
.pfnCallback
||
368 (msg
== PSPCB_ADDREF
&& hpsp
->pspW
.dwSize
<= PROPSHEETPAGEW_V1_SIZE
))
371 hpsp
->pspW
.pfnCallback(0, msg
, &hpsp
->pspW
);
375 if (!(hpsp
->pspA
.dwFlags
& PSP_USECALLBACK
) || !hpsp
->pspA
.pfnCallback
||
376 (msg
== PSPCB_ADDREF
&& hpsp
->pspA
.dwSize
<= PROPSHEETPAGEA_V1_SIZE
))
379 hpsp
->pspA
.pfnCallback(0, msg
, &hpsp
->pspA
);
383 static const DLGTEMPLATE
* HPSP_load_template(HPROPSHEETPAGE hpsp
, DWORD
*size
)
391 if (hpsp
->pspW
.dwFlags
& PSP_DLGINDIRECT
)
394 *size
= get_template_size(hpsp
->pspW
.pResource
);
395 return hpsp
->pspW
.pResource
;
398 hinst
= hpsp
->pspW
.hInstance
;
399 res
= FindResourceW(hinst
, hpsp
->pspW
.pszTemplate
, (LPWSTR
)RT_DIALOG
);
403 if (hpsp
->pspA
.dwFlags
& PSP_DLGINDIRECT
)
406 *size
= get_template_size(hpsp
->pspA
.pResource
);
407 return hpsp
->pspA
.pResource
;
410 hinst
= hpsp
->pspA
.hInstance
;
411 res
= FindResourceA(hinst
, hpsp
->pspA
.pszTemplate
, (LPSTR
)RT_DIALOG
);
415 *size
= SizeofResource(hinst
, res
);
417 template = LoadResource(hinst
, res
);
418 return LockResource(template);
421 static WCHAR
* HPSP_get_title(HPROPSHEETPAGE hpsp
, const WCHAR
*template_title
)
430 title
= hpsp
->pspW
.pszTitle
;
431 hinst
= hpsp
->pspW
.hInstance
;
435 title
= hpsp
->pspA
.pszTitle
;
436 hinst
= hpsp
->pspA
.hInstance
;
439 if (IS_INTRESOURCE(title
))
441 if (LoadStringW(hinst
, (DWORD_PTR
)title
, szTitle
, ARRAY_SIZE(szTitle
)))
443 else if (*template_title
)
444 pTitle
= template_title
;
448 return heap_strdupW(pTitle
);
452 return heap_strdupW(title
);
453 return heap_strdupAtoW(title
);
456 static HICON
HPSP_get_icon(HPROPSHEETPAGE hpsp
)
462 if (hpsp
->pspW
.dwFlags
& PSP_USEICONID
)
464 int cx
= GetSystemMetrics(SM_CXSMICON
);
465 int cy
= GetSystemMetrics(SM_CYSMICON
);
467 ret
= LoadImageW(hpsp
->pspW
.hInstance
, hpsp
->pspW
.pszIcon
, IMAGE_ICON
,
468 cx
, cy
, LR_DEFAULTCOLOR
);
472 ret
= hpsp
->pspW
.hIcon
;
477 if (hpsp
->pspA
.dwFlags
& PSP_USEICONID
)
479 int cx
= GetSystemMetrics(SM_CXSMICON
);
480 int cy
= GetSystemMetrics(SM_CYSMICON
);
482 ret
= LoadImageA(hpsp
->pspA
.hInstance
, hpsp
->pspA
.pszIcon
, IMAGE_ICON
,
483 cx
, cy
, LR_DEFAULTCOLOR
);
487 ret
= hpsp
->pspA
.hIcon
;
494 static LRESULT
HPSP_get_template(HPROPSHEETPAGE hpsp
)
497 return (LRESULT
)hpsp
->pspW
.pszTemplate
;
498 return (LRESULT
)hpsp
->pspA
.pszTemplate
;
501 static HWND
HPSP_create_page(HPROPSHEETPAGE hpsp
, DLGTEMPLATE
*template, HWND parent
)
507 hwnd
= CreateDialogIndirectParamW(hpsp
->pspW
.hInstance
, template,
508 parent
, hpsp
->pspW
.pfnDlgProc
, (LPARAM
)&hpsp
->pspW
);
512 hwnd
= CreateDialogIndirectParamA(hpsp
->pspA
.hInstance
, template,
513 parent
, hpsp
->pspA
.pfnDlgProc
, (LPARAM
)&hpsp
->pspA
);
519 static void HPSP_set_header_title(HPROPSHEETPAGE hpsp
, const WCHAR
*title
)
523 if (!IS_INTRESOURCE(hpsp
->pspW
.pszHeaderTitle
))
524 Free((void *)hpsp
->pspW
.pszHeaderTitle
);
526 hpsp
->pspW
.pszHeaderTitle
= heap_strdupW(title
);
527 hpsp
->pspW
.dwFlags
|= PSP_USEHEADERTITLE
;
531 if (!IS_INTRESOURCE(hpsp
->pspA
.pszHeaderTitle
))
532 Free((void *)hpsp
->pspA
.pszHeaderTitle
);
534 hpsp
->pspA
.pszHeaderTitle
= heap_strdupWtoA(title
);
535 hpsp
->pspA
.dwFlags
|= PSP_USEHEADERTITLE
;
539 static void HPSP_set_header_subtitle(HPROPSHEETPAGE hpsp
, const WCHAR
*subtitle
)
543 if (!IS_INTRESOURCE(hpsp
->pspW
.pszHeaderTitle
))
544 Free((void *)hpsp
->pspW
.pszHeaderTitle
);
546 hpsp
->pspW
.pszHeaderTitle
= heap_strdupW(subtitle
);
547 hpsp
->pspW
.dwFlags
|= PSP_USEHEADERSUBTITLE
;
551 if (!IS_INTRESOURCE(hpsp
->pspA
.pszHeaderTitle
))
552 Free((void *)hpsp
->pspA
.pszHeaderTitle
);
554 hpsp
->pspA
.pszHeaderTitle
= heap_strdupWtoA(subtitle
);
555 hpsp
->pspA
.dwFlags
|= PSP_USEHEADERSUBTITLE
;
559 static void HPSP_draw_text(HPROPSHEETPAGE hpsp
, HDC hdc
, BOOL title
, RECT
*r
, UINT format
)
564 text
= title
? hpsp
->pspW
.pszHeaderTitle
: hpsp
->pspW
.pszHeaderSubTitle
;
566 text
= title
? hpsp
->pspA
.pszHeaderTitle
: hpsp
->pspA
.pszHeaderSubTitle
;
568 if (IS_INTRESOURCE(text
))
573 len
= LoadStringW(hpsp
->unicode
? hpsp
->pspW
.hInstance
: hpsp
->pspA
.hInstance
,
574 (UINT_PTR
)text
, buf
, ARRAY_SIZE(buf
));
576 DrawTextW(hdc
, buf
, len
, r
, format
);
578 else if (hpsp
->unicode
)
579 DrawTextW(hdc
, text
, -1, r
, format
);
581 DrawTextA(hdc
, text
, -1, r
, format
);
584 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
585 /******************************************************************************
586 * PROPSHEET_UnImplementedFlags
588 * Document use of flags we don't implement yet.
590 static VOID
PROPSHEET_UnImplementedFlags(DWORD dwFlags
)
597 * unhandled header flags:
598 * PSH_RTLREADING 0x00000800
599 * PSH_STRETCHWATERMARK 0x00040000
600 * PSH_USEPAGELANG 0x00200000
603 add_flag(PSH_RTLREADING
);
604 add_flag(PSH_STRETCHWATERMARK
);
605 add_flag(PSH_USEPAGELANG
);
606 if (string
[0] != '\0')
607 FIXME("%s\n", string
);
611 /******************************************************************************
612 * PROPSHEET_GetPageRect
614 * Retrieve rect from tab control and map into the dialog for SetWindowPos
616 static void PROPSHEET_GetPageRect(const PropSheetInfo
* psInfo
, HWND hwndDlg
,
617 RECT
*rc
, HPROPSHEETPAGE hpsp
)
619 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
) {
623 if (((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
)) &&
624 (psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) &&
625 !(HPSP_get_flags(hpsp
) & PSP_HIDEHEADER
)) ||
626 (psInfo
->ppshheader
.dwFlags
& PSH_WIZARD
))
628 rc
->left
= rc
->top
= WIZARD_PADDING
;
632 rc
->left
= rc
->top
= 0;
634 rc
->right
= psInfo
->width
- rc
->left
;
635 rc
->bottom
= psInfo
->height
- rc
->top
;
636 MapDialogRect(hwndDlg
, rc
);
638 if ((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
)) &&
639 (psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) &&
640 !(HPSP_get_flags(hpsp
) & PSP_HIDEHEADER
))
642 hwndChild
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINEHEADER
);
643 GetClientRect(hwndChild
, &r
);
644 MapWindowPoints(hwndChild
, hwndDlg
, (LPPOINT
) &r
, 2);
645 rc
->top
+= r
.bottom
+ 1;
648 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
649 GetClientRect(hwndTabCtrl
, rc
);
650 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, FALSE
, (LPARAM
)rc
);
651 MapWindowPoints(hwndTabCtrl
, hwndDlg
, (LPPOINT
)rc
, 2);
655 /******************************************************************************
656 * PROPSHEET_FindPageByResId
658 * Find page index corresponding to page resource id.
660 static INT
PROPSHEET_FindPageByResId(const PropSheetInfo
* psInfo
, LRESULT resId
)
664 for (i
= 0; i
< psInfo
->nPages
; i
++)
666 /* Fixme: if resource ID is a string shall we use strcmp ??? */
667 if (HPSP_get_template(psInfo
->proppage
[i
].hpage
) == resId
)
674 /******************************************************************************
675 * PROPSHEET_CollectSheetInfoCommon
677 * Common code for PROPSHEET_CollectSheetInfoA/W
679 static void PROPSHEET_CollectSheetInfoCommon(PropSheetInfo
* psInfo
, DWORD dwFlags
)
681 PROPSHEET_UnImplementedFlags(dwFlags
);
683 psInfo
->hasHelp
= dwFlags
& PSH_HASHELP
;
684 psInfo
->hasApply
= !(dwFlags
& PSH_NOAPPLYNOW
);
685 psInfo
->hasFinish
= dwFlags
& PSH_WIZARDHASFINISH
;
686 psInfo
->isModeless
= dwFlags
& PSH_MODELESS
;
687 psInfo
->usePropPage
= dwFlags
& PSH_PROPSHEETPAGE
;
688 if (psInfo
->active_page
< 0 || psInfo
->active_page
>= psInfo
->nPages
)
689 psInfo
->active_page
= 0;
692 psInfo
->hImageList
= 0;
693 psInfo
->activeValid
= FALSE
;
696 /******************************************************************************
697 * PROPSHEET_CollectSheetInfoA
699 * Collect relevant data.
701 static void PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh
,
702 PropSheetInfo
* psInfo
)
704 DWORD dwSize
= min(lppsh
->dwSize
,sizeof(PROPSHEETHEADERA
));
705 DWORD dwFlags
= lppsh
->dwFlags
;
707 psInfo
->useCallback
= (dwFlags
& PSH_USECALLBACK
)&& (lppsh
->pfnCallback
);
709 memcpy(&psInfo
->ppshheader
,lppsh
,dwSize
);
710 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%#lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
711 lppsh
->dwSize
, lppsh
->dwFlags
, lppsh
->hwndParent
, lppsh
->hInstance
,
712 debugstr_a(lppsh
->pszCaption
), lppsh
->nPages
, lppsh
->pfnCallback
);
714 if (lppsh
->dwFlags
& INTRNL_ANY_WIZARD
)
715 psInfo
->ppshheader
.pszCaption
= NULL
;
718 if (!IS_INTRESOURCE(lppsh
->pszCaption
))
720 int len
= MultiByteToWideChar(CP_ACP
, 0, lppsh
->pszCaption
, -1, NULL
, 0);
721 WCHAR
*caption
= Alloc( len
*sizeof (WCHAR
) );
723 MultiByteToWideChar(CP_ACP
, 0, lppsh
->pszCaption
, -1, caption
, len
);
724 psInfo
->ppshheader
.pszCaption
= caption
;
727 psInfo
->nPages
= lppsh
->nPages
;
729 if (dwFlags
& PSH_USEPSTARTPAGE
)
731 TRACE("PSH_USEPSTARTPAGE is on\n");
732 psInfo
->active_page
= 0;
735 psInfo
->active_page
= lppsh
->nStartPage
;
737 PROPSHEET_CollectSheetInfoCommon(psInfo
, dwFlags
);
740 /******************************************************************************
741 * PROPSHEET_CollectSheetInfoW
743 * Collect relevant data.
745 static void PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh
,
746 PropSheetInfo
* psInfo
)
748 DWORD dwSize
= min(lppsh
->dwSize
,sizeof(PROPSHEETHEADERW
));
749 DWORD dwFlags
= lppsh
->dwFlags
;
751 psInfo
->useCallback
= (dwFlags
& PSH_USECALLBACK
) && (lppsh
->pfnCallback
);
753 memcpy(&psInfo
->ppshheader
,lppsh
,dwSize
);
754 TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%#lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t%s\nnPages\t\t%d\npfnCallback\t%p\n",
755 lppsh
->dwSize
, lppsh
->dwFlags
, lppsh
->hwndParent
, lppsh
->hInstance
, debugstr_w(lppsh
->pszCaption
), lppsh
->nPages
, lppsh
->pfnCallback
);
757 if (lppsh
->dwFlags
& INTRNL_ANY_WIZARD
)
758 psInfo
->ppshheader
.pszCaption
= NULL
;
761 if (!IS_INTRESOURCE(lppsh
->pszCaption
))
762 psInfo
->ppshheader
.pszCaption
= heap_strdupW( lppsh
->pszCaption
);
764 psInfo
->nPages
= lppsh
->nPages
;
766 if (dwFlags
& PSH_USEPSTARTPAGE
)
768 TRACE("PSH_USEPSTARTPAGE is on\n");
769 psInfo
->active_page
= 0;
772 psInfo
->active_page
= lppsh
->nStartPage
;
774 PROPSHEET_CollectSheetInfoCommon(psInfo
, dwFlags
);
777 /******************************************************************************
778 * PROPSHEET_CollectPageInfo
780 * Collect property sheet data.
781 * With code taken from DIALOG_ParseTemplate32.
783 static BOOL
PROPSHEET_CollectPageInfo(HPROPSHEETPAGE hpsp
,
784 PropSheetInfo
* psInfo
,
785 int index
, BOOL resize
)
787 const DLGTEMPLATE
* pTemplate
;
796 psInfo
->proppage
[index
].hpage
= hpsp
;
797 psInfo
->proppage
[index
].hwndPage
= 0;
798 psInfo
->proppage
[index
].isDirty
= FALSE
;
801 * Process property page flags.
803 dwFlags
= HPSP_get_flags(hpsp
);
804 psInfo
->proppage
[index
].hasHelp
= dwFlags
& PSP_HASHELP
;
805 psInfo
->proppage
[index
].hasIcon
= dwFlags
& (PSP_USEHICON
| PSP_USEICONID
);
807 /* as soon as we have a page with the help flag, set the sheet flag on */
808 if (psInfo
->proppage
[index
].hasHelp
)
809 psInfo
->hasHelp
= TRUE
;
812 * Process page template.
814 pTemplate
= HPSP_load_template(hpsp
, NULL
);
817 * Extract the size of the page and the caption.
822 p
= (const WORD
*)pTemplate
;
824 if (((const MyDLGTEMPLATEEX
*)pTemplate
)->signature
== 0xFFFF)
826 /* DLGTEMPLATEEX (not defined in any std. header file) */
830 p
+= 2; /* help ID */
831 p
+= 2; /* ext style */
839 p
+= 2; /* ext style */
845 width
= (WORD
)*p
; p
++;
846 height
= (WORD
)*p
; p
++;
848 if (HPSP_get_flags(hpsp
) & (PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
))
849 psInfo
->ppshheader
.dwFlags
|= PSH_HEADER
;
851 /* Special calculation for interior wizard pages so the largest page is
852 * calculated correctly. We need to add all the padding and space occupied
853 * by the header so the width and height sums up to the whole wizard client
855 if ((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
)) &&
856 (psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) &&
857 !(dwFlags
& PSP_HIDEHEADER
))
859 height
+= 2 * WIZARD_PADDING
+ WIZARD_HEADER_HEIGHT
;
860 width
+= 2 * WIZARD_PADDING
;
862 if (psInfo
->ppshheader
.dwFlags
& PSH_WIZARD
)
864 height
+= 2 * WIZARD_PADDING
;
865 width
+= 2 * WIZARD_PADDING
;
868 /* remember the largest width and height */
871 if (width
> psInfo
->width
)
872 psInfo
->width
= width
;
874 if (height
> psInfo
->height
)
875 psInfo
->height
= height
;
888 p
+= lstrlenW( p
) + 1;
902 p
+= lstrlenW( p
) + 1;
906 /* Extract the caption */
907 psInfo
->proppage
[index
].pszText
= p
;
908 TRACE("Tab %d %s\n",index
,debugstr_w( p
));
910 if (dwFlags
& PSP_USETITLE
)
911 psInfo
->proppage
[index
].pszText
= HPSP_get_title(hpsp
, p
);
914 * Build the image list for icons
916 if ((dwFlags
& PSP_USEHICON
) || (dwFlags
& PSP_USEICONID
))
919 int icon_cx
= GetSystemMetrics(SM_CXSMICON
);
920 int icon_cy
= GetSystemMetrics(SM_CYSMICON
);
922 if ((hIcon
= HPSP_get_icon(hpsp
)))
924 if (psInfo
->hImageList
== 0 )
925 psInfo
->hImageList
= ImageList_Create(icon_cx
, icon_cy
, ILC_COLOR
, 1, 1);
927 ImageList_AddIcon(psInfo
->hImageList
, hIcon
);
935 /******************************************************************************
936 * PROPSHEET_CreateDialog
938 * Creates the actual property sheet.
940 static INT_PTR
PROPSHEET_CreateDialog(PropSheetInfo
* psInfo
)
947 WORD resID
= IDD_PROPSHEET
;
949 TRACE("(%p)\n", psInfo
);
950 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
953 if( psInfo
->unicode
)
955 if(!(hRes
= FindResourceW(COMCTL32_hModule
,
956 MAKEINTRESOURCEW(resID
),
962 if(!(hRes
= FindResourceA(COMCTL32_hModule
,
963 MAKEINTRESOURCEA(resID
),
968 if(!(template = LoadResource(COMCTL32_hModule
, hRes
)))
972 * Make a copy of the dialog template.
974 resSize
= SizeofResource(COMCTL32_hModule
, hRes
);
976 temp
= Alloc(2 * resSize
);
981 memcpy(temp
, template, resSize
);
983 if (psInfo
->ppshheader
.dwFlags
& PSH_NOCONTEXTHELP
)
985 if (((MyDLGTEMPLATEEX
*)temp
)->signature
== 0xFFFF)
986 ((MyDLGTEMPLATEEX
*)temp
)->style
&= ~DS_CONTEXTHELP
;
988 ((DLGTEMPLATE
*)temp
)->style
&= ~DS_CONTEXTHELP
;
990 if ((psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
) &&
991 (psInfo
->ppshheader
.dwFlags
& PSH_WIZARDCONTEXTHELP
))
993 if (((MyDLGTEMPLATEEX
*)temp
)->signature
== 0xFFFF)
994 ((MyDLGTEMPLATEEX
*)temp
)->style
|= DS_CONTEXTHELP
;
996 ((DLGTEMPLATE
*)temp
)->style
|= DS_CONTEXTHELP
;
999 if (psInfo
->useCallback
)
1000 (*(psInfo
->ppshheader
.pfnCallback
))(0, PSCB_PRECREATE
, (LPARAM
)temp
);
1002 /* NOTE: MSDN states "Returns a positive value if successful, or -1
1003 * otherwise for modal property sheets.", but this is wrong. The
1004 * actual return value is either TRUE (success), FALSE (cancel) or
1006 if( psInfo
->unicode
)
1008 ret
= (INT_PTR
)CreateDialogIndirectParamW(psInfo
->ppshheader
.hInstance
,
1009 temp
, psInfo
->ppshheader
.hwndParent
,
1010 PROPSHEET_DialogProc
, (LPARAM
)psInfo
);
1011 if ( !ret
) ret
= -1;
1015 ret
= (INT_PTR
)CreateDialogIndirectParamA(psInfo
->ppshheader
.hInstance
,
1016 temp
, psInfo
->ppshheader
.hwndParent
,
1017 PROPSHEET_DialogProc
, (LPARAM
)psInfo
);
1018 if ( !ret
) ret
= -1;
1026 /******************************************************************************
1027 * PROPSHEET_SizeMismatch
1029 * Verify that the tab control and the "largest" property sheet page dlg. template
1032 static BOOL
PROPSHEET_SizeMismatch(HWND hwndDlg
, const PropSheetInfo
* psInfo
)
1034 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1035 RECT rcOrigTab
, rcPage
;
1038 * Original tab size.
1040 GetClientRect(hwndTabCtrl
, &rcOrigTab
);
1041 TRACE("orig tab %s\n", wine_dbgstr_rect(&rcOrigTab
));
1044 * Biggest page size.
1046 SetRect(&rcPage
, 0, 0, psInfo
->width
, psInfo
->height
);
1047 MapDialogRect(hwndDlg
, &rcPage
);
1048 TRACE("biggest page %s\n", wine_dbgstr_rect(&rcPage
));
1050 if ( (rcPage
.right
- rcPage
.left
) != (rcOrigTab
.right
- rcOrigTab
.left
) )
1052 if ( (rcPage
.bottom
- rcPage
.top
) != (rcOrigTab
.bottom
- rcOrigTab
.top
) )
1058 /******************************************************************************
1059 * PROPSHEET_AdjustSize
1061 * Resizes the property sheet and the tab control to fit the largest page.
1063 static BOOL
PROPSHEET_AdjustSize(HWND hwndDlg
, PropSheetInfo
* psInfo
)
1065 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1066 HWND hwndButton
= GetDlgItem(hwndDlg
, IDOK
);
1069 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndDlg
);
1073 /* Get the height of buttons */
1074 GetClientRect(hwndButton
, &rc
);
1075 buttonHeight
= rc
.bottom
;
1078 * Biggest page size.
1080 SetRect(&rc
, 0, 0, psInfo
->width
, psInfo
->height
);
1081 MapDialogRect(hwndDlg
, &rc
);
1083 /* retrieve the dialog units */
1084 units
.left
= units
.right
= 4;
1085 units
.top
= units
.bottom
= 8;
1086 MapDialogRect(hwndDlg
, &units
);
1089 * Resize the tab control.
1091 GetClientRect(hwndTabCtrl
,&tabRect
);
1093 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, FALSE
, (LPARAM
)&tabRect
);
1095 if ((rc
.bottom
- rc
.top
) < (tabRect
.bottom
- tabRect
.top
))
1097 rc
.bottom
= rc
.top
+ tabRect
.bottom
- tabRect
.top
;
1098 psInfo
->height
= MulDiv((rc
.bottom
- rc
.top
),8,units
.top
);
1101 if ((rc
.right
- rc
.left
) < (tabRect
.right
- tabRect
.left
))
1103 rc
.right
= rc
.left
+ tabRect
.right
- tabRect
.left
;
1104 psInfo
->width
= MulDiv((rc
.right
- rc
.left
),4,units
.left
);
1107 SendMessageW(hwndTabCtrl
, TCM_ADJUSTRECT
, TRUE
, (LPARAM
)&rc
);
1109 rc
.right
-= rc
.left
;
1110 rc
.bottom
-= rc
.top
;
1111 TRACE("setting tab %p, rc (0,0)-(%ld,%ld)\n", hwndTabCtrl
, rc
.right
, rc
.bottom
);
1112 SetWindowPos(hwndTabCtrl
, 0, 0, 0, rc
.right
, rc
.bottom
,
1113 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1115 GetClientRect(hwndTabCtrl
, &rc
);
1117 TRACE("tab client rc %s\n", wine_dbgstr_rect(&rc
));
1119 rc
.right
+= (padding
.x
* 2);
1120 rc
.bottom
+= buttonHeight
+ (3 * padding
.y
);
1122 style
= GetWindowLongW(hwndDlg
, GWL_STYLE
);
1123 if (!(style
& WS_CHILD
))
1124 AdjustWindowRect(&rc
, style
, FALSE
);
1126 rc
.right
-= rc
.left
;
1127 rc
.bottom
-= rc
.top
;
1130 * Resize the property sheet.
1132 TRACE("setting dialog %p, rc (0,0)-(%ld,%ld)\n", hwndDlg
, rc
.right
, rc
.bottom
);
1133 SetWindowPos(hwndDlg
, 0, 0, 0, rc
.right
, rc
.bottom
,
1134 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1138 /******************************************************************************
1139 * PROPSHEET_AdjustSizeWizard
1141 * Resizes the property sheet to fit the largest page.
1143 static BOOL
PROPSHEET_AdjustSizeWizard(HWND hwndDlg
, const PropSheetInfo
* psInfo
)
1145 HWND hwndLine
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINE
);
1146 RECT rc
, lineRect
, dialogRect
;
1148 /* Biggest page size */
1149 SetRect(&rc
, 0, 0, psInfo
->width
, psInfo
->height
);
1150 MapDialogRect(hwndDlg
, &rc
);
1152 TRACE("Biggest page %s\n", wine_dbgstr_rect(&rc
));
1154 /* Add space for the buttons row */
1155 GetWindowRect(hwndLine
, &lineRect
);
1156 MapWindowPoints(NULL
, hwndDlg
, (LPPOINT
)&lineRect
, 2);
1157 GetClientRect(hwndDlg
, &dialogRect
);
1158 rc
.bottom
+= dialogRect
.bottom
- lineRect
.top
- 1;
1160 /* Convert the client coordinates to window coordinates */
1161 AdjustWindowRect(&rc
, GetWindowLongW(hwndDlg
, GWL_STYLE
), FALSE
);
1163 /* Resize the property sheet */
1164 TRACE("setting dialog %p, rc (0,0)-(%ld,%ld)\n", hwndDlg
, rc
.right
, rc
.bottom
);
1165 SetWindowPos(hwndDlg
, 0, 0, 0, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
,
1166 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1171 /******************************************************************************
1172 * PROPSHEET_AdjustButtons
1174 * Adjusts the buttons' positions.
1176 static BOOL
PROPSHEET_AdjustButtons(HWND hwndParent
, const PropSheetInfo
* psInfo
)
1178 HWND hwndButton
= GetDlgItem(hwndParent
, IDOK
);
1181 int num_buttons
= 2;
1182 int buttonWidth
, buttonHeight
;
1183 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndParent
);
1185 if (psInfo
->hasApply
)
1188 if (psInfo
->hasHelp
)
1192 * Obtain the size of the buttons.
1194 GetClientRect(hwndButton
, &rcSheet
);
1195 buttonWidth
= rcSheet
.right
;
1196 buttonHeight
= rcSheet
.bottom
;
1199 * Get the size of the property sheet.
1201 GetClientRect(hwndParent
, &rcSheet
);
1204 * All buttons will be at this y coordinate.
1206 y
= rcSheet
.bottom
- (padding
.y
+ buttonHeight
);
1209 * Position OK button and make it default.
1211 hwndButton
= GetDlgItem(hwndParent
, IDOK
);
1213 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * num_buttons
);
1215 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1216 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1218 SendMessageW(hwndParent
, DM_SETDEFID
, IDOK
, 0);
1222 * Position Cancel button.
1224 hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
1226 x
+= padding
.x
+ buttonWidth
;
1228 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1229 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1232 * Position Apply button.
1234 hwndButton
= GetDlgItem(hwndParent
, IDC_APPLY_BUTTON
);
1236 if(psInfo
->hasApply
)
1237 x
+= padding
.x
+ buttonWidth
;
1239 ShowWindow(hwndButton
, SW_HIDE
);
1241 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1242 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1243 EnableWindow(hwndButton
, FALSE
);
1246 * Position Help button.
1248 hwndButton
= GetDlgItem(hwndParent
, IDHELP
);
1250 x
+= padding
.x
+ buttonWidth
;
1251 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1252 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1254 if(!psInfo
->hasHelp
)
1255 ShowWindow(hwndButton
, SW_HIDE
);
1260 /******************************************************************************
1261 * PROPSHEET_AdjustButtonsWizard
1263 * Adjusts the buttons' positions.
1265 static BOOL
PROPSHEET_AdjustButtonsWizard(HWND hwndParent
,
1266 const PropSheetInfo
* psInfo
)
1268 HWND hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
1269 HWND hwndLine
= GetDlgItem(hwndParent
, IDC_SUNKEN_LINE
);
1270 HWND hwndLineHeader
= GetDlgItem(hwndParent
, IDC_SUNKEN_LINEHEADER
);
1273 int num_buttons
= 3;
1274 int buttonWidth
, buttonHeight
, lineHeight
, lineWidth
;
1275 PADDING_INFO padding
= PROPSHEET_GetPaddingInfoWizard(hwndParent
, psInfo
);
1277 if (psInfo
->hasHelp
)
1279 if (psInfo
->hasFinish
)
1283 * Obtain the size of the buttons.
1285 GetClientRect(hwndButton
, &rcSheet
);
1286 buttonWidth
= rcSheet
.right
;
1287 buttonHeight
= rcSheet
.bottom
;
1289 GetClientRect(hwndLine
, &rcSheet
);
1290 lineHeight
= rcSheet
.bottom
;
1293 * Get the size of the property sheet.
1295 GetClientRect(hwndParent
, &rcSheet
);
1298 * All buttons will be at this y coordinate.
1300 y
= rcSheet
.bottom
- (padding
.y
+ buttonHeight
);
1303 * Position the Back button.
1305 hwndButton
= GetDlgItem(hwndParent
, IDC_BACK_BUTTON
);
1307 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * (num_buttons
- 1)) - buttonWidth
;
1309 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1310 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1313 * Position the Next button.
1315 hwndButton
= GetDlgItem(hwndParent
, IDC_NEXT_BUTTON
);
1319 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1320 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1323 * Position the Finish button.
1325 hwndButton
= GetDlgItem(hwndParent
, IDC_FINISH_BUTTON
);
1327 if (psInfo
->hasFinish
)
1328 x
+= padding
.x
+ buttonWidth
;
1330 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1331 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1333 if (!psInfo
->hasFinish
)
1334 ShowWindow(hwndButton
, SW_HIDE
);
1337 * Position the Cancel button.
1339 hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
1341 x
+= padding
.x
+ buttonWidth
;
1343 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1344 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1347 * Position Help button.
1349 hwndButton
= GetDlgItem(hwndParent
, IDHELP
);
1351 if (psInfo
->hasHelp
)
1353 x
+= padding
.x
+ buttonWidth
;
1355 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
1356 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
1359 ShowWindow(hwndButton
, SW_HIDE
);
1361 if (psInfo
->ppshheader
.dwFlags
&
1362 (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
| PSH_WIZARD_LITE
))
1366 * Position and resize the sunken line.
1369 y
= rcSheet
.bottom
- ((padding
.y
* 2) + buttonHeight
+ lineHeight
);
1371 lineWidth
= rcSheet
.right
- (padding
.x
* 2);
1372 SetWindowPos(hwndLine
, 0, x
, y
, lineWidth
, 2,
1373 SWP_NOZORDER
| SWP_NOACTIVATE
);
1376 * Position and resize the header sunken line.
1379 SetWindowPos(hwndLineHeader
, 0, 0, 0, rcSheet
.right
, 2,
1380 SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
);
1381 if (!(psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
)))
1382 ShowWindow(hwndLineHeader
, SW_HIDE
);
1387 /******************************************************************************
1388 * PROPSHEET_GetPaddingInfo
1390 * Returns the layout information.
1392 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
)
1394 HWND hwndTab
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1396 PADDING_INFO padding
;
1398 GetWindowRect(hwndTab
, &rcTab
);
1399 MapWindowPoints( 0, hwndDlg
, (POINT
*)&rcTab
, 2 );
1401 padding
.x
= rcTab
.left
;
1402 padding
.y
= rcTab
.top
;
1407 /******************************************************************************
1408 * PROPSHEET_GetPaddingInfoWizard
1410 * Returns the layout information.
1411 * Vertical spacing is the distance between the line and the buttons.
1412 * Do NOT use the Help button to gather padding information when it isn't mapped
1413 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
1414 * for it in this case !
1415 * FIXME: I'm not sure about any other coordinate problems with these evil
1416 * buttons. Fix it in case additional problems appear or maybe calculate
1417 * a padding in a completely different way, as this is somewhat messy.
1419 static PADDING_INFO
PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg
, const PropSheetInfo
*
1422 PADDING_INFO padding
;
1426 POINT ptButton
, ptLine
;
1429 if (psInfo
->hasHelp
)
1435 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
1437 idButton
= IDC_NEXT_BUTTON
;
1441 /* hopefully this is ok */
1442 idButton
= IDCANCEL
;
1446 hwndControl
= GetDlgItem(hwndDlg
, idButton
);
1447 GetWindowRect(hwndControl
, &rc
);
1448 MapWindowPoints( 0, hwndDlg
, (POINT
*)&rc
, 2 );
1449 ptButton
.x
= rc
.left
;
1450 ptButton
.y
= rc
.top
;
1453 hwndControl
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINE
);
1454 GetWindowRect(hwndControl
, &rc
);
1455 MapWindowPoints( 0, hwndDlg
, (POINT
*)&rc
, 2 );
1457 ptLine
.y
= rc
.bottom
;
1459 padding
.y
= ptButton
.y
- ptLine
.y
;
1462 ERR("padding negative ! Please report this !\n");
1464 /* this is most probably not correct, but the best we have now */
1465 padding
.x
= padding
.y
;
1469 /******************************************************************************
1470 * PROPSHEET_CreateTabControl
1472 * Insert the tabs in the tab control.
1474 static BOOL
PROPSHEET_CreateTabControl(HWND hwndParent
,
1475 const PropSheetInfo
* psInfo
)
1477 HWND hwndTabCtrl
= GetDlgItem(hwndParent
, IDC_TABCONTROL
);
1483 item
.mask
= TCIF_TEXT
;
1484 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
1486 nTabs
= psInfo
->nPages
;
1489 * Set the image list for icons.
1491 if (psInfo
->hImageList
)
1493 SendMessageW(hwndTabCtrl
, TCM_SETIMAGELIST
, 0, (LPARAM
)psInfo
->hImageList
);
1496 SendMessageW(hwndTabCtrl
, WM_SETREDRAW
, 0, 0);
1497 for (i
= 0; i
< nTabs
; i
++)
1499 if ( psInfo
->proppage
[i
].hasIcon
)
1501 item
.mask
|= TCIF_IMAGE
;
1502 item
.iImage
= iImage
++;
1506 item
.mask
&= ~TCIF_IMAGE
;
1509 item
.pszText
= (LPWSTR
) psInfo
->proppage
[i
].pszText
;
1510 SendMessageW(hwndTabCtrl
, TCM_INSERTITEMW
, i
, (LPARAM
)&item
);
1512 SendMessageW(hwndTabCtrl
, WM_SETREDRAW
, 1, 0);
1517 /******************************************************************************
1518 * PROPSHEET_WizardSubclassProc
1520 * Subclassing window procedure for wizard exterior pages to prevent drawing
1521 * background and so drawing above the watermark.
1523 static LRESULT CALLBACK
1524 PROPSHEET_WizardSubclassProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
, UINT_PTR uID
, DWORD_PTR dwRef
)
1531 case WM_CTLCOLORSTATIC
:
1532 SetBkColor((HDC
)wParam
, GetSysColor(COLOR_WINDOW
));
1533 return (INT_PTR
)GetSysColorBrush(COLOR_WINDOW
);
1536 return DefSubclassProc(hwnd
, uMsg
, wParam
, lParam
);
1539 /******************************************************************************
1540 * PROPSHEET_CreatePage
1544 static BOOL
PROPSHEET_CreatePage(HWND hwndParent
,
1546 const PropSheetInfo
* psInfo
,
1547 HPROPSHEETPAGE hpsp
)
1549 const DLGTEMPLATE
* pTemplate
;
1552 DLGTEMPLATE
* pTemplateCopy
= NULL
;
1554 TRACE("index %d\n", index
);
1561 pTemplate
= HPSP_load_template(hpsp
, &resSize
);
1562 pTemplateCopy
= Alloc(resSize
);
1566 TRACE("copying pTemplate %p into pTemplateCopy %p (%ld)\n", pTemplate
, pTemplateCopy
, resSize
);
1567 memcpy(pTemplateCopy
, pTemplate
, resSize
);
1569 if (((MyDLGTEMPLATEEX
*)pTemplateCopy
)->signature
== 0xFFFF)
1571 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
|= WS_CHILD
| WS_TABSTOP
| DS_CONTROL
;
1572 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~DS_MODALFRAME
;
1573 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_CAPTION
;
1574 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_SYSMENU
;
1575 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_POPUP
;
1576 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_DISABLED
;
1577 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_VISIBLE
;
1578 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->style
&= ~WS_THICKFRAME
;
1580 ((MyDLGTEMPLATEEX
*)pTemplateCopy
)->exStyle
|= WS_EX_CONTROLPARENT
;
1584 pTemplateCopy
->style
|= WS_CHILD
| WS_TABSTOP
| DS_CONTROL
;
1585 pTemplateCopy
->style
&= ~DS_MODALFRAME
;
1586 pTemplateCopy
->style
&= ~WS_CAPTION
;
1587 pTemplateCopy
->style
&= ~WS_SYSMENU
;
1588 pTemplateCopy
->style
&= ~WS_POPUP
;
1589 pTemplateCopy
->style
&= ~WS_DISABLED
;
1590 pTemplateCopy
->style
&= ~WS_VISIBLE
;
1591 pTemplateCopy
->style
&= ~WS_THICKFRAME
;
1593 pTemplateCopy
->dwExtendedStyle
|= WS_EX_CONTROLPARENT
;
1596 HPSP_call_callback(hpsp
, PSPCB_CREATE
);
1597 hwndPage
= HPSP_create_page(hpsp
, pTemplateCopy
, hwndParent
);
1598 /* Free a no more needed copy */
1599 Free(pTemplateCopy
);
1604 psInfo
->proppage
[index
].hwndPage
= hwndPage
;
1606 /* Subclass exterior wizard pages */
1607 if((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
)) &&
1608 (psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) &&
1609 (HPSP_get_flags(hpsp
) & PSP_HIDEHEADER
))
1611 SetWindowSubclass(hwndPage
, PROPSHEET_WizardSubclassProc
, 1, 0);
1613 if (!(psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
))
1614 EnableThemeDialogTexture (hwndPage
, ETDT_ENABLETAB
);
1619 /******************************************************************************
1620 * PROPSHEET_LoadWizardBitmaps
1622 * Loads the watermark and header bitmaps for a wizard.
1624 static VOID
PROPSHEET_LoadWizardBitmaps(PropSheetInfo
*psInfo
)
1626 if (psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
))
1628 /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark
1629 and put the HBITMAP in hbmWatermark. Thus all the rest of the code always
1630 considers hbmWatermark as valid. */
1631 if ((psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) &&
1632 !(psInfo
->ppshheader
.dwFlags
& PSH_USEHBMWATERMARK
))
1634 psInfo
->ppshheader
.hbmWatermark
=
1635 CreateMappedBitmap(psInfo
->ppshheader
.hInstance
, (INT_PTR
)psInfo
->ppshheader
.pszbmWatermark
, 0, NULL
, 0);
1638 /* Same behavior as for watermarks */
1639 if ((psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) &&
1640 !(psInfo
->ppshheader
.dwFlags
& PSH_USEHBMHEADER
))
1642 psInfo
->ppshheader
.hbmHeader
=
1643 CreateMappedBitmap(psInfo
->ppshheader
.hInstance
, (INT_PTR
)psInfo
->ppshheader
.pszbmHeader
, 0, NULL
, 0);
1649 /******************************************************************************
1650 * PROPSHEET_ShowPage
1652 * Displays or creates the specified page.
1654 static BOOL
PROPSHEET_ShowPage(HWND hwndDlg
, int index
, PropSheetInfo
* psInfo
)
1657 HWND hwndLineHeader
;
1660 TRACE("active_page %d, index %d\n", psInfo
->active_page
, index
);
1661 if (index
== psInfo
->active_page
)
1663 if (GetTopWindow(hwndDlg
) != psInfo
->proppage
[index
].hwndPage
)
1664 SetWindowPos(psInfo
->proppage
[index
].hwndPage
, HWND_TOP
, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
);
1668 if (psInfo
->proppage
[index
].hwndPage
== 0)
1670 PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, psInfo
->proppage
[index
].hpage
);
1673 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
1675 PROPSHEET_SetTitleW(hwndDlg
, psInfo
->ppshheader
.dwFlags
,
1676 psInfo
->proppage
[index
].pszText
);
1678 control
= GetNextDlgTabItem(psInfo
->proppage
[index
].hwndPage
, NULL
, FALSE
);
1683 if (psInfo
->active_page
!= -1)
1684 ShowWindow(psInfo
->proppage
[psInfo
->active_page
].hwndPage
, SW_HIDE
);
1686 ShowWindow(psInfo
->proppage
[index
].hwndPage
, SW_SHOW
);
1688 /* Synchronize current selection with tab control
1689 * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1690 hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1691 SendMessageW(hwndTabCtrl
, TCM_SETCURSEL
, index
, 0);
1693 psInfo
->active_page
= index
;
1694 psInfo
->activeValid
= TRUE
;
1696 if (psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
) )
1698 hwndLineHeader
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINEHEADER
);
1700 if ((HPSP_get_flags(psInfo
->proppage
[index
].hpage
) & PSP_HIDEHEADER
) ||
1701 (!(psInfo
->ppshheader
.dwFlags
& PSH_HEADER
)) )
1702 ShowWindow(hwndLineHeader
, SW_HIDE
);
1704 ShowWindow(hwndLineHeader
, SW_SHOW
);
1710 /******************************************************************************
1713 static BOOL
PROPSHEET_Back(HWND hwndDlg
)
1717 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1721 TRACE("active_page %d\n", psInfo
->active_page
);
1722 if (psInfo
->active_page
< 0)
1725 psn
.hdr
.code
= PSN_WIZBACK
;
1726 psn
.hdr
.hwndFrom
= hwndDlg
;
1730 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1732 result
= SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1735 else if (result
== 0)
1736 idx
= psInfo
->active_page
- 1;
1738 idx
= PROPSHEET_FindPageByResId(psInfo
, result
);
1740 if (idx
>= 0 && idx
< psInfo
->nPages
)
1742 if (PROPSHEET_CanSetCurSel(hwndDlg
))
1744 SetFocus(GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
));
1745 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_BACK_BUTTON
, 0);
1746 PROPSHEET_SetCurSel(hwndDlg
, idx
, -1, 0);
1752 /******************************************************************************
1755 static BOOL
PROPSHEET_Next(HWND hwndDlg
)
1759 LRESULT msgResult
= 0;
1760 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1763 TRACE("active_page %d\n", psInfo
->active_page
);
1764 if (psInfo
->active_page
< 0)
1767 psn
.hdr
.code
= PSN_WIZNEXT
;
1768 psn
.hdr
.hwndFrom
= hwndDlg
;
1772 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1774 msgResult
= SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1775 if (msgResult
== -1)
1777 else if (msgResult
== 0)
1778 idx
= psInfo
->active_page
+ 1;
1780 idx
= PROPSHEET_FindPageByResId(psInfo
, msgResult
);
1782 if (idx
< psInfo
->nPages
)
1784 if (PROPSHEET_CanSetCurSel(hwndDlg
) != FALSE
)
1786 SetFocus(GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
));
1787 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_NEXT_BUTTON
, 0);
1788 PROPSHEET_SetCurSel(hwndDlg
, idx
, 1, 0);
1795 /******************************************************************************
1798 static BOOL
PROPSHEET_Finish(HWND hwndDlg
)
1802 LRESULT msgResult
= 0;
1803 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1805 TRACE("active_page %d\n", psInfo
->active_page
);
1806 if (psInfo
->active_page
< 0)
1809 psn
.hdr
.code
= PSN_WIZFINISH
;
1810 psn
.hdr
.hwndFrom
= hwndDlg
;
1814 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1816 msgResult
= SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1818 TRACE("msg result %Id\n", msgResult
);
1823 if (psInfo
->result
== 0)
1824 psInfo
->result
= IDOK
;
1825 if (psInfo
->isModeless
)
1826 psInfo
->activeValid
= FALSE
;
1828 psInfo
->ended
= TRUE
;
1833 /******************************************************************************
1836 static BOOL
PROPSHEET_Apply(HWND hwndDlg
, LPARAM lParam
)
1841 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1843 TRACE("active_page %d\n", psInfo
->active_page
);
1844 if (psInfo
->active_page
< 0)
1847 psn
.hdr
.hwndFrom
= hwndDlg
;
1853 * Send PSN_KILLACTIVE to the current page.
1855 psn
.hdr
.code
= PSN_KILLACTIVE
;
1857 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1859 if (SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
) != FALSE
)
1863 * Send PSN_APPLY to all pages.
1865 psn
.hdr
.code
= PSN_APPLY
;
1866 psn
.lParam
= lParam
;
1868 for (i
= 0; i
< psInfo
->nPages
; i
++)
1870 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
1873 switch (SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
))
1875 case PSNRET_INVALID
:
1876 PROPSHEET_ShowPage(hwndDlg
, i
, psInfo
);
1878 case PSNRET_INVALID_NOCHANGEPAGE
:
1886 psInfo
->activeValid
= FALSE
;
1888 else if(psInfo
->active_page
>= 0)
1890 psn
.hdr
.code
= PSN_SETACTIVE
;
1892 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1893 SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1899 /******************************************************************************
1902 static void PROPSHEET_Cancel(HWND hwndDlg
, LPARAM lParam
)
1904 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1909 TRACE("active_page %d\n", psInfo
->active_page
);
1910 if (psInfo
->active_page
< 0)
1913 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1914 psn
.hdr
.code
= PSN_QUERYCANCEL
;
1915 psn
.hdr
.hwndFrom
= hwndDlg
;
1919 if (SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
))
1922 psn
.hdr
.code
= PSN_RESET
;
1923 psn
.lParam
= lParam
;
1925 for (i
= 0; i
< psInfo
->nPages
; i
++)
1927 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
1930 SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1933 if (psInfo
->isModeless
)
1935 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1936 psInfo
->activeValid
= FALSE
;
1939 psInfo
->ended
= TRUE
;
1942 /******************************************************************************
1945 static void PROPSHEET_Help(HWND hwndDlg
)
1947 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1951 TRACE("active_page %d\n", psInfo
->active_page
);
1952 if (psInfo
->active_page
< 0)
1955 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1956 psn
.hdr
.code
= PSN_HELP
;
1957 psn
.hdr
.hwndFrom
= hwndDlg
;
1961 SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
1964 /******************************************************************************
1967 static void PROPSHEET_Changed(HWND hwndDlg
, HWND hwndDirtyPage
)
1970 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
1973 if (!psInfo
) return;
1975 * Set the dirty flag of this page.
1977 for (i
= 0; i
< psInfo
->nPages
; i
++)
1979 if (psInfo
->proppage
[i
].hwndPage
== hwndDirtyPage
)
1980 psInfo
->proppage
[i
].isDirty
= TRUE
;
1984 * Enable the Apply button.
1986 if (psInfo
->hasApply
)
1988 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
1990 EnableWindow(hwndApplyBtn
, TRUE
);
1994 /******************************************************************************
1995 * PROPSHEET_UnChanged
1997 static void PROPSHEET_UnChanged(HWND hwndDlg
, HWND hwndCleanPage
)
2000 BOOL noPageDirty
= TRUE
;
2001 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
2002 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2005 if ( !psInfo
) return;
2006 for (i
= 0; i
< psInfo
->nPages
; i
++)
2008 /* set the specified page as clean */
2009 if (psInfo
->proppage
[i
].hwndPage
== hwndCleanPage
)
2010 psInfo
->proppage
[i
].isDirty
= FALSE
;
2012 /* look to see if there are any dirty pages */
2013 if (psInfo
->proppage
[i
].isDirty
)
2014 noPageDirty
= FALSE
;
2018 * Disable Apply button.
2021 EnableWindow(hwndApplyBtn
, FALSE
);
2024 /******************************************************************************
2025 * PROPSHEET_PressButton
2027 static void PROPSHEET_PressButton(HWND hwndDlg
, int buttonID
)
2029 TRACE("buttonID %d\n", buttonID
);
2032 case PSBTN_APPLYNOW
:
2033 PROPSHEET_DoCommand(hwndDlg
, IDC_APPLY_BUTTON
);
2036 PROPSHEET_Back(hwndDlg
);
2039 PROPSHEET_DoCommand(hwndDlg
, IDCANCEL
);
2042 PROPSHEET_Finish(hwndDlg
);
2045 PROPSHEET_DoCommand(hwndDlg
, IDHELP
);
2048 PROPSHEET_Next(hwndDlg
);
2051 PROPSHEET_DoCommand(hwndDlg
, IDOK
);
2054 FIXME("Invalid button index %d\n", buttonID
);
2059 /*************************************************************************
2060 * BOOL PROPSHEET_CanSetCurSel [Internal]
2062 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
2065 * hwndDlg [I] handle to a Dialog hWnd
2068 * TRUE if Current Selection can change
2072 static BOOL
PROPSHEET_CanSetCurSel(HWND hwndDlg
)
2074 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2085 TRACE("active_page %d\n", psInfo
->active_page
);
2086 if (psInfo
->active_page
< 0)
2093 * Notify the current page.
2095 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
2096 psn
.hdr
.code
= PSN_KILLACTIVE
;
2097 psn
.hdr
.hwndFrom
= hwndDlg
;
2101 res
= !SendMessageW(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
2104 TRACE("<-- %d\n", res
);
2108 /******************************************************************************
2109 * PROPSHEET_SetCurSel
2111 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
2114 HPROPSHEETPAGE hpage
2117 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2118 HWND hwndHelp
= GetDlgItem(hwndDlg
, IDHELP
);
2119 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
2121 TRACE("index %d, skipdir %d, hpage %p\n", index
, skipdir
, hpage
);
2123 index
= PROPSHEET_GetPageIndex(hpage
, psInfo
, index
);
2125 if (index
< 0 || index
>= psInfo
->nPages
)
2127 TRACE("Could not find page to select!\n");
2131 /* unset active page while doing this transition. */
2132 if (psInfo
->active_page
!= -1)
2133 ShowWindow(psInfo
->proppage
[psInfo
->active_page
].hwndPage
, SW_HIDE
);
2134 psInfo
->active_page
= -1;
2142 SendMessageW(hwndTabControl
, TCM_SETCURSEL
, index
, 0);
2144 psn
.hdr
.code
= PSN_SETACTIVE
;
2145 psn
.hdr
.hwndFrom
= hwndDlg
;
2149 if (!psInfo
->proppage
[index
].hwndPage
) {
2150 if(!PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, psInfo
->proppage
[index
].hpage
)) {
2151 PROPSHEET_RemovePage(hwndDlg
, index
, NULL
);
2153 if (!psInfo
->isModeless
)
2155 DestroyWindow(hwndDlg
);
2159 if(index
>= psInfo
->nPages
)
2167 /* Resize the property sheet page to the fit in the Tab control
2168 * (for regular property sheets) or to fit in the client area (for
2170 * NOTE: The resizing happens every time the page is selected and
2171 * not only when it's created (some applications depend on it). */
2172 PROPSHEET_GetPageRect(psInfo
, hwndDlg
, &rc
, psInfo
->proppage
[index
].hpage
);
2173 TRACE("setting page %p, rc (%s) w=%ld, h=%ld\n",
2174 psInfo
->proppage
[index
].hwndPage
, wine_dbgstr_rect(&rc
),
2175 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
);
2176 SetWindowPos(psInfo
->proppage
[index
].hwndPage
, HWND_TOP
,
2178 rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, 0);
2180 result
= SendMessageW(psInfo
->proppage
[index
].hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &psn
);
2187 WARN("Tried to skip before first property sheet page!\n");
2190 if (index
>= psInfo
->nPages
) {
2191 WARN("Tried to skip after last property sheet page!\n");
2192 index
= psInfo
->nPages
-1;
2196 else if (result
!= 0)
2198 int old_index
= index
;
2199 index
= PROPSHEET_FindPageByResId(psInfo
, result
);
2200 if(index
>= psInfo
->nPages
) {
2202 WARN("Tried to skip to nonexistent page by res id\n");
2209 /* Invalidate the header area */
2210 if ( (psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
)) &&
2211 (psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) )
2213 HWND hwndLineHeader
= GetDlgItem(hwndDlg
, IDC_SUNKEN_LINEHEADER
);
2216 GetClientRect(hwndLineHeader
, &r
);
2217 MapWindowPoints(hwndLineHeader
, hwndDlg
, (LPPOINT
) &r
, 2);
2218 SetRect(&r
, 0, 0, r
.right
+ 1, r
.top
- 1);
2220 InvalidateRect(hwndDlg
, &r
, TRUE
);
2224 * Display the new page.
2226 PROPSHEET_ShowPage(hwndDlg
, index
, psInfo
);
2228 if (psInfo
->proppage
[index
].hasHelp
)
2229 EnableWindow(hwndHelp
, TRUE
);
2231 EnableWindow(hwndHelp
, FALSE
);
2236 /******************************************************************************
2237 * PROPSHEET_SetCurSelId
2239 * Selects the page, specified by resource id.
2241 static void PROPSHEET_SetCurSelId(HWND hwndDlg
, int id
)
2244 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2246 idx
= PROPSHEET_FindPageByResId(psInfo
, id
);
2247 if (idx
< psInfo
->nPages
)
2249 if (PROPSHEET_CanSetCurSel(hwndDlg
) != FALSE
)
2250 PROPSHEET_SetCurSel(hwndDlg
, idx
, 1, 0);
2254 /******************************************************************************
2255 * PROPSHEET_SetTitleA
2257 static void PROPSHEET_SetTitleA(HWND hwndDlg
, DWORD dwStyle
, LPCSTR lpszText
)
2259 if(!IS_INTRESOURCE(lpszText
))
2262 MultiByteToWideChar(CP_ACP
, 0, lpszText
, -1, szTitle
, ARRAY_SIZE(szTitle
));
2263 PROPSHEET_SetTitleW(hwndDlg
, dwStyle
, szTitle
);
2267 PROPSHEET_SetTitleW(hwndDlg
, dwStyle
, (LPCWSTR
)lpszText
);
2271 /******************************************************************************
2272 * PROPSHEET_SetTitleW
2274 static void PROPSHEET_SetTitleW(HWND hwndDlg
, DWORD dwStyle
, LPCWSTR lpszText
)
2276 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2279 TRACE("%s (style %#lx)\n", debugstr_w(lpszText
), dwStyle
);
2280 if (IS_INTRESOURCE(lpszText
)) {
2281 if (!LoadStringW(psInfo
->ppshheader
.hInstance
, LOWORD(lpszText
), szTitle
, ARRAY_SIZE(szTitle
)))
2285 if (dwStyle
& PSH_PROPTITLE
)
2288 int lentitle
= lstrlenW(lpszText
);
2289 int lenprop
= lstrlenW(psInfo
->strPropertiesFor
);
2291 dest
= Alloc( (lentitle
+ lenprop
+ 1)*sizeof (WCHAR
));
2292 wsprintfW(dest
, psInfo
->strPropertiesFor
, lpszText
);
2294 SetWindowTextW(hwndDlg
, dest
);
2298 SetWindowTextW(hwndDlg
, lpszText
);
2301 /******************************************************************************
2302 * PROPSHEET_SetFinishTextA
2304 static void PROPSHEET_SetFinishTextA(HWND hwndDlg
, LPCSTR lpszText
)
2306 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2307 HWND hwndButton
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
2309 TRACE("'%s'\n", lpszText
);
2310 /* Set text, show and enable the Finish button */
2311 SetWindowTextA(hwndButton
, lpszText
);
2312 ShowWindow(hwndButton
, SW_SHOW
);
2313 EnableWindow(hwndButton
, TRUE
);
2315 /* Make it default pushbutton */
2316 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
2318 /* Hide Back button */
2319 hwndButton
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
2320 ShowWindow(hwndButton
, SW_HIDE
);
2322 if (!psInfo
->hasFinish
)
2324 /* Hide Next button */
2325 hwndButton
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
2326 ShowWindow(hwndButton
, SW_HIDE
);
2330 /******************************************************************************
2331 * PROPSHEET_SetFinishTextW
2333 static void PROPSHEET_SetFinishTextW(HWND hwndDlg
, LPCWSTR lpszText
)
2335 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2336 HWND hwndButton
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
2338 TRACE("%s\n", debugstr_w(lpszText
));
2339 /* Set text, show and enable the Finish button */
2340 SetWindowTextW(hwndButton
, lpszText
);
2341 ShowWindow(hwndButton
, SW_SHOW
);
2342 EnableWindow(hwndButton
, TRUE
);
2344 /* Make it default pushbutton */
2345 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
2347 /* Hide Back button */
2348 hwndButton
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
2349 ShowWindow(hwndButton
, SW_HIDE
);
2351 if (!psInfo
->hasFinish
)
2353 /* Hide Next button */
2354 hwndButton
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
2355 ShowWindow(hwndButton
, SW_HIDE
);
2359 /******************************************************************************
2360 * PROPSHEET_QuerySiblings
2362 static LRESULT
PROPSHEET_QuerySiblings(HWND hwndDlg
,
2363 WPARAM wParam
, LPARAM lParam
)
2367 LRESULT msgResult
= 0;
2368 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2370 while ((i
< psInfo
->nPages
) && (msgResult
== 0))
2372 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
2373 msgResult
= SendMessageW(hwndPage
, PSM_QUERYSIBLINGS
, wParam
, lParam
);
2380 /******************************************************************************
2381 * PROPSHEET_InsertPage
2383 static BOOL
PROPSHEET_InsertPage(HWND hwndDlg
, HPROPSHEETPAGE hpageInsertAfter
, HPROPSHEETPAGE hpage
)
2385 PropSheetInfo
*psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2386 PropPageInfo
*ppi
, *prev_ppi
= psInfo
->proppage
;
2387 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
2391 TRACE("hwndDlg %p, hpageInsertAfter %p, hpage %p\n", hwndDlg
, hpageInsertAfter
, hpage
);
2393 if (IS_INTRESOURCE(hpageInsertAfter
))
2394 index
= LOWORD(hpageInsertAfter
);
2397 index
= PROPSHEET_GetPageIndex(hpageInsertAfter
, psInfo
, -1);
2400 TRACE("Could not find page to insert after!\n");
2406 if (index
> psInfo
->nPages
)
2407 index
= psInfo
->nPages
;
2409 ppi
= Alloc(sizeof(PropPageInfo
) * (psInfo
->nPages
+ 1));
2413 if (hpage
&& hpage
->magic
!= HPROPSHEETPAGE_MAGIC
)
2415 if (psInfo
->unicode
)
2416 hpage
= CreatePropertySheetPageW((const PROPSHEETPAGEW
*)hpage
);
2418 hpage
= CreatePropertySheetPageA((const PROPSHEETPAGEA
*)hpage
);
2422 * Fill in a new PropPageInfo entry.
2425 memcpy(ppi
, prev_ppi
, index
* sizeof(PropPageInfo
));
2426 memset(&ppi
[index
], 0, sizeof(PropPageInfo
));
2427 if (index
< psInfo
->nPages
)
2428 memcpy(&ppi
[index
+ 1], &prev_ppi
[index
], (psInfo
->nPages
- index
) * sizeof(PropPageInfo
));
2429 psInfo
->proppage
= ppi
;
2431 if (!PROPSHEET_CollectPageInfo(hpage
, psInfo
, index
, FALSE
))
2433 psInfo
->proppage
= prev_ppi
;
2438 psInfo
->proppage
[index
].hpage
= hpage
;
2440 if (HPSP_get_flags(hpage
) & PSP_PREMATURE
)
2442 /* Create the page but don't show it */
2443 if (!PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, hpage
))
2445 psInfo
->proppage
= prev_ppi
;
2453 if (index
<= psInfo
->active_page
)
2454 psInfo
->active_page
++;
2457 * Add a new tab to the tab control.
2459 item
.mask
= TCIF_TEXT
;
2460 item
.pszText
= (LPWSTR
) psInfo
->proppage
[index
].pszText
;
2461 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
2463 if (psInfo
->hImageList
)
2464 SendMessageW(hwndTabControl
, TCM_SETIMAGELIST
, 0, (LPARAM
)psInfo
->hImageList
);
2466 if (psInfo
->proppage
[index
].hasIcon
)
2468 item
.mask
|= TCIF_IMAGE
;
2469 item
.iImage
= index
;
2472 SendMessageW(hwndTabControl
, TCM_INSERTITEMW
, index
, (LPARAM
)&item
);
2474 /* If it is the only page - show it */
2475 if (psInfo
->nPages
== 1)
2476 PROPSHEET_SetCurSel(hwndDlg
, 0, 1, 0);
2481 /******************************************************************************
2484 static BOOL
PROPSHEET_AddPage(HWND hwndDlg
, HPROPSHEETPAGE hpage
)
2486 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2487 TRACE("hwndDlg %p, hpage %p\n", hwndDlg
, hpage
);
2488 return PROPSHEET_InsertPage(hwndDlg
, UlongToPtr(psInfo
->nPages
), hpage
);
2491 /******************************************************************************
2492 * PROPSHEET_RemovePage
2494 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
,
2496 HPROPSHEETPAGE hpage
)
2498 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2499 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
2500 PropPageInfo
* oldPages
;
2502 TRACE("index %d, hpage %p\n", index
, hpage
);
2507 index
= PROPSHEET_GetPageIndex(hpage
, psInfo
, index
);
2509 /* Make sure that index is within range */
2510 if (index
< 0 || index
>= psInfo
->nPages
)
2512 TRACE("Could not find page to remove!\n");
2516 TRACE("total pages %d removing page %d active page %d\n",
2517 psInfo
->nPages
, index
, psInfo
->active_page
);
2519 * Check if we're removing the active page.
2521 if (index
== psInfo
->active_page
)
2523 if (psInfo
->nPages
> 1)
2527 /* activate previous page */
2528 PROPSHEET_SetCurSel(hwndDlg
, index
- 1, -1, 0);
2532 /* activate the next page */
2533 PROPSHEET_SetCurSel(hwndDlg
, index
+ 1, 1, 0);
2534 psInfo
->active_page
= index
;
2539 psInfo
->active_page
= -1;
2540 if (!psInfo
->isModeless
)
2542 psInfo
->ended
= TRUE
;
2547 else if (index
< psInfo
->active_page
)
2548 psInfo
->active_page
--;
2550 /* Unsubclass the page dialog window */
2551 if((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
)) &&
2552 (psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) &&
2553 (HPSP_get_flags(psInfo
->proppage
[index
].hpage
) & PSP_HIDEHEADER
))
2555 RemoveWindowSubclass(psInfo
->proppage
[index
].hwndPage
,
2556 PROPSHEET_WizardSubclassProc
, 1);
2559 /* Destroy page dialog window */
2560 DestroyWindow(psInfo
->proppage
[index
].hwndPage
);
2562 /* Free page resources */
2563 if(psInfo
->proppage
[index
].hpage
)
2565 if (HPSP_get_flags(psInfo
->proppage
[index
].hpage
) & PSP_USETITLE
)
2566 Free ((LPVOID
)psInfo
->proppage
[index
].pszText
);
2568 DestroyPropertySheetPage(psInfo
->proppage
[index
].hpage
);
2571 /* Remove the tab */
2572 SendMessageW(hwndTabControl
, TCM_DELETEITEM
, index
, 0);
2574 oldPages
= psInfo
->proppage
;
2576 psInfo
->proppage
= Alloc(sizeof(PropPageInfo
) * psInfo
->nPages
);
2579 memcpy(&psInfo
->proppage
[0], &oldPages
[0], index
* sizeof(PropPageInfo
));
2581 if (index
< psInfo
->nPages
)
2582 memcpy(&psInfo
->proppage
[index
], &oldPages
[index
+ 1],
2583 (psInfo
->nPages
- index
) * sizeof(PropPageInfo
));
2590 /******************************************************************************
2591 * PROPSHEET_SetWizButtons
2593 * This code will work if (and assumes that) the Next button is on top of the
2594 * Finish button. ie. Finish comes after Next in the Z order.
2595 * This means make sure the dialog template reflects this.
2598 static void PROPSHEET_SetWizButtons(HWND hwndDlg
, DWORD dwFlags
)
2600 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2601 HWND hwndBack
= GetDlgItem(hwndDlg
, IDC_BACK_BUTTON
);
2602 HWND hwndNext
= GetDlgItem(hwndDlg
, IDC_NEXT_BUTTON
);
2603 HWND hwndFinish
= GetDlgItem(hwndDlg
, IDC_FINISH_BUTTON
);
2604 BOOL enable_finish
= ((dwFlags
& PSWIZB_FINISH
) || psInfo
->hasFinish
) && !(dwFlags
& PSWIZB_DISABLEDFINISH
);
2606 TRACE("%lx\n", dwFlags
);
2608 EnableWindow(hwndBack
, dwFlags
& PSWIZB_BACK
);
2609 EnableWindow(hwndNext
, dwFlags
& PSWIZB_NEXT
);
2610 EnableWindow(hwndFinish
, enable_finish
);
2612 /* set the default pushbutton to an enabled button */
2614 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_FINISH_BUTTON
, 0);
2615 else if (dwFlags
& PSWIZB_NEXT
)
2616 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_NEXT_BUTTON
, 0);
2617 else if (dwFlags
& PSWIZB_BACK
)
2618 SendMessageW(hwndDlg
, DM_SETDEFID
, IDC_BACK_BUTTON
, 0);
2620 SendMessageW(hwndDlg
, DM_SETDEFID
, IDCANCEL
, 0);
2622 if (!psInfo
->hasFinish
)
2624 if ((dwFlags
& PSWIZB_FINISH
) || (dwFlags
& PSWIZB_DISABLEDFINISH
))
2626 /* Hide the Next button */
2627 ShowWindow(hwndNext
, SW_HIDE
);
2629 /* Show the Finish button */
2630 ShowWindow(hwndFinish
, SW_SHOW
);
2634 /* Hide the Finish button */
2635 ShowWindow(hwndFinish
, SW_HIDE
);
2636 /* Show the Next button */
2637 ShowWindow(hwndNext
, SW_SHOW
);
2642 /******************************************************************************
2643 * PROPSHEET_SetHeaderTitleW
2645 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg
, UINT page_index
, const WCHAR
*title
)
2647 PropSheetInfo
*psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2649 TRACE("(%p, %u, %s)\n", hwndDlg
, page_index
, debugstr_w(title
));
2651 if (page_index
>= psInfo
->nPages
)
2654 HPSP_set_header_title(psInfo
->proppage
[page_index
].hpage
, title
);
2657 /******************************************************************************
2658 * PROPSHEET_SetHeaderTitleA
2660 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg
, UINT page_index
, const char *title
)
2664 TRACE("(%p, %u, %s)\n", hwndDlg
, page_index
, debugstr_a(title
));
2666 titleW
= heap_strdupAtoW(title
);
2667 PROPSHEET_SetHeaderTitleW(hwndDlg
, page_index
, titleW
);
2671 /******************************************************************************
2672 * PROPSHEET_SetHeaderSubTitleW
2674 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg
, UINT page_index
, const WCHAR
*subtitle
)
2676 PropSheetInfo
*psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2678 TRACE("(%p, %u, %s)\n", hwndDlg
, page_index
, debugstr_w(subtitle
));
2680 if (page_index
>= psInfo
->nPages
)
2683 HPSP_set_header_subtitle(psInfo
->proppage
[page_index
].hpage
, subtitle
);
2686 /******************************************************************************
2687 * PROPSHEET_SetHeaderSubTitleA
2689 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg
, UINT page_index
, const char *subtitle
)
2693 TRACE("(%p, %u, %s)\n", hwndDlg
, page_index
, debugstr_a(subtitle
));
2695 subtitleW
= heap_strdupAtoW(subtitle
);
2696 PROPSHEET_SetHeaderSubTitleW(hwndDlg
, page_index
, subtitleW
);
2700 /******************************************************************************
2701 * PROPSHEET_HwndToIndex
2703 static LRESULT
PROPSHEET_HwndToIndex(HWND hwndDlg
, HWND hPageDlg
)
2706 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2708 TRACE("(%p, %p)\n", hwndDlg
, hPageDlg
);
2710 for (index
= 0; index
< psInfo
->nPages
; index
++)
2711 if (psInfo
->proppage
[index
].hwndPage
== hPageDlg
)
2713 WARN("%p not found\n", hPageDlg
);
2717 /******************************************************************************
2718 * PROPSHEET_IndexToHwnd
2720 static LRESULT
PROPSHEET_IndexToHwnd(HWND hwndDlg
, int iPageIndex
)
2722 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2723 TRACE("(%p, %d)\n", hwndDlg
, iPageIndex
);
2726 if (iPageIndex
<0 || iPageIndex
>=psInfo
->nPages
) {
2727 WARN("%d out of range.\n", iPageIndex
);
2730 return (LRESULT
)psInfo
->proppage
[iPageIndex
].hwndPage
;
2733 /******************************************************************************
2734 * PROPSHEET_PageToIndex
2736 static LRESULT
PROPSHEET_PageToIndex(HWND hwndDlg
, HPROPSHEETPAGE hPage
)
2738 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2740 TRACE("(%p, %p)\n", hwndDlg
, hPage
);
2742 return PROPSHEET_GetPageIndex(hPage
, psInfo
, -1);
2745 /******************************************************************************
2746 * PROPSHEET_IndexToPage
2748 static LRESULT
PROPSHEET_IndexToPage(HWND hwndDlg
, int iPageIndex
)
2750 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2751 TRACE("(%p, %d)\n", hwndDlg
, iPageIndex
);
2752 if (iPageIndex
<0 || iPageIndex
>=psInfo
->nPages
) {
2753 WARN("%d out of range.\n", iPageIndex
);
2756 return (LRESULT
)psInfo
->proppage
[iPageIndex
].hpage
;
2759 /******************************************************************************
2760 * PROPSHEET_IdToIndex
2762 static LRESULT
PROPSHEET_IdToIndex(HWND hwndDlg
, int iPageId
)
2765 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2766 TRACE("(%p, %d)\n", hwndDlg
, iPageId
);
2767 for (index
= 0; index
< psInfo
->nPages
; index
++) {
2768 if (HPSP_get_template(psInfo
->proppage
[index
].hpage
) == iPageId
)
2775 /******************************************************************************
2776 * PROPSHEET_IndexToId
2778 static LRESULT
PROPSHEET_IndexToId(HWND hwndDlg
, int iPageIndex
)
2780 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2781 HPROPSHEETPAGE hpsp
;
2784 TRACE("(%p, %d)\n", hwndDlg
, iPageIndex
);
2786 if (iPageIndex
<0 || iPageIndex
>=psInfo
->nPages
) {
2787 WARN("%d out of range.\n", iPageIndex
);
2790 hpsp
= psInfo
->proppage
[iPageIndex
].hpage
;
2791 template = HPSP_get_template(hpsp
);
2792 if (HPSP_get_flags(hpsp
) & PSP_DLGINDIRECT
|| !IS_INTRESOURCE(template))
2797 /******************************************************************************
2798 * PROPSHEET_GetResult
2800 static LRESULT
PROPSHEET_GetResult(HWND hwndDlg
)
2802 PropSheetInfo
* psInfo
= GetPropW(hwndDlg
, PropSheetInfoStr
);
2803 return psInfo
->result
;
2806 /******************************************************************************
2807 * PROPSHEET_RecalcPageSizes
2809 static BOOL
PROPSHEET_RecalcPageSizes(HWND hwndDlg
)
2811 FIXME("(%p): stub\n", hwndDlg
);
2815 /******************************************************************************
2816 * PROPSHEET_GetPageIndex
2818 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
2819 * the array of PropPageInfo. If page is not found original index is used
2820 * (page takes precedence over index).
2822 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE page
, const PropSheetInfo
* psInfo
, int original_index
)
2826 TRACE("page %p index %d\n", page
, original_index
);
2828 for (index
= 0; index
< psInfo
->nPages
; index
++)
2829 if (psInfo
->proppage
[index
].hpage
== page
)
2832 return original_index
;
2835 /******************************************************************************
2838 static void PROPSHEET_CleanUp(HWND hwndDlg
)
2841 PropSheetInfo
* psInfo
= RemovePropW(hwndDlg
, PropSheetInfoStr
);
2844 if (!psInfo
) return;
2845 if (!IS_INTRESOURCE(psInfo
->ppshheader
.pszCaption
))
2846 Free ((LPVOID
)psInfo
->ppshheader
.pszCaption
);
2848 for (i
= 0; i
< psInfo
->nPages
; i
++)
2850 DWORD flags
= HPSP_get_flags(psInfo
->proppage
[i
].hpage
);
2852 /* Unsubclass the page dialog window */
2853 if((psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_NEW
| PSH_WIZARD97_OLD
)) &&
2854 (psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) &&
2855 (flags
& PSP_HIDEHEADER
))
2857 RemoveWindowSubclass(psInfo
->proppage
[i
].hwndPage
,
2858 PROPSHEET_WizardSubclassProc
, 1);
2861 if(psInfo
->proppage
[i
].hwndPage
)
2862 DestroyWindow(psInfo
->proppage
[i
].hwndPage
);
2864 if (flags
& PSP_USETITLE
)
2865 Free ((LPVOID
)psInfo
->proppage
[i
].pszText
);
2867 DestroyPropertySheetPage(psInfo
->proppage
[i
].hpage
);
2870 DeleteObject(psInfo
->hFont
);
2871 DeleteObject(psInfo
->hFontBold
);
2872 /* If we created the bitmaps, destroy them */
2873 if ((psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) &&
2874 (!(psInfo
->ppshheader
.dwFlags
& PSH_USEHBMWATERMARK
)) )
2875 DeleteObject(psInfo
->ppshheader
.hbmWatermark
);
2876 if ((psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) &&
2877 (!(psInfo
->ppshheader
.dwFlags
& PSH_USEHBMHEADER
)) )
2878 DeleteObject(psInfo
->ppshheader
.hbmHeader
);
2880 Free(psInfo
->proppage
);
2881 Free(psInfo
->strPropertiesFor
);
2882 ImageList_Destroy(psInfo
->hImageList
);
2887 static INT
do_loop(const PropSheetInfo
*psInfo
)
2891 HWND hwnd
= psInfo
->hwnd
;
2892 HWND parent
= psInfo
->ppshheader
.hwndParent
;
2894 while(IsWindow(hwnd
) && !psInfo
->ended
&& (ret
= GetMessageW(&msg
, NULL
, 0, 0)))
2899 if(!IsDialogMessageW(hwnd
, &msg
))
2901 TranslateMessage(&msg
);
2902 DispatchMessageW(&msg
);
2906 if(ret
== 0 && msg
.message
)
2907 PostQuitMessage(msg
.wParam
);
2910 ret
= psInfo
->result
;
2913 EnableWindow(parent
, TRUE
);
2915 DestroyWindow(hwnd
);
2919 /******************************************************************************
2920 * PROPSHEET_PropertySheet
2922 * Common code between PropertySheetA/W
2924 static INT_PTR
PROPSHEET_PropertySheet(PropSheetInfo
* psInfo
, BOOL unicode
)
2928 if (psInfo
->active_page
>= psInfo
->nPages
) psInfo
->active_page
= 0;
2929 TRACE("startpage: %d of %d pages\n", psInfo
->active_page
, psInfo
->nPages
);
2931 psInfo
->unicode
= unicode
;
2932 psInfo
->ended
= FALSE
;
2934 if(!psInfo
->isModeless
)
2936 parent
= psInfo
->ppshheader
.hwndParent
;
2937 if (parent
) EnableWindow(parent
, FALSE
);
2939 bRet
= PROPSHEET_CreateDialog(psInfo
);
2940 if(!psInfo
->isModeless
)
2941 bRet
= do_loop(psInfo
);
2945 /******************************************************************************
2946 * PropertySheet (COMCTL32.@)
2947 * PropertySheetA (COMCTL32.@)
2949 * Creates a property sheet in the specified property sheet header.
2952 * Modal property sheets: Positive if successful or -1 otherwise.
2953 * Modeless property sheets: Property sheet handle.
2955 *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect.
2956 *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect.
2958 INT_PTR WINAPI
PropertySheetA(LPCPROPSHEETHEADERA lppsh
)
2960 PropSheetInfo
* psInfo
= GlobalAlloc(GPTR
, sizeof(PropSheetInfo
));
2964 TRACE("(%p)\n", lppsh
);
2966 PROPSHEET_CollectSheetInfoA(lppsh
, psInfo
);
2968 psInfo
->proppage
= Alloc(sizeof(PropPageInfo
) * lppsh
->nPages
);
2969 pByte
= (const BYTE
*) psInfo
->ppshheader
.ppsp
;
2971 for (n
= i
= 0; i
< lppsh
->nPages
; i
++, n
++)
2973 if (!psInfo
->usePropPage
)
2975 if (psInfo
->ppshheader
.phpage
[i
] &&
2976 psInfo
->ppshheader
.phpage
[i
]->magic
== HPROPSHEETPAGE_MAGIC
)
2978 psInfo
->proppage
[n
].hpage
= psInfo
->ppshheader
.phpage
[i
];
2982 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageA(
2983 (const PROPSHEETPAGEA
*)psInfo
->ppshheader
.phpage
[i
]);
2988 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageA((LPCPROPSHEETPAGEA
)pByte
);
2989 pByte
+= ((LPCPROPSHEETPAGEA
)pByte
)->dwSize
;
2992 if (!PROPSHEET_CollectPageInfo(psInfo
->proppage
[n
].hpage
, psInfo
, n
, TRUE
))
2994 if (psInfo
->usePropPage
)
2995 DestroyPropertySheetPage(psInfo
->proppage
[n
].hpage
);
3001 return PROPSHEET_PropertySheet(psInfo
, FALSE
);
3004 /******************************************************************************
3005 * PropertySheetW (COMCTL32.@)
3007 * See PropertySheetA.
3009 INT_PTR WINAPI
PropertySheetW(LPCPROPSHEETHEADERW lppsh
)
3011 PropSheetInfo
* psInfo
= GlobalAlloc(GPTR
, sizeof(PropSheetInfo
));
3015 TRACE("(%p)\n", lppsh
);
3017 PROPSHEET_CollectSheetInfoW(lppsh
, psInfo
);
3019 psInfo
->proppage
= Alloc(sizeof(PropPageInfo
) * lppsh
->nPages
);
3020 pByte
= (const BYTE
*) psInfo
->ppshheader
.ppsp
;
3022 for (n
= i
= 0; i
< lppsh
->nPages
; i
++, n
++)
3024 if (!psInfo
->usePropPage
)
3026 if (psInfo
->ppshheader
.phpage
[i
] &&
3027 psInfo
->ppshheader
.phpage
[i
]->magic
== HPROPSHEETPAGE_MAGIC
)
3029 psInfo
->proppage
[n
].hpage
= psInfo
->ppshheader
.phpage
[i
];
3033 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageW(
3034 (const PROPSHEETPAGEW
*)psInfo
->ppshheader
.phpage
[i
]);
3039 psInfo
->proppage
[n
].hpage
= CreatePropertySheetPageW((LPCPROPSHEETPAGEW
)pByte
);
3040 pByte
+= ((LPCPROPSHEETPAGEW
)pByte
)->dwSize
;
3043 if (!PROPSHEET_CollectPageInfo(psInfo
->proppage
[n
].hpage
, psInfo
, n
, TRUE
))
3045 if (psInfo
->usePropPage
)
3046 DestroyPropertySheetPage(psInfo
->proppage
[n
].hpage
);
3052 return PROPSHEET_PropertySheet(psInfo
, TRUE
);
3055 /******************************************************************************
3056 * CreatePropertySheetPage (COMCTL32.@)
3057 * CreatePropertySheetPageA (COMCTL32.@)
3059 * Creates a new property sheet page.
3062 * Success: Handle to new property sheet page.
3066 * An application must use the PSM_ADDPAGE message to add the new page to
3067 * an existing property sheet.
3069 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageA(
3070 LPCPROPSHEETPAGEA lpPropSheetPage
)
3072 PROPSHEETPAGEA
*ppsp
;
3075 if (lpPropSheetPage
->dwSize
< PROPSHEETPAGEA_V1_SIZE
)
3078 ret
= Alloc(FIELD_OFFSET(struct _PSP
, data
[lpPropSheetPage
->dwSize
]));
3079 ret
->magic
= HPROPSHEETPAGE_MAGIC
;
3081 memcpy(ppsp
, lpPropSheetPage
, lpPropSheetPage
->dwSize
);
3083 if ( !(ppsp
->dwFlags
& PSP_DLGINDIRECT
) )
3085 if (!IS_INTRESOURCE( ppsp
->pszTemplate
))
3086 ppsp
->pszTemplate
= heap_strdupA( lpPropSheetPage
->pszTemplate
);
3089 if (ppsp
->dwFlags
& PSP_USEICONID
)
3091 if (!IS_INTRESOURCE( ppsp
->pszIcon
))
3092 ppsp
->pszIcon
= heap_strdupA( lpPropSheetPage
->pszIcon
);
3095 if (ppsp
->dwFlags
& PSP_USETITLE
)
3097 if (!IS_INTRESOURCE( ppsp
->pszTitle
))
3098 ppsp
->pszTitle
= heap_strdupA( lpPropSheetPage
->pszTitle
);
3101 if (ppsp
->dwFlags
& PSP_HIDEHEADER
)
3102 ppsp
->dwFlags
&= ~(PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
);
3104 if (ppsp
->dwFlags
& PSP_USEHEADERTITLE
)
3106 if (!IS_INTRESOURCE( ppsp
->pszHeaderTitle
))
3107 ppsp
->pszHeaderTitle
= heap_strdupA( lpPropSheetPage
->pszHeaderTitle
);
3110 if (ppsp
->dwFlags
& PSP_USEHEADERSUBTITLE
)
3112 if (!IS_INTRESOURCE( ppsp
->pszHeaderSubTitle
))
3113 ppsp
->pszHeaderSubTitle
= heap_strdupA( lpPropSheetPage
->pszHeaderSubTitle
);
3116 HPSP_call_callback(ret
, PSPCB_ADDREF
);
3120 /******************************************************************************
3121 * CreatePropertySheetPageW (COMCTL32.@)
3123 * See CreatePropertySheetA.
3125 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage
)
3127 PROPSHEETPAGEW
*ppsp
;
3130 if (lpPropSheetPage
->dwSize
< PROPSHEETPAGEW_V1_SIZE
)
3133 ret
= Alloc(FIELD_OFFSET(struct _PSP
, data
[lpPropSheetPage
->dwSize
]));
3134 ret
->magic
= HPROPSHEETPAGE_MAGIC
;
3135 ret
->unicode
= TRUE
;
3137 memcpy(ppsp
, lpPropSheetPage
, lpPropSheetPage
->dwSize
);
3139 if ( !(ppsp
->dwFlags
& PSP_DLGINDIRECT
) )
3141 if (!IS_INTRESOURCE( ppsp
->pszTemplate
))
3142 ppsp
->pszTemplate
= heap_strdupW( lpPropSheetPage
->pszTemplate
);
3145 if ( ppsp
->dwFlags
& PSP_USEICONID
)
3147 if (!IS_INTRESOURCE( ppsp
->pszIcon
))
3148 ppsp
->pszIcon
= heap_strdupW( lpPropSheetPage
->pszIcon
);
3151 if (ppsp
->dwFlags
& PSP_USETITLE
)
3153 if (!IS_INTRESOURCE( ppsp
->pszTitle
))
3154 ppsp
->pszTitle
= heap_strdupW( lpPropSheetPage
->pszTitle
);
3157 if (ppsp
->dwFlags
& PSP_HIDEHEADER
)
3158 ppsp
->dwFlags
&= ~(PSP_USEHEADERTITLE
| PSP_USEHEADERSUBTITLE
);
3160 if (ppsp
->dwFlags
& PSP_USEHEADERTITLE
)
3162 if (!IS_INTRESOURCE( ppsp
->pszHeaderTitle
))
3163 ppsp
->pszHeaderTitle
= heap_strdupW( ppsp
->pszHeaderTitle
);
3166 if (ppsp
->dwFlags
& PSP_USEHEADERSUBTITLE
)
3168 if (!IS_INTRESOURCE( ppsp
->pszHeaderSubTitle
))
3169 ppsp
->pszHeaderSubTitle
= heap_strdupW( ppsp
->pszHeaderSubTitle
);
3172 HPSP_call_callback(ret
, PSPCB_ADDREF
);
3176 /******************************************************************************
3177 * DestroyPropertySheetPage (COMCTL32.@)
3179 * Destroys a property sheet page previously created with
3180 * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated
3187 BOOL WINAPI
DestroyPropertySheetPage(HPROPSHEETPAGE hpsp
)
3192 HPSP_call_callback(hpsp
, PSPCB_RELEASE
);
3196 PROPSHEETPAGEW
*psp
= &hpsp
->pspW
;
3198 if (!(psp
->dwFlags
& PSP_DLGINDIRECT
) && !IS_INTRESOURCE(psp
->pszTemplate
))
3199 Free((void *)psp
->pszTemplate
);
3201 if ((psp
->dwFlags
& PSP_USEICONID
) && !IS_INTRESOURCE(psp
->pszIcon
))
3202 Free((void *)psp
->pszIcon
);
3204 if ((psp
->dwFlags
& PSP_USETITLE
) && !IS_INTRESOURCE(psp
->pszTitle
))
3205 Free((void *)psp
->pszTitle
);
3207 if ((psp
->dwFlags
& PSP_USEHEADERTITLE
) && !IS_INTRESOURCE(psp
->pszHeaderTitle
))
3208 Free((void *)psp
->pszHeaderTitle
);
3210 if ((psp
->dwFlags
& PSP_USEHEADERSUBTITLE
) && !IS_INTRESOURCE(psp
->pszHeaderSubTitle
))
3211 Free((void *)psp
->pszHeaderSubTitle
);
3215 PROPSHEETPAGEA
*psp
= &hpsp
->pspA
;
3217 if (!(psp
->dwFlags
& PSP_DLGINDIRECT
) && !IS_INTRESOURCE(psp
->pszTemplate
))
3218 Free((void *)psp
->pszTemplate
);
3220 if ((psp
->dwFlags
& PSP_USEICONID
) && !IS_INTRESOURCE(psp
->pszIcon
))
3221 Free((void *)psp
->pszIcon
);
3223 if ((psp
->dwFlags
& PSP_USETITLE
) && !IS_INTRESOURCE(psp
->pszTitle
))
3224 Free((void *)psp
->pszTitle
);
3226 if ((psp
->dwFlags
& PSP_USEHEADERTITLE
) && !IS_INTRESOURCE(psp
->pszHeaderTitle
))
3227 Free((void *)psp
->pszHeaderTitle
);
3229 if ((psp
->dwFlags
& PSP_USEHEADERSUBTITLE
) && !IS_INTRESOURCE(psp
->pszHeaderSubTitle
))
3230 Free((void *)psp
->pszHeaderSubTitle
);
3237 /******************************************************************************
3238 * PROPSHEET_IsDialogMessage
3240 static BOOL
PROPSHEET_IsDialogMessage(HWND hwnd
, LPMSG lpMsg
)
3242 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3245 if (!psInfo
|| (hwnd
!= lpMsg
->hwnd
&& !IsChild(hwnd
, lpMsg
->hwnd
)))
3248 if (lpMsg
->message
== WM_KEYDOWN
&& (GetKeyState(VK_CONTROL
) & 0x8000))
3251 INT dlgCode
= SendMessageW(lpMsg
->hwnd
, WM_GETDLGCODE
, 0, (LPARAM
)lpMsg
);
3253 if (!(dlgCode
& DLGC_WANTMESSAGE
))
3255 switch (lpMsg
->wParam
)
3258 if (GetKeyState(VK_SHIFT
) & 0x8000)
3264 case VK_NEXT
: new_page
= 1; break;
3265 case VK_PRIOR
: new_page
= -1; break;
3271 if (PROPSHEET_CanSetCurSel(hwnd
) != FALSE
)
3273 new_page
+= psInfo
->active_page
;
3276 new_page
= psInfo
->nPages
- 1;
3277 else if (new_page
>= psInfo
->nPages
)
3280 PROPSHEET_SetCurSel(hwnd
, new_page
, 1, 0);
3287 return IsDialogMessageW(hwnd
, lpMsg
);
3290 /******************************************************************************
3291 * PROPSHEET_DoCommand
3293 static BOOL
PROPSHEET_DoCommand(HWND hwnd
, WORD wID
)
3299 case IDC_APPLY_BUTTON
:
3301 HWND hwndApplyBtn
= GetDlgItem(hwnd
, IDC_APPLY_BUTTON
);
3303 if (PROPSHEET_Apply(hwnd
, wID
== IDOK
? 1: 0) == FALSE
)
3308 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3310 /* don't overwrite ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM */
3311 if (psInfo
->result
== 0)
3312 psInfo
->result
= IDOK
;
3314 if (psInfo
->isModeless
)
3315 psInfo
->activeValid
= FALSE
;
3317 psInfo
->ended
= TRUE
;
3320 EnableWindow(hwndApplyBtn
, FALSE
);
3325 case IDC_BACK_BUTTON
:
3326 PROPSHEET_Back(hwnd
);
3329 case IDC_NEXT_BUTTON
:
3330 PROPSHEET_Next(hwnd
);
3333 case IDC_FINISH_BUTTON
:
3334 PROPSHEET_Finish(hwnd
);
3338 PROPSHEET_Cancel(hwnd
, 0);
3342 PROPSHEET_Help(hwnd
);
3352 /******************************************************************************
3355 static LRESULT
PROPSHEET_Paint(HWND hwnd
, HDC hdcParam
)
3357 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3362 HPALETTE hOldPal
= 0;
3366 HPROPSHEETPAGE hpsp
;
3369 hdc
= hdcParam
? hdcParam
: BeginPaint(hwnd
, &ps
);
3372 hdcSrc
= CreateCompatibleDC(0);
3374 if (psInfo
->ppshheader
.dwFlags
& PSH_USEHPLWATERMARK
)
3375 hOldPal
= SelectPalette(hdc
, psInfo
->ppshheader
.hplWatermark
, FALSE
);
3377 if (psInfo
->active_page
< 0)
3380 hpsp
= psInfo
->proppage
[psInfo
->active_page
].hpage
;
3381 flags
= HPSP_get_flags(hpsp
);
3383 if ( hpsp
&& !(flags
& PSP_HIDEHEADER
) &&
3384 (psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
)) &&
3385 (psInfo
->ppshheader
.dwFlags
& PSH_HEADER
) )
3387 HWND hwndLineHeader
= GetDlgItem(hwnd
, IDC_SUNKEN_LINEHEADER
);
3389 COLORREF clrOld
= 0;
3392 GetClientRect(hwndLineHeader
, &r
);
3393 MapWindowPoints(hwndLineHeader
, hwnd
, (LPPOINT
) &r
, 2);
3394 SetRect(&rzone
, 0, 0, r
.right
+ 1, r
.top
- 1);
3396 hOldFont
= SelectObject(hdc
, psInfo
->hFontBold
);
3398 if (psInfo
->ppshheader
.dwFlags
& PSH_USEHBMHEADER
)
3400 hbmp
= SelectObject(hdcSrc
, psInfo
->ppshheader
.hbmHeader
);
3402 GetObjectW(psInfo
->ppshheader
.hbmHeader
, sizeof(BITMAP
), &bm
);
3403 if (psInfo
->ppshheader
.dwFlags
& PSH_WIZARD97_OLD
)
3405 /* Fill the unoccupied part of the header with color of the
3406 * left-top pixel, but do it only when needed.
3408 if (bm
.bmWidth
< r
.right
|| bm
.bmHeight
< r
.bottom
)
3410 hbr
= CreateSolidBrush(GetPixel(hdcSrc
, 0, 0));
3412 if (bm
.bmWidth
< r
.right
)
3414 r
.left
= bm
.bmWidth
;
3415 FillRect(hdc
, &r
, hbr
);
3417 if (bm
.bmHeight
< r
.bottom
)
3420 r
.top
= bm
.bmHeight
;
3421 FillRect(hdc
, &r
, hbr
);
3426 /* Draw the header itself. */
3427 BitBlt(hdc
, 0, 0, bm
.bmWidth
, min(bm
.bmHeight
, rzone
.bottom
),
3428 hdcSrc
, 0, 0, SRCCOPY
);
3433 hbr
= GetSysColorBrush(COLOR_WINDOW
);
3434 FillRect(hdc
, &rzone
, hbr
);
3436 /* Draw the header bitmap. It's always centered like a
3437 * common 49 x 49 bitmap. */
3438 margin
= (rzone
.bottom
- 49) / 2;
3439 BitBlt(hdc
, rzone
.right
- 49 - margin
, margin
,
3440 min(bm
.bmWidth
, 49), min(bm
.bmHeight
, 49),
3441 hdcSrc
, 0, 0, SRCCOPY
);
3443 /* NOTE: Native COMCTL32 draws a white stripe over the bitmap
3444 * if its height is smaller than 49 pixels. Because the reason
3445 * for this bug is unknown the current code doesn't try to
3449 SelectObject(hdcSrc
, hbmp
);
3452 clrOld
= SetTextColor (hdc
, 0x00000000);
3453 oldBkMode
= SetBkMode (hdc
, TRANSPARENT
);
3455 if (flags
& PSP_USEHEADERTITLE
) {
3456 SetRect(&r
, 20, 10, 0, 0);
3457 HPSP_draw_text(hpsp
, hdc
, TRUE
, &r
, DT_LEFT
| DT_SINGLELINE
| DT_NOCLIP
);
3460 if (flags
& PSP_USEHEADERSUBTITLE
) {
3461 SelectObject(hdc
, psInfo
->hFont
);
3462 SetRect(&r
, 40, 25, rzone
.right
- 69, rzone
.bottom
);
3463 HPSP_draw_text(hpsp
, hdc
, FALSE
, &r
, DT_LEFT
| DT_WORDBREAK
);
3466 offsety
= rzone
.bottom
+ 2;
3468 SetTextColor(hdc
, clrOld
);
3469 SetBkMode(hdc
, oldBkMode
);
3470 SelectObject(hdc
, hOldFont
);
3473 if ( (flags
& PSP_HIDEHEADER
) &&
3474 (psInfo
->ppshheader
.dwFlags
& (PSH_WIZARD97_OLD
| PSH_WIZARD97_NEW
)) &&
3475 (psInfo
->ppshheader
.dwFlags
& PSH_WATERMARK
) )
3477 HWND hwndLine
= GetDlgItem(hwnd
, IDC_SUNKEN_LINE
);
3479 GetClientRect(hwndLine
, &r
);
3480 MapWindowPoints(hwndLine
, hwnd
, (LPPOINT
) &r
, 2);
3481 SetRect(&rzone
, 0, 0, r
.right
, r
.top
- 1);
3483 hbr
= GetSysColorBrush(COLOR_WINDOW
);
3484 FillRect(hdc
, &rzone
, hbr
);
3486 GetObjectW(psInfo
->ppshheader
.hbmWatermark
, sizeof(BITMAP
), &bm
);
3487 hbmp
= SelectObject(hdcSrc
, psInfo
->ppshheader
.hbmWatermark
);
3489 /* The watermark is truncated to a width of 164 pixels */
3490 r
.right
= min(r
.right
, 164);
3491 BitBlt(hdc
, 0, offsety
, min(bm
.bmWidth
, r
.right
),
3492 min(bm
.bmHeight
, r
.bottom
), hdcSrc
, 0, 0, SRCCOPY
);
3494 /* If the bitmap is not big enough, fill the remaining area
3495 with the color of pixel (0,0) of bitmap - see MSDN */
3496 if (r
.top
> bm
.bmHeight
) {
3497 r
.bottom
= r
.top
- 1;
3498 r
.top
= bm
.bmHeight
;
3500 r
.right
= bm
.bmWidth
;
3501 hbr
= CreateSolidBrush(GetPixel(hdcSrc
, 0, 0));
3502 FillRect(hdc
, &r
, hbr
);
3506 SelectObject(hdcSrc
, hbmp
);
3509 if (psInfo
->ppshheader
.dwFlags
& PSH_USEHPLWATERMARK
)
3510 SelectPalette(hdc
, hOldPal
, FALSE
);
3514 if (!hdcParam
) EndPaint(hwnd
, &ps
);
3519 /******************************************************************************
3520 * PROPSHEET_DialogProc
3522 static INT_PTR CALLBACK
3523 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
3525 TRACE("hwnd %p, msg=0x%04x, wparam %Ix, lparam %Ix\n", hwnd
, uMsg
, wParam
, lParam
);
3531 PropSheetInfo
* psInfo
= (PropSheetInfo
*) lParam
;
3532 WCHAR
* strCaption
= Alloc(MAX_CAPTION_LENGTH
*sizeof(WCHAR
));
3533 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
3537 /* Using PropSheetInfoStr to store extra data doesn't match the native
3538 * common control: native uses TCM_[GS]ETITEM
3540 SetPropW(hwnd
, PropSheetInfoStr
, psInfo
);
3543 * psInfo->hwnd is not being used by WINE code - it exists
3544 * for compatibility with "real" Windoze. The same about
3545 * SetWindowLongPtr - WINE is only using the PropSheetInfoStr
3548 psInfo
->hwnd
= hwnd
;
3549 SetWindowLongPtrW(hwnd
, DWLP_USER
, (DWORD_PTR
)psInfo
);
3551 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
3553 /* set up the Next and Back buttons by default */
3554 PROPSHEET_SetWizButtons(hwnd
, PSWIZB_BACK
|PSWIZB_NEXT
);
3558 SystemParametersInfoW (SPI_GETICONTITLELOGFONT
, 0, &logFont
, 0);
3559 psInfo
->hFont
= CreateFontIndirectW (&logFont
);
3560 logFont
.lfWeight
= FW_BOLD
;
3561 psInfo
->hFontBold
= CreateFontIndirectW (&logFont
);
3564 * Small icon in the title bar.
3566 if ((psInfo
->ppshheader
.dwFlags
& PSH_USEICONID
) ||
3567 (psInfo
->ppshheader
.dwFlags
& PSH_USEHICON
))
3570 int icon_cx
= GetSystemMetrics(SM_CXSMICON
);
3571 int icon_cy
= GetSystemMetrics(SM_CYSMICON
);
3573 if (psInfo
->ppshheader
.dwFlags
& PSH_USEICONID
)
3574 hIcon
= LoadImageW(psInfo
->ppshheader
.hInstance
,
3575 psInfo
->ppshheader
.pszIcon
,
3580 hIcon
= psInfo
->ppshheader
.hIcon
;
3582 SendMessageW(hwnd
, WM_SETICON
, 0, (LPARAM
)hIcon
);
3585 if (psInfo
->ppshheader
.dwFlags
& PSH_USEHICON
)
3586 SendMessageW(hwnd
, WM_SETICON
, 0, (LPARAM
)psInfo
->ppshheader
.hIcon
);
3588 psInfo
->strPropertiesFor
= strCaption
;
3590 GetWindowTextW(hwnd
, psInfo
->strPropertiesFor
, MAX_CAPTION_LENGTH
);
3592 PROPSHEET_CreateTabControl(hwnd
, psInfo
);
3594 PROPSHEET_LoadWizardBitmaps(psInfo
);
3596 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
3598 ShowWindow(hwndTabCtrl
, SW_HIDE
);
3599 PROPSHEET_AdjustSizeWizard(hwnd
, psInfo
);
3600 PROPSHEET_AdjustButtonsWizard(hwnd
, psInfo
);
3601 SetFocus(GetDlgItem(hwnd
, IDC_NEXT_BUTTON
));
3605 if (PROPSHEET_SizeMismatch(hwnd
, psInfo
))
3607 PROPSHEET_AdjustSize(hwnd
, psInfo
);
3608 PROPSHEET_AdjustButtons(hwnd
, psInfo
);
3610 SetFocus(GetDlgItem(hwnd
, IDOK
));
3613 if (IS_INTRESOURCE(psInfo
->ppshheader
.pszCaption
) &&
3614 psInfo
->ppshheader
.hInstance
)
3618 if (LoadStringW(psInfo
->ppshheader
.hInstance
,
3619 (UINT_PTR
)psInfo
->ppshheader
.pszCaption
, szText
, 255))
3620 PROPSHEET_SetTitleW(hwnd
, psInfo
->ppshheader
.dwFlags
, szText
);
3624 PROPSHEET_SetTitleW(hwnd
, psInfo
->ppshheader
.dwFlags
,
3625 psInfo
->ppshheader
.pszCaption
);
3629 if (psInfo
->useCallback
)
3630 (*(psInfo
->ppshheader
.pfnCallback
))(hwnd
, PSCB_INITIALIZED
, 0);
3632 idx
= psInfo
->active_page
;
3633 psInfo
->active_page
= -1;
3635 PROPSHEET_SetCurSel(hwnd
, idx
, 1, psInfo
->proppage
[idx
].hpage
);
3637 /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
3638 * as some programs call TCM_GETCURSEL to get the current selection
3639 * from which to switch to the next page */
3640 SendMessageW(hwndTabCtrl
, TCM_SETCURSEL
, psInfo
->active_page
, 0);
3642 PROPSHEET_UnChanged(hwnd
, NULL
);
3644 /* wizards set their focus during init */
3645 if (psInfo
->ppshheader
.dwFlags
& INTRNL_ANY_WIZARD
)
3651 case WM_PRINTCLIENT
:
3653 PROPSHEET_Paint(hwnd
, (HDC
)wParam
);
3657 PROPSHEET_CleanUp(hwnd
);
3661 PROPSHEET_Cancel(hwnd
, 1);
3662 return FALSE
; /* let DefDlgProc post us WM_COMMAND/IDCANCEL */
3665 if (!PROPSHEET_DoCommand(hwnd
, LOWORD(wParam
)))
3667 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3672 /* No default handler, forward notification to active page */
3673 if (psInfo
->activeValid
&& psInfo
->active_page
!= -1)
3675 HWND hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
3676 SendMessageW(hwndPage
, WM_COMMAND
, wParam
, lParam
);
3683 NMHDR
* pnmh
= (LPNMHDR
) lParam
;
3685 if (pnmh
->code
== TCN_SELCHANGE
)
3687 int index
= SendMessageW(pnmh
->hwndFrom
, TCM_GETCURSEL
, 0, 0);
3688 PROPSHEET_SetCurSel(hwnd
, index
, 1, 0);
3691 if(pnmh
->code
== TCN_SELCHANGING
)
3693 BOOL bRet
= PROPSHEET_CanSetCurSel(hwnd
);
3694 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, !bRet
);
3701 case WM_SYSCOLORCHANGE
:
3702 COMCTL32_RefreshSysColors();
3705 case PSM_GETCURRENTPAGEHWND
:
3707 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3713 if (psInfo
->activeValid
&& psInfo
->active_page
!= -1)
3714 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
3716 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, (DWORD_PTR
)hwndPage
);
3722 PROPSHEET_Changed(hwnd
, (HWND
)wParam
);
3726 PROPSHEET_UnChanged(hwnd
, (HWND
)wParam
);
3729 case PSM_GETTABCONTROL
:
3731 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
3733 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, (DWORD_PTR
)hwndTabCtrl
);
3742 msgResult
= PROPSHEET_CanSetCurSel(hwnd
);
3743 if(msgResult
!= FALSE
)
3745 msgResult
= PROPSHEET_SetCurSel(hwnd
,
3748 (HPROPSHEETPAGE
)lParam
);
3751 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3756 case PSM_CANCELTOCLOSE
:
3758 WCHAR buf
[MAX_BUTTONTEXT_LENGTH
];
3759 HWND hwndOK
= GetDlgItem(hwnd
, IDOK
);
3760 HWND hwndCancel
= GetDlgItem(hwnd
, IDCANCEL
);
3762 EnableWindow(hwndCancel
, FALSE
);
3763 if (LoadStringW(COMCTL32_hModule
, IDS_CLOSE
, buf
, ARRAY_SIZE(buf
)))
3764 SetWindowTextW(hwndOK
, buf
);
3769 case PSM_RESTARTWINDOWS
:
3771 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3776 /* reboot system takes precedence over restart windows */
3777 if (psInfo
->result
!= ID_PSREBOOTSYSTEM
)
3778 psInfo
->result
= ID_PSRESTARTWINDOWS
;
3783 case PSM_REBOOTSYSTEM
:
3785 PropSheetInfo
* psInfo
= GetPropW(hwnd
, PropSheetInfoStr
);
3790 psInfo
->result
= ID_PSREBOOTSYSTEM
;
3796 PROPSHEET_SetTitleA(hwnd
, (DWORD
) wParam
, (LPCSTR
) lParam
);
3800 PROPSHEET_SetTitleW(hwnd
, (DWORD
) wParam
, (LPCWSTR
) lParam
);
3805 BOOL msgResult
= PROPSHEET_Apply(hwnd
, 0);
3807 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3812 case PSM_QUERYSIBLINGS
:
3814 LRESULT msgResult
= PROPSHEET_QuerySiblings(hwnd
, wParam
, lParam
);
3816 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3824 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
3825 * a return value. This is not true. PSM_ADDPAGE returns TRUE
3826 * on success or FALSE otherwise, as specified on MSDN Online.
3827 * Also see the MFC code for
3828 * CPropertySheet::AddPage(CPropertyPage* pPage).
3831 BOOL msgResult
= PROPSHEET_AddPage(hwnd
, (HPROPSHEETPAGE
)lParam
);
3833 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3838 case PSM_REMOVEPAGE
:
3839 PROPSHEET_RemovePage(hwnd
, (int)wParam
, (HPROPSHEETPAGE
)lParam
);
3842 case PSM_ISDIALOGMESSAGE
:
3844 BOOL msgResult
= PROPSHEET_IsDialogMessage(hwnd
, (LPMSG
)lParam
);
3845 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3849 case PSM_PRESSBUTTON
:
3850 PROPSHEET_PressButton(hwnd
, (int)wParam
);
3853 case PSM_SETFINISHTEXTA
:
3854 PROPSHEET_SetFinishTextA(hwnd
, (LPCSTR
) lParam
);
3857 case PSM_SETWIZBUTTONS
:
3858 PROPSHEET_SetWizButtons(hwnd
, (DWORD
)lParam
);
3861 case PSM_SETCURSELID
:
3862 PROPSHEET_SetCurSelId(hwnd
, (int)lParam
);
3865 case PSM_SETFINISHTEXTW
:
3866 PROPSHEET_SetFinishTextW(hwnd
, (LPCWSTR
) lParam
);
3869 case PSM_INSERTPAGE
:
3871 BOOL msgResult
= PROPSHEET_InsertPage(hwnd
, (HPROPSHEETPAGE
)wParam
, (HPROPSHEETPAGE
)lParam
);
3872 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3876 case PSM_SETHEADERTITLEW
:
3877 PROPSHEET_SetHeaderTitleW(hwnd
, wParam
, (LPCWSTR
)lParam
);
3880 case PSM_SETHEADERTITLEA
:
3881 PROPSHEET_SetHeaderTitleA(hwnd
, wParam
, (LPCSTR
)lParam
);
3884 case PSM_SETHEADERSUBTITLEW
:
3885 PROPSHEET_SetHeaderSubTitleW(hwnd
, wParam
, (LPCWSTR
)lParam
);
3888 case PSM_SETHEADERSUBTITLEA
:
3889 PROPSHEET_SetHeaderSubTitleA(hwnd
, wParam
, (LPCSTR
)lParam
);
3892 case PSM_HWNDTOINDEX
:
3894 LRESULT msgResult
= PROPSHEET_HwndToIndex(hwnd
, (HWND
)wParam
);
3895 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3899 case PSM_INDEXTOHWND
:
3901 LRESULT msgResult
= PROPSHEET_IndexToHwnd(hwnd
, (int)wParam
);
3902 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3906 case PSM_PAGETOINDEX
:
3908 LRESULT msgResult
= PROPSHEET_PageToIndex(hwnd
, (HPROPSHEETPAGE
)wParam
);
3909 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3913 case PSM_INDEXTOPAGE
:
3915 LRESULT msgResult
= PROPSHEET_IndexToPage(hwnd
, (int)wParam
);
3916 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3922 LRESULT msgResult
= PROPSHEET_IdToIndex(hwnd
, (int)lParam
);
3923 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3929 LRESULT msgResult
= PROPSHEET_IndexToId(hwnd
, (int)wParam
);
3930 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3936 LRESULT msgResult
= PROPSHEET_GetResult(hwnd
);
3937 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);
3941 case PSM_RECALCPAGESIZES
:
3943 LRESULT msgResult
= PROPSHEET_RecalcPageSizes(hwnd
);
3944 SetWindowLongPtrW(hwnd
, DWLP_MSGRESULT
, msgResult
);