Documentation ordinal fixes.
[wine/wine64.git] / dlls / comctl32 / propsheet.c
blobc4b1905d163132483851b69e63ed931cae4e1c95
1 /*
2 * Property Sheets
4 * Copyright 1998 Francis Beaudet
5 * Copyright 1999 Thuy Nguyen
7 * TODO:
8 * - Tab order
9 * - Unicode property sheets
12 #include <string.h>
13 #include "winbase.h"
14 #include "commctrl.h"
15 #include "prsht.h"
16 #include "winnls.h"
17 #include "comctl32.h"
18 #include "debugtools.h"
19 #include "heap.h"
22 /******************************************************************************
23 * Data structures
25 typedef struct
27 WORD dlgVer;
28 WORD signature;
29 DWORD helpID;
30 DWORD exStyle;
31 DWORD style;
32 } MyDLGTEMPLATEEX;
34 typedef struct tagPropPageInfo
36 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
37 HWND hwndPage;
38 BOOL isDirty;
39 LPCWSTR pszText;
40 BOOL hasHelp;
41 BOOL useCallback;
42 BOOL hasIcon;
43 } PropPageInfo;
45 typedef struct tagPropSheetInfo
47 HWND hwnd;
48 PROPSHEETHEADERA ppshheader;
49 LPSTR strPropertiesFor;
50 int nPages;
51 int active_page;
52 BOOL isModeless;
53 BOOL hasHelp;
54 BOOL hasApply;
55 BOOL useCallback;
56 BOOL restartWindows;
57 BOOL rebootSystem;
58 BOOL activeValid;
59 PropPageInfo* proppage;
60 int x;
61 int y;
62 int width;
63 int height;
64 HIMAGELIST hImageList;
65 } PropSheetInfo;
67 typedef struct
69 int x;
70 int y;
71 } PADDING_INFO;
73 /******************************************************************************
74 * Defines and global variables
77 const char * PropSheetInfoStr = "PropertySheetInfo";
79 #define MAX_CAPTION_LENGTH 255
80 #define MAX_TABTEXT_LENGTH 255
81 #define MAX_BUTTONTEXT_LENGTH 64
83 /******************************************************************************
84 * Prototypes
86 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
87 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
88 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
89 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
90 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
91 PropSheetInfo * psInfo);
92 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
93 PropSheetInfo * psInfo,
94 int index);
95 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
96 PropSheetInfo * psInfo);
97 static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index,
98 const PropSheetInfo * psInfo,
99 LPCPROPSHEETPAGEA ppshpage);
100 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
101 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
102 static BOOL PROPSHEET_Back(HWND hwndDlg);
103 static BOOL PROPSHEET_Next(HWND hwndDlg);
104 static BOOL PROPSHEET_Finish(HWND hwndDlg);
105 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
106 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
107 static void PROPSHEET_Help(HWND hwndDlg);
108 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
109 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
110 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
111 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
112 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
113 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
114 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
115 int index,
116 int skipdir,
117 HPROPSHEETPAGE hpage);
118 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
119 WPARAM wParam, LPARAM lParam);
120 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
121 HPROPSHEETPAGE hpage);
123 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
124 int index,
125 HPROPSHEETPAGE hpage);
126 static void PROPSHEET_CleanUp();
127 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
128 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
129 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
130 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
132 BOOL WINAPI
133 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
135 DEFAULT_DEBUG_CHANNEL(propsheet);
137 /******************************************************************************
138 * PROPSHEET_CollectSheetInfo
140 * Collect relevant data.
142 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
143 PropSheetInfo * psInfo)
145 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
146 DWORD dwFlags = lppsh->dwFlags;
148 psInfo->hasHelp = dwFlags & PSH_HASHELP;
149 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
150 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
151 psInfo->isModeless = dwFlags & PSH_MODELESS;
153 memcpy(&psInfo->ppshheader,lppsh,dwSize);
155 if (HIWORD(lppsh->pszCaption))
156 psInfo->ppshheader.pszCaption = HEAP_strdupA( GetProcessHeap(),
157 0, lppsh->pszCaption );
159 psInfo->nPages = lppsh->nPages;
161 if (dwFlags & PSH_USEPSTARTPAGE)
163 TRACE("PSH_USEPSTARTPAGE is on");
164 psInfo->active_page = 0;
166 else
167 psInfo->active_page = lppsh->u2.nStartPage;
169 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
170 psInfo->active_page = 0;
172 psInfo->restartWindows = FALSE;
173 psInfo->rebootSystem = FALSE;
174 psInfo->hImageList = 0;
175 psInfo->activeValid = FALSE;
177 return TRUE;
180 /******************************************************************************
181 * PROPSHEET_CollectPageInfo
183 * Collect property sheet data.
184 * With code taken from DIALOG_ParseTemplate32.
186 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
187 PropSheetInfo * psInfo,
188 int index)
190 DLGTEMPLATE* pTemplate;
191 const WORD* p;
192 DWORD dwFlags;
193 int width, height;
195 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
196 psInfo->proppage[index].hwndPage = 0;
197 psInfo->proppage[index].isDirty = FALSE;
200 * Process property page flags.
202 dwFlags = lppsp->dwFlags;
203 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
204 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
205 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
207 /* as soon as we have a page with the help flag, set the sheet flag on */
208 if (psInfo->proppage[index].hasHelp)
209 psInfo->hasHelp = TRUE;
212 * Process page template.
214 if (dwFlags & PSP_DLGINDIRECT)
215 pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
216 else
218 HRSRC hResource = FindResourceA(lppsp->hInstance,
219 lppsp->u.pszTemplate,
220 RT_DIALOGA);
221 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
222 hResource);
223 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
227 * Extract the size of the page and the caption.
229 if (!pTemplate)
230 return FALSE;
232 p = (const WORD *)pTemplate;
234 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
236 /* DIALOGEX template */
238 p++; /* dlgVer */
239 p++; /* signature */
240 p += 2; /* help ID */
241 p += 2; /* ext style */
242 p += 2; /* style */
244 else
246 /* DIALOG template */
248 p += 2; /* style */
249 p += 2; /* ext style */
252 p++; /* nb items */
253 p++; /* x */
254 p++; /* y */
255 width = (WORD)*p; p++;
256 height = (WORD)*p; p++;
258 /* remember the largest width and height */
259 if (width > psInfo->width)
260 psInfo->width = width;
262 if (height > psInfo->height)
263 psInfo->height = height;
265 /* menu */
266 switch ((WORD)*p)
268 case 0x0000:
269 p++;
270 break;
271 case 0xffff:
272 p += 2;
273 break;
274 default:
275 p += lstrlenW( (LPCWSTR)p ) + 1;
276 break;
279 /* class */
280 switch ((WORD)*p)
282 case 0x0000:
283 p++;
284 break;
285 case 0xffff:
286 p += 2;
287 break;
288 default:
289 p += lstrlenW( (LPCWSTR)p ) + 1;
290 break;
293 /* Extract the caption */
294 psInfo->proppage[index].pszText = (LPCWSTR)p;
295 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
296 p += lstrlenW((LPCWSTR)p) + 1;
298 if (dwFlags & PSP_USETITLE)
300 if ( !HIWORD( lppsp->pszTitle ) )
302 char szTitle[256];
304 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
305 return FALSE;
307 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
308 0, szTitle );
310 else
311 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
313 lppsp->pszTitle);
317 * Build the image list for icons
319 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
321 HICON hIcon;
322 int icon_cx = GetSystemMetrics(SM_CXSMICON);
323 int icon_cy = GetSystemMetrics(SM_CYSMICON);
325 if (dwFlags & PSP_USEICONID)
326 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
327 icon_cx, icon_cy, LR_DEFAULTCOLOR);
328 else
329 hIcon = lppsp->u2.hIcon;
331 if ( hIcon )
333 if (psInfo->hImageList == 0 )
334 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
336 ImageList_AddIcon(psInfo->hImageList, hIcon);
341 return TRUE;
345 /******************************************************************************
346 * PROPSHEET_CreateDialog
348 * Creates the actual property sheet.
350 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
352 LRESULT ret;
353 LPCVOID template;
354 LPVOID temp = 0;
355 HRSRC hRes;
356 DWORD resSize;
357 WORD resID = IDD_PROPSHEET;
359 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
360 resID = IDD_WIZARD;
362 if(!(hRes = FindResourceA(COMCTL32_hModule,
363 MAKEINTRESOURCEA(resID),
364 RT_DIALOGA)))
365 return FALSE;
367 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
368 return FALSE;
371 * Make a copy of the dialog template.
373 resSize = SizeofResource(COMCTL32_hModule, hRes);
375 temp = COMCTL32_Alloc(resSize);
377 if (!temp)
378 return FALSE;
380 memcpy(temp, template, resSize);
382 if (psInfo->useCallback)
383 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
385 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
386 ret = DialogBoxIndirectParamA(psInfo->ppshheader.hInstance,
387 (LPDLGTEMPLATEA) temp,
388 psInfo->ppshheader.hwndParent,
389 (DLGPROC) PROPSHEET_DialogProc,
390 (LPARAM)psInfo);
391 else
392 ret = CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
393 (LPDLGTEMPLATEA) temp,
394 psInfo->ppshheader.hwndParent,
395 (DLGPROC) PROPSHEET_DialogProc,
396 (LPARAM)psInfo);
398 COMCTL32_Free(temp);
400 return ret;
403 /******************************************************************************
404 * PROPSHEET_SizeMismatch
406 * Verify that the tab control and the "largest" property sheet page dlg. template
407 * match in size.
409 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
411 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
412 RECT rcOrigTab, rcPage;
415 * Original tab size.
417 GetClientRect(hwndTabCtrl, &rcOrigTab);
418 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
419 rcOrigTab.right, rcOrigTab.bottom);
422 * Biggest page size.
424 rcPage.left = psInfo->x;
425 rcPage.top = psInfo->y;
426 rcPage.right = psInfo->width;
427 rcPage.bottom = psInfo->height;
429 MapDialogRect(hwndDlg, &rcPage);
430 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
431 rcPage.right, rcPage.bottom);
433 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
434 return TRUE;
435 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
436 return TRUE;
438 return FALSE;
441 /******************************************************************************
442 * PROPSHEET_IsTooSmallWizard
444 * Verify that the default property sheet is big enough.
446 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
448 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
449 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
450 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
452 GetClientRect(hwndDlg, &rcSheetClient);
453 GetWindowRect(hwndDlg, &rcSheetRect);
454 GetWindowRect(hwndLine, &rcLine);
456 /* Remove the space below the sunken line */
457 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
459 /* Remove the buffer zone all around the edge */
460 rcSheetClient.bottom -= (padding.y * 2);
461 rcSheetClient.right -= (padding.x * 2);
464 * Biggest page size.
466 rcPage.left = psInfo->x;
467 rcPage.top = psInfo->y;
468 rcPage.right = psInfo->width;
469 rcPage.bottom = psInfo->height;
471 MapDialogRect(hwndDlg, &rcPage);
472 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
473 rcPage.right, rcPage.bottom);
475 if (rcPage.right > rcSheetClient.right)
476 return TRUE;
478 if (rcPage.bottom > rcSheetClient.bottom)
479 return TRUE;
481 return FALSE;
484 /******************************************************************************
485 * PROPSHEET_AdjustSize
487 * Resizes the property sheet and the tab control to fit the largest page.
489 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
491 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
492 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
493 RECT rc,tabRect;
494 int tabOffsetX, tabOffsetY, buttonHeight;
495 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
496 RECT units;
498 /* Get the height of buttons */
499 GetClientRect(hwndButton, &rc);
500 buttonHeight = rc.bottom;
503 * Biggest page size.
505 rc.left = psInfo->x;
506 rc.top = psInfo->y;
507 rc.right = psInfo->width;
508 rc.bottom = psInfo->height;
510 MapDialogRect(hwndDlg, &rc);
512 /* retrieve the dialog units */
513 units.left = units.right = 4;
514 units.top = units.bottom = 8;
515 MapDialogRect(hwndDlg, &units);
518 * Resize the tab control.
520 GetClientRect(hwndTabCtrl,&tabRect);
522 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
524 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
526 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
527 psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
530 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
532 rc.right = rc.left + tabRect.right - tabRect.left;
533 psInfo->width = MulDiv((rc.right - rc.left),4,units.left);
536 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
538 tabOffsetX = -(rc.left);
539 tabOffsetY = -(rc.top);
541 rc.right -= rc.left;
542 rc.bottom -= rc.top;
543 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
544 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
546 GetClientRect(hwndTabCtrl, &rc);
548 TRACE("tab client rc %d %d %d %d\n",
549 rc.left, rc.top, rc.right, rc.bottom);
551 rc.right += ((padding.x * 2) + tabOffsetX);
552 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
555 * Resize the property sheet.
557 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
558 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
559 return TRUE;
562 /******************************************************************************
563 * PROPSHEET_AdjustSizeWizard
565 * Resizes the property sheet to fit the largest page.
567 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
569 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
570 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
571 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
572 RECT rc,tabRect;
573 int buttonHeight, lineHeight;
574 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
575 RECT units;
577 /* Get the height of buttons */
578 GetClientRect(hwndButton, &rc);
579 buttonHeight = rc.bottom;
581 GetClientRect(hwndLine, &rc);
582 lineHeight = rc.bottom;
584 /* retrieve the dialog units */
585 units.left = units.right = 4;
586 units.top = units.bottom = 8;
587 MapDialogRect(hwndDlg, &units);
590 * Biggest page size.
592 rc.left = psInfo->x;
593 rc.top = psInfo->y;
594 rc.right = psInfo->width;
595 rc.bottom = psInfo->height;
597 MapDialogRect(hwndDlg, &rc);
599 GetClientRect(hwndTabCtrl,&tabRect);
601 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
603 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
604 psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);
607 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
609 rc.right = rc.left + tabRect.right - tabRect.left;
610 psInfo->width = MulDiv((rc.right - rc.left), 4, units.left);
613 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
615 /* Make room */
616 rc.right += (padding.x * 2);
617 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
620 * Resize the property sheet.
622 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
623 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
624 return TRUE;
627 /******************************************************************************
628 * PROPSHEET_AdjustButtons
630 * Adjusts the buttons' positions.
632 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
634 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
635 RECT rcSheet;
636 int x, y;
637 int num_buttons = 2;
638 int buttonWidth, buttonHeight;
639 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
641 if (psInfo->hasApply)
642 num_buttons++;
644 if (psInfo->hasHelp)
645 num_buttons++;
648 * Obtain the size of the buttons.
650 GetClientRect(hwndButton, &rcSheet);
651 buttonWidth = rcSheet.right;
652 buttonHeight = rcSheet.bottom;
655 * Get the size of the property sheet.
657 GetClientRect(hwndParent, &rcSheet);
660 * All buttons will be at this y coordinate.
662 y = rcSheet.bottom - (padding.y + buttonHeight);
665 * Position OK button.
667 hwndButton = GetDlgItem(hwndParent, IDOK);
669 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
671 SetWindowPos(hwndButton, 0, x, y, 0, 0,
672 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
675 * Position Cancel button.
677 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
679 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
681 SetWindowPos(hwndButton, 0, x, y, 0, 0,
682 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
685 * Position Apply button.
687 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
689 if (psInfo->hasApply)
691 if (psInfo->hasHelp)
692 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
693 else
694 x = rcSheet.right - (padding.x + buttonWidth);
696 SetWindowPos(hwndButton, 0, x, y, 0, 0,
697 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
699 EnableWindow(hwndButton, FALSE);
701 else
702 ShowWindow(hwndButton, SW_HIDE);
705 * Position Help button.
707 hwndButton = GetDlgItem(hwndParent, IDHELP);
709 if (psInfo->hasHelp)
711 x = rcSheet.right - (padding.x + buttonWidth);
713 SetWindowPos(hwndButton, 0, x, y, 0, 0,
714 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
716 else
717 ShowWindow(hwndButton, SW_HIDE);
719 return TRUE;
722 /******************************************************************************
723 * PROPSHEET_AdjustButtonsWizard
725 * Adjusts the buttons' positions.
727 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
728 PropSheetInfo* psInfo)
730 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
731 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
732 RECT rcSheet;
733 int x, y;
734 int num_buttons = 3;
735 int buttonWidth, buttonHeight, lineHeight, lineWidth;
736 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
738 if (psInfo->hasHelp)
739 num_buttons++;
742 * Obtain the size of the buttons.
744 GetClientRect(hwndButton, &rcSheet);
745 buttonWidth = rcSheet.right;
746 buttonHeight = rcSheet.bottom;
748 GetClientRect(hwndLine, &rcSheet);
749 lineHeight = rcSheet.bottom;
752 * Get the size of the property sheet.
754 GetClientRect(hwndParent, &rcSheet);
757 * All buttons will be at this y coordinate.
759 y = rcSheet.bottom - (padding.y + buttonHeight);
762 * Position the Next and the Finish buttons.
764 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
766 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
768 SetWindowPos(hwndButton, 0, x, y, 0, 0,
769 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
771 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
773 SetWindowPos(hwndButton, 0, x, y, 0, 0,
774 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
776 ShowWindow(hwndButton, SW_HIDE);
779 * Position the Back button.
781 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
783 x -= buttonWidth;
785 SetWindowPos(hwndButton, 0, x, y, 0, 0,
786 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
789 * Position the Cancel button.
791 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
793 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
795 SetWindowPos(hwndButton, 0, x, y, 0, 0,
796 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
799 * Position Help button.
801 hwndButton = GetDlgItem(hwndParent, IDHELP);
803 if (psInfo->hasHelp)
805 x = rcSheet.right - (padding.x + buttonWidth);
807 SetWindowPos(hwndButton, 0, x, y, 0, 0,
808 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
810 else
811 ShowWindow(hwndButton, SW_HIDE);
814 * Position and resize the sunken line.
816 x = padding.x;
817 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
819 GetClientRect(hwndParent, &rcSheet);
820 lineWidth = rcSheet.right - (padding.x * 2);
822 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
823 SWP_NOZORDER | SWP_NOACTIVATE);
825 return TRUE;
828 /******************************************************************************
829 * PROPSHEET_GetPaddingInfo
831 * Returns the layout information.
833 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
835 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
836 RECT rcTab;
837 POINT tl;
838 PADDING_INFO padding;
840 GetWindowRect(hwndTab, &rcTab);
842 tl.x = rcTab.left;
843 tl.y = rcTab.top;
845 ScreenToClient(hwndDlg, &tl);
847 padding.x = tl.x;
848 padding.y = tl.y;
850 return padding;
853 /******************************************************************************
854 * PROPSHEET_GetPaddingInfoWizard
856 * Returns the layout information.
857 * Vertical spacing is the distance between the line and the buttons.
858 * Do NOT use the Help button to gather padding information when it isn't mapped
859 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
860 * for it in this case !
861 * FIXME: I'm not sure about any other coordinate problems with these evil
862 * buttons. Fix it in case additional problems appear or maybe calculate
863 * a padding in a completely different way, as this is somewhat messy.
865 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
866 psInfo)
868 PADDING_INFO padding;
869 RECT rc;
870 HWND hwndControl;
871 INT idButton;
872 POINT ptButton, ptLine;
874 if (psInfo->hasHelp)
876 idButton = IDHELP;
878 else
880 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
882 idButton = IDC_NEXT_BUTTON;
884 else
886 /* hopefully this is ok */
887 idButton = IDCANCEL;
891 hwndControl = GetDlgItem(hwndDlg, idButton);
892 GetWindowRect(hwndControl, &rc);
894 ptButton.x = rc.left;
895 ptButton.y = rc.top;
897 ScreenToClient(hwndDlg, &ptButton);
899 /* Line */
900 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
901 GetWindowRect(hwndControl, &rc);
903 ptLine.x = 0;
904 ptLine.y = rc.bottom;
906 ScreenToClient(hwndDlg, &ptLine);
908 padding.y = ptButton.y - ptLine.y;
910 if (padding.y < 0)
911 ERR("padding negative ! Please report this !\n");
913 /* this is most probably not correct, but the best we have now */
914 padding.x = padding.y;
915 return padding;
918 /******************************************************************************
919 * PROPSHEET_CreateTabControl
921 * Insert the tabs in the tab control.
923 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
924 PropSheetInfo * psInfo)
926 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
927 TCITEMA item;
928 int i, nTabs;
929 int iImage = 0;
930 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
932 item.mask = TCIF_TEXT;
933 item.pszText = tabtext;
934 item.cchTextMax = MAX_TABTEXT_LENGTH;
936 nTabs = psInfo->nPages;
939 * Set the image list for icons.
941 if (psInfo->hImageList)
943 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
946 for (i = 0; i < nTabs; i++)
948 if ( psInfo->proppage[i].hasIcon )
950 item.mask |= TCIF_IMAGE;
951 item.iImage = iImage++;
953 else
955 item.mask &= ~TCIF_IMAGE;
958 WideCharToMultiByte(CP_ACP, 0,
959 (LPCWSTR)psInfo->proppage[i].pszText,
960 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
962 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
965 return TRUE;
968 /******************************************************************************
969 * PROPSHEET_CreatePage
971 * Creates a page.
973 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
974 int index,
975 const PropSheetInfo * psInfo,
976 LPCPROPSHEETPAGEA ppshpage)
978 DLGTEMPLATE* pTemplate;
979 HWND hwndPage;
980 RECT rc;
981 PropPageInfo* ppInfo = psInfo->proppage;
982 PADDING_INFO padding;
983 UINT pageWidth,pageHeight;
984 DWORD resSize;
985 LPVOID temp = NULL;
987 TRACE("index %d\n", index);
989 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
990 pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
991 else
993 HRSRC hResource;
994 HANDLE hTemplate;
996 hResource = FindResourceA(ppshpage->hInstance,
997 ppshpage->u.pszTemplate,
998 RT_DIALOGA);
999 if(!hResource)
1000 return FALSE;
1002 resSize = SizeofResource(ppshpage->hInstance, hResource);
1004 hTemplate = LoadResource(ppshpage->hInstance, hResource);
1005 if(!hTemplate)
1006 return FALSE;
1008 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1010 * Make a copy of the dialog template to make it writable
1012 temp = COMCTL32_Alloc(resSize);
1013 if (!temp)
1014 return FALSE;
1016 memcpy(temp, pTemplate, resSize);
1017 pTemplate = temp;
1020 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1022 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1023 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1024 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1025 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1026 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1027 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1028 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1030 else
1032 pTemplate->style |= WS_CHILD | DS_CONTROL;
1033 pTemplate->style &= ~DS_MODALFRAME;
1034 pTemplate->style &= ~WS_CAPTION;
1035 pTemplate->style &= ~WS_SYSMENU;
1036 pTemplate->style &= ~WS_POPUP;
1037 pTemplate->style &= ~WS_DISABLED;
1038 pTemplate->style &= ~WS_VISIBLE;
1041 if (psInfo->proppage[index].useCallback)
1042 (*(ppshpage->pfnCallback))(hwndParent,
1043 PSPCB_CREATE,
1044 (LPPROPSHEETPAGEA)ppshpage);
1046 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1047 pTemplate,
1048 hwndParent,
1049 ppshpage->pfnDlgProc,
1050 (LPARAM)ppshpage);
1051 /* Free a no more needed copy */
1052 if(temp)
1053 COMCTL32_Free(temp);
1055 ppInfo[index].hwndPage = hwndPage;
1057 rc.left = psInfo->x;
1058 rc.top = psInfo->y;
1059 rc.right = psInfo->width;
1060 rc.bottom = psInfo->height;
1062 MapDialogRect(hwndParent, &rc);
1064 pageWidth = rc.right - rc.left;
1065 pageHeight = rc.bottom - rc.top;
1067 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1068 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1069 else
1072 * Ask the Tab control to fit this page in.
1075 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1076 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1077 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1080 SetWindowPos(hwndPage, HWND_TOP,
1081 rc.left + padding.x,
1082 rc.top + padding.y,
1083 pageWidth, pageHeight, 0);
1085 return TRUE;
1088 /******************************************************************************
1089 * PROPSHEET_ShowPage
1091 * Displays or creates the specified page.
1093 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1095 if (index == psInfo->active_page)
1097 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1098 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1099 return TRUE;
1102 if (psInfo->proppage[index].hwndPage == 0)
1104 LPCPROPSHEETPAGEA ppshpage;
1106 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1107 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1110 if (psInfo->active_page != -1)
1111 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1113 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1115 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1117 HWND hwndTabCtrl;
1119 /* Synchronize current selection with tab control */
1120 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1121 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1124 psInfo->active_page = index;
1125 psInfo->activeValid = TRUE;
1127 return TRUE;
1130 /******************************************************************************
1131 * PROPSHEET_Back
1133 static BOOL PROPSHEET_Back(HWND hwndDlg)
1135 BOOL res;
1136 PSHNOTIFY psn;
1137 HWND hwndPage;
1138 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1139 PropSheetInfoStr);
1140 LRESULT result;
1142 if (psInfo->active_page < 0)
1143 return FALSE;
1145 psn.hdr.code = PSN_WIZBACK;
1146 psn.hdr.hwndFrom = hwndDlg;
1147 psn.hdr.idFrom = 0;
1148 psn.lParam = 0;
1150 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1152 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1153 if (result == -1)
1154 return FALSE;
1156 if (psInfo->active_page > 0)
1158 res = PROPSHEET_CanSetCurSel(hwndDlg);
1159 if(res != FALSE)
1161 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, -1, 0);
1165 return TRUE;
1168 /******************************************************************************
1169 * PROPSHEET_Next
1171 static BOOL PROPSHEET_Next(HWND hwndDlg)
1173 PSHNOTIFY psn;
1174 HWND hwndPage;
1175 LRESULT msgResult = 0;
1176 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1177 PropSheetInfoStr);
1179 if (psInfo->active_page < 0)
1180 return FALSE;
1182 psn.hdr.code = PSN_WIZNEXT;
1183 psn.hdr.hwndFrom = hwndDlg;
1184 psn.hdr.idFrom = 0;
1185 psn.lParam = 0;
1187 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1189 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1190 if (msgResult == -1)
1191 return FALSE;
1193 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1195 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 1, 0);
1198 return TRUE;
1201 /******************************************************************************
1202 * PROPSHEET_Finish
1204 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1206 PSHNOTIFY psn;
1207 HWND hwndPage;
1208 LRESULT msgResult = 0;
1209 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1210 PropSheetInfoStr);
1212 if (psInfo->active_page < 0)
1213 return FALSE;
1215 psn.hdr.code = PSN_WIZFINISH;
1216 psn.hdr.hwndFrom = hwndDlg;
1217 psn.hdr.idFrom = 0;
1218 psn.lParam = 0;
1220 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1222 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1224 TRACE("msg result %ld\n", msgResult);
1226 if (msgResult != 0)
1227 return FALSE;
1229 if (psInfo->isModeless)
1230 psInfo->activeValid = FALSE;
1231 else
1232 EndDialog(hwndDlg, TRUE);
1234 return TRUE;
1237 /******************************************************************************
1238 * PROPSHEET_Apply
1240 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1242 int i;
1243 HWND hwndPage;
1244 PSHNOTIFY psn;
1245 LRESULT msgResult;
1246 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1247 PropSheetInfoStr);
1249 if (psInfo->active_page < 0)
1250 return FALSE;
1252 psn.hdr.hwndFrom = hwndDlg;
1253 psn.hdr.idFrom = 0;
1254 psn.lParam = 0;
1258 * Send PSN_KILLACTIVE to the current page.
1260 psn.hdr.code = PSN_KILLACTIVE;
1262 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1264 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1265 return FALSE;
1268 * Send PSN_APPLY to all pages.
1270 psn.hdr.code = PSN_APPLY;
1271 psn.lParam = lParam;
1273 for (i = 0; i < psInfo->nPages; i++)
1275 hwndPage = psInfo->proppage[i].hwndPage;
1276 if (hwndPage)
1278 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1279 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1280 return FALSE;
1284 if(lParam)
1286 psInfo->activeValid = FALSE;
1288 else if(psInfo->active_page >= 0)
1290 psn.hdr.code = PSN_SETACTIVE;
1291 psn.lParam = 0;
1292 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1293 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1296 return TRUE;
1299 /******************************************************************************
1300 * PROPSHEET_Cancel
1302 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1304 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1305 PropSheetInfoStr);
1306 HWND hwndPage;
1307 PSHNOTIFY psn;
1308 int i;
1310 if (psInfo->active_page < 0)
1311 return;
1313 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1314 psn.hdr.code = PSN_QUERYCANCEL;
1315 psn.hdr.hwndFrom = hwndDlg;
1316 psn.hdr.idFrom = 0;
1317 psn.lParam = 0;
1319 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1320 return;
1322 psn.hdr.code = PSN_RESET;
1323 psn.lParam = lParam;
1325 for (i = 0; i < psInfo->nPages; i++)
1327 hwndPage = psInfo->proppage[i].hwndPage;
1329 if (hwndPage)
1330 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1333 if (psInfo->isModeless)
1335 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1336 psInfo->activeValid = FALSE;
1338 else
1339 EndDialog(hwndDlg, FALSE);
1342 /******************************************************************************
1343 * PROPSHEET_Help
1345 static void PROPSHEET_Help(HWND hwndDlg)
1347 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1348 PropSheetInfoStr);
1349 HWND hwndPage;
1350 PSHNOTIFY psn;
1352 if (psInfo->active_page < 0)
1353 return;
1355 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1356 psn.hdr.code = PSN_HELP;
1357 psn.hdr.hwndFrom = hwndDlg;
1358 psn.hdr.idFrom = 0;
1359 psn.lParam = 0;
1361 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1364 /******************************************************************************
1365 * PROPSHEET_Changed
1367 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1369 int i;
1370 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1371 PropSheetInfoStr);
1373 if (!psInfo) return;
1375 * Set the dirty flag of this page.
1377 for (i = 0; i < psInfo->nPages; i++)
1379 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1380 psInfo->proppage[i].isDirty = TRUE;
1384 * Enable the Apply button.
1386 if (psInfo->hasApply)
1388 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1390 EnableWindow(hwndApplyBtn, TRUE);
1394 /******************************************************************************
1395 * PROPSHEET_UnChanged
1397 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1399 int i;
1400 BOOL noPageDirty = TRUE;
1401 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1402 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1403 PropSheetInfoStr);
1405 if ( !psInfo ) return;
1406 for (i = 0; i < psInfo->nPages; i++)
1408 /* set the specified page as clean */
1409 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1410 psInfo->proppage[i].isDirty = FALSE;
1412 /* look to see if there's any dirty pages */
1413 if (psInfo->proppage[i].isDirty)
1414 noPageDirty = FALSE;
1418 * Disable Apply button.
1420 if (noPageDirty)
1421 EnableWindow(hwndApplyBtn, FALSE);
1424 /******************************************************************************
1425 * PROPSHEET_PressButton
1427 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1429 switch (buttonID)
1431 case PSBTN_APPLYNOW:
1432 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1433 break;
1434 case PSBTN_BACK:
1435 PROPSHEET_Back(hwndDlg);
1436 break;
1437 case PSBTN_CANCEL:
1438 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1439 break;
1440 case PSBTN_FINISH:
1441 PROPSHEET_Finish(hwndDlg);
1442 break;
1443 case PSBTN_HELP:
1444 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1445 break;
1446 case PSBTN_NEXT:
1447 PROPSHEET_Next(hwndDlg);
1448 break;
1449 case PSBTN_OK:
1450 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1451 break;
1452 default:
1453 FIXME("Invalid button index %d\n", buttonID);
1458 /*************************************************************************
1459 * BOOL PROPSHEET_CanSetCurSel [Internal]
1461 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1463 * PARAMS
1464 * hwndDlg [I] handle to a Dialog hWnd
1466 * RETURNS
1467 * TRUE if Current Selection can change
1469 * NOTES
1471 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1473 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1474 PropSheetInfoStr);
1475 HWND hwndPage;
1476 PSHNOTIFY psn;
1478 if (!psInfo)
1479 return FALSE;
1481 if (psInfo->active_page < 0)
1482 return TRUE;
1485 * Notify the current page.
1487 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1488 psn.hdr.code = PSN_KILLACTIVE;
1489 psn.hdr.hwndFrom = hwndDlg;
1490 psn.hdr.idFrom = 0;
1491 psn.lParam = 0;
1493 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1496 /******************************************************************************
1497 * PROPSHEET_SetCurSel
1499 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1500 int index,
1501 int skipdir,
1502 HPROPSHEETPAGE hpage
1505 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1506 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1508 /* hpage takes precedence over index */
1509 if (hpage != NULL)
1510 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1512 if (index < 0 || index >= psInfo->nPages)
1514 TRACE("Could not find page to select!\n");
1515 return FALSE;
1518 while (1) {
1519 int result;
1520 PSHNOTIFY psn;
1522 psn.hdr.code = PSN_SETACTIVE;
1523 psn.hdr.hwndFrom = hwndDlg;
1524 psn.hdr.idFrom = 0;
1525 psn.lParam = 0;
1527 if (!psInfo->proppage[index].hwndPage) {
1528 LPCPROPSHEETPAGEA ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1529 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1532 result = SendMessageA(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1533 if (!result)
1534 break;
1535 if (result == -1) {
1536 index+=skipdir;
1537 if (index < 0) {
1538 index = 0;
1539 FIXME("Tried to skip before first property sheet page!\n");
1540 break;
1542 if (index >= psInfo->nPages) {
1543 FIXME("Tried to skip after last property sheet page!\n");
1544 index = psInfo->nPages-1;
1545 break;
1550 * Display the new page.
1552 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1554 if (psInfo->proppage[index].hasHelp)
1555 EnableWindow(hwndHelp, TRUE);
1556 else
1557 EnableWindow(hwndHelp, FALSE);
1559 return TRUE;
1562 /******************************************************************************
1563 * PROPSHEET_SetTitleA
1565 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1567 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1568 char szTitle[256];
1570 if (HIWORD(lpszText) == 0) {
1571 if (!LoadStringA(psInfo->ppshheader.hInstance,
1572 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1573 return;
1574 lpszText = szTitle;
1576 if (dwStyle & PSH_PROPTITLE)
1578 char* dest;
1579 int lentitle = strlen(lpszText);
1580 int lenprop = strlen(psInfo->strPropertiesFor);
1582 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1583 strcpy(dest, psInfo->strPropertiesFor);
1584 strcat(dest, lpszText);
1586 SetWindowTextA(hwndDlg, dest);
1587 COMCTL32_Free(dest);
1589 else
1590 SetWindowTextA(hwndDlg, lpszText);
1593 /******************************************************************************
1594 * PROPSHEET_SetFinishTextA
1596 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1598 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1600 /* Set text, show and enable the Finish button */
1601 SetWindowTextA(hwndButton, lpszText);
1602 ShowWindow(hwndButton, SW_SHOW);
1603 EnableWindow(hwndButton, TRUE);
1605 /* Make it default pushbutton */
1606 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1608 /* Hide Back button */
1609 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1610 ShowWindow(hwndButton, SW_HIDE);
1612 /* Hide Next button */
1613 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1614 ShowWindow(hwndButton, SW_HIDE);
1617 /******************************************************************************
1618 * PROPSHEET_QuerySiblings
1620 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1621 WPARAM wParam, LPARAM lParam)
1623 int i = 0;
1624 HWND hwndPage;
1625 LRESULT msgResult = 0;
1626 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1627 PropSheetInfoStr);
1629 while ((i < psInfo->nPages) && (msgResult == 0))
1631 hwndPage = psInfo->proppage[i].hwndPage;
1632 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1633 i++;
1636 return msgResult;
1640 /******************************************************************************
1641 * PROPSHEET_AddPage
1643 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1644 HPROPSHEETPAGE hpage)
1646 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1647 PropSheetInfoStr);
1648 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1649 TCITEMA item;
1650 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1651 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1654 * Allocate and fill in a new PropPageInfo entry.
1656 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1657 sizeof(PropPageInfo) *
1658 (psInfo->nPages + 1));
1659 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1660 return FALSE;
1662 psInfo->proppage[psInfo->nPages].hpage = hpage;
1664 if (ppsp->dwFlags & PSP_PREMATURE)
1666 /* Create the page but don't show it */
1667 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1671 * Add a new tab to the tab control.
1673 item.mask = TCIF_TEXT;
1674 item.pszText = tabtext;
1675 item.cchTextMax = MAX_TABTEXT_LENGTH;
1677 WideCharToMultiByte(CP_ACP, 0,
1678 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1679 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1681 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1682 (LPARAM)&item);
1684 psInfo->nPages++;
1686 /* If it is the only page - show it */
1687 if(psInfo->nPages == 1)
1688 PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
1689 return TRUE;
1692 /******************************************************************************
1693 * PROPSHEET_RemovePage
1695 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1696 int index,
1697 HPROPSHEETPAGE hpage)
1699 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1700 PropSheetInfoStr);
1701 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1702 PropPageInfo* oldPages;
1704 if (!psInfo) {
1705 return FALSE;
1707 oldPages = psInfo->proppage;
1709 * hpage takes precedence over index.
1711 if (hpage != 0)
1713 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1716 /* Make sure that index is within range */
1717 if (index < 0 || index >= psInfo->nPages)
1719 TRACE("Could not find page to remove!\n");
1720 return FALSE;
1723 TRACE("total pages %d removing page %d active page %d\n",
1724 psInfo->nPages, index, psInfo->active_page);
1726 * Check if we're removing the active page.
1728 if (index == psInfo->active_page)
1730 if (psInfo->nPages > 1)
1732 if (index > 0)
1734 /* activate previous page */
1735 PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
1737 else
1739 /* activate the next page */
1740 PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
1741 psInfo->active_page = index;
1744 else
1746 psInfo->active_page = -1;
1747 if (!psInfo->isModeless)
1749 EndDialog(hwndDlg, FALSE);
1750 return TRUE;
1754 else if (index < psInfo->active_page)
1755 psInfo->active_page--;
1757 /* Destroy page dialog window */
1758 DestroyWindow(psInfo->proppage[index].hwndPage);
1760 /* Free page resources */
1761 if(psInfo->proppage[index].hpage)
1763 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1765 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1766 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1768 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1771 /* Remove the tab */
1772 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1774 psInfo->nPages--;
1775 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1777 if (index > 0)
1778 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1780 if (index < psInfo->nPages)
1781 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1782 (psInfo->nPages - index) * sizeof(PropPageInfo));
1784 COMCTL32_Free(oldPages);
1786 return FALSE;
1789 /******************************************************************************
1790 * PROPSHEET_SetWizButtons
1792 * This code will work if (and assumes that) the Next button is on top of the
1793 * Finish button. ie. Finish comes after Next in the Z order.
1794 * This means make sure the dialog template reflects this.
1797 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1799 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1800 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1801 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1803 TRACE("%ld\n", dwFlags);
1805 EnableWindow(hwndBack, FALSE);
1806 EnableWindow(hwndNext, FALSE);
1807 EnableWindow(hwndFinish, FALSE);
1809 if (dwFlags & PSWIZB_BACK)
1810 EnableWindow(hwndBack, TRUE);
1812 if (dwFlags & PSWIZB_NEXT)
1814 /* Hide the Finish button */
1815 ShowWindow(hwndFinish, SW_HIDE);
1817 /* Show and enable the Next button */
1818 ShowWindow(hwndNext, SW_SHOW);
1819 EnableWindow(hwndNext, TRUE);
1821 /* Set the Next button as the default pushbutton */
1822 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1825 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1827 /* Hide the Next button */
1828 ShowWindow(hwndNext, SW_HIDE);
1830 /* Show the Finish button */
1831 ShowWindow(hwndFinish, SW_SHOW);
1833 if (dwFlags & PSWIZB_FINISH)
1834 EnableWindow(hwndFinish, TRUE);
1836 /* Set the Finish button as the default pushbutton */
1837 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1841 /******************************************************************************
1842 * PROPSHEET_GetPageIndex
1844 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1845 * the array of PropPageInfo.
1847 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1849 BOOL found = FALSE;
1850 int index = 0;
1852 while ((index < psInfo->nPages) && (found == FALSE))
1854 if (psInfo->proppage[index].hpage == hpage)
1855 found = TRUE;
1856 else
1857 index++;
1860 if (found == FALSE)
1861 index = -1;
1863 return index;
1866 /******************************************************************************
1867 * PROPSHEET_CleanUp
1869 static void PROPSHEET_CleanUp(HWND hwndDlg)
1871 int i;
1872 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1873 PropSheetInfoStr);
1875 TRACE("\n");
1876 if (HIWORD(psInfo->ppshheader.pszCaption))
1877 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
1879 for (i = 0; i < psInfo->nPages; i++)
1881 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1883 if(psInfo->proppage[i].hwndPage)
1884 DestroyWindow(psInfo->proppage[i].hwndPage);
1886 if(psp)
1888 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1889 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1891 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1895 COMCTL32_Free(psInfo->proppage);
1896 COMCTL32_Free(psInfo->strPropertiesFor);
1897 ImageList_Destroy(psInfo->hImageList);
1899 GlobalFree((HGLOBAL)psInfo);
1902 /******************************************************************************
1903 * PropertySheet (COMCTL32.87)
1904 * PropertySheetA (COMCTL32.88)
1906 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1908 int bRet = 0;
1909 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1910 sizeof(PropSheetInfo));
1911 int i, n;
1912 BYTE* pByte;
1914 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1916 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1917 lppsh->nPages);
1918 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
1920 for (n = i = 0; i < lppsh->nPages; i++, n++)
1922 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1923 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
1924 else
1926 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1927 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1930 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1931 psInfo, n))
1933 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1934 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1935 n--;
1936 psInfo->nPages--;
1940 bRet = PROPSHEET_CreateDialog(psInfo);
1942 return bRet;
1945 /******************************************************************************
1946 * PropertySheetW (COMCTL32.89)
1948 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1950 FIXME("(%p): stub\n", propertySheetHeader);
1952 return -1;
1955 /******************************************************************************
1956 * CreatePropertySheetPage (COMCTL32.18)
1957 * CreatePropertySheetPageA (COMCTL32.19)
1959 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1960 LPCPROPSHEETPAGEA lpPropSheetPage)
1962 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1964 memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
1966 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
1967 ppsp->u.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u.pszTemplate );
1969 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1970 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
1973 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1974 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
1975 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1976 ppsp->pszTitle = NULL;
1978 return (HPROPSHEETPAGE)ppsp;
1981 /******************************************************************************
1982 * CreatePropertySheetPageW (COMCTL32.20)
1984 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1986 FIXME("(%p): stub\n", lpPropSheetPage);
1988 return 0;
1991 /******************************************************************************
1992 * DestroyPropertySheetPage (COMCTL32.24)
1994 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1996 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
1998 if (!psp)
1999 return FALSE;
2001 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
2002 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
2004 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2005 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2007 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2008 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2010 COMCTL32_Free(hPropPage);
2012 return TRUE;
2015 /******************************************************************************
2016 * PROPSHEET_IsDialogMessage
2018 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2020 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2022 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2023 return FALSE;
2025 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2027 int new_page = 0;
2028 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2030 if (!(dlgCode & DLGC_WANTMESSAGE))
2032 switch (lpMsg->wParam)
2034 case VK_TAB:
2035 if (GetKeyState(VK_SHIFT) & 0x8000)
2036 new_page = -1;
2037 else
2038 new_page = 1;
2039 break;
2041 case VK_NEXT: new_page = 1; break;
2042 case VK_PRIOR: new_page = -1; break;
2046 if (new_page)
2048 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2050 new_page += psInfo->active_page;
2052 if (new_page < 0)
2053 new_page = psInfo->nPages - 1;
2054 else if (new_page >= psInfo->nPages)
2055 new_page = 0;
2057 PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
2060 return TRUE;
2064 return IsDialogMessageA(hwnd, lpMsg);
2067 /******************************************************************************
2068 * PROPSHEET_DialogProc
2070 BOOL WINAPI
2071 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2073 switch (uMsg)
2075 case WM_INITDIALOG:
2077 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2078 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2079 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2080 LPCPROPSHEETPAGEA ppshpage;
2081 int idx;
2083 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2086 * psInfo->hwnd is not being used by WINE code - it exists
2087 * for compatibility with "real" Windoze. The same about
2088 * SetWindowLong - WINE is only using the PropSheetInfoStr
2089 * property.
2091 psInfo->hwnd = hwnd;
2092 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2095 * Small icon in the title bar.
2097 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2098 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2100 HICON hIcon;
2101 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2102 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2104 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2105 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2106 psInfo->ppshheader.u.pszIcon,
2107 IMAGE_ICON,
2108 icon_cx, icon_cy,
2109 LR_DEFAULTCOLOR);
2110 else
2111 hIcon = psInfo->ppshheader.u.hIcon;
2113 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2116 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2117 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u.hIcon);
2119 psInfo->strPropertiesFor = strCaption;
2121 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2123 PROPSHEET_CreateTabControl(hwnd, psInfo);
2125 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2127 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2129 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2130 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2133 else
2135 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2137 PROPSHEET_AdjustSize(hwnd, psInfo);
2138 PROPSHEET_AdjustButtons(hwnd, psInfo);
2142 if (psInfo->useCallback)
2143 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2144 PSCB_INITIALIZED, (LPARAM)0);
2146 idx = psInfo->active_page;
2147 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2148 psInfo->active_page = -1;
2150 PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
2152 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2153 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2155 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2156 psInfo->ppshheader.hInstance)
2158 char szText[256];
2160 if (LoadStringA(psInfo->ppshheader.hInstance,
2161 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2162 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2164 else
2166 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2167 psInfo->ppshheader.pszCaption);
2170 return TRUE;
2173 case WM_DESTROY:
2174 PROPSHEET_CleanUp(hwnd);
2175 return TRUE;
2177 case WM_CLOSE:
2178 PROPSHEET_Cancel(hwnd, 1);
2179 return TRUE;
2181 case WM_COMMAND:
2183 WORD wID = LOWORD(wParam);
2185 switch (wID)
2187 case IDOK:
2188 case IDC_APPLY_BUTTON:
2190 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2192 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2193 break;
2195 if (wID == IDOK)
2197 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2198 PropSheetInfoStr);
2199 int result = TRUE;
2201 if (psInfo->restartWindows)
2202 result = ID_PSRESTARTWINDOWS;
2204 /* reboot system takes precedence over restart windows */
2205 if (psInfo->rebootSystem)
2206 result = ID_PSREBOOTSYSTEM;
2208 if (psInfo->isModeless)
2209 psInfo->activeValid = FALSE;
2210 else
2211 EndDialog(hwnd, result);
2213 else
2214 EnableWindow(hwndApplyBtn, FALSE);
2216 break;
2219 case IDC_BACK_BUTTON:
2220 PROPSHEET_Back(hwnd);
2221 break;
2223 case IDC_NEXT_BUTTON:
2224 PROPSHEET_Next(hwnd);
2225 break;
2227 case IDC_FINISH_BUTTON:
2228 PROPSHEET_Finish(hwnd);
2229 break;
2231 case IDCANCEL:
2232 PROPSHEET_Cancel(hwnd, 0);
2233 break;
2235 case IDHELP:
2236 PROPSHEET_Help(hwnd);
2237 break;
2240 return TRUE;
2243 case WM_NOTIFY:
2245 NMHDR* pnmh = (LPNMHDR) lParam;
2247 if (pnmh->code == TCN_SELCHANGE)
2249 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2250 PROPSHEET_SetCurSel(hwnd, index, 1, 0);
2253 if(pnmh->code == TCN_SELCHANGING)
2255 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2256 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2257 return TRUE;
2260 return FALSE;
2263 case PSM_GETCURRENTPAGEHWND:
2265 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2266 PropSheetInfoStr);
2267 HWND hwndPage = 0;
2269 if (psInfo->activeValid && psInfo->active_page != -1)
2270 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2272 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2274 return TRUE;
2277 case PSM_CHANGED:
2278 PROPSHEET_Changed(hwnd, (HWND)wParam);
2279 return TRUE;
2281 case PSM_UNCHANGED:
2282 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2283 return TRUE;
2285 case PSM_GETTABCONTROL:
2287 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2289 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2291 return TRUE;
2294 case PSM_SETCURSEL:
2296 BOOL msgResult;
2298 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2299 if(msgResult != FALSE)
2301 msgResult = PROPSHEET_SetCurSel(hwnd,
2302 (int)wParam,
2304 (HPROPSHEETPAGE)lParam);
2307 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2309 return TRUE;
2312 case PSM_CANCELTOCLOSE:
2314 char buf[MAX_BUTTONTEXT_LENGTH];
2315 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2316 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2318 EnableWindow(hwndCancel, FALSE);
2319 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2320 SetWindowTextA(hwndOK, buf);
2322 return FALSE;
2325 case PSM_RESTARTWINDOWS:
2327 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2328 PropSheetInfoStr);
2330 psInfo->restartWindows = TRUE;
2331 return TRUE;
2334 case PSM_REBOOTSYSTEM:
2336 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2337 PropSheetInfoStr);
2339 psInfo->rebootSystem = TRUE;
2340 return TRUE;
2343 case PSM_SETTITLEA:
2344 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2345 return TRUE;
2347 case PSM_APPLY:
2349 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2351 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2353 return TRUE;
2356 case PSM_QUERYSIBLINGS:
2358 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2360 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2362 return TRUE;
2365 case PSM_ADDPAGE:
2368 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2369 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2370 * on success or FALSE otherwise, as specified on MSDN Online.
2371 * Also see the MFC code for
2372 * CPropertySheet::AddPage(CPropertyPage* pPage).
2375 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2377 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2379 return TRUE;
2382 case PSM_REMOVEPAGE:
2383 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2384 return TRUE;
2386 case PSM_ISDIALOGMESSAGE:
2388 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2389 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2390 return TRUE;
2393 case PSM_PRESSBUTTON:
2394 PROPSHEET_PressButton(hwnd, (int)wParam);
2395 return TRUE;
2397 case PSM_SETFINISHTEXTA:
2398 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2399 return TRUE;
2401 case PSM_SETWIZBUTTONS:
2402 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2403 return TRUE;
2405 case PSM_SETTITLEW:
2406 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2407 return FALSE;
2409 case PSM_SETCURSELID:
2410 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2411 return FALSE;
2413 case PSM_SETFINISHTEXTW:
2414 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2415 return FALSE;
2417 default:
2418 return FALSE;
2421 return FALSE;