Got rid of the Wine internal lstrcpy* functions and of winestring.h.
[wine/gsoc_dplay.git] / dlls / comctl32 / propsheet.c
blobfc377e2151e10b310e66d13bbab7a85c8dd17a4c
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 BOOL 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, const PropSheetInfo* psInfo);
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->u.pResource;
218 else
220 HRSRC hResource = FindResourceA(lppsp->hInstance,
221 lppsp->u.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, psInfo);
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, psInfo);
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, psInfo);
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 * Vertical spacing is the distance between the line and the buttons.
890 * Do NOT use the Help button to gather padding information when it isn't mapped
891 * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
892 * for it in this case !
893 * FIXME: I'm not sure about any other coordinate problems with these evil
894 * buttons. Fix it in case additional problems appear or maybe calculate
895 * a padding in a completely different way, as this is somewhat messy.
897 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
898 psInfo)
900 PADDING_INFO padding;
901 RECT rc;
902 HWND hwndControl;
903 INT idButton;
904 POINT ptButton, ptLine;
906 if (psInfo->hasHelp)
908 idButton = IDHELP;
910 else
912 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
914 idButton = IDC_NEXT_BUTTON;
916 else
918 /* hopefully this is ok */
919 idButton = IDCANCEL;
923 hwndControl = GetDlgItem(hwndDlg, idButton);
924 GetWindowRect(hwndControl, &rc);
926 ptButton.x = rc.left;
927 ptButton.y = rc.top;
929 ScreenToClient(hwndDlg, &ptButton);
931 /* Line */
932 hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
933 GetWindowRect(hwndControl, &rc);
935 ptLine.x = 0;
936 ptLine.y = rc.bottom;
938 ScreenToClient(hwndDlg, &ptLine);
940 padding.y = ptButton.y - ptLine.y;
942 if (padding.y < 0)
943 ERR("padding negative ! Please report this !\n");
945 /* this is most probably not correct, but the best we have now */
946 padding.x = padding.y;
947 return padding;
950 /******************************************************************************
951 * PROPSHEET_CreateTabControl
953 * Insert the tabs in the tab control.
955 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
956 PropSheetInfo * psInfo)
958 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
959 TCITEMA item;
960 int i, nTabs;
961 int iImage = 0;
962 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
964 item.mask = TCIF_TEXT;
965 item.pszText = tabtext;
966 item.cchTextMax = MAX_TABTEXT_LENGTH;
968 nTabs = psInfo->nPages;
971 * Set the image list for icons.
973 if (psInfo->hImageList)
975 SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
978 for (i = 0; i < nTabs; i++)
980 if ( psInfo->proppage[i].hasIcon )
982 item.mask |= TCIF_IMAGE;
983 item.iImage = iImage++;
985 else
987 item.mask &= ~TCIF_IMAGE;
990 WideCharToMultiByte(CP_ACP, 0,
991 (LPCWSTR)psInfo->proppage[i].pszText,
992 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
994 SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
997 return TRUE;
1000 /******************************************************************************
1001 * PROPSHEET_CreatePage
1003 * Creates a page.
1005 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
1006 int index,
1007 const PropSheetInfo * psInfo,
1008 LPCPROPSHEETPAGEA ppshpage)
1010 DLGTEMPLATE* pTemplate;
1011 HWND hwndPage;
1012 RECT rc;
1013 PropPageInfo* ppInfo = psInfo->proppage;
1014 PADDING_INFO padding;
1015 UINT pageWidth,pageHeight;
1016 DWORD resSize;
1017 LPVOID temp = NULL;
1019 TRACE("index %d\n", index);
1021 if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1022 pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
1023 else
1025 HRSRC hResource;
1026 HANDLE hTemplate;
1028 hResource = FindResourceA(ppshpage->hInstance,
1029 ppshpage->u.pszTemplate,
1030 RT_DIALOGA);
1031 if(!hResource)
1032 return FALSE;
1034 resSize = SizeofResource(ppshpage->hInstance, hResource);
1036 hTemplate = LoadResource(ppshpage->hInstance, hResource);
1037 if(!hTemplate)
1038 return FALSE;
1040 pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1042 * Make a copy of the dialog template to make it writable
1044 temp = COMCTL32_Alloc(resSize);
1045 if (!temp)
1046 return FALSE;
1048 memcpy(temp, pTemplate, resSize);
1049 pTemplate = temp;
1052 if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1054 ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | DS_CONTROL;
1055 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1056 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1057 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1058 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1059 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1060 ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1062 else
1064 pTemplate->style |= WS_CHILD | DS_CONTROL;
1065 pTemplate->style &= ~DS_MODALFRAME;
1066 pTemplate->style &= ~WS_CAPTION;
1067 pTemplate->style &= ~WS_SYSMENU;
1068 pTemplate->style &= ~WS_POPUP;
1069 pTemplate->style &= ~WS_DISABLED;
1070 pTemplate->style &= ~WS_VISIBLE;
1073 if (psInfo->proppage[index].useCallback)
1074 (*(ppshpage->pfnCallback))(hwndParent,
1075 PSPCB_CREATE,
1076 (LPPROPSHEETPAGEA)ppshpage);
1078 hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1079 pTemplate,
1080 hwndParent,
1081 ppshpage->pfnDlgProc,
1082 (LPARAM)ppshpage);
1083 /* Free a no more needed copy */
1084 if(temp)
1085 COMCTL32_Free(temp);
1087 ppInfo[index].hwndPage = hwndPage;
1089 rc.left = psInfo->x;
1090 rc.top = psInfo->y;
1091 rc.right = psInfo->width;
1092 rc.bottom = psInfo->height;
1094 MapDialogRect(hwndParent, &rc);
1096 pageWidth = rc.right - rc.left;
1097 pageHeight = rc.bottom - rc.top;
1099 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
1100 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
1101 else
1104 * Ask the Tab control to fit this page in.
1107 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1108 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
1109 padding = PROPSHEET_GetPaddingInfo(hwndParent);
1112 SetWindowPos(hwndPage, HWND_TOP,
1113 rc.left + padding.x,
1114 rc.top + padding.y,
1115 pageWidth, pageHeight, 0);
1117 return TRUE;
1120 /******************************************************************************
1121 * PROPSHEET_ShowPage
1123 * Displays or creates the specified page.
1125 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1127 if (index == psInfo->active_page)
1129 if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1130 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1131 return TRUE;
1134 if (psInfo->proppage[index].hwndPage == 0)
1136 LPCPROPSHEETPAGEA ppshpage;
1137 PSHNOTIFY psn;
1139 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[index].hpage;
1140 PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1142 psn.hdr.hwndFrom = hwndDlg;
1143 psn.hdr.code = PSN_SETACTIVE;
1144 psn.hdr.idFrom = 0;
1145 psn.lParam = 0;
1147 /* Send the notification before showing the page. */
1148 SendMessageA(psInfo->proppage[index].hwndPage,
1149 WM_NOTIFY, 0, (LPARAM) &psn);
1152 * TODO: check return value.
1156 if (psInfo->active_page != -1)
1157 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1159 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1161 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
1163 HWND hwndTabCtrl;
1165 /* Synchronize current selection with tab control */
1166 hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1167 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1170 psInfo->active_page = index;
1171 psInfo->activeValid = TRUE;
1173 return TRUE;
1176 /******************************************************************************
1177 * PROPSHEET_Back
1179 static BOOL PROPSHEET_Back(HWND hwndDlg)
1181 BOOL res;
1182 PSHNOTIFY psn;
1183 HWND hwndPage;
1184 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1185 PropSheetInfoStr);
1187 if (psInfo->active_page < 0)
1188 return FALSE;
1190 psn.hdr.code = PSN_WIZBACK;
1191 psn.hdr.hwndFrom = hwndDlg;
1192 psn.hdr.idFrom = 0;
1193 psn.lParam = 0;
1195 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1197 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) == -1)
1198 return FALSE;
1200 if (psInfo->active_page > 0)
1202 res = PROPSHEET_CanSetCurSel(hwndDlg);
1203 if(res != FALSE)
1205 res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1209 return TRUE;
1212 /******************************************************************************
1213 * PROPSHEET_Next
1215 static BOOL PROPSHEET_Next(HWND hwndDlg)
1217 PSHNOTIFY psn;
1218 HWND hwndPage;
1219 LRESULT msgResult = 0;
1220 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1221 PropSheetInfoStr);
1223 if (psInfo->active_page < 0)
1224 return FALSE;
1226 psn.hdr.code = PSN_WIZNEXT;
1227 psn.hdr.hwndFrom = hwndDlg;
1228 psn.hdr.idFrom = 0;
1229 psn.lParam = 0;
1231 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1233 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1235 TRACE("msg result %ld\n", msgResult);
1237 if (msgResult == -1)
1238 return FALSE;
1240 if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1242 PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1245 return TRUE;
1248 /******************************************************************************
1249 * PROPSHEET_Finish
1251 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1253 PSHNOTIFY psn;
1254 HWND hwndPage;
1255 LRESULT msgResult = 0;
1256 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1257 PropSheetInfoStr);
1259 if (psInfo->active_page < 0)
1260 return FALSE;
1262 psn.hdr.code = PSN_WIZFINISH;
1263 psn.hdr.hwndFrom = hwndDlg;
1264 psn.hdr.idFrom = 0;
1265 psn.lParam = 0;
1267 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1269 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1271 TRACE("msg result %ld\n", msgResult);
1273 if (msgResult != 0)
1274 return FALSE;
1276 if (psInfo->isModeless)
1277 psInfo->activeValid = FALSE;
1278 else
1279 EndDialog(hwndDlg, TRUE);
1281 return TRUE;
1284 /******************************************************************************
1285 * PROPSHEET_Apply
1287 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1289 int i;
1290 HWND hwndPage;
1291 PSHNOTIFY psn;
1292 LRESULT msgResult;
1293 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1294 PropSheetInfoStr);
1296 if (psInfo->active_page < 0)
1297 return FALSE;
1299 psn.hdr.hwndFrom = hwndDlg;
1300 psn.hdr.idFrom = 0;
1301 psn.lParam = 0;
1305 * Send PSN_KILLACTIVE to the current page.
1307 psn.hdr.code = PSN_KILLACTIVE;
1309 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1311 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1312 return FALSE;
1315 * Send PSN_APPLY to all pages.
1317 psn.hdr.code = PSN_APPLY;
1318 psn.lParam = lParam;
1320 for (i = 0; i < psInfo->nPages; i++)
1322 hwndPage = psInfo->proppage[i].hwndPage;
1323 if (hwndPage)
1325 msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1326 if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1327 return FALSE;
1331 if(lParam)
1333 psInfo->activeValid = FALSE;
1335 else if(psInfo->active_page >= 0)
1337 psn.hdr.code = PSN_SETACTIVE;
1338 psn.lParam = 0;
1339 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1340 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1343 return TRUE;
1346 /******************************************************************************
1347 * PROPSHEET_Cancel
1349 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1351 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1352 PropSheetInfoStr);
1353 HWND hwndPage;
1354 PSHNOTIFY psn;
1355 int i;
1357 if (psInfo->active_page < 0)
1358 return;
1360 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1361 psn.hdr.code = PSN_QUERYCANCEL;
1362 psn.hdr.hwndFrom = hwndDlg;
1363 psn.hdr.idFrom = 0;
1364 psn.lParam = 0;
1366 if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1367 return;
1369 psn.hdr.code = PSN_RESET;
1370 psn.lParam = lParam;
1372 for (i = 0; i < psInfo->nPages; i++)
1374 hwndPage = psInfo->proppage[i].hwndPage;
1376 if (hwndPage)
1377 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1380 if (psInfo->isModeless)
1382 /* makes PSM_GETCURRENTPAGEHWND return NULL */
1383 psInfo->activeValid = FALSE;
1385 else
1386 EndDialog(hwndDlg, FALSE);
1389 /******************************************************************************
1390 * PROPSHEET_Help
1392 static void PROPSHEET_Help(HWND hwndDlg)
1394 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1395 PropSheetInfoStr);
1396 HWND hwndPage;
1397 PSHNOTIFY psn;
1399 if (psInfo->active_page < 0)
1400 return;
1402 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1403 psn.hdr.code = PSN_HELP;
1404 psn.hdr.hwndFrom = hwndDlg;
1405 psn.hdr.idFrom = 0;
1406 psn.lParam = 0;
1408 SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1411 /******************************************************************************
1412 * PROPSHEET_Changed
1414 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1416 int i;
1417 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1418 PropSheetInfoStr);
1420 if (!psInfo) return;
1422 * Set the dirty flag of this page.
1424 for (i = 0; i < psInfo->nPages; i++)
1426 if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1427 psInfo->proppage[i].isDirty = TRUE;
1431 * Enable the Apply button.
1433 if (psInfo->hasApply)
1435 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1437 EnableWindow(hwndApplyBtn, TRUE);
1441 /******************************************************************************
1442 * PROPSHEET_UnChanged
1444 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1446 int i;
1447 BOOL noPageDirty = TRUE;
1448 HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1449 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1450 PropSheetInfoStr);
1452 if ( !psInfo ) return;
1453 for (i = 0; i < psInfo->nPages; i++)
1455 /* set the specified page as clean */
1456 if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1457 psInfo->proppage[i].isDirty = FALSE;
1459 /* look to see if there's any dirty pages */
1460 if (psInfo->proppage[i].isDirty)
1461 noPageDirty = FALSE;
1465 * Disable Apply button.
1467 if (noPageDirty)
1468 EnableWindow(hwndApplyBtn, FALSE);
1471 /******************************************************************************
1472 * PROPSHEET_PressButton
1474 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1476 switch (buttonID)
1478 case PSBTN_APPLYNOW:
1479 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1480 break;
1481 case PSBTN_BACK:
1482 PROPSHEET_Back(hwndDlg);
1483 break;
1484 case PSBTN_CANCEL:
1485 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1486 break;
1487 case PSBTN_FINISH:
1488 PROPSHEET_Finish(hwndDlg);
1489 break;
1490 case PSBTN_HELP:
1491 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1492 break;
1493 case PSBTN_NEXT:
1494 PROPSHEET_Next(hwndDlg);
1495 break;
1496 case PSBTN_OK:
1497 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1498 break;
1499 default:
1500 FIXME("Invalid button index %d\n", buttonID);
1505 /*************************************************************************
1506 * BOOL PROPSHEET_CanSetCurSel [Internal]
1508 * Test weither the current page can be changed by sending a PSN_KILLACTIVE
1510 * PARAMS
1511 * hwndDlg [I] handle to a Dialog hWnd
1513 * RETURNS
1514 * TRUE if Current Selection can change
1516 * NOTES
1518 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1520 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1521 PropSheetInfoStr);
1522 HWND hwndPage;
1523 PSHNOTIFY psn;
1525 if (!psInfo)
1526 return FALSE;
1528 if (psInfo->active_page < 0)
1529 return TRUE;
1532 * Notify the current page.
1534 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1535 psn.hdr.code = PSN_KILLACTIVE;
1536 psn.hdr.hwndFrom = hwndDlg;
1537 psn.hdr.idFrom = 0;
1538 psn.lParam = 0;
1540 return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1543 /******************************************************************************
1544 * PROPSHEET_SetCurSel
1546 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1547 int index,
1548 HPROPSHEETPAGE hpage)
1550 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1551 PropSheetInfoStr);
1552 HWND hwndPage;
1553 HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP);
1555 /* hpage takes precedence over index */
1556 if (hpage != NULL)
1557 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1559 if (index < 0 || index >= psInfo->nPages)
1561 TRACE("Could not find page to select!\n");
1562 return FALSE;
1565 hwndPage = psInfo->proppage[index].hwndPage;
1568 * Notify the new page if it's already created.
1569 * If not it will get created and notified in PROPSHEET_ShowPage.
1571 if (hwndPage)
1573 int result;
1574 PSHNOTIFY psn;
1576 psn.hdr.code = PSN_SETACTIVE;
1577 psn.hdr.hwndFrom = hwndDlg;
1578 psn.hdr.idFrom = 0;
1579 psn.lParam = 0;
1581 result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1584 * TODO: check return value.
1589 * Display the new page.
1591 PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1593 if (psInfo->proppage[index].hasHelp)
1594 EnableWindow(hwndHelp, TRUE);
1595 else
1596 EnableWindow(hwndHelp, FALSE);
1598 return TRUE;
1601 /******************************************************************************
1602 * PROPSHEET_SetTitleA
1604 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1606 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg, PropSheetInfoStr);
1607 char szTitle[256];
1609 if (HIWORD(lpszText) == 0) {
1610 if (!LoadStringA(psInfo->ppshheader.hInstance,
1611 LOWORD(lpszText), szTitle, sizeof(szTitle)-1))
1612 return;
1613 lpszText = szTitle;
1615 if (dwStyle & PSH_PROPTITLE)
1617 char* dest;
1618 int lentitle = strlen(lpszText);
1619 int lenprop = strlen(psInfo->strPropertiesFor);
1621 dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1622 strcpy(dest, psInfo->strPropertiesFor);
1623 strcat(dest, lpszText);
1625 SetWindowTextA(hwndDlg, dest);
1626 COMCTL32_Free(dest);
1628 else
1629 SetWindowTextA(hwndDlg, lpszText);
1632 /******************************************************************************
1633 * PROPSHEET_SetFinishTextA
1635 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1637 HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1639 /* Set text, show and enable the Finish button */
1640 SetWindowTextA(hwndButton, lpszText);
1641 ShowWindow(hwndButton, SW_SHOW);
1642 EnableWindow(hwndButton, TRUE);
1644 /* Make it default pushbutton */
1645 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1647 /* Hide Back button */
1648 hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1649 ShowWindow(hwndButton, SW_HIDE);
1651 /* Hide Next button */
1652 hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1653 ShowWindow(hwndButton, SW_HIDE);
1656 /******************************************************************************
1657 * PROPSHEET_QuerySiblings
1659 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1660 WPARAM wParam, LPARAM lParam)
1662 int i = 0;
1663 HWND hwndPage;
1664 LRESULT msgResult = 0;
1665 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1666 PropSheetInfoStr);
1668 while ((i < psInfo->nPages) && (msgResult == 0))
1670 hwndPage = psInfo->proppage[i].hwndPage;
1671 msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1672 i++;
1675 return msgResult;
1679 /******************************************************************************
1680 * PROPSHEET_AddPage
1682 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1683 HPROPSHEETPAGE hpage)
1685 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1686 PropSheetInfoStr);
1687 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1688 TCITEMA item;
1689 char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1690 LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1693 * Allocate and fill in a new PropPageInfo entry.
1695 psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1696 sizeof(PropPageInfo) *
1697 (psInfo->nPages + 1));
1698 if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
1699 return FALSE;
1701 psInfo->proppage[psInfo->nPages].hpage = hpage;
1703 if (ppsp->dwFlags & PSP_PREMATURE)
1705 /* Create the page but don't show it */
1706 PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
1710 * Add a new tab to the tab control.
1712 item.mask = TCIF_TEXT;
1713 item.pszText = tabtext;
1714 item.cchTextMax = MAX_TABTEXT_LENGTH;
1716 WideCharToMultiByte(CP_ACP, 0,
1717 (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1718 -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1720 SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1721 (LPARAM)&item);
1723 psInfo->nPages++;
1725 /* If it is the only page - show it */
1726 if(psInfo->nPages == 1)
1727 PROPSHEET_ShowPage(hwndDlg, 0, psInfo);
1729 return TRUE;
1732 /******************************************************************************
1733 * PROPSHEET_RemovePage
1735 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1736 int index,
1737 HPROPSHEETPAGE hpage)
1739 PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1740 PropSheetInfoStr);
1741 HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1742 PropPageInfo* oldPages;
1744 if (!psInfo) {
1745 return FALSE;
1747 oldPages = psInfo->proppage;
1749 * hpage takes precedence over index.
1751 if (hpage != 0)
1753 index = PROPSHEET_GetPageIndex(hpage, psInfo);
1756 /* Make sure that index is within range */
1757 if (index < 0 || index >= psInfo->nPages)
1759 TRACE("Could not find page to remove!\n");
1760 return FALSE;
1763 TRACE("total pages %d removing page %d active page %d\n",
1764 psInfo->nPages, index, psInfo->active_page);
1766 * Check if we're removing the active page.
1768 if (index == psInfo->active_page)
1770 if (psInfo->nPages > 1)
1772 if (index > 0)
1774 /* activate previous page */
1775 PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1777 else
1779 /* activate the next page */
1780 PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1781 psInfo->active_page = index;
1784 else
1786 psInfo->active_page = -1;
1787 if (!psInfo->isModeless)
1789 EndDialog(hwndDlg, FALSE);
1790 return TRUE;
1794 else if (index < psInfo->active_page)
1795 psInfo->active_page--;
1797 /* Destroy page dialog window */
1798 DestroyWindow(psInfo->proppage[index].hwndPage);
1800 /* Free page resources */
1801 if(psInfo->proppage[index].hpage)
1803 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[index].hpage;
1805 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
1806 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[index].pszText);
1808 DestroyPropertySheetPage(psInfo->proppage[index].hpage);
1811 /* Remove the tab */
1812 SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1814 psInfo->nPages--;
1815 psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1817 if (index > 0)
1818 memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1820 if (index < psInfo->nPages)
1821 memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1822 (psInfo->nPages - index) * sizeof(PropPageInfo));
1824 COMCTL32_Free(oldPages);
1826 return FALSE;
1829 /******************************************************************************
1830 * PROPSHEET_SetWizButtons
1832 * This code will work if (and assumes that) the Next button is on top of the
1833 * Finish button. ie. Finish comes after Next in the Z order.
1834 * This means make sure the dialog template reflects this.
1837 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1839 HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1840 HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1841 HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1843 TRACE("%ld\n", dwFlags);
1845 EnableWindow(hwndBack, FALSE);
1846 EnableWindow(hwndNext, FALSE);
1847 EnableWindow(hwndFinish, FALSE);
1849 if (dwFlags & PSWIZB_BACK)
1850 EnableWindow(hwndBack, TRUE);
1852 if (dwFlags & PSWIZB_NEXT)
1854 /* Hide the Finish button */
1855 ShowWindow(hwndFinish, SW_HIDE);
1857 /* Show and enable the Next button */
1858 ShowWindow(hwndNext, SW_SHOW);
1859 EnableWindow(hwndNext, TRUE);
1861 /* Set the Next button as the default pushbutton */
1862 SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1865 if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1867 /* Hide the Next button */
1868 ShowWindow(hwndNext, SW_HIDE);
1870 /* Show the Finish button */
1871 ShowWindow(hwndFinish, SW_SHOW);
1873 if (dwFlags & PSWIZB_FINISH)
1874 EnableWindow(hwndFinish, TRUE);
1876 /* Set the Finish button as the default pushbutton */
1877 SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1881 /******************************************************************************
1882 * PROPSHEET_GetPageIndex
1884 * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1885 * the array of PropPageInfo.
1887 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1889 BOOL found = FALSE;
1890 int index = 0;
1892 while ((index < psInfo->nPages) && (found == FALSE))
1894 if (psInfo->proppage[index].hpage == hpage)
1895 found = TRUE;
1896 else
1897 index++;
1900 if (found == FALSE)
1901 index = -1;
1903 return index;
1906 /******************************************************************************
1907 * PROPSHEET_CleanUp
1909 static void PROPSHEET_CleanUp(HWND hwndDlg)
1911 int i;
1912 PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1913 PropSheetInfoStr);
1915 TRACE("\n");
1916 if (HIWORD(psInfo->ppshheader.pszCaption))
1917 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->ppshheader.pszCaption);
1919 for (i = 0; i < psInfo->nPages; i++)
1921 PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
1923 if(psInfo->proppage[i].hwndPage)
1924 DestroyWindow(psInfo->proppage[i].hwndPage);
1926 if(psp)
1928 if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
1929 HeapFree(GetProcessHeap(), 0, (LPVOID)psInfo->proppage[i].pszText);
1931 DestroyPropertySheetPage(psInfo->proppage[i].hpage);
1935 COMCTL32_Free(psInfo->proppage);
1936 COMCTL32_Free(psInfo->strPropertiesFor);
1937 ImageList_Destroy(psInfo->hImageList);
1939 GlobalFree((HGLOBAL)psInfo);
1942 /******************************************************************************
1943 * PropertySheetA (COMCTL32.84)(COMCTL32.83)
1945 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1947 int bRet = 0;
1948 PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1949 sizeof(PropSheetInfo));
1950 int i, n;
1951 BYTE* pByte;
1953 PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1955 psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1956 lppsh->nPages);
1957 pByte = (BYTE*) psInfo->ppshheader.u3.ppsp;
1959 for (n = i = 0; i < lppsh->nPages; i++, n++)
1961 if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1962 psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
1963 else
1965 psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
1966 pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize;
1969 if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEA)psInfo->proppage[n].hpage,
1970 psInfo, n))
1972 if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
1973 DestroyPropertySheetPage(psInfo->proppage[n].hpage);
1974 n--;
1975 psInfo->nPages--;
1979 bRet = PROPSHEET_CreateDialog(psInfo);
1981 return bRet;
1984 /******************************************************************************
1985 * PropertySheetW (COMCTL32.85)
1987 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1989 FIXME("(%p): stub\n", propertySheetHeader);
1991 return -1;
1994 /******************************************************************************
1995 * CreatePropertySheetPageA (COMCTL32.19)(COMCTL32.18)
1997 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1998 LPCPROPSHEETPAGEA lpPropSheetPage)
2000 PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
2002 *ppsp = *lpPropSheetPage;
2004 if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) )
2005 ppsp->u.pszTemplate = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u.pszTemplate );
2007 if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) )
2008 ppsp->u2.pszIcon = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->u2.pszIcon );
2011 if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle ))
2012 ppsp->pszTitle = HEAP_strdupA( GetProcessHeap(), 0, lpPropSheetPage->pszTitle );
2013 else if ( !(ppsp->dwFlags & PSP_USETITLE) )
2014 ppsp->pszTitle = NULL;
2016 return (HPROPSHEETPAGE)ppsp;
2019 /******************************************************************************
2020 * CreatePropertySheetPageW (COMCTL32.20)
2022 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
2024 FIXME("(%p): stub\n", lpPropSheetPage);
2026 return 0;
2029 /******************************************************************************
2030 * DestroyPropertySheetPage (COMCTL32.24)
2032 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
2034 PROPSHEETPAGEA *psp = (PROPSHEETPAGEA *)hPropPage;
2036 if (!psp)
2037 return FALSE;
2039 if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
2040 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u.pszTemplate);
2042 if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
2043 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->u2.pszIcon);
2045 if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
2046 HeapFree(GetProcessHeap(), 0, (LPVOID)psp->pszTitle);
2048 COMCTL32_Free(hPropPage);
2050 return TRUE;
2053 /******************************************************************************
2054 * PROPSHEET_IsDialogMessage
2056 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
2058 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, PropSheetInfoStr);
2060 if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
2061 return FALSE;
2063 if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
2065 int new_page = 0;
2066 INT dlgCode = SendMessageA(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
2068 if (!(dlgCode & DLGC_WANTMESSAGE))
2070 switch (lpMsg->wParam)
2072 case VK_TAB:
2073 if (GetKeyState(VK_SHIFT) & 0x8000)
2074 new_page = -1;
2075 else
2076 new_page = 1;
2077 break;
2079 case VK_NEXT: new_page = 1; break;
2080 case VK_PRIOR: new_page = -1; break;
2084 if (new_page)
2086 if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
2088 new_page += psInfo->active_page;
2090 if (new_page < 0)
2091 new_page = psInfo->nPages - 1;
2092 else if (new_page >= psInfo->nPages)
2093 new_page = 0;
2095 PROPSHEET_SetCurSel(hwnd, new_page, 0);
2098 return TRUE;
2102 return IsDialogMessageA(hwnd, lpMsg);
2105 /******************************************************************************
2106 * PROPSHEET_DialogProc
2108 BOOL WINAPI
2109 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2111 switch (uMsg)
2113 case WM_INITDIALOG:
2115 PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
2116 char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
2117 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2118 LPCPROPSHEETPAGEA ppshpage;
2119 int idx;
2121 SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
2124 * psInfo->hwnd is not being used by WINE code - it exists
2125 * for compatibility with "real" Windoze. The same about
2126 * SetWindowLong - WINE is only using the PropSheetInfoStr
2127 * property.
2129 psInfo->hwnd = hwnd;
2130 SetWindowLongA(hwnd,DWL_USER,(LONG)psInfo);
2133 * Small icon in the title bar.
2135 if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
2136 (psInfo->ppshheader.dwFlags & PSH_USEHICON))
2138 HICON hIcon;
2139 int icon_cx = GetSystemMetrics(SM_CXSMICON);
2140 int icon_cy = GetSystemMetrics(SM_CYSMICON);
2142 if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
2143 hIcon = LoadImageA(psInfo->ppshheader.hInstance,
2144 psInfo->ppshheader.u.pszIcon,
2145 IMAGE_ICON,
2146 icon_cx, icon_cy,
2147 LR_DEFAULTCOLOR);
2148 else
2149 hIcon = psInfo->ppshheader.u.hIcon;
2151 SendMessageA(hwnd, WM_SETICON, 0, hIcon);
2154 if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
2155 SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader.u.hIcon);
2157 psInfo->strPropertiesFor = strCaption;
2159 GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
2161 PROPSHEET_CreateTabControl(hwnd, psInfo);
2163 if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
2165 if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
2167 PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
2168 PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
2171 else
2173 if (PROPSHEET_SizeMismatch(hwnd, psInfo))
2175 PROPSHEET_AdjustSize(hwnd, psInfo);
2176 PROPSHEET_AdjustButtons(hwnd, psInfo);
2180 if (psInfo->useCallback)
2181 (*(psInfo->ppshheader.pfnCallback))(hwnd,
2182 PSCB_INITIALIZED, (LPARAM)0);
2184 idx = psInfo->active_page;
2185 ppshpage = (LPCPROPSHEETPAGEA)psInfo->proppage[idx].hpage;
2186 psInfo->active_page = -1;
2188 PROPSHEET_SetCurSel(hwnd, idx, psInfo->proppage[idx].hpage);
2190 if (!(psInfo->ppshheader.dwFlags & PSH_WIZARD))
2191 SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
2193 if (!HIWORD(psInfo->ppshheader.pszCaption) &&
2194 psInfo->ppshheader.hInstance)
2196 char szText[256];
2198 if (LoadStringA(psInfo->ppshheader.hInstance,
2199 (UINT)psInfo->ppshheader.pszCaption, szText, 255))
2200 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags, szText);
2202 else
2204 PROPSHEET_SetTitleA(hwnd, psInfo->ppshheader.dwFlags,
2205 psInfo->ppshheader.pszCaption);
2208 return TRUE;
2211 case WM_DESTROY:
2212 PROPSHEET_CleanUp(hwnd);
2213 return TRUE;
2215 case WM_CLOSE:
2216 PROPSHEET_Cancel(hwnd, 1);
2217 return TRUE;
2219 case WM_COMMAND:
2221 WORD wID = LOWORD(wParam);
2223 switch (wID)
2225 case IDOK:
2226 case IDC_APPLY_BUTTON:
2228 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
2230 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
2231 break;
2233 if (wID == IDOK)
2235 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2236 PropSheetInfoStr);
2237 int result = TRUE;
2239 if (psInfo->restartWindows)
2240 result = ID_PSRESTARTWINDOWS;
2242 /* reboot system takes precedence over restart windows */
2243 if (psInfo->rebootSystem)
2244 result = ID_PSREBOOTSYSTEM;
2246 if (psInfo->isModeless)
2247 psInfo->activeValid = FALSE;
2248 else
2249 EndDialog(hwnd, result);
2251 else
2252 EnableWindow(hwndApplyBtn, FALSE);
2254 break;
2257 case IDC_BACK_BUTTON:
2258 PROPSHEET_Back(hwnd);
2259 break;
2261 case IDC_NEXT_BUTTON:
2262 PROPSHEET_Next(hwnd);
2263 break;
2265 case IDC_FINISH_BUTTON:
2266 PROPSHEET_Finish(hwnd);
2267 break;
2269 case IDCANCEL:
2270 PROPSHEET_Cancel(hwnd, 0);
2271 break;
2273 case IDHELP:
2274 PROPSHEET_Help(hwnd);
2275 break;
2278 return TRUE;
2281 case WM_NOTIFY:
2283 NMHDR* pnmh = (LPNMHDR) lParam;
2285 if (pnmh->code == TCN_SELCHANGE)
2287 int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
2288 PROPSHEET_SetCurSel(hwnd, index, 0);
2291 if(pnmh->code == TCN_SELCHANGING)
2293 BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
2294 SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
2295 return TRUE;
2298 return FALSE;
2301 case PSM_GETCURRENTPAGEHWND:
2303 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2304 PropSheetInfoStr);
2305 HWND hwndPage = 0;
2307 if (psInfo->activeValid && psInfo->active_page != -1)
2308 hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
2310 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
2312 return TRUE;
2315 case PSM_CHANGED:
2316 PROPSHEET_Changed(hwnd, (HWND)wParam);
2317 return TRUE;
2319 case PSM_UNCHANGED:
2320 PROPSHEET_UnChanged(hwnd, (HWND)wParam);
2321 return TRUE;
2323 case PSM_GETTABCONTROL:
2325 HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
2327 SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
2329 return TRUE;
2332 case PSM_SETCURSEL:
2334 BOOL msgResult;
2336 msgResult = PROPSHEET_CanSetCurSel(hwnd);
2337 if(msgResult != FALSE)
2339 msgResult = PROPSHEET_SetCurSel(hwnd,
2340 (int)wParam,
2341 (HPROPSHEETPAGE)lParam);
2344 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2346 return TRUE;
2349 case PSM_CANCELTOCLOSE:
2351 char buf[MAX_BUTTONTEXT_LENGTH];
2352 HWND hwndOK = GetDlgItem(hwnd, IDOK);
2353 HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2355 EnableWindow(hwndCancel, FALSE);
2356 if (LoadStringA(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
2357 SetWindowTextA(hwndOK, buf);
2359 return FALSE;
2362 case PSM_RESTARTWINDOWS:
2364 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2365 PropSheetInfoStr);
2367 psInfo->restartWindows = TRUE;
2368 return TRUE;
2371 case PSM_REBOOTSYSTEM:
2373 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2374 PropSheetInfoStr);
2376 psInfo->rebootSystem = TRUE;
2377 return TRUE;
2380 case PSM_SETTITLEA:
2381 PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2382 return TRUE;
2384 case PSM_APPLY:
2386 BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
2388 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2390 return TRUE;
2393 case PSM_QUERYSIBLINGS:
2395 LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2397 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2399 return TRUE;
2402 case PSM_ADDPAGE:
2405 * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
2406 * a return value. This is not true. PSM_ADDPAGE returns TRUE
2407 * on success or FALSE otherwise, as specified on MSDN Online.
2408 * Also see the MFC code for
2409 * CPropertySheet::AddPage(CPropertyPage* pPage).
2412 BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2414 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2416 return TRUE;
2419 case PSM_REMOVEPAGE:
2420 PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2421 return TRUE;
2423 case PSM_ISDIALOGMESSAGE:
2425 BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
2426 SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2427 return TRUE;
2430 case PSM_PRESSBUTTON:
2431 PROPSHEET_PressButton(hwnd, (int)wParam);
2432 return TRUE;
2434 case PSM_SETFINISHTEXTA:
2435 PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
2436 return TRUE;
2438 case PSM_SETWIZBUTTONS:
2439 PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2440 return TRUE;
2442 case PSM_SETTITLEW:
2443 FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2444 return FALSE;
2446 case PSM_SETCURSELID:
2447 FIXME("Unimplemented msg PSM_SETCURSELID\n");
2448 return FALSE;
2450 case PSM_SETFINISHTEXTW:
2451 FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2452 return FALSE;
2454 default:
2455 return FALSE;
2458 return FALSE;