ole32: Add some tests for the flags input to CoRegisterClassObject.
[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   Free(temp);
1498
1499   psInfo->proppage[index].hwndPage = hwndPage;
1500
1501   /* Subclass exterior wizard pages */
1502   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
1503      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1504      (ppshpage->dwFlags & PSP_HIDEHEADER))
1505   {
1506       SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1,
1507                         (DWORD_PTR)ppshpage);
1508   }
1509   if (!(psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD))
1510       EnableThemeDialogTexture (hwndPage, ETDT_ENABLETAB);
1511
1512   return TRUE;
1513 }
1514
1515 /******************************************************************************
1516  *            PROPSHEET_LoadWizardBitmaps
1517  *
1518  * Loads the watermark and header bitmaps for a wizard.
1519  */
1520 static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo)
1521 {
1522   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD))
1523   {
1524     /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark 
1525        and put the HBITMAP in hbmWatermark. Thus all the rest of the code always 
1526        considers hbmWatermark as valid. */
1527     if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1528         !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK))
1529     {
1530       ((PropSheetInfo *)psInfo)->ppshheader.u4.hbmWatermark = 
1531         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0);
1532     }
1533
1534     /* Same behavior as for watermarks */
1535     if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
1536         !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER))
1537     {
1538       ((PropSheetInfo *)psInfo)->ppshheader.u5.hbmHeader = 
1539         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0);
1540     }
1541   }
1542 }
1543
1544
1545 /******************************************************************************
1546  *            PROPSHEET_ShowPage
1547  *
1548  * Displays or creates the specified page.
1549  */
1550 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1551 {
1552   HWND hwndTabCtrl;
1553   HWND hwndLineHeader;
1554   LPCPROPSHEETPAGEW ppshpage;
1555
1556   TRACE("active_page %d, index %d\n", psInfo->active_page, index);
1557   if (index == psInfo->active_page)
1558   {
1559       if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1560           SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1561       return TRUE;
1562   }
1563
1564   ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1565   if (psInfo->proppage[index].hwndPage == 0)
1566   {
1567      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1568   }
1569
1570   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1571   {
1572      PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,
1573                          psInfo->proppage[index].pszText);
1574   }
1575
1576   if (psInfo->active_page != -1)
1577      ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1578
1579   ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1580
1581   /* Synchronize current selection with tab control
1582    * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1583   hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1584   SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1585
1586   psInfo->active_page = index;
1587   psInfo->activeValid = TRUE;
1588
1589   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) )
1590   {
1591       hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
1592       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1593       
1594       if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) )
1595           ShowWindow(hwndLineHeader, SW_HIDE);
1596       else
1597           ShowWindow(hwndLineHeader, SW_SHOW);
1598   }
1599
1600   return TRUE;
1601 }
1602
1603 /******************************************************************************
1604  *            PROPSHEET_Back
1605  */
1606 static BOOL PROPSHEET_Back(HWND hwndDlg)
1607 {
1608   PSHNOTIFY psn;
1609   HWND hwndPage;
1610   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1611                                                     PropSheetInfoStr);
1612   LRESULT result;
1613   int idx;
1614
1615   TRACE("active_page %d\n", psInfo->active_page);
1616   if (psInfo->active_page < 0)
1617      return FALSE;
1618
1619   psn.hdr.code     = PSN_WIZBACK;
1620   psn.hdr.hwndFrom = hwndDlg;
1621   psn.hdr.idFrom   = 0;
1622   psn.lParam       = 0;
1623
1624   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1625
1626   result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1627   if (result == -1)
1628     return FALSE;
1629   else if (result == 0)
1630      idx = psInfo->active_page - 1;
1631   else
1632      idx = PROPSHEET_FindPageByResId(psInfo, result);
1633
1634   if (idx >= 0 && idx < psInfo->nPages)
1635   {
1636      if (PROPSHEET_CanSetCurSel(hwndDlg))
1637         PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);
1638   }
1639   return TRUE;
1640 }
1641
1642 /******************************************************************************
1643  *            PROPSHEET_Next
1644  */
1645 static BOOL PROPSHEET_Next(HWND hwndDlg)
1646 {
1647   PSHNOTIFY psn;
1648   HWND hwndPage;
1649   LRESULT msgResult = 0;
1650   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1651                                                     PropSheetInfoStr);
1652   int idx;
1653
1654   TRACE("active_page %d\n", psInfo->active_page);
1655   if (psInfo->active_page < 0)
1656      return FALSE;
1657
1658   psn.hdr.code     = PSN_WIZNEXT;
1659   psn.hdr.hwndFrom = hwndDlg;
1660   psn.hdr.idFrom   = 0;
1661   psn.lParam       = 0;
1662
1663   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1664
1665   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1666   if (msgResult == -1)
1667     return FALSE;
1668   else if (msgResult == 0)
1669      idx = psInfo->active_page + 1;
1670   else
1671      idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
1672
1673   if (idx < psInfo->nPages )
1674   {
1675      if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1676         PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
1677   }
1678
1679   return TRUE;
1680 }
1681
1682 /******************************************************************************
1683  *            PROPSHEET_Finish
1684  */
1685 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1686 {
1687   PSHNOTIFY psn;
1688   HWND hwndPage;
1689   LRESULT msgResult = 0;
1690   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1691                                                     PropSheetInfoStr);
1692
1693   TRACE("active_page %d\n", psInfo->active_page);
1694   if (psInfo->active_page < 0)
1695      return FALSE;
1696
1697   psn.hdr.code     = PSN_WIZFINISH;
1698   psn.hdr.hwndFrom = hwndDlg;
1699   psn.hdr.idFrom   = 0;
1700   psn.lParam       = 0;
1701
1702   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1703
1704   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1705
1706   TRACE("msg result %ld\n", msgResult);
1707
1708   if (msgResult != 0)
1709     return FALSE;
1710
1711   if (psInfo->result == 0)
1712       psInfo->result = IDOK;
1713   if (psInfo->isModeless)
1714     psInfo->activeValid = FALSE;
1715   else
1716     psInfo->ended = TRUE;
1717
1718   return TRUE;
1719 }
1720
1721 /******************************************************************************
1722  *            PROPSHEET_Apply
1723  */
1724 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1725 {
1726   int i;
1727   HWND hwndPage;
1728   PSHNOTIFY psn;
1729   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1730                                                     PropSheetInfoStr);
1731
1732   TRACE("active_page %d\n", psInfo->active_page);
1733   if (psInfo->active_page < 0)
1734      return FALSE;
1735
1736   psn.hdr.hwndFrom = hwndDlg;
1737   psn.hdr.idFrom   = 0;
1738   psn.lParam       = 0;
1739
1740
1741   /*
1742    * Send PSN_KILLACTIVE to the current page.
1743    */
1744   psn.hdr.code = PSN_KILLACTIVE;
1745
1746   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1747
1748   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1749     return FALSE;
1750
1751   /*
1752    * Send PSN_APPLY to all pages.
1753    */
1754   psn.hdr.code = PSN_APPLY;
1755   psn.lParam   = lParam;
1756
1757   for (i = 0; i < psInfo->nPages; i++)
1758   {
1759     hwndPage = psInfo->proppage[i].hwndPage;
1760     if (hwndPage)
1761     {
1762        switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1763        {
1764        case PSNRET_INVALID:
1765            PROPSHEET_ShowPage(hwndDlg, i, psInfo);
1766            /* fall through */
1767        case PSNRET_INVALID_NOCHANGEPAGE:
1768            return FALSE;
1769        }
1770     }
1771   }
1772
1773   if(lParam)
1774   {
1775      psInfo->activeValid = FALSE;
1776   }
1777   else if(psInfo->active_page >= 0)
1778   {
1779      psn.hdr.code = PSN_SETACTIVE;
1780      psn.lParam   = 0;
1781      hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1782      SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1783   }
1784
1785   return TRUE;
1786 }
1787
1788 /******************************************************************************
1789  *            PROPSHEET_Cancel
1790  */
1791 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1792 {
1793   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1794                                                     PropSheetInfoStr);
1795   HWND hwndPage;
1796   PSHNOTIFY psn;
1797   int i;
1798
1799   TRACE("active_page %d\n", psInfo->active_page);
1800   if (psInfo->active_page < 0)
1801      return;
1802
1803   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1804   psn.hdr.code     = PSN_QUERYCANCEL;
1805   psn.hdr.hwndFrom = hwndDlg;
1806   psn.hdr.idFrom   = 0;
1807   psn.lParam       = 0;
1808
1809   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1810     return;
1811
1812   psn.hdr.code = PSN_RESET;
1813   psn.lParam   = lParam;
1814
1815   for (i = 0; i < psInfo->nPages; i++)
1816   {
1817     hwndPage = psInfo->proppage[i].hwndPage;
1818
1819     if (hwndPage)
1820        SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1821   }
1822
1823   if (psInfo->isModeless)
1824   {
1825      /* makes PSM_GETCURRENTPAGEHWND return NULL */
1826      psInfo->activeValid = FALSE;
1827   }
1828   else
1829     psInfo->ended = TRUE;
1830 }
1831
1832 /******************************************************************************
1833  *            PROPSHEET_Help
1834  */
1835 static void PROPSHEET_Help(HWND hwndDlg)
1836 {
1837   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1838                                                     PropSheetInfoStr);
1839   HWND hwndPage;
1840   PSHNOTIFY psn;
1841
1842   TRACE("active_page %d\n", psInfo->active_page);
1843   if (psInfo->active_page < 0)
1844      return;
1845
1846   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1847   psn.hdr.code     = PSN_HELP;
1848   psn.hdr.hwndFrom = hwndDlg;
1849   psn.hdr.idFrom   = 0;
1850   psn.lParam       = 0;
1851
1852   SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1853 }
1854
1855 /******************************************************************************
1856  *            PROPSHEET_Changed
1857  */
1858 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1859 {
1860   int i;
1861   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1862                                                     PropSheetInfoStr);
1863
1864   TRACE("\n");
1865   if (!psInfo) return;
1866   /*
1867    * Set the dirty flag of this page.
1868    */
1869   for (i = 0; i < psInfo->nPages; i++)
1870   {
1871     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1872       psInfo->proppage[i].isDirty = TRUE;
1873   }
1874
1875   /*
1876    * Enable the Apply button.
1877    */
1878   if (psInfo->hasApply)
1879   {
1880     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1881
1882     EnableWindow(hwndApplyBtn, TRUE);
1883   }
1884 }
1885
1886 /******************************************************************************
1887  *            PROPSHEET_UnChanged
1888  */
1889 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1890 {
1891   int i;
1892   BOOL noPageDirty = TRUE;
1893   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1894   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1895                                                     PropSheetInfoStr);
1896
1897   TRACE("\n");
1898   if ( !psInfo ) return;
1899   for (i = 0; i < psInfo->nPages; i++)
1900   {
1901     /* set the specified page as clean */
1902     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1903       psInfo->proppage[i].isDirty = FALSE;
1904
1905     /* look to see if there's any dirty pages */
1906     if (psInfo->proppage[i].isDirty)
1907       noPageDirty = FALSE;
1908   }
1909
1910   /*
1911    * Disable Apply button.
1912    */
1913   if (noPageDirty)
1914     EnableWindow(hwndApplyBtn, FALSE);
1915 }
1916
1917 /******************************************************************************
1918  *            PROPSHEET_PressButton
1919  */
1920 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1921 {
1922   TRACE("buttonID %d\n", buttonID);
1923   switch (buttonID)
1924   {
1925     case PSBTN_APPLYNOW:
1926       PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
1927       break;
1928     case PSBTN_BACK:
1929       PROPSHEET_Back(hwndDlg);
1930       break;
1931     case PSBTN_CANCEL:
1932       PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
1933       break;
1934     case PSBTN_FINISH:
1935       PROPSHEET_Finish(hwndDlg);
1936       break;
1937     case PSBTN_HELP:
1938       PROPSHEET_DoCommand(hwndDlg, IDHELP);
1939       break;
1940     case PSBTN_NEXT:
1941       PROPSHEET_Next(hwndDlg);
1942       break;
1943     case PSBTN_OK:
1944       PROPSHEET_DoCommand(hwndDlg, IDOK);
1945       break;
1946     default:
1947       FIXME("Invalid button index %d\n", buttonID);
1948   }
1949 }
1950
1951
1952 /*************************************************************************
1953  * BOOL PROPSHEET_CanSetCurSel [Internal]
1954  *
1955  * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1956  *
1957  * PARAMS
1958  *     hwndDlg        [I] handle to a Dialog hWnd
1959  *
1960  * RETURNS
1961  *     TRUE if Current Selection can change
1962  *
1963  * NOTES
1964  */
1965 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1966 {
1967   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1968                                                     PropSheetInfoStr);
1969   HWND hwndPage;
1970   PSHNOTIFY psn;
1971   BOOL res = FALSE;
1972
1973   TRACE("active_page %d\n", psInfo->active_page);
1974   if (!psInfo)
1975   {
1976      res = FALSE;
1977      goto end;
1978   }
1979
1980   if (psInfo->active_page < 0)
1981   {
1982      res = TRUE;
1983      goto end;
1984   }
1985
1986   /*
1987    * Notify the current page.
1988    */
1989   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1990   psn.hdr.code     = PSN_KILLACTIVE;
1991   psn.hdr.hwndFrom = hwndDlg;
1992   psn.hdr.idFrom   = 0;
1993   psn.lParam       = 0;
1994
1995   res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1996
1997 end:
1998   TRACE("<-- %d\n", res);
1999   return res;
2000 }
2001
2002 /******************************************************************************
2003  *            PROPSHEET_SetCurSel
2004  */
2005 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
2006                                 int index,
2007                                 int skipdir,
2008                                 HPROPSHEETPAGE hpage
2009                                 )
2010 {
2011   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2012   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
2013   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2014
2015   TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
2016   /* hpage takes precedence over index */
2017   if (hpage != NULL)
2018     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2019
2020   if (index < 0 || index >= psInfo->nPages)
2021   {
2022     TRACE("Could not find page to select!\n");
2023     return FALSE;
2024   }
2025
2026   while (1) {
2027     int result;
2028     PSHNOTIFY psn;
2029     RECT rc;
2030     LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2031
2032     if (hwndTabControl)
2033         SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);
2034
2035     psn.hdr.code     = PSN_SETACTIVE;
2036     psn.hdr.hwndFrom = hwndDlg;
2037     psn.hdr.idFrom   = 0;
2038     psn.lParam       = 0;
2039
2040     if (!psInfo->proppage[index].hwndPage) {
2041       PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
2042     }
2043
2044     /* Resize the property sheet page to the fit in the Tab control
2045      * (for regular property sheets) or to fit in the client area (for
2046      * wizards).
2047      * NOTE: The resizing happens every time the page is selected and
2048      * not only when it's created (some applications depend on it). */
2049     PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage);
2050     TRACE("setting page %p, rc (%d,%d)-(%d,%d) w=%d, h=%d\n",
2051           psInfo->proppage[index].hwndPage, rc.left, rc.top, rc.right, rc.bottom,
2052           rc.right - rc.left, rc.bottom - rc.top);
2053     SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP,
2054                  rc.left, rc.top,
2055                  rc.right - rc.left, rc.bottom - rc.top, 0);
2056
2057     result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
2058     if (!result)
2059       break;
2060     if (result == -1) {
2061       index+=skipdir;
2062       if (index < 0) {
2063         index = 0;
2064         WARN("Tried to skip before first property sheet page!\n");
2065         break;
2066       }
2067       if (index >= psInfo->nPages) {
2068         WARN("Tried to skip after last property sheet page!\n");
2069         index = psInfo->nPages-1;
2070         break;
2071       }
2072     }
2073     else if (result != 0)
2074     {
2075       int old_index = index;
2076       index = PROPSHEET_FindPageByResId(psInfo, result);
2077       if(index >= psInfo->nPages) {
2078         index = old_index;
2079         WARN("Tried to skip to nonexistant page by res id\n");
2080         break;
2081       }
2082       continue;
2083     }
2084   }
2085
2086   /* Invalidate the header area */
2087   if ( (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
2088        (psInfo->ppshheader.dwFlags & PSH_HEADER) )
2089   {
2090     HWND hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
2091     RECT r;
2092
2093     GetClientRect(hwndLineHeader, &r);
2094     MapWindowPoints(hwndLineHeader, hwndDlg, (LPPOINT) &r, 2);
2095     SetRect(&r, 0, 0, r.right + 1, r.top - 1);
2096
2097     InvalidateRect(hwndDlg, &r, TRUE);
2098   }
2099
2100   /*
2101    * Display the new page.
2102    */
2103   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
2104
2105   if (psInfo->proppage[index].hasHelp)
2106     EnableWindow(hwndHelp, TRUE);
2107   else
2108     EnableWindow(hwndHelp, FALSE);
2109
2110   return TRUE;
2111 }
2112
2113 /******************************************************************************
2114  *            PROPSHEET_SetCurSelId
2115  *
2116  * Selects the page, specified by resource id.
2117  */
2118 static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)
2119 {
2120       int idx;
2121       PropSheetInfo* psInfo =
2122           (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2123
2124       idx = PROPSHEET_FindPageByResId(psInfo, id);
2125       if (idx < psInfo->nPages )
2126       {
2127           if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
2128               PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
2129       }
2130 }
2131
2132 /******************************************************************************
2133  *            PROPSHEET_SetTitleA
2134  */
2135 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
2136 {
2137   if(HIWORD(lpszText))
2138   {
2139      WCHAR szTitle[256];
2140      MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
2141                          szTitle, sizeof(szTitle)/sizeof(WCHAR));
2142      PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
2143   }
2144   else
2145   {
2146      PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
2147   }
2148 }
2149
2150 /******************************************************************************
2151  *            PROPSHEET_SetTitleW
2152  */
2153 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
2154 {
2155   PropSheetInfo*        psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2156   WCHAR                 szTitle[256];
2157
2158   TRACE("%s (style %08x)\n", debugstr_w(lpszText), dwStyle);
2159   if (HIWORD(lpszText) == 0) {
2160     if (!LoadStringW(psInfo->ppshheader.hInstance,
2161                      LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))
2162       return;
2163     lpszText = szTitle;
2164   }
2165   if (dwStyle & PSH_PROPTITLE)
2166   {
2167     WCHAR* dest;
2168     int lentitle = strlenW(lpszText);
2169     int lenprop  = strlenW(psInfo->strPropertiesFor);
2170
2171     dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
2172     wsprintfW(dest, psInfo->strPropertiesFor, lpszText);
2173
2174     SetWindowTextW(hwndDlg, dest);
2175     Free(dest);
2176   }
2177   else
2178     SetWindowTextW(hwndDlg, lpszText);
2179 }
2180
2181 /******************************************************************************
2182  *            PROPSHEET_SetFinishTextA
2183  */
2184 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
2185 {
2186   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2187   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2188
2189   TRACE("'%s'\n", lpszText);
2190   /* Set text, show and enable the Finish button */
2191   SetWindowTextA(hwndButton, lpszText);
2192   ShowWindow(hwndButton, SW_SHOW);
2193   EnableWindow(hwndButton, TRUE);
2194
2195   /* Make it default pushbutton */
2196   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2197
2198   /* Hide Back button */
2199   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2200   ShowWindow(hwndButton, SW_HIDE);
2201
2202   if (!psInfo->hasFinish)
2203   {
2204     /* Hide Next button */
2205     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2206     ShowWindow(hwndButton, SW_HIDE);
2207   }
2208 }
2209
2210 /******************************************************************************
2211  *            PROPSHEET_SetFinishTextW
2212  */
2213 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
2214 {
2215   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2216   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2217
2218   TRACE("%s\n", debugstr_w(lpszText));
2219   /* Set text, show and enable the Finish button */
2220   SetWindowTextW(hwndButton, lpszText);
2221   ShowWindow(hwndButton, SW_SHOW);
2222   EnableWindow(hwndButton, TRUE);
2223
2224   /* Make it default pushbutton */
2225   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2226
2227   /* Hide Back button */
2228   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2229   ShowWindow(hwndButton, SW_HIDE);
2230
2231   if (!psInfo->hasFinish)
2232   {
2233     /* Hide Next button */
2234     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2235     ShowWindow(hwndButton, SW_HIDE);
2236   }
2237 }
2238
2239 /******************************************************************************
2240  *            PROPSHEET_QuerySiblings
2241  */
2242 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
2243                                        WPARAM wParam, LPARAM lParam)
2244 {
2245   int i = 0;
2246   HWND hwndPage;
2247   LRESULT msgResult = 0;
2248   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2249
2250   while ((i < psInfo->nPages) && (msgResult == 0))
2251   {
2252     hwndPage = psInfo->proppage[i].hwndPage;
2253     msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
2254     i++;
2255   }
2256
2257   return msgResult;
2258 }
2259
2260
2261 /******************************************************************************
2262  *            PROPSHEET_AddPage
2263  */
2264 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
2265                               HPROPSHEETPAGE hpage)
2266 {
2267   PropPageInfo * ppi;
2268   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2269                                                      PropSheetInfoStr);
2270   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2271   TCITEMW item;
2272   LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
2273
2274   TRACE("hpage %p\n", hpage);
2275   /*
2276    * Allocate and fill in a new PropPageInfo entry.
2277    */
2278   ppi = (PropPageInfo*) ReAlloc(psInfo->proppage,
2279                                 sizeof(PropPageInfo) *
2280                                 (psInfo->nPages + 1));
2281   if (!ppi)
2282       return FALSE;
2283
2284   psInfo->proppage = ppi;
2285   if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
2286       return FALSE;
2287
2288   psInfo->proppage[psInfo->nPages].hpage = hpage;
2289
2290   if (ppsp->dwFlags & PSP_PREMATURE)
2291   {
2292      /* Create the page but don't show it */
2293      PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
2294   }
2295
2296   /*
2297    * Add a new tab to the tab control.
2298    */
2299   item.mask = TCIF_TEXT;
2300   item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
2301   item.cchTextMax = MAX_TABTEXT_LENGTH;
2302
2303   if (psInfo->hImageList)
2304   {
2305     SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
2306   }
2307
2308   if ( psInfo->proppage[psInfo->nPages].hasIcon )
2309   {
2310     item.mask |= TCIF_IMAGE;
2311     item.iImage = psInfo->nPages;
2312   }
2313
2314   SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
2315                (LPARAM)&item);
2316
2317   psInfo->nPages++;
2318
2319   /* If it is the only page - show it */
2320   if(psInfo->nPages == 1)
2321      PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
2322   return TRUE;
2323 }
2324
2325 /******************************************************************************
2326  *            PROPSHEET_RemovePage
2327  */
2328 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
2329                                  int index,
2330                                  HPROPSHEETPAGE hpage)
2331 {
2332   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2333                                                      PropSheetInfoStr);
2334   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2335   PropPageInfo* oldPages;
2336
2337   TRACE("index %d, hpage %p\n", index, hpage);
2338   if (!psInfo) {
2339     return FALSE;
2340   }
2341   /*
2342    * hpage takes precedence over index.
2343    */
2344   if (hpage != 0)
2345   {
2346     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2347   }
2348
2349   /* Make sure that index is within range */
2350   if (index < 0 || index >= psInfo->nPages)
2351   {
2352       TRACE("Could not find page to remove!\n");
2353       return FALSE;
2354   }
2355
2356   TRACE("total pages %d removing page %d active page %d\n",
2357         psInfo->nPages, index, psInfo->active_page);
2358   /*
2359    * Check if we're removing the active page.
2360    */
2361   if (index == psInfo->active_page)
2362   {
2363     if (psInfo->nPages > 1)
2364     {
2365       if (index > 0)
2366       {
2367         /* activate previous page  */
2368         PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
2369       }
2370       else
2371       {
2372         /* activate the next page */
2373         PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
2374         psInfo->active_page = index;
2375       }
2376     }
2377     else
2378     {
2379       psInfo->active_page = -1;
2380       if (!psInfo->isModeless)
2381       {
2382          psInfo->ended = TRUE;
2383          return TRUE;
2384       }
2385     }
2386   }
2387   else if (index < psInfo->active_page)
2388     psInfo->active_page--;
2389
2390   /* Unsubclass the page dialog window */
2391   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) &&
2392      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2393      ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER))
2394   {
2395      RemoveWindowSubclass(psInfo->proppage[index].hwndPage,
2396                           PROPSHEET_WizardSubclassProc, 1);
2397   }
2398
2399   /* Destroy page dialog window */
2400   DestroyWindow(psInfo->proppage[index].hwndPage);
2401
2402   /* Free page resources */
2403   if(psInfo->proppage[index].hpage)
2404   {
2405      PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
2406
2407      if (psp->dwFlags & PSP_USETITLE)
2408         Free ((LPVOID)psInfo->proppage[index].pszText);
2409
2410      DestroyPropertySheetPage(psInfo->proppage[index].hpage);
2411   }
2412
2413   /* Remove the tab */
2414   SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
2415
2416   oldPages = psInfo->proppage;
2417   psInfo->nPages--;
2418   psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);
2419
2420   if (index > 0)
2421     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
2422
2423   if (index < psInfo->nPages)
2424     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
2425            (psInfo->nPages - index) * sizeof(PropPageInfo));
2426
2427   Free(oldPages);
2428
2429   return FALSE;
2430 }
2431
2432 /******************************************************************************
2433  *            PROPSHEET_SetWizButtons
2434  *
2435  * This code will work if (and assumes that) the Next button is on top of the
2436  * Finish button. ie. Finish comes after Next in the Z order.
2437  * This means make sure the dialog template reflects this.
2438  *
2439  */
2440 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
2441 {
2442   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2443                                                     PropSheetInfoStr);
2444   HWND hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2445   HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2446   HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2447
2448   TRACE("%d\n", dwFlags);
2449
2450   EnableWindow(hwndBack, FALSE);
2451   EnableWindow(hwndNext, FALSE);
2452   EnableWindow(hwndFinish, FALSE);
2453
2454   /* set the default pushbutton to an enabled button */
2455   if (((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH))
2456     SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2457   else if (dwFlags & PSWIZB_NEXT)
2458     SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
2459   else if (dwFlags & PSWIZB_BACK)
2460     SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0);
2461   else
2462     SendMessageW(hwndDlg, DM_SETDEFID, IDCANCEL, 0);
2463
2464
2465   if (dwFlags & PSWIZB_BACK)
2466     EnableWindow(hwndBack, TRUE);
2467
2468   if (dwFlags & PSWIZB_NEXT)
2469     EnableWindow(hwndNext, TRUE);
2470
2471   if (!psInfo->hasFinish)
2472   {
2473     if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
2474     {
2475       /* Hide the Next button */
2476       ShowWindow(hwndNext, SW_HIDE);
2477       
2478       /* Show the Finish button */
2479       ShowWindow(hwndFinish, SW_SHOW);
2480
2481       if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2482         EnableWindow(hwndFinish, TRUE);
2483     }
2484     else
2485     {
2486       /* Hide the Finish button */
2487       ShowWindow(hwndFinish, SW_HIDE);
2488       /* Show the Next button */
2489       ShowWindow(hwndNext, SW_SHOW);
2490     }
2491   }
2492   else if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2493     EnableWindow(hwndFinish, TRUE);
2494 }
2495
2496 /******************************************************************************
2497  *            PROPSHEET_InsertPage
2498  */
2499 static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage)
2500 {
2501     if (!HIWORD(hpageInsertAfter))
2502         FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage);
2503     else
2504         FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage);
2505     return FALSE;
2506 }
2507
2508 /******************************************************************************
2509  *            PROPSHEET_SetHeaderTitleW
2510  */
2511 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle)
2512 {
2513     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle));
2514 }
2515
2516 /******************************************************************************
2517  *            PROPSHEET_SetHeaderTitleA
2518  */
2519 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle)
2520 {
2521     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle));
2522 }
2523
2524 /******************************************************************************
2525  *            PROPSHEET_SetHeaderSubTitleW
2526  */
2527 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle)
2528 {
2529     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle));
2530 }
2531
2532 /******************************************************************************
2533  *            PROPSHEET_SetHeaderSubTitleA
2534  */
2535 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle)
2536 {
2537     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle));
2538 }
2539
2540 /******************************************************************************
2541  *            PROPSHEET_HwndToIndex
2542  */
2543 static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg)
2544 {
2545     int index;
2546     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2547                                                        PropSheetInfoStr);
2548
2549     TRACE("(%p, %p)\n", hwndDlg, hPageDlg);
2550
2551     for (index = 0; index < psInfo->nPages; index++)
2552         if (psInfo->proppage[index].hwndPage == hPageDlg)
2553             return index;
2554     WARN("%p not found\n", hPageDlg);
2555     return -1;
2556 }
2557
2558 /******************************************************************************
2559  *            PROPSHEET_IndexToHwnd
2560  */
2561 static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex)
2562 {
2563     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2564                                                        PropSheetInfoStr);
2565     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2566     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2567         WARN("%d out of range.\n", iPageIndex);
2568         return 0;
2569     }
2570     return (LRESULT)psInfo->proppage[iPageIndex].hwndPage;
2571 }
2572
2573 /******************************************************************************
2574  *            PROPSHEET_PageToIndex
2575  */
2576 static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage)
2577 {
2578     int index;
2579     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2580                                                        PropSheetInfoStr);
2581
2582     TRACE("(%p, %p)\n", hwndDlg, hPage);
2583
2584     for (index = 0; index < psInfo->nPages; index++)
2585         if (psInfo->proppage[index].hpage == hPage)
2586             return index;
2587     WARN("%p not found\n", hPage);
2588     return -1;
2589 }
2590
2591 /******************************************************************************
2592  *            PROPSHEET_IndexToPage
2593  */
2594 static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex)
2595 {
2596     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2597                                                        PropSheetInfoStr);
2598     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2599     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2600         WARN("%d out of range.\n", iPageIndex);
2601         return 0;
2602     }
2603     return (LRESULT)psInfo->proppage[iPageIndex].hpage;
2604 }
2605
2606 /******************************************************************************
2607  *            PROPSHEET_IdToIndex
2608  */
2609 static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId)
2610 {
2611     int index;
2612     LPCPROPSHEETPAGEW psp;
2613     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2614                                                        PropSheetInfoStr);
2615     TRACE("(%p, %d)\n", hwndDlg, iPageId);
2616     for (index = 0; index < psInfo->nPages; index++) {
2617         psp = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2618         if (psp->u.pszTemplate == MAKEINTRESOURCEW(iPageId))
2619             return index;
2620     }
2621
2622     return -1;
2623 }
2624
2625 /******************************************************************************
2626  *            PROPSHEET_IndexToId
2627  */
2628 static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex)
2629 {
2630     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2631                                                        PropSheetInfoStr);
2632     LPCPROPSHEETPAGEW psp;
2633     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2634     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2635         WARN("%d out of range.\n", iPageIndex);
2636         return 0;
2637     }
2638     psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage;
2639     if (psp->dwFlags & PSP_DLGINDIRECT || HIWORD(psp->u.pszTemplate)) {
2640         return 0;
2641     }
2642     return (LRESULT)psp->u.pszTemplate;
2643 }
2644
2645 /******************************************************************************
2646  *            PROPSHEET_GetResult
2647  */
2648 static LRESULT PROPSHEET_GetResult(HWND hwndDlg)
2649 {
2650     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2651                                                        PropSheetInfoStr);
2652     return psInfo->result;
2653 }
2654
2655 /******************************************************************************
2656  *            PROPSHEET_RecalcPageSizes
2657  */
2658 static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg)
2659 {
2660     FIXME("(%p): stub\n", hwndDlg);
2661     return FALSE;
2662 }
2663
2664 /******************************************************************************
2665  *            PROPSHEET_GetPageIndex
2666  *
2667  * Given a HPROPSHEETPAGE, returns the index of the corresponding page from
2668  * the array of PropPageInfo.
2669  */
2670 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo)
2671 {
2672   BOOL found = FALSE;
2673   int index = 0;
2674
2675   TRACE("hpage %p\n", hpage);
2676   while ((index < psInfo->nPages) && (found == FALSE))
2677   {
2678     if (psInfo->proppage[index].hpage == hpage)
2679       found = TRUE;
2680     else
2681       index++;
2682   }
2683
2684   if (found == FALSE)
2685     index = -1;
2686
2687   return index;
2688 }
2689
2690 /******************************************************************************
2691  *            PROPSHEET_CleanUp
2692  */
2693 static void PROPSHEET_CleanUp(HWND hwndDlg)
2694 {
2695   int i;
2696   PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg,
2697                                                        PropSheetInfoStr);
2698
2699   TRACE("\n");
2700   if (!psInfo) return;
2701   if (HIWORD(psInfo->ppshheader.pszCaption))
2702       Free ((LPVOID)psInfo->ppshheader.pszCaption);
2703
2704   for (i = 0; i < psInfo->nPages; i++)
2705   {
2706      PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage;
2707
2708      /* Unsubclass the page dialog window */
2709      if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
2710         (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2711         (psp->dwFlags & PSP_HIDEHEADER))
2712      {
2713         RemoveWindowSubclass(psInfo->proppage[i].hwndPage,
2714                              PROPSHEET_WizardSubclassProc, 1);
2715      }
2716
2717      if(psInfo->proppage[i].hwndPage)
2718         DestroyWindow(psInfo->proppage[i].hwndPage);
2719
2720      if(psp)
2721      {
2722         if (psp->dwFlags & PSP_USETITLE)
2723            Free ((LPVOID)psInfo->proppage[i].pszText);
2724
2725         DestroyPropertySheetPage(psInfo->proppage[i].hpage);
2726      }
2727   }
2728
2729   DeleteObject(psInfo->hFont);
2730   DeleteObject(psInfo->hFontBold);
2731   /* If we created the bitmaps, destroy them */
2732   if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2733       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) )
2734       DeleteObject(psInfo->ppshheader.u4.hbmWatermark);
2735   if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
2736       (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) )
2737       DeleteObject(psInfo->ppshheader.u5.hbmHeader);
2738
2739   Free(psInfo->proppage);
2740   Free(psInfo->strPropertiesFor);
2741   ImageList_Destroy(psInfo->hImageList);
2742
2743   GlobalFree((HGLOBAL)psInfo);
2744 }
2745
2746 static INT do_loop(PropSheetInfo *psInfo)
2747 {
2748     MSG msg;
2749     INT ret = -1;
2750     HWND hwnd = psInfo->hwnd;
2751
2752     while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0)))
2753     {
2754         if(ret == -1)
2755             break;
2756
2757         if(!IsDialogMessageW(hwnd, &msg))
2758         {
2759             TranslateMessage(&msg);
2760             DispatchMessageW(&msg);
2761         }
2762     }
2763
2764     if(ret == 0)
2765     {
2766         PostQuitMessage(msg.wParam);
2767         ret = -1;
2768     }
2769
2770     if(ret != -1)
2771         ret = psInfo->result;
2772
2773     DestroyWindow(hwnd);
2774     return ret;
2775 }
2776
2777 /******************************************************************************
2778  *            PropertySheet    (COMCTL32.@)
2779  *            PropertySheetA   (COMCTL32.@)
2780  *
2781  * Creates a property sheet in the specified property sheet header.
2782  *
2783  * RETURNS
2784  *     Modal property sheets: Positive if successful or -1 otherwise.
2785  *     Modeless property sheets: Property sheet handle.
2786  *     Or:
2787  *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect.
2788  *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect.
2789  */
2790 INT_PTR WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh)
2791 {
2792   INT_PTR bRet = 0;
2793   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2794                                                        sizeof(PropSheetInfo));
2795   UINT i, n;
2796   const BYTE* pByte;
2797
2798   TRACE("(%p)\n", lppsh);
2799
2800   PROPSHEET_CollectSheetInfoA(lppsh, psInfo);
2801
2802   psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
2803                                                     lppsh->nPages);
2804   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
2805
2806   for (n = i = 0; i < lppsh->nPages; i++, n++)
2807   {
2808     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2809       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2810     else
2811     {
2812        psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte);
2813        pByte += ((LPCPROPSHEETPAGEA)pByte)->dwSize;
2814     }
2815
2816     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
2817                                psInfo, n))
2818     {
2819         if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2820             DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2821         n--;
2822         psInfo->nPages--;
2823     }
2824   }
2825
2826   if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0;
2827   TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages);
2828
2829   psInfo->unicode = FALSE;
2830   psInfo->ended = FALSE;
2831
2832   bRet = PROPSHEET_CreateDialog(psInfo);
2833   if(!psInfo->isModeless)
2834       bRet = do_loop(psInfo);
2835
2836   return bRet;
2837 }
2838
2839 /******************************************************************************
2840  *            PropertySheetW   (COMCTL32.@)
2841  *
2842  * See PropertySheetA.
2843  */
2844 INT_PTR WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh)
2845 {
2846   INT_PTR bRet = 0;
2847   PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR,
2848                                                        sizeof(PropSheetInfo));
2849   UINT i, n;
2850   const BYTE* pByte;
2851
2852   TRACE("(%p)\n", lppsh);
2853
2854   PROPSHEET_CollectSheetInfoW(lppsh, psInfo);
2855
2856   psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) *
2857                                                     lppsh->nPages);
2858   pByte = (const BYTE*) psInfo->ppshheader.u3.ppsp;
2859
2860   for (n = i = 0; i < lppsh->nPages; i++, n++)
2861   {
2862     if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE))
2863       psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i];
2864     else
2865     {
2866        psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte);
2867        pByte += ((LPCPROPSHEETPAGEW)pByte)->dwSize;
2868     }
2869
2870     if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage,
2871                                psInfo, n))
2872     {
2873         if (lppsh->dwFlags & PSH_PROPSHEETPAGE)
2874             DestroyPropertySheetPage(psInfo->proppage[n].hpage);
2875         n--;
2876         psInfo->nPages--;
2877     }
2878   }
2879
2880   if (psInfo->active_page >= psInfo->nPages) psInfo->active_page = 0;
2881   TRACE("startpage: %d of %d pages\n", psInfo->active_page, psInfo->nPages);
2882
2883   psInfo->unicode = TRUE;
2884   psInfo->ended = FALSE;
2885
2886   bRet = PROPSHEET_CreateDialog(psInfo);
2887   if(!psInfo->isModeless)
2888       bRet = do_loop(psInfo);
2889
2890   return bRet;
2891 }
2892
2893 static LPWSTR load_string( HINSTANCE instance, LPCWSTR str )
2894 {
2895     LPWSTR ret;
2896     UINT len;
2897
2898     if (IS_INTRESOURCE(str))
2899     {
2900         HRSRC hrsrc;
2901         HGLOBAL hmem;
2902         WCHAR *ptr;
2903         WORD i, id = LOWORD(str);
2904
2905         if (!(hrsrc = FindResourceW( instance, MAKEINTRESOURCEW((id >> 4) + 1), (LPWSTR)RT_STRING )))
2906             return NULL;
2907         if (!(hmem = LoadResource( instance, hrsrc ))) return NULL;
2908         if (!(ptr = LockResource( hmem ))) return NULL;
2909         for (i = id & 0x0f; i > 0; i--) ptr += *ptr + 1;
2910         len = *ptr;
2911         if (!len) return NULL;
2912         ret = Alloc( (len + 1) * sizeof(WCHAR) );
2913         if (ret)
2914         {
2915             memcpy( ret, ptr + 1, len * sizeof(WCHAR) );
2916             ret[len] = 0;
2917         }
2918     }
2919     else
2920     {
2921         int len = (strlenW(str) + 1) * sizeof(WCHAR);
2922         ret = Alloc( len );
2923         if (ret) memcpy( ret, str, len );
2924     }
2925     return ret;
2926 }
2927
2928
2929 /******************************************************************************
2930  *            CreatePropertySheetPage    (COMCTL32.@)
2931  *            CreatePropertySheetPageA   (COMCTL32.@)
2932  *
2933  * Creates a new property sheet page.
2934  *
2935  * RETURNS
2936  *     Success: Handle to new property sheet page.
2937  *     Failure: NULL.
2938  *
2939  * NOTES
2940  *     An application must use the PSM_ADDPAGE message to add the new page to
2941  *     an existing property sheet.
2942  */
2943 HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(
2944                           LPCPROPSHEETPAGEA lpPropSheetPage)
2945 {
2946   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
2947
2948   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA)));
2949
2950   ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE;
2951
2952     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
2953     {
2954         if (HIWORD( ppsp->u.pszTemplate ))
2955         {
2956             int len = strlen(lpPropSheetPage->u.pszTemplate) + 1;
2957             char *template = Alloc( len );
2958
2959             ppsp->u.pszTemplate = (LPWSTR)strcpy( template, lpPropSheetPage->u.pszTemplate );
2960         }
2961     }
2962
2963     if (ppsp->dwFlags & PSP_USEICONID)
2964     {
2965         if (HIWORD( ppsp->u2.pszIcon ))
2966             PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon);
2967     }
2968
2969     if (ppsp->dwFlags & PSP_USETITLE)
2970     {
2971         if (HIWORD( ppsp->pszTitle ))
2972             PROPSHEET_AtoW( &ppsp->pszTitle, lpPropSheetPage->pszTitle );
2973         else
2974             ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
2975     }
2976     else
2977         ppsp->pszTitle = NULL;
2978
2979     if (ppsp->dwFlags & PSP_HIDEHEADER)
2980         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
2981
2982     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
2983     {
2984         if (HIWORD( ppsp->pszHeaderTitle ))
2985             PROPSHEET_AtoW(&ppsp->pszHeaderTitle, lpPropSheetPage->pszHeaderTitle);
2986         else
2987             ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
2988     }
2989     else
2990         ppsp->pszHeaderTitle = NULL;
2991
2992     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
2993     {
2994         if (HIWORD( ppsp->pszHeaderSubTitle ))
2995             PROPSHEET_AtoW(&ppsp->pszHeaderSubTitle, lpPropSheetPage->pszHeaderSubTitle);
2996         else
2997             ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
2998     }
2999     else
3000         ppsp->pszHeaderSubTitle = NULL;
3001
3002     return (HPROPSHEETPAGE)ppsp;
3003 }
3004
3005 /******************************************************************************
3006  *            CreatePropertySheetPageW   (COMCTL32.@)
3007  *
3008  * See CreatePropertySheetA.
3009  */
3010 HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage)
3011 {
3012   PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW));
3013
3014   memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW)));
3015
3016   ppsp->dwFlags |= PSP_INTERNAL_UNICODE;
3017
3018     if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) )
3019     {
3020         if (HIWORD( ppsp->u.pszTemplate ))
3021         {
3022             int len = strlenW(lpPropSheetPage->u.pszTemplate) + 1;
3023             WCHAR *template = Alloc( len * sizeof (WCHAR) );
3024
3025             ppsp->u.pszTemplate = strcpyW( template, lpPropSheetPage->u.pszTemplate );
3026         }
3027     }
3028
3029     if ( ppsp->dwFlags & PSP_USEICONID )
3030     {
3031         if (HIWORD( ppsp->u2.pszIcon ))
3032         {
3033             int len = strlenW(lpPropSheetPage->u2.pszIcon) + 1;
3034             WCHAR *icon = Alloc( len * sizeof (WCHAR) );
3035
3036             ppsp->u2.pszIcon = strcpyW( icon, lpPropSheetPage->u2.pszIcon );
3037         }
3038     }
3039
3040     if (ppsp->dwFlags & PSP_USETITLE)
3041         ppsp->pszTitle = load_string( ppsp->hInstance, ppsp->pszTitle );
3042     else
3043         ppsp->pszTitle = NULL;
3044
3045     if (ppsp->dwFlags & PSP_HIDEHEADER)
3046         ppsp->dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE);
3047
3048     if (ppsp->dwFlags & PSP_USEHEADERTITLE)
3049         ppsp->pszHeaderTitle = load_string( ppsp->hInstance, ppsp->pszHeaderTitle );
3050     else
3051         ppsp->pszHeaderTitle = NULL;
3052
3053     if (ppsp->dwFlags & PSP_USEHEADERSUBTITLE)
3054         ppsp->pszHeaderSubTitle = load_string( ppsp->hInstance, ppsp->pszHeaderSubTitle );
3055     else
3056         ppsp->pszHeaderSubTitle = NULL;
3057
3058     return (HPROPSHEETPAGE)ppsp;
3059 }
3060
3061 /******************************************************************************
3062  *            DestroyPropertySheetPage   (COMCTL32.@)
3063  *
3064  * Destroys a property sheet page previously created with
3065  * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated
3066  * memory.
3067  *
3068  * RETURNS
3069  *     Success: TRUE
3070  *     Failure: FALSE
3071  */
3072 BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage)
3073 {
3074   PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage;
3075
3076   if (!psp)
3077      return FALSE;
3078
3079   if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) )
3080      Free ((LPVOID)psp->u.pszTemplate);
3081
3082   if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) )
3083      Free ((LPVOID)psp->u2.pszIcon);
3084
3085   if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle ))
3086      Free ((LPVOID)psp->pszTitle);
3087
3088   Free(hPropPage);
3089
3090   return TRUE;
3091 }
3092
3093 /******************************************************************************
3094  *            PROPSHEET_IsDialogMessage
3095  */
3096 static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg)
3097 {
3098    PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3099
3100    TRACE("\n");
3101    if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd)))
3102       return FALSE;
3103
3104    if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000))
3105    {
3106       int new_page = 0;
3107       INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg);
3108
3109       if (!(dlgCode & DLGC_WANTMESSAGE))
3110       {
3111          switch (lpMsg->wParam)
3112          {
3113             case VK_TAB:
3114                if (GetKeyState(VK_SHIFT) & 0x8000)
3115                    new_page = -1;
3116                 else
3117                    new_page = 1;
3118                break;
3119
3120             case VK_NEXT:   new_page = 1;  break;
3121             case VK_PRIOR:  new_page = -1; break;
3122          }
3123       }
3124
3125       if (new_page)
3126       {
3127          if (PROPSHEET_CanSetCurSel(hwnd) != FALSE)
3128          {
3129             new_page += psInfo->active_page;
3130
3131             if (new_page < 0)
3132                new_page = psInfo->nPages - 1;
3133             else if (new_page >= psInfo->nPages)
3134                new_page = 0;
3135
3136             PROPSHEET_SetCurSel(hwnd, new_page, 1, 0);
3137          }
3138
3139          return TRUE;
3140       }
3141    }
3142
3143    return IsDialogMessageW(hwnd, lpMsg);
3144 }
3145
3146 /******************************************************************************
3147  *            PROPSHEET_DoCommand
3148  */
3149 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID)
3150 {
3151
3152     switch (wID) {
3153
3154     case IDOK:
3155     case IDC_APPLY_BUTTON:
3156         {
3157             HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON);
3158
3159             if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE)
3160                 break;
3161
3162             if (wID == IDOK)
3163                 {
3164                     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3165                                                                       PropSheetInfoStr);
3166
3167                     /* don't overwrite ID_PSRESTARTWINDOWS or ID_PSREBOOTSYSTEM */
3168                     if (psInfo->result == 0)
3169                         psInfo->result = IDOK;
3170
3171                     if (psInfo->isModeless)
3172                         psInfo->activeValid = FALSE;
3173                     else
3174                         psInfo->ended = TRUE;
3175                 }
3176             else
3177                 EnableWindow(hwndApplyBtn, FALSE);
3178
3179             break;
3180         }
3181
3182     case IDC_BACK_BUTTON:
3183         PROPSHEET_Back(hwnd);
3184         break;
3185
3186     case IDC_NEXT_BUTTON:
3187         PROPSHEET_Next(hwnd);
3188         break;
3189
3190     case IDC_FINISH_BUTTON:
3191         PROPSHEET_Finish(hwnd);
3192         break;
3193
3194     case IDCANCEL:
3195         PROPSHEET_Cancel(hwnd, 0);
3196         break;
3197
3198     case IDHELP:
3199         PROPSHEET_Help(hwnd);
3200         break;
3201
3202     default:
3203         return FALSE;
3204     }
3205
3206     return TRUE;
3207 }
3208
3209 /******************************************************************************
3210  *            PROPSHEET_Paint
3211  */
3212 static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam)
3213 {
3214     PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3215     PAINTSTRUCT ps;
3216     HDC hdc, hdcSrc;
3217     BITMAP bm;
3218     HBITMAP hbmp;
3219     HPALETTE hOldPal = 0;
3220     int offsety = 0;
3221     HBRUSH hbr;
3222     RECT r, rzone;
3223     LPCPROPSHEETPAGEW ppshpage;
3224     WCHAR szBuffer[256];
3225     int nLength;
3226
3227     hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps);
3228     if (!hdc) return 1;
3229
3230     hdcSrc = CreateCompatibleDC(0);
3231     ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage;
3232
3233     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
3234         hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE);
3235
3236     if ( (!(ppshpage->dwFlags & PSP_HIDEHEADER)) &&
3237          (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
3238          (psInfo->ppshheader.dwFlags & PSH_HEADER) ) 
3239     {
3240         HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER);
3241         HFONT hOldFont;
3242         COLORREF clrOld = 0;
3243         int oldBkMode = 0;
3244
3245         hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader);
3246         hOldFont = SelectObject(hdc, psInfo->hFontBold);
3247
3248         GetClientRect(hwndLineHeader, &r);
3249         MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2);
3250         SetRect(&rzone, 0, 0, r.right + 1, r.top - 1);
3251
3252         GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), (LPVOID)&bm);               
3253
3254         if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD)
3255         {
3256             /* Fill the unoccupied part of the header with color of the
3257              * left-top pixel, but do it only when needed.
3258              */
3259             if (bm.bmWidth < r.right || bm.bmHeight < r.bottom)
3260             {
3261                 hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
3262                 CopyRect(&r, &rzone);
3263                 if (bm.bmWidth < r.right)
3264                 {
3265                     r.left = bm.bmWidth;
3266                     FillRect(hdc, &r, hbr);
3267                 }
3268                 if (bm.bmHeight < r.bottom)
3269                 {
3270                     r.left = 0;
3271                     r.top = bm.bmHeight;
3272                     FillRect(hdc, &r, hbr);
3273                 }
3274                 DeleteObject(hbr);
3275             }
3276
3277             /* Draw the header itself. */
3278             BitBlt(hdc, 0, 0,
3279                    bm.bmWidth, min(bm.bmHeight, rzone.bottom),
3280                    hdcSrc, 0, 0, SRCCOPY);
3281         }
3282         else
3283         {
3284             int margin;
3285             hbr = GetSysColorBrush(COLOR_WINDOW);
3286             FillRect(hdc, &rzone, hbr);
3287
3288             /* Draw the header bitmap. It's always centered like a
3289              * common 49 x 49 bitmap. */
3290             margin = (rzone.bottom - 49) / 2;
3291             BitBlt(hdc, rzone.right - 49 - margin, margin,
3292                    min(bm.bmWidth, 49), min(bm.bmHeight, 49),
3293                    hdcSrc, 0, 0, SRCCOPY);
3294
3295             /* NOTE: Native COMCTL32 draws a white stripe over the bitmap
3296              * if its height is smaller than 49 pixels. Because the reason
3297              * for this bug is unknown the current code doesn't try to
3298              * replicate it. */
3299         }
3300
3301         clrOld = SetTextColor (hdc, 0x00000000);
3302         oldBkMode = SetBkMode (hdc, TRANSPARENT); 
3303
3304         if (ppshpage->dwFlags & PSP_USEHEADERTITLE) {
3305             SetRect(&r, 20, 10, 0, 0);
3306             if (HIWORD(ppshpage->pszHeaderTitle))
3307                 DrawTextW(hdc, ppshpage->pszHeaderTitle, -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
3308             else
3309             {
3310                 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderTitle,
3311                                       szBuffer, 256);
3312                 if (nLength != 0)
3313                 {
3314                     DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP);
3315                 }
3316             }
3317         }
3318
3319         if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) {
3320             SelectObject(hdc, psInfo->hFont);
3321             SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom);
3322             if (HIWORD(ppshpage->pszHeaderTitle))
3323                 DrawTextW(hdc, ppshpage->pszHeaderSubTitle, -1, &r, DT_LEFT | DT_WORDBREAK);
3324             else
3325             {
3326                 nLength = LoadStringW(ppshpage->hInstance, (UINT_PTR)ppshpage->pszHeaderSubTitle,
3327                                       szBuffer, 256);
3328                 if (nLength != 0)
3329                 {
3330                     DrawTextW(hdc, szBuffer, nLength, &r, DT_LEFT | DT_WORDBREAK);
3331                 }
3332             }
3333         }
3334
3335         offsety = rzone.bottom + 2;
3336
3337         SetTextColor(hdc, clrOld);
3338         SetBkMode(hdc, oldBkMode);
3339         SelectObject(hdc, hOldFont);
3340         SelectObject(hdcSrc, hbmp);
3341     }
3342
3343     if ( (ppshpage->dwFlags & PSP_HIDEHEADER) &&
3344          (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
3345          (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) 
3346     {
3347         HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE);          
3348
3349         GetClientRect(hwndLine, &r);
3350         MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2);
3351
3352         rzone.left = 0;
3353         rzone.top = 0;
3354         rzone.right = r.right;
3355         rzone.bottom = r.top - 1;
3356
3357         hbr = GetSysColorBrush(COLOR_WINDOW);
3358         FillRect(hdc, &rzone, hbr);
3359
3360         GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), (LPVOID)&bm);
3361         hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark);
3362
3363         /* The watermark is truncated to a width of 164 pixels */
3364         r.right = min(r.right, 164);
3365         BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right),
3366                min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY);
3367
3368         /* If the bitmap is not big enough, fill the remaining area
3369            with the color of pixel (0,0) of bitmap - see MSDN */
3370         if (r.top > bm.bmHeight) {
3371             r.bottom = r.top - 1;
3372             r.top = bm.bmHeight;
3373             r.left = 0;
3374             r.right = bm.bmWidth;
3375             hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0));
3376             FillRect(hdc, &r, hbr);
3377             DeleteObject(hbr);
3378         }
3379
3380         SelectObject(hdcSrc, hbmp);         
3381     }
3382
3383     if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) 
3384         SelectPalette(hdc, hOldPal, FALSE);
3385
3386     DeleteDC(hdcSrc);
3387
3388     if (!hdcParam) EndPaint(hwnd, &ps);
3389
3390     return 0;
3391 }
3392
3393 /******************************************************************************
3394  *            PROPSHEET_DialogProc
3395  */
3396 static INT_PTR CALLBACK
3397 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
3398 {
3399   TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n",
3400         hwnd, uMsg, wParam, lParam);
3401
3402   switch (uMsg)
3403   {
3404     case WM_INITDIALOG:
3405     {
3406       PropSheetInfo* psInfo = (PropSheetInfo*) lParam;
3407       WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR));
3408       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
3409       LPCPROPSHEETPAGEW ppshpage;
3410       int idx;
3411       LOGFONTW logFont;
3412
3413       /* Using PropSheetInfoStr to store extra data doesn't match the native
3414        * common control: native uses TCM_[GS]ETITEM
3415        */
3416       SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo);
3417
3418       /*
3419        * psInfo->hwnd is not being used by WINE code - it exists
3420        * for compatibility with "real" Windoze. The same about
3421        * SetWindowLongPtr - WINE is only using the PropSheetInfoStr
3422        * property.
3423        */
3424       psInfo->hwnd = hwnd;
3425       SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo);
3426
3427       /* set up the Next and Back buttons by default */
3428       PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT);
3429
3430       /* Set up fonts */
3431       SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0);
3432       psInfo->hFont = CreateFontIndirectW (&logFont);
3433       logFont.lfWeight = FW_BOLD;
3434       psInfo->hFontBold = CreateFontIndirectW (&logFont);
3435       
3436       /*
3437        * Small icon in the title bar.
3438        */
3439       if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) ||
3440           (psInfo->ppshheader.dwFlags & PSH_USEHICON))
3441       {
3442         HICON hIcon;
3443         int icon_cx = GetSystemMetrics(SM_CXSMICON);
3444         int icon_cy = GetSystemMetrics(SM_CYSMICON);
3445
3446         if (psInfo->ppshheader.dwFlags & PSH_USEICONID)
3447           hIcon = LoadImageW(psInfo->ppshheader.hInstance,
3448                              psInfo->ppshheader.u.pszIcon,
3449                              IMAGE_ICON,
3450                              icon_cx, icon_cy,
3451                              LR_DEFAULTCOLOR);
3452         else
3453           hIcon = psInfo->ppshheader.u.hIcon;
3454
3455         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon);
3456       }
3457
3458       if (psInfo->ppshheader.dwFlags & PSH_USEHICON)
3459         SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon);
3460
3461       psInfo->strPropertiesFor = strCaption;
3462
3463       GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH);
3464
3465       PROPSHEET_CreateTabControl(hwnd, psInfo);
3466
3467       PROPSHEET_LoadWizardBitmaps(psInfo);
3468
3469       if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
3470       {
3471         ShowWindow(hwndTabCtrl, SW_HIDE);
3472         PROPSHEET_AdjustSizeWizard(hwnd, psInfo);
3473         PROPSHEET_AdjustButtonsWizard(hwnd, psInfo);
3474       }
3475       else
3476       {
3477         if (PROPSHEET_SizeMismatch(hwnd, psInfo))
3478         {
3479           PROPSHEET_AdjustSize(hwnd, psInfo);
3480           PROPSHEET_AdjustButtons(hwnd, psInfo);
3481         }
3482       }
3483
3484       if (!HIWORD(psInfo->ppshheader.pszCaption) &&
3485               psInfo->ppshheader.hInstance)
3486       {
3487          WCHAR szText[256];
3488
3489          if (LoadStringW(psInfo->ppshheader.hInstance,
3490                          (UINT_PTR)psInfo->ppshheader.pszCaption, szText, 255))
3491             PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText);
3492       }
3493       else
3494       {
3495          PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags,
3496                          psInfo->ppshheader.pszCaption);
3497       }
3498
3499
3500       if (psInfo->useCallback)
3501              (*(psInfo->ppshheader.pfnCallback))(hwnd,
3502                                               PSCB_INITIALIZED, (LPARAM)0);
3503
3504       idx = psInfo->active_page;
3505       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage;
3506       psInfo->active_page = -1;
3507
3508       PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage);
3509
3510       /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD,
3511        * as some programs call TCM_GETCURSEL to get the current selection
3512        * from which to switch to the next page */
3513       SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0);
3514
3515       return TRUE;
3516     }
3517
3518     case WM_PRINTCLIENT:
3519     case WM_PAINT:
3520       PROPSHEET_Paint(hwnd, (HDC)wParam);
3521       return TRUE;
3522
3523     case WM_DESTROY:
3524       PROPSHEET_CleanUp(hwnd);
3525       return TRUE;
3526
3527     case WM_CLOSE:
3528       PROPSHEET_Cancel(hwnd, 1);
3529       return FALSE; /* let DefDlgProc post us WM_COMMAND/IDCANCEL */
3530
3531     case WM_COMMAND:
3532       if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam)))
3533       {
3534           PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr);
3535
3536           if (!psInfo)
3537               return FALSE;
3538
3539           /* No default handler, forward notification to active page */
3540           if (psInfo->activeValid && psInfo->active_page != -1)
3541           {
3542              HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
3543              SendMessageW(hwndPage, WM_COMMAND, wParam, lParam);
3544           }
3545       }
3546       return TRUE;
3547
3548     case WM_NOTIFY:
3549     {
3550       NMHDR* pnmh = (LPNMHDR) lParam;
3551
3552       if (pnmh->code == TCN_SELCHANGE)
3553       {
3554         int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
3555         PROPSHEET_SetCurSel(hwnd, index, 1, 0);
3556       }
3557
3558       if(pnmh->code == TCN_SELCHANGING)
3559       {
3560         BOOL bRet = PROPSHEET_CanSetCurSel(hwnd);
3561         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet);
3562         return TRUE;
3563       }
3564
3565       return FALSE;
3566     }
3567   
3568     case WM_SYSCOLORCHANGE:
3569       COMCTL32_RefreshSysColors();
3570       return FALSE;
3571
3572     case PSM_GETCURRENTPAGEHWND:
3573     {
3574       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3575                                                         PropSheetInfoStr);
3576       HWND hwndPage = 0;
3577
3578       if (!psInfo)
3579         return FALSE;
3580
3581       if (psInfo->activeValid && psInfo->active_page != -1)
3582         hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
3583
3584       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage);
3585
3586       return TRUE;
3587     }
3588
3589     case PSM_CHANGED:
3590       PROPSHEET_Changed(hwnd, (HWND)wParam);
3591       return TRUE;
3592
3593     case PSM_UNCHANGED:
3594       PROPSHEET_UnChanged(hwnd, (HWND)wParam);
3595       return TRUE;
3596
3597     case PSM_GETTABCONTROL:
3598     {
3599       HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL);
3600
3601       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl);
3602
3603       return TRUE;
3604     }
3605
3606     case PSM_SETCURSEL:
3607     {
3608       BOOL msgResult;
3609
3610       msgResult = PROPSHEET_CanSetCurSel(hwnd);
3611       if(msgResult != FALSE)
3612       {
3613         msgResult = PROPSHEET_SetCurSel(hwnd,
3614                                        (int)wParam,
3615                                        1,
3616                                        (HPROPSHEETPAGE)lParam);
3617       }
3618
3619       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3620
3621       return TRUE;
3622     }
3623
3624     case PSM_CANCELTOCLOSE:
3625     {
3626       WCHAR buf[MAX_BUTTONTEXT_LENGTH];
3627       HWND hwndOK = GetDlgItem(hwnd, IDOK);
3628       HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL);
3629
3630       EnableWindow(hwndCancel, FALSE);
3631       if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf)))
3632          SetWindowTextW(hwndOK, buf);
3633
3634       return FALSE;
3635     }
3636
3637     case PSM_RESTARTWINDOWS:
3638     {
3639       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3640                                                         PropSheetInfoStr);
3641
3642       if (!psInfo)
3643         return FALSE;
3644
3645       /* reboot system takes precedence over restart windows */
3646       if (psInfo->result != ID_PSREBOOTSYSTEM)
3647           psInfo->result = ID_PSRESTARTWINDOWS;
3648
3649       return TRUE;
3650     }
3651
3652     case PSM_REBOOTSYSTEM:
3653     {
3654       PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd,
3655                                                         PropSheetInfoStr);
3656
3657       if (!psInfo)
3658         return FALSE;
3659
3660       psInfo->result = ID_PSREBOOTSYSTEM;
3661
3662       return TRUE;
3663     }
3664
3665     case PSM_SETTITLEA:
3666       PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam);
3667       return TRUE;
3668
3669     case PSM_SETTITLEW:
3670       PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam);
3671       return TRUE;
3672
3673     case PSM_APPLY:
3674     {
3675       BOOL msgResult = PROPSHEET_Apply(hwnd, 0);
3676
3677       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3678
3679       return TRUE;
3680     }
3681
3682     case PSM_QUERYSIBLINGS:
3683     {
3684       LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam);
3685
3686       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3687
3688       return TRUE;
3689     }
3690
3691     case PSM_ADDPAGE:
3692     {
3693       /*
3694        * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have
3695        *       a return value. This is not true. PSM_ADDPAGE returns TRUE
3696        *       on success or FALSE otherwise, as specified on MSDN Online.
3697        *       Also see the MFC code for
3698        *       CPropertySheet::AddPage(CPropertyPage* pPage).
3699        */
3700
3701       BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam);
3702
3703       SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3704
3705       return TRUE;
3706     }
3707
3708     case PSM_REMOVEPAGE:
3709       PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam);
3710       return TRUE;
3711
3712     case PSM_ISDIALOGMESSAGE:
3713     {
3714        BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam);
3715        SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3716        return TRUE;
3717     }
3718
3719     case PSM_PRESSBUTTON:
3720       PROPSHEET_PressButton(hwnd, (int)wParam);
3721       return TRUE;
3722
3723     case PSM_SETFINISHTEXTA:
3724       PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam);
3725       return TRUE;
3726
3727     case PSM_SETWIZBUTTONS:
3728       PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam);
3729       return TRUE;
3730
3731     case PSM_SETCURSELID:
3732         PROPSHEET_SetCurSelId(hwnd, (int)lParam);
3733         return TRUE;
3734
3735     case PSM_SETFINISHTEXTW:
3736         PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam);
3737         return FALSE;
3738
3739     case PSM_INSERTPAGE:
3740     {
3741         BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam);
3742         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3743         return TRUE;
3744     }
3745
3746     case PSM_SETHEADERTITLEW:
3747         PROPSHEET_SetHeaderTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
3748         return TRUE;
3749
3750     case PSM_SETHEADERTITLEA:
3751         PROPSHEET_SetHeaderTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
3752         return TRUE;
3753
3754     case PSM_SETHEADERSUBTITLEW:
3755         PROPSHEET_SetHeaderSubTitleW(hwnd, (int)wParam, (LPCWSTR)lParam);
3756         return TRUE;
3757
3758     case PSM_SETHEADERSUBTITLEA:
3759         PROPSHEET_SetHeaderSubTitleA(hwnd, (int)wParam, (LPCSTR)lParam);
3760         return TRUE;
3761
3762     case PSM_HWNDTOINDEX:
3763     {
3764         LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam);
3765         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3766         return TRUE;
3767     }
3768
3769     case PSM_INDEXTOHWND:
3770     {
3771         LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam);
3772         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3773         return TRUE;
3774     }
3775
3776     case PSM_PAGETOINDEX:
3777     {
3778         LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam);
3779         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3780         return TRUE;
3781     }
3782
3783     case PSM_INDEXTOPAGE:
3784     {
3785         LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam);
3786         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3787         return TRUE;
3788     }
3789
3790     case PSM_IDTOINDEX:
3791     {
3792         LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam);
3793         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3794         return TRUE;
3795     }
3796
3797     case PSM_INDEXTOID:
3798     {
3799         LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam);
3800         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3801         return TRUE;
3802     }
3803
3804     case PSM_GETRESULT:
3805     {
3806         LRESULT msgResult = PROPSHEET_GetResult(hwnd);
3807         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3808         return TRUE;
3809     }
3810
3811     case PSM_RECALCPAGESIZES:
3812     {
3813         LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd);
3814         SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult);
3815         return TRUE;
3816     }
3817
3818     default:
3819       return FALSE;
3820   }
3821 }