Added missing prototypes for StrRetToBuf(A|W).
[wine] / dlls / comctl32 / propsheet.c
1 /*
2  * Property Sheets
3  *
4  * Copyright 1998 Francis Beaudet
5  * Copyright 1999 Thuy Nguyen
6  *
7  * TODO:
8  *   - Tab order
9  *   - Unicode property sheets
10  */
11
12 #include <string.h>
13 #include "winbase.h"
14 #include "commctrl.h"
15 #include "prsht.h"
16 #include "winnls.h"
17 #include "comctl32.h"
18 #include "debugtools.h"
19 #include "heap.h"
20
21
22 /******************************************************************************
23  * Data structures
24  */
25 typedef struct
26 {
27   WORD dlgVer;
28   WORD signature;
29   DWORD helpID;
30   DWORD exStyle;
31   DWORD style;
32 } MyDLGTEMPLATEEX;
33
34 typedef struct tagPropPageInfo
35 {
36   int index; /* corresponds to the index in ppshheader->ppsp */
37   HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
38   HWND hwndPage;
39   BOOL isDirty;
40   LPCWSTR pszText;
41   BOOL hasHelp;
42   BOOL useCallback;
43 } PropPageInfo;
44
45 typedef struct tagPropSheetInfo
46 {
47   LPSTR strPropertiesFor;
48   int nPages;
49   int active_page;
50   LPCPROPSHEETHEADERA ppshheader;
51   BOOL isModeless;
52   BOOL hasHelp;
53   BOOL hasApply;
54   BOOL useCallback;
55   BOOL restartWindows;
56   BOOL rebootSystem;
57   PropPageInfo* proppage;
58   int x;
59   int y;
60   int width;
61   int height;
62   HIMAGELIST hImageList;
63 } PropSheetInfo;
64
65 typedef struct
66 {
67   int x;
68   int y;
69 } PADDING_INFO;
70
71 /******************************************************************************
72  * Defines and global variables
73  */
74
75 const char * PropSheetInfoStr = "PropertySheetInfo";
76
77 #define MAX_CAPTION_LENGTH 255
78 #define MAX_TABTEXT_LENGTH 255
79
80 /******************************************************************************
81  * Prototypes
82  */
83 static BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo);
84 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo);
85 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo);
86 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo);
87 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
88                                        PropSheetInfo * psInfo);
89 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
90                                       PropSheetInfo * psInfo,
91                                       int index);
92 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
93                                        PropSheetInfo * psInfo);
94 static int PROPSHEET_CreatePage(HWND hwndParent, int index,
95                                 const PropSheetInfo * psInfo,
96                                 LPCPROPSHEETPAGEA ppshpage,
97                                 BOOL showPage);
98 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo);
99 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
100 static BOOL PROPSHEET_Back(HWND hwndDlg);
101 static BOOL PROPSHEET_Next(HWND hwndDlg);
102 static BOOL PROPSHEET_Finish(HWND hwndDlg);
103 static BOOL PROPSHEET_Apply(HWND hwndDlg);
104 static void PROPSHEET_Cancel(HWND hwndDlg);
105 static void PROPSHEET_Help(HWND hwndDlg);
106 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
107 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
108 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
109 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText);
110 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
111 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
112 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
113                                 int index,
114                                 HPROPSHEETPAGE hpage);
115 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
116                                        WPARAM wParam, LPARAM lParam);
117 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
118                                               int index);
119 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
120                               HPROPSHEETPAGE hpage);
121
122 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
123                                  int index,
124                                  HPROPSHEETPAGE hpage);
125 static void PROPSHEET_CleanUp();
126 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
127 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags);
128 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg);
129
130 BOOL WINAPI
131 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
132
133 DEFAULT_DEBUG_CHANNEL(propsheet)
134
135 /******************************************************************************
136  *            PROPSHEET_CollectSheetInfo
137  *
138  * Collect relevant data.
139  */
140 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
141                                        PropSheetInfo * psInfo)
142 {
143   DWORD dwFlags = lppsh->dwFlags;
144
145   psInfo->hasHelp = dwFlags & PSH_HASHELP;
146   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
147   psInfo->useCallback = dwFlags & PSH_USECALLBACK;
148   psInfo->isModeless = dwFlags & PSH_MODELESS;
149   psInfo->ppshheader = lppsh;
150   psInfo->nPages = lppsh->nPages;
151
152   if (dwFlags & PSH_USEPSTARTPAGE)
153   {
154     TRACE("PSH_USEPSTARTPAGE is on");
155     psInfo->active_page = 0;
156   }
157   else
158     psInfo->active_page = lppsh->u2.nStartPage;
159
160   psInfo->restartWindows = FALSE;
161   psInfo->rebootSystem = FALSE;
162   psInfo->hImageList = 0;
163
164   return TRUE;
165 }
166
167 /******************************************************************************
168  *            PROPSHEET_CollectPageInfo
169  *
170  * Collect property sheet data.
171  * With code taken from DIALOG_ParseTemplate32.
172  */
173 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
174                                PropSheetInfo * psInfo,
175                                int index)
176 {
177   DLGTEMPLATE* pTemplate;
178   const WORD*  p;
179   DWORD dwFlags;
180   int width, height;
181
182   if (psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE)
183     psInfo->proppage[index].hpage = 0;
184   psInfo->proppage[index].hwndPage = 0;
185   psInfo->proppage[index].isDirty = FALSE;
186
187   /*
188    * Process property page flags.
189    */
190   dwFlags = lppsp->dwFlags;
191   psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
192   psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
193
194   /* as soon as we have a page with the help flag, set the sheet flag on */
195   if (psInfo->proppage[index].hasHelp)
196     psInfo->hasHelp = TRUE;
197
198   /*
199    * Process page template.
200    */
201   if (dwFlags & PSP_DLGINDIRECT)
202     pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
203   else
204   {
205     HRSRC hResource = FindResourceA(lppsp->hInstance,
206                                     lppsp->u1.pszTemplate,
207                                     RT_DIALOGA);
208     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
209                                      hResource);
210     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
211   }
212
213   /*
214    * Extract the size of the page and the caption.
215    */
216   p = (const WORD *)pTemplate;
217
218   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
219   {
220     /* DIALOGEX template */
221
222     p++;       /* dlgVer    */
223     p++;       /* signature */
224     p += 2;    /* help ID   */
225     p += 2;    /* ext style */
226     p += 2;    /* style     */
227   }
228   else
229   {
230     /* DIALOG template */
231
232     p += 2;    /* style     */
233     p += 2;    /* ext style */
234   }
235
236   p++;    /* nb items */
237   p++;    /*   x      */
238   p++;    /*   y      */
239   width  = (WORD)*p; p++;
240   height = (WORD)*p; p++;
241
242   /* remember the largest width and height */
243   if (width > psInfo->width)
244     psInfo->width = width;
245
246   if (height > psInfo->height)
247     psInfo->height = height;
248
249   /* menu */
250   switch ((WORD)*p)
251   {
252     case 0x0000:
253       p++;
254       break;
255     case 0xffff:
256       p += 2;
257       break;
258     default:
259       p += lstrlenW( (LPCWSTR)p ) + 1;
260       break;
261   } 
262
263   /* class */
264   switch ((WORD)*p)
265   {
266     case 0x0000:
267       p++;
268       break;
269     case 0xffff:
270       p += 2;
271       break;
272     default:
273       p += lstrlenW( (LPCWSTR)p ) + 1;
274       break;
275   }
276
277   /* Extract the caption */
278   psInfo->proppage[index].pszText = (LPCWSTR)p;
279   TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
280   p += lstrlenW((LPCWSTR)p) + 1;
281
282   if (dwFlags & PSP_USETITLE)
283   {
284     psInfo->proppage[index].pszText = HEAP_strdupAtoW(GetProcessHeap(),
285                                                       0,
286                                                       lppsp->pszTitle);
287   }
288
289   /*
290    * Build the image list for icons
291    */
292   if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
293   {
294     HICON hIcon;
295     int icon_cx = GetSystemMetrics(SM_CXSMICON);
296     int icon_cy = GetSystemMetrics(SM_CYSMICON);
297
298     if (dwFlags & PSP_USEICONID)
299       hIcon = LoadImageA(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON, 
300                          icon_cx, icon_cy, LR_DEFAULTCOLOR);
301     else
302       hIcon = lppsp->u2.hIcon;
303
304     if (psInfo->hImageList == 0)
305       psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
306
307     ImageList_AddIcon(psInfo->hImageList, hIcon);
308   }
309
310   return TRUE;
311 }
312
313 /******************************************************************************
314  *            PROPSHEET_CreateDialog
315  *
316  * Creates the actual property sheet.
317  */
318 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
319 {
320   LRESULT ret;
321   LPCVOID template;
322   LPVOID temp = 0;
323   HRSRC hRes;
324   DWORD resSize;
325   WORD resID = IDD_PROPSHEET;
326
327   if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
328     resID = IDD_WIZARD;
329
330   if(!(hRes = FindResourceA(COMCTL32_hModule,
331                             MAKEINTRESOURCEA(resID),
332                             RT_DIALOGA)))
333     return FALSE;
334
335   if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
336     return FALSE;
337
338   /*
339    * Make a copy of the dialog template.
340    */
341   resSize = SizeofResource(COMCTL32_hModule, hRes);
342
343   temp = COMCTL32_Alloc(resSize);
344
345   if (!temp)
346     return FALSE;
347
348   memcpy(temp, template, resSize);
349
350   if (psInfo->useCallback)
351     (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
352
353   if (psInfo->ppshheader->dwFlags & PSH_MODELESS)
354     ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
355                                      (LPDLGTEMPLATEA) temp,
356                                      psInfo->ppshheader->hwndParent,
357                                      (DLGPROC) PROPSHEET_DialogProc,
358                                      (LPARAM)psInfo);
359   else
360     ret = DialogBoxIndirectParamA(psInfo->ppshheader->hInstance,
361                                   (LPDLGTEMPLATEA) temp,
362                                   psInfo->ppshheader->hwndParent,
363                                   (DLGPROC) PROPSHEET_DialogProc,
364                                   (LPARAM)psInfo);
365
366   COMCTL32_Free(temp);
367
368   return ret;
369 }
370
371 /******************************************************************************
372  *            PROPSHEET_IsTooSmall
373  * 
374  * Verify that the resource property sheet is big enough.
375  */
376 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
377 {
378   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
379   RECT rcOrigTab, rcPage;
380
381   /*
382    * Original tab size.
383    */
384   GetClientRect(hwndTabCtrl, &rcOrigTab);
385   TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
386         rcOrigTab.right, rcOrigTab.bottom);
387
388   /*
389    * Biggest page size.
390    */
391   rcPage.left   = psInfo->x;
392   rcPage.top    = psInfo->y;
393   rcPage.right  = psInfo->width;
394   rcPage.bottom = psInfo->height;
395
396   MapDialogRect(hwndDlg, &rcPage);
397   TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
398         rcPage.right, rcPage.bottom);
399
400   if (rcPage.right > rcOrigTab.right)
401     return TRUE;
402
403   if (rcPage.bottom > rcOrigTab.bottom)
404     return TRUE;
405
406   return FALSE;
407 }
408
409 /******************************************************************************
410  *            PROPSHEET_IsTooSmallWizard
411  *
412  * Verify that the default property sheet is big enough.
413  */
414 static BOOL PROPSHEET_IsTooSmallWizard(HWND hwndDlg, PropSheetInfo* psInfo)
415 {
416   RECT rcSheetRect, rcPage, rcLine, rcSheetClient;
417   HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
418   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
419
420   GetClientRect(hwndDlg, &rcSheetClient);
421   GetWindowRect(hwndDlg, &rcSheetRect);
422   GetWindowRect(hwndLine, &rcLine);
423
424   /* Remove the space below the sunken line */
425   rcSheetClient.bottom -= (rcSheetRect.bottom - rcLine.top);
426
427   /* Remove the buffer zone all around the edge */
428   rcSheetClient.bottom -= (padding.y * 2);
429   rcSheetClient.right -= (padding.x * 2);
430
431   /*
432    * Biggest page size.
433    */
434   rcPage.left   = psInfo->x;
435   rcPage.top    = psInfo->y;
436   rcPage.right  = psInfo->width;
437   rcPage.bottom = psInfo->height;
438
439   MapDialogRect(hwndDlg, &rcPage);
440   TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
441         rcPage.right, rcPage.bottom);
442
443   if (rcPage.right > rcSheetClient.right)
444     return TRUE;
445
446   if (rcPage.bottom > rcSheetClient.bottom)
447     return TRUE;
448
449   return FALSE;
450 }
451
452 /******************************************************************************
453  *            PROPSHEET_AdjustSize
454  *
455  * Resizes the property sheet and the tab control to fit the largest page.
456  */
457 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
458 {
459   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
460   HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
461   RECT rc;
462   int tabOffsetX, tabOffsetY, buttonHeight;
463   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
464
465   /* Get the height of buttons */
466   GetClientRect(hwndButton, &rc);
467   buttonHeight = rc.bottom;
468
469   /*
470    * Biggest page size.
471    */
472   rc.left   = psInfo->x;
473   rc.top    = psInfo->y;
474   rc.right  = psInfo->width;
475   rc.bottom = psInfo->height;
476
477   MapDialogRect(hwndDlg, &rc);
478
479   /*
480    * Resize the tab control.
481    */
482   SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
483
484   tabOffsetX = -(rc.left);
485   tabOffsetY = -(rc.top);
486
487   rc.right -= rc.left;
488   rc.bottom -= rc.top;
489   SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
490                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
491
492   GetClientRect(hwndTabCtrl, &rc);
493
494   TRACE("tab client rc %d %d %d %d\n",
495         rc.left, rc.top, rc.right, rc.bottom);
496
497   rc.right += ((padding.x * 2) + tabOffsetX);
498   rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
499
500   /*
501    * Resize the property sheet.
502    */
503   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
504                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
505
506   return TRUE;
507 }
508
509 /******************************************************************************
510  *            PROPSHEET_AdjustSizeWizard
511  *
512  * Resizes the property sheet to fit the largest page.
513  */
514 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
515 {
516   HWND hwndButton = GetDlgItem(hwndDlg, IDCANCEL);
517   HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
518   RECT rc;
519   int buttonHeight, lineHeight;
520   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg);
521
522   /* Get the height of buttons */
523   GetClientRect(hwndButton, &rc);
524   buttonHeight = rc.bottom;
525
526   GetClientRect(hwndLine, &rc);
527   lineHeight = rc.bottom;
528
529   /*
530    * Biggest page size.
531    */
532   rc.left   = psInfo->x;
533   rc.top    = psInfo->y;
534   rc.right  = psInfo->width;
535   rc.bottom = psInfo->height;
536
537   MapDialogRect(hwndDlg, &rc);
538
539   TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
540
541   /* Make room */
542   rc.right += (padding.x * 2);
543   rc.bottom += (buttonHeight + (5 * padding.y) + lineHeight);
544
545   /*
546    * Resize the property sheet.
547    */
548   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
549                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
550
551   return TRUE;
552 }
553
554 /******************************************************************************
555  *            PROPSHEET_AdjustButtons
556  *
557  * Adjusts the buttons' positions.
558  */
559 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
560 {
561   HWND hwndButton = GetDlgItem(hwndParent, IDOK);
562   RECT rcSheet;
563   int x, y;
564   int num_buttons = 2;
565   int buttonWidth, buttonHeight;
566   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
567
568   if (psInfo->hasApply)
569     num_buttons++;
570
571   if (psInfo->hasHelp)
572     num_buttons++;
573
574   /*
575    * Obtain the size of the buttons.
576    */
577   GetClientRect(hwndButton, &rcSheet);
578   buttonWidth = rcSheet.right;
579   buttonHeight = rcSheet.bottom;
580
581   /*
582    * Get the size of the property sheet.
583    */ 
584   GetClientRect(hwndParent, &rcSheet);
585
586   /* 
587    * All buttons will be at this y coordinate.
588    */
589   y = rcSheet.bottom - (padding.y + buttonHeight);
590
591   /*
592    * Position OK button.
593    */
594   hwndButton = GetDlgItem(hwndParent, IDOK);
595
596   x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
597
598   SetWindowPos(hwndButton, 0, x, y, 0, 0,
599                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
600
601   /*
602    * Position Cancel button.
603    */
604   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
605
606   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
607
608   SetWindowPos(hwndButton, 0, x, y, 0, 0,
609                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
610
611   /*
612    * Position Apply button.
613    */
614   hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
615
616   if (psInfo->hasApply)
617   {
618     if (psInfo->hasHelp)
619       x = rcSheet.right - ((padding.x + buttonWidth) * 2);
620     else
621       x = rcSheet.right - (padding.x + buttonWidth);
622   
623     SetWindowPos(hwndButton, 0, x, y, 0, 0,
624                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
625
626     EnableWindow(hwndButton, FALSE);
627   }
628   else
629     ShowWindow(hwndButton, SW_HIDE);
630
631   /*
632    * Position Help button.
633    */
634   hwndButton = GetDlgItem(hwndParent, IDHELP);
635
636   if (psInfo->hasHelp)
637   {
638     x = rcSheet.right - (padding.x + buttonWidth);
639   
640     SetWindowPos(hwndButton, 0, x, y, 0, 0,
641                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
642   }
643   else
644     ShowWindow(hwndButton, SW_HIDE);
645
646   return TRUE;
647 }
648
649 /******************************************************************************
650  *            PROPSHEET_AdjustButtonsWizard
651  *
652  * Adjusts the buttons' positions.
653  */
654 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
655                                           PropSheetInfo* psInfo)
656 {
657   HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
658   HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
659   RECT rcSheet;
660   int x, y;
661   int num_buttons = 3;
662   int buttonWidth, buttonHeight, lineHeight, lineWidth;
663   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
664
665   if (psInfo->hasHelp)
666     num_buttons++;
667
668   /*
669    * Obtain the size of the buttons.
670    */
671   GetClientRect(hwndButton, &rcSheet);
672   buttonWidth = rcSheet.right;
673   buttonHeight = rcSheet.bottom;
674
675   GetClientRect(hwndLine, &rcSheet);
676   lineHeight = rcSheet.bottom;
677
678   /*
679    * Get the size of the property sheet.
680    */
681   GetClientRect(hwndParent, &rcSheet);
682
683   /*
684    * All buttons will be at this y coordinate.
685    */
686   y = rcSheet.bottom - (padding.y + buttonHeight);
687
688   /*
689    * Position the Next and the Finish buttons.
690    */
691   hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
692
693   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
694
695   SetWindowPos(hwndButton, 0, x, y, 0, 0,
696                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
697
698   hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
699
700   SetWindowPos(hwndButton, 0, x, y, 0, 0,
701                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
702
703   ShowWindow(hwndButton, SW_HIDE);
704
705   /*
706    * Position the Back button.
707    */
708   hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
709
710   x -= buttonWidth;
711
712   SetWindowPos(hwndButton, 0, x, y, 0, 0,
713                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
714
715   /*
716    * Position the Cancel button.
717    */
718   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
719
720   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2));
721
722   SetWindowPos(hwndButton, 0, x, y, 0, 0,
723                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
724
725   /*
726    * Position Help button.
727    */
728   hwndButton = GetDlgItem(hwndParent, IDHELP);
729
730   if (psInfo->hasHelp)
731   {
732     x = rcSheet.right - (padding.x + buttonWidth);
733
734     SetWindowPos(hwndButton, 0, x, y, 0, 0,
735                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
736   }
737   else
738     ShowWindow(hwndButton, SW_HIDE);
739
740   /*
741    * Position and resize the sunken line.
742    */
743   x = padding.x;
744   y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
745
746   GetClientRect(hwndParent, &rcSheet);
747   lineWidth = rcSheet.right - (padding.x * 2);
748
749   SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
750                SWP_NOZORDER | SWP_NOACTIVATE);
751
752   return TRUE;
753 }
754
755 /******************************************************************************
756  *            PROPSHEET_GetPaddingInfo
757  *
758  * Returns the layout information.
759  */
760 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
761 {
762   HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
763   RECT rcTab;
764   POINT tl;
765   PADDING_INFO padding;
766
767   GetWindowRect(hwndTab, &rcTab);
768
769   tl.x = rcTab.left;
770   tl.y = rcTab.top;
771
772   ScreenToClient(hwndDlg, &tl);
773
774   padding.x = tl.x;
775   padding.y = tl.y;
776
777   return padding;
778 }
779
780 /******************************************************************************
781  *            PROPSHEET_GetPaddingInfoWizard
782  *
783  * Returns the layout information.
784  * Horizontal spacing is the distance between the Cancel and Help buttons.
785  * Vertical spacing is the distance between the line and the buttons.
786  */
787 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg)
788 {
789   PADDING_INFO padding;
790   RECT rc;
791   HWND hwndControl;
792   POINT ptHelp, ptCancel, ptLine;
793
794   /* Help button */
795   hwndControl = GetDlgItem(hwndDlg, IDHELP);
796   GetWindowRect(hwndControl, &rc);
797
798   ptHelp.x = rc.left;
799   ptHelp.y = rc.top;
800
801   ScreenToClient(hwndDlg, &ptHelp);
802
803   /* Cancel button */
804   hwndControl = GetDlgItem(hwndDlg, IDCANCEL);
805   GetWindowRect(hwndControl, &rc);
806
807   ptCancel.x = rc.right;
808   ptCancel.y = rc.top;
809
810   ScreenToClient(hwndDlg, &ptCancel);
811
812   /* Line */
813   hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
814   GetWindowRect(hwndControl, &rc);
815
816   ptLine.x = 0;
817   ptLine.y = rc.bottom;
818
819   ScreenToClient(hwndDlg, &ptLine);
820
821   padding.x = ptHelp.x - ptCancel.x;
822   padding.y = ptHelp.y - ptLine.y;
823
824   return padding;
825 }
826
827 /******************************************************************************
828  *            PROPSHEET_CreateTabControl
829  *
830  * Insert the tabs in the tab control.
831  */
832 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
833                                        PropSheetInfo * psInfo)
834 {
835   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
836   TCITEMA item;
837   int i, nTabs;
838   char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
839
840   item.mask = TCIF_TEXT;
841   item.pszText = tabtext;
842   item.cchTextMax = MAX_TABTEXT_LENGTH;
843
844   nTabs = psInfo->ppshheader->nPages;
845
846   /*
847    * Set the image list for icons.
848    */
849   if (psInfo->hImageList)
850   {
851     item.mask |= TCIF_IMAGE;
852     SendMessageA(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
853   }
854
855   for (i = 0; i < nTabs; i++)
856   {
857     item.iImage = i;
858
859     WideCharToMultiByte(CP_ACP, 0,
860                         (LPCWSTR)psInfo->proppage[i].pszText,
861                         -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
862
863     SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
864   }
865
866   return TRUE;
867 }
868
869 /******************************************************************************
870  *            PROPSHEET_CreatePage
871  *
872  * Creates a page.
873  */
874 static int PROPSHEET_CreatePage(HWND hwndParent,
875                                 int index,
876                                 const PropSheetInfo * psInfo,
877                                 LPCPROPSHEETPAGEA ppshpage,
878                                 BOOL showPage)
879 {
880   DLGTEMPLATE* pTemplate;
881   HWND hwndPage;
882   RECT rc;
883   PropPageInfo* ppInfo = psInfo->proppage;
884   PADDING_INFO padding;
885   HWND hwndAfter;
886
887   TRACE("index %d\n", index);
888
889   if (ppshpage->dwFlags & PSP_DLGINDIRECT)
890     pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
891   else
892   {
893     HRSRC hResource = FindResourceA(ppshpage->hInstance,
894                                     ppshpage->u1.pszTemplate,
895                                     RT_DIALOGA);
896     HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
897     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
898   }
899
900   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
901   {
902     ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD;
903     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
904     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
905     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
906     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
907     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
908   }
909   else
910   {
911     pTemplate->style |= WS_CHILD;
912     pTemplate->style &= ~DS_MODALFRAME;
913     pTemplate->style &= ~WS_CAPTION;
914     pTemplate->style &= ~WS_SYSMENU;
915     pTemplate->style &= ~WS_POPUP;
916     pTemplate->style &= ~WS_DISABLED;
917   }
918
919   if (psInfo->proppage[index].useCallback)
920     (*(ppshpage->pfnCallback))(hwndParent,
921                                PSPCB_CREATE,
922                                (LPPROPSHEETPAGEA)ppshpage);
923
924   hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
925                                         pTemplate,
926                                         hwndParent,
927                                         ppshpage->pfnDlgProc,
928                                         (LPARAM)ppshpage);
929
930   ppInfo[index].hwndPage = hwndPage;
931
932   rc.left = psInfo->x;
933   rc.top = psInfo->y;
934   rc.right = psInfo->width;
935   rc.bottom = psInfo->height;
936
937   MapDialogRect(hwndParent, &rc);
938
939   if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
940   {
941     GetWindowRect(hwndParent, &rc);
942     padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);
943     hwndAfter = hwndParent;
944   }
945   else
946   {
947     /*
948      * Ask the Tab control to fit this page in.
949      */
950
951     HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
952     SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
953     padding = PROPSHEET_GetPaddingInfo(hwndParent);
954     hwndAfter = HWND_TOP;
955   }
956
957   SetWindowPos(hwndPage, hwndAfter,
958                rc.left + padding.x,
959                rc.top + padding.y,
960                0, 0, SWP_NOSIZE);
961
962   if (showPage)
963   {
964     NMHDR hdr;
965
966     hdr.hwndFrom = hwndParent;
967     hdr.code = PSN_SETACTIVE;
968
969     /*
970      * Send the notification before showing the page.
971      */
972     SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
973
974     ShowWindow(hwndPage, SW_SHOW);
975   }
976   else
977     ShowWindow(hwndPage, SW_HIDE);
978
979   return TRUE;
980 }
981
982 /******************************************************************************
983  *            PROPSHEET_ShowPage
984  *
985  * Displays or creates the specified page.
986  */
987 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
988 {
989   if (index == psInfo->active_page)
990     return TRUE;
991
992   ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
993
994   if (psInfo->proppage[index].hwndPage != 0)
995     ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
996   else
997   {
998     LPCPROPSHEETPAGEA ppshpage = PROPSHEET_GetPSPPage(psInfo, index);
999     PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage, TRUE);
1000   }
1001
1002   psInfo->active_page = index;
1003
1004   return TRUE;
1005 }
1006
1007 /******************************************************************************
1008  *            PROPSHEET_Back
1009  */
1010 static BOOL PROPSHEET_Back(HWND hwndDlg)
1011 {
1012   BOOL res;
1013   NMHDR hdr;
1014   HWND hwndPage;
1015   HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1016   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1017                                                     PropSheetInfoStr);
1018
1019   hdr.code = PSN_WIZBACK;
1020
1021   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1022
1023   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) == -1)
1024     return FALSE;
1025
1026   res = PROPSHEET_CanSetCurSel(hwndDlg);
1027   if(res != FALSE)
1028   {
1029     res = PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page - 1, 0);
1030   }
1031
1032   /* if we went to page 0, disable Back button */
1033   if (res && (psInfo->active_page == 0))
1034     EnableWindow(hwndBack, FALSE);
1035
1036   return TRUE;
1037 }
1038
1039 /******************************************************************************
1040  *            PROPSHEET_Next
1041  */
1042 static BOOL PROPSHEET_Next(HWND hwndDlg)
1043 {
1044   NMHDR hdr;
1045   HWND hwndPage;
1046   LRESULT msgResult = 0;
1047   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1048                                                     PropSheetInfoStr);
1049
1050   hdr.code = PSN_WIZNEXT;
1051
1052   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1053
1054   msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1055
1056   TRACE("msg result %ld\n", msgResult);
1057
1058   if (msgResult == -1)
1059     return FALSE;
1060
1061   if(PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1062   {
1063     PROPSHEET_SetCurSel(hwndDlg, psInfo->active_page + 1, 0);
1064   }
1065
1066   return TRUE;
1067 }
1068
1069 /******************************************************************************
1070  *            PROPSHEET_Finish
1071  */
1072 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1073 {
1074   NMHDR hdr;
1075   HWND hwndPage;
1076   LRESULT msgResult = 0;
1077   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1078                                                     PropSheetInfoStr);
1079
1080   hdr.code = PSN_WIZFINISH;
1081
1082   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1083
1084   msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1085
1086   TRACE("msg result %ld\n", msgResult);
1087
1088   if (msgResult != 0)
1089     return FALSE;
1090
1091   if (psInfo->isModeless)
1092     psInfo->active_page = -1;
1093   else
1094     EndDialog(hwndDlg, TRUE);
1095
1096   return TRUE;
1097 }
1098
1099 /******************************************************************************
1100  *            PROPSHEET_Apply
1101  */
1102 static BOOL PROPSHEET_Apply(HWND hwndDlg)
1103 {
1104   int i;
1105   NMHDR hdr;
1106   HWND hwndPage;
1107   LRESULT msgResult;
1108   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1109                                                     PropSheetInfoStr);
1110
1111   hdr.hwndFrom = hwndDlg;
1112
1113   /*
1114    * Send PSN_KILLACTIVE to the current page.
1115    */
1116   hdr.code = PSN_KILLACTIVE;
1117
1118   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1119
1120   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) != FALSE)
1121     return FALSE;
1122
1123   /*
1124    * Send PSN_APPLY to all pages.
1125    */
1126   hdr.code = PSN_APPLY;
1127
1128   for (i = 0; i < psInfo->nPages; i++)
1129   {
1130     hwndPage = psInfo->proppage[i].hwndPage;
1131     msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1132
1133     if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
1134       return FALSE;
1135   }
1136
1137   return TRUE;
1138 }
1139
1140 /******************************************************************************
1141  *            PROPSHEET_Cancel
1142  */
1143 static void PROPSHEET_Cancel(HWND hwndDlg)
1144 {
1145   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1146                                                     PropSheetInfoStr);
1147   HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1148   NMHDR hdr;
1149
1150   hdr.hwndFrom = hwndDlg;
1151   hdr.code = PSN_QUERYCANCEL;
1152
1153   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
1154     return;
1155
1156   hdr.code = PSN_RESET;
1157
1158   SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1159
1160   if (psInfo->isModeless)
1161     psInfo->active_page = -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
1162   else
1163     EndDialog(hwndDlg, FALSE);
1164 }
1165
1166 /******************************************************************************
1167  *            PROPSHEET_Help
1168  */
1169 static void PROPSHEET_Help(HWND hwndDlg)
1170 {
1171   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1172                                                     PropSheetInfoStr);
1173   HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1174   NMHDR hdr;
1175
1176   hdr.hwndFrom = hwndDlg;
1177   hdr.code = PSN_HELP;
1178
1179   SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1180 }
1181
1182 /******************************************************************************
1183  *            PROPSHEET_Changed
1184  */
1185 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1186 {
1187   int i;
1188   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1189                                                     PropSheetInfoStr);
1190
1191   if (!psInfo) return;
1192   /*
1193    * Set the dirty flag of this page.
1194    */
1195   for (i = 0; i < psInfo->nPages; i++)
1196   {
1197     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1198       psInfo->proppage[i].isDirty = TRUE;
1199   }
1200
1201   /*
1202    * Enable the Apply button.
1203    */
1204   if (psInfo->hasApply)
1205   {
1206     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1207
1208     EnableWindow(hwndApplyBtn, TRUE);
1209   }
1210 }
1211
1212 /******************************************************************************
1213  *            PROPSHEET_UnChanged
1214  */
1215 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1216 {
1217   int i;
1218   BOOL noPageDirty = TRUE;
1219   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1220   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1221                                                     PropSheetInfoStr);
1222
1223   for (i = 0; i < psInfo->nPages; i++)
1224   {
1225     /* set the specified page as clean */
1226     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1227       psInfo->proppage[i].isDirty = FALSE;
1228
1229     /* look to see if there's any dirty pages */
1230     if (psInfo->proppage[i].isDirty)
1231       noPageDirty = FALSE;
1232   }
1233
1234   /*
1235    * Disable Apply button.
1236    */
1237   if (noPageDirty)
1238     EnableWindow(hwndApplyBtn, FALSE);
1239 }
1240
1241 /******************************************************************************
1242  *            PROPSHEET_PressButton
1243  */
1244 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1245 {
1246   switch (buttonID)
1247   {
1248     case PSBTN_APPLYNOW:
1249       SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
1250       break;
1251     case PSBTN_BACK:
1252       PROPSHEET_Back(hwndDlg);
1253       break;
1254     case PSBTN_CANCEL:
1255       SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
1256       break;
1257     case PSBTN_FINISH:
1258       PROPSHEET_Finish(hwndDlg);
1259       break;
1260     case PSBTN_HELP:
1261       SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
1262       break;
1263     case PSBTN_NEXT:
1264       PROPSHEET_Next(hwndDlg);
1265       break;
1266     case PSBTN_OK:
1267       SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
1268       break;
1269     default:
1270       FIXME("Invalid button index %d\n", buttonID);
1271   }
1272 }
1273
1274
1275 /*************************************************************************
1276  * BOOL PROPSHEET_CanSetCurSel [Internal] 
1277  *
1278  * Test weither the current page can be change by sending a PSN_KILLACTIVE
1279  *
1280  * PARAMS
1281  *     hwndDlg        [I] handle to a Dialog hWnd
1282  *
1283  * RETURNS
1284  *     TRUE if Current Selection can change
1285  *
1286  * NOTES
1287  */
1288 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1289 {
1290   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1291                                                     PropSheetInfoStr);
1292   HWND hwndPage;
1293   NMHDR hdr;
1294   /*
1295    * Notify the current page.
1296    */
1297   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1298
1299   hdr.hwndFrom = hwndDlg;
1300   hdr.code = PSN_KILLACTIVE;
1301
1302   return !SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1303 }
1304
1305 /******************************************************************************
1306  *            PROPSHEET_SetCurSel
1307  */
1308 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
1309                                 int index,
1310                                 HPROPSHEETPAGE hpage)
1311 {
1312   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1313                                                     PropSheetInfoStr);
1314   HWND hwndPage;
1315   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
1316   NMHDR hdr;
1317
1318   /*
1319    * Notify the current page.
1320    */
1321   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1322
1323   hdr.hwndFrom = hwndDlg;
1324   hdr.code = PSN_KILLACTIVE;
1325
1326   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
1327     return FALSE;
1328
1329   /*
1330    * hpage takes precedence over index.
1331    */
1332   if (hpage != NULL)
1333   {
1334     index = PROPSHEET_GetPageIndex(hpage, psInfo);
1335
1336     if (index == -1)
1337     {
1338       TRACE("Could not find page to remove!\n");
1339       return FALSE;
1340     }
1341   }
1342
1343   hwndPage = psInfo->proppage[index].hwndPage;
1344
1345   /*
1346    * Notify the new page if it's already created.
1347    * If not it will get created and notified in PROPSHEET_ShowPage.
1348    */
1349   if (hwndPage)
1350   {
1351     int result;
1352     hdr.code = PSN_SETACTIVE;
1353
1354     result = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
1355     /*
1356      * TODO: check return value. 
1357      */
1358   }
1359
1360   /*
1361    * Display the new page.
1362    */
1363   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
1364
1365   if (psInfo->proppage[index].hasHelp)
1366     EnableWindow(hwndHelp, TRUE);
1367   else
1368     EnableWindow(hwndHelp, FALSE);
1369
1370   return TRUE;
1371 }
1372
1373 /******************************************************************************
1374  *            PROPSHEET_SetTitleA
1375  */
1376 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
1377 {
1378   if (dwStyle & PSH_PROPTITLE)
1379   {
1380     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1381                                                       PropSheetInfoStr);
1382     char* dest;
1383     int lentitle = strlen(lpszText);
1384     int lenprop  = strlen(psInfo->strPropertiesFor);
1385
1386     dest = COMCTL32_Alloc(lentitle + lenprop + 1);
1387     strcpy(dest, psInfo->strPropertiesFor);
1388     strcat(dest, lpszText);
1389
1390     SetWindowTextA(hwndDlg, dest);
1391     COMCTL32_Free(dest);
1392   }
1393   else
1394     SetWindowTextA(hwndDlg, lpszText);
1395 }
1396
1397 /******************************************************************************
1398  *            PROPSHEET_SetFinishTextA
1399  */
1400 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
1401 {
1402   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1403
1404   /* Set text, show and enable the Finish button */
1405   SetWindowTextA(hwndButton, lpszText);
1406   ShowWindow(hwndButton, SW_SHOW);
1407   EnableWindow(hwndButton, TRUE);
1408
1409   /* Make it default pushbutton */
1410   SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1411
1412   /* Hide Back button */
1413   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1414   ShowWindow(hwndButton, SW_HIDE);
1415
1416   /* Hide Next button */
1417   hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1418   ShowWindow(hwndButton, SW_HIDE);
1419 }
1420
1421 /******************************************************************************
1422  *            PROPSHEET_QuerySiblings
1423  */
1424 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
1425                                        WPARAM wParam, LPARAM lParam)
1426 {
1427   int i = 0;
1428   HWND hwndPage;
1429   LRESULT msgResult = 0;
1430   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1431                                                     PropSheetInfoStr);
1432
1433   while ((i < psInfo->nPages) && (msgResult == 0))
1434   {
1435     hwndPage = psInfo->proppage[i].hwndPage;
1436     msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
1437     i++;
1438   }
1439
1440   return msgResult;
1441 }
1442
1443 /******************************************************************************
1444  *            PROPSHEET_GetPSPPage
1445  */
1446 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
1447                                               int index)
1448 {
1449   BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
1450   LPCPROPSHEETPAGEA lppsp;
1451   int realIndex = psInfo->proppage[index].index;
1452
1453   if (usePSP)
1454   {
1455     BYTE* pByte;
1456
1457     lppsp = psInfo->ppshheader->u3.ppsp;
1458
1459     pByte = (BYTE*) lppsp;
1460
1461     pByte += (lppsp->dwSize * realIndex);
1462     lppsp = (LPCPROPSHEETPAGEA)pByte;
1463   }
1464   else
1465     lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
1466
1467   return lppsp;
1468 }
1469
1470 /******************************************************************************
1471  *            PROPSHEET_AddPage
1472  */
1473 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
1474                               HPROPSHEETPAGE hpage)
1475 {
1476   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1477                                                      PropSheetInfoStr);
1478   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1479   TCITEMA item;
1480   char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
1481   LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
1482
1483   /*
1484    * Allocate and fill in a new PropPageInfo entry.
1485    */
1486   psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
1487                                                       sizeof(PropPageInfo) *
1488                                                       (psInfo->nPages + 1));
1489
1490   PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
1491   psInfo->proppage[psInfo->nPages].index = -1;
1492   psInfo->proppage[psInfo->nPages].hpage = hpage;
1493
1494   /*
1495    * Create the page but don't show it.
1496    */
1497   PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
1498
1499   /*
1500    * Add a new tab to the tab control.
1501    */
1502   item.mask = TCIF_TEXT;
1503   item.pszText = tabtext;
1504   item.cchTextMax = MAX_TABTEXT_LENGTH;
1505
1506   WideCharToMultiByte(CP_ACP, 0,
1507                       (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1508                       -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1509
1510   SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1511                (LPARAM)&item);
1512
1513   psInfo->nPages++;
1514
1515   return FALSE;
1516 }
1517
1518 /******************************************************************************
1519  *            PROPSHEET_RemovePage
1520  */
1521 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1522                                  int index,
1523                                  HPROPSHEETPAGE hpage)
1524 {
1525   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1526                                                      PropSheetInfoStr);
1527   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1528   PropPageInfo* oldPages;
1529
1530   if (!psInfo) {
1531     FIXME("No psInfo for propertysheet at windows 0x%04x? returning FALSE...\n");
1532     return FALSE;
1533   }
1534   oldPages = psInfo->proppage;
1535   /*
1536    * hpage takes precedence over index.
1537    */
1538   if (hpage != 0)
1539   {
1540     index = PROPSHEET_GetPageIndex(hpage, psInfo);
1541
1542     if (index == -1)
1543     {
1544       TRACE("Could not find page to remove!\n");
1545       return FALSE;
1546     }
1547   }
1548
1549   TRACE("total pages %d removing page %d active page %d\n",
1550         psInfo->nPages, index, psInfo->active_page);
1551   /*
1552    * Check if we're removing the active page.
1553    */
1554   if (index == psInfo->active_page)
1555   {
1556     if (psInfo->nPages > 1)
1557     {
1558       if (index > 0)
1559       {
1560         /* activate previous page  */
1561         PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1562       }
1563       else
1564       {
1565         /* activate the next page */
1566         PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1567       }
1568     }
1569     else
1570     {
1571       TRACE("Removing the only page, close the dialog!\n");
1572
1573       if (psInfo->isModeless)
1574         psInfo->active_page = -1;
1575       else
1576         EndDialog(hwndDlg, FALSE);
1577
1578       return TRUE;
1579     }
1580   }
1581
1582   if (index < psInfo->active_page)
1583     psInfo->active_page--;
1584
1585   /* Remove the tab */
1586   SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1587
1588   psInfo->nPages--;
1589   psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1590
1591   if (index > 0)  
1592     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1593
1594   if (index < psInfo->nPages)
1595     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1596            (psInfo->nPages - index) * sizeof(PropPageInfo));
1597
1598   COMCTL32_Free(oldPages);
1599
1600   return FALSE;
1601 }
1602
1603 /******************************************************************************
1604  *            PROPSHEET_SetWizButtons
1605  *
1606  * This code will work if (and assumes that) the Next button is on top of the
1607  * Finish button. ie. Finish comes after Next in the Z order.
1608  * This means make sure the dialog template reflects this.
1609  *
1610  */
1611 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
1612 {
1613   HWND hwndButton;
1614
1615   TRACE("%ld\n", dwFlags);
1616
1617   if (dwFlags & PSWIZB_BACK)
1618   {
1619     hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
1620     EnableWindow(hwndButton, TRUE);
1621   }
1622
1623   if (dwFlags & PSWIZB_NEXT)
1624   {
1625     /* Hide the Finish button */
1626     hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1627     ShowWindow(hwndButton, SW_HIDE);
1628
1629     /* Show and enable the Next button */
1630     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1631     
1632     ShowWindow(hwndButton, SW_SHOW);
1633     EnableWindow(hwndButton, TRUE);
1634
1635     /* Set the Next button as the default pushbutton  */
1636     SendMessageA(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
1637   }
1638
1639   if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
1640   {
1641     /* Hide the Next button */
1642     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
1643     ShowWindow(hwndButton, SW_HIDE);
1644
1645     /* Show the Finish button */
1646     hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
1647     ShowWindow(hwndButton, SW_SHOW);
1648
1649     if (dwFlags & PSWIZB_FINISH)
1650       EnableWindow(hwndButton, TRUE);
1651     else
1652       EnableWindow(hwndButton, FALSE);
1653
1654     /* Set the Finish button as the default pushbutton  */
1655     SendMessageA(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
1656   }
1657 }
1658
1659 /******************************************************************************
1660  *            PROPSHEET_GetPageIndex
1661  *
1662  * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1663  * the array of PropPageInfo.
1664  */
1665 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1666 {
1667   BOOL found = FALSE;
1668   int index = 0;
1669
1670   while ((index < psInfo->nPages) && (found == FALSE))
1671   {
1672     if (psInfo->proppage[index].hpage == hpage)
1673       found = TRUE;
1674     else
1675       index++;
1676   }
1677
1678   if (found == FALSE)
1679     index = -1;
1680
1681   return index;
1682 }
1683
1684 /******************************************************************************
1685  *            PROPSHEET_CleanUp
1686  */
1687 static void PROPSHEET_CleanUp(HWND hwndDlg)
1688 {
1689   PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1690                                                        PropSheetInfoStr);
1691
1692   TRACE("\n");
1693   COMCTL32_Free(psInfo->proppage);
1694   COMCTL32_Free(psInfo->strPropertiesFor);
1695   ImageList_Destroy(psInfo->hImageList);
1696
1697   GlobalFree((HGLOBAL)psInfo);
1698 }
1699
1700 /******************************************************************************
1701  *            PropertySheetA   (COMCTL32.84)(COMCTL32.83)
1702  */
1703 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1704 {
1705   int bRet = 0;
1706   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1707                                                        sizeof(PropSheetInfo));
1708   LPCPROPSHEETPAGEA lppsp;
1709   int i;
1710
1711   PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1712
1713   psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1714                                                     lppsh->nPages);
1715
1716   for (i = 0; i < lppsh->nPages; i++)
1717   {
1718     psInfo->proppage[i].index = i;
1719     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1720       psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1721     lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1722     PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1723   }
1724
1725   bRet = PROPSHEET_CreateDialog(psInfo);
1726
1727   return bRet;
1728 }
1729
1730 /******************************************************************************
1731  *            PropertySheet32W   (COMCTL32.85)
1732  */
1733 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1734 {
1735     FIXME("(%p): stub\n", propertySheetHeader);
1736
1737     return -1;
1738 }
1739
1740 /******************************************************************************
1741  *            CreatePropertySheetPageA   (COMCTL32.19)(COMCTL32.18)
1742  */
1743 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1744                           LPCPROPSHEETPAGEA lpPropSheetPage)
1745 {
1746   PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1747
1748   *ppsp = *lpPropSheetPage;
1749
1750   return (HPROPSHEETPAGE)ppsp;
1751 }
1752
1753 /******************************************************************************
1754  *            CreatePropertySheetPageW   (COMCTL32.20)
1755  */
1756 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1757 {
1758     FIXME("(%p): stub\n", lpPropSheetPage);
1759
1760     return 0;
1761 }
1762
1763 /******************************************************************************
1764  *            DestroyPropertySheetPage   (COMCTL32.24)
1765  */
1766 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1767 {
1768   COMCTL32_Free(hPropPage);
1769
1770   return TRUE;
1771 }
1772
1773 /******************************************************************************
1774  *            PROPSHEET_DialogProc
1775  */
1776 BOOL WINAPI
1777 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1778 {
1779   switch (uMsg)
1780   {
1781     case WM_INITDIALOG:
1782     {
1783       PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1784       char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1785       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1786       LPCPROPSHEETPAGEA ppshpage;
1787
1788       /*
1789        * Small icon in the title bar.
1790        */
1791       if ((psInfo->ppshheader->dwFlags & PSH_USEICONID) ||
1792           (psInfo->ppshheader->dwFlags & PSH_USEHICON))
1793       {
1794         HICON hIcon;
1795         int icon_cx = GetSystemMetrics(SM_CXSMICON);
1796         int icon_cy = GetSystemMetrics(SM_CYSMICON);
1797
1798         if (psInfo->ppshheader->dwFlags & PSH_USEICONID)
1799           hIcon = LoadImageA(psInfo->ppshheader->hInstance,
1800                              psInfo->ppshheader->u1.pszIcon,
1801                              IMAGE_ICON,
1802                              icon_cx, icon_cy,
1803                              LR_DEFAULTCOLOR);
1804         else
1805           hIcon = psInfo->ppshheader->u1.hIcon;
1806
1807         SendMessageA(hwnd, WM_SETICON, 0, hIcon);
1808       }
1809       
1810       if (psInfo->ppshheader->dwFlags & PSH_USEHICON)
1811         SendMessageA(hwnd, WM_SETICON, 0, psInfo->ppshheader->u1.hIcon);
1812
1813       psInfo->strPropertiesFor = strCaption;
1814
1815       GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1816
1817       if (psInfo->ppshheader->dwFlags & PSH_WIZARD)
1818       {
1819         HWND hwndBack = GetDlgItem(hwnd, IDC_BACK_BUTTON);
1820
1821         if (PROPSHEET_IsTooSmallWizard(hwnd, psInfo))
1822         {
1823           PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
1824           PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
1825         }
1826
1827         /* Disable Back button if we start at page 0 */
1828         if (psInfo->active_page == 0)
1829           EnableWindow(hwndBack, FALSE);
1830       }
1831       else
1832       {
1833         PROPSHEET_CreateTabControl(hwnd, psInfo);
1834
1835         if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1836         {
1837           PROPSHEET_AdjustSize(hwnd, psInfo);
1838           PROPSHEET_AdjustButtons(hwnd, psInfo);
1839         }
1840       }
1841
1842       ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);      
1843       PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1844
1845       if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
1846         SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1847
1848       SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1849
1850       PROPSHEET_SetTitleA(hwnd,
1851                           psInfo->ppshheader->dwFlags,
1852                           psInfo->ppshheader->pszCaption);
1853
1854       return TRUE;
1855     }
1856
1857     case WM_DESTROY:
1858       PROPSHEET_CleanUp(hwnd);
1859       return TRUE;
1860
1861     case WM_CLOSE:
1862       PROPSHEET_Cancel(hwnd);
1863       return TRUE;
1864
1865     case WM_COMMAND:
1866     {
1867       WORD wID = LOWORD(wParam);
1868
1869       switch (wID)
1870       {
1871         case IDOK:
1872         case IDC_APPLY_BUTTON:
1873         {
1874           HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1875
1876           if (PROPSHEET_Apply(hwnd) == FALSE)
1877             break;
1878
1879           EnableWindow(hwndApplyBtn, FALSE);
1880
1881           if (wID == IDOK)
1882           {
1883             PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1884                                                             PropSheetInfoStr);
1885             int result = TRUE;
1886
1887             if (psInfo->restartWindows)
1888               result = ID_PSRESTARTWINDOWS;
1889
1890             /* reboot system takes precedence over restart windows */
1891             if (psInfo->rebootSystem)
1892               result = ID_PSREBOOTSYSTEM;
1893
1894             if (psInfo->isModeless)
1895               psInfo->active_page = -1;
1896             else
1897               EndDialog(hwnd, result);
1898           }
1899
1900           break;
1901         }
1902
1903         case IDC_BACK_BUTTON:
1904           PROPSHEET_Back(hwnd);
1905           break;
1906
1907         case IDC_NEXT_BUTTON:
1908           PROPSHEET_Next(hwnd);
1909           break;
1910
1911         case IDC_FINISH_BUTTON:
1912           PROPSHEET_Finish(hwnd);
1913           break;
1914
1915         case IDCANCEL:
1916           PROPSHEET_Cancel(hwnd);
1917           break;
1918
1919         case IDHELP:
1920           PROPSHEET_Help(hwnd);
1921           break;
1922       }
1923
1924       return TRUE;
1925     }
1926
1927     case WM_NOTIFY:
1928     {
1929       NMHDR* pnmh = (LPNMHDR) lParam;
1930
1931       if (pnmh->code == TCN_SELCHANGE)
1932       {
1933         int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1934         PROPSHEET_SetCurSel(hwnd, index, 0);
1935       }
1936
1937       if(pnmh->code == TCN_SELCHANGING)
1938       {
1939         BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
1940         SetWindowLongA(hwnd, DWL_MSGRESULT, !bRet);
1941         return TRUE;
1942       }
1943
1944
1945       return 0;
1946     }
1947
1948     case PSM_GETCURRENTPAGEHWND:
1949     {
1950       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1951                                                         PropSheetInfoStr);
1952       HWND hwndPage = 0;
1953
1954       if (psInfo->active_page != -1)
1955         hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1956
1957       SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1958
1959       return TRUE;
1960     }
1961
1962     case PSM_CHANGED:
1963       PROPSHEET_Changed(hwnd, (HWND)wParam);
1964       return TRUE;
1965
1966     case PSM_UNCHANGED:
1967       PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1968       return TRUE;
1969
1970     case PSM_GETTABCONTROL:
1971     {
1972       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1973
1974       SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1975
1976       return TRUE;
1977     }
1978
1979     case PSM_SETCURSEL:
1980     {
1981       BOOL msgResult;
1982
1983       msgResult = PROPSHEET_CanSetCurSel(hwnd);
1984       if(msgResult != FALSE)
1985       {
1986         msgResult = PROPSHEET_SetCurSel(hwnd,
1987                                        (int)wParam,
1988                                        (HPROPSHEETPAGE)lParam);
1989       }
1990
1991       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1992
1993       return TRUE;
1994     }
1995
1996     case PSM_CANCELTOCLOSE:
1997     {
1998       HWND hwndOK = GetDlgItem(hwnd, IDOK);
1999       HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
2000
2001       EnableWindow(hwndCancel, FALSE);
2002       SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
2003
2004       return TRUE;
2005     }
2006
2007     case PSM_RESTARTWINDOWS:
2008     {
2009       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
2010                                                         PropSheetInfoStr);
2011
2012       psInfo->restartWindows = TRUE;
2013       return TRUE;
2014     }
2015
2016     case PSM_REBOOTSYSTEM:
2017     {
2018       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, 
2019                                                         PropSheetInfoStr);
2020
2021       psInfo->rebootSystem = TRUE;
2022       return TRUE;
2023     }
2024
2025     case PSM_SETTITLEA:
2026       PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
2027       return TRUE;
2028
2029     case PSM_APPLY:
2030     {
2031       BOOL msgResult = PROPSHEET_Apply(hwnd);
2032
2033       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2034
2035       return TRUE;
2036     }
2037
2038     case PSM_QUERYSIBLINGS:
2039     {
2040       LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
2041
2042       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
2043
2044       return TRUE;
2045     }
2046
2047     case PSM_ADDPAGE:
2048       PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
2049       return TRUE;
2050
2051     case PSM_REMOVEPAGE:
2052       PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
2053       return TRUE;
2054
2055     case PSM_ISDIALOGMESSAGE:
2056     {
2057       FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
2058       return 0;
2059     }
2060
2061     case PSM_PRESSBUTTON:
2062       PROPSHEET_PressButton(hwnd, (int)wParam);
2063       return TRUE;
2064
2065     case PSM_SETFINISHTEXTA:
2066       PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);        
2067       return TRUE;
2068
2069     case PSM_SETWIZBUTTONS:
2070       PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
2071       return TRUE;
2072
2073     case PSM_SETTITLEW:
2074         FIXME("Unimplemented msg PSM_SETTITLE32W\n");
2075         return 0;
2076     case PSM_SETCURSELID:
2077         FIXME("Unimplemented msg PSM_SETCURSELID\n");
2078         return 0;
2079     case PSM_SETFINISHTEXTW:
2080         FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
2081         return 0;
2082
2083     default:
2084       return FALSE;
2085   }
2086 }
2087