Be a bit more graceful on NULL property sheet titles.
[wine.git] / dlls / comctl32 / propsheet.c
bloba288d2f1bb265baaf34b0e0f62280b4a02980222
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))
157 psInfo->ppshheader.pszCaption = HeapAlloc( GetProcessHeap(), 0, strlen(lppsh->pszCaption)+1 );
158 strcpy( (char *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );
160 psInfo->nPages = lppsh->nPages;
162 if (dwFlags & PSH_USEPSTARTPAGE)
164 TRACE("PSH_USEPSTARTPAGE is on");
165 psInfo->active_page = 0;
167 else
168 psInfo->active_page = lppsh->u2.nStartPage;
170 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
171 psInfo->active_page = 0;
173 psInfo->restartWindows = FALSE;
174 psInfo->rebootSystem = FALSE;
175 psInfo->hImageList = 0;
176 psInfo->activeValid = FALSE;
178 return TRUE;
181 /******************************************************************************
182 * PROPSHEET_CollectPageInfo
184 * Collect property sheet data.
185 * With code taken from DIALOG_ParseTemplate32.
187 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
188 PropSheetInfo * psInfo,
189 int index)
191 DLGTEMPLATE* pTemplate;
192 const WORD* p;
193 DWORD dwFlags;
194 int width, height;
196 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
197 psInfo->proppage[index].hwndPage = 0;
198 psInfo->proppage[index].isDirty = FALSE;
201 * Process property page flags.
203 dwFlags = lppsp->dwFlags;
204 psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
205 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
206 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
208 /* as soon as we have a page with the help flag, set the sheet flag on */
209 if (psInfo->proppage[index].hasHelp)
210 psInfo->hasHelp = TRUE;
213 * Process page template.
215 if (dwFlags & PSP_DLGINDIRECT)
216 pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
217 else
219 HRSRC hResource = FindResourceA(lppsp->hInstance,
220 lppsp->u.pszTemplate,
221 RT_DIALOGA);
222 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
223 hResource);
224 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
228 * Extract the size of the page and the caption.
230 if (!pTemplate)
231 return FALSE;
233 p = (const WORD *)pTemplate;
235 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
237 /* DIALOGEX template */
239 p++; /* dlgVer */
240 p++; /* signature */
241 p += 2; /* help ID */
242 p += 2; /* ext style */
243 p += 2; /* style */
245 else
247 /* DIALOG template */
249 p += 2; /* style */
250 p += 2; /* ext style */
253 p++; /* nb items */
254 p++; /* x */
255 p++; /* y */
256 width = (WORD)*p; p++;
257 height = (WORD)*p; p++;
259 /* remember the largest width and height */
260 if (width > psInfo->width)
261 psInfo->width = width;
263 if (height > psInfo->height)
264 psInfo->height = height;
266 /* menu */
267 switch ((WORD)*p)
269 case 0x0000:
270 p++;
271 break;
272 case 0xffff:
273 p += 2;
274 break;
275 default:
276 p += lstrlenW( (LPCWSTR)p ) + 1;
277 break;
280 /* class */
281 switch ((WORD)*p)
283 case 0x0000:
284 p++;
285 break;
286 case 0xffff:
287 p += 2;
288 break;
289 default:
290 p += lstrlenW( (LPCWSTR)p ) + 1;
291 break;
294 /* Extract the caption */
295 psInfo->proppage[index].pszText = (LPCWSTR)p;
296 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
297 p += lstrlenW((LPCWSTR)p) + 1;
299 if (dwFlags & PSP_USETITLE)
301 if ( !HIWORD( lppsp->pszTitle ) )
303 char szTitle[256];
305 if (LoadStringA( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,256 )) {
306 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(), 0, szTitle );
307 } else {
308 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(), 0, "(null)" );
309 FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
312 } else
313 psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
315 lppsp->pszTitle);
319 * Build the image list for icons
321 if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
323 HICON hIcon;
324 int icon_cx = GetSystemMetrics(SM_CXSMICON);
325 int icon_cy = GetSystemMetrics(SM_CYSMICON);
327 if (dwFlags & PSP_USEICONID)
328 hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
329 icon_cx, icon_cy, LR_DEFAULTCOLOR);
330 else
331 hIcon = lppsp->u2.hIcon;
333 if ( hIcon )
335 if (psInfo->hImageList == 0 )
336 psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
338 ImageList_AddIcon(psInfo->hImageList, hIcon);
343 return TRUE;
347 /******************************************************************************
348 * PROPSHEET_CreateDialog
350 * Creates the actual property sheet.
352 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
354 LRESULT ret;
355 LPCVOID template;
356 LPVOID temp = 0;
357 HRSRC hRes;
358 DWORD resSize;
359 WORD resID = IDD_PROPSHEET;
361 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
362 resID = IDD_WIZARD;
364 if(!(hRes = FindResourceA(COMCTL32_hModule,
365 MAKEINTRESOURCEA(resID),
366 RT_DIALOGA)))
367 return FALSE;
369 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
370 return FALSE;
373 * Make a copy of the dialog template.
375 resSize = SizeofResource(COMCTL32_hModule, hRes);
377 temp = COMCTL32_Alloc(resSize);
379 if (!temp)
380 return FALSE;
382 memcpy(temp, template, resSize);
384 if (psInfo->useCallback)
385 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
387 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
388 ret = DialogBoxIndirectParamA(psInfo->ppshheader.hInstance,
389 (LPDLGTEMPLATEA) temp,
390 psInfo->ppshheader.hwndParent,
391 (DLGPROC) PROPSHEET_DialogProc,
392 (LPARAM)psInfo);
393 else
394 ret = CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
395 (LPDLGTEMPLATEA) temp,
396 psInfo->ppshheader.hwndParent,
397 (DLGPROC) PROPSHEET_DialogProc,
398 (LPARAM)psInfo);
400 COMCTL32_Free(temp);
402 return ret;
405 /******************************************************************************
406 * PROPSHEET_SizeMismatch
408 * Verify that the tab control and the "largest" property sheet page dlg. template
409 * match in size.
411 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
413 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
414 RECT rcOrigTab, rcPage;
417 * Original tab size.
419 GetClientRect(hwndTabCtrl, &rcOrigTab);
420 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
421 rcOrigTab.right, rcOrigTab.bottom);
424 * Biggest page size.
426 rcPage.left = psInfo->x;
427 rcPage.top = psInfo->y;
428 rcPage.right = psInfo->width;
429 rcPage.bottom = psInfo->height;
431 MapDialogRect(hwndDlg, &rcPage);
432 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
433 rcPage.right, rcPage.bottom);
435 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
436 return TRUE;
437 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
438 return TRUE;
440 return FALSE;
443 /******************************************************************************
444 * PROPSHEET_IsTooSmallWizard
446 * Verify that the default property sheet is big enough.
448 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
450 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
451 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
452 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
454 GetClientRect(hwndDlg, &rcSheetClient);
455 GetWindowRect(hwndDlg, &rcSheetRect);
456 GetWindowRect(hwndLine, &rcLine);
458 /* Remove the space below the sunken line */
459 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
461 /* Remove the buffer zone all around the edge */
462 rcSheetClient.bottom -= (padding.y * 2);
463 rcSheetClient.right -= (padding.x * 2);
466 * Biggest page size.
468 rcPage.left = psInfo->x;
469 rcPage.top = psInfo->y;
470 rcPage.right = psInfo->width;
471 rcPage.bottom = psInfo->height;
473 MapDialogRect(hwndDlg, &rcPage);
474 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
475 rcPage.right, rcPage.bottom);
477 if (rcPage.right > rcSheetClient.right)
478 return TRUE;
480 if (rcPage.bottom > rcSheetClient.bottom)
481 return TRUE;
483 return FALSE;
486 /******************************************************************************
487 * PROPSHEET_AdjustSize
489 * Resizes the property sheet and the tab control to fit the largest page.
491 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
493 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
494 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
495 RECT rc,tabRect;
496 int tabOffsetX, tabOffsetY, buttonHeight;
497 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
498 RECT units;
500 /* Get the height of buttons */
501 GetClientRect(hwndButton, &rc);
502 buttonHeight = rc.bottom;
505 * Biggest page size.
507 rc.left = psInfo->x;
508 rc.top = psInfo->y;
509 rc.right = psInfo->width;
510 rc.bottom = psInfo->height;
512 MapDialogRect(hwndDlg, &rc);
514 /* retrieve the dialog units */
515 units.left = units.right = 4;
516 units.top = units.bottom = 8;
517 MapDialogRect(hwndDlg, &units);
520 * Resize the tab control.
522 GetClientRect(hwndTabCtrl,&tabRect);
524 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
526 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
528 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
529 psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
532 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
534 rc.right = rc.left + tabRect.right - tabRect.left;
535 psInfo->width = MulDiv((rc.right - rc.left),4,units.left);
538 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
540 tabOffsetX = -(rc.left);
541 tabOffsetY = -(rc.top);
543 rc.right -= rc.left;
544 rc.bottom -= rc.top;
545 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
546 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
548 GetClientRect(hwndTabCtrl, &rc);
550 TRACE("tab client rc %d %d %d %d\n",
551 rc.left, rc.top, rc.right, rc.bottom);
553 rc.right += ((padding.x * 2) + tabOffsetX);
554 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
557 * Resize the property sheet.
559 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
560 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
561 return TRUE;
564 /******************************************************************************
565 * PROPSHEET_AdjustSizeWizard
567 * Resizes the property sheet to fit the largest page.
569 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
571 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
572 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
573 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
574 RECT rc,tabRect;
575 int buttonHeight, lineHeight;
576 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg, psInfo);
577 RECT units;
579 /* Get the height of buttons */
580 GetClientRect(hwndButton, &rc);
581 buttonHeight = rc.bottom;
583 GetClientRect(hwndLine, &rc);
584 lineHeight = rc.bottom;
586 /* retrieve the dialog units */
587 units.left = units.right = 4;
588 units.top = units.bottom = 8;
589 MapDialogRect(hwndDlg, &units);
592 * Biggest page size.
594 rc.left = psInfo->x;
595 rc.top = psInfo->y;
596 rc.right = psInfo->width;
597 rc.bottom = psInfo->height;
599 MapDialogRect(hwndDlg, &rc);
601 GetClientRect(hwndTabCtrl,&tabRect);
603 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
605 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
606 psInfo->height = MulDiv((rc.bottom - rc.top), 8, units.top);
609 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
611 rc.right = rc.left + tabRect.right - tabRect.left;
612 psInfo->width = MulDiv((rc.right - rc.left), 4, units.left);
615 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
617 /* Make room */
618 rc.right += (padding.x * 2);
619 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
622 * Resize the property sheet.
624 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
625 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
626 return TRUE;
629 /******************************************************************************
630 * PROPSHEET_AdjustButtons
632 * Adjusts the buttons' positions.
634 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
636 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
637 RECT rcSheet;
638 int x, y;
639 int num_buttons = 2;
640 int buttonWidth, buttonHeight;
641 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
643 if (psInfo->hasApply)
644 num_buttons++;
646 if (psInfo->hasHelp)
647 num_buttons++;
650 * Obtain the size of the buttons.
652 GetClientRect(hwndButton, &rcSheet);
653 buttonWidth = rcSheet.right;
654 buttonHeight = rcSheet.bottom;
657 * Get the size of the property sheet.
659 GetClientRect(hwndParent, &rcSheet);
662 * All buttons will be at this y coordinate.
664 y = rcSheet.bottom - (padding.y + buttonHeight);
667 * Position OK button.
669 hwndButton = GetDlgItem(hwndParent, IDOK);
671 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
673 SetWindowPos(hwndButton, 0, x, y, 0, 0,
674 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
677 * Position Cancel button.
679 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
681 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
683 SetWindowPos(hwndButton, 0, x, y, 0, 0,
684 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
687 * Position Apply button.
689 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
691 if (psInfo->hasApply)
693 if (psInfo->hasHelp)
694 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
695 else
696 x = rcSheet.right - (padding.x + buttonWidth);
698 SetWindowPos(hwndButton, 0, x, y, 0, 0,
699 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
701 EnableWindow(hwndButton, FALSE);
703 else
704 ShowWindow(hwndButton, SW_HIDE);
707 * Position Help button.
709 hwndButton = GetDlgItem(hwndParent, IDHELP);
711 if (psInfo->hasHelp)
713 x = rcSheet.right - (padding.x + buttonWidth);
715 SetWindowPos(hwndButton, 0, x, y, 0, 0,
716 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
718 else
719 ShowWindow(hwndButton, SW_HIDE);
721 return TRUE;
724 /******************************************************************************
725 * PROPSHEET_AdjustButtonsWizard
727 * Adjusts the buttons' positions.
729 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
730 PropSheetInfo* psInfo)
732 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
733 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
734 RECT rcSheet;
735 int x, y;
736 int num_buttons = 3;
737 int buttonWidth, buttonHeight, lineHeight, lineWidth;
738 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
740 if (psInfo->hasHelp)
741 num_buttons++;
744 * Obtain the size of the buttons.
746 GetClientRect(hwndButton, &rcSheet);
747 buttonWidth = rcSheet.right;
748 buttonHeight = rcSheet.bottom;
750 GetClientRect(hwndLine, &rcSheet);
751 lineHeight = rcSheet.bottom;
754 * Get the size of the property sheet.
756 GetClientRect(hwndParent, &rcSheet);
759 * All buttons will be at this y coordinate.
761 y = rcSheet.bottom - (padding.y + buttonHeight);
764 * Position the Next and the Finish buttons.
766 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
768 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
770 SetWindowPos(hwndButton, 0, x, y, 0, 0,
771 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
773 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
775 SetWindowPos(hwndButton, 0, x, y, 0, 0,
776 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
778 ShowWindow(hwndButton, SW_HIDE);
781 * Position the Back button.
783 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
785 x -= buttonWidth;
787 SetWindowPos(hwndButton, 0, x, y, 0, 0,
788 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
791 * Position the Cancel button.
793 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
795 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
797 SetWindowPos(hwndButton, 0, x, y, 0, 0,
798 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
801 * Position Help button.
803 hwndButton = GetDlgItem(hwndParent, IDHELP);
805 if (psInfo->hasHelp)
807 x = rcSheet.right - (padding.x + buttonWidth);
809 SetWindowPos(hwndButton, 0, x, y, 0, 0,
810 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
812 else
813 ShowWindow(hwndButton, SW_HIDE);
816 * Position and resize the sunken line.
818 x = padding.x;
819 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
821 GetClientRect(hwndParent, &rcSheet);
822 lineWidth = rcSheet.right - (padding.x * 2);
824 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
825 SWP_NOZORDER | SWP_NOACTIVATE);
827 return TRUE;
830 /******************************************************************************
831 * PROPSHEET_GetPaddingInfo
833 * Returns the layout information.
835 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
837 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
838 RECT rcTab;
839 POINT tl;
840 PADDING_INFO padding;
842 GetWindowRect(hwndTab, &rcTab);
844 tl.x = rcTab.left;
845 tl.y = rcTab.top;
847 ScreenToClient(hwndDlg, &tl);
849 padding.x = tl.x;
850 padding.y = tl.y;
852 return padding;
855 /******************************************************************************
856 * PROPSHEET_GetPaddingInfoWizard
858 * Returns the layout information.
859 * Vertical spacing is the distance between the line and the buttons.
860 * Do NOT use the Help button to gather padding information when it isn't mapped
861 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
862 * for it in this case !
863 * FIXME: I'm not sure about any other coordinate problems with these evil
864 * buttons. Fix it in case additional problems appear or maybe calculate
865 * a padding in a completely different way, as this is somewhat messy.
867 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
868 psInfo)
870 PADDING_INFO padding;
871 RECT rc;
872 HWND hwndControl;
873 INT idButton;
874 POINT ptButton, ptLine;
876 if (psInfo->hasHelp)
878 idButton = IDHELP;
880 else
882 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
884 idButton = IDC_NEXT_BUTTON;
886 else
888 /* hopefully this is ok */
889 idButton = IDCANCEL;
893 hwndControl = GetDlgItem(hwndDlg, idButton);
894 GetWindowRect(hwndControl, &rc);
896 ptButton.x = rc.left;
897 ptButton.y = rc.top;
899 ScreenToClient(hwndDlg, &ptButton);
901 /* Line */
902 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
903 GetWindowRect(hwndControl, &rc);
905 ptLine.x = 0;
906 ptLine.y = rc.bottom;
908 ScreenToClient(hwndDlg, &ptLine);
910 padding.y = ptButton.y - ptLine.y;
912 if (padding.y < 0)
913 ERR("padding negative ! Please report this !\n");
915 /* this is most probably not correct, but the best we have now */
916 padding.x = padding.y;
917 return padding;
920 /******************************************************************************
921 * PROPSHEET_CreateTabControl
923 * Insert the tabs in the tab control.
925 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
926 PropSheetInfo * psInfo)
928 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
929 TCITEMA item;
930 int i, nTabs;
931 int iImage = 0;
932 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
934 item.mask = TCIF_TEXT;
935 item.pszText = tabtext;
936 item.cchTextMax = MAX_TABTEXT_LENGTH;
938 nTabs = psInfo->nPages;
941 * Set the image list for icons.
943 if (psInfo->hImageList)
945 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
948 for (i = 0; i < nTabs; i++)
950 if ( psInfo->proppage[i].hasIcon )
952 item.mask |= TCIF_IMAGE;
953 item.iImage = iImage++;
955 else
957 item.mask &= ~TCIF_IMAGE;
960 WideCharToMultiByte(CP_ACP, 0,
961 (LPCWSTR)psInfo->proppage[i].pszText,
962 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
964 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
967 return TRUE;
970 /******************************************************************************
971 * PROPSHEET_CreatePage
973 * Creates a page.
975 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
976 int index,
977 const PropSheetInfo * psInfo,
978 LPCPROPSHEETPAGEA ppshpage)
980 DLGTEMPLATE* pTemplate;
981 HWND hwndPage;
982 RECT rc;
983 PropPageInfo* ppInfo = psInfo->proppage;
984 PADDING_INFO padding;
985 UINT pageWidth,pageHeight;
986 DWORD resSize;
987 LPVOID temp = NULL;
989 TRACE("index %d\n", index);
991 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
992 pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
993 else
995 HRSRC hResource;
996 HANDLE hTemplate;
998 hResource = FindResourceA(ppshpage->hInstance,
999 ppshpage->u.pszTemplate,
1000 RT_DIALOGA);
1001 if(!hResource)
1002 return FALSE;
1004 resSize = SizeofResource(ppshpage->hInstance, hResource);
1006 hTemplate = LoadResource(ppshpage->hInstance, hResource);
1007 if(!hTemplate)
1008 return FALSE;
1010 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1012 * Make a copy of the dialog template to make it writable
1014 temp = COMCTL32_Alloc(resSize);
1015 if (!temp)
1016 return FALSE;
1018 memcpy(temp, pTemplate, resSize);
1019 pTemplate = temp;
1022 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1024 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1025 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1026 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1027 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1028 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1029 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1030 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1032 else
1034 pTemplate->style |= WS_CHILD | DS_CONTROL;
1035 pTemplate->style &= ~DS_MODALFRAME;
1036 pTemplate->style &= ~WS_CAPTION;
1037 pTemplate->style &= ~WS_SYSMENU;
1038 pTemplate->style &= ~WS_POPUP;
1039 pTemplate->style &= ~WS_DISABLED;
1040 pTemplate->style &= ~WS_VISIBLE;
1043 if (psInfo->proppage[index].useCallback)
1044 (*(ppshpage->pfnCallback))(hwndParent,
1045 PSPCB_CREATE,
1046 (LPPROPSHEETPAGEA)ppshpage);
1048 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1049 pTemplate,
1050 hwndParent,
1051 ppshpage->pfnDlgProc,
1052 (LPARAM)ppshpage);
1053 /* Free a no more needed copy */
1054 if(temp)
1055 COMCTL32_Free(temp);
1057 ppInfo[index].hwndPage = hwndPage;
1059 rc.left = psInfo->x;
1060 rc.top = psInfo->y;
1061 rc.right = psInfo->width;
1062 rc.bottom = psInfo->height;
1064 MapDialogRect(hwndParent, &rc);
1066 pageWidth = rc.right - rc.left;
1067 pageHeight = rc.bottom - rc.top;
1069 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1070 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1071 else
1074 * Ask the Tab control to fit this page in.
1077 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1078 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1079 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1082 SetWindowPos(hwndPage, HWND_TOP,
1083 rc.left + padding.x,
1084 rc.top + padding.y,
1085 pageWidth, pageHeight, 0);
1087 return TRUE;
1090 /******************************************************************************
1091 * PROPSHEET_ShowPage
1093 * Displays or creates the specified page.
1095 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1097 if (index == psInfo->active_page)
1099 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1100 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1101 return TRUE;
1104 if (psInfo->proppage[index].hwndPage == 0)
1106 LPCPROPSHEETPAGEA ppshpage;
1108 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1109 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1112 if (psInfo->active_page != -1)
1113 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1115 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1117 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1119 HWND hwndTabCtrl;
1121 /* Synchronize current selection with tab control */
1122 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1123 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1126 psInfo->active_page = index;
1127 psInfo->activeValid = TRUE;
1129 return TRUE;
1132 /******************************************************************************
1133 * PROPSHEET_Back
1135 static BOOL PROPSHEET_Back(HWND hwndDlg)
1137 BOOL res;
1138 PSHNOTIFY psn;
1139 HWND hwndPage;
1140 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1141 PropSheetInfoStr);
1142 LRESULT result;
1144 if (psInfo->active_page < 0)
1145 return FALSE;
1147 psn.hdr.code = PSN_WIZBACK;
1148 psn.hdr.hwndFrom = hwndDlg;
1149 psn.hdr.idFrom = 0;
1150 psn.lParam = 0;
1152 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1154 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1155 if (result == -1)
1156 return FALSE;
1158 if (psInfo->active_page > 0)
1160 res = PROPSHEET_CanSetCurSel(hwndDlg);
1161 if(res != FALSE)
1163 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, -1, 0);
1167 return TRUE;
1170 /******************************************************************************
1171 * PROPSHEET_Next
1173 static BOOL PROPSHEET_Next(HWND hwndDlg)
1175 PSHNOTIFY psn;
1176 HWND hwndPage;
1177 LRESULT msgResult = 0;
1178 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1179 PropSheetInfoStr);
1181 if (psInfo->active_page < 0)
1182 return FALSE;
1184 psn.hdr.code = PSN_WIZNEXT;
1185 psn.hdr.hwndFrom = hwndDlg;
1186 psn.hdr.idFrom = 0;
1187 psn.lParam = 0;
1189 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1191 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1192 if (msgResult == -1)
1193 return FALSE;
1195 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1197 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 1, 0);
1200 return TRUE;
1203 /******************************************************************************
1204 * PROPSHEET_Finish
1206 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1208 PSHNOTIFY psn;
1209 HWND hwndPage;
1210 LRESULT msgResult = 0;
1211 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1212 PropSheetInfoStr);
1214 if (psInfo->active_page < 0)
1215 return FALSE;
1217 psn.hdr.code = PSN_WIZFINISH;
1218 psn.hdr.hwndFrom = hwndDlg;
1219 psn.hdr.idFrom = 0;
1220 psn.lParam = 0;
1222 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1224 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1226 TRACE("msg result %ld\n", msgResult);
1228 if (msgResult != 0)
1229 return FALSE;
1231 if (psInfo->isModeless)
1232 psInfo->activeValid = FALSE;
1233 else
1234 EndDialog(hwndDlg, TRUE);
1236 return TRUE;
1239 /******************************************************************************
1240 * PROPSHEET_Apply
1242 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1244 int i;
1245 HWND hwndPage;
1246 PSHNOTIFY psn;
1247 LRESULT msgResult;
1248 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1249 PropSheetInfoStr);
1251 if (psInfo->active_page < 0)
1252 return FALSE;
1254 psn.hdr.hwndFrom = hwndDlg;
1255 psn.hdr.idFrom = 0;
1256 psn.lParam = 0;
1260 * Send PSN_KILLACTIVE to the current page.
1262 psn.hdr.code = PSN_KILLACTIVE;
1264 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1266 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1267 return FALSE;
1270 * Send PSN_APPLY to all pages.
1272 psn.hdr.code = PSN_APPLY;
1273 psn.lParam = lParam;
1275 for (i = 0; i < psInfo->nPages; i++)
1277 hwndPage = psInfo->proppage[i].hwndPage;
1278 if (hwndPage)
1280 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1281 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1282 return FALSE;
1286 if(lParam)
1288 psInfo->activeValid = FALSE;
1290 else if(psInfo->active_page >= 0)
1292 psn.hdr.code = PSN_SETACTIVE;
1293 psn.lParam = 0;
1294 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1295 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1298 return TRUE;
1301 /******************************************************************************
1302 * PROPSHEET_Cancel
1304 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1306 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1307 PropSheetInfoStr);
1308 HWND hwndPage;
1309 PSHNOTIFY psn;
1310 int i;
1312 if (psInfo->active_page < 0)
1313 return;
1315 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1316 psn.hdr.code = PSN_QUERYCANCEL;
1317 psn.hdr.hwndFrom = hwndDlg;
1318 psn.hdr.idFrom = 0;
1319 psn.lParam = 0;
1321 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1322 return;
1324 psn.hdr.code = PSN_RESET;
1325 psn.lParam = lParam;
1327 for (i = 0; i < psInfo->nPages; i++)
1329 hwndPage = psInfo->proppage[i].hwndPage;
1331 if (hwndPage)
1332 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1335 if (psInfo->isModeless)
1337 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1338 psInfo->activeValid = FALSE;
1340 else
1341 EndDialog(hwndDlg, FALSE);
1344 /******************************************************************************
1345 * PROPSHEET_Help
1347 static void PROPSHEET_Help(HWND hwndDlg)
1349 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1350 PropSheetInfoStr);
1351 HWND hwndPage;
1352 PSHNOTIFY psn;
1354 if (psInfo->active_page < 0)
1355 return;
1357 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1358 psn.hdr.code = PSN_HELP;
1359 psn.hdr.hwndFrom = hwndDlg;
1360 psn.hdr.idFrom = 0;
1361 psn.lParam = 0;
1363 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1366 /******************************************************************************
1367 * PROPSHEET_Changed
1369 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1371 int i;
1372 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1373 PropSheetInfoStr);
1375 if (!psInfo) return;
1377 * Set the dirty flag of this page.
1379 for (i = 0; i < psInfo->nPages; i++)
1381 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1382 psInfo->proppage[i].isDirty = TRUE;
1386 * Enable the Apply button.
1388 if (psInfo->hasApply)
1390 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1392 EnableWindow(hwndApplyBtn, TRUE);
1396 /******************************************************************************
1397 * PROPSHEET_UnChanged
1399 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1401 int i;
1402 BOOL noPageDirty = TRUE;
1403 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1404 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1405 PropSheetInfoStr);
1407 if ( !psInfo ) return;
1408 for (i = 0; i < psInfo->nPages; i++)
1410 /* set the specified page as clean */
1411 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1412 psInfo->proppage[i].isDirty = FALSE;
1414 /* look to see if there's any dirty pages */
1415 if (psInfo->proppage[i].isDirty)
1416 noPageDirty = FALSE;
1420 * Disable Apply button.
1422 if (noPageDirty)
1423 EnableWindow(hwndApplyBtn, FALSE);
1426 /******************************************************************************
1427 * PROPSHEET_PressButton
1429 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1431 switch (buttonID)
1433 case PSBTN_APPLYNOW:
1434 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1435 break;
1436 case PSBTN_BACK:
1437 PROPSHEET_Back(hwndDlg);
1438 break;
1439 case PSBTN_CANCEL:
1440 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1441 break;
1442 case PSBTN_FINISH:
1443 PROPSHEET_Finish(hwndDlg);
1444 break;
1445 case PSBTN_HELP:
1446 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1447 break;
1448 case PSBTN_NEXT:
1449 PROPSHEET_Next(hwndDlg);
1450 break;
1451 case PSBTN_OK:
1452 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1453 break;
1454 default:
1455 FIXME("Invalid button index %d\n", buttonID);
1460 /*************************************************************************
1461 * BOOL PROPSHEET_CanSetCurSel [Internal]
1463 * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1465 * PARAMS
1466 * hwndDlg [I] handle to a Dialog hWnd
1468 * RETURNS
1469 * TRUE if Current Selection can change
1471 * NOTES
1473 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1475 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1476 PropSheetInfoStr);
1477 HWND hwndPage;
1478 PSHNOTIFY psn;
1480 if (!psInfo)
1481 return FALSE;
1483 if (psInfo->active_page < 0)
1484 return TRUE;
1487 * Notify the current page.
1489 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1490 psn.hdr.code = PSN_KILLACTIVE;
1491 psn.hdr.hwndFrom = hwndDlg;
1492 psn.hdr.idFrom = 0;
1493 psn.lParam = 0;
1495 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1498 /******************************************************************************
1499 * PROPSHEET_SetCurSel
1501 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1502 int index,
1503 int skipdir,
1504 HPROPSHEETPAGE hpage
1507 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1508 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1510 /* hpage takes precedence over index */
1511 if (hpage != NULL)
1512 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1514 if (index < 0 || index >= psInfo->nPages)
1516 TRACE("Could not find page to select!\n");
1517 return FALSE;
1520 while (1) {
1521 int result;
1522 PSHNOTIFY psn;
1524 psn.hdr.code = PSN_SETACTIVE;
1525 psn.hdr.hwndFrom = hwndDlg;
1526 psn.hdr.idFrom = 0;
1527 psn.lParam = 0;
1529 if (!psInfo->proppage[index].hwndPage) {
1530 LPCPROPSHEETPAGEA ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1531 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1534 result = SendMessageA(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1535 if (!result)
1536 break;
1537 if (result == -1) {
1538 index+=skipdir;
1539 if (index < 0) {
1540 index = 0;
1541 FIXME("Tried to skip before first property sheet page!\n");
1542 break;
1544 if (index >= psInfo->nPages) {
1545 FIXME("Tried to skip after last property sheet page!\n");
1546 index = psInfo->nPages-1;
1547 break;
1552 * Display the new page.
1554 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1556 if (psInfo->proppage[index].hasHelp)
1557 EnableWindow(hwndHelp, TRUE);
1558 else
1559 EnableWindow(hwndHelp, FALSE);
1561 return TRUE;
1564 /******************************************************************************
1565 * PROPSHEET_SetTitleA
1567 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1569 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1570 char szTitle[256];
1572 if (HIWORD(lpszText) == 0) {
1573 if (!LoadStringA(psInfo->ppshheader.hInstance,
1574 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1575 return;
1576 lpszText = szTitle;
1578 if (dwStyle & PSH_PROPTITLE)
1580 char* dest;
1581 int lentitle = strlen(lpszText);
1582 int lenprop = strlen(psInfo->strPropertiesFor);
1584 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1585 strcpy(dest, psInfo->strPropertiesFor);
1586 strcat(dest, lpszText);
1588 SetWindowTextA(hwndDlg, dest);
1589 COMCTL32_Free(dest);
1591 else
1592 SetWindowTextA(hwndDlg, lpszText);
1595 /******************************************************************************
1596 * PROPSHEET_SetFinishTextA
1598 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1600 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1602 /* Set text, show and enable the Finish button */
1603 SetWindowTextA(hwndButton, lpszText);
1604 ShowWindow(hwndButton, SW_SHOW);
1605 EnableWindow(hwndButton, TRUE);
1607 /* Make it default pushbutton */
1608 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1610 /* Hide Back button */
1611 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1612 ShowWindow(hwndButton, SW_HIDE);
1614 /* Hide Next button */
1615 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1616 ShowWindow(hwndButton, SW_HIDE);
1619 /******************************************************************************
1620 * PROPSHEET_QuerySiblings
1622 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1623 WPARAM wParam, LPARAM lParam)
1625 int i = 0;
1626 HWND hwndPage;
1627 LRESULT msgResult = 0;
1628 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1629 PropSheetInfoStr);
1631 while ((i < psInfo->nPages) && (msgResult == 0))
1633 hwndPage = psInfo->proppage[i].hwndPage;
1634 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1635 i++;
1638 return msgResult;
1642 /******************************************************************************
1643 * PROPSHEET_AddPage
1645 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1646 HPROPSHEETPAGE hpage)
1648 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1649 PropSheetInfoStr);
1650 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1651 TCITEMA item;
1652 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1653 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1656 * Allocate and fill in a new PropPageInfo entry.
1658 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1659 sizeof(PropPageInfo) *
1660 (psInfo->nPages + 1));
1661 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1662 return FALSE;
1664 psInfo->proppage[psInfo->nPages].hpage = hpage;
1666 if (ppsp->dwFlags & PSP_PREMATURE)
1668 /* Create the page but don't show it */
1669 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1673 * Add a new tab to the tab control.
1675 item.mask = TCIF_TEXT;
1676 item.pszText = tabtext;
1677 item.cchTextMax = MAX_TABTEXT_LENGTH;
1679 WideCharToMultiByte(CP_ACP, 0,
1680 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1681 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1683 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1684 (LPARAM)&item);
1686 psInfo->nPages++;
1688 /* If it is the only page - show it */
1689 if(psInfo->nPages == 1)
1690 PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
1691 return TRUE;
1694 /******************************************************************************
1695 * PROPSHEET_RemovePage
1697 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1698 int index,
1699 HPROPSHEETPAGE hpage)
1701 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1702 PropSheetInfoStr);
1703 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1704 PropPageInfo* oldPages;
1706 if (!psInfo) {
1707 return FALSE;
1709 oldPages = psInfo->proppage;
1711 * hpage takes precedence over index.
1713 if (hpage != 0)
1715 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1718 /* Make sure that index is within range */
1719 if (index < 0 || index >= psInfo->nPages)
1721 TRACE("Could not find page to remove!\n");
1722 return FALSE;
1725 TRACE("total pages %d removing page %d active page %d\n",
1726 psInfo->nPages, index, psInfo->active_page);
1728 * Check if we're removing the active page.
1730 if (index == psInfo->active_page)
1732 if (psInfo->nPages > 1)
1734 if (index > 0)
1736 /* activate previous page */
1737 PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
1739 else
1741 /* activate the next page */
1742 PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
1743 psInfo->active_page = index;
1746 else
1748 psInfo->active_page = -1;
1749 if (!psInfo->isModeless)
1751 EndDialog(hwndDlg, FALSE);
1752 return TRUE;
1756 else if (index < psInfo->active_page)
1757 psInfo->active_page--;
1759 /* Destroy page dialog window */
1760 DestroyWindow(psInfo->proppage[index].hwndPage);
1762 /* Free page resources */
1763 if(psInfo->proppage[index].hpage)
1765 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1767 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1768 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1770 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1773 /* Remove the tab */
1774 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1776 psInfo->nPages--;
1777 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1779 if (index > 0)
1780 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1782 if (index < psInfo->nPages)
1783 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1784 (psInfo->nPages - index) * sizeof(PropPageInfo));
1786 COMCTL32_Free(oldPages);
1788 return FALSE;
1791 /******************************************************************************
1792 * PROPSHEET_SetWizButtons
1794 * This code will work if (and assumes that) the Next button is on top of the
1795 * Finish button. ie. Finish comes after Next in the Z order.
1796 * This means make sure the dialog template reflects this.
1799 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1801 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1802 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1803 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1805 TRACE("%ld\n", dwFlags);
1807 EnableWindow(hwndBack, FALSE);
1808 EnableWindow(hwndNext, FALSE);
1809 EnableWindow(hwndFinish, FALSE);
1811 if (dwFlags & PSWIZB_BACK)
1812 EnableWindow(hwndBack, TRUE);
1814 if (dwFlags & PSWIZB_NEXT)
1816 /* Hide the Finish button */
1817 ShowWindow(hwndFinish, SW_HIDE);
1819 /* Show and enable the Next button */
1820 ShowWindow(hwndNext, SW_SHOW);
1821 EnableWindow(hwndNext, TRUE);
1823 /* Set the Next button as the default pushbutton */
1824 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1827 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1829 /* Hide the Next button */
1830 ShowWindow(hwndNext, SW_HIDE);
1832 /* Show the Finish button */
1833 ShowWindow(hwndFinish, SW_SHOW);
1835 if (dwFlags & PSWIZB_FINISH)
1836 EnableWindow(hwndFinish, TRUE);
1838 /* Set the Finish button as the default pushbutton */
1839 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1843 /******************************************************************************
1844 * PROPSHEET_GetPageIndex
1846 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1847 * the array of PropPageInfo.
1849 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1851 BOOL found = FALSE;
1852 int index = 0;
1854 while ((index < psInfo->nPages) && (found == FALSE))
1856 if (psInfo->proppage[index].hpage == hpage)
1857 found = TRUE;
1858 else
1859 index++;
1862 if (found == FALSE)
1863 index = -1;
1865 return index;
1868 /******************************************************************************
1869 * PROPSHEET_CleanUp
1871 static void PROPSHEET_CleanUp(HWND hwndDlg)
1873 int i;
1874 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1875 PropSheetInfoStr);
1877 TRACE("\n");
1878 if (HIWORD(psInfo->ppshheader.pszCaption))
1879 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
1881 for (i = 0; i < psInfo->nPages; i++)
1883 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1885 if(psInfo->proppage[i].hwndPage)
1886 DestroyWindow(psInfo->proppage[i].hwndPage);
1888 if(psp)
1890 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1891 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1893 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1897 COMCTL32_Free(psInfo->proppage);
1898 COMCTL32_Free(psInfo->strPropertiesFor);
1899 ImageList_Destroy(psInfo->hImageList);
1901 GlobalFree((HGLOBAL)psInfo);
1904 /******************************************************************************
1905 * PropertySheet (COMCTL32.87)
1906 * PropertySheetA (COMCTL32.88)
1908 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1910 int bRet = 0;
1911 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1912 sizeof(PropSheetInfo));
1913 int i, n;
1914 BYTE* pByte;
1916 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1918 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1919 lppsh->nPages);
1920 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
1922 for (n = i = 0; i < lppsh->nPages; i++, n++)
1924 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1925 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
1926 else
1928 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1929 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1932 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1933 psInfo, n))
1935 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1936 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1937 n--;
1938 psInfo->nPages--;
1942 bRet = PROPSHEET_CreateDialog(psInfo);
1944 return bRet;
1947 /******************************************************************************
1948 * PropertySheetW (COMCTL32.89)
1950 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1952 FIXME("(%p): stub\n", propertySheetHeader);
1954 return -1;
1957 /******************************************************************************
1958 * CreatePropertySheetPage (COMCTL32.18)
1959 * CreatePropertySheetPageA (COMCTL32.19)
1961 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1962 LPCPROPSHEETPAGEA lpPropSheetPage)
1964 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1966 memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
1968 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
1970 ppsp->u.pszTemplate = HeapAlloc( GetProcessHeap(),0,strlen(lpPropSheetPage->u.pszTemplate)+1 );
1971 strcpy( (char *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate );
1973 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1975 ppsp->u2.pszIcon = HeapAlloc( GetProcessHeap(), 0, strlen(lpPropSheetPage->u2.pszIcon)+1 );
1976 strcpy( (char *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon );
1979 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1981 ppsp->pszTitle = HeapAlloc( GetProcessHeap(), 0, strlen(lpPropSheetPage->pszTitle)+1 );
1982 strcpy( (char *)ppsp->pszTitle, lpPropSheetPage->pszTitle );
1984 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1985 ppsp->pszTitle = NULL;
1987 return (HPROPSHEETPAGE)ppsp;
1990 /******************************************************************************
1991 * CreatePropertySheetPageW (COMCTL32.20)
1993 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1995 FIXME("(%p): stub\n", lpPropSheetPage);
1997 return 0;
2000 /******************************************************************************
2001 * DestroyPropertySheetPage (COMCTL32.24)
2003 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
2005 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
2007 if (!psp)
2008 return FALSE;
2010 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
2011 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
2013 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2014 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2016 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2017 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2019 COMCTL32_Free(hPropPage);
2021 return TRUE;
2024 /******************************************************************************
2025 * PROPSHEET_IsDialogMessage
2027 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2029 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2031 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2032 return FALSE;
2034 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2036 int new_page = 0;
2037 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2039 if (!(dlgCode & DLGC_WANTMESSAGE))
2041 switch (lpMsg->wParam)
2043 case VK_TAB:
2044 if (GetKeyState(VK_SHIFT) & 0x8000)
2045 new_page = -1;
2046 else
2047 new_page = 1;
2048 break;
2050 case VK_NEXT: new_page = 1; break;
2051 case VK_PRIOR: new_page = -1; break;
2055 if (new_page)
2057 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2059 new_page += psInfo->active_page;
2061 if (new_page < 0)
2062 new_page = psInfo->nPages - 1;
2063 else if (new_page >= psInfo->nPages)
2064 new_page = 0;
2066 PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
2069 return TRUE;
2073 return IsDialogMessageA(hwnd, lpMsg);
2076 /******************************************************************************
2077 * PROPSHEET_DialogProc
2079 BOOL WINAPI
2080 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2082 switch (uMsg)
2084 case WM_INITDIALOG:
2086 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2087 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2088 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2089 LPCPROPSHEETPAGEA ppshpage;
2090 int idx;
2092 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2095 * psInfo->hwnd is not being used by WINE code - it exists
2096 * for compatibility with "real" Windoze. The same about
2097 * SetWindowLong - WINE is only using the PropSheetInfoStr
2098 * property.
2100 psInfo->hwnd = hwnd;
2101 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2104 * Small icon in the title bar.
2106 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2107 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2109 HICON hIcon;
2110 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2111 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2113 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2114 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2115 psInfo->ppshheader.u.pszIcon,
2116 IMAGE_ICON,
2117 icon_cx, icon_cy,
2118 LR_DEFAULTCOLOR);
2119 else
2120 hIcon = psInfo->ppshheader.u.hIcon;
2122 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2125 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2126 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u.hIcon);
2128 psInfo->strPropertiesFor = strCaption;
2130 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2132 PROPSHEET_CreateTabControl(hwnd, psInfo);
2134 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2136 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2138 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2139 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2142 else
2144 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2146 PROPSHEET_AdjustSize(hwnd, psInfo);
2147 PROPSHEET_AdjustButtons(hwnd, psInfo);
2151 if (psInfo->useCallback)
2152 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2153 PSCB_INITIALIZED, (LPARAM)0);
2155 idx = psInfo->active_page;
2156 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2157 psInfo->active_page = -1;
2159 PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
2161 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2162 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2164 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2165 psInfo->ppshheader.hInstance)
2167 char szText[256];
2169 if (LoadStringA(psInfo->ppshheader.hInstance,
2170 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2171 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2173 else
2175 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2176 psInfo->ppshheader.pszCaption);
2179 return TRUE;
2182 case WM_DESTROY:
2183 PROPSHEET_CleanUp(hwnd);
2184 return TRUE;
2186 case WM_CLOSE:
2187 PROPSHEET_Cancel(hwnd, 1);
2188 return TRUE;
2190 case WM_COMMAND:
2192 WORD wID = LOWORD(wParam);
2194 switch (wID)
2196 case IDOK:
2197 case IDC_APPLY_BUTTON:
2199 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2201 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2202 break;
2204 if (wID == IDOK)
2206 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2207 PropSheetInfoStr);
2208 int result = TRUE;
2210 if (psInfo->restartWindows)
2211 result = ID_PSRESTARTWINDOWS;
2213 /* reboot system takes precedence over restart windows */
2214 if (psInfo->rebootSystem)
2215 result = ID_PSREBOOTSYSTEM;
2217 if (psInfo->isModeless)
2218 psInfo->activeValid = FALSE;
2219 else
2220 EndDialog(hwnd, result);
2222 else
2223 EnableWindow(hwndApplyBtn, FALSE);
2225 break;
2228 case IDC_BACK_BUTTON:
2229 PROPSHEET_Back(hwnd);
2230 break;
2232 case IDC_NEXT_BUTTON:
2233 PROPSHEET_Next(hwnd);
2234 break;
2236 case IDC_FINISH_BUTTON:
2237 PROPSHEET_Finish(hwnd);
2238 break;
2240 case IDCANCEL:
2241 PROPSHEET_Cancel(hwnd, 0);
2242 break;
2244 case IDHELP:
2245 PROPSHEET_Help(hwnd);
2246 break;
2249 return TRUE;
2252 case WM_NOTIFY:
2254 NMHDR* pnmh = (LPNMHDR) lParam;
2256 if (pnmh->code == TCN_SELCHANGE)
2258 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2259 PROPSHEET_SetCurSel(hwnd, index, 1, 0);
2262 if(pnmh->code == TCN_SELCHANGING)
2264 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2265 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2266 return TRUE;
2269 return FALSE;
2272 case PSM_GETCURRENTPAGEHWND:
2274 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2275 PropSheetInfoStr);
2276 HWND hwndPage = 0;
2278 if (psInfo->activeValid && psInfo->active_page != -1)
2279 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2281 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2283 return TRUE;
2286 case PSM_CHANGED:
2287 PROPSHEET_Changed(hwnd, (HWND)wParam);
2288 return TRUE;
2290 case PSM_UNCHANGED:
2291 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2292 return TRUE;
2294 case PSM_GETTABCONTROL:
2296 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2298 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2300 return TRUE;
2303 case PSM_SETCURSEL:
2305 BOOL msgResult;
2307 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2308 if(msgResult != FALSE)
2310 msgResult = PROPSHEET_SetCurSel(hwnd,
2311 (int)wParam,
2313 (HPROPSHEETPAGE)lParam);
2316 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2318 return TRUE;
2321 case PSM_CANCELTOCLOSE:
2323 char buf[MAX_BUTTONTEXT_LENGTH];
2324 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2325 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2327 EnableWindow(hwndCancel, FALSE);
2328 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2329 SetWindowTextA(hwndOK, buf);
2331 return FALSE;
2334 case PSM_RESTARTWINDOWS:
2336 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2337 PropSheetInfoStr);
2339 psInfo->restartWindows = TRUE;
2340 return TRUE;
2343 case PSM_REBOOTSYSTEM:
2345 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2346 PropSheetInfoStr);
2348 psInfo->rebootSystem = TRUE;
2349 return TRUE;
2352 case PSM_SETTITLEA:
2353 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2354 return TRUE;
2356 case PSM_APPLY:
2358 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2360 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2362 return TRUE;
2365 case PSM_QUERYSIBLINGS:
2367 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2369 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2371 return TRUE;
2374 case PSM_ADDPAGE:
2377 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2378 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2379 * on success or FALSE otherwise, as specified on MSDN Online.
2380 * Also see the MFC code for
2381 * CPropertySheet::AddPage(CPropertyPage* pPage).
2384 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2386 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2388 return TRUE;
2391 case PSM_REMOVEPAGE:
2392 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2393 return TRUE;
2395 case PSM_ISDIALOGMESSAGE:
2397 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2398 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2399 return TRUE;
2402 case PSM_PRESSBUTTON:
2403 PROPSHEET_PressButton(hwnd, (int)wParam);
2404 return TRUE;
2406 case PSM_SETFINISHTEXTA:
2407 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2408 return TRUE;
2410 case PSM_SETWIZBUTTONS:
2411 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2412 return TRUE;
2414 case PSM_SETTITLEW:
2415 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2416 return FALSE;
2418 case PSM_SETCURSELID:
2419 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2420 return FALSE;
2422 case PSM_SETFINISHTEXTW:
2423 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2424 return FALSE;
2426 default:
2427 return FALSE;
2430 return FALSE;