wineoss: Renamed the dlls/winmm/wineoss directory to dlls/wineoss.drv.
[wine] / dlls / comctl32 / propsheet.c
1 /*
2  * Property Sheets
3  *
4  * Copyright 1998 Francis Beaudet
5  * Copyright 1999 Thuy Nguyen
6  * Copyright 2004 Maxime Bellenge
7  * Copyright 2004 Filip Navara
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  *
23  * This code was audited for completeness against the documented features
24  * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara.
25  * 
26  * Unless otherwise noted, we believe this code to be complete, as per
27  * the specification mentioned above.
28  * If you discover missing features, or bugs, please note them below.
29  *
30  * TODO:
31  *   - Tab order
32  *   - Wizard 97 header resizing
33  *   - Enforcing of minimal wizard size
34  *   - Messages:
35  *     o PSM_INSERTPAGE
36  *     o PSM_RECALCPAGESIZES
37  *     o PSM_SETHEADERSUBTITLE
38  *     o PSM_SETHEADERTITLE
39  *     o WM_HELP
40  *     o WM_CONTEXTMENU
41  *   - Notifications:
42  *     o PSN_GETOBJECT
43  *     o PSN_QUERYINITIALFOCUS
44  *     o PSN_TRANSLATEACCELERATOR
45  *   - Styles:
46  *     o PSH_RTLREADING
47  *     o PSH_STRETCHWATERMARK
48  *     o PSH_USEPAGELANG
49  *     o PSH_USEPSTARTPAGE
50  *   - Page styles:
51  *     o PSP_USEFUSIONCONTEXT
52  *     o PSP_USEREFPARENT
53  */
54
55 #include <stdarg.h>
56 #include <string.h>
57
58 #define NONAMELESSUNION
59 #define NONAMELESSSTRUCT
60 #include "windef.h"
61 #include "winbase.h"
62 #include "wingdi.h"
63 #include "winuser.h"
64 #include "winnls.h"
65 #include "commctrl.h"
66 #include "prsht.h"
67 #include "comctl32.h"
68 #include "uxtheme.h"
69
70 #include "wine/debug.h"
71 #include "wine/unicode.h"
72
73 /******************************************************************************
74  * Data structures
75  */
76 #include "pshpack2.h"
77
78 typedef struct
79 {
80   WORD dlgVer;
81   WORD signature;
82   DWORD helpID;
83   DWORD exStyle;
84   DWORD style;
85 } MyDLGTEMPLATEEX;
86
87 typedef struct
88 {
89   DWORD helpid;
90   DWORD exStyle;
91   DWORD style;
92   short x;
93   short y;
94   short cx;
95   short cy;
96   DWORD id;
97 } MyDLGITEMTEMPLATEEX;
98 #include "poppack.h"
99
100 typedef struct tagPropPageInfo
101 {
102   HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
103   HWND hwndPage;
104   BOOL isDirty;
105   LPCWSTR pszText;
106   BOOL hasHelp;
107   BOOL useCallback;
108   BOOL hasIcon;
109 } PropPageInfo;
110
111 typedef struct tagPropSheetInfo
112 {
113   HWND hwnd;
114   PROPSHEETHEADERW ppshheader;
115   BOOL unicode;
116   LPWSTR strPropertiesFor;
117   int nPages;
118   int active_page;
119   BOOL isModeless;
120   BOOL hasHelp;
121   BOOL hasApply;
122   BOOL hasFinish;
123   BOOL useCallback;
124   BOOL activeValid;
125   PropPageInfo* proppage;
126   HFONT hFont;
127   HFONT hFontBold;
128   int width;
129   int height;
130   HIMAGELIST hImageList;
131   BOOL ended;
132   INT result;
133 } PropSheetInfo;
134
135 typedef struct
136 {
137   int x;
138   int y;
139 } PADDING_INFO;
140
141 /******************************************************************************
142  * Defines and global variables
143  */
144
145 static const WCHAR PropSheetInfoStr[] =
146     {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };
147
148 #define PSP_INTERNAL_UNICODE 0x80000000
149
150 #define MAX_CAPTION_LENGTH 255
151 #define MAX_TABTEXT_LENGTH 255
152 #define MAX_BUTTONTEXT_LENGTH 64
153
154 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
155
156 /* Wizard metrics specified in DLUs */
157 #define WIZARD_PADDING 7
158 #define WIZARD_HEADER_HEIGHT 36
159                                 
160 /******************************************************************************
161  * Prototypes
162  */
163 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
164 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);
165 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
166 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
167                                 int index,
168                                 int skipdir,
169                                 HPROPSHEETPAGE hpage);
170 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
171 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
172 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
173
174 static INT_PTR CALLBACK
175 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
176
177 WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
178
179 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
180 /******************************************************************************
181  *            PROPSHEET_UnImplementedFlags
182  *
183  * Document use of flags we don't implement yet.
184  */
185 static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)
186 {
187     CHAR string[256];
188
189     string[0] = '\0';
190
191   /*
192    * unhandled header flags:
193    *  PSH_RTLREADING         0x00000800
194    *  PSH_STRETCHWATERMARK   0x00040000
195    *  PSH_USEPAGELANG        0x00200000
196    */
197
198     add_flag(PSH_RTLREADING);
199     add_flag(PSH_STRETCHWATERMARK);
200     add_flag(PSH_USEPAGELANG);
201     if (string[0] != '\0')
202         FIXME("%s\n", string);
203 }
204 #undef add_flag
205
206 /******************************************************************************
207  *            PROPSHEET_GetPageRect
208  *
209  * Retrieve rect from tab control and map into the dialog for SetWindowPos
210  */
211 static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg,
212                                   RECT *rc, LPCPROPSHEETPAGEW ppshpage)
213 {
214     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {     
215         HWND hwndChild;
216         RECT r;
217
218         if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
219              (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
220              !(ppshpage->dwFlags & PSP_HIDEHEADER)) ||
221             (psInfo->ppshheader.dwFlags & PSH_WIZARD))
222         {
223             rc->left = rc->top = WIZARD_PADDING;
224         }
225         else
226         {
227             rc->left = rc->top = 0;
228         }
229         rc->right = psInfo->width - rc->left;
230         rc->bottom = psInfo->height - rc->top;
231         MapDialogRect(hwndDlg, rc);
232
233         if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
234             (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
235             !(ppshpage->dwFlags & PSP_HIDEHEADER))
236         {
237             hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
238             GetClientRect(hwndChild, &r);
239             MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2);
240             rc->top += r.bottom + 1;
241         }
242     } else {
243         HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
244         GetClientRect(hwndTabCtrl, rc);
245         SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc);
246         MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2);
247     }
248 }
249
250 /******************************************************************************
251  *            PROPSHEET_FindPageByResId
252  *
253  * Find page index corresponding to page resource id.
254  */
255 static INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId)
256 {
257    INT i;
258
259    for (i = 0; i < psInfo->nPages; i++)
260    {
261       LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;
262
263       /* Fixme: if resource ID is a string shall we use strcmp ??? */
264       if (lppsp->u.pszTemplate == (LPVOID)resId)
265          break;
266    }
267
268    return i;
269 }
270
271 /******************************************************************************
272  *            PROPSHEET_AtoW
273  *
274  * Convert ASCII to Unicode since all data is saved as Unicode.
275  */
276 static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr)
277 {
278     INT len;
279     WCHAR *to;
280
281     TRACE("<%s>\n", frstr);
282     len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0);
283     to = Alloc(len * sizeof(WCHAR));
284     MultiByteToWideChar(CP_ACP, 0, frstr, -1, to, len);
285     *tostr = to;
286 }
287
288 /******************************************************************************
289  *            PROPSHEET_CollectSheetInfoA
290  *
291  * Collect relevant data.
292  */
293 static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
294                                        PropSheetInfo * psInfo)
295 {
296   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
297   DWORD dwFlags = lppsh->dwFlags;
298
299   psInfo->hasHelp = dwFlags & PSH_HASHELP;
300   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
301   psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
302   psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);
303   psInfo->isModeless = dwFlags & PSH_MODELESS;
304
305   memcpy(&psInfo->ppshheader,lppsh,dwSize);
306   TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
307         lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,
308         debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
309
310   PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
311
312   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
313      psInfo->ppshheader.pszCaption = NULL;
314   else
315   {
316      if (HIWORD(lppsh->pszCaption))
317      {
318         int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0);
319         WCHAR *caption = Alloc( len*sizeof (WCHAR) );
320
321         MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, caption, len);
322         psInfo->ppshheader.pszCaption = caption;
323      }
324   }
325   psInfo->nPages = lppsh->nPages;
326
327   if (dwFlags & PSH_USEPSTARTPAGE)
328   {
329     TRACE("PSH_USEPSTARTPAGE is on\n");
330     psInfo->active_page = 0;
331   }
332   else
333     psInfo->active_page = lppsh->u2.nStartPage;
334
335   if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
336      psInfo->active_page = 0;
337
338   psInfo->result = 0;
339   psInfo->hImageList = 0;
340   psInfo->activeValid = FALSE;
341
342   return TRUE;
343 }
344
345 /******************************************************************************
346  *            PROPSHEET_CollectSheetInfoW
347  *
348  * Collect relevant data.
349  */
350 static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
351                                        PropSheetInfo * psInfo)
352 {
353   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));
354   DWORD dwFlags = lppsh->dwFlags;
355
356   psInfo->hasHelp = dwFlags & PSH_HASHELP;
357   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
358   psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
359   psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);
360   psInfo->isModeless = dwFlags & PSH_MODELESS;
361
362   memcpy(&psInfo->ppshheader,lppsh,dwSize);
363   TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%d\ndwFlags\t\t%08x\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n",
364       lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
365
366   PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
367
368   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
369      psInfo->ppshheader.pszCaption = NULL;
370   else
371   {
372      if (HIWORD(lppsh->pszCaption))
373      {
374         int len = strlenW(lppsh->pszCaption);
375         WCHAR *caption = Alloc( (len+1)*sizeof(WCHAR) );
376
377         psInfo->ppshheader.pszCaption = strcpyW( caption, lppsh->pszCaption );
378      }
379   }
380   psInfo->nPages = lppsh->nPages;
381
382   if (dwFlags & PSH_USEPSTARTPAGE)
383   {
384     TRACE("PSH_USEPSTARTPAGE is on\n");
385     psInfo->active_page = 0;
386   }
387   else
388     psInfo->active_page = lppsh->u2.nStartPage;
389
390   if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
391      psInfo->active_page = 0;
392
393   psInfo->result = 0;
394   psInfo->hImageList = 0;
395   psInfo->activeValid = FALSE;
396
397   return TRUE;
398 }
399
400 /******************************************************************************
401  *            PROPSHEET_CollectPageInfo
402  *
403  * Collect property sheet data.
404  * With code taken from DIALOG_ParseTemplate32.
405  */
406 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
407                                PropSheetInfo * psInfo,
408                                int index)
409 {
410   const DLGTEMPLATE* pTemplate;
411   const WORD*  p;
412   DWORD dwFlags;
413   int width, height;
414
415   if (!lppsp)
416     return FALSE;
417
418   TRACE("\n");
419   psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
420   psInfo->proppage[index].hwndPage = 0;
421   psInfo->proppage[index].isDirty = FALSE;
422
423   /*
424    * Process property page flags.
425    */
426   dwFlags = lppsp->dwFlags;
427   psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
428   psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
429   psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
430
431   /* as soon as we have a page with the help flag, set the sheet flag on */
432   if (psInfo->proppage[index].hasHelp)
433     psInfo->hasHelp = TRUE;
434
435   /*
436    * Process page template.
437    */
438   if (dwFlags & PSP_DLGINDIRECT)
439     pTemplate = lppsp->u.pResource;
440   else if(dwFlags & PSP_INTERNAL_UNICODE )
441   {
442     HRSRC hResource = FindResourceW(lppsp->hInstance,
443                                     lppsp->u.pszTemplate,
444                                     (LPWSTR)RT_DIALOG);
445     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
446                                      hResource);
447     pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
448   }
449   else
450   {
451     HRSRC hResource = FindResourceA(lppsp->hInstance,
452                                     (LPCSTR)lppsp->u.pszTemplate,
453                                     (LPSTR)RT_DIALOG);
454     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
455                                      hResource);
456     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
457   }
458
459   /*
460    * Extract the size of the page and the caption.
461    */
462   if (!pTemplate)
463       return FALSE;
464
465   p = (const WORD *)pTemplate;
466
467   if (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
468   {
469     /* DLGTEMPLATEEX (not defined in any std. header file) */
470
471     p++;       /* dlgVer    */
472     p++;       /* signature */
473     p += 2;    /* help ID   */
474     p += 2;    /* ext style */
475     p += 2;    /* style     */
476   }
477   else
478   {
479     /* DLGTEMPLATE */
480
481     p += 2;    /* style     */
482     p += 2;    /* ext style */
483   }
484
485   p++;    /* nb items */
486   p++;    /*   x      */
487   p++;    /*   y      */
488   width  = (WORD)*p; p++;
489   height = (WORD)*p; p++;
490
491   /* Special calculation for interior wizard pages so the largest page is
492    * calculated correctly. We need to add all the padding and space occupied
493    * by the header so the width and height sums up to the whole wizard client
494    * area. */
495   if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
496       (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
497       !(dwFlags & PSP_HIDEHEADER))
498   {
499       height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT;
500       width += 2 * WIZARD_PADDING;
501   }
502   if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
503   {
504       height += 2 * WIZARD_PADDING;
505       width += 2 * WIZARD_PADDING;
506   }
507
508   /* remember the largest width and height */
509   if (width > psInfo->width)
510     psInfo->width = width;
511
512   if (height > psInfo->height)
513     psInfo->height = height;
514
515   /* menu */
516   switch ((WORD)*p)
517   {
518     case 0x0000:
519       p++;
520       break;
521     case 0xffff:
522       p += 2;
523       break;
524     default:
525       p += lstrlenW( (LPCWSTR)p ) + 1;
526       break;
527   }
528
529   /* class */
530   switch ((WORD)*p)
531   {
532     case 0x0000:
533       p++;
534       break;
535     case 0xffff:
536       p += 2;
537       break;
538     default:
539       p += lstrlenW( (LPCWSTR)p ) + 1;
540       break;
541   }
542
543   /* Extract the caption */
544   psInfo->proppage[index].pszText = (LPCWSTR)p;
545   TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
546   p += lstrlenW((LPCWSTR)p) + 1;
547
548   if (dwFlags & PSP_USETITLE)
549   {
550     WCHAR szTitle[256];
551     const WCHAR *pTitle;
552     static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 };
553     WCHAR *text;
554     int len;
555
556     if ( !HIWORD( lppsp->pszTitle ) )
557     {
558       if (!LoadStringW( lppsp->hInstance, (DWORD_PTR)lppsp->pszTitle,szTitle,sizeof(szTitle) ))
559       {
560         pTitle = pszNull;
561         FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
562       }
563       else
564         pTitle = szTitle;
565     }
566     else
567       pTitle = lppsp->pszTitle;
568
569     len = strlenW(pTitle);
570     text = Alloc( (len+1)*sizeof (WCHAR) );
571     psInfo->proppage[index].pszText = strcpyW( text, pTitle);
572   }
573
574   /*
575    * Build the image list for icons
576    */
577   if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
578   {
579     HICON hIcon;
580     int icon_cx = GetSystemMetrics(SM_CXSMICON);
581     int icon_cy = GetSystemMetrics(SM_CYSMICON);
582
583     if (dwFlags & PSP_USEICONID)
584       hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
585                          icon_cx, icon_cy, LR_DEFAULTCOLOR);
586     else
587       hIcon = lppsp->u2.hIcon;
588
589     if ( hIcon )
590     {
591       if (psInfo->hImageList == 0 )
592         psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
593
594       ImageList_AddIcon(psInfo->hImageList, hIcon);
595     }
596
597   }
598
599   return TRUE;
600 }
601
602 /******************************************************************************
603  *            PROPSHEET_CreateDialog
604  *
605  * Creates the actual property sheet.
606  */
607 static INT_PTR PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
608 {
609   LRESULT ret;
610   LPCVOID template;
611   LPVOID temp = 0;
612   HRSRC hRes;
613   DWORD resSize;
614   WORD resID = IDD_PROPSHEET;
615
616   TRACE("\n");
617   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
618     resID = IDD_WIZARD;
619
620   if( psInfo->unicode )
621   {
622     if(!(hRes = FindResourceW(COMCTL32_hModule,
623                             MAKEINTRESOURCEW(resID),
624                             (LPWSTR)RT_DIALOG)))
625       return -1;
626   }
627   else
628   {
629     if(!(hRes = FindResourceA(COMCTL32_hModule,
630                             MAKEINTRESOURCEA(resID),
631                             (LPSTR)RT_DIALOG)))
632       return -1;
633   }
634
635   if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
636     return -1;
637
638   /*
639    * Make a copy of the dialog template.
640    */
641   resSize = SizeofResource(COMCTL32_hModule, hRes);
642
643   temp = Alloc(resSize);
644
645   if (!temp)
646     return -1;
647
648   memcpy(temp, template, resSize);
649
650   if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP)
651   {
652     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
653       ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP;
654     else
655       ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP;
656   }
657   if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) &&
658       (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP))
659   {
660     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
661       ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP;
662     else
663       ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP;
664   }
665
666   if (psInfo->useCallback)
667     (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
668
669   /* NOTE: MSDN states "Returns a positive value if successful, or -1
670    * otherwise for modal property sheets.", but this is wrong. The
671    * actual return value is either TRUE (success), FALSE (cancel) or
672    * -1 (error). */
673   if( psInfo->unicode )
674   {
675     ret = (INT_PTR)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,
676                                           (LPDLGTEMPLATEW) temp,
677                                           psInfo->ppshheader.hwndParent,
678                                           PROPSHEET_DialogProc,
679                                           (LPARAM)psInfo);
680     if ( !ret ) ret = -1;
681   }
682   else
683   {
684     ret = (INT_PTR)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
685                                           (LPDLGTEMPLATEA) temp,
686                                           psInfo->ppshheader.hwndParent,
687                                           PROPSHEET_DialogProc,
688                                           (LPARAM)psInfo);
689     if ( !ret ) ret = -1;
690   }
691
692   Free(temp);
693
694   return ret;
695 }
696
697 /******************************************************************************
698  *            PROPSHEET_SizeMismatch
699  *
700  *     Verify that the tab control and the "largest" property sheet page dlg. template
701  *     match in size.
702  */
703 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
704 {
705   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
706   RECT rcOrigTab, rcPage;
707
708   /*
709    * Original tab size.
710    */
711   GetClientRect(hwndTabCtrl, &rcOrigTab);
712   TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
713         rcOrigTab.right, rcOrigTab.bottom);
714
715   /*
716    * Biggest page size.
717    */
718   rcPage.left   = 0;
719   rcPage.top    = 0;
720   rcPage.right  = psInfo->width;
721   rcPage.bottom = psInfo->height;
722
723   MapDialogRect(hwndDlg, &rcPage);
724   TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
725         rcPage.right, rcPage.bottom);
726
727   if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
728     return TRUE;
729   if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
730     return TRUE;
731
732   return FALSE;
733 }
734
735 /******************************************************************************
736  *            PROPSHEET_AdjustSize
737  *
738  * Resizes the property sheet and the tab control to fit the largest page.
739  */
740 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
741 {
742   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
743   HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
744   RECT rc,tabRect;
745   int tabOffsetX, tabOffsetY, buttonHeight;
746   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
747   RECT units;
748
749   /* Get the height of buttons */
750   GetClientRect(hwndButton, &rc);
751   buttonHeight = rc.bottom;
752
753   /*
754    * Biggest page size.
755    */
756   rc.left   = 0;
757   rc.top    = 0;
758   rc.right  = psInfo->width;
759   rc.bottom = psInfo->height;
760
761   MapDialogRect(hwndDlg, &rc);
762
763   /* retrieve the dialog units */
764   units.left = units.right = 4;
765   units.top = units.bottom = 8;
766   MapDialogRect(hwndDlg, &units);
767
768   /*
769    * Resize the tab control.
770    */
771   GetClientRect(hwndTabCtrl,&tabRect);
772
773   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
774
775   if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
776   {
777       rc.bottom = rc.top + tabRect.bottom - tabRect.top;
778       psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
779   }
780
781   if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
782   {
783       rc.right = rc.left + tabRect.right - tabRect.left;
784       psInfo->width  = MulDiv((rc.right - rc.left),4,units.left);
785   }
786
787   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
788
789   tabOffsetX = -(rc.left);
790   tabOffsetY = -(rc.top);
791
792   rc.right -= rc.left;
793   rc.bottom -= rc.top;
794   TRACE("setting tab %p, rc (0,0)-(%d,%d)\n",
795         hwndTabCtrl, rc.right, rc.bottom);
796   SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
797                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
798
799   GetClientRect(hwndTabCtrl, &rc);
800
801   TRACE("tab client rc %d %d %d %d\n",
802         rc.left, rc.top, rc.right, rc.bottom);
803
804   rc.right += ((padding.x * 2) + tabOffsetX);
805   rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
806
807   /*
808    * Resize the property sheet.
809    */
810   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
811         hwndDlg, rc.right, rc.bottom);
812   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
813                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
814   return TRUE;
815 }
816
817 /******************************************************************************
818  *            PROPSHEET_AdjustSizeWizard
819  *
820  * Resizes the property sheet to fit the largest page.
821  */
822 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
823 {
824   HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
825   RECT rc, lineRect, dialogRect;
826
827   /* Biggest page size */
828   rc.left   = 0;
829   rc.top    = 0;
830   rc.right  = psInfo->width;
831   rc.bottom = psInfo->height;
832   MapDialogRect(hwndDlg, &rc);
833
834   TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
835
836   /* Add space for the buttons row */
837   GetWindowRect(hwndLine, &lineRect);
838   MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2);
839   GetClientRect(hwndDlg, &dialogRect);
840   rc.bottom += dialogRect.bottom - lineRect.top - 1;
841
842   /* Convert the client coordinates to window coordinates */
843   AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE);
844
845   /* Resize the property sheet */
846   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
847         hwndDlg, rc.right, rc.bottom);
848   SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
849                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
850
851   return TRUE;
852 }
853
854 /******************************************************************************
855  *            PROPSHEET_AdjustButtons
856  *
857  * Adjusts the buttons' positions.
858  */
859 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
860 {
861   HWND hwndButton = GetDlgItem(hwndParent, IDOK);
862   RECT rcSheet;
863   int x, y;
864   int num_buttons = 2;
865   int buttonWidth, buttonHeight;
866   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
867
868   if (psInfo->hasApply)
869     num_buttons++;
870
871   if (psInfo->hasHelp)
872     num_buttons++;
873
874   /*
875    * Obtain the size of the buttons.
876    */
877   GetClientRect(hwndButton, &rcSheet);
878   buttonWidth = rcSheet.right;
879   buttonHeight = rcSheet.bottom;
880
881   /*
882    * Get the size of the property sheet.
883    */
884   GetClientRect(hwndParent, &rcSheet);
885
886   /*
887    * All buttons will be at this y coordinate.
888    */
889   y = rcSheet.bottom - (padding.y + buttonHeight);
890
891   /*
892    * Position OK button and make it default.
893    */
894   hwndButton = GetDlgItem(hwndParent, IDOK);
895
896   x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
897
898   SetWindowPos(hwndButton, 0, x, y, 0, 0,
899                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
900
901   SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0);
902
903
904   /*
905    * Position Cancel button.
906    */
907   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
908
909   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
910
911   SetWindowPos(hwndButton, 0, x, y, 0, 0,
912                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
913
914   /*
915    * Position Apply button.
916    */
917   hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
918
919   if (psInfo->hasApply)
920   {
921     if (psInfo->hasHelp)
922       x = rcSheet.right - ((padding.x + buttonWidth) * 2);
923     else
924       x = rcSheet.right - (padding.x + buttonWidth);
925
926     SetWindowPos(hwndButton, 0, x, y, 0, 0,
927                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
928
929     EnableWindow(hwndButton, FALSE);
930   }
931   else
932     ShowWindow(hwndButton, SW_HIDE);
933
934   /*
935    * Position Help button.
936    */
937   hwndButton = GetDlgItem(hwndParent, IDHELP);
938
939   if (psInfo->hasHelp)
940   {
941     x = rcSheet.right - (padding.x + buttonWidth);
942
943     SetWindowPos(hwndButton, 0, x, y, 0, 0,
944                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
945   }
946   else
947     ShowWindow(hwndButton, SW_HIDE);
948
949   return TRUE;
950 }
951
952 /******************************************************************************
953  *            PROPSHEET_AdjustButtonsWizard
954  *
955  * Adjusts the buttons' positions.
956  */
957 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
958                                           PropSheetInfo* psInfo)
959 {
960   HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
961   HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
962   HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER);
963   RECT rcSheet;
964   int x, y;
965   int num_buttons = 3;
966   int buttonWidth, buttonHeight, lineHeight, lineWidth;
967   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
968
969   if (psInfo->hasHelp)
970     num_buttons++;
971   if (psInfo->hasFinish)
972     num_buttons++;
973
974   /*
975    * Obtain the size of the buttons.
976    */
977   GetClientRect(hwndButton, &rcSheet);
978   buttonWidth = rcSheet.right;
979   buttonHeight = rcSheet.bottom;
980
981   GetClientRect(hwndLine, &rcSheet);
982   lineHeight = rcSheet.bottom;
983
984   /*
985    * Get the size of the property sheet.
986    */
987   GetClientRect(hwndParent, &rcSheet);
988
989   /*
990    * All buttons will be at this y coordinate.
991    */
992   y = rcSheet.bottom - (padding.y + buttonHeight);
993   
994   /*
995    * Position the Back button.
996    */
997   hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
998
999   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)) - buttonWidth;
1000
1001   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1002                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1003
1004   /*
1005    * Position the Next button.
1006    */
1007   hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
1008   
1009   x += buttonWidth;
1010   
1011   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1012                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1013
1014   /*
1015    * Position the Finish button.
1016    */
1017   hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
1018   
1019   if (psInfo->hasFinish)
1020     x += padding.x + buttonWidth;
1021
1022   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1023                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1024
1025   if (!psInfo->hasFinish)
1026     ShowWindow(hwndButton, SW_HIDE);
1027
1028   /*
1029    * Position the Cancel button.
1030    */
1031   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
1032
1033   x += padding.x + buttonWidth;
1034
1035   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1036                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1037
1038   /*
1039    * Position Help button.
1040    */
1041   hwndButton = GetDlgItem(hwndParent, IDHELP);
1042
1043   if (psInfo->hasHelp)
1044   {
1045     x += padding.x + buttonWidth;
1046
1047     SetWindowPos(hwndButton, 0, x, y, 0, 0,
1048                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1049   }
1050   else
1051     ShowWindow(hwndButton, SW_HIDE);
1052
1053   if (psInfo->ppshheader.dwFlags &
1054       (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) 
1055       padding.x = 0;
1056
1057   /*
1058    * Position and resize the sunken line.
1059    */
1060   x = padding.x;
1061   y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
1062
1063   lineWidth = rcSheet.right - (padding.x * 2);
1064   SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
1065                SWP_NOZORDER | SWP_NOACTIVATE);
1066
1067   /*
1068    * Position and resize the header sunken line.
1069    */
1070   
1071   SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2,
1072                SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1073   if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)))
1074       ShowWindow(hwndLineHeader, SW_HIDE);
1075
1076   return TRUE;
1077 }
1078
1079 /******************************************************************************
1080  *            PROPSHEET_GetPaddingInfo
1081  *
1082  * Returns the layout information.
1083  */
1084 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
1085 {
1086   HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1087   RECT rcTab;
1088   POINT tl;
1089   PADDING_INFO padding;
1090
1091   GetWindowRect(hwndTab, &rcTab);
1092
1093   tl.x = rcTab.left;
1094   tl.y = rcTab.top;
1095
1096   ScreenToClient(hwndDlg, &tl);
1097
1098   padding.x = tl.x;
1099   padding.y = tl.y;
1100
1101   return padding;
1102 }
1103
1104 /******************************************************************************
1105  *            PROPSHEET_GetPaddingInfoWizard
1106  *
1107  * Returns the layout information.
1108  * Vertical spacing is the distance between the line and the buttons.
1109  * Do NOT use the Help button to gather padding information when it isn't mapped
1110  * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
1111  * for it in this case !
1112  * FIXME: I'm not sure about any other coordinate problems with these evil
1113  * buttons. Fix it in case additional problems appear or maybe calculate
1114  * a padding in a completely different way, as this is somewhat messy.
1115  */
1116 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
1117  psInfo)
1118 {
1119   PADDING_INFO padding;
1120   RECT rc;
1121   HWND hwndControl;
1122   INT idButton;
1123   POINT ptButton, ptLine;
1124
1125   TRACE("\n");
1126   if (psInfo->hasHelp)
1127   {
1128         idButton = IDHELP;
1129   }
1130   else
1131   {
1132     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1133     {
1134         idButton = IDC_NEXT_BUTTON;
1135     }
1136     else
1137     {
1138         /* hopefully this is ok */
1139         idButton = IDCANCEL;
1140     }
1141   }
1142
1143   hwndControl = GetDlgItem(hwndDlg, idButton);
1144   GetWindowRect(hwndControl, &rc);
1145
1146   ptButton.x = rc.left;
1147   ptButton.y = rc.top;
1148
1149   ScreenToClient(hwndDlg, &ptButton);
1150
1151   /* Line */
1152   hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
1153   GetWindowRect(hwndControl, &rc);
1154
1155   ptLine.x = rc.left;
1156   ptLine.y = rc.bottom;
1157
1158   ScreenToClient(hwndDlg, &ptLine);
1159
1160   padding.y = ptButton.y - ptLine.y;
1161
1162   if (padding.y < 0)
1163           ERR("padding negative ! Please report this !\n");
1164
1165   /* this is most probably not correct, but the best we have now */
1166   padding.x = padding.y;
1167   return padding;
1168 }
1169
1170 /******************************************************************************
1171  *            PROPSHEET_CreateTabControl
1172  *
1173  * Insert the tabs in the tab control.
1174  */
1175 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
1176                                        PropSheetInfo * psInfo)
1177 {
1178   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1179   TCITEMW item;
1180   int i, nTabs;
1181   int iImage = 0;
1182
1183   TRACE("\n");
1184   item.mask = TCIF_TEXT;
1185   item.cchTextMax = MAX_TABTEXT_LENGTH;
1186
1187   nTabs = psInfo->nPages;
1188
1189   /*
1190    * Set the image list for icons.
1191    */
1192   if (psInfo->hImageList)
1193   {
1194     SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
1195   }
1196
1197   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 0, 0);
1198   for (i = 0; i < nTabs; i++)
1199   {
1200     if ( psInfo->proppage[i].hasIcon )
1201     {
1202       item.mask |= TCIF_IMAGE;
1203       item.iImage = iImage++;
1204     }
1205     else
1206     {
1207       item.mask &= ~TCIF_IMAGE;
1208     }
1209
1210     item.pszText = (LPWSTR) psInfo->proppage[i].pszText;
1211     SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item);
1212   }
1213   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 1, 0);
1214
1215   return TRUE;
1216 }
1217
1218 /******************************************************************************
1219  *            PROPSHEET_WizardSubclassProc
1220  *
1221  * Subclassing window procedure for wizard extrior pages to prevent drawing
1222  * background and so drawing above the watermark.
1223  */
1224 static LRESULT CALLBACK
1225 PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
1226 {
1227   switch (uMsg)
1228   {
1229     case WM_ERASEBKGND:
1230       return TRUE;
1231
1232     case WM_CTLCOLORSTATIC:
1233       SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
1234       return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
1235   }
1236
1237   return DefSubclassProc(hwnd, uMsg, wParam, lParam);
1238 }
1239
1240 /*
1241  * Get the size of an in-memory Template
1242  *
1243  *( Based on the code of PROPSHEET_CollectPageInfo)
1244  * See also dialog.c/DIALOG_ParseTemplate32().
1245  */
1246
1247 static UINT GetTemplateSize(const DLGTEMPLATE* pTemplate)
1248
1249 {
1250   const WORD*  p = (const WORD *)pTemplate;
1251   BOOL  istemplateex = (((const MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF);
1252   WORD nrofitems;
1253   UINT ret;
1254
1255   if (istemplateex)
1256   {
1257     /* DLGTEMPLATEEX (not defined in any std. header file) */
1258
1259     TRACE("is DLGTEMPLATEEX\n");
1260     p++;       /* dlgVer    */
1261     p++;       /* signature */
1262     p += 2;    /* help ID   */
1263     p += 2;    /* ext style */
1264     p += 2;    /* style     */
1265   }
1266   else
1267   {
1268     /* DLGTEMPLATE */
1269
1270     TRACE("is DLGTEMPLATE\n");
1271     p += 2;    /* style     */
1272     p += 2;    /* ext style */
1273   }
1274
1275   nrofitems =   (WORD)*p; p++;    /* nb items */
1276   p++;    /*   x      */
1277   p++;    /*   y      */
1278   p++;    /*   width  */
1279   p++;    /*   height */
1280
1281   /* menu */
1282   switch ((WORD)*p)
1283   {
1284     case 0x0000:
1285       p++;
1286       break;
1287     case 0xffff:
1288       p += 2;
1289       break;
1290     default:
1291       TRACE("menu %s\n",debugstr_w((LPCWSTR)p));
1292       p += lstrlenW( (LPCWSTR)p ) + 1;
1293       break;
1294   }
1295
1296   /* class */
1297   switch ((WORD)*p)
1298   {
1299     case 0x0000:
1300       p++;
1301       break;
1302     case 0xffff:
1303       p += 2; /* 0xffff plus predefined window class ordinal value */
1304       break;
1305     default:
1306       TRACE("class %s\n",debugstr_w((LPCWSTR)p));
1307       p += lstrlenW( (LPCWSTR)p ) + 1;
1308       break;
1309   }
1310
1311   /* title */
1312   TRACE("title %s\n",debugstr_w((LPCWSTR)p));
1313   p += lstrlenW((LPCWSTR)p) + 1;
1314
1315   /* font, if DS_SETFONT set */
1316   if ((DS_SETFONT & ((istemplateex)?  ((const MyDLGTEMPLATEEX*)pTemplate)->style :
1317                      pTemplate->style)))
1318     {
1319       p+=(istemplateex)?3:1;
1320       TRACE("font %s\n",debugstr_w((LPCWSTR)p));
1321       p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */
1322     }
1323
1324   /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)
1325    * that are following the DLGTEMPLATE(EX) data */
1326   TRACE("%d items\n",nrofitems);
1327   while (nrofitems > 0)
1328     {
1329       p = (WORD*)(((DWORD_PTR)p + 3) & ~3); /* DWORD align */
1330       
1331       /* skip header */
1332       p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD);
1333       
1334       /* check class */
1335       switch ((WORD)*p)
1336         {
1337         case 0x0000:
1338           p++;
1339           break;
1340         case 0xffff:
1341           TRACE("class ordinal 0x%08x\n",*(const DWORD*)p);
1342           p += 2;
1343           break;
1344         default:
1345           TRACE("class %s\n",debugstr_w((LPCWSTR)p));
1346           p += lstrlenW( (LPCWSTR)p ) + 1;
1347           break;
1348         }
1349
1350       /* check title text */
1351       switch ((WORD)*p)
1352         {
1353         case 0x0000:
1354           p++;
1355           break;
1356         case 0xffff:
1357           TRACE("text ordinal 0x%08x\n",*(const DWORD*)p);
1358           p += 2;
1359           break;
1360         default:
1361           TRACE("text %s\n",debugstr_w((LPCWSTR)p));
1362           p += lstrlenW( (LPCWSTR)p ) + 1;
1363           break;
1364         }
1365       p += *p / sizeof(WORD) + 1;    /* Skip extra data */
1366       --nrofitems;
1367     }
1368   
1369   ret = (p - (const WORD*)pTemplate) * sizeof(WORD);
1370   TRACE("%p %p size 0x%08x\n", p, pTemplate, ret);
1371   return ret;
1372 }
1373
1374 /******************************************************************************
1375  *            PROPSHEET_CreatePage
1376  *
1377  * Creates a page.
1378  */
1379 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
1380                                 int index,
1381                                 const PropSheetInfo * psInfo,
1382                                 LPCPROPSHEETPAGEW ppshpage)
1383 {
1384   DLGTEMPLATE* pTemplate;
1385   HWND hwndPage;
1386   DWORD resSize;
1387   LPVOID temp = NULL;
1388
1389   TRACE("index %d\n", index);
1390
1391   if (ppshpage == NULL)
1392   {
1393     return FALSE;
1394   }
1395
1396   if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1397     {
1398       pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
1399       resSize = GetTemplateSize(pTemplate);
1400     }
1401   else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
1402   {
1403     HRSRC hResource;
1404     HANDLE hTemplate;
1405
1406     hResource = FindResourceW(ppshpage->hInstance,
1407                                     ppshpage->u.pszTemplate,
1408                                     (LPWSTR)RT_DIALOG);
1409     if(!hResource)
1410         return FALSE;
1411
1412     resSize = SizeofResource(ppshpage->hInstance, hResource);
1413
1414     hTemplate = LoadResource(ppshpage->hInstance, hResource);
1415     if(!hTemplate)
1416         return FALSE;
1417
1418     pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
1419     /*
1420      * Make a copy of the dialog template to make it writable
1421      */
1422   }
1423   else
1424   {
1425     HRSRC hResource;
1426     HANDLE hTemplate;
1427
1428     hResource = FindResourceA(ppshpage->hInstance,
1429                                     (LPCSTR)ppshpage->u.pszTemplate,
1430                                     (LPSTR)RT_DIALOG);
1431     if(!hResource)
1432         return FALSE;
1433
1434     resSize = SizeofResource(ppshpage->hInstance, hResource);
1435
1436     hTemplate = LoadResource(ppshpage->hInstance, hResource);
1437     if(!hTemplate)
1438         return FALSE;
1439
1440     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1441     /*
1442      * Make a copy of the dialog template to make it writable
1443      */
1444   }
1445   temp = Alloc(resSize);
1446   if (!temp)
1447     return FALSE;
1448   
1449   TRACE("copying pTemplate %p into temp %p (%d)\n", pTemplate, temp, resSize);
1450   memcpy(temp, pTemplate, resSize);
1451   pTemplate = temp;
1452
1453   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1454   {
1455     ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
1456     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1457     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1458     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1459     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1460     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1461     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1462     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME;
1463
1464     ((MyDLGTEMPLATEEX*)pTemplate)->exStyle |= WS_EX_CONTROLPARENT;
1465   }
1466   else
1467   {
1468     pTemplate->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
1469     pTemplate->style &= ~DS_MODALFRAME;
1470     pTemplate->style &= ~WS_CAPTION;
1471     pTemplate->style &= ~WS_SYSMENU;
1472     pTemplate->style &= ~WS_POPUP;
1473     pTemplate->style &= ~WS_DISABLED;
1474     pTemplate->style &= ~WS_VISIBLE;
1475     pTemplate->style &= ~WS_THICKFRAME;
1476
1477     pTemplate->dwExtendedStyle |= WS_EX_CONTROLPARENT;
1478   }
1479
1480   if (psInfo->proppage[index].useCallback)
1481     (*(ppshpage->pfnCallback))(0, PSPCB_CREATE,
1482                                (LPPROPSHEETPAGEW)ppshpage);
1483
1484   if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
1485      hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,
1486                                         pTemplate,
1487                                         hwndParent,
1488                                         ppshpage->pfnDlgProc,
1489                                         (LPARAM)ppshpage);
1490   else
1491      hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1492                                         pTemplate,
1493                                         hwndParent,
1494                                         ppshpage->pfnDlgProc,
1495                                         (LPARAM)ppshpage);
1496   /* Free a no more needed copy */
1497   if(temp)
1498       Free(temp);
1499
1500   psInfo->proppage[index].hwndPage = hwndPage;
1501
1502   /* Subclass exterior wizard pages */
1503   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
1504      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1505      (ppshpage->dwFlags & PSP_HIDEHEADER))
1506   {
1507       SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1,
1508                         (DWORD_PTR)ppshpage);
1509   }
1510   if (!(psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD))
1511       EnableThemeDialogTexture (hwndPage, ETDT_ENABLETAB);
1512
1513   return TRUE;
1514 }
1515
1516 /******************************************************************************
1517  *            PROPSHEET_LoadWizardBitmaps
1518  *
1519  * Loads the watermark and header bitmaps for a wizard.
1520  */
1521 static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo)
1522 {
1523   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD))
1524   {
1525     /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark 
1526        and put the HBITMAP in hbmWatermark. Thus all the rest of the code always 
1527        considers hbmWatermark as valid. */
1528     if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1529         !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK))
1530     {
1531       ((PropSheetInfo *)psInfo)->ppshheader.u4.hbmWatermark = 
1532         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0);
1533     }
1534
1535     /* Same behavior as for watermarks */
1536     if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
1537         !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER))
1538     {
1539       ((PropSheetInfo *)psInfo)->ppshheader.u5.hbmHeader = 
1540         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0);
1541     }
1542   }
1543 }
1544
1545
1546 /******************************************************************************
1547  *            PROPSHEET_ShowPage
1548  *
1549  * Displays or creates the specified page.
1550  */
1551 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1552 {
1553   HWND hwndTabCtrl;
1554   HWND hwndLineHeader;
1555   LPCPROPSHEETPAGEW ppshpage;
1556
1557   TRACE("active_page %d, index %d\n", psInfo->active_page, index);
1558   if (index == psInfo->active_page)
1559   {
1560       if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1561           SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1562       return TRUE;
1563   }
1564
1565   ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1566   if (psInfo->proppage[index].hwndPage == 0)
1567   {
1568      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1569   }
1570
1571   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1572   {
1573      PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,
1574                          psInfo->proppage[index].pszText);
1575   }
1576
1577   if (psInfo->active_page != -1)
1578      ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1579
1580   ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1581
1582   /* Synchronize current selection with tab control
1583    * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1584   hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1585   SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1586
1587   psInfo->active_page = index;
1588   psInfo->activeValid = TRUE;
1589
1590   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) )
1591   {
1592       hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
1593       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1594       
1595       if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) )
1596           ShowWindow(hwndLineHeader, SW_HIDE);
1597       else
1598           ShowWindow(hwndLineHeader, SW_SHOW);
1599   }
1600
1601   return TRUE;
1602 }
1603
1604 /******************************************************************************
1605  *            PROPSHEET_Back
1606  */
1607 static BOOL PROPSHEET_Back(HWND hwndDlg)
1608 {
1609   PSHNOTIFY psn;
1610   HWND hwndPage;
1611   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1612                                                     PropSheetInfoStr);
1613   LRESULT result;
1614   int idx;
1615
1616   TRACE("active_page %d\n", psInfo->active_page);
1617   if (psInfo->active_page < 0)
1618      return FALSE;
1619
1620   psn.hdr.code     = PSN_WIZBACK;
1621   psn.hdr.hwndFrom = hwndDlg;
1622   psn.hdr.idFrom   = 0;
1623   psn.lParam       = 0;
1624
1625   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1626
1627   result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1628   if (result == -1)
1629     return FALSE;
1630   else if (result == 0)
1631      idx = psInfo->active_page - 1;
1632   else
1633      idx = PROPSHEET_FindPageByResId(psInfo, result);
1634
1635   if (idx >= 0 && idx < psInfo->nPages)
1636   {
1637      if (PROPSHEET_CanSetCurSel(hwndDlg))
1638         PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);
1639   }
1640   return TRUE;
1641 }
1642
1643 /******************************************************************************
1644  *            PROPSHEET_Next
1645  */
1646 static BOOL PROPSHEET_Next(HWND hwndDlg)
1647 {
1648   PSHNOTIFY psn;
1649   HWND hwndPage;
1650   LRESULT msgResult = 0;
1651   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1652                                                     PropSheetInfoStr);
1653   int idx;
1654
1655   TRACE("active_page %d\n", psInfo->active_page);
1656   if (psInfo->active_page < 0)
1657      return FALSE;
1658
1659   psn.hdr.code     = PSN_WIZNEXT;
1660   psn.hdr.hwndFrom = hwndDlg;
1661   psn.hdr.idFrom   = 0;
1662   psn.lParam       = 0;
1663
1664   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1665
1666   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1667   if (msgResult == -1)
1668     return FALSE;
1669   else if (msgResult == 0)
1670      idx = psInfo->active_page + 1;
1671   else
1672      idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
1673
1674   if (idx < psInfo->nPages )
1675   {
1676      if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1677         PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
1678   }
1679
1680   return TRUE;
1681 }
1682
1683 /******************************************************************************
1684  *            PROPSHEET_Finish
1685  */
1686 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1687 {
1688   PSHNOTIFY psn;
1689   HWND hwndPage;
1690   LRESULT msgResult = 0;
1691   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1692                                                     PropSheetInfoStr);
1693
1694   TRACE("active_page %d\n", psInfo->active_page);
1695   if (psInfo->active_page < 0)
1696      return FALSE;
1697
1698   psn.hdr.code     = PSN_WIZFINISH;
1699   psn.hdr.hwndFrom = hwndDlg;
1700   psn.hdr.idFrom   = 0;
1701   psn.lParam       = 0;
1702
1703   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1704
1705   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1706
1707   TRACE("msg result %ld\n", msgResult);
1708
1709   if (msgResult != 0)
1710     return FALSE;
1711
1712   if (psInfo->result == 0)
1713       psInfo->result = IDOK;
1714   if (psInfo->isModeless)
1715     psInfo->activeValid = FALSE;
1716   else
1717     psInfo->ended = TRUE;
1718
1719   return TRUE;
1720 }
1721
1722 /******************************************************************************
1723  *            PROPSHEET_Apply
1724  */
1725 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1726 {
1727   int i;
1728   HWND hwndPage;
1729   PSHNOTIFY psn;
1730   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1731                                                     PropSheetInfoStr);
1732
1733   TRACE("active_page %d\n", psInfo->active_page);
1734   if (psInfo->active_page < 0)
1735      return FALSE;
1736
1737   psn.hdr.hwndFrom = hwndDlg;
1738   psn.hdr.idFrom   = 0;
1739   psn.lParam       = 0;
1740
1741
1742   /*
1743    * Send PSN_KILLACTIVE to the current page.
1744    */
1745   psn.hdr.code = PSN_KILLACTIVE;
1746
1747   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1748
1749   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1750     return FALSE;
1751
1752   /*
1753    * Send PSN_APPLY to all pages.
1754    */
1755   psn.hdr.code = PSN_APPLY;
1756   psn.lParam   = lParam;
1757
1758   for (i = 0; i < psInfo->nPages; i++)
1759   {
1760     hwndPage = psInfo->proppage[i].hwndPage;
1761     if (hwndPage)
1762     {
1763        switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1764        {
1765        case PSNRET_INVALID:
1766            PROPSHEET_ShowPage(hwndDlg, i, psInfo);
1767            /* fall through */
1768        case PSNRET_INVALID_NOCHANGEPAGE:
1769            return FALSE;
1770        }
1771     }
1772   }
1773
1774   if(lParam)
1775   {
1776      psInfo->activeValid = FALSE;
1777   }
1778   else if(psInfo->active_page >= 0)
1779   {
1780      psn.hdr.code = PSN_SETACTIVE;
1781      psn.lParam   = 0;
1782      hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1783      SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1784   }
1785
1786   return TRUE;
1787 }
1788
1789 /******************************************************************************
1790  *            PROPSHEET_Cancel
1791  */
1792 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1793 {
1794   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1795                                                     PropSheetInfoStr);
1796   HWND hwndPage;
1797   PSHNOTIFY psn;
1798   int i;
1799
1800   TRACE("active_page %d\n", psInfo->active_page);
1801   if (psInfo->active_page < 0)
1802      return;
1803
1804   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1805   psn.hdr.code     = PSN_QUERYCANCEL;
1806   psn.hdr.hwndFrom = hwndDlg;
1807   psn.hdr.idFrom   = 0;
1808   psn.lParam       = 0;
1809
1810   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1811     return;
1812
1813   psn.hdr.code = PSN_RESET;
1814   psn.lParam   = lParam;
1815
1816   for (i = 0; i < psInfo->nPages; i++)
1817   {
1818     hwndPage = psInfo->proppage[i].hwndPage;
1819
1820     if (hwndPage)
1821        SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1822   }
1823
1824   if (psInfo->isModeless)
1825   {
1826      /* makes PSM_GETCURRENTPAGEHWND return NULL */
1827      psInfo->activeValid = FALSE;
1828   }
1829   else
1830     psInfo->ended = TRUE;
1831 }
1832
1833 /******************************************************************************
1834  *            PROPSHEET_Help
1835  */
1836 static void PROPSHEET_Help(HWND hwndDlg)
1837 {
1838   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1839                                                     PropSheetInfoStr);
1840   HWND hwndPage;
1841   PSHNOTIFY psn;
1842
1843   TRACE("active_page %d\n", psInfo->active_page);
1844   if (psInfo->active_page < 0)
1845      return;
1846
1847   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1848   psn.hdr.code     = PSN_HELP;
1849   psn.hdr.hwndFrom = hwndDlg;
1850   psn.hdr.idFrom   = 0;
1851   psn.lParam       = 0;
1852
1853   SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1854 }
1855
1856 /******************************************************************************
1857  *            PROPSHEET_Changed
1858  */
1859 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1860 {
1861   int i;
1862   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1863                                                     PropSheetInfoStr);
1864
1865   TRACE("\n");
1866   if (!psInfo) return;
1867   /*
1868    * Set the dirty flag of this page.
1869    */
1870   for (i = 0; i < psInfo->nPages; i++)
1871   {
1872     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1873       psInfo->proppage[i].isDirty = TRUE;
1874   }
1875
1876   /*
1877    * Enable the Apply button.
1878    */
1879   if (psInfo->hasApply)
1880   {
1881     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1882
1883     EnableWindow(hwndApplyBtn, TRUE);
1884   }
1885 }
1886
1887 /******************************************************************************
1888  *            PROPSHEET_UnChanged
1889  */
1890 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1891 {
1892   int i;
1893   BOOL noPageDirty = TRUE;
1894   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1895   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1896                                                     PropSheetInfoStr);
1897
1898   TRACE("\n");
1899   if ( !psInfo ) return;
1900   for (i = 0; i < psInfo->nPages; i++)
1901   {
1902     /* set the specified page as clean */
1903     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1904       psInfo->proppage[i].isDirty = FALSE;
1905
1906     /* look to see if there's any dirty pages */
1907     if (psInfo->proppage[i].isDirty)
1908       noPageDirty = FALSE;
1909   }
1910
1911   /*
1912    * Disable Apply button.
1913    */
1914   if (noPageDirty)
1915     EnableWindow(hwndApplyBtn, FALSE);
1916 }
1917
1918 /******************************************************************************
1919  *            PROPSHEET_PressButton
1920  */
1921 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1922 {
1923   TRACE("buttonID %d\n", buttonID);
1924   switch (buttonID)
1925   {
1926     case PSBTN_APPLYNOW:
1927       PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
1928       break;
1929     case PSBTN_BACK:
1930       PROPSHEET_Back(hwndDlg);
1931       break;
1932     case PSBTN_CANCEL:
1933       PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
1934       break;
1935     case PSBTN_FINISH:
1936       PROPSHEET_Finish(hwndDlg);
1937       break;
1938     case PSBTN_HELP:
1939       PROPSHEET_DoCommand(hwndDlg, IDHELP);
1940       break;
1941     case PSBTN_NEXT:
1942       PROPSHEET_Next(hwndDlg);
1943       break;
1944     case PSBTN_OK:
1945       PROPSHEET_DoCommand(hwndDlg, IDOK);
1946       break;
1947     default:
1948       FIXME("Invalid button index %d\n", buttonID);
1949   }
1950 }
1951
1952
1953 /*************************************************************************
1954  * BOOL PROPSHEET_CanSetCurSel [Internal]
1955  *
1956  * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1957  *
1958  * PARAMS
1959  *     hwndDlg        [I] handle to a Dialog hWnd
1960  *
1961  * RETURNS
1962  *     TRUE if Current Selection can change
1963  *
1964  * NOTES
1965  */
1966 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1967 {
1968   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1969                                                     PropSheetInfoStr);
1970   HWND hwndPage;
1971   PSHNOTIFY psn;
1972   BOOL res = FALSE;
1973
1974   TRACE("active_page %d\n", psInfo->active_page);
1975   if (!psInfo)
1976   {
1977      res = FALSE;
1978      goto end;
1979   }
1980
1981   if (psInfo->active_page < 0)
1982   {
1983      res = TRUE;
1984      goto end;
1985   }
1986
1987   /*
1988    * Notify the current page.
1989    */
1990   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1991   psn.hdr.code     = PSN_KILLACTIVE;
1992   psn.hdr.hwndFrom = hwndDlg;
1993   psn.hdr.idFrom   = 0;
1994   psn.lParam       = 0;
1995
1996   res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1997
1998 end:
1999   TRACE("<-- %d\n", res);
2000   return res;
2001 }
2002
2003 /******************************************************************************
2004  *            PROPSHEET_SetCurSel
2005  */
2006 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
2007                                 int index,
2008                                 int skipdir,
2009                                 HPROPSHEETPAGE hpage
2010                                 )
2011 {
2012   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2013   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
2014   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2015
2016   TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
2017   /* hpage takes precedence over index */
2018   if (hpage != NULL)
2019     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2020
2021   if (index < 0 || index >= psInfo->nPages)
2022   {
2023     TRACE("Could not find page to select!\n");
2024     return FALSE;
2025   }
2026
2027   while (1) {
2028     int result;
2029     PSHNOTIFY psn;
2030     RECT rc;
2031     LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2032
2033     if (hwndTabControl)
2034         SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);
2035
2036     psn.hdr.code     = PSN_SETACTIVE;
2037     psn.hdr.hwndFrom = hwndDlg;
2038     psn.hdr.idFrom   = 0;
2039     psn.lParam       = 0;
2040
2041     if (!psInfo->proppage[index].hwndPage) {
2042       PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
2043     }
2044
2045     /* Resize the property sheet page to the fit in the Tab control
2046      * (for regular property sheets) or to fit in the client area (for
2047      * wizards).
2048      * NOTE: The resizing happens every time the page is selected and
2049      * not only when it's created (some applications depend on it). */
2050     PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage);
2051     TRACE("setting page %p, rc (%d,%d)-(%d,%d) w=%d, h=%d\n",
2052           psInfo->proppage[index].hwndPage, rc.left, rc.top, rc.right, rc.bottom,
2053           rc.right - rc.left, rc.bottom - rc.top);
2054     SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP,
2055                  rc.left, rc.top,
2056                  rc.right - rc.left, rc.bottom - rc.top, 0);
2057
2058     result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
2059     if (!result)
2060       break;
2061     if (result == -1) {
2062       index+=skipdir;
2063       if (index < 0) {
2064         index = 0;
2065         WARN("Tried to skip before first property sheet page!\n");
2066         break;
2067       }
2068       if (index >= psInfo->nPages) {
2069         WARN("Tried to skip after last property sheet page!\n");
2070         index = psInfo->nPages-1;
2071         break;
2072       }
2073     }
2074     else if (result != 0)
2075     {
2076       int old_index = index;
2077       index = PROPSHEET_FindPageByResId(psInfo, result);
2078       if(index >= psInfo->nPages) {
2079         index = old_index;
2080         WARN("Tried to skip to nonexistant page by res id\n");
2081         break;
2082       }
2083       continue;
2084     }
2085   }
2086
2087   /* Invalidate the header area */
2088   if ( (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
2089        (psInfo->ppshheader.dwFlags & PSH_HEADER) )
2090   {
2091     HWND hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
2092     RECT r;
2093
2094     GetClientRect(hwndLineHeader, &r);
2095     MapWindowPoints(hwndLineHeader, hwndDlg, (LPPOINT) &r, 2);
2096     SetRect(&r, 0, 0, r.right + 1, r.top - 1);
2097
2098     InvalidateRect(hwndDlg, &r, TRUE);
2099   }
2100
2101   /*
2102    * Display the new page.
2103    */
2104   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
2105
2106   if (psInfo->proppage[index].hasHelp)
2107     EnableWindow(hwndHelp, TRUE);
2108   else
2109     EnableWindow(hwndHelp, FALSE);
2110
2111   return TRUE;
2112 }
2113
2114 /******************************************************************************
2115  *            PROPSHEET_SetCurSelId
2116  *
2117  * Selects the page, specified by resource id.
2118  */
2119 static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)
2120 {
2121       int idx;
2122       PropSheetInfo* psInfo =
2123           (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2124
2125       idx = PROPSHEET_FindPageByResId(psInfo, id);
2126       if (idx < psInfo->nPages )
2127       {
2128           if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
2129               PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
2130       }
2131 }
2132
2133 /******************************************************************************
2134  *            PROPSHEET_SetTitleA
2135  */
2136 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
2137 {
2138   if(HIWORD(lpszText))
2139   {
2140      WCHAR szTitle[256];
2141      MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
2142                          szTitle, sizeof(szTitle)/sizeof(WCHAR));
2143      PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
2144   }
2145   else
2146   {
2147      PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
2148   }
2149 }
2150
2151 /******************************************************************************
2152  *            PROPSHEET_SetTitleW
2153  */
2154 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
2155 {
2156   PropSheetInfo*        psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2157   WCHAR                 szTitle[256];
2158
2159   TRACE("'%s' (style %08x)\n", debugstr_w(lpszText), dwStyle);
2160   if (HIWORD(lpszText) == 0) {
2161     if (!LoadStringW(psInfo->ppshheader.hInstance,
2162                      LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))
2163       return;
2164     lpszText = szTitle;
2165   }
2166   if (dwStyle & PSH_PROPTITLE)
2167   {
2168     WCHAR* dest;
2169     int lentitle = strlenW(lpszText);
2170     int lenprop  = strlenW(psInfo->strPropertiesFor);
2171
2172     dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
2173     wsprintfW(dest, psInfo->strPropertiesFor, lpszText);
2174
2175     SetWindowTextW(hwndDlg, dest);
2176     Free(dest);
2177   }
2178   else
2179     SetWindowTextW(hwndDlg, lpszText);
2180 }
2181
2182 /******************************************************************************
2183  *            PROPSHEET_SetFinishTextA
2184  */
2185 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
2186 {
2187   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2188   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2189
2190   TRACE("'%s'\n", lpszText);
2191   /* Set text, show and enable the Finish button */
2192   SetWindowTextA(hwndButton, lpszText);
2193   ShowWindow(hwndButton, SW_SHOW);
2194   EnableWindow(hwndButton, TRUE);
2195
2196   /* Make it default pushbutton */
2197   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2198
2199   /* Hide Back button */
2200   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2201   ShowWindow(hwndButton, SW_HIDE);
2202
2203   if (!psInfo->hasFinish)
2204   {
2205     /* Hide Next button */
2206     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2207     ShowWindow(hwndButton, SW_HIDE);
2208   }
2209 }
2210
2211 /******************************************************************************
2212  *            PROPSHEET_SetFinishTextW
2213  */
2214 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
2215 {
2216   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2217   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2218
2219   TRACE("'%s'\n", debugstr_w(lpszText));
2220   /* Set text, show and enable the Finish button */
2221   SetWindowTextW(hwndButton, lpszText);
2222   ShowWindow(hwndButton, SW_SHOW);
2223   EnableWindow(hwndButton, TRUE);
2224
2225   /* Make it default pushbutton */
2226   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2227
2228   /* Hide Back button */
2229   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2230   ShowWindow(hwndButton, SW_HIDE);
2231
2232   if (!psInfo->hasFinish)
2233   {
2234     /* Hide Next button */
2235     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2236     ShowWindow(hwndButton, SW_HIDE);
2237   }
2238 }
2239
2240 /******************************************************************************
2241  *            PROPSHEET_QuerySiblings
2242  */
2243 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
2244                                        WPARAM wParam, LPARAM lParam)
2245 {
2246   int i = 0;
2247   HWND hwndPage;
2248   LRESULT msgResult = 0;
2249   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2250
2251   while ((i < psInfo->nPages) && (msgResult == 0))
2252   {
2253     hwndPage = psInfo->proppage[i].hwndPage;
2254     msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
2255     i++;
2256   }
2257
2258   return msgResult;
2259 }
2260
2261
2262 /******************************************************************************
2263  *            PROPSHEET_AddPage
2264  */
2265 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
2266                               HPROPSHEETPAGE hpage)
2267 {
2268   PropPageInfo * ppi;
2269   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2270                                                      PropSheetInfoStr);
2271   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2272   TCITEMW item;
2273   LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
2274
2275   TRACE("hpage %p\n", hpage);
2276   /*
2277    * Allocate and fill in a new PropPageInfo entry.
2278    */
2279   ppi = (PropPageInfo*) ReAlloc(psInfo->proppage,
2280                                 sizeof(PropPageInfo) *
2281                                 (psInfo->nPages + 1));
2282   if (!ppi)
2283       return FALSE;
2284
2285   psInfo->proppage = ppi;
2286   if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
2287       return FALSE;
2288
2289   psInfo->proppage[psInfo->nPages].hpage = hpage;
2290
2291   if (ppsp->dwFlags & PSP_PREMATURE)
2292   {
2293      /* Create the page but don't show it */
2294      PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
2295   }
2296
2297   /*
2298    * Add a new tab to the tab control.
2299    */
2300   item.mask = TCIF_TEXT;
2301   item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
2302   item.cchTextMax = MAX_TABTEXT_LENGTH;
2303
2304   if (psInfo->hImageList)
2305   {
2306     SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
2307   }
2308
2309   if ( psInfo->proppage[psInfo->nPages].hasIcon )
2310   {
2311     item.mask |= TCIF_IMAGE;
2312     item.iImage = psInfo->nPages;
2313   }
2314
2315   SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
2316                (LPARAM)&item);
2317
2318   psInfo->nPages++;
2319
2320   /* If it is the only page - show it */
2321   if(psInfo->nPages == 1)
2322      PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
2323   return TRUE;
2324 }
2325
2326 /******************************************************************************
2327  *            PROPSHEET_RemovePage
2328  */
2329 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
2330                                  int index,
2331                                  HPROPSHEETPAGE hpage)
2332 {
2333   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2334                                                      PropSheetInfoStr);
2335   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2336   PropPageInfo* oldPages;
2337
2338   TRACE("index %d, hpage %p\n", index, hpage);
2339   if (!psInfo) {
2340     return FALSE;
2341   }
2342   /*
2343    * hpage takes precedence over index.
2344    */
2345   if (hpage != 0)
2346   {
2347     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2348   }
2349
2350   /* Make sure that index is within range */
2351   if (index < 0 || index >= psInfo->nPages)
2352   {
2353       TRACE("Could not find page to remove!\n");
2354       return FALSE;
2355   }
2356
2357   TRACE("total pages %d removing page %d active page %d\n",
2358         psInfo->nPages, index, psInfo->active_page);
2359   /*
2360    * Check if we're removing the active page.
2361    */
2362   if (index == psInfo->active_page)
2363   {
2364     if (psInfo->nPages > 1)
2365     {
2366       if (index > 0)
2367       {
2368         /* activate previous page  */
2369         PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
2370       }
2371       else
2372       {
2373         /* activate the next page */
2374         PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
2375         psInfo->active_page = index;
2376       }
2377     }
2378     else
2379     {
2380       psInfo->active_page = -1;
2381       if (!psInfo->isModeless)
2382       {
2383          psInfo->ended = TRUE;
2384          return TRUE;
2385       }
2386     }
2387   }
2388   else if (index < psInfo->active_page)
2389     psInfo->active_page--;
2390
2391   /* Unsubclass the page dialog window */
2392   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) &&
2393      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2394      ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER))
2395   {
2396      RemoveWindowSubclass(psInfo->proppage[index].hwndPage,
2397                           PROPSHEET_WizardSubclassProc, 1);
2398   }
2399
2400   /* Destroy page dialog window */
2401   DestroyWindow(psInfo->proppage[index].hwndPage);
2402
2403   /* Free page resources */
2404   if(psInfo->proppage[index].hpage)
2405   {
2406      PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
2407
2408      if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
2409         Free ((LPVOID)psInfo->proppage[index].pszText);
2410
2411      DestroyPropertySheetPage(psInfo->proppage[index].hpage);
2412   }
2413
2414   /* Remove the tab */
2415   SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
2416
2417   oldPages = psInfo->proppage;
2418   psInfo->nPages--;
2419   psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);
2420
2421   if (index > 0)
2422     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
2423
2424   if (index < psInfo->nPages)
2425     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
2426            (psInfo->nPages - index) * sizeof(PropPageInfo));
2427
2428   Free(oldPages);
2429
2430   return FALSE;
2431 }
2432
2433 /******************************************************************************
2434  *            PROPSHEET_SetWizButtons
2435  *
2436  * This code will work if (and assumes that) the Next button is on top of the
2437  * Finish button. ie. Finish comes after Next in the Z order.
2438  * This means make sure the dialog template reflects this.
2439  *
2440  */
2441 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
2442 {
2443   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2444                                                     PropSheetInfoStr);
2445   HWND hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2446   HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2447   HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2448
2449   TRACE("%d\n", dwFlags);
2450
2451   EnableWindow(hwndBack, FALSE);
2452   EnableWindow(hwndNext, FALSE);
2453   EnableWindow(hwndFinish, FALSE);
2454
2455   /* set the default pushbutton to an enabled button */
2456   if (((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH))
2457     SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2458   else if (dwFlags & PSWIZB_NEXT)
2459     SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
2460   else if (dwFlags & PSWIZB_BACK)
2461     SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0);
2462   else
2463     SendMessageW(hwndDlg, DM_SETDEFID, IDCANCEL, 0);
2464
2465
2466   if (dwFlags & PSWIZB_BACK)
2467     EnableWindow(hwndBack, TRUE);
2468
2469   if (dwFlags & PSWIZB_NEXT)
2470     EnableWindow(hwndNext, TRUE);
2471
2472   if (!psInfo->hasFinish)
2473   {
2474     if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
2475     {
2476       /* Hide the Next button */
2477       ShowWindow(hwndNext, SW_HIDE);
2478       
2479       /* Show the Finish button */
2480       ShowWindow(hwndFinish, SW_SHOW);
2481
2482       if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2483         EnableWindow(hwndFinish, TRUE);
2484     }
2485     else
2486     {
2487       /* Hide the Finish button */
2488       ShowWindow(hwndFinish, SW_HIDE);
2489       /* Show the Next button */
2490       ShowWindow(hwndNext, SW_SHOW);
2491     }
2492   }
2493   else if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2494     EnableWindow(hwndFinish, TRUE);
2495 }
2496
2497 /******************************************************************************
2498  *            PROPSHEET_InsertPage
2499  */
2500 static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage)
2501 {
2502     if (!HIWORD(hpageInsertAfter))
2503         FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage);
2504     else
2505         FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage);
2506     return FALSE;
2507 }
2508
2509 /******************************************************************************
2510  *            PROPSHEET_SetHeaderTitleW
2511  */
2512 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle)
2513 {
2514     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle));
2515 }
2516
2517 /******************************************************************************
2518  *            PROPSHEET_SetHeaderTitleA
2519  */
2520 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle)
2521 {
2522     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle));
2523 }
2524
2525 /******************************************************************************
2526  *            PROPSHEET_SetHeaderSubTitleW
2527  */
2528 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle)
2529 {
2530     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle));
2531 }
2532
2533 /******************************************************************************
2534  *            PROPSHEET_SetHeaderSubTitleA
2535  */
2536 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle)
2537 {
2538     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle));
2539 }
2540
2541 /******************************************************************************
2542  *            PROPSHEET_HwndToIndex
2543  */
2544 static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg)
2545 {
2546     int index;
2547     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2548                                                        PropSheetInfoStr);
2549
2550     TRACE("(%p, %p)\n", hwndDlg, hPageDlg);
2551
2552     for (index = 0; index < psInfo->nPages; index++)
2553         if (psInfo->proppage[index].hwndPage == hPageDlg)
2554             return index;
2555     WARN("%p not found\n", hPageDlg);
2556     return -1;
2557 }
2558
2559 /******************************************************************************
2560  *            PROPSHEET_IndexToHwnd
2561  */
2562 static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex)
2563 {
2564     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2565                                                        PropSheetInfoStr);
2566     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2567     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2568         WARN("%d out of range.\n", iPageIndex);
2569         return 0;
2570     }
2571     return (LRESULT)psInfo->proppage[iPageIndex].hwndPage;
2572 }
2573
2574 /******************************************************************************
2575  *            PROPSHEET_PageToIndex
2576  */
2577 static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage)
2578 {
2579     int index;
2580     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2581                                                        PropSheetInfoStr);
2582
2583     TRACE("(%p, %p)\n", hwndDlg, hPage);
2584
2585     for (index = 0; index < psInfo->nPages; index++)
2586         if (psInfo->proppage[index].hpage == hPage)
2587             return index;
2588     WARN("%p not found\n", hPage);
2589     return -1;
2590 }
2591
2592 /******************************************************************************
2593  *            PROPSHEET_IndexToPage
2594  */
2595 static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex)
2596 {
2597     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2598                                                        PropSheetInfoStr);
2599     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2600     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2601         WARN("%d out of range.\n", iPageIndex);
2602         return 0;
2603     }
2604     return (LRESULT)psInfo->proppage[iPageIndex].hpage;
2605 }
2606
2607 /******************************************************************************
2608  *            PROPSHEET_IdToIndex
2609  */
2610 static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId)
2611 {
2612     int index;
2613     LPCPROPSHEETPAGEW psp;
2614     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2615                                                        PropSheetInfoStr);
2616     TRACE("(%p, %d)\n", hwndDlg, iPageId);
2617     for (index = 0; index < psInfo->nPages; index++) {
2618         psp = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2619         if (psp->u.pszTemplate == MAKEINTRESOURCEW(iPageId))
2620             return index;
2621     }
2622
2623     return -1;
2624 }
2625
2626 /******************************************************************************
2627  *            PROPSHEET_IndexToId
2628  */
2629 static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex)
2630 {
2631     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2632                                                        PropSheetInfoStr);
2633     LPCPROPSHEETPAGEW psp;
2634     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2635     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2636         WARN("%d out of range.\n", iPageIndex);
2637         return 0;
2638     }
2639     psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage;
2640     if (psp->dwFlags & PSP_DLGINDIRECT || HIWORD(psp->u.pszTemplate)) {
2641         return 0;
2642     }
2643     return (LRESULT)psp->u.pszTemplate;
2644 }
2645
2646 /******************************************************************************
2647  *            PROPSHEET_GetResult
2648  */
2649 static LRESULT PROPSHEET_GetResult(HWND hwndDlg)
2650 {
2651     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2652                                                        PropSheetInfoStr);
2653     return psInfo->result;
2654 }
2655
2656 /******************************************************************************
2657  *            PROPSHEET_RecalcPageSizes
2658  */
2659 static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg)
2660 {
2661     FIXME("(%p): stub\n", hwndDlg);
2662     return FALSE;
2663 }
2664
2665 /******************************************************************************
2666  *            PROPSHEET_GetPageIndex
2667  *
2668  * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
2669  * the array of PropPageInfo.
2670  */
2671 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
2672 {
2673   BOOL found = FALSE;
2674   int index = 0;
2675
2676   TRACE("hpage %p\n", hpage);
2677   while ((index < psInfo->nPages) && (found == FALSE))
2678   {
2679     if (psInfo->proppage[index].hpage == hpage)
2680       found = TRUE;
2681     else
2682       index++;
2683   }
2684
2685   if (found == FALSE)
2686     index = -1;
2687
2688   return index;
2689 }
2690
2691 /******************************************************************************
2692  *            PROPSHEET_CleanUp
2693  */
2694 static void PROPSHEET_CleanUp(HWND hwndDlg)
2695 {
2696   int i;
2697   PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg,
2698                                                        PropSheetInfoStr);
2699
2700   TRACE("\n");
2701   if (!psInfo) return;
2702   if (HIWORD(psInfo->ppshheader.pszCaption))
2703       Free ((LPVOID)psInfo->ppshheader.pszCaption);
2704
2705   for (i = 0; i < psInfo->nPages; i++)
2706   {
2707      PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
2708
2709      /* Unsubclass the page dialog window */
2710      if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
2711         (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2712         (psp->dwFlags & PSP_HIDEHEADER))
2713      {
2714         RemoveWindowSubclass(psInfo->proppage[i].hwndPage,
2715                              PROPSHEET_WizardSubclassProc, 1);
2716      }
2717
2718      if(psInfo->proppage[i].hwndPage)
2719         DestroyWindow(psInfo->proppage[i].hwndPage);
2720
2721      if(psp)
2722      {
2723         if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText)
2724            Free ((LPVOID)psInfo->proppage[i].pszText);
2725
2726         DestroyPropertySheetPage(psInfo->proppage[i].hpage);
2727      }
2728   }
2729
2730   DeleteObject(psInfo->hFont);
2731   DeleteObject(psInfo->hFontBold);
2732   /* If we created the bitmaps, destroy them */
2733   if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2734       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) )
2735       DeleteObject(psInfo->ppshheader.u4.hbmWatermark);
2736   if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
2737       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) )
2738       DeleteObject(psInfo->ppshheader.u5.hbmHeader);
2739
2740   Free(psInfo->proppage);
2741   Free(psInfo->strPropertiesFor);
2742   ImageList_Destroy(psInfo->hImageList);
2743
2744   GlobalFree((HGLOBAL)psInfo);
2745 }
2746
2747 static INT do_loop(PropSheetInfo *psInfo)
2748 {
2749     MSG msg;
2750     INT ret = -1;
2751     HWND hwnd = psInfo->hwnd;
2752
2753     while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0)))
2754     {
2755         if(ret == -1)
2756             break;
2757
2758         if(!IsDialogMessageW(hwnd, &msg))
2759         {
2760             TranslateMessage(&msg);
2761             DispatchMessageW(&msg);
2762         }
2763     }
2764
2765     if(ret == 0)
2766     {
2767         PostQuitMessage(msg.wParam);
2768         ret = -1;
2769     }
2770
2771     if(ret != -1)
2772         ret = psInfo->result;
2773
2774     DestroyWindow(hwnd);
2775     return ret;
2776 }
2777
2778 /******************************************************************************
2779  *            PropertySheet    (COMCTL32.@)
2780  *            PropertySheetA   (COMCTL32.@)
2781  *
2782  * Creates a property sheet in the specified property sheet header.
2783  *
2784  * RETURNS
2785  *     Modal property sheets: Positive if successful or -1 otherwise.
2786  *     Modeless property sheets: Property sheet handle.
2787  *     Or:
2788  *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect.
2789  *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect.
2790  */
2791 INT_PTR WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
2792 {
2793   INT_PTR bRet = 0;
2794   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2795                                                        sizeof(PropSheetInfo));
2796   UINT i, n;
2797   const BYTE* pByte;
2798
2799   TRACE("(%p)\n", lppsh);
2800
2801   PROPSHEET_CollectSheetInfoA(lppsh, psInfo);
2802
2803   psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
2804                                                     lppsh->nPages);
2805   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
2806
2807   for (n = i = 0; i < lppsh->nPages; i++, n++)
2808   {
2809     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2810       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2811     else
2812     {
2813        psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
2814        pByte += ((LPCPROPSHEETPAGEA)pByte)->dwSize;
2815     }
2816
2817     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
2818                                psInfo, n))
2819     {
2820         if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2821             DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2822         n--;
2823         psInfo->nPages--;
2824     }
2825   }
2826
2827   if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0;
2828   TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages);
2829
2830   psInfo->unicode = FALSE;
2831   psInfo->ended = FALSE;
2832
2833   bRet = PROPSHEET_CreateDialog(psInfo);
2834   if(!psInfo->isModeless)
2835       bRet = do_loop(psInfo);
2836
2837   return bRet;
2838 }
2839
2840 /******************************************************************************
2841  *            PropertySheetW   (COMCTL32.@)
2842  *
2843  * See PropertySheetA.
2844  */
2845 INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
2846 {
2847   INT_PTR bRet = 0;
2848   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2849                                                        sizeof(PropSheetInfo));
2850   UINT i, n;
2851   const BYTE* pByte;
2852
2853   TRACE("(%p)\n", lppsh);
2854
2855   PROPSHEET_CollectSheetInfoW(lppsh, psInfo);
2856
2857   psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
2858                                                     lppsh->nPages);
2859   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
2860
2861   for (n = i = 0; i < lppsh->nPages; i++, n++)
2862   {
2863     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2864       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2865     else
2866     {
2867        psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);
2868        pByte += ((LPCPROPSHEETPAGEW)pByte)->dwSize;
2869     }
2870
2871     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
2872                                psInfo, n))
2873     {
2874         if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2875             DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2876         n--;
2877         psInfo->nPages--;
2878     }
2879   }
2880
2881   if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0;
2882   TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages);
2883
2884   psInfo->unicode = TRUE;
2885   psInfo->ended = FALSE;
2886
2887   bRet = PROPSHEET_CreateDialog(psInfo);
2888   if(!psInfo->isModeless)
2889       bRet = do_loop(psInfo);
2890
2891   return bRet;
2892 }
2893
2894 static LPWSTR load_string( HINSTANCE instance, LPCWSTR str )
2895 {
2896     LPWSTR ret;
2897     UINT len;
2898
2899     if (IS_INTRESOURCE(str))
2900     {
2901         HRSRC hrsrc;
2902         HGLOBAL hmem;
2903         WCHAR *ptr;
2904         WORD i, id = LOWORD(str);
2905
2906         if (!(hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((id >> 4) + 1), (LPWSTR)RT_STRING )))
2907             return NULL;
2908         if (!(hmem = LoadResource( instance, hrsrc ))) return NULL;
2909         if (!(ptr = LockResource( hmem ))) return NULL;
2910         for (i = id & 0x0f; i > 0; i--) ptr += *ptr + 1;
2911         len = *ptr;
2912         if (!len) return NULL;
2913         ret = Alloc( (len + 1) * sizeof(WCHAR) );
2914         if (ret)
2915         {
2916             memcpy( ret, ptr + 1, len * sizeof(WCHAR) );
2917             ret[len] = 0;
2918         }
2919     }
2920     else
2921     {
2922         int len = (strlenW(str) + 1) * sizeof(WCHAR);
2923         ret = Alloc( len );
2924         if (ret) memcpy( ret, str, len );
2925     }
2926     return ret;
2927 }
2928
2929
2930 /******************************************************************************
2931  *            CreatePropertySheetPage    (COMCTL32.@)
2932  *            CreatePropertySheetPageA   (COMCTL32.@)
2933  *
2934  * Creates a new property sheet page.
2935  *
2936  * RETURNS
2937  *     Success: Handle to new property sheet page.
2938  *     Failure: NULL.
2939  *
2940  * NOTES
2941  *     An application must use the PSM_ADDPAGE message to add the new page to
2942  *     an existing property sheet.
2943  */
2944 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
2945                           LPCPROPSHEETPAGEA lpPropSheetPage)
2946 {
2947   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
2948
2949   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
2950
2951   ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE;
2952
2953     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
2954     {
2955         if (HIWORD( ppsp->u.pszTemplate ))
2956         {
2957             int len = strlen(lpPropSheetPage->u.pszTemplate) + 1;
2958             char *template = Alloc( len );
2959
2960             ppsp->u.pszTemplate = (LPWSTR)strcpy( template, lpPropSheetPage->u.pszTemplate );
2961         }
2962     }
2963
2964     if (ppsp->dwFlags & PSP_USEICONID)
2965     {
2966         if (HIWORD( ppsp->u2.pszIcon ))
2967             PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon);
2968     }
2969
2970     if (ppsp->dwFlags & PSP_USETITLE)
2971     {
2972         if (HIWORD( ppsp->pszTitle ))
2973             PROPSHEET_AtoW( &ppsp->pszTitle, lpPropSheetPage->pszTitle );
2974         else
2975             ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
2976     }
2977     else
2978         ppsp->pszTitle = NULL;
2979
2980     if (ppsp->dwFlags & PSP_HIDEHEADER)
2981         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
2982
2983     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
2984     {
2985         if (HIWORD( ppsp->pszHeaderTitle ))
2986             PROPSHEET_AtoW(&ppsp->pszHeaderTitle, lpPropSheetPage->pszHeaderTitle);
2987         else
2988             ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
2989     }
2990     else
2991         ppsp->pszHeaderTitle = NULL;
2992
2993     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
2994     {
2995         if (HIWORD( ppsp->pszHeaderSubTitle ))
2996             PROPSHEET_AtoW(&ppsp->pszHeaderSubTitle, lpPropSheetPage->pszHeaderSubTitle);
2997         else
2998             ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
2999     }
3000     else
3001         ppsp->pszHeaderSubTitle = NULL;
3002
3003     return (HPROPSHEETPAGE)ppsp;
3004 }
3005
3006 /******************************************************************************
3007  *            CreatePropertySheetPageW   (COMCTL32.@)
3008  *
3009  * See CreatePropertySheetA.
3010  */
3011 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
3012 {
3013   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
3014
3015   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));
3016
3017   ppsp->dwFlags |= PSP_INTERNAL_UNICODE;
3018
3019     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
3020     {
3021         if (HIWORD( ppsp->u.pszTemplate ))
3022         {
3023             int len = strlenW(lpPropSheetPage->u.pszTemplate) + 1;
3024             WCHAR *template = Alloc( len * sizeof (WCHAR) );
3025
3026             ppsp->u.pszTemplate = strcpyW( template, lpPropSheetPage->u.pszTemplate );
3027         }
3028     }
3029
3030     if ( ppsp->dwFlags & PSP_USEICONID )
3031     {
3032         if (HIWORD( ppsp->u2.pszIcon ))
3033         {
3034             int len = strlenW(lpPropSheetPage->u2.pszIcon) + 1;
3035             WCHAR *icon = Alloc( len * sizeof (WCHAR) );
3036
3037             ppsp->u2.pszIcon = strcpyW( icon, lpPropSheetPage->u2.pszIcon );
3038         }
3039     }
3040
3041     if (ppsp->dwFlags & PSP_USETITLE)
3042         ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
3043     else
3044         ppsp->pszTitle = NULL;
3045
3046     if (ppsp->dwFlags & PSP_HIDEHEADER)
3047         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
3048
3049     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
3050         ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
3051     else
3052         ppsp->pszHeaderTitle = NULL;
3053
3054     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
3055         ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
3056     else
3057         ppsp->pszHeaderSubTitle = NULL;
3058
3059     return (HPROPSHEETPAGE)ppsp;
3060 }
3061
3062 /******************************************************************************
3063  *            DestroyPropertySheetPage   (COMCTL32.@)
3064  *
3065  * Destroys a property sheet page previously created with
3066  * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated
3067  * memory.
3068  *
3069  * RETURNS
3070  *     Success: TRUE
3071  *     Failure: FALSE
3072  */
3073 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
3074 {
3075   PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;
3076
3077   if (!psp)
3078      return FALSE;
3079
3080   if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
3081      Free ((LPVOID)psp->u.pszTemplate);
3082
3083   if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
3084      Free ((LPVOID)psp->u2.pszIcon);
3085
3086   if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
3087      Free ((LPVOID)psp->pszTitle);
3088
3089   Free(hPropPage);
3090
3091   return TRUE;
3092 }
3093
3094 /******************************************************************************
3095  *            PROPSHEET_IsDialogMessage
3096  */
3097 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
3098 {
3099    PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3100
3101    TRACE("\n");
3102    if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
3103       return FALSE;
3104
3105    if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
3106    {
3107       int new_page = 0;
3108       INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
3109
3110       if (!(dlgCode & DLGC_WANTMESSAGE))
3111       {
3112          switch (lpMsg->wParam)
3113          {
3114             case VK_TAB:
3115                if (GetKeyState(VK_SHIFT) & 0x8000)
3116                    new_page = -1;
3117                 else
3118                    new_page = 1;
3119                break;
3120
3121             case VK_NEXT:   new_page = 1;  break;
3122             case VK_PRIOR:  new_page = -1; break;
3123          }
3124       }
3125
3126       if (new_page)
3127       {
3128          if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
3129          {
3130             new_page += psInfo->active_page;
3131
3132             if (new_page < 0)
3133                new_page = psInfo->nPages - 1;
3134             else if (new_page >= psInfo->nPages)
3135                new_page = 0;
3136
3137             PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
3138          }
3139
3140          return TRUE;
3141       }
3142    }
3143
3144    return IsDialogMessageW(hwnd, lpMsg);
3145 }
3146
3147 /******************************************************************************
3148  *            PROPSHEET_DoCommand
3149  */
3150 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)
3151 {
3152
3153     switch (wID) {
3154
3155     case IDOK:
3156     case IDC_APPLY_BUTTON:
3157         {
3158             HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
3159
3160             if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
3161                 break;
3162
3163             if (wID == IDOK)
3164                 {
3165                     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3166                                                                       PropSheetInfoStr);
3167
3168                     /* don't overwrite ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM */
3169                     if (psInfo->result == 0)
3170                         psInfo->result = IDOK;
3171
3172                     if (psInfo->isModeless)
3173                         psInfo->activeValid = FALSE;
3174                     else
3175                         psInfo->ended = TRUE;
3176                 }
3177             else
3178                 EnableWindow(hwndApplyBtn, FALSE);
3179
3180             break;
3181         }
3182
3183     case IDC_BACK_BUTTON:
3184         PROPSHEET_Back(hwnd);
3185         break;
3186
3187     case IDC_NEXT_BUTTON:
3188         PROPSHEET_Next(hwnd);
3189         break;
3190
3191     case IDC_FINISH_BUTTON:
3192         PROPSHEET_Finish(hwnd);
3193         break;
3194
3195     case IDCANCEL:
3196         PROPSHEET_Cancel(hwnd, 0);
3197         break;
3198
3199     case IDHELP:
3200         PROPSHEET_Help(hwnd);
3201         break;
3202
3203     default:
3204         return FALSE;
3205     }
3206
3207     return TRUE;
3208 }
3209
3210 /******************************************************************************
3211  *            PROPSHEET_Paint
3212  */
3213 static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam)
3214 {
3215     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3216     PAINTSTRUCT ps;
3217     HDC hdc, hdcSrc;
3218     BITMAP bm;
3219     HBITMAP hbmp;
3220     HPALETTE hOldPal = 0;
3221     int offsety = 0;
3222     HBRUSH hbr;
3223     RECT r, rzone;
3224     LPCPROPSHEETPAGEW ppshpage;
3225     WCHAR szBuffer[256];
3226     int nLength;
3227
3228     hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps);
3229     if (!hdc) return 1;
3230
3231     hdcSrc = CreateCompatibleDC(0);
3232     ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage;
3233
3234     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
3235         hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE);
3236
3237     if ( (!(ppshpage->dwFlags & PSP_HIDEHEADER)) &&
3238          (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
3239          (psInfo->ppshheader.dwFlags & PSH_HEADER) ) 
3240     {
3241         HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER);
3242         HFONT hOldFont;
3243         COLORREF clrOld = 0;
3244         int oldBkMode = 0;
3245
3246         hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader);
3247         hOldFont = SelectObject(hdc, psInfo->hFontBold);
3248
3249         GetClientRect(hwndLineHeader, &r);
3250         MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2);
3251         SetRect(&rzone, 0, 0, r.right + 1, r.top - 1);
3252
3253         GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), (LPVOID)&bm);               
3254
3255         if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD)
3256         {
3257             /* Fill the unoccupied part of the header with color of the
3258              * left-top pixel, but do it only when needed.
3259              */
3260             if (bm.bmWidth < r.right || bm.bmHeight < r.bottom)
3261             {
3262                 hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
3263                 CopyRect(&r, &rzone);
3264                 if (bm.bmWidth < r.right)
3265                 {
3266                     r.left = bm.bmWidth;
3267                     FillRect(hdc, &r, hbr);
3268                 }
3269                 if (bm.bmHeight < r.bottom)
3270                 {
3271                     r.left = 0;
3272                     r.top = bm.bmHeight;
3273                     FillRect(hdc, &r, hbr);
3274                 }
3275                 DeleteObject(hbr);
3276             }
3277
3278             /* Draw the header itself. */
3279             BitBlt(hdc, 0, 0,
3280                    bm.bmWidth, min(bm.bmHeight, rzone.bottom),
3281                    hdcSrc, 0, 0, SRCCOPY);
3282         }
3283         else
3284         {
3285             int margin;
3286             hbr = GetSysColorBrush(COLOR_WINDOW);
3287             FillRect(hdc, &rzone, hbr);
3288
3289             /* Draw the header bitmap. It's always centered like a
3290              * common 49 x 49 bitmap. */
3291             margin = (rzone.bottom - 49) / 2;
3292             BitBlt(hdc, rzone.right - 49 - margin, margin,
3293                    min(bm.bmWidth, 49), min(bm.bmHeight, 49),
3294                    hdcSrc, 0, 0, SRCCOPY);
3295
3296             /* NOTE: Native COMCTL32 draws a white stripe over the bitmap
3297              * if its height is smaller than 49 pixels. Because the reason
3298              * for this bug is unknown the current code doesn't try to
3299              * replicate it. */
3300         }
3301
3302         clrOld = SetTextColor (hdc, 0x00000000);
3303         oldBkMode = SetBkMode (hdc, TRANSPARENT); 
3304
3305         if (ppshpage->dwFlags & PSP_USEHEADERTITLE) {
3306             SetRect(&r, 20, 10, 0, 0);
3307             if (HIWORD(ppshpage->pszHeaderTitle))
3308                 DrawTextW(hdc, ppshpage->pszHeaderTitle, -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
3309             else
3310             {
3311                 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderTitle,
3312                                       szBuffer, 256);
3313                 if (nLength != 0)
3314                 {
3315                     DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
3316                 }
3317             }
3318         }
3319
3320         if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) {
3321             SelectObject(hdc, psInfo->hFont);
3322             SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom);
3323             if (HIWORD(ppshpage->pszHeaderTitle))
3324                 DrawTextW(hdc, ppshpage->pszHeaderSubTitle, -1, &r, DT_LEFT | DT_WORDBREAK);
3325             else
3326             {
3327                 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderSubTitle,
3328                                       szBuffer, 256);
3329                 if (nLength != 0)
3330                 {
3331                     DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_WORDBREAK);
3332                 }
3333             }
3334         }
3335
3336         offsety = rzone.bottom + 2;
3337
3338         SetTextColor(hdc, clrOld);
3339         SetBkMode(hdc, oldBkMode);
3340         SelectObject(hdc, hOldFont);
3341         SelectObject(hdcSrc, hbmp);
3342     }
3343
3344     if ( (ppshpage->dwFlags & PSP_HIDEHEADER) &&
3345          (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
3346          (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) 
3347     {
3348         HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE);          
3349
3350         GetClientRect(hwndLine, &r);
3351         MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2);
3352
3353         rzone.left = 0;
3354         rzone.top = 0;
3355         rzone.right = r.right;
3356         rzone.bottom = r.top - 1;
3357
3358         hbr = GetSysColorBrush(COLOR_WINDOW);
3359         FillRect(hdc, &rzone, hbr);
3360
3361         GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), (LPVOID)&bm);
3362         hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark);
3363
3364         /* The watermark is truncated to a width of 164 pixels */
3365         r.right = min(r.right, 164);
3366         BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right),
3367                min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY);
3368
3369         /* If the bitmap is not big enough, fill the remaining area
3370            with the color of pixel (0,0) of bitmap - see MSDN */
3371         if (r.top > bm.bmHeight) {
3372             r.bottom = r.top - 1;
3373             r.top = bm.bmHeight;
3374             r.left = 0;
3375             r.right = bm.bmWidth;
3376             hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
3377             FillRect(hdc, &r, hbr);
3378             DeleteObject(hbr);
3379         }
3380
3381         SelectObject(hdcSrc, hbmp);         
3382     }
3383
3384     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
3385         SelectPalette(hdc, hOldPal, FALSE);
3386
3387     DeleteDC(hdcSrc);
3388
3389     if (!hdcParam) EndPaint(hwnd, &ps);
3390
3391     return 0;
3392 }
3393
3394 /******************************************************************************
3395  *            PROPSHEET_DialogProc
3396  */
3397 static INT_PTR CALLBACK
3398 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3399 {
3400   TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n",
3401         hwnd, uMsg, wParam, lParam);
3402
3403   switch (uMsg)
3404   {
3405     case WM_INITDIALOG:
3406     {
3407       PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
3408       WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));
3409       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
3410       LPCPROPSHEETPAGEW ppshpage;
3411       int idx;
3412       LOGFONTW logFont;
3413
3414       /* Using PropSheetInfoStr to store extra data doesn't match the native
3415        * common control: native uses TCM_[GS]ETITEM
3416        */
3417       SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
3418
3419       /*
3420        * psInfo->hwnd is not being used by WINE code - it exists
3421        * for compatibility with "real" Windoze. The same about
3422        * SetWindowLongPtr - WINE is only using the PropSheetInfoStr
3423        * property.
3424        */
3425       psInfo->hwnd = hwnd;
3426       SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo);
3427
3428       /* set up the Next and Back buttons by default */
3429       PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);
3430
3431       /* Set up fonts */
3432       SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
3433       psInfo->hFont = CreateFontIndirectW (&logFont);
3434       logFont.lfWeight = FW_BOLD;
3435       psInfo->hFontBold = CreateFontIndirectW (&logFont);
3436       
3437       /*
3438        * Small icon in the title bar.
3439        */
3440       if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
3441           (psInfo->ppshheader.dwFlags & PSH_USEHICON))
3442       {
3443         HICON hIcon;
3444         int icon_cx = GetSystemMetrics(SM_CXSMICON);
3445         int icon_cy = GetSystemMetrics(SM_CYSMICON);
3446
3447         if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
3448           hIcon = LoadImageW(psInfo->ppshheader.hInstance,
3449                              psInfo->ppshheader.u.pszIcon,
3450                              IMAGE_ICON,
3451                              icon_cx, icon_cy,
3452                              LR_DEFAULTCOLOR);
3453         else
3454           hIcon = psInfo->ppshheader.u.hIcon;
3455
3456         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon);
3457       }
3458
3459       if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
3460         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon);
3461
3462       psInfo->strPropertiesFor = strCaption;
3463
3464       GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
3465
3466       PROPSHEET_CreateTabControl(hwnd, psInfo);
3467
3468       PROPSHEET_LoadWizardBitmaps(psInfo);
3469
3470       if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
3471       {
3472         ShowWindow(hwndTabCtrl, SW_HIDE);
3473         PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
3474         PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
3475       }
3476       else
3477       {
3478         if (PROPSHEET_SizeMismatch(hwnd, psInfo))
3479         {
3480           PROPSHEET_AdjustSize(hwnd, psInfo);
3481           PROPSHEET_AdjustButtons(hwnd, psInfo);
3482         }
3483       }
3484
3485       if (!HIWORD(psInfo->ppshheader.pszCaption) &&
3486               psInfo->ppshheader.hInstance)
3487       {
3488          WCHAR szText[256];
3489
3490          if (LoadStringW(psInfo->ppshheader.hInstance,
3491                          (UINT_PTR)psInfo->ppshheader.pszCaption, szText, 255))
3492             PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);
3493       }
3494       else
3495       {
3496          PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,
3497                          psInfo->ppshheader.pszCaption);
3498       }
3499
3500
3501       if (psInfo->useCallback)
3502              (*(psInfo->ppshheader.pfnCallback))(hwnd,
3503                                               PSCB_INITIALIZED, (LPARAM)0);
3504
3505       idx = psInfo->active_page;
3506       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage;
3507       psInfo->active_page = -1;
3508
3509       PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
3510
3511       /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
3512        * as some programs call TCM_GETCURSEL to get the current selection
3513        * from which to switch to the next page */
3514       SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
3515
3516       return TRUE;
3517     }
3518
3519     case WM_PRINTCLIENT:
3520     case WM_PAINT:
3521       PROPSHEET_Paint(hwnd, (HDC)wParam);
3522       return TRUE;
3523
3524     case WM_DESTROY:
3525       PROPSHEET_CleanUp(hwnd);
3526       return TRUE;
3527
3528     case WM_CLOSE:
3529       PROPSHEET_Cancel(hwnd, 1);
3530       return FALSE; /* let DefDlgProc post us WM_COMMAND/IDCANCEL */
3531
3532     case WM_COMMAND:
3533       if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam)))
3534       {
3535           PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3536
3537           if (!psInfo)
3538               return FALSE;
3539
3540           /* No default handler, forward notification to active page */
3541           if (psInfo->activeValid && psInfo->active_page != -1)
3542           {
3543              HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
3544              SendMessageW(hwndPage, WM_COMMAND, wParam, lParam);
3545           }
3546       }
3547       return TRUE;
3548
3549     case WM_NOTIFY:
3550     {
3551       NMHDR* pnmh = (LPNMHDR) lParam;
3552
3553       if (pnmh->code == TCN_SELCHANGE)
3554       {
3555         int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
3556         PROPSHEET_SetCurSel(hwnd, index, 1, 0);
3557       }
3558
3559       if(pnmh->code == TCN_SELCHANGING)
3560       {
3561         BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
3562         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet);
3563         return TRUE;
3564       }
3565
3566       return FALSE;
3567     }
3568   
3569     case WM_SYSCOLORCHANGE:
3570       COMCTL32_RefreshSysColors();
3571       return FALSE;
3572
3573     case PSM_GETCURRENTPAGEHWND:
3574     {
3575       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3576                                                         PropSheetInfoStr);
3577       HWND hwndPage = 0;
3578
3579       if (!psInfo)
3580         return FALSE;
3581
3582       if (psInfo->activeValid && psInfo->active_page != -1)
3583         hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
3584
3585       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage);
3586
3587       return TRUE;
3588     }
3589
3590     case PSM_CHANGED:
3591       PROPSHEET_Changed(hwnd, (HWND)wParam);
3592       return TRUE;
3593
3594     case PSM_UNCHANGED:
3595       PROPSHEET_UnChanged(hwnd, (HWND)wParam);
3596       return TRUE;
3597
3598     case PSM_GETTABCONTROL:
3599     {
3600       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
3601
3602       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl);
3603
3604       return TRUE;
3605     }
3606
3607     case PSM_SETCURSEL:
3608     {
3609       BOOL msgResult;
3610
3611       msgResult = PROPSHEET_CanSetCurSel(hwnd);
3612       if(msgResult != FALSE)
3613       {
3614         msgResult = PROPSHEET_SetCurSel(hwnd,
3615                                        (int)wParam,
3616                                        1,
3617                                        (HPROPSHEETPAGE)lParam);
3618       }
3619
3620       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3621
3622       return TRUE;
3623     }
3624
3625     case PSM_CANCELTOCLOSE:
3626     {
3627       WCHAR buf[MAX_BUTTONTEXT_LENGTH];
3628       HWND hwndOK = GetDlgItem(hwnd, IDOK);
3629       HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
3630
3631       EnableWindow(hwndCancel, FALSE);
3632       if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
3633          SetWindowTextW(hwndOK, buf);
3634
3635       return FALSE;
3636     }
3637
3638     case PSM_RESTARTWINDOWS:
3639     {
3640       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3641                                                         PropSheetInfoStr);
3642
3643       if (!psInfo)
3644         return FALSE;
3645
3646       /* reboot system takes precedence over restart windows */
3647       if (psInfo->result != ID_PSREBOOTSYSTEM)
3648           psInfo->result = ID_PSRESTARTWINDOWS;
3649
3650       return TRUE;
3651     }
3652
3653     case PSM_REBOOTSYSTEM:
3654     {
3655       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3656                                                         PropSheetInfoStr);
3657
3658       if (!psInfo)
3659         return FALSE;
3660
3661       psInfo->result = ID_PSREBOOTSYSTEM;
3662
3663       return TRUE;
3664     }
3665
3666     case PSM_SETTITLEA:
3667       PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
3668       return TRUE;
3669
3670     case PSM_SETTITLEW:
3671       PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);
3672       return TRUE;
3673
3674     case PSM_APPLY:
3675     {
3676       BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
3677
3678       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3679
3680       return TRUE;
3681     }
3682
3683     case PSM_QUERYSIBLINGS:
3684     {
3685       LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
3686
3687       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3688
3689       return TRUE;
3690     }
3691
3692     case PSM_ADDPAGE:
3693     {
3694       /*
3695        * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
3696        *       a return value. This is not true. PSM_ADDPAGE returns TRUE
3697        *       on success or FALSE otherwise, as specified on MSDN Online.
3698        *       Also see the MFC code for
3699        *       CPropertySheet::AddPage(CPropertyPage* pPage).
3700        */
3701
3702       BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
3703
3704       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3705
3706       return TRUE;
3707     }
3708
3709     case PSM_REMOVEPAGE:
3710       PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
3711       return TRUE;
3712
3713     case PSM_ISDIALOGMESSAGE:
3714     {
3715        BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
3716        SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3717        return TRUE;
3718     }
3719
3720     case PSM_PRESSBUTTON:
3721       PROPSHEET_PressButton(hwnd, (int)wParam);
3722       return TRUE;
3723
3724     case PSM_SETFINISHTEXTA:
3725       PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
3726       return TRUE;
3727
3728     case PSM_SETWIZBUTTONS:
3729       PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
3730       return TRUE;
3731
3732     case PSM_SETCURSELID:
3733         PROPSHEET_SetCurSelId(hwnd, (int)lParam);
3734         return TRUE;
3735
3736     case PSM_SETFINISHTEXTW:
3737         PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);
3738         return FALSE;
3739
3740     case PSM_INSERTPAGE:
3741     {
3742         BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam);
3743         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3744         return TRUE;
3745     }
3746
3747     case PSM_SETHEADERTITLEW:
3748         PROPSHEET_SetHeaderTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
3749         return TRUE;
3750
3751     case PSM_SETHEADERTITLEA:
3752         PROPSHEET_SetHeaderTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
3753         return TRUE;
3754
3755     case PSM_SETHEADERSUBTITLEW:
3756         PROPSHEET_SetHeaderSubTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
3757         return TRUE;
3758
3759     case PSM_SETHEADERSUBTITLEA:
3760         PROPSHEET_SetHeaderSubTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
3761         return TRUE;
3762
3763     case PSM_HWNDTOINDEX:
3764     {
3765         LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam);
3766         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3767         return TRUE;
3768     }
3769
3770     case PSM_INDEXTOHWND:
3771     {
3772         LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam);
3773         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3774         return TRUE;
3775     }
3776
3777     case PSM_PAGETOINDEX:
3778     {
3779         LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam);
3780         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3781         return TRUE;
3782     }
3783
3784     case PSM_INDEXTOPAGE:
3785     {
3786         LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam);
3787         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3788         return TRUE;
3789     }
3790
3791     case PSM_IDTOINDEX:
3792     {
3793         LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam);
3794         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3795         return TRUE;
3796     }
3797
3798     case PSM_INDEXTOID:
3799     {
3800         LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam);
3801         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3802         return TRUE;
3803     }
3804
3805     case PSM_GETRESULT:
3806     {
3807         LRESULT msgResult = PROPSHEET_GetResult(hwnd);
3808         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3809         return TRUE;
3810     }
3811
3812     case PSM_RECALCPAGESIZES:
3813     {
3814         LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd);
3815         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3816         return TRUE;
3817     }
3818
3819     default:
3820       return FALSE;
3821   }
3822 }