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