Disable the owner of a modal dialog box just before creating the
[wine.git] / dlls / comctl32 / propsheet.c
blobdd641fef5523066f06dc96311f2f4ecde3c27aa5
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 "dialog.h"
17 #include "win.h"
18 #include "winnls.h"
19 #include "comctl32.h"
20 #include "debugtools.h"
21 #include "heap.h"
24 /******************************************************************************
25 * Data structures
27 typedef struct
29 WORD dlgVer;
30 WORD signature;
31 DWORD helpID;
32 DWORD exStyle;
33 DWORD style;
34 } MyDLGTEMPLATEEX;
36 typedef struct tagPropPageInfo
38 HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
39 HWND hwndPage;
40 BOOL isDirty;
41 LPCWSTR pszText;
42 BOOL hasHelp;
43 BOOL useCallback;
44 BOOL hasIcon;
45 } PropPageInfo;
47 typedef struct tagPropSheetInfo
49 HWND hwnd;
50 PROPSHEETHEADERA ppshheader;
51 LPSTR strPropertiesFor;
52 int nPages;
53 int active_page;
54 BOOL isModeless;
55 BOOL hasHelp;
56 BOOL hasApply;
57 BOOL useCallback;
58 BOOL restartWindows;
59 BOOL rebootSystem;
60 BOOL activeValid;
61 PropPageInfo* proppage;
62 int x;
63 int y;
64 int width;
65 int height;
66 HIMAGELIST hImageList;
67 } PropSheetInfo;
69 typedef struct
71 int x;
72 int y;
73 } PADDING_INFO;
75 /******************************************************************************
76 * Defines and global variables
79 const char * PropSheetInfoStr = "PropertySheetInfo";
81 #define MAX_CAPTION_LENGTH 255
82 #define MAX_TABTEXT_LENGTH 255
83 #define MAX_BUTTONTEXT_LENGTH 64
85 /******************************************************************************
86 * Prototypes
88 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
89 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo);
90 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
91 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
92 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
93 PropSheetInfo * psInfo);
94 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
95 PropSheetInfo * psInfo,
96 int index);
97 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
98 PropSheetInfo * psInfo);
99 static int PROPSHEET_CreatePage(HWND hwndParent, int index,
100 const PropSheetInfo * psInfo,
101 LPCPROPSHEETPAGEA ppshpage);
102 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
103 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
104 static BOOL PROPSHEET_Back(HWND hwndDlg);
105 static BOOL PROPSHEET_Next(HWND hwndDlg);
106 static BOOL PROPSHEET_Finish(HWND hwndDlg);
107 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam);
108 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam);
109 static void PROPSHEET_Help(HWND hwndDlg);
110 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
111 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
112 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
113 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
114 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
115 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
116 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
117 int index,
118 HPROPSHEETPAGE hpage);
119 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
120 WPARAM wParam, LPARAM lParam);
121 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
122 HPROPSHEETPAGE hpage);
124 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
125 int index,
126 HPROPSHEETPAGE hpage);
127 static void PROPSHEET_CleanUp();
128 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
129 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
130 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg);
131 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg);
132 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner);
134 BOOL WINAPI
135 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
137 DEFAULT_DEBUG_CHANNEL(propsheet)
139 /******************************************************************************
140 * PROPSHEET_CollectSheetInfo
142 * Collect relevant data.
144 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
145 PropSheetInfo * psInfo)
147 DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
148 DWORD dwFlags = lppsh->dwFlags;
150 psInfo->hasHelp = dwFlags & PSH_HASHELP;
151 psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
152 psInfo->useCallback = dwFlags & PSH_USECALLBACK;
153 psInfo->isModeless = dwFlags & PSH_MODELESS;
155 memcpy(&psInfo->ppshheader,lppsh,dwSize);
157 if (HIWORD(lppsh->pszCaption))
158 psInfo->ppshheader.pszCaption = HEAP_strdupA( GetProcessHeap(),
159 0, lppsh->pszCaption );
161 psInfo->nPages = lppsh->nPages;
163 if (dwFlags & PSH_USEPSTARTPAGE)
165 TRACE("PSH_USEPSTARTPAGE is on");
166 psInfo->active_page = 0;
168 else
169 psInfo->active_page = lppsh->u2.nStartPage;
171 if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
172 psInfo->active_page = 0;
174 psInfo->restartWindows = FALSE;
175 psInfo->rebootSystem = FALSE;
176 psInfo->hImageList = 0;
177 psInfo->activeValid = FALSE;
179 return TRUE;
182 /******************************************************************************
183 * PROPSHEET_CollectPageInfo
185 * Collect property sheet data.
186 * With code taken from DIALOG_ParseTemplate32.
188 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
189 PropSheetInfo * psInfo,
190 int index)
192 DLGTEMPLATE* pTemplate;
193 const WORD* p;
194 DWORD dwFlags;
195 int width, height;
197 psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
198 psInfo->proppage[index].hwndPage = 0;
199 psInfo->proppage[index].isDirty = FALSE;
202 * Process property page flags.
204 dwFlags = lppsp->dwFlags;
205 psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
206 psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
207 psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
209 /* as soon as we have a page with the help flag, set the sheet flag on */
210 if (psInfo->proppage[index].hasHelp)
211 psInfo->hasHelp = TRUE;
214 * Process page template.
216 if (dwFlags & PSP_DLGINDIRECT)
217 pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
218 else
220 HRSRC hResource = FindResourceA(lppsp->hInstance,
221 lppsp->u1.pszTemplate,
222 RT_DIALOGA);
223 HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
224 hResource);
225 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
229 * Extract the size of the page and the caption.
231 if (!pTemplate)
232 return FALSE;
234 p = (const WORD *)pTemplate;
236 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
238 /* DIALOGEX template */
240 p++; /* dlgVer */
241 p++; /* signature */
242 p += 2; /* help ID */
243 p += 2; /* ext style */
244 p += 2; /* style */
246 else
248 /* DIALOG template */
250 p += 2; /* style */
251 p += 2; /* ext style */
254 p++; /* nb items */
255 p++; /* x */
256 p++; /* y */
257 width = (WORD)*p; p++;
258 height = (WORD)*p; p++;
260 /* remember the largest width and height */
261 if (width > psInfo->width)
262 psInfo->width = width;
264 if (height > psInfo->height)
265 psInfo->height = height;
267 /* menu */
268 switch ((WORD)*p)
270 case 0x0000:
271 p++;
272 break;
273 case 0xffff:
274 p += 2;
275 break;
276 default:
277 p += lstrlenW( (LPCWSTR)p ) + 1;
278 break;
281 /* class */
282 switch ((WORD)*p)
284 case 0x0000:
285 p++;
286 break;
287 case 0xffff:
288 p += 2;
289 break;
290 default:
291 p += lstrlenW( (LPCWSTR)p ) + 1;
292 break;
295 /* Extract the caption */
296 psInfo->proppage[index].pszText = (LPCWSTR)p;
297 TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
298 p += lstrlenW((LPCWSTR)p) + 1;
300 if (dwFlags & PSP_USETITLE)
302 if ( !HIWORD( lppsp->pszTitle ) )
304 char szTitle[256];
306 if ( !LoadStringA( lppsp->hInstance, (UINT) lppsp->pszTitle, szTitle, 256 ) )
307 return FALSE;
309 psInfo->proppage[index].pszText = HEAP_strdupAtoW( GetProcessHeap(),
310 0, szTitle );
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;
346 /******************************************************************************
347 * PROPSHEET_DoDialogBox
349 * Copied from windows/dialog.c:DIALOG_DoDialogBox
351 static INT PROPSHEET_DoDialogBox( HWND hwnd, HWND owner)
353 WND * wndPtr;
354 DIALOGINFO * dlgInfo;
355 MSG msg;
356 INT retval;
358 /* Owner must be a top-level window */
359 owner = WIN_GetTopParent( owner );
360 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return -1;
361 dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
363 if (!(dlgInfo->flags & DF_END)) /* was EndDialog called in WM_INITDIALOG ? */
365 EnableWindow( owner, FALSE );
366 ShowWindow( hwnd, SW_SHOW );
367 while (GetMessageA(&msg, 0, 0, 0))
369 if (!PROPSHEET_IsDialogMessage( hwnd, &msg))
371 TranslateMessage( &msg );
372 DispatchMessageA( &msg );
374 if (dlgInfo->flags & DF_END) break;
376 EnableWindow( owner, TRUE );
378 retval = dlgInfo->idResult;
379 WIN_ReleaseWndPtr(wndPtr);
380 DestroyWindow( hwnd );
381 return retval;
385 /******************************************************************************
386 * PROPSHEET_CreateDialog
388 * Creates the actual property sheet.
390 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
392 LRESULT ret;
393 LPCVOID template;
394 LPVOID temp = 0;
395 HRSRC hRes;
396 DWORD resSize;
397 WORD resID = IDD_PROPSHEET;
399 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
400 resID = IDD_WIZARD;
402 if(!(hRes = FindResourceA(COMCTL32_hModule,
403 MAKEINTRESOURCEA(resID),
404 RT_DIALOGA)))
405 return FALSE;
407 if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
408 return FALSE;
411 * Make a copy of the dialog template.
413 resSize = SizeofResource(COMCTL32_hModule, hRes);
415 temp = COMCTL32_Alloc(resSize);
417 if (!temp)
418 return FALSE;
420 memcpy(temp, template, resSize);
422 if (psInfo->useCallback)
423 (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
425 ret = CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
426 (LPDLGTEMPLATEA) temp,
427 psInfo->ppshheader.hwndParent,
428 (DLGPROC) PROPSHEET_DialogProc,
429 (LPARAM)psInfo);
431 if (!(psInfo->ppshheader.dwFlags & PSH_MODELESS))
432 ret = PROPSHEET_DoDialogBox((HWND)ret, psInfo->ppshheader.hwndParent);
434 COMCTL32_Free(temp);
436 return ret;
439 /******************************************************************************
440 * PROPSHEET_SizeMismatch
442 * Verify that the tab control and the "largest" property sheet page dlg. template
443 * match in size.
445 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
447 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
448 RECT rcOrigTab, rcPage;
451 * Original tab size.
453 GetClientRect(hwndTabCtrl, &rcOrigTab);
454 TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
455 rcOrigTab.right, rcOrigTab.bottom);
458 * Biggest page size.
460 rcPage.left = psInfo->x;
461 rcPage.top = psInfo->y;
462 rcPage.right = psInfo->width;
463 rcPage.bottom = psInfo->height;
465 MapDialogRect(hwndDlg, &rcPage);
466 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
467 rcPage.right, rcPage.bottom);
469 if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
470 return TRUE;
471 if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
472 return TRUE;
474 return FALSE;
477 /******************************************************************************
478 * PROPSHEET_IsTooSmallWizard
480 * Verify that the default property sheet is big enough.
482 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
484 RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
485 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
486 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
488 GetClientRect(hwndDlg, &rcSheetClient);
489 GetWindowRect(hwndDlg, &rcSheetRect);
490 GetWindowRect(hwndLine, &rcLine);
492 /* Remove the space below the sunken line */
493 rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
495 /* Remove the buffer zone all around the edge */
496 rcSheetClient.bottom -= (padding.y * 2);
497 rcSheetClient.right -= (padding.x * 2);
500 * Biggest page size.
502 rcPage.left = psInfo->x;
503 rcPage.top = psInfo->y;
504 rcPage.right = psInfo->width;
505 rcPage.bottom = psInfo->height;
507 MapDialogRect(hwndDlg, &rcPage);
508 TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
509 rcPage.right, rcPage.bottom);
511 if (rcPage.right > rcSheetClient.right)
512 return TRUE;
514 if (rcPage.bottom > rcSheetClient.bottom)
515 return TRUE;
517 return FALSE;
520 /******************************************************************************
521 * PROPSHEET_AdjustSize
523 * Resizes the property sheet and the tab control to fit the largest page.
525 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
527 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
528 HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
529 RECT rc,tabRect;
530 int tabOffsetX, tabOffsetY, buttonHeight;
531 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
532 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
533 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
535 /* Get the height of buttons */
536 GetClientRect(hwndButton, &rc);
537 buttonHeight = rc.bottom;
540 * Biggest page size.
542 rc.left = psInfo->x;
543 rc.top = psInfo->y;
544 rc.right = psInfo->width;
545 rc.bottom = psInfo->height;
547 MapDialogRect(hwndDlg, &rc);
550 * Resize the tab control.
552 GetClientRect(hwndTabCtrl,&tabRect);
554 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
556 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
558 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
559 psInfo->height = MulDiv((rc.bottom - rc.top),8,dlgInfo->yBaseUnit);
562 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
564 rc.right = rc.left + tabRect.right - tabRect.left;
565 psInfo->width = MulDiv((rc.right - rc.left),4,dlgInfo->xBaseUnit);
568 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
570 tabOffsetX = -(rc.left);
571 tabOffsetY = -(rc.top);
573 rc.right -= rc.left;
574 rc.bottom -= rc.top;
575 SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
576 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
578 GetClientRect(hwndTabCtrl, &rc);
580 TRACE("tab client rc %d %d %d %d\n",
581 rc.left, rc.top, rc.right, rc.bottom);
583 rc.right += ((padding.x * 2) + tabOffsetX);
584 rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
587 * Resize the property sheet.
589 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
590 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
592 WIN_ReleaseWndPtr(wndPtr);
593 return TRUE;
596 /******************************************************************************
597 * PROPSHEET_AdjustSizeWizard
599 * Resizes the property sheet to fit the largest page.
601 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
603 HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
604 HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
605 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
606 RECT rc,tabRect;
607 int buttonHeight, lineHeight;
608 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
609 WND * wndPtr = WIN_FindWndPtr( hwndDlg );
610 DIALOGINFO * dlgInfo = (DIALOGINFO *)wndPtr->wExtra;
612 /* Get the height of buttons */
613 GetClientRect(hwndButton, &rc);
614 buttonHeight = rc.bottom;
616 GetClientRect(hwndLine, &rc);
617 lineHeight = rc.bottom;
620 * Biggest page size.
622 rc.left = psInfo->x;
623 rc.top = psInfo->y;
624 rc.right = psInfo->width;
625 rc.bottom = psInfo->height;
627 MapDialogRect(hwndDlg, &rc);
629 GetClientRect(hwndTabCtrl,&tabRect);
631 if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
633 rc.bottom = rc.top + tabRect.bottom - tabRect.top;
634 psInfo->height = MulDiv((rc.bottom - rc.top), 8, dlgInfo->yBaseUnit);
637 if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
639 rc.right = rc.left + tabRect.right - tabRect.left;
640 psInfo->width = MulDiv((rc.right - rc.left), 4, dlgInfo->xBaseUnit);
643 TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
645 /* Make room */
646 rc.right += (padding.x * 2);
647 rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
650 * Resize the property sheet.
652 SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
653 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
655 WIN_ReleaseWndPtr(wndPtr);
656 return TRUE;
659 /******************************************************************************
660 * PROPSHEET_AdjustButtons
662 * Adjusts the buttons' positions.
664 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
666 HWND hwndButton = GetDlgItem(hwndParent, IDOK);
667 RECT rcSheet;
668 int x, y;
669 int num_buttons = 2;
670 int buttonWidth, buttonHeight;
671 PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
673 if (psInfo->hasApply)
674 num_buttons++;
676 if (psInfo->hasHelp)
677 num_buttons++;
680 * Obtain the size of the buttons.
682 GetClientRect(hwndButton, &rcSheet);
683 buttonWidth = rcSheet.right;
684 buttonHeight = rcSheet.bottom;
687 * Get the size of the property sheet.
689 GetClientRect(hwndParent, &rcSheet);
692 * All buttons will be at this y coordinate.
694 y = rcSheet.bottom - (padding.y + buttonHeight);
697 * Position OK button.
699 hwndButton = GetDlgItem(hwndParent, IDOK);
701 x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
703 SetWindowPos(hwndButton, 0, x, y, 0, 0,
704 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
707 * Position Cancel button.
709 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
711 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
713 SetWindowPos(hwndButton, 0, x, y, 0, 0,
714 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
717 * Position Apply button.
719 hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
721 if (psInfo->hasApply)
723 if (psInfo->hasHelp)
724 x = rcSheet.right - ((padding.x + buttonWidth) * 2);
725 else
726 x = rcSheet.right - (padding.x + buttonWidth);
728 SetWindowPos(hwndButton, 0, x, y, 0, 0,
729 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
731 EnableWindow(hwndButton, FALSE);
733 else
734 ShowWindow(hwndButton, SW_HIDE);
737 * Position Help button.
739 hwndButton = GetDlgItem(hwndParent, IDHELP);
741 if (psInfo->hasHelp)
743 x = rcSheet.right - (padding.x + buttonWidth);
745 SetWindowPos(hwndButton, 0, x, y, 0, 0,
746 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
748 else
749 ShowWindow(hwndButton, SW_HIDE);
751 return TRUE;
754 /******************************************************************************
755 * PROPSHEET_AdjustButtonsWizard
757 * Adjusts the buttons' positions.
759 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
760 PropSheetInfo* psInfo)
762 HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
763 HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
764 RECT rcSheet;
765 int x, y;
766 int num_buttons = 3;
767 int buttonWidth, buttonHeight, lineHeight, lineWidth;
768 PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
770 if (psInfo->hasHelp)
771 num_buttons++;
774 * Obtain the size of the buttons.
776 GetClientRect(hwndButton, &rcSheet);
777 buttonWidth = rcSheet.right;
778 buttonHeight = rcSheet.bottom;
780 GetClientRect(hwndLine, &rcSheet);
781 lineHeight = rcSheet.bottom;
784 * Get the size of the property sheet.
786 GetClientRect(hwndParent, &rcSheet);
789 * All buttons will be at this y coordinate.
791 y = rcSheet.bottom - (padding.y + buttonHeight);
794 * Position the Next and the Finish buttons.
796 hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
798 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
800 SetWindowPos(hwndButton, 0, x, y, 0, 0,
801 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
803 hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
805 SetWindowPos(hwndButton, 0, x, y, 0, 0,
806 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
808 ShowWindow(hwndButton, SW_HIDE);
811 * Position the Back button.
813 hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
815 x -= buttonWidth;
817 SetWindowPos(hwndButton, 0, x, y, 0, 0,
818 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
821 * Position the Cancel button.
823 hwndButton = GetDlgItem(hwndParent, IDCANCEL);
825 x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
827 SetWindowPos(hwndButton, 0, x, y, 0, 0,
828 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
831 * Position Help button.
833 hwndButton = GetDlgItem(hwndParent, IDHELP);
835 if (psInfo->hasHelp)
837 x = rcSheet.right - (padding.x + buttonWidth);
839 SetWindowPos(hwndButton, 0, x, y, 0, 0,
840 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
842 else
843 ShowWindow(hwndButton, SW_HIDE);
846 * Position and resize the sunken line.
848 x = padding.x;
849 y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
851 GetClientRect(hwndParent, &rcSheet);
852 lineWidth = rcSheet.right - (padding.x * 2);
854 SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
855 SWP_NOZORDER | SWP_NOACTIVATE);
857 return TRUE;
860 /******************************************************************************
861 * PROPSHEET_GetPaddingInfo
863 * Returns the layout information.
865 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
867 HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
868 RECT rcTab;
869 POINT tl;
870 PADDING_INFO padding;
872 GetWindowRect(hwndTab, &rcTab);
874 tl.x = rcTab.left;
875 tl.y = rcTab.top;
877 ScreenToClient(hwndDlg, &tl);
879 padding.x = tl.x;
880 padding.y = tl.y;
882 return padding;
885 /******************************************************************************
886 * PROPSHEET_GetPaddingInfoWizard
888 * Returns the layout information.
889 * Horizontal spacing is the distance between the Cancel and Help buttons.
890 * Vertical spacing is the distance between the line and the buttons.
892 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
894 PADDING_INFO padding;
895 RECT rc;
896 HWND hwndControl;
897 POINT ptHelp, ptCancel, ptLine;
899 /* Help button */
900 hwndControl = GetDlgItem(hwndDlg, IDHELP);
901 GetWindowRect(hwndControl, &rc);
903 ptHelp.x = rc.left;
904 ptHelp.y = rc.top;
906 ScreenToClient(hwndDlg, &ptHelp);
908 /* Cancel button */
909 hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
910 GetWindowRect(hwndControl, &rc);
912 ptCancel.x = rc.right;
913 ptCancel.y = rc.top;
915 ScreenToClient(hwndDlg, &ptCancel);
917 /* Line */
918 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
919 GetWindowRect(hwndControl, &rc);
921 ptLine.x = 0;
922 ptLine.y = rc.bottom;
924 ScreenToClient(hwndDlg, &ptLine);
926 padding.x = ptHelp.x - ptCancel.x;
927 padding.y = ptHelp.y - ptLine.y;
929 return padding;
932 /******************************************************************************
933 * PROPSHEET_CreateTabControl
935 * Insert the tabs in the tab control.
937 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
938 PropSheetInfo * psInfo)
940 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
941 TCITEMA item;
942 int i, nTabs;
943 int iImage = 0;
944 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
946 item.mask = TCIF_TEXT;
947 item.pszText = tabtext;
948 item.cchTextMax = MAX_TABTEXT_LENGTH;
950 nTabs = psInfo->nPages;
953 * Set the image list for icons.
955 if (psInfo->hImageList)
957 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
960 for (i = 0; i < nTabs; i++)
962 if ( psInfo->proppage[i].hasIcon )
964 item.mask |= TCIF_IMAGE;
965 item.iImage = iImage++;
967 else
969 item.mask &= ~TCIF_IMAGE;
972 WideCharToMultiByte(CP_ACP, 0,
973 (LPCWSTR)psInfo->proppage[i].pszText,
974 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
976 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
979 return TRUE;
982 /******************************************************************************
983 * PROPSHEET_CreatePage
985 * Creates a page.
987 static int PROPSHEET_CreatePage(HWND hwndParent,
988 int index,
989 const PropSheetInfo * psInfo,
990 LPCPROPSHEETPAGEA ppshpage)
992 DLGTEMPLATE* pTemplate;
993 HWND hwndPage;
994 RECT rc;
995 PropPageInfo* ppInfo = psInfo->proppage;
996 PADDING_INFO padding;
997 UINT pageWidth,pageHeight;
999 TRACE("index %d\n", index);
1001 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1002 pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
1003 else
1005 HRSRC hResource = FindResourceA(ppshpage->hInstance,
1006 ppshpage->u1.pszTemplate,
1007 RT_DIALOGA);
1008 HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
1009 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1012 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1014 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1015 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1016 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1017 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1018 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1019 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1020 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1022 else
1024 pTemplate->style |= WS_CHILD | DS_CONTROL;
1025 pTemplate->style &= ~DS_MODALFRAME;
1026 pTemplate->style &= ~WS_CAPTION;
1027 pTemplate->style &= ~WS_SYSMENU;
1028 pTemplate->style &= ~WS_POPUP;
1029 pTemplate->style &= ~WS_DISABLED;
1030 pTemplate->style &= ~WS_VISIBLE;
1033 if (psInfo->proppage[index].useCallback)
1034 (*(ppshpage->pfnCallback))(hwndParent,
1035 PSPCB_CREATE,
1036 (LPPROPSHEETPAGEA)ppshpage);
1038 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1039 pTemplate,
1040 hwndParent,
1041 ppshpage->pfnDlgProc,
1042 (LPARAM)ppshpage);
1044 ppInfo[index].hwndPage = hwndPage;
1046 rc.left = psInfo->x;
1047 rc.top = psInfo->y;
1048 rc.right = psInfo->width;
1049 rc.bottom = psInfo->height;
1051 MapDialogRect(hwndParent, &rc);
1053 pageWidth = rc.right - rc.left;
1054 pageHeight = rc.bottom - rc.top;
1056 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1057 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
1058 else
1061 * Ask the Tab control to fit this page in.
1064 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1065 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1066 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1069 SetWindowPos(hwndPage, HWND_TOP,
1070 rc.left + padding.x,
1071 rc.top + padding.y,
1072 pageWidth, pageHeight, 0);
1074 return TRUE;
1077 /******************************************************************************
1078 * PROPSHEET_ShowPage
1080 * Displays or creates the specified page.
1082 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1084 if (index == psInfo->active_page)
1086 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1087 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1088 return TRUE;
1091 if (psInfo->proppage[index].hwndPage == 0)
1093 LPCPROPSHEETPAGEA ppshpage;
1094 PSHNOTIFY psn;
1096 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1097 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1099 psn.hdr.hwndFrom = hwndDlg;
1100 psn.hdr.code = PSN_SETACTIVE;
1101 psn.hdr.idFrom = 0;
1102 psn.lParam = 0;
1104 /* Send the notification before showing the page. */
1105 SendMessageA(psInfo->proppage[index].hwndPage,
1106 WM_NOTIFY, 0, (LPARAM) &psn);
1109 * TODO: check return value.
1113 if (psInfo->active_page != -1)
1114 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1116 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1118 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1120 HWND hwndTabCtrl;
1122 /* Synchronize current selection with tab control */
1123 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1124 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1127 psInfo->active_page = index;
1128 psInfo->activeValid = TRUE;
1130 return TRUE;
1133 /******************************************************************************
1134 * PROPSHEET_Back
1136 static BOOL PROPSHEET_Back(HWND hwndDlg)
1138 BOOL res;
1139 PSHNOTIFY psn;
1140 HWND hwndPage;
1141 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1142 PropSheetInfoStr);
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 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1155 return FALSE;
1157 if (psInfo->active_page > 0)
1159 res = PROPSHEET_CanSetCurSel(hwndDlg);
1160 if(res != FALSE)
1162 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1166 return TRUE;
1169 /******************************************************************************
1170 * PROPSHEET_Next
1172 static BOOL PROPSHEET_Next(HWND hwndDlg)
1174 PSHNOTIFY psn;
1175 HWND hwndPage;
1176 LRESULT msgResult = 0;
1177 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1178 PropSheetInfoStr);
1180 if (psInfo->active_page < 0)
1181 return FALSE;
1183 psn.hdr.code = PSN_WIZNEXT;
1184 psn.hdr.hwndFrom = hwndDlg;
1185 psn.hdr.idFrom = 0;
1186 psn.lParam = 0;
1188 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1190 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1192 TRACE("msg result %ld\n", msgResult);
1194 if (msgResult == -1)
1195 return FALSE;
1197 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1199 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1202 return TRUE;
1205 /******************************************************************************
1206 * PROPSHEET_Finish
1208 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1210 PSHNOTIFY psn;
1211 HWND hwndPage;
1212 LRESULT msgResult = 0;
1213 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1214 PropSheetInfoStr);
1216 if (psInfo->active_page < 0)
1217 return FALSE;
1219 psn.hdr.code = PSN_WIZFINISH;
1220 psn.hdr.hwndFrom = hwndDlg;
1221 psn.hdr.idFrom = 0;
1222 psn.lParam = 0;
1224 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1226 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1228 TRACE("msg result %ld\n", msgResult);
1230 if (msgResult != 0)
1231 return FALSE;
1233 if (psInfo->isModeless)
1234 psInfo->activeValid = FALSE;
1235 else
1236 EndDialog(hwndDlg, TRUE);
1238 return TRUE;
1241 /******************************************************************************
1242 * PROPSHEET_Apply
1244 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1246 int i;
1247 HWND hwndPage;
1248 PSHNOTIFY psn;
1249 LRESULT msgResult;
1250 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1251 PropSheetInfoStr);
1253 if (psInfo->active_page < 0)
1254 return FALSE;
1256 psn.hdr.hwndFrom = hwndDlg;
1257 psn.hdr.idFrom = 0;
1258 psn.lParam = 0;
1262 * Send PSN_KILLACTIVE to the current page.
1264 psn.hdr.code = PSN_KILLACTIVE;
1266 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1268 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1269 return FALSE;
1272 * Send PSN_APPLY to all pages.
1274 psn.hdr.code = PSN_APPLY;
1275 psn.lParam = lParam;
1277 for (i = 0; i < psInfo->nPages; i++)
1279 hwndPage = psInfo->proppage[i].hwndPage;
1280 if (hwndPage)
1282 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1283 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1284 return FALSE;
1288 if(lParam)
1290 psInfo->activeValid = FALSE;
1292 else if(psInfo->active_page >= 0)
1294 psn.hdr.code = PSN_SETACTIVE;
1295 psn.lParam = 0;
1296 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1297 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1300 return TRUE;
1303 /******************************************************************************
1304 * PROPSHEET_Cancel
1306 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1308 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1309 PropSheetInfoStr);
1310 HWND hwndPage;
1311 PSHNOTIFY psn;
1312 int i;
1314 if (psInfo->active_page < 0)
1315 return;
1317 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1318 psn.hdr.code = PSN_QUERYCANCEL;
1319 psn.hdr.hwndFrom = hwndDlg;
1320 psn.hdr.idFrom = 0;
1321 psn.lParam = 0;
1323 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1324 return;
1326 psn.hdr.code = PSN_RESET;
1327 psn.lParam = lParam;
1329 for (i = 0; i < psInfo->nPages; i++)
1331 hwndPage = psInfo->proppage[i].hwndPage;
1333 if (hwndPage)
1334 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1337 if (psInfo->isModeless)
1339 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1340 psInfo->activeValid = FALSE;
1342 else
1343 EndDialog(hwndDlg, FALSE);
1346 /******************************************************************************
1347 * PROPSHEET_Help
1349 static void PROPSHEET_Help(HWND hwndDlg)
1351 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1352 PropSheetInfoStr);
1353 HWND hwndPage;
1354 PSHNOTIFY psn;
1356 if (psInfo->active_page < 0)
1357 return;
1359 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1360 psn.hdr.code = PSN_HELP;
1361 psn.hdr.hwndFrom = hwndDlg;
1362 psn.hdr.idFrom = 0;
1363 psn.lParam = 0;
1365 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1368 /******************************************************************************
1369 * PROPSHEET_Changed
1371 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1373 int i;
1374 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1375 PropSheetInfoStr);
1377 if (!psInfo) return;
1379 * Set the dirty flag of this page.
1381 for (i = 0; i < psInfo->nPages; i++)
1383 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1384 psInfo->proppage[i].isDirty = TRUE;
1388 * Enable the Apply button.
1390 if (psInfo->hasApply)
1392 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1394 EnableWindow(hwndApplyBtn, TRUE);
1398 /******************************************************************************
1399 * PROPSHEET_UnChanged
1401 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1403 int i;
1404 BOOL noPageDirty = TRUE;
1405 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1406 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1407 PropSheetInfoStr);
1409 if ( !psInfo ) return;
1410 for (i = 0; i < psInfo->nPages; i++)
1412 /* set the specified page as clean */
1413 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1414 psInfo->proppage[i].isDirty = FALSE;
1416 /* look to see if there's any dirty pages */
1417 if (psInfo->proppage[i].isDirty)
1418 noPageDirty = FALSE;
1422 * Disable Apply button.
1424 if (noPageDirty)
1425 EnableWindow(hwndApplyBtn, FALSE);
1428 /******************************************************************************
1429 * PROPSHEET_PressButton
1431 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1433 switch (buttonID)
1435 case PSBTN_APPLYNOW:
1436 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1437 break;
1438 case PSBTN_BACK:
1439 PROPSHEET_Back(hwndDlg);
1440 break;
1441 case PSBTN_CANCEL:
1442 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1443 break;
1444 case PSBTN_FINISH:
1445 PROPSHEET_Finish(hwndDlg);
1446 break;
1447 case PSBTN_HELP:
1448 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1449 break;
1450 case PSBTN_NEXT:
1451 PROPSHEET_Next(hwndDlg);
1452 break;
1453 case PSBTN_OK:
1454 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1455 break;
1456 default:
1457 FIXME("Invalid button index %d\n", buttonID);
1462 /*************************************************************************
1463 * BOOL PROPSHEET_CanSetCurSel [Internal]
1465 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1467 * PARAMS
1468 * hwndDlg [I] handle to a Dialog hWnd
1470 * RETURNS
1471 * TRUE if Current Selection can change
1473 * NOTES
1475 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1477 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1478 PropSheetInfoStr);
1479 HWND hwndPage;
1480 PSHNOTIFY psn;
1482 if (!psInfo)
1483 return FALSE;
1485 if (psInfo->active_page < 0)
1486 return TRUE;
1489 * Notify the current page.
1491 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1492 psn.hdr.code = PSN_KILLACTIVE;
1493 psn.hdr.hwndFrom = hwndDlg;
1494 psn.hdr.idFrom = 0;
1495 psn.lParam = 0;
1497 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1500 /******************************************************************************
1501 * PROPSHEET_SetCurSel
1503 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1504 int index,
1505 HPROPSHEETPAGE hpage)
1507 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1508 PropSheetInfoStr);
1509 HWND hwndPage;
1510 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1512 /* hpage takes precedence over index */
1513 if (hpage != NULL)
1514 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1516 if (index < 0 || index >= psInfo->nPages)
1518 TRACE("Could not find page to select!\n");
1519 return FALSE;
1522 hwndPage = psInfo->proppage[index].hwndPage;
1525 * Notify the new page if it's already created.
1526 * If not it will get created and notified in PROPSHEET_ShowPage.
1528 if (hwndPage)
1530 int result;
1531 PSHNOTIFY psn;
1533 psn.hdr.code = PSN_SETACTIVE;
1534 psn.hdr.hwndFrom = hwndDlg;
1535 psn.hdr.idFrom = 0;
1536 psn.lParam = 0;
1538 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1541 * TODO: check return value.
1546 * Display the new page.
1548 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1550 if (psInfo->proppage[index].hasHelp)
1551 EnableWindow(hwndHelp, TRUE);
1552 else
1553 EnableWindow(hwndHelp, FALSE);
1555 return TRUE;
1558 /******************************************************************************
1559 * PROPSHEET_SetTitleA
1561 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1563 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1564 char szTitle[256];
1566 if (HIWORD(lpszText) == 0) {
1567 if (!LoadStringA(psInfo->ppshheader.hInstance,
1568 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1569 return;
1570 lpszText = szTitle;
1572 if (dwStyle & PSH_PROPTITLE)
1574 char* dest;
1575 int lentitle = strlen(lpszText);
1576 int lenprop = strlen(psInfo->strPropertiesFor);
1578 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1579 strcpy(dest, psInfo->strPropertiesFor);
1580 strcat(dest, lpszText);
1582 SetWindowTextA(hwndDlg, dest);
1583 COMCTL32_Free(dest);
1585 else
1586 SetWindowTextA(hwndDlg, lpszText);
1589 /******************************************************************************
1590 * PROPSHEET_SetFinishTextA
1592 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1594 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1596 /* Set text, show and enable the Finish button */
1597 SetWindowTextA(hwndButton, lpszText);
1598 ShowWindow(hwndButton, SW_SHOW);
1599 EnableWindow(hwndButton, TRUE);
1601 /* Make it default pushbutton */
1602 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1604 /* Hide Back button */
1605 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1606 ShowWindow(hwndButton, SW_HIDE);
1608 /* Hide Next button */
1609 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1610 ShowWindow(hwndButton, SW_HIDE);
1613 /******************************************************************************
1614 * PROPSHEET_QuerySiblings
1616 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1617 WPARAM wParam, LPARAM lParam)
1619 int i = 0;
1620 HWND hwndPage;
1621 LRESULT msgResult = 0;
1622 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1623 PropSheetInfoStr);
1625 while ((i < psInfo->nPages) && (msgResult == 0))
1627 hwndPage = psInfo->proppage[i].hwndPage;
1628 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1629 i++;
1632 return msgResult;
1636 /******************************************************************************
1637 * PROPSHEET_AddPage
1639 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1640 HPROPSHEETPAGE hpage)
1642 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1643 PropSheetInfoStr);
1644 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1645 TCITEMA item;
1646 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1647 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1650 * Allocate and fill in a new PropPageInfo entry.
1652 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1653 sizeof(PropPageInfo) *
1654 (psInfo->nPages + 1));
1655 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1656 return FALSE;
1658 psInfo->proppage[psInfo->nPages].hpage = hpage;
1660 if (ppsp->dwFlags & PSP_PREMATURE)
1662 /* Create the page but don't show it */
1663 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1667 * Add a new tab to the tab control.
1669 item.mask = TCIF_TEXT;
1670 item.pszText = tabtext;
1671 item.cchTextMax = MAX_TABTEXT_LENGTH;
1673 WideCharToMultiByte(CP_ACP, 0,
1674 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1675 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1677 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1678 (LPARAM)&item);
1680 psInfo->nPages++;
1682 /* If it is the only page - show it */
1683 if(psInfo->nPages == 1)
1684 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1686 return TRUE;
1689 /******************************************************************************
1690 * PROPSHEET_RemovePage
1692 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1693 int index,
1694 HPROPSHEETPAGE hpage)
1696 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1697 PropSheetInfoStr);
1698 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1699 PropPageInfo* oldPages;
1701 if (!psInfo) {
1702 return FALSE;
1704 oldPages = psInfo->proppage;
1706 * hpage takes precedence over index.
1708 if (hpage != 0)
1710 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1713 /* Make shure that index is within range */
1714 if (index < 0 || index >= psInfo->nPages)
1716 TRACE("Could not find page to remove!\n");
1717 return FALSE;
1720 TRACE("total pages %d removing page %d active page %d\n",
1721 psInfo->nPages, index, psInfo->active_page);
1723 * Check if we're removing the active page.
1725 if (index == psInfo->active_page)
1727 if (psInfo->nPages > 1)
1729 if (index > 0)
1731 /* activate previous page */
1732 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1734 else
1736 /* activate the next page */
1737 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1738 psInfo->active_page = index;
1741 else
1743 psInfo->active_page = -1;
1744 if (!psInfo->isModeless)
1746 EndDialog(hwndDlg, FALSE);
1747 return TRUE;
1751 else if (index < psInfo->active_page)
1752 psInfo->active_page--;
1754 /* Destroy page dialog window */
1755 DestroyWindow(psInfo->proppage[index].hwndPage);
1757 /* Free page resources */
1758 if(psInfo->proppage[index].hpage)
1760 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1762 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1763 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1765 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1768 /* Remove the tab */
1769 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1771 psInfo->nPages--;
1772 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1774 if (index > 0)
1775 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1777 if (index < psInfo->nPages)
1778 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1779 (psInfo->nPages - index) * sizeof(PropPageInfo));
1781 COMCTL32_Free(oldPages);
1783 return FALSE;
1786 /******************************************************************************
1787 * PROPSHEET_SetWizButtons
1789 * This code will work if (and assumes that) the Next button is on top of the
1790 * Finish button. ie. Finish comes after Next in the Z order.
1791 * This means make sure the dialog template reflects this.
1794 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1796 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1797 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1798 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1800 TRACE("%ld\n", dwFlags);
1802 EnableWindow(hwndBack, FALSE);
1803 EnableWindow(hwndNext, FALSE);
1804 EnableWindow(hwndFinish, FALSE);
1806 if (dwFlags & PSWIZB_BACK)
1807 EnableWindow(hwndBack, TRUE);
1809 if (dwFlags & PSWIZB_NEXT)
1811 /* Hide the Finish button */
1812 ShowWindow(hwndFinish, SW_HIDE);
1814 /* Show and enable the Next button */
1815 ShowWindow(hwndNext, SW_SHOW);
1816 EnableWindow(hwndNext, TRUE);
1818 /* Set the Next button as the default pushbutton */
1819 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1822 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1824 /* Hide the Next button */
1825 ShowWindow(hwndNext, SW_HIDE);
1827 /* Show the Finish button */
1828 ShowWindow(hwndFinish, SW_SHOW);
1830 if (dwFlags & PSWIZB_FINISH)
1831 EnableWindow(hwndFinish, TRUE);
1833 /* Set the Finish button as the default pushbutton */
1834 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1838 /******************************************************************************
1839 * PROPSHEET_GetPageIndex
1841 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1842 * the array of PropPageInfo.
1844 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1846 BOOL found = FALSE;
1847 int index = 0;
1849 while ((index < psInfo->nPages) && (found == FALSE))
1851 if (psInfo->proppage[index].hpage == hpage)
1852 found = TRUE;
1853 else
1854 index++;
1857 if (found == FALSE)
1858 index = -1;
1860 return index;
1863 /******************************************************************************
1864 * PROPSHEET_CleanUp
1866 static void PROPSHEET_CleanUp(HWND hwndDlg)
1868 int i;
1869 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1870 PropSheetInfoStr);
1872 TRACE("\n");
1873 if (HIWORD(psInfo->ppshheader.pszCaption))
1874 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
1876 for (i = 0; i < psInfo->nPages; i++)
1878 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1880 if(psInfo->proppage[i].hwndPage)
1881 DestroyWindow(psInfo->proppage[i].hwndPage);
1883 if(psp)
1885 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1886 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1888 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1892 COMCTL32_Free(psInfo->proppage);
1893 COMCTL32_Free(psInfo->strPropertiesFor);
1894 ImageList_Destroy(psInfo->hImageList);
1896 GlobalFree((HGLOBAL)psInfo);
1899 /******************************************************************************
1900 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1902 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1904 int bRet = 0;
1905 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1906 sizeof(PropSheetInfo));
1907 int i, n;
1908 BYTE* pByte;
1910 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1912 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1913 lppsh->nPages);
1914 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
1916 for (n = i = 0; i < lppsh->nPages; i++, n++)
1918 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1919 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
1920 else
1922 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1923 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1926 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1927 psInfo, n))
1929 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1930 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1931 n--;
1932 psInfo->nPages--;
1936 bRet = PROPSHEET_CreateDialog(psInfo);
1938 return bRet;
1941 /******************************************************************************
1942 * PropertySheetW (COMCTL32.85)
1944 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1946 FIXME("(%p): stub\n", propertySheetHeader);
1948 return -1;
1951 /******************************************************************************
1952 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1954 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1955 LPCPROPSHEETPAGEA lpPropSheetPage)
1957 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1959 *ppsp = *lpPropSheetPage;
1961 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u1.pszTemplate ) )
1962 ppsp->u1.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u1.pszTemplate );
1964 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
1965 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
1968 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
1969 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
1970 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
1971 ppsp->pszTitle = NULL;
1973 return (HPROPSHEETPAGE)ppsp;
1976 /******************************************************************************
1977 * CreatePropertySheetPageW (COMCTL32.20)
1979 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1981 FIXME("(%p): stub\n", lpPropSheetPage);
1983 return 0;
1986 /******************************************************************************
1987 * DestroyPropertySheetPage (COMCTL32.24)
1989 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1991 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
1993 if (!psp)
1994 return FALSE;
1996 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u1.pszTemplate ) )
1997 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u1.pszTemplate);
1999 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2000 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2002 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2003 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2005 COMCTL32_Free(hPropPage);
2007 return TRUE;
2010 /******************************************************************************
2011 * PROPSHEET_IsDialogMessage
2013 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2015 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2017 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2018 return FALSE;
2020 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2022 int new_page = 0;
2023 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2025 if (!(dlgCode & DLGC_WANTMESSAGE))
2027 switch (lpMsg->wParam)
2029 case VK_TAB:
2030 if (GetKeyState(VK_SHIFT) & 0x8000)
2031 new_page = -1;
2032 else
2033 new_page = 1;
2034 break;
2036 case VK_NEXT: new_page = 1; break;
2037 case VK_PRIOR: new_page = -1; break;
2041 if (new_page)
2043 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2045 new_page += psInfo->active_page;
2047 if (new_page < 0)
2048 new_page = psInfo->nPages - 1;
2049 else if (new_page >= psInfo->nPages)
2050 new_page = 0;
2052 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2055 return TRUE;
2059 return IsDialogMessageA(hwnd, lpMsg);
2062 /******************************************************************************
2063 * PROPSHEET_DialogProc
2065 BOOL WINAPI
2066 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2068 switch (uMsg)
2070 case WM_INITDIALOG:
2072 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2073 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2074 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2075 LPCPROPSHEETPAGEA ppshpage;
2076 int idx;
2078 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2081 * psInfo->hwnd is not being used by WINE code - it exists
2082 * for compatibility with "real" Windoze. The same about
2083 * SetWindowLong - WINE is only using the PropSheetInfoStr
2084 * property.
2086 psInfo->hwnd = hwnd;
2087 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2090 * Small icon in the title bar.
2092 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2093 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2095 HICON hIcon;
2096 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2097 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2099 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2100 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2101 psInfo->ppshheader.u1.pszIcon,
2102 IMAGE_ICON,
2103 icon_cx, icon_cy,
2104 LR_DEFAULTCOLOR);
2105 else
2106 hIcon = psInfo->ppshheader.u1.hIcon;
2108 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2111 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2112 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u1.hIcon);
2114 psInfo->strPropertiesFor = strCaption;
2116 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2118 PROPSHEET_CreateTabControl(hwnd, psInfo);
2120 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2122 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2124 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2125 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2128 else
2130 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2132 PROPSHEET_AdjustSize(hwnd, psInfo);
2133 PROPSHEET_AdjustButtons(hwnd, psInfo);
2137 if (psInfo->useCallback)
2138 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2139 PSCB_INITIALIZED, (LPARAM)0);
2141 idx = psInfo->active_page;
2142 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2143 psInfo->active_page = -1;
2145 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2147 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2148 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2150 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2151 psInfo->ppshheader.hInstance)
2153 char szText[256];
2155 if (LoadStringA(psInfo->ppshheader.hInstance,
2156 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2157 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2159 else
2161 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2162 psInfo->ppshheader.pszCaption);
2165 return TRUE;
2168 case WM_DESTROY:
2169 PROPSHEET_CleanUp(hwnd);
2170 return TRUE;
2172 case WM_CLOSE:
2173 PROPSHEET_Cancel(hwnd, 1);
2174 return TRUE;
2176 case WM_COMMAND:
2178 WORD wID = LOWORD(wParam);
2180 switch (wID)
2182 case IDOK:
2183 case IDC_APPLY_BUTTON:
2185 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2187 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2188 break;
2190 if (wID == IDOK)
2192 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2193 PropSheetInfoStr);
2194 int result = TRUE;
2196 if (psInfo->restartWindows)
2197 result = ID_PSRESTARTWINDOWS;
2199 /* reboot system takes precedence over restart windows */
2200 if (psInfo->rebootSystem)
2201 result = ID_PSREBOOTSYSTEM;
2203 if (psInfo->isModeless)
2204 psInfo->activeValid = FALSE;
2205 else
2206 EndDialog(hwnd, result);
2208 else
2209 EnableWindow(hwndApplyBtn, FALSE);
2211 break;
2214 case IDC_BACK_BUTTON:
2215 PROPSHEET_Back(hwnd);
2216 break;
2218 case IDC_NEXT_BUTTON:
2219 PROPSHEET_Next(hwnd);
2220 break;
2222 case IDC_FINISH_BUTTON:
2223 PROPSHEET_Finish(hwnd);
2224 break;
2226 case IDCANCEL:
2227 PROPSHEET_Cancel(hwnd, 0);
2228 break;
2230 case IDHELP:
2231 PROPSHEET_Help(hwnd);
2232 break;
2235 return TRUE;
2238 case WM_NOTIFY:
2240 NMHDR* pnmh = (LPNMHDR) lParam;
2242 if (pnmh->code == TCN_SELCHANGE)
2244 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2245 PROPSHEET_SetCurSel(hwnd, index, 0);
2248 if(pnmh->code == TCN_SELCHANGING)
2250 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2251 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2252 return TRUE;
2256 return 0;
2259 case PSM_GETCURRENTPAGEHWND:
2261 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2262 PropSheetInfoStr);
2263 HWND hwndPage = 0;
2265 if (psInfo->activeValid && psInfo->active_page != -1)
2266 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2268 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2270 return TRUE;
2273 case PSM_CHANGED:
2274 PROPSHEET_Changed(hwnd, (HWND)wParam);
2275 return TRUE;
2277 case PSM_UNCHANGED:
2278 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2279 return TRUE;
2281 case PSM_GETTABCONTROL:
2283 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2285 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2287 return TRUE;
2290 case PSM_SETCURSEL:
2292 BOOL msgResult;
2294 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2295 if(msgResult != FALSE)
2297 msgResult = PROPSHEET_SetCurSel(hwnd,
2298 (int)wParam,
2299 (HPROPSHEETPAGE)lParam);
2302 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2304 return TRUE;
2307 case PSM_CANCELTOCLOSE:
2309 char buf[MAX_BUTTONTEXT_LENGTH];
2310 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2311 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2313 EnableWindow(hwndCancel, FALSE);
2314 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2315 SetWindowTextA(hwndOK, buf);
2317 return FALSE;
2320 case PSM_RESTARTWINDOWS:
2322 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2323 PropSheetInfoStr);
2325 psInfo->restartWindows = TRUE;
2326 return TRUE;
2329 case PSM_REBOOTSYSTEM:
2331 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2332 PropSheetInfoStr);
2334 psInfo->rebootSystem = TRUE;
2335 return TRUE;
2338 case PSM_SETTITLEA:
2339 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2340 return TRUE;
2342 case PSM_APPLY:
2344 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2346 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2348 return TRUE;
2351 case PSM_QUERYSIBLINGS:
2353 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2355 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2357 return TRUE;
2360 case PSM_ADDPAGE:
2363 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2364 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2365 * on success or FALSE otherwise, as specified on MSDN Online.
2366 * Also see the MFC code for
2367 * CPropertySheet::AddPage(CPropertyPage* pPage).
2370 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2372 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2374 return TRUE;
2377 case PSM_REMOVEPAGE:
2378 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2379 return TRUE;
2381 case PSM_ISDIALOGMESSAGE:
2383 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2384 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2385 return TRUE;
2388 case PSM_PRESSBUTTON:
2389 PROPSHEET_PressButton(hwnd, (int)wParam);
2390 return TRUE;
2392 case PSM_SETFINISHTEXTA:
2393 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2394 return TRUE;
2396 case PSM_SETWIZBUTTONS:
2397 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2398 return TRUE;
2400 case PSM_SETTITLEW:
2401 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2402 return 0;
2403 case PSM_SETCURSELID:
2404 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2405 return 0;
2406 case PSM_SETFINISHTEXTW:
2407 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2408 return 0;
2410 default:
2411 return FALSE;