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