4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
10 * - Unicode property sheets
19 #include "debugtools.h"
22 /******************************************************************************
34 typedef struct tagPropPageInfo
36 int index
; /* corresponds to the index in ppshheader->ppsp */
37 HPROPSHEETPAGE hpage
; /* to keep track of pages not passed to PropertySheet */
45 typedef struct tagPropSheetInfo
47 LPSTR strPropertiesFor
;
50 LPCPROPSHEETHEADERA ppshheader
;
57 PropPageInfo
* proppage
;
70 /******************************************************************************
71 * Defines and global variables
74 const char * PropSheetInfoStr
= "PropertySheetInfo";
76 #define MAX_CAPTION_LENGTH 255
77 #define MAX_TABTEXT_LENGTH 255
80 /******************************************************************************
83 static BOOL
PROPSHEET_CreateDialog(PropSheetInfo
* psInfo
);
84 static BOOL
PROPSHEET_IsTooSmall(HWND hwndDlg
, PropSheetInfo
* psInfo
);
85 static BOOL
PROPSHEET_AdjustSize(HWND hwndDlg
, PropSheetInfo
* psInfo
);
86 static BOOL
PROPSHEET_AdjustButtons(HWND hwndParent
, PropSheetInfo
* psInfo
);
87 static BOOL
PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh
,
88 PropSheetInfo
* psInfo
);
89 static BOOL
PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp
,
90 PropSheetInfo
* psInfo
,
92 static BOOL
PROPSHEET_CreateTabControl(HWND hwndParent
,
93 PropSheetInfo
* psInfo
);
94 static int PROPSHEET_CreatePage(HWND hwndParent
, int index
,
95 const PropSheetInfo
* psInfo
,
96 LPCPROPSHEETPAGEA ppshpage
,
98 static BOOL
PROPSHEET_ShowPage(HWND hwndDlg
, int index
, PropSheetInfo
* psInfo
);
99 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
);
100 static BOOL
PROPSHEET_Apply(HWND hwndDlg
);
101 static void PROPSHEET_Cancel(HWND hwndDlg
);
102 static void PROPSHEET_Help(HWND hwndDlg
);
103 static void PROPSHEET_Changed(HWND hwndDlg
, HWND hwndDirtyPage
);
104 static void PROPSHEET_UnChanged(HWND hwndDlg
, HWND hwndCleanPage
);
105 static void PROPSHEET_PressButton(HWND hwndDlg
, int buttonID
);
106 static void PROPSHEET_SetTitleA(HWND hwndDlg
, DWORD dwStyle
, LPCSTR lpszText
);
107 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
109 HPROPSHEETPAGE hpage
);
110 static LRESULT
PROPSHEET_QuerySiblings(HWND hwndDlg
,
111 WPARAM wParam
, LPARAM lParam
);
112 static LPCPROPSHEETPAGEA
PROPSHEET_GetPSPPage(const PropSheetInfo
* psInfo
,
114 static BOOL
PROPSHEET_AddPage(HWND hwndDlg
,
115 HPROPSHEETPAGE hpage
);
117 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
,
119 HPROPSHEETPAGE hpage
);
120 static void PROPSHEET_CleanUp();
121 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage
, PropSheetInfo
* psInfo
);
124 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
126 DEFAULT_DEBUG_CHANNEL(propsheet
)
128 /******************************************************************************
129 * PROPSHEET_CollectSheetInfo
131 * Collect relevant data.
133 static BOOL
PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh
,
134 PropSheetInfo
* psInfo
)
136 DWORD dwFlags
= lppsh
->dwFlags
;
138 psInfo
->hasHelp
= dwFlags
& PSH_HASHELP
;
139 psInfo
->hasApply
= !(dwFlags
& PSH_NOAPPLYNOW
);
140 psInfo
->useCallback
= dwFlags
& PSH_USECALLBACK
;
141 psInfo
->isModeless
= dwFlags
& PSH_MODELESS
;
142 psInfo
->ppshheader
= lppsh
;
143 psInfo
->nPages
= lppsh
->nPages
;
145 if (dwFlags
& PSH_USEPSTARTPAGE
)
147 TRACE("PSH_USEPSTARTPAGE is on");
148 psInfo
->active_page
= 0;
151 psInfo
->active_page
= lppsh
->u2
.nStartPage
;
153 psInfo
->restartWindows
= FALSE
;
154 psInfo
->rebootSystem
= FALSE
;
159 /******************************************************************************
160 * PROPSHEET_CollectPageInfo
162 * Collect property sheet data.
163 * With code taken from DIALOG_ParseTemplate32.
165 BOOL
PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp
,
166 PropSheetInfo
* psInfo
,
169 DLGTEMPLATE
* pTemplate
;
174 if (psInfo
->ppshheader
->dwFlags
& PSH_PROPSHEETPAGE
)
175 psInfo
->proppage
[index
].hpage
= 0;
176 psInfo
->proppage
[index
].hwndPage
= 0;
177 psInfo
->proppage
[index
].isDirty
= FALSE
;
180 * Process property page flags.
182 dwFlags
= lppsp
->dwFlags
;
183 psInfo
->proppage
[index
].useCallback
= dwFlags
& PSP_USECALLBACK
;
184 psInfo
->proppage
[index
].hasHelp
= dwFlags
& PSP_HASHELP
;
186 /* as soon as we have a page with the help flag, set the sheet flag on */
187 if (psInfo
->proppage
[index
].hasHelp
)
188 psInfo
->hasHelp
= TRUE
;
191 * Process page template.
193 if (dwFlags
& PSP_DLGINDIRECT
)
194 pTemplate
= (DLGTEMPLATE
*)lppsp
->u1
.pResource
;
197 HRSRC hResource
= FindResourceA(lppsp
->hInstance
,
198 lppsp
->u1
.pszTemplate
,
200 HGLOBAL hTemplate
= LoadResource(lppsp
->hInstance
,
202 pTemplate
= (LPDLGTEMPLATEA
)LockResource(hTemplate
);
206 * Extract the size of the page and the caption.
208 p
= (const WORD
*)pTemplate
;
210 if (((MyDLGTEMPLATEEX
*)pTemplate
)->signature
== 0xFFFF)
212 /* DIALOGEX template */
216 p
+= 2; /* help ID */
217 p
+= 2; /* ext style */
222 /* DIALOG template */
225 p
+= 2; /* ext style */
231 width
= (WORD
)*p
; p
++;
232 height
= (WORD
)*p
; p
++;
234 /* remember the largest width and height */
235 if (width
> psInfo
->width
)
236 psInfo
->width
= width
;
238 if (height
> psInfo
->height
)
239 psInfo
->height
= height
;
251 p
+= lstrlenW( (LPCWSTR
)p
) + 1;
265 p
+= lstrlenW( (LPCWSTR
)p
) + 1;
269 /* Extract the caption */
270 psInfo
->proppage
[index
].pszText
= (LPCWSTR
)p
;
271 TRACE("Tab %d %s\n",index
,debugstr_w((LPCWSTR
)p
));
272 p
+= lstrlenW((LPCWSTR
)p
) + 1;
277 /******************************************************************************
278 * PROPSHEET_CreateDialog
280 * Creates the actual property sheet.
282 BOOL
PROPSHEET_CreateDialog(PropSheetInfo
* psInfo
)
288 if(!(hRes
= FindResourceA(COMCTL32_hModule
,
289 MAKEINTRESOURCEA(IDD_PROPSHEET
),
293 if(!(template = (LPVOID
)LoadResource(COMCTL32_hModule
, hRes
)))
296 if (psInfo
->useCallback
)
297 (*(psInfo
->ppshheader
->pfnCallback
))(0, PSCB_PRECREATE
, (LPARAM
)template);
299 if (psInfo
->ppshheader
->dwFlags
& PSH_MODELESS
)
300 ret
= CreateDialogIndirectParamA(psInfo
->ppshheader
->hInstance
,
301 (LPDLGTEMPLATEA
) template,
302 psInfo
->ppshheader
->hwndParent
,
303 (DLGPROC
) PROPSHEET_DialogProc
,
306 ret
= DialogBoxIndirectParamA(psInfo
->ppshheader
->hInstance
,
307 (LPDLGTEMPLATEA
) template,
308 psInfo
->ppshheader
->hwndParent
,
309 (DLGPROC
) PROPSHEET_DialogProc
,
315 /******************************************************************************
316 * PROPSHEET_IsTooSmall
318 * Verify that the resource property sheet is big enough.
320 static BOOL
PROPSHEET_IsTooSmall(HWND hwndDlg
, PropSheetInfo
* psInfo
)
322 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
323 RECT rcOrigTab
, rcPage
;
328 GetClientRect(hwndTabCtrl
, &rcOrigTab
);
329 TRACE("orig tab %d %d %d %d\n", rcOrigTab
.left
, rcOrigTab
.top
,
330 rcOrigTab
.right
, rcOrigTab
.bottom
);
335 rcPage
.left
= psInfo
->x
;
336 rcPage
.top
= psInfo
->y
;
337 rcPage
.right
= psInfo
->width
;
338 rcPage
.bottom
= psInfo
->height
;
340 MapDialogRect(hwndDlg
, &rcPage
);
341 TRACE("biggest page %d %d %d %d\n", rcPage
.left
, rcPage
.top
,
342 rcPage
.right
, rcPage
.bottom
);
344 if (rcPage
.right
> rcOrigTab
.right
)
347 if (rcPage
.bottom
> rcOrigTab
.bottom
)
353 /******************************************************************************
354 * PROPSHEET_AdjustSize
356 * Resizes the property sheet and the tab control to fit the largest page.
358 static BOOL
PROPSHEET_AdjustSize(HWND hwndDlg
, PropSheetInfo
* psInfo
)
360 HWND hwndTabCtrl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
361 HWND hwndButton
= GetDlgItem(hwndDlg
, IDOK
);
363 int tabOffsetX
, tabOffsetY
, buttonHeight
;
364 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndDlg
);
366 /* Get the height of buttons */
367 GetClientRect(hwndButton
, &rc
);
368 buttonHeight
= rc
.bottom
;
375 rc
.right
= psInfo
->width
;
376 rc
.bottom
= psInfo
->height
;
378 MapDialogRect(hwndDlg
, &rc
);
381 * Resize the tab control.
383 SendMessageA(hwndTabCtrl
, TCM_ADJUSTRECT
, TRUE
, (LPARAM
)&rc
);
385 tabOffsetX
= -(rc
.left
);
386 tabOffsetY
= -(rc
.top
);
390 SetWindowPos(hwndTabCtrl
, 0, 0, 0, rc
.right
, rc
.bottom
,
391 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
393 GetClientRect(hwndTabCtrl
, &rc
);
395 TRACE("tab client rc %d %d %d %d\n",
396 rc
.left
, rc
.top
, rc
.right
, rc
.bottom
);
398 rc
.right
+= ((padding
.x
* 2) + tabOffsetX
);
399 rc
.bottom
+= (buttonHeight
+ (3 * padding
.y
) + tabOffsetY
);
402 * Resize the property sheet.
404 SetWindowPos(hwndDlg
, 0, 0, 0, rc
.right
, rc
.bottom
,
405 SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
410 /******************************************************************************
411 * PROPSHEET_AdjustButtons
413 * Adjusts the buttons' positions.
415 static BOOL
PROPSHEET_AdjustButtons(HWND hwndParent
, PropSheetInfo
* psInfo
)
417 HWND hwndButton
= GetDlgItem(hwndParent
, IDOK
);
421 int buttonWidth
, buttonHeight
;
422 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndParent
);
424 if (psInfo
->hasApply
)
431 * Obtain the size of the buttons.
433 GetClientRect(hwndButton
, &rcSheet
);
434 buttonWidth
= rcSheet
.right
;
435 buttonHeight
= rcSheet
.bottom
;
438 * Get the size of the property sheet.
440 GetClientRect(hwndParent
, &rcSheet
);
443 * All buttons will be at this y coordinate.
445 y
= rcSheet
.bottom
- (padding
.y
+ buttonHeight
);
448 * Position OK button.
450 hwndButton
= GetDlgItem(hwndParent
, IDOK
);
452 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * num_buttons
);
454 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
455 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
458 * Position Cancel button.
460 hwndButton
= GetDlgItem(hwndParent
, IDCANCEL
);
462 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * (num_buttons
- 1));
464 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
465 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
468 * Position Apply button.
470 hwndButton
= GetDlgItem(hwndParent
, IDC_APPLY_BUTTON
);
472 if (psInfo
->hasApply
)
475 x
= rcSheet
.right
- ((padding
.x
+ buttonWidth
) * 2);
477 x
= rcSheet
.right
- (padding
.x
+ buttonWidth
);
479 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
480 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
482 EnableWindow(hwndButton
, FALSE
);
485 ShowWindow(hwndButton
, SW_HIDE
);
488 * Position Help button.
490 hwndButton
= GetDlgItem(hwndParent
, IDHELP
);
494 x
= rcSheet
.right
- (padding
.x
+ buttonWidth
);
496 SetWindowPos(hwndButton
, 0, x
, y
, 0, 0,
497 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
500 ShowWindow(hwndButton
, SW_HIDE
);
505 /******************************************************************************
506 * PROPSHEET_GetPaddingInfo
508 * Returns the layout information.
510 static PADDING_INFO
PROPSHEET_GetPaddingInfo(HWND hwndDlg
)
512 HWND hwndTab
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
515 PADDING_INFO padding
;
517 GetWindowRect(hwndTab
, &rcTab
);
522 ScreenToClient(hwndDlg
, &tl
);
530 /******************************************************************************
531 * PROPSHEET_CreateTabControl
533 * Insert the tabs in the tab control.
535 static BOOL
PROPSHEET_CreateTabControl(HWND hwndParent
,
536 PropSheetInfo
* psInfo
)
538 HWND hwndTabCtrl
= GetDlgItem(hwndParent
, IDC_TABCONTROL
);
541 char tabtext
[MAX_TABTEXT_LENGTH
] = "Tab text";
543 item
.mask
= TCIF_TEXT
;
544 item
.pszText
= tabtext
;
545 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
547 nTabs
= psInfo
->ppshheader
->nPages
;
549 for (i
= 0; i
< nTabs
; i
++)
551 WideCharToMultiByte(CP_ACP
, 0,
552 (LPCWSTR
)psInfo
->proppage
[i
].pszText
,
553 -1, tabtext
, MAX_TABTEXT_LENGTH
, NULL
, NULL
);
555 SendMessageA(hwndTabCtrl
, TCM_INSERTITEMA
, (WPARAM
)i
, (LPARAM
)&item
);
561 /******************************************************************************
562 * PROPSHEET_CreatePage
566 static int PROPSHEET_CreatePage(HWND hwndParent
,
568 const PropSheetInfo
* psInfo
,
569 LPCPROPSHEETPAGEA ppshpage
,
572 DLGTEMPLATE
* pTemplate
;
575 PropPageInfo
* ppInfo
= psInfo
->proppage
;
576 PADDING_INFO padding
= PROPSHEET_GetPaddingInfo(hwndParent
);
577 HWND hwndTabCtrl
= GetDlgItem(hwndParent
, IDC_TABCONTROL
);
579 TRACE("index %d\n", index
);
581 if (ppshpage
->dwFlags
& PSP_DLGINDIRECT
)
582 pTemplate
= (DLGTEMPLATE
*)ppshpage
->u1
.pResource
;
585 HRSRC hResource
= FindResourceA(ppshpage
->hInstance
,
586 ppshpage
->u1
.pszTemplate
,
588 HGLOBAL hTemplate
= LoadResource(ppshpage
->hInstance
, hResource
);
589 pTemplate
= (LPDLGTEMPLATEA
)LockResource(hTemplate
);
592 if (((MyDLGTEMPLATEEX
*)pTemplate
)->signature
== 0xFFFF)
594 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
|= WS_CHILD
;
595 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~DS_MODALFRAME
;
596 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_CAPTION
;
597 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_SYSMENU
;
598 ((MyDLGTEMPLATEEX
*)pTemplate
)->style
&= ~WS_POPUP
;
602 pTemplate
->style
|= WS_CHILD
;
603 pTemplate
->style
&= ~DS_MODALFRAME
;
604 pTemplate
->style
&= ~WS_CAPTION
;
605 pTemplate
->style
&= ~WS_SYSMENU
;
606 pTemplate
->style
&= ~WS_POPUP
;
609 if (psInfo
->proppage
[index
].useCallback
)
610 (*(ppshpage
->pfnCallback
))(hwndParent
,
612 (LPPROPSHEETPAGEA
)ppshpage
);
614 hwndPage
= CreateDialogIndirectParamA(ppshpage
->hInstance
,
617 ppshpage
->pfnDlgProc
,
620 ppInfo
[index
].hwndPage
= hwndPage
;
624 rc
.right
= psInfo
->width
;
625 rc
.bottom
= psInfo
->height
;
627 MapDialogRect(hwndParent
, &rc
);
630 * Ask the Tab control to fit this page in.
632 SendMessageA(hwndTabCtrl
, TCM_ADJUSTRECT
, FALSE
, (LPARAM
)&rc
);
634 SetWindowPos(hwndPage
, HWND_TOP
,
640 ShowWindow(hwndPage
, SW_SHOW
);
642 ShowWindow(hwndPage
, SW_HIDE
);
647 /******************************************************************************
650 * Displays or creates the specified page.
652 static BOOL
PROPSHEET_ShowPage(HWND hwndDlg
, int index
, PropSheetInfo
* psInfo
)
654 if (index
== psInfo
->active_page
)
657 ShowWindow(psInfo
->proppage
[psInfo
->active_page
].hwndPage
, SW_HIDE
);
659 if (psInfo
->proppage
[index
].hwndPage
!= 0)
660 ShowWindow(psInfo
->proppage
[index
].hwndPage
, SW_SHOW
);
663 LPCPROPSHEETPAGEA ppshpage
= PROPSHEET_GetPSPPage(psInfo
, index
);
664 PROPSHEET_CreatePage(hwndDlg
, index
, psInfo
, ppshpage
, TRUE
);
667 psInfo
->active_page
= index
;
672 /******************************************************************************
675 static BOOL
PROPSHEET_Apply(HWND hwndDlg
)
681 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
684 hdr
.hwndFrom
= hwndDlg
;
687 * Send PSN_KILLACTIVE to the current page.
689 hdr
.code
= PSN_KILLACTIVE
;
691 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
693 if (SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
) != FALSE
)
697 * Send PSN_APPLY to all pages.
699 hdr
.code
= PSN_APPLY
;
701 for (i
= 0; i
< psInfo
->nPages
; i
++)
703 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
704 msgResult
= SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
);
706 if (msgResult
== PSNRET_INVALID_NOCHANGEPAGE
)
713 /******************************************************************************
716 static void PROPSHEET_Cancel(HWND hwndDlg
)
718 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
720 HWND hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
723 hdr
.hwndFrom
= hwndDlg
;
724 hdr
.code
= PSN_QUERYCANCEL
;
726 if (SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
))
729 hdr
.code
= PSN_RESET
;
731 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
);
733 if (psInfo
->isModeless
)
734 psInfo
->active_page
= -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
736 EndDialog(hwndDlg
, FALSE
);
739 /******************************************************************************
742 static void PROPSHEET_Help(HWND hwndDlg
)
744 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
746 HWND hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
749 hdr
.hwndFrom
= hwndDlg
;
752 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
);
755 /******************************************************************************
758 static void PROPSHEET_Changed(HWND hwndDlg
, HWND hwndDirtyPage
)
761 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
765 * Set the dirty flag of this page.
767 for (i
= 0; i
< psInfo
->nPages
; i
++)
769 if (psInfo
->proppage
[i
].hwndPage
== hwndDirtyPage
)
770 psInfo
->proppage
[i
].isDirty
= TRUE
;
774 * Enable the Apply button.
776 if (psInfo
->hasApply
)
778 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
780 EnableWindow(hwndApplyBtn
, TRUE
);
784 /******************************************************************************
785 * PROPSHEET_UnChanged
787 static void PROPSHEET_UnChanged(HWND hwndDlg
, HWND hwndCleanPage
)
790 BOOL noPageDirty
= TRUE
;
791 HWND hwndApplyBtn
= GetDlgItem(hwndDlg
, IDC_APPLY_BUTTON
);
792 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
795 for (i
= 0; i
< psInfo
->nPages
; i
++)
797 /* set the specified page as clean */
798 if (psInfo
->proppage
[i
].hwndPage
== hwndCleanPage
)
799 psInfo
->proppage
[i
].isDirty
= FALSE
;
801 /* look to see if there's any dirty pages */
802 if (psInfo
->proppage
[i
].isDirty
)
807 * Disable Apply button.
810 EnableWindow(hwndApplyBtn
, FALSE
);
813 /******************************************************************************
814 * PROPSHEET_PressButton
816 static void PROPSHEET_PressButton(HWND hwndDlg
, int buttonID
)
821 SendMessageA(hwndDlg
, WM_COMMAND
, IDC_APPLY_BUTTON
, 0);
824 FIXME("Wizard mode not implemented.\n");
827 SendMessageA(hwndDlg
, WM_COMMAND
, IDCANCEL
, 0);
830 FIXME("Wizard mode not implemented.\n");
833 SendMessageA(hwndDlg
, WM_COMMAND
, IDHELP
, 0);
836 FIXME("Wizard mode not implemented.\n");
839 SendMessageA(hwndDlg
, WM_COMMAND
, IDOK
, 0);
842 FIXME("Invalid button index %d\n", buttonID
);
846 /******************************************************************************
847 * PROPSHEET_SetCurSel
849 static BOOL
PROPSHEET_SetCurSel(HWND hwndDlg
,
851 HPROPSHEETPAGE hpage
)
853 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
856 HWND hwndHelp
= GetDlgItem(hwndDlg
, IDHELP
);
860 * Notify the current page.
862 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
864 hdr
.hwndFrom
= hwndDlg
;
865 hdr
.code
= PSN_KILLACTIVE
;
867 if (SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
))
871 FIXME("Implement HPROPSHEETPAGE!\n");
873 hwndPage
= psInfo
->proppage
[index
].hwndPage
;
876 * Notify the new page.
878 hdr
.code
= PSN_SETACTIVE
;
880 SendMessageA(hwndPage
, WM_NOTIFY
, 0, (LPARAM
) &hdr
);
883 * Display the new page.
885 PROPSHEET_ShowPage(hwndDlg
, index
, psInfo
);
887 if (psInfo
->proppage
[index
].hasHelp
)
888 EnableWindow(hwndHelp
, TRUE
);
890 EnableWindow(hwndHelp
, FALSE
);
895 /******************************************************************************
896 * PROPSHEET_SetTitleA
898 static void PROPSHEET_SetTitleA(HWND hwndDlg
, DWORD dwStyle
, LPCSTR lpszText
)
900 if (dwStyle
& PSH_PROPTITLE
)
902 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
905 int lentitle
= strlen(lpszText
);
906 int lenprop
= strlen(psInfo
->strPropertiesFor
);
908 dest
= COMCTL32_Alloc(lentitle
+ lenprop
+ 1);
909 strcpy(dest
, psInfo
->strPropertiesFor
);
910 strcat(dest
, lpszText
);
912 SetWindowTextA(hwndDlg
, dest
);
916 SetWindowTextA(hwndDlg
, lpszText
);
919 /******************************************************************************
920 * PROPSHEET_QuerySiblings
922 static LRESULT
PROPSHEET_QuerySiblings(HWND hwndDlg
,
923 WPARAM wParam
, LPARAM lParam
)
927 LRESULT msgResult
= 0;
928 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
931 while ((i
< psInfo
->nPages
) && (msgResult
== 0))
933 hwndPage
= psInfo
->proppage
[i
].hwndPage
;
934 msgResult
= SendMessageA(hwndPage
, PSM_QUERYSIBLINGS
, wParam
, lParam
);
941 /******************************************************************************
942 * PROPSHEET_GetPSPPage
944 static LPCPROPSHEETPAGEA
PROPSHEET_GetPSPPage(const PropSheetInfo
* psInfo
,
947 BOOL usePSP
= psInfo
->ppshheader
->dwFlags
& PSH_PROPSHEETPAGE
;
948 LPCPROPSHEETPAGEA lppsp
;
949 int realIndex
= psInfo
->proppage
[index
].index
;
955 lppsp
= psInfo
->ppshheader
->u3
.ppsp
;
957 pByte
= (BYTE
*) lppsp
;
959 pByte
+= (lppsp
->dwSize
* realIndex
);
960 lppsp
= (LPCPROPSHEETPAGEA
)pByte
;
963 lppsp
= (LPCPROPSHEETPAGEA
) psInfo
->ppshheader
->u3
.phpage
[realIndex
];
968 /******************************************************************************
971 static BOOL
PROPSHEET_AddPage(HWND hwndDlg
,
972 HPROPSHEETPAGE hpage
)
974 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
976 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
978 char tabtext
[MAX_TABTEXT_LENGTH
] = "Tab text";
979 LPCPROPSHEETPAGEA ppsp
= (LPCPROPSHEETPAGEA
)hpage
;
982 * Allocate and fill in a new PropPageInfo entry.
984 psInfo
->proppage
= (PropPageInfo
*) COMCTL32_ReAlloc(psInfo
->proppage
,
985 sizeof(PropPageInfo
) *
986 (psInfo
->nPages
+ 1));
988 PROPSHEET_CollectPageInfo(ppsp
, psInfo
, psInfo
->nPages
);
989 psInfo
->proppage
[psInfo
->nPages
].index
= -1;
990 psInfo
->proppage
[psInfo
->nPages
].hpage
= hpage
;
993 * Create the page but don't show it.
995 PROPSHEET_CreatePage(hwndDlg
, psInfo
->nPages
, psInfo
, ppsp
, FALSE
);
998 * Add a new tab to the tab control.
1000 item
.mask
= TCIF_TEXT
;
1001 item
.pszText
= tabtext
;
1002 item
.cchTextMax
= MAX_TABTEXT_LENGTH
;
1004 WideCharToMultiByte(CP_ACP
, 0,
1005 (LPCWSTR
)psInfo
->proppage
[psInfo
->nPages
].pszText
,
1006 -1, tabtext
, MAX_TABTEXT_LENGTH
, NULL
, NULL
);
1008 SendMessageA(hwndTabControl
, TCM_INSERTITEMA
, psInfo
->nPages
+ 1,
1016 /******************************************************************************
1017 * PROPSHEET_RemovePage
1019 static BOOL
PROPSHEET_RemovePage(HWND hwndDlg
,
1021 HPROPSHEETPAGE hpage
)
1023 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwndDlg
,
1025 HWND hwndTabControl
= GetDlgItem(hwndDlg
, IDC_TABCONTROL
);
1026 PropPageInfo
* oldPages
= psInfo
->proppage
;
1029 * hpage takes precedence over index.
1033 index
= PROPSHEET_GetPageIndex(hpage
, psInfo
);
1037 TRACE("Could not find page to remove!\n");
1042 TRACE("total pages %d removing page %d active page %d\n",
1043 psInfo
->nPages
, index
, psInfo
->active_page
);
1045 * Check if we're removing the active page.
1047 if (index
== psInfo
->active_page
)
1049 if (psInfo
->nPages
> 1)
1053 /* activate previous page */
1054 PROPSHEET_ShowPage(hwndDlg
, index
- 1, psInfo
);
1058 /* activate the next page */
1059 PROPSHEET_ShowPage(hwndDlg
, index
+ 1, psInfo
);
1064 TRACE("Removing the only page, close the dialog!\n");
1066 if (psInfo
->isModeless
)
1067 psInfo
->active_page
= -1;
1069 EndDialog(hwndDlg
, FALSE
);
1075 if (index
< psInfo
->active_page
)
1076 psInfo
->active_page
--;
1078 /* Remove the tab */
1079 SendMessageA(hwndTabControl
, TCM_DELETEITEM
, index
, 0);
1082 psInfo
->proppage
= COMCTL32_Alloc(sizeof(PropPageInfo
) * psInfo
->nPages
);
1085 memcpy(&psInfo
->proppage
[0], &oldPages
[0], index
* sizeof(PropPageInfo
));
1087 if (index
< psInfo
->nPages
)
1088 memcpy(&psInfo
->proppage
[index
], &oldPages
[index
+ 1],
1089 (psInfo
->nPages
- index
) * sizeof(PropPageInfo
));
1091 COMCTL32_Free(oldPages
);
1096 /******************************************************************************
1097 * PROPSHEET_GetPageIndex
1099 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1100 * the array of PropPageInfo.
1102 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage
, PropSheetInfo
* psInfo
)
1107 while ((index
< psInfo
->nPages
) && (found
== FALSE
))
1109 if (psInfo
->proppage
[index
].hpage
== hpage
)
1121 /******************************************************************************
1124 static void PROPSHEET_CleanUp(HWND hwndDlg
)
1126 PropSheetInfo
* psInfo
= (PropSheetInfo
*) RemovePropA(hwndDlg
,
1128 COMCTL32_Free(psInfo
->proppage
);
1129 COMCTL32_Free(psInfo
->strPropertiesFor
);
1131 GlobalFree((HGLOBAL
)psInfo
);
1134 /******************************************************************************
1135 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1137 INT WINAPI
PropertySheetA(LPCPROPSHEETHEADERA lppsh
)
1140 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GlobalAlloc(GPTR
,
1141 sizeof(PropSheetInfo
));
1142 LPCPROPSHEETPAGEA lppsp
;
1145 PROPSHEET_CollectSheetInfo(lppsh
, psInfo
);
1147 psInfo
->proppage
= (PropPageInfo
*) COMCTL32_Alloc(sizeof(PropPageInfo
) *
1150 for (i
= 0; i
< lppsh
->nPages
; i
++)
1152 psInfo
->proppage
[i
].index
= i
;
1153 if (!(lppsh
->dwFlags
& PSH_PROPSHEETPAGE
))
1154 psInfo
->proppage
[i
].hpage
= psInfo
->ppshheader
->u3
.phpage
[i
];
1155 lppsp
= PROPSHEET_GetPSPPage(psInfo
, i
);
1156 PROPSHEET_CollectPageInfo(lppsp
, psInfo
, i
);
1159 bRet
= PROPSHEET_CreateDialog(psInfo
);
1164 /******************************************************************************
1165 * PropertySheet32W (COMCTL32.85)
1167 INT WINAPI
PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader
)
1169 FIXME("(%p): stub\n", propertySheetHeader
);
1174 /******************************************************************************
1175 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1177 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageA(
1178 LPCPROPSHEETPAGEA lpPropSheetPage
)
1180 PROPSHEETPAGEA
* ppsp
= COMCTL32_Alloc(sizeof(PROPSHEETPAGEA
));
1182 *ppsp
= *lpPropSheetPage
;
1184 return (HPROPSHEETPAGE
)ppsp
;
1187 /******************************************************************************
1188 * CreatePropertySheetPageW (COMCTL32.20)
1190 HPROPSHEETPAGE WINAPI
CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage
)
1192 FIXME("(%p): stub\n", lpPropSheetPage
);
1197 /******************************************************************************
1198 * DestroyPropertySheetPage (COMCTL32.24)
1200 BOOL WINAPI
DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage
)
1202 COMCTL32_Free(hPropPage
);
1207 /******************************************************************************
1208 * PROPSHEET_DialogProc
1211 PROPSHEET_DialogProc(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1217 PropSheetInfo
* psInfo
= (PropSheetInfo
*) lParam
;
1218 char* strCaption
= (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH
);
1219 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
1220 LPCPROPSHEETPAGEA ppshpage
;
1222 psInfo
->strPropertiesFor
= strCaption
;
1224 GetWindowTextA(hwnd
, psInfo
->strPropertiesFor
, MAX_CAPTION_LENGTH
);
1226 PROPSHEET_CreateTabControl(hwnd
, psInfo
);
1228 if (PROPSHEET_IsTooSmall(hwnd
, psInfo
))
1230 PROPSHEET_AdjustSize(hwnd
, psInfo
);
1231 PROPSHEET_AdjustButtons(hwnd
, psInfo
);
1234 ppshpage
= PROPSHEET_GetPSPPage(psInfo
, psInfo
->active_page
);
1235 PROPSHEET_CreatePage(hwnd
, psInfo
->active_page
, psInfo
, ppshpage
, TRUE
);
1236 SendMessageA(hwndTabCtrl
, TCM_SETCURSEL
, psInfo
->active_page
, 0);
1238 SetPropA(hwnd
, PropSheetInfoStr
, (HANDLE
)psInfo
);
1240 PROPSHEET_SetTitleA(hwnd
,
1241 psInfo
->ppshheader
->dwFlags
,
1242 psInfo
->ppshheader
->pszCaption
);
1248 PROPSHEET_CleanUp(hwnd
);
1252 PROPSHEET_Cancel(hwnd
);
1257 WORD wID
= LOWORD(wParam
);
1262 case IDC_APPLY_BUTTON
:
1264 HWND hwndApplyBtn
= GetDlgItem(hwnd
, IDC_APPLY_BUTTON
);
1266 if (PROPSHEET_Apply(hwnd
) == FALSE
)
1269 EnableWindow(hwndApplyBtn
, FALSE
);
1273 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwnd
,
1277 if (psInfo
->restartWindows
)
1278 result
= ID_PSRESTARTWINDOWS
;
1280 /* reboot system takes precedence over restart windows */
1281 if (psInfo
->rebootSystem
)
1282 result
= ID_PSREBOOTSYSTEM
;
1284 if (psInfo
->isModeless
)
1285 psInfo
->active_page
= -1;
1287 EndDialog(hwnd
, result
);
1294 PROPSHEET_Cancel(hwnd
);
1298 PROPSHEET_Help(hwnd
);
1307 NMHDR
* pnmh
= (LPNMHDR
) lParam
;
1309 if (pnmh
->code
== TCN_SELCHANGE
)
1311 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwnd
,
1313 int index
= SendMessageA(pnmh
->hwndFrom
, TCM_GETCURSEL
, 0, 0);
1314 HWND hwndHelp
= GetDlgItem(hwnd
, IDHELP
);
1316 PROPSHEET_ShowPage(hwnd
, index
, psInfo
);
1318 if (psInfo
->proppage
[index
].hasHelp
)
1319 EnableWindow(hwndHelp
, TRUE
);
1321 EnableWindow(hwndHelp
, FALSE
);
1327 case PSM_GETCURRENTPAGEHWND
:
1329 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwnd
,
1333 if (psInfo
->active_page
!= -1)
1334 hwndPage
= psInfo
->proppage
[psInfo
->active_page
].hwndPage
;
1336 SetWindowLongA(hwnd
, DWL_MSGRESULT
, hwndPage
);
1342 PROPSHEET_Changed(hwnd
, (HWND
)wParam
);
1346 PROPSHEET_UnChanged(hwnd
, (HWND
)wParam
);
1349 case PSM_GETTABCONTROL
:
1351 HWND hwndTabCtrl
= GetDlgItem(hwnd
, IDC_TABCONTROL
);
1353 SetWindowLongA(hwnd
, DWL_MSGRESULT
, hwndTabCtrl
);
1362 msgResult
= PROPSHEET_SetCurSel(hwnd
,
1364 (HPROPSHEETPAGE
)lParam
);
1366 SetWindowLongA(hwnd
, DWL_MSGRESULT
, msgResult
);
1371 case PSM_CANCELTOCLOSE
:
1373 HWND hwndOK
= GetDlgItem(hwnd
, IDOK
);
1374 HWND hwndCancel
= GetDlgItem(hwnd
, IDCANCEL
);
1376 EnableWindow(hwndCancel
, FALSE
);
1377 SetWindowTextA(hwndOK
, "Close"); /* FIXME: hardcoded string */
1382 case PSM_RESTARTWINDOWS
:
1384 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwnd
,
1387 psInfo
->restartWindows
= TRUE
;
1391 case PSM_REBOOTSYSTEM
:
1393 PropSheetInfo
* psInfo
= (PropSheetInfo
*) GetPropA(hwnd
,
1396 psInfo
->rebootSystem
= TRUE
;
1401 PROPSHEET_SetTitleA(hwnd
, (DWORD
) wParam
, (LPCSTR
) lParam
);
1406 BOOL msgResult
= PROPSHEET_Apply(hwnd
);
1408 SetWindowLongA(hwnd
, DWL_MSGRESULT
, msgResult
);
1413 case PSM_QUERYSIBLINGS
:
1415 LRESULT msgResult
= PROPSHEET_QuerySiblings(hwnd
, wParam
, lParam
);
1417 SetWindowLongA(hwnd
, DWL_MSGRESULT
, msgResult
);
1423 PROPSHEET_AddPage(hwnd
, (HPROPSHEETPAGE
)lParam
);
1426 case PSM_REMOVEPAGE
:
1427 PROPSHEET_RemovePage(hwnd
, (int)wParam
, (HPROPSHEETPAGE
)lParam
);
1430 case PSM_ISDIALOGMESSAGE
:
1432 FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1436 case PSM_PRESSBUTTON
:
1437 PROPSHEET_PressButton(hwnd
, (int)wParam
);
1441 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
1443 case PSM_SETWIZBUTTONS
:
1444 FIXME("Unimplemented msg PSM_SETWIZBUTTONS\n");
1446 case PSM_SETCURSELID
:
1447 FIXME("Unimplemented msg PSM_SETCURSELID\n");
1449 case PSM_SETFINISHTEXTA
:
1450 FIXME("Unimplemented msg PSM_SETFINISHTEXT32A\n");
1452 case PSM_SETFINISHTEXTW
:
1453 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");