Compiler warnings fix.
[wine] / dlls / comctl32 / propsheet.c
1 /*
2  * Property Sheets
3  *
4  * Copyright 1998 Francis Beaudet
5  * Copyright 1999 Thuy Nguyen
6  *
7  * TODO:
8  *   - Modeless mode
9  *   - Wizard mode
10  *   - Unicode property sheets
11  */
12
13 #include <string.h>
14 #include "winbase.h"
15 #include "commctrl.h"
16 #include "prsht.h"
17 #include "winnls.h"
18 #include "comctl32.h"
19 #include "debugtools.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 } PropSheetInfo;
63
64 typedef struct
65 {
66   int x;
67   int y;
68 } PADDING_INFO;
69
70 /******************************************************************************
71  * Defines and global variables
72  */
73
74 const char * PropSheetInfoStr = "PropertySheetInfo";
75
76 #define MAX_CAPTION_LENGTH 255
77 #define MAX_TABTEXT_LENGTH 255
78
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_Apply(HWND hwndDlg);
101 static void PROPSHEET_Cancel(HWND hwndDlg);
102 static void PROPSHEET_Help(HWND hwndDlg);
103 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage);
104 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage);
105 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID);
106 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText);
107 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
108                                 int index,
109                                 HPROPSHEETPAGE hpage);
110 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
111                                        WPARAM wParam, LPARAM lParam);
112 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
113                                               int index);
114 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
115                               HPROPSHEETPAGE hpage);
116
117 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
118                                  int index,
119                                  HPROPSHEETPAGE hpage);
120 static void PROPSHEET_CleanUp();
121 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
122
123 BOOL WINAPI
124 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
125
126 DEFAULT_DEBUG_CHANNEL(propsheet)
127
128 /******************************************************************************
129  *            PROPSHEET_CollectSheetInfo
130  *
131  * Collect relevant data.
132  */
133 static BOOL PROPSHEET_CollectSheetInfo(LPCPROPSHEETHEADERA lppsh,
134                                        PropSheetInfo * psInfo)
135 {
136   DWORD dwFlags = lppsh->dwFlags;
137
138   psInfo->hasHelp = dwFlags & PSH_HASHELP;
139   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
140   psInfo->useCallback = dwFlags & PSH_USECALLBACK;
141   psInfo->isModeless = dwFlags & PSH_MODELESS;
142   psInfo->ppshheader = lppsh;
143   psInfo->nPages = lppsh->nPages;
144
145   if (dwFlags & PSH_USEPSTARTPAGE)
146   {
147     TRACE("PSH_USEPSTARTPAGE is on");
148     psInfo->active_page = 0;
149   }
150   else
151     psInfo->active_page = lppsh->u2.nStartPage;
152
153   psInfo->restartWindows = FALSE;
154   psInfo->rebootSystem = FALSE;
155
156   return TRUE;
157 }
158
159 /******************************************************************************
160  *            PROPSHEET_CollectPageInfo
161  *
162  * Collect property sheet data.
163  * With code taken from DIALOG_ParseTemplate32.
164  */
165 BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEA lppsp,
166                                PropSheetInfo * psInfo,
167                                int index)
168 {
169   DLGTEMPLATE* pTemplate;
170   const WORD*  p;
171   DWORD dwFlags;
172   int width, height;
173
174   if (psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE)
175     psInfo->proppage[index].hpage = 0;
176   psInfo->proppage[index].hwndPage = 0;
177   psInfo->proppage[index].isDirty = FALSE;
178
179   /*
180    * Process property page flags.
181    */
182   dwFlags = lppsp->dwFlags;
183   psInfo->proppage[index].useCallback = dwFlags & PSP_USECALLBACK;
184   psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
185
186   /* as soon as we have a page with the help flag, set the sheet flag on */
187   if (psInfo->proppage[index].hasHelp)
188     psInfo->hasHelp = TRUE;
189
190   /*
191    * Process page template.
192    */
193   if (dwFlags & PSP_DLGINDIRECT)
194     pTemplate = (DLGTEMPLATE*)lppsp->u1.pResource;
195   else
196   {
197     HRSRC hResource = FindResourceA(lppsp->hInstance,
198                                     lppsp->u1.pszTemplate,
199                                     RT_DIALOGA);
200     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
201                                      hResource);
202     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
203   }
204
205   /*
206    * Extract the size of the page and the caption.
207    */
208   p = (const WORD *)pTemplate;
209
210   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
211   {
212     /* DIALOGEX template */
213
214     p++;       /* dlgVer    */
215     p++;       /* signature */
216     p += 2;    /* help ID   */
217     p += 2;    /* ext style */
218     p += 2;    /* style     */
219   }
220   else
221   {
222     /* DIALOG template */
223
224     p += 2;    /* style     */
225     p += 2;    /* ext style */
226   }
227
228   p++;    /* nb items */
229   p++;    /*   x      */
230   p++;    /*   y      */
231   width  = (WORD)*p; p++;
232   height = (WORD)*p; p++;
233
234   /* remember the largest width and height */
235   if (width > psInfo->width)
236     psInfo->width = width;
237
238   if (height > psInfo->height)
239     psInfo->height = height;
240
241   /* menu */
242   switch ((WORD)*p)
243   {
244     case 0x0000:
245       p++;
246       break;
247     case 0xffff:
248       p += 2;
249       break;
250     default:
251       p += lstrlenW( (LPCWSTR)p ) + 1;
252       break;
253   } 
254
255   /* class */
256   switch ((WORD)*p)
257   {
258     case 0x0000:
259       p++;
260       break;
261     case 0xffff:
262       p += 2;
263       break;
264     default:
265       p += lstrlenW( (LPCWSTR)p ) + 1;
266       break;
267   }
268
269   /* Extract the caption */
270   psInfo->proppage[index].pszText = (LPCWSTR)p;
271   TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
272   p += lstrlenW((LPCWSTR)p) + 1;
273
274   return TRUE;
275 }
276
277 /******************************************************************************
278  *            PROPSHEET_CreateDialog
279  *
280  * Creates the actual property sheet.
281  */
282 BOOL PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
283 {
284   LRESULT ret;
285   LPCVOID template;
286   HRSRC hRes;
287
288   if(!(hRes = FindResourceA(COMCTL32_hModule,
289                             MAKEINTRESOURCEA(IDD_PROPSHEET),
290                             RT_DIALOGA)))
291     return FALSE;
292
293   if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
294     return FALSE;
295
296   if (psInfo->useCallback)
297     (*(psInfo->ppshheader->pfnCallback))(0, PSCB_PRECREATE, (LPARAM)template);
298
299   if (psInfo->ppshheader->dwFlags & PSH_MODELESS)
300     ret = CreateDialogIndirectParamA(psInfo->ppshheader->hInstance,
301                                      (LPDLGTEMPLATEA) template,
302                                      psInfo->ppshheader->hwndParent,
303                                      (DLGPROC) PROPSHEET_DialogProc,
304                                      (LPARAM)psInfo);
305   else
306     ret = DialogBoxIndirectParamA(psInfo->ppshheader->hInstance,
307                                   (LPDLGTEMPLATEA) template,
308                                   psInfo->ppshheader->hwndParent,
309                                   (DLGPROC) PROPSHEET_DialogProc,
310                                   (LPARAM)psInfo);
311
312   return ret;
313 }
314
315 /******************************************************************************
316  *            PROPSHEET_IsTooSmall
317  * 
318  * Verify that the resource property sheet is big enough.
319  */
320 static BOOL PROPSHEET_IsTooSmall(HWND hwndDlg, PropSheetInfo* psInfo)
321 {
322   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
323   RECT rcOrigTab, rcPage;
324
325   /*
326    * Original tab size.
327    */
328   GetClientRect(hwndTabCtrl, &rcOrigTab);
329   TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
330         rcOrigTab.right, rcOrigTab.bottom);
331
332   /*
333    * Biggest page size.
334    */
335   rcPage.left   = psInfo->x;
336   rcPage.top    = psInfo->y;
337   rcPage.right  = psInfo->width;
338   rcPage.bottom = psInfo->height;
339
340   MapDialogRect(hwndDlg, &rcPage);
341   TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
342         rcPage.right, rcPage.bottom);
343
344   if (rcPage.right > rcOrigTab.right)
345     return TRUE;
346
347   if (rcPage.bottom > rcOrigTab.bottom)
348     return TRUE;
349
350   return FALSE;
351 }
352
353 /******************************************************************************
354  *            PROPSHEET_AdjustSize
355  *
356  * Resizes the property sheet and the tab control to fit the largest page.
357  */
358 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
359 {
360   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
361   HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
362   RECT rc;
363   int tabOffsetX, tabOffsetY, buttonHeight;
364   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
365
366   /* Get the height of buttons */
367   GetClientRect(hwndButton, &rc);
368   buttonHeight = rc.bottom;
369
370   /*
371    * Biggest page size.
372    */
373   rc.left   = psInfo->x;
374   rc.top    = psInfo->y;
375   rc.right  = psInfo->width;
376   rc.bottom = psInfo->height;
377
378   MapDialogRect(hwndDlg, &rc);
379
380   /*
381    * Resize the tab control.
382    */
383   SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
384
385   tabOffsetX = -(rc.left);
386   tabOffsetY = -(rc.top);
387
388   rc.right -= rc.left;
389   rc.bottom -= rc.top;
390   SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
391                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
392
393   GetClientRect(hwndTabCtrl, &rc);
394
395   TRACE("tab client rc %d %d %d %d\n",
396         rc.left, rc.top, rc.right, rc.bottom);
397
398   rc.right += ((padding.x * 2) + tabOffsetX);
399   rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
400
401   /*
402    * Resize the property sheet.
403    */
404   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
405                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
406
407   return TRUE;
408 }
409
410 /******************************************************************************
411  *            PROPSHEET_AdjustButtons
412  *
413  * Adjusts the buttons' positions.
414  */
415 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
416 {
417   HWND hwndButton = GetDlgItem(hwndParent, IDOK);
418   RECT rcSheet;
419   int x, y;
420   int num_buttons = 2;
421   int buttonWidth, buttonHeight;
422   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
423
424   if (psInfo->hasApply)
425     num_buttons++;
426
427   if (psInfo->hasHelp)
428     num_buttons++;
429
430   /*
431    * Obtain the size of the buttons.
432    */
433   GetClientRect(hwndButton, &rcSheet);
434   buttonWidth = rcSheet.right;
435   buttonHeight = rcSheet.bottom;
436
437   /*
438    * Get the size of the property sheet.
439    */ 
440   GetClientRect(hwndParent, &rcSheet);
441
442   /* 
443    * All buttons will be at this y coordinate.
444    */
445   y = rcSheet.bottom - (padding.y + buttonHeight);
446
447   /*
448    * Position OK button.
449    */
450   hwndButton = GetDlgItem(hwndParent, IDOK);
451
452   x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
453
454   SetWindowPos(hwndButton, 0, x, y, 0, 0,
455                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
456
457   /*
458    * Position Cancel button.
459    */
460   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
461
462   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
463
464   SetWindowPos(hwndButton, 0, x, y, 0, 0,
465                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
466
467   /*
468    * Position Apply button.
469    */
470   hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
471
472   if (psInfo->hasApply)
473   {
474     if (psInfo->hasHelp)
475       x = rcSheet.right - ((padding.x + buttonWidth) * 2);
476     else
477       x = rcSheet.right - (padding.x + buttonWidth);
478   
479     SetWindowPos(hwndButton, 0, x, y, 0, 0,
480                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
481
482     EnableWindow(hwndButton, FALSE);
483   }
484   else
485     ShowWindow(hwndButton, SW_HIDE);
486
487   /*
488    * Position Help button.
489    */
490   hwndButton = GetDlgItem(hwndParent, IDHELP);
491
492   if (psInfo->hasHelp)
493   {
494     x = rcSheet.right - (padding.x + buttonWidth);
495   
496     SetWindowPos(hwndButton, 0, x, y, 0, 0,
497                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
498   }
499   else
500     ShowWindow(hwndButton, SW_HIDE);
501
502   return TRUE;
503 }
504
505 /******************************************************************************
506  *            PROPSHEET_GetPaddingInfo
507  *
508  * Returns the layout information.
509  */
510 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
511 {
512   HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
513   RECT rcTab;
514   POINT tl;
515   PADDING_INFO padding;
516
517   GetWindowRect(hwndTab, &rcTab);
518
519   tl.x = rcTab.left;
520   tl.y = rcTab.top;
521
522   ScreenToClient(hwndDlg, &tl);
523
524   padding.x = tl.x;
525   padding.y = tl.y;
526
527   return padding;
528 }
529
530 /******************************************************************************
531  *            PROPSHEET_CreateTabControl
532  *
533  * Insert the tabs in the tab control.
534  */
535 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
536                                        PropSheetInfo * psInfo)
537 {
538   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
539   TCITEMA item;
540   int i, nTabs;
541   char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
542
543   item.mask = TCIF_TEXT;
544   item.pszText = tabtext;
545   item.cchTextMax = MAX_TABTEXT_LENGTH;
546
547   nTabs = psInfo->ppshheader->nPages;
548
549   for (i = 0; i < nTabs; i++)
550   {
551     WideCharToMultiByte(CP_ACP, 0,
552                         (LPCWSTR)psInfo->proppage[i].pszText,
553                         -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
554
555     SendMessageA(hwndTabCtrl, TCM_INSERTITEMA, (WPARAM)i, (LPARAM)&item);
556   }
557
558   return TRUE;
559 }
560
561 /******************************************************************************
562  *            PROPSHEET_CreatePage
563  *
564  * Creates a page.
565  */
566 static int PROPSHEET_CreatePage(HWND hwndParent,
567                                 int index,
568                                 const PropSheetInfo * psInfo,
569                                 LPCPROPSHEETPAGEA ppshpage,
570                                 BOOL showPage)
571 {
572   DLGTEMPLATE* pTemplate;
573   HWND hwndPage;
574   RECT rc;
575   PropPageInfo* ppInfo = psInfo->proppage;
576   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
577   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
578
579   TRACE("index %d\n", index);
580
581   if (ppshpage->dwFlags & PSP_DLGINDIRECT)
582     pTemplate = (DLGTEMPLATE*)ppshpage->u1.pResource;
583   else
584   {
585     HRSRC hResource = FindResourceA(ppshpage->hInstance,
586                                     ppshpage->u1.pszTemplate,
587                                     RT_DIALOGA);
588     HGLOBAL hTemplate = LoadResource(ppshpage->hInstance, hResource);
589     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
590   }
591
592   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
593   {
594     ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD;
595     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
596     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
597     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
598     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
599   }
600   else
601   {
602     pTemplate->style |= WS_CHILD;
603     pTemplate->style &= ~DS_MODALFRAME;
604     pTemplate->style &= ~WS_CAPTION;
605     pTemplate->style &= ~WS_SYSMENU;
606     pTemplate->style &= ~WS_POPUP;
607   }
608
609   if (psInfo->proppage[index].useCallback)
610     (*(ppshpage->pfnCallback))(hwndParent,
611                                PSPCB_CREATE,
612                                (LPPROPSHEETPAGEA)ppshpage);
613
614   hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
615                                         pTemplate,
616                                         hwndParent,
617                                         ppshpage->pfnDlgProc,
618                                         (LPARAM)ppshpage);
619
620   ppInfo[index].hwndPage = hwndPage;
621
622   rc.left = psInfo->x;
623   rc.top = psInfo->y;
624   rc.right = psInfo->width;
625   rc.bottom = psInfo->height;
626
627   MapDialogRect(hwndParent, &rc);
628
629   /*
630    * Ask the Tab control to fit this page in.
631    */
632   SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);
633
634   SetWindowPos(hwndPage, HWND_TOP,
635                rc.left + padding.x,
636                rc.top + padding.y,
637                0, 0, SWP_NOSIZE);
638
639   if (showPage)
640     ShowWindow(hwndPage, SW_SHOW);
641   else
642     ShowWindow(hwndPage, SW_HIDE);
643
644   return TRUE;
645 }
646
647 /******************************************************************************
648  *            PROPSHEET_ShowPage
649  *
650  * Displays or creates the specified page.
651  */
652 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
653 {
654   if (index == psInfo->active_page)
655     return TRUE;
656
657   ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
658
659   if (psInfo->proppage[index].hwndPage != 0)
660     ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
661   else
662   {
663     LPCPROPSHEETPAGEA ppshpage = PROPSHEET_GetPSPPage(psInfo, index);
664     PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage, TRUE);
665   }
666
667   psInfo->active_page = index;
668
669   return TRUE;
670 }
671
672 /******************************************************************************
673  *            PROPSHEET_Apply
674  */
675 static BOOL PROPSHEET_Apply(HWND hwndDlg)
676 {
677   int i;
678   NMHDR hdr;
679   HWND hwndPage;
680   LRESULT msgResult;
681   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
682                                                     PropSheetInfoStr);
683
684   hdr.hwndFrom = hwndDlg;
685
686   /*
687    * Send PSN_KILLACTIVE to the current page.
688    */
689   hdr.code = PSN_KILLACTIVE;
690
691   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
692
693   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr) != FALSE)
694     return FALSE;
695
696   /*
697    * Send PSN_APPLY to all pages.
698    */
699   hdr.code = PSN_APPLY;
700
701   for (i = 0; i < psInfo->nPages; i++)
702   {
703     hwndPage = psInfo->proppage[i].hwndPage;
704     msgResult = SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
705
706     if (msgResult == PSNRET_INVALID_NOCHANGEPAGE)
707       return FALSE;
708   }
709
710   return TRUE;
711 }
712
713 /******************************************************************************
714  *            PROPSHEET_Cancel
715  */
716 static void PROPSHEET_Cancel(HWND hwndDlg)
717 {
718   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
719                                                     PropSheetInfoStr);
720   HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
721   NMHDR hdr;
722
723   hdr.hwndFrom = hwndDlg;
724   hdr.code = PSN_QUERYCANCEL;
725
726   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
727     return;
728
729   hdr.code = PSN_RESET;
730
731   SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
732
733   if (psInfo->isModeless)
734     psInfo->active_page = -1; /* makes PSM_GETCURRENTPAGEHWND return NULL */
735   else
736     EndDialog(hwndDlg, FALSE);
737 }
738
739 /******************************************************************************
740  *            PROPSHEET_Help
741  */
742 static void PROPSHEET_Help(HWND hwndDlg)
743 {
744   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
745                                                     PropSheetInfoStr);
746   HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
747   NMHDR hdr;
748
749   hdr.hwndFrom = hwndDlg;
750   hdr.code = PSN_HELP;
751
752   SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
753 }
754
755 /******************************************************************************
756  *            PROPSHEET_Changed
757  */
758 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
759 {
760   int i;
761   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
762                                                     PropSheetInfoStr);
763
764   if (!psInfo) return;
765   /*
766    * Set the dirty flag of this page.
767    */
768   for (i = 0; i < psInfo->nPages; i++)
769   {
770     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
771       psInfo->proppage[i].isDirty = TRUE;
772   }
773
774   /*
775    * Enable the Apply button.
776    */
777   if (psInfo->hasApply)
778   {
779     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
780
781     EnableWindow(hwndApplyBtn, TRUE);
782   }
783 }
784
785 /******************************************************************************
786  *            PROPSHEET_UnChanged
787  */
788 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
789 {
790   int i;
791   BOOL noPageDirty = TRUE;
792   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
793   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
794                                                     PropSheetInfoStr);
795
796   for (i = 0; i < psInfo->nPages; i++)
797   {
798     /* set the specified page as clean */
799     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
800       psInfo->proppage[i].isDirty = FALSE;
801
802     /* look to see if there's any dirty pages */
803     if (psInfo->proppage[i].isDirty)
804       noPageDirty = FALSE;
805   }
806
807   /*
808    * Disable Apply button.
809    */
810   if (noPageDirty)
811     EnableWindow(hwndApplyBtn, FALSE);
812 }
813
814 /******************************************************************************
815  *            PROPSHEET_PressButton
816  */
817 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
818 {
819   switch (buttonID)
820   {
821     case PSBTN_APPLYNOW:
822       SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
823       break;
824     case PSBTN_BACK:
825       FIXME("Wizard mode not implemented.\n");
826       break;
827     case PSBTN_CANCEL:
828       SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
829       break;
830     case PSBTN_FINISH:
831       FIXME("Wizard mode not implemented.\n");
832       break;
833     case PSBTN_HELP:
834       SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
835       break;
836     case PSBTN_NEXT:
837       FIXME("Wizard mode not implemented.\n");
838       break;
839     case PSBTN_OK:
840       SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
841       break;
842     default:
843       FIXME("Invalid button index %d\n", buttonID);
844   }
845 }
846
847 /******************************************************************************
848  *            PROPSHEET_SetCurSel
849  */
850 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
851                                 int index,
852                                 HPROPSHEETPAGE hpage)
853 {
854   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
855                                                     PropSheetInfoStr);
856   HWND hwndPage;
857   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
858   NMHDR hdr;
859
860   /*
861    * Notify the current page.
862    */
863   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
864
865   hdr.hwndFrom = hwndDlg;
866   hdr.code = PSN_KILLACTIVE;
867
868   if (SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr))
869     return FALSE;
870
871   if (hpage != NULL)
872     FIXME("Implement HPROPSHEETPAGE!\n");
873   else
874     hwndPage = psInfo->proppage[index].hwndPage;
875
876   /*
877    * Notify the new page.
878    */
879   hdr.code = PSN_SETACTIVE;
880
881   SendMessageA(hwndPage, WM_NOTIFY, 0, (LPARAM) &hdr);
882
883   /*
884    * Display the new page.
885    */
886   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
887
888   if (psInfo->proppage[index].hasHelp)
889     EnableWindow(hwndHelp, TRUE);
890   else
891     EnableWindow(hwndHelp, FALSE);
892
893   return TRUE;
894 }
895
896 /******************************************************************************
897  *            PROPSHEET_SetTitleA
898  */
899 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
900 {
901   if (dwStyle & PSH_PROPTITLE)
902   {
903     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
904                                                       PropSheetInfoStr);
905     char* dest;
906     int lentitle = strlen(lpszText);
907     int lenprop  = strlen(psInfo->strPropertiesFor);
908
909     dest = COMCTL32_Alloc(lentitle + lenprop + 1);
910     strcpy(dest, psInfo->strPropertiesFor);
911     strcat(dest, lpszText);
912
913     SetWindowTextA(hwndDlg, dest);
914     COMCTL32_Free(dest);
915   }
916   else
917     SetWindowTextA(hwndDlg, lpszText);
918 }
919
920 /******************************************************************************
921  *            PROPSHEET_QuerySiblings
922  */
923 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
924                                        WPARAM wParam, LPARAM lParam)
925 {
926   int i = 0;
927   HWND hwndPage;
928   LRESULT msgResult = 0;
929   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
930                                                     PropSheetInfoStr);
931
932   while ((i < psInfo->nPages) && (msgResult == 0))
933   {
934     hwndPage = psInfo->proppage[i].hwndPage;
935     msgResult = SendMessageA(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
936     i++;
937   }
938
939   return msgResult;
940 }
941
942 /******************************************************************************
943  *            PROPSHEET_GetPSPPage
944  */
945 static LPCPROPSHEETPAGEA PROPSHEET_GetPSPPage(const PropSheetInfo * psInfo,
946                                               int index)
947 {
948   BOOL usePSP = psInfo->ppshheader->dwFlags & PSH_PROPSHEETPAGE;
949   LPCPROPSHEETPAGEA lppsp;
950   int realIndex = psInfo->proppage[index].index;
951
952   if (usePSP)
953   {
954     BYTE* pByte;
955
956     lppsp = psInfo->ppshheader->u3.ppsp;
957
958     pByte = (BYTE*) lppsp;
959
960     pByte += (lppsp->dwSize * realIndex);
961     lppsp = (LPCPROPSHEETPAGEA)pByte;
962   }
963   else
964     lppsp = (LPCPROPSHEETPAGEA) psInfo->ppshheader->u3.phpage[realIndex];
965
966   return lppsp;
967 }
968
969 /******************************************************************************
970  *            PROPSHEET_AddPage
971  */
972 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
973                               HPROPSHEETPAGE hpage)
974 {
975   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
976                                                      PropSheetInfoStr);
977   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
978   TCITEMA item;
979   char tabtext[MAX_TABTEXT_LENGTH] = "Tab text";
980   LPCPROPSHEETPAGEA ppsp = (LPCPROPSHEETPAGEA)hpage;
981
982   /*
983    * Allocate and fill in a new PropPageInfo entry.
984    */
985   psInfo->proppage = (PropPageInfo*) COMCTL32_ReAlloc(psInfo->proppage,
986                                                       sizeof(PropPageInfo) *
987                                                       (psInfo->nPages + 1));
988
989   PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages);
990   psInfo->proppage[psInfo->nPages].index = -1;
991   psInfo->proppage[psInfo->nPages].hpage = hpage;
992
993   /*
994    * Create the page but don't show it.
995    */
996   PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp, FALSE);
997
998   /*
999    * Add a new tab to the tab control.
1000    */
1001   item.mask = TCIF_TEXT;
1002   item.pszText = tabtext;
1003   item.cchTextMax = MAX_TABTEXT_LENGTH;
1004
1005   WideCharToMultiByte(CP_ACP, 0,
1006                       (LPCWSTR)psInfo->proppage[psInfo->nPages].pszText,
1007                       -1, tabtext, MAX_TABTEXT_LENGTH, NULL, NULL);
1008
1009   SendMessageA(hwndTabControl, TCM_INSERTITEMA, psInfo->nPages + 1,
1010                (LPARAM)&item);
1011
1012   psInfo->nPages++;
1013
1014   return FALSE;
1015 }
1016
1017 /******************************************************************************
1018  *            PROPSHEET_RemovePage
1019  */
1020 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
1021                                  int index,
1022                                  HPROPSHEETPAGE hpage)
1023 {
1024   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropA(hwndDlg,
1025                                                      PropSheetInfoStr);
1026   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1027   PropPageInfo* oldPages = psInfo->proppage;
1028
1029   /*
1030    * hpage takes precedence over index.
1031    */
1032   if (hpage != 0)
1033   {
1034     index = PROPSHEET_GetPageIndex(hpage, psInfo);
1035
1036     if (index == -1)
1037     {
1038       TRACE("Could not find page to remove!\n");
1039       return FALSE;
1040     }
1041   }
1042
1043   TRACE("total pages %d removing page %d active page %d\n",
1044         psInfo->nPages, index, psInfo->active_page);
1045   /*
1046    * Check if we're removing the active page.
1047    */
1048   if (index == psInfo->active_page)
1049   {
1050     if (psInfo->nPages > 1)
1051     {
1052       if (index > 0)
1053       {
1054         /* activate previous page  */
1055         PROPSHEET_ShowPage(hwndDlg, index - 1, psInfo);
1056       }
1057       else
1058       {
1059         /* activate the next page */
1060         PROPSHEET_ShowPage(hwndDlg, index + 1, psInfo);
1061       }
1062     }
1063     else
1064     {
1065       TRACE("Removing the only page, close the dialog!\n");
1066
1067       if (psInfo->isModeless)
1068         psInfo->active_page = -1;
1069       else
1070         EndDialog(hwndDlg, FALSE);
1071
1072       return TRUE;
1073     }
1074   }
1075
1076   if (index < psInfo->active_page)
1077     psInfo->active_page--;
1078
1079   /* Remove the tab */
1080   SendMessageA(hwndTabControl, TCM_DELETEITEM, index, 0);
1081
1082   psInfo->nPages--;
1083   psInfo->proppage = COMCTL32_Alloc(sizeof(PropPageInfo) * psInfo->nPages);
1084
1085   if (index > 0)  
1086     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
1087
1088   if (index < psInfo->nPages)
1089     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
1090            (psInfo->nPages - index) * sizeof(PropPageInfo));
1091
1092   COMCTL32_Free(oldPages);
1093
1094   return FALSE;
1095 }
1096
1097 /******************************************************************************
1098  *            PROPSHEET_GetPageIndex
1099  *
1100  * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
1101  * the array of PropPageInfo.
1102  */
1103 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
1104 {
1105   BOOL found = FALSE;
1106   int index = 0;
1107
1108   while ((index < psInfo->nPages) && (found == FALSE))
1109   {
1110     if (psInfo->proppage[index].hpage == hpage)
1111       found = TRUE;
1112     else
1113       index++;
1114   }
1115
1116   if (found == FALSE)
1117     index = -1;
1118
1119   return index;
1120 }
1121
1122 /******************************************************************************
1123  *            PROPSHEET_CleanUp
1124  */
1125 static void PROPSHEET_CleanUp(HWND hwndDlg)
1126 {
1127   PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropA(hwndDlg,
1128                                                        PropSheetInfoStr);
1129   COMCTL32_Free(psInfo->proppage);
1130   COMCTL32_Free(psInfo->strPropertiesFor);
1131
1132   GlobalFree((HGLOBAL)psInfo);
1133 }
1134
1135 /******************************************************************************
1136  *            PropertySheetA   (COMCTL32.84)(COMCTL32.83)
1137  */
1138 INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
1139 {
1140   int bRet = 0;
1141   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
1142                                                        sizeof(PropSheetInfo));
1143   LPCPROPSHEETPAGEA lppsp;
1144   int i;
1145
1146   PROPSHEET_CollectSheetInfo(lppsh, psInfo);
1147
1148   psInfo->proppage = (PropPageInfo*) COMCTL32_Alloc(sizeof(PropPageInfo) *
1149                                                     lppsh->nPages);
1150
1151   for (i = 0; i < lppsh->nPages; i++)
1152   {
1153     psInfo->proppage[i].index = i;
1154     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
1155       psInfo->proppage[i].hpage = psInfo->ppshheader->u3.phpage[i];
1156     lppsp = PROPSHEET_GetPSPPage(psInfo, i);
1157     PROPSHEET_CollectPageInfo(lppsp, psInfo, i);
1158   }
1159
1160   bRet = PROPSHEET_CreateDialog(psInfo);
1161
1162   return bRet;
1163 }
1164
1165 /******************************************************************************
1166  *            PropertySheet32W   (COMCTL32.85)
1167  */
1168 INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW propertySheetHeader)
1169 {
1170     FIXME("(%p): stub\n", propertySheetHeader);
1171
1172     return -1;
1173 }
1174
1175 /******************************************************************************
1176  *            CreatePropertySheetPageA   (COMCTL32.19)(COMCTL32.18)
1177  */
1178 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
1179                           LPCPROPSHEETPAGEA lpPropSheetPage)
1180 {
1181   PROPSHEETPAGEA* ppsp = COMCTL32_Alloc(sizeof(PROPSHEETPAGEA));
1182
1183   *ppsp = *lpPropSheetPage;
1184
1185   return (HPROPSHEETPAGE)ppsp;
1186 }
1187
1188 /******************************************************************************
1189  *            CreatePropertySheetPageW   (COMCTL32.20)
1190  */
1191 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
1192 {
1193     FIXME("(%p): stub\n", lpPropSheetPage);
1194
1195     return 0;
1196 }
1197
1198 /******************************************************************************
1199  *            DestroyPropertySheetPage   (COMCTL32.24)
1200  */
1201 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
1202 {
1203   COMCTL32_Free(hPropPage);
1204
1205   return TRUE;
1206 }
1207
1208 /******************************************************************************
1209  *            PROPSHEET_DialogProc
1210  */
1211 BOOL WINAPI
1212 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1213 {
1214   switch (uMsg)
1215   {
1216     case WM_INITDIALOG:
1217     {
1218       PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
1219       char* strCaption = (char*)COMCTL32_Alloc(MAX_CAPTION_LENGTH);
1220       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1221       LPCPROPSHEETPAGEA ppshpage;
1222
1223       psInfo->strPropertiesFor = strCaption;
1224
1225       GetWindowTextA(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
1226
1227       PROPSHEET_CreateTabControl(hwnd, psInfo);
1228
1229       if (PROPSHEET_IsTooSmall(hwnd, psInfo))
1230       {
1231         PROPSHEET_AdjustSize(hwnd, psInfo);
1232         PROPSHEET_AdjustButtons(hwnd, psInfo);
1233       }
1234
1235       ppshpage = PROPSHEET_GetPSPPage(psInfo, psInfo->active_page);      
1236       PROPSHEET_CreatePage(hwnd, psInfo->active_page, psInfo, ppshpage, TRUE);
1237       SendMessageA(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
1238
1239       SetPropA(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
1240
1241       PROPSHEET_SetTitleA(hwnd,
1242                           psInfo->ppshheader->dwFlags,
1243                           psInfo->ppshheader->pszCaption);
1244
1245       return TRUE;
1246     }
1247
1248     case WM_DESTROY:
1249       PROPSHEET_CleanUp(hwnd);
1250       return TRUE;
1251
1252     case WM_CLOSE:
1253       PROPSHEET_Cancel(hwnd);
1254       return TRUE;
1255
1256     case WM_COMMAND:
1257     {
1258       WORD wID = LOWORD(wParam);
1259
1260       switch (wID)
1261       {
1262         case IDOK:
1263         case IDC_APPLY_BUTTON:
1264         {
1265           HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
1266
1267           if (PROPSHEET_Apply(hwnd) == FALSE)
1268             break;
1269
1270           EnableWindow(hwndApplyBtn, FALSE);
1271
1272           if (wID == IDOK)
1273           {
1274             PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1275                                                             PropSheetInfoStr);
1276             int result = TRUE;
1277
1278             if (psInfo->restartWindows)
1279               result = ID_PSRESTARTWINDOWS;
1280
1281             /* reboot system takes precedence over restart windows */
1282             if (psInfo->rebootSystem)
1283               result = ID_PSREBOOTSYSTEM;
1284
1285             if (psInfo->isModeless)
1286               psInfo->active_page = -1;
1287             else
1288               EndDialog(hwnd, result);
1289           }
1290
1291           break;
1292         }
1293
1294         case IDCANCEL:
1295           PROPSHEET_Cancel(hwnd);
1296           break;
1297
1298         case IDHELP:
1299           PROPSHEET_Help(hwnd);
1300           break;
1301       }
1302
1303       return TRUE;
1304     }
1305
1306     case WM_NOTIFY:
1307     {
1308       NMHDR* pnmh = (LPNMHDR) lParam;
1309
1310       if (pnmh->code == TCN_SELCHANGE)
1311       {
1312         PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1313                                                           PropSheetInfoStr);
1314         int index = SendMessageA(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
1315         HWND hwndHelp  = GetDlgItem(hwnd, IDHELP);
1316
1317         PROPSHEET_ShowPage(hwnd, index, psInfo);
1318
1319         if (psInfo->proppage[index].hasHelp)
1320           EnableWindow(hwndHelp, TRUE);
1321         else
1322           EnableWindow(hwndHelp, FALSE);
1323       }
1324
1325       return 0;
1326     }
1327
1328     case PSM_GETCURRENTPAGEHWND:
1329     {
1330       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1331                                                         PropSheetInfoStr);
1332       HWND hwndPage = 0;
1333
1334       if (psInfo->active_page != -1)
1335         hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1336
1337       SetWindowLongA(hwnd, DWL_MSGRESULT, hwndPage);
1338
1339       return TRUE;
1340     }
1341
1342     case PSM_CHANGED:
1343       PROPSHEET_Changed(hwnd, (HWND)wParam);
1344       return TRUE;
1345
1346     case PSM_UNCHANGED:
1347       PROPSHEET_UnChanged(hwnd, (HWND)wParam);
1348       return TRUE;
1349
1350     case PSM_GETTABCONTROL:
1351     {
1352       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
1353
1354       SetWindowLongA(hwnd, DWL_MSGRESULT, hwndTabCtrl);
1355
1356       return TRUE;
1357     }
1358
1359     case PSM_SETCURSEL:
1360     {
1361       BOOL msgResult;
1362
1363       msgResult = PROPSHEET_SetCurSel(hwnd,
1364                                       (int)wParam,
1365                                       (HPROPSHEETPAGE)lParam);
1366
1367       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1368
1369       return TRUE;
1370     }
1371
1372     case PSM_CANCELTOCLOSE:
1373     {
1374       HWND hwndOK = GetDlgItem(hwnd, IDOK);
1375       HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
1376
1377       EnableWindow(hwndCancel, FALSE);
1378       SetWindowTextA(hwndOK, "Close"); /* FIXME: hardcoded string */
1379
1380       return TRUE;
1381     }
1382
1383     case PSM_RESTARTWINDOWS:
1384     {
1385       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,
1386                                                         PropSheetInfoStr);
1387
1388       psInfo->restartWindows = TRUE;
1389       return TRUE;
1390     }
1391
1392     case PSM_REBOOTSYSTEM:
1393     {
1394       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, 
1395                                                         PropSheetInfoStr);
1396
1397       psInfo->rebootSystem = TRUE;
1398       return TRUE;
1399     }
1400
1401     case PSM_SETTITLEA:
1402       PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
1403       return TRUE;
1404
1405     case PSM_APPLY:
1406     {
1407       BOOL msgResult = PROPSHEET_Apply(hwnd);
1408
1409       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1410
1411       return TRUE;
1412     }
1413
1414     case PSM_QUERYSIBLINGS:
1415     {
1416       LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
1417
1418       SetWindowLongA(hwnd, DWL_MSGRESULT, msgResult);
1419
1420       return TRUE;
1421     }
1422
1423     case PSM_ADDPAGE:
1424       PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
1425       return TRUE;
1426
1427     case PSM_REMOVEPAGE:
1428       PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
1429       return TRUE;
1430
1431     case PSM_ISDIALOGMESSAGE:
1432     {
1433       FIXME("Unimplemented msg PSM_ISDIALOGMESSAGE\n");
1434       return 0;
1435     }
1436
1437     case PSM_PRESSBUTTON:
1438       PROPSHEET_PressButton(hwnd, (int)wParam);
1439       return TRUE;
1440
1441     case PSM_SETTITLEW:
1442         FIXME("Unimplemented msg PSM_SETTITLE32W\n");
1443         return 0;
1444     case PSM_SETWIZBUTTONS:
1445         FIXME("Unimplemented msg PSM_SETWIZBUTTONS\n");
1446         return 0;
1447     case PSM_SETCURSELID:
1448         FIXME("Unimplemented msg PSM_SETCURSELID\n");
1449         return 0;
1450     case PSM_SETFINISHTEXTA:
1451         FIXME("Unimplemented msg PSM_SETFINISHTEXT32A\n");
1452         return 0;
1453     case PSM_SETFINISHTEXTW:
1454         FIXME("Unimplemented msg PSM_SETFINISHTEXT32W\n");
1455         return 0;
1456
1457     default:
1458       return FALSE;
1459   }
1460 }
1461