comctl32: Fix return value of PropertySheet() for modal propsheets.
[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_GETRESULT
36  *     o PSM_INSERTPAGE
37  *     o PSM_RECALCPAGESIZES
38  *     o PSM_SETHEADERSUBTITLE
39  *     o PSM_SETHEADERTITLE
40  *     o WM_HELP
41  *     o WM_CONTEXTMENU
42  *   - Notifications:
43  *     o PSN_GETOBJECT
44  *     o PSN_QUERYINITIALFOCUS
45  *     o PSN_TRANSLATEACCELERATOR
46  *   - Styles:
47  *     o PSH_RTLREADING
48  *     o PSH_STRETCHWATERMARK
49  *     o PSH_USEPAGELANG
50  *     o PSH_USEPSTARTPAGE
51  *   - Page styles:
52  *     o PSP_USEFUSIONCONTEXT
53  *     o PSP_USEREFPARENT
54  */
55
56 #include <stdarg.h>
57 #include <string.h>
58
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "wingdi.h"
64 #include "winuser.h"
65 #include "winnls.h"
66 #include "commctrl.h"
67 #include "prsht.h"
68 #include "comctl32.h"
69 #include "uxtheme.h"
70
71 #include "wine/debug.h"
72 #include "wine/unicode.h"
73
74 /******************************************************************************
75  * Data structures
76  */
77 #include "pshpack2.h"
78
79 typedef struct
80 {
81   WORD dlgVer;
82   WORD signature;
83   DWORD helpID;
84   DWORD exStyle;
85   DWORD style;
86 } MyDLGTEMPLATEEX;
87
88 typedef struct
89 {
90   DWORD helpid;
91   DWORD exStyle;
92   DWORD style;
93   short x;
94   short y;
95   short cx;
96   short cy;
97   DWORD id;
98 } MyDLGITEMTEMPLATEEX;
99 #include "poppack.h"
100
101 typedef struct tagPropPageInfo
102 {
103   HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */
104   HWND hwndPage;
105   BOOL isDirty;
106   LPCWSTR pszText;
107   BOOL hasHelp;
108   BOOL useCallback;
109   BOOL hasIcon;
110 } PropPageInfo;
111
112 typedef struct tagPropSheetInfo
113 {
114   HWND hwnd;
115   PROPSHEETHEADERW ppshheader;
116   BOOL unicode;
117   LPWSTR strPropertiesFor;
118   int nPages;
119   int active_page;
120   BOOL isModeless;
121   BOOL hasHelp;
122   BOOL hasApply;
123   BOOL hasFinish;
124   BOOL useCallback;
125   BOOL activeValid;
126   PropPageInfo* proppage;
127   HFONT hFont;
128   HFONT hFontBold;
129   int width;
130   int height;
131   HIMAGELIST hImageList;
132   BOOL ended;
133   INT result;
134 } PropSheetInfo;
135
136 typedef struct
137 {
138   int x;
139   int y;
140 } PADDING_INFO;
141
142 /******************************************************************************
143  * Defines and global variables
144  */
145
146 static const WCHAR PropSheetInfoStr[] =
147     {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 };
148
149 #define PSP_INTERNAL_UNICODE 0x80000000
150
151 #define MAX_CAPTION_LENGTH 255
152 #define MAX_TABTEXT_LENGTH 255
153 #define MAX_BUTTONTEXT_LENGTH 64
154
155 #define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)
156
157 /* Wizard metrics specified in DLUs */
158 #define WIZARD_PADDING 7
159 #define WIZARD_HEADER_HEIGHT 36
160                                 
161 /******************************************************************************
162  * Prototypes
163  */
164 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg);
165 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText);
166 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg);
167 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
168                                 int index,
169                                 int skipdir,
170                                 HPROPSHEETPAGE hpage);
171 static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo);
172 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo);
173 static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID);
174
175 static INT_PTR CALLBACK
176 PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
177
178 WINE_DEFAULT_DEBUG_CHANNEL(propsheet);
179
180 #define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");}
181 /******************************************************************************
182  *            PROPSHEET_UnImplementedFlags
183  *
184  * Document use of flags we don't implement yet.
185  */
186 static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags)
187 {
188     CHAR string[256];
189
190     string[0] = '\0';
191
192   /*
193    * unhandled header flags:
194    *  PSH_RTLREADING         0x00000800
195    *  PSH_STRETCHWATERMARK   0x00040000
196    *  PSH_USEPAGELANG        0x00200000
197    */
198
199     add_flag(PSH_RTLREADING);
200     add_flag(PSH_STRETCHWATERMARK);
201     add_flag(PSH_USEPAGELANG);
202     if (string[0] != '\0')
203         FIXME("%s\n", string);
204 }
205 #undef add_flag
206
207 /******************************************************************************
208  *            PROPSHEET_GetPageRect
209  *
210  * Retrieve rect from tab control and map into the dialog for SetWindowPos
211  */
212 static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg,
213                                   RECT *rc, LPCPROPSHEETPAGEW ppshpage)
214 {
215     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) {     
216         HWND hwndChild;
217         RECT r;
218
219         if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
220              (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
221              !(ppshpage->dwFlags & PSP_HIDEHEADER)) ||
222             (psInfo->ppshheader.dwFlags & PSH_WIZARD))
223         {
224             rc->left = rc->top = WIZARD_PADDING;
225         }
226         else
227         {
228             rc->left = rc->top = 0;
229         }
230         rc->right = psInfo->width - rc->left;
231         rc->bottom = psInfo->height - rc->top;
232         MapDialogRect(hwndDlg, rc);
233
234         if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
235             (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
236             !(ppshpage->dwFlags & PSP_HIDEHEADER))
237         {
238             hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
239             GetClientRect(hwndChild, &r);
240             MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2);
241             rc->top += r.bottom + 1;
242         }
243     } else {
244         HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
245         GetClientRect(hwndTabCtrl, rc);
246         SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc);
247         MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2);
248     }
249 }
250
251 /******************************************************************************
252  *            PROPSHEET_FindPageByResId
253  *
254  * Find page index corresponding to page resource id.
255  */
256 static INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId)
257 {
258    INT i;
259
260    for (i = 0; i < psInfo->nPages; i++)
261    {
262       LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage;
263
264       /* Fixme: if resource ID is a string shall we use strcmp ??? */
265       if (lppsp->u.pszTemplate == (LPVOID)resId)
266          break;
267    }
268
269    return i;
270 }
271
272 /******************************************************************************
273  *            PROPSHEET_AtoW
274  *
275  * Convert ASCII to Unicode since all data is saved as Unicode.
276  */
277 static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr)
278 {
279     INT len;
280
281     TRACE("<%s>\n", frstr);
282     len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0);
283     *tostr = Alloc(len * sizeof(WCHAR));
284     MultiByteToWideChar(CP_ACP, 0, frstr, -1, (LPWSTR)*tostr, len);
285 }
286
287 /******************************************************************************
288  *            PROPSHEET_CollectSheetInfoA
289  *
290  * Collect relevant data.
291  */
292 static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh,
293                                        PropSheetInfo * psInfo)
294 {
295   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA));
296   DWORD dwFlags = lppsh->dwFlags;
297
298   psInfo->hasHelp = dwFlags & PSH_HASHELP;
299   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
300   psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
301   psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback);
302   psInfo->isModeless = dwFlags & PSH_MODELESS;
303
304   memcpy(&psInfo->ppshheader,lppsh,dwSize);
305   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",
306         lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance,
307         debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
308
309   PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
310
311   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
312      psInfo->ppshheader.pszCaption = NULL;
313   else
314   {
315      if (HIWORD(lppsh->pszCaption))
316      {
317         int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0);
318         psInfo->ppshheader.pszCaption = Alloc( len*sizeof (WCHAR) );
319         MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len);
320      }
321   }
322   psInfo->nPages = lppsh->nPages;
323
324   if (dwFlags & PSH_USEPSTARTPAGE)
325   {
326     TRACE("PSH_USEPSTARTPAGE is on\n");
327     psInfo->active_page = 0;
328   }
329   else
330     psInfo->active_page = lppsh->u2.nStartPage;
331
332   if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
333      psInfo->active_page = 0;
334
335   psInfo->result = 0;
336   psInfo->hImageList = 0;
337   psInfo->activeValid = FALSE;
338
339   return TRUE;
340 }
341
342 /******************************************************************************
343  *            PROPSHEET_CollectSheetInfoW
344  *
345  * Collect relevant data.
346  */
347 static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh,
348                                        PropSheetInfo * psInfo)
349 {
350   DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW));
351   DWORD dwFlags = lppsh->dwFlags;
352
353   psInfo->hasHelp = dwFlags & PSH_HASHELP;
354   psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW);
355   psInfo->hasFinish = dwFlags & PSH_WIZARDHASFINISH;
356   psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback);
357   psInfo->isModeless = dwFlags & PSH_MODELESS;
358
359   memcpy(&psInfo->ppshheader,lppsh,dwSize);
360   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",
361       lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback);
362
363   PROPSHEET_UnImplementedFlags(lppsh->dwFlags);
364
365   if (lppsh->dwFlags & INTRNL_ANY_WIZARD)
366      psInfo->ppshheader.pszCaption = NULL;
367   else
368   {
369      if (HIWORD(lppsh->pszCaption))
370      {
371         int len = strlenW(lppsh->pszCaption);
372         psInfo->ppshheader.pszCaption = Alloc( (len+1)*sizeof(WCHAR) );
373         strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption );
374      }
375   }
376   psInfo->nPages = lppsh->nPages;
377
378   if (dwFlags & PSH_USEPSTARTPAGE)
379   {
380     TRACE("PSH_USEPSTARTPAGE is on\n");
381     psInfo->active_page = 0;
382   }
383   else
384     psInfo->active_page = lppsh->u2.nStartPage;
385
386   if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages)
387      psInfo->active_page = 0;
388
389   psInfo->result = 0;
390   psInfo->hImageList = 0;
391   psInfo->activeValid = FALSE;
392
393   return TRUE;
394 }
395
396 /******************************************************************************
397  *            PROPSHEET_CollectPageInfo
398  *
399  * Collect property sheet data.
400  * With code taken from DIALOG_ParseTemplate32.
401  */
402 static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp,
403                                PropSheetInfo * psInfo,
404                                int index)
405 {
406   DLGTEMPLATE* pTemplate;
407   const WORD*  p;
408   DWORD dwFlags;
409   int width, height;
410
411   if (!lppsp)
412     return FALSE;
413
414   TRACE("\n");
415   psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp;
416   psInfo->proppage[index].hwndPage = 0;
417   psInfo->proppage[index].isDirty = FALSE;
418
419   /*
420    * Process property page flags.
421    */
422   dwFlags = lppsp->dwFlags;
423   psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback);
424   psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP;
425   psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID);
426
427   /* as soon as we have a page with the help flag, set the sheet flag on */
428   if (psInfo->proppage[index].hasHelp)
429     psInfo->hasHelp = TRUE;
430
431   /*
432    * Process page template.
433    */
434   if (dwFlags & PSP_DLGINDIRECT)
435     pTemplate = (DLGTEMPLATE*)lppsp->u.pResource;
436   else if(dwFlags & PSP_INTERNAL_UNICODE )
437   {
438     HRSRC hResource = FindResourceW(lppsp->hInstance,
439                                     lppsp->u.pszTemplate,
440                                     (LPWSTR)RT_DIALOG);
441     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
442                                      hResource);
443     pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
444   }
445   else
446   {
447     HRSRC hResource = FindResourceA(lppsp->hInstance,
448                                     (LPCSTR)lppsp->u.pszTemplate,
449                                     (LPSTR)RT_DIALOG);
450     HGLOBAL hTemplate = LoadResource(lppsp->hInstance,
451                                      hResource);
452     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
453   }
454
455   /*
456    * Extract the size of the page and the caption.
457    */
458   if (!pTemplate)
459       return FALSE;
460
461   p = (const WORD *)pTemplate;
462
463   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
464   {
465     /* DLGTEMPLATEEX (not defined in any std. header file) */
466
467     p++;       /* dlgVer    */
468     p++;       /* signature */
469     p += 2;    /* help ID   */
470     p += 2;    /* ext style */
471     p += 2;    /* style     */
472   }
473   else
474   {
475     /* DLGTEMPLATE */
476
477     p += 2;    /* style     */
478     p += 2;    /* ext style */
479   }
480
481   p++;    /* nb items */
482   p++;    /*   x      */
483   p++;    /*   y      */
484   width  = (WORD)*p; p++;
485   height = (WORD)*p; p++;
486
487   /* Special calculation for interior wizard pages so the largest page is
488    * calculated correctly. We need to add all the padding and space occupied
489    * by the header so the width and height sums up to the whole wizard client
490    * area. */
491   if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
492       (psInfo->ppshheader.dwFlags & PSH_HEADER) &&
493       !(dwFlags & PSP_HIDEHEADER))
494   {
495       height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT;
496       width += 2 * WIZARD_PADDING;
497   }
498   if (psInfo->ppshheader.dwFlags & PSH_WIZARD)
499   {
500       height += 2 * WIZARD_PADDING;
501       width += 2 * WIZARD_PADDING;
502   }
503
504   /* remember the largest width and height */
505   if (width > psInfo->width)
506     psInfo->width = width;
507
508   if (height > psInfo->height)
509     psInfo->height = height;
510
511   /* menu */
512   switch ((WORD)*p)
513   {
514     case 0x0000:
515       p++;
516       break;
517     case 0xffff:
518       p += 2;
519       break;
520     default:
521       p += lstrlenW( (LPCWSTR)p ) + 1;
522       break;
523   }
524
525   /* class */
526   switch ((WORD)*p)
527   {
528     case 0x0000:
529       p++;
530       break;
531     case 0xffff:
532       p += 2;
533       break;
534     default:
535       p += lstrlenW( (LPCWSTR)p ) + 1;
536       break;
537   }
538
539   /* Extract the caption */
540   psInfo->proppage[index].pszText = (LPCWSTR)p;
541   TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p));
542   p += lstrlenW((LPCWSTR)p) + 1;
543
544   if (dwFlags & PSP_USETITLE)
545   {
546     WCHAR szTitle[256];
547     const WCHAR *pTitle;
548     static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 };
549     int len;
550
551     if ( !HIWORD( lppsp->pszTitle ) )
552     {
553       if (!LoadStringW( lppsp->hInstance, (DWORD_PTR)lppsp->pszTitle,szTitle,sizeof(szTitle) ))
554       {
555         pTitle = pszNull;
556         FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle));
557       }
558       else
559         pTitle = szTitle;
560     }
561     else
562       pTitle = lppsp->pszTitle;
563
564     len = strlenW(pTitle);
565     psInfo->proppage[index].pszText = Alloc( (len+1)*sizeof (WCHAR) );
566     strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle);
567   }
568
569   /*
570    * Build the image list for icons
571    */
572   if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID))
573   {
574     HICON hIcon;
575     int icon_cx = GetSystemMetrics(SM_CXSMICON);
576     int icon_cy = GetSystemMetrics(SM_CYSMICON);
577
578     if (dwFlags & PSP_USEICONID)
579       hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON,
580                          icon_cx, icon_cy, LR_DEFAULTCOLOR);
581     else
582       hIcon = lppsp->u2.hIcon;
583
584     if ( hIcon )
585     {
586       if (psInfo->hImageList == 0 )
587         psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1);
588
589       ImageList_AddIcon(psInfo->hImageList, hIcon);
590     }
591
592   }
593
594   return TRUE;
595 }
596
597 /******************************************************************************
598  *            PROPSHEET_CreateDialog
599  *
600  * Creates the actual property sheet.
601  */
602 static INT_PTR PROPSHEET_CreateDialog(PropSheetInfo* psInfo)
603 {
604   LRESULT ret;
605   LPCVOID template;
606   LPVOID temp = 0;
607   HRSRC hRes;
608   DWORD resSize;
609   WORD resID = IDD_PROPSHEET;
610
611   TRACE("\n");
612   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
613     resID = IDD_WIZARD;
614
615   if( psInfo->unicode )
616   {
617     if(!(hRes = FindResourceW(COMCTL32_hModule,
618                             MAKEINTRESOURCEW(resID),
619                             (LPWSTR)RT_DIALOG)))
620       return -1;
621   }
622   else
623   {
624     if(!(hRes = FindResourceA(COMCTL32_hModule,
625                             MAKEINTRESOURCEA(resID),
626                             (LPSTR)RT_DIALOG)))
627       return -1;
628   }
629
630   if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes)))
631     return -1;
632
633   /*
634    * Make a copy of the dialog template.
635    */
636   resSize = SizeofResource(COMCTL32_hModule, hRes);
637
638   temp = Alloc(resSize);
639
640   if (!temp)
641     return -1;
642
643   memcpy(temp, template, resSize);
644
645   if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP)
646   {
647     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
648       ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP;
649     else
650       ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP;
651   }
652   if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) &&
653       (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP))
654   {
655     if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF)
656       ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP;
657     else
658       ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP;
659   }
660
661   if (psInfo->useCallback)
662     (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp);
663
664   /* NOTE: MSDN states "Returns a positive value if successful, or -1
665    * otherwise for modal property sheets.", but this is wrong. The
666    * actual return value is either TRUE (success), FALSE (cancel) or
667    * -1 (error). */
668   if( psInfo->unicode )
669   {
670     ret = (INT_PTR)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance,
671                                           (LPDLGTEMPLATEW) temp,
672                                           psInfo->ppshheader.hwndParent,
673                                           PROPSHEET_DialogProc,
674                                           (LPARAM)psInfo);
675     if ( !ret ) ret = -1;
676   }
677   else
678   {
679     ret = (INT_PTR)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance,
680                                           (LPDLGTEMPLATEA) temp,
681                                           psInfo->ppshheader.hwndParent,
682                                           PROPSHEET_DialogProc,
683                                           (LPARAM)psInfo);
684     if ( !ret ) ret = -1;
685   }
686
687   Free(temp);
688
689   return ret;
690 }
691
692 /******************************************************************************
693  *            PROPSHEET_SizeMismatch
694  *
695  *     Verify that the tab control and the "largest" property sheet page dlg. template
696  *     match in size.
697  */
698 static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo)
699 {
700   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
701   RECT rcOrigTab, rcPage;
702
703   /*
704    * Original tab size.
705    */
706   GetClientRect(hwndTabCtrl, &rcOrigTab);
707   TRACE("orig tab %d %d %d %d\n", rcOrigTab.left, rcOrigTab.top,
708         rcOrigTab.right, rcOrigTab.bottom);
709
710   /*
711    * Biggest page size.
712    */
713   rcPage.left   = 0;
714   rcPage.top    = 0;
715   rcPage.right  = psInfo->width;
716   rcPage.bottom = psInfo->height;
717
718   MapDialogRect(hwndDlg, &rcPage);
719   TRACE("biggest page %d %d %d %d\n", rcPage.left, rcPage.top,
720         rcPage.right, rcPage.bottom);
721
722   if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) )
723     return TRUE;
724   if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) )
725     return TRUE;
726
727   return FALSE;
728 }
729
730 /******************************************************************************
731  *            PROPSHEET_AdjustSize
732  *
733  * Resizes the property sheet and the tab control to fit the largest page.
734  */
735 static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo)
736 {
737   HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
738   HWND hwndButton = GetDlgItem(hwndDlg, IDOK);
739   RECT rc,tabRect;
740   int tabOffsetX, tabOffsetY, buttonHeight;
741   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg);
742   RECT units;
743
744   /* Get the height of buttons */
745   GetClientRect(hwndButton, &rc);
746   buttonHeight = rc.bottom;
747
748   /*
749    * Biggest page size.
750    */
751   rc.left   = 0;
752   rc.top    = 0;
753   rc.right  = psInfo->width;
754   rc.bottom = psInfo->height;
755
756   MapDialogRect(hwndDlg, &rc);
757
758   /* retrieve the dialog units */
759   units.left = units.right = 4;
760   units.top = units.bottom = 8;
761   MapDialogRect(hwndDlg, &units);
762
763   /*
764    * Resize the tab control.
765    */
766   GetClientRect(hwndTabCtrl,&tabRect);
767
768   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect);
769
770   if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top))
771   {
772       rc.bottom = rc.top + tabRect.bottom - tabRect.top;
773       psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top);
774   }
775
776   if ((rc.right - rc.left) < (tabRect.right - tabRect.left))
777   {
778       rc.right = rc.left + tabRect.right - tabRect.left;
779       psInfo->width  = MulDiv((rc.right - rc.left),4,units.left);
780   }
781
782   SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc);
783
784   tabOffsetX = -(rc.left);
785   tabOffsetY = -(rc.top);
786
787   rc.right -= rc.left;
788   rc.bottom -= rc.top;
789   TRACE("setting tab %p, rc (0,0)-(%d,%d)\n",
790         hwndTabCtrl, rc.right, rc.bottom);
791   SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom,
792                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
793
794   GetClientRect(hwndTabCtrl, &rc);
795
796   TRACE("tab client rc %d %d %d %d\n",
797         rc.left, rc.top, rc.right, rc.bottom);
798
799   rc.right += ((padding.x * 2) + tabOffsetX);
800   rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY);
801
802   /*
803    * Resize the property sheet.
804    */
805   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
806         hwndDlg, rc.right, rc.bottom);
807   SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom,
808                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
809   return TRUE;
810 }
811
812 /******************************************************************************
813  *            PROPSHEET_AdjustSizeWizard
814  *
815  * Resizes the property sheet to fit the largest page.
816  */
817 static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo)
818 {
819   HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
820   RECT rc, lineRect, dialogRect;
821
822   /* Biggest page size */
823   rc.left   = 0;
824   rc.top    = 0;
825   rc.right  = psInfo->width;
826   rc.bottom = psInfo->height;
827   MapDialogRect(hwndDlg, &rc);
828
829   TRACE("Biggest page %d %d %d %d\n", rc.left, rc.top, rc.right, rc.bottom);
830
831   /* Add space for the buttons row */
832   GetWindowRect(hwndLine, &lineRect);
833   MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2);
834   GetClientRect(hwndDlg, &dialogRect);
835   rc.bottom += dialogRect.bottom - lineRect.top - 1;
836
837   /* Convert the client coordinates to window coordinates */
838   AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE);
839
840   /* Resize the property sheet */
841   TRACE("setting dialog %p, rc (0,0)-(%d,%d)\n",
842         hwndDlg, rc.right, rc.bottom);
843   SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
844                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
845
846   return TRUE;
847 }
848
849 /******************************************************************************
850  *            PROPSHEET_AdjustButtons
851  *
852  * Adjusts the buttons' positions.
853  */
854 static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo)
855 {
856   HWND hwndButton = GetDlgItem(hwndParent, IDOK);
857   RECT rcSheet;
858   int x, y;
859   int num_buttons = 2;
860   int buttonWidth, buttonHeight;
861   PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent);
862
863   if (psInfo->hasApply)
864     num_buttons++;
865
866   if (psInfo->hasHelp)
867     num_buttons++;
868
869   /*
870    * Obtain the size of the buttons.
871    */
872   GetClientRect(hwndButton, &rcSheet);
873   buttonWidth = rcSheet.right;
874   buttonHeight = rcSheet.bottom;
875
876   /*
877    * Get the size of the property sheet.
878    */
879   GetClientRect(hwndParent, &rcSheet);
880
881   /*
882    * All buttons will be at this y coordinate.
883    */
884   y = rcSheet.bottom - (padding.y + buttonHeight);
885
886   /*
887    * Position OK button and make it default.
888    */
889   hwndButton = GetDlgItem(hwndParent, IDOK);
890
891   x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons);
892
893   SetWindowPos(hwndButton, 0, x, y, 0, 0,
894                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
895
896   SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0);
897
898
899   /*
900    * Position Cancel button.
901    */
902   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
903
904   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1));
905
906   SetWindowPos(hwndButton, 0, x, y, 0, 0,
907                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
908
909   /*
910    * Position Apply button.
911    */
912   hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON);
913
914   if (psInfo->hasApply)
915   {
916     if (psInfo->hasHelp)
917       x = rcSheet.right - ((padding.x + buttonWidth) * 2);
918     else
919       x = rcSheet.right - (padding.x + buttonWidth);
920
921     SetWindowPos(hwndButton, 0, x, y, 0, 0,
922                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
923
924     EnableWindow(hwndButton, FALSE);
925   }
926   else
927     ShowWindow(hwndButton, SW_HIDE);
928
929   /*
930    * Position Help button.
931    */
932   hwndButton = GetDlgItem(hwndParent, IDHELP);
933
934   if (psInfo->hasHelp)
935   {
936     x = rcSheet.right - (padding.x + buttonWidth);
937
938     SetWindowPos(hwndButton, 0, x, y, 0, 0,
939                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
940   }
941   else
942     ShowWindow(hwndButton, SW_HIDE);
943
944   return TRUE;
945 }
946
947 /******************************************************************************
948  *            PROPSHEET_AdjustButtonsWizard
949  *
950  * Adjusts the buttons' positions.
951  */
952 static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent,
953                                           PropSheetInfo* psInfo)
954 {
955   HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL);
956   HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE);
957   HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER);
958   RECT rcSheet;
959   int x, y;
960   int num_buttons = 3;
961   int buttonWidth, buttonHeight, lineHeight, lineWidth;
962   PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo);
963
964   if (psInfo->hasHelp)
965     num_buttons++;
966   if (psInfo->hasFinish)
967     num_buttons++;
968
969   /*
970    * Obtain the size of the buttons.
971    */
972   GetClientRect(hwndButton, &rcSheet);
973   buttonWidth = rcSheet.right;
974   buttonHeight = rcSheet.bottom;
975
976   GetClientRect(hwndLine, &rcSheet);
977   lineHeight = rcSheet.bottom;
978
979   /*
980    * Get the size of the property sheet.
981    */
982   GetClientRect(hwndParent, &rcSheet);
983
984   /*
985    * All buttons will be at this y coordinate.
986    */
987   y = rcSheet.bottom - (padding.y + buttonHeight);
988   
989   /*
990    * Position the Back button.
991    */
992   hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON);
993
994   x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)) - buttonWidth;
995
996   SetWindowPos(hwndButton, 0, x, y, 0, 0,
997                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
998
999   /*
1000    * Position the Next button.
1001    */
1002   hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON);
1003   
1004   x += buttonWidth;
1005   
1006   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1007                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1008
1009   /*
1010    * Position the Finish button.
1011    */
1012   hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON);
1013   
1014   if (psInfo->hasFinish)
1015     x += padding.x + buttonWidth;
1016
1017   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1018                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1019
1020   if (!psInfo->hasFinish)
1021     ShowWindow(hwndButton, SW_HIDE);
1022
1023   /*
1024    * Position the Cancel button.
1025    */
1026   hwndButton = GetDlgItem(hwndParent, IDCANCEL);
1027
1028   x += padding.x + buttonWidth;
1029
1030   SetWindowPos(hwndButton, 0, x, y, 0, 0,
1031                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1032
1033   /*
1034    * Position Help button.
1035    */
1036   hwndButton = GetDlgItem(hwndParent, IDHELP);
1037
1038   if (psInfo->hasHelp)
1039   {
1040     x += padding.x + buttonWidth;
1041
1042     SetWindowPos(hwndButton, 0, x, y, 0, 0,
1043                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
1044   }
1045   else
1046     ShowWindow(hwndButton, SW_HIDE);
1047
1048   if (psInfo->ppshheader.dwFlags &
1049       (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) 
1050       padding.x = 0;
1051
1052   /*
1053    * Position and resize the sunken line.
1054    */
1055   x = padding.x;
1056   y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight);
1057
1058   lineWidth = rcSheet.right - (padding.x * 2);
1059   SetWindowPos(hwndLine, 0, x, y, lineWidth, 2,
1060                SWP_NOZORDER | SWP_NOACTIVATE);
1061
1062   /*
1063    * Position and resize the header sunken line.
1064    */
1065   
1066   SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2,
1067                SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
1068   if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)))
1069       ShowWindow(hwndLineHeader, SW_HIDE);
1070
1071   return TRUE;
1072 }
1073
1074 /******************************************************************************
1075  *            PROPSHEET_GetPaddingInfo
1076  *
1077  * Returns the layout information.
1078  */
1079 static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg)
1080 {
1081   HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1082   RECT rcTab;
1083   POINT tl;
1084   PADDING_INFO padding;
1085
1086   GetWindowRect(hwndTab, &rcTab);
1087
1088   tl.x = rcTab.left;
1089   tl.y = rcTab.top;
1090
1091   ScreenToClient(hwndDlg, &tl);
1092
1093   padding.x = tl.x;
1094   padding.y = tl.y;
1095
1096   return padding;
1097 }
1098
1099 /******************************************************************************
1100  *            PROPSHEET_GetPaddingInfoWizard
1101  *
1102  * Returns the layout information.
1103  * Vertical spacing is the distance between the line and the buttons.
1104  * Do NOT use the Help button to gather padding information when it isn't mapped
1105  * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates
1106  * for it in this case !
1107  * FIXME: I'm not sure about any other coordinate problems with these evil
1108  * buttons. Fix it in case additional problems appear or maybe calculate
1109  * a padding in a completely different way, as this is somewhat messy.
1110  */
1111 static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo*
1112  psInfo)
1113 {
1114   PADDING_INFO padding;
1115   RECT rc;
1116   HWND hwndControl;
1117   INT idButton;
1118   POINT ptButton, ptLine;
1119
1120   TRACE("\n");
1121   if (psInfo->hasHelp)
1122   {
1123         idButton = IDHELP;
1124   }
1125   else
1126   {
1127     if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1128     {
1129         idButton = IDC_NEXT_BUTTON;
1130     }
1131     else
1132     {
1133         /* hopefully this is ok */
1134         idButton = IDCANCEL;
1135     }
1136   }
1137
1138   hwndControl = GetDlgItem(hwndDlg, idButton);
1139   GetWindowRect(hwndControl, &rc);
1140
1141   ptButton.x = rc.left;
1142   ptButton.y = rc.top;
1143
1144   ScreenToClient(hwndDlg, &ptButton);
1145
1146   /* Line */
1147   hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE);
1148   GetWindowRect(hwndControl, &rc);
1149
1150   ptLine.x = rc.left;
1151   ptLine.y = rc.bottom;
1152
1153   ScreenToClient(hwndDlg, &ptLine);
1154
1155   padding.y = ptButton.y - ptLine.y;
1156
1157   if (padding.y < 0)
1158           ERR("padding negative ! Please report this !\n");
1159
1160   /* this is most probably not correct, but the best we have now */
1161   padding.x = padding.y;
1162   return padding;
1163 }
1164
1165 /******************************************************************************
1166  *            PROPSHEET_CreateTabControl
1167  *
1168  * Insert the tabs in the tab control.
1169  */
1170 static BOOL PROPSHEET_CreateTabControl(HWND hwndParent,
1171                                        PropSheetInfo * psInfo)
1172 {
1173   HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);
1174   TCITEMW item;
1175   int i, nTabs;
1176   int iImage = 0;
1177
1178   TRACE("\n");
1179   item.mask = TCIF_TEXT;
1180   item.cchTextMax = MAX_TABTEXT_LENGTH;
1181
1182   nTabs = psInfo->nPages;
1183
1184   /*
1185    * Set the image list for icons.
1186    */
1187   if (psInfo->hImageList)
1188   {
1189     SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
1190   }
1191
1192   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 0, 0);
1193   for (i = 0; i < nTabs; i++)
1194   {
1195     if ( psInfo->proppage[i].hasIcon )
1196     {
1197       item.mask |= TCIF_IMAGE;
1198       item.iImage = iImage++;
1199     }
1200     else
1201     {
1202       item.mask &= ~TCIF_IMAGE;
1203     }
1204
1205     item.pszText = (LPWSTR) psInfo->proppage[i].pszText;
1206     SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item);
1207   }
1208   SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 1, 0);
1209
1210   return TRUE;
1211 }
1212
1213 /******************************************************************************
1214  *            PROPSHEET_WizardSubclassProc
1215  *
1216  * Subclassing window procedure for wizard extrior pages to prevent drawing
1217  * background and so drawing above the watermark.
1218  */
1219 static LRESULT CALLBACK
1220 PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef)
1221 {
1222   switch (uMsg)
1223   {
1224     case WM_ERASEBKGND:
1225       return TRUE;
1226
1227     case WM_CTLCOLORSTATIC:
1228       SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
1229       return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
1230   }
1231
1232   return DefSubclassProc(hwnd, uMsg, wParam, lParam);
1233 }
1234
1235 /*
1236  * Get the size of an in-memory Template
1237  *
1238  *( Based on the code of PROPSHEET_CollectPageInfo)
1239  * See also dialog.c/DIALOG_ParseTemplate32().
1240  */
1241
1242 static UINT GetTemplateSize(DLGTEMPLATE* pTemplate)
1243
1244 {
1245   const WORD*  p = (const WORD *)pTemplate;
1246   BOOL  istemplateex = (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF);
1247   WORD nrofitems;
1248   UINT ret;
1249
1250   if (istemplateex)
1251   {
1252     /* DLGTEMPLATEEX (not defined in any std. header file) */
1253
1254     TRACE("is DLGTEMPLATEEX\n");
1255     p++;       /* dlgVer    */
1256     p++;       /* signature */
1257     p += 2;    /* help ID   */
1258     p += 2;    /* ext style */
1259     p += 2;    /* style     */
1260   }
1261   else
1262   {
1263     /* DLGTEMPLATE */
1264
1265     TRACE("is DLGTEMPLATE\n");
1266     p += 2;    /* style     */
1267     p += 2;    /* ext style */
1268   }
1269
1270   nrofitems =   (WORD)*p; p++;    /* nb items */
1271   p++;    /*   x      */
1272   p++;    /*   y      */
1273   p++;    /*   width  */
1274   p++;    /*   height */
1275
1276   /* menu */
1277   switch ((WORD)*p)
1278   {
1279     case 0x0000:
1280       p++;
1281       break;
1282     case 0xffff:
1283       p += 2;
1284       break;
1285     default:
1286       TRACE("menu %s\n",debugstr_w((LPCWSTR)p));
1287       p += lstrlenW( (LPCWSTR)p ) + 1;
1288       break;
1289   }
1290
1291   /* class */
1292   switch ((WORD)*p)
1293   {
1294     case 0x0000:
1295       p++;
1296       break;
1297     case 0xffff:
1298       p += 2; /* 0xffff plus predefined window class ordinal value */
1299       break;
1300     default:
1301       TRACE("class %s\n",debugstr_w((LPCWSTR)p));
1302       p += lstrlenW( (LPCWSTR)p ) + 1;
1303       break;
1304   }
1305
1306   /* title */
1307   TRACE("title %s\n",debugstr_w((LPCWSTR)p));
1308   p += lstrlenW((LPCWSTR)p) + 1;
1309
1310   /* font, if DS_SETFONT set */
1311   if ((DS_SETFONT & ((istemplateex)?  ((MyDLGTEMPLATEEX*)pTemplate)->style :
1312                      pTemplate->style)))
1313     {
1314       p+=(istemplateex)?3:1;
1315       TRACE("font %s\n",debugstr_w((LPCWSTR)p));
1316       p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */
1317     }
1318
1319   /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data)
1320    * that are following the DLGTEMPLATE(EX) data */
1321   TRACE("%d items\n",nrofitems);
1322   while (nrofitems > 0)
1323     {
1324       p = (WORD*)(((DWORD_PTR)p + 3) & ~3); /* DWORD align */
1325       
1326       /* skip header */
1327       p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD);
1328       
1329       /* check class */
1330       switch ((WORD)*p)
1331         {
1332         case 0x0000:
1333           p++;
1334           break;
1335         case 0xffff:
1336           TRACE("class ordinal 0x%08x\n",*(DWORD*)p);
1337           p += 2;
1338           break;
1339         default:
1340           TRACE("class %s\n",debugstr_w((LPCWSTR)p));
1341           p += lstrlenW( (LPCWSTR)p ) + 1;
1342           break;
1343         }
1344
1345       /* check title text */
1346       switch ((WORD)*p)
1347         {
1348         case 0x0000:
1349           p++;
1350           break;
1351         case 0xffff:
1352           TRACE("text ordinal 0x%08x\n",*(DWORD*)p);
1353           p += 2;
1354           break;
1355         default:
1356           TRACE("text %s\n",debugstr_w((LPCWSTR)p));
1357           p += lstrlenW( (LPCWSTR)p ) + 1;
1358           break;
1359         }
1360       p += *p / sizeof(WORD) + 1;    /* Skip extra data */
1361       --nrofitems;
1362     }
1363   
1364   ret = (p - (WORD*)pTemplate) * sizeof(WORD);
1365   TRACE("%p %p size 0x%08x\n", p, pTemplate, ret);
1366   return ret;
1367 }
1368
1369 /******************************************************************************
1370  *            PROPSHEET_CreatePage
1371  *
1372  * Creates a page.
1373  */
1374 static BOOL PROPSHEET_CreatePage(HWND hwndParent,
1375                                 int index,
1376                                 const PropSheetInfo * psInfo,
1377                                 LPCPROPSHEETPAGEW ppshpage)
1378 {
1379   DLGTEMPLATE* pTemplate;
1380   HWND hwndPage;
1381   DWORD resSize;
1382   LPVOID temp = NULL;
1383
1384   TRACE("index %d\n", index);
1385
1386   if (ppshpage == NULL)
1387   {
1388     return FALSE;
1389   }
1390
1391   if (ppshpage->dwFlags & PSP_DLGINDIRECT)
1392     {
1393       pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource;
1394       resSize = GetTemplateSize(pTemplate);
1395     }
1396   else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
1397   {
1398     HRSRC hResource;
1399     HANDLE hTemplate;
1400
1401     hResource = FindResourceW(ppshpage->hInstance,
1402                                     ppshpage->u.pszTemplate,
1403                                     (LPWSTR)RT_DIALOG);
1404     if(!hResource)
1405         return FALSE;
1406
1407     resSize = SizeofResource(ppshpage->hInstance, hResource);
1408
1409     hTemplate = LoadResource(ppshpage->hInstance, hResource);
1410     if(!hTemplate)
1411         return FALSE;
1412
1413     pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate);
1414     /*
1415      * Make a copy of the dialog template to make it writable
1416      */
1417   }
1418   else
1419   {
1420     HRSRC hResource;
1421     HANDLE hTemplate;
1422
1423     hResource = FindResourceA(ppshpage->hInstance,
1424                                     (LPCSTR)ppshpage->u.pszTemplate,
1425                                     (LPSTR)RT_DIALOG);
1426     if(!hResource)
1427         return FALSE;
1428
1429     resSize = SizeofResource(ppshpage->hInstance, hResource);
1430
1431     hTemplate = LoadResource(ppshpage->hInstance, hResource);
1432     if(!hTemplate)
1433         return FALSE;
1434
1435     pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate);
1436     /*
1437      * Make a copy of the dialog template to make it writable
1438      */
1439   }
1440   temp = Alloc(resSize);
1441   if (!temp)
1442     return FALSE;
1443   
1444   TRACE("copying pTemplate %p into temp %p (%d)\n", pTemplate, temp, resSize);
1445   memcpy(temp, pTemplate, resSize);
1446   pTemplate = temp;
1447
1448   if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF)
1449   {
1450     ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
1451     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME;
1452     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION;
1453     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU;
1454     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP;
1455     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED;
1456     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE;
1457     ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME;
1458
1459     ((MyDLGTEMPLATEEX*)pTemplate)->exStyle |= WS_EX_CONTROLPARENT;
1460   }
1461   else
1462   {
1463     pTemplate->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL;
1464     pTemplate->style &= ~DS_MODALFRAME;
1465     pTemplate->style &= ~WS_CAPTION;
1466     pTemplate->style &= ~WS_SYSMENU;
1467     pTemplate->style &= ~WS_POPUP;
1468     pTemplate->style &= ~WS_DISABLED;
1469     pTemplate->style &= ~WS_VISIBLE;
1470     pTemplate->style &= ~WS_THICKFRAME;
1471
1472     pTemplate->dwExtendedStyle |= WS_EX_CONTROLPARENT;
1473   }
1474
1475   if (psInfo->proppage[index].useCallback)
1476     (*(ppshpage->pfnCallback))(0, PSPCB_CREATE,
1477                                (LPPROPSHEETPAGEW)ppshpage);
1478
1479   if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE)
1480      hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance,
1481                                         pTemplate,
1482                                         hwndParent,
1483                                         ppshpage->pfnDlgProc,
1484                                         (LPARAM)ppshpage);
1485   else
1486      hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance,
1487                                         pTemplate,
1488                                         hwndParent,
1489                                         ppshpage->pfnDlgProc,
1490                                         (LPARAM)ppshpage);
1491   /* Free a no more needed copy */
1492   if(temp)
1493       Free(temp);
1494
1495   psInfo->proppage[index].hwndPage = hwndPage;
1496
1497   /* Subclass exterior wizard pages */
1498   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) &&
1499      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1500      (ppshpage->dwFlags & PSP_HIDEHEADER))
1501   {
1502       SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1,
1503                         (DWORD_PTR)ppshpage);
1504   }
1505   if (!(psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD))
1506       EnableThemeDialogTexture (hwndPage, ETDT_ENABLETAB);
1507
1508   return TRUE;
1509 }
1510
1511 /******************************************************************************
1512  *            PROPSHEET_LoadWizardBitmaps
1513  *
1514  * Loads the watermark and header bitmaps for a wizard.
1515  */
1516 static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo)
1517 {
1518   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD))
1519   {
1520     /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark 
1521        and put the HBITMAP in hbmWatermark. Thus all the rest of the code always 
1522        considers hbmWatermark as valid. */
1523     if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
1524         !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK))
1525     {
1526       ((PropSheetInfo *)psInfo)->ppshheader.u4.hbmWatermark = 
1527         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0);
1528     }
1529
1530     /* Same behavior as for watermarks */
1531     if ((psInfo->ppshheader.dwFlags & PSH_HEADER) &&
1532         !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER))
1533     {
1534       ((PropSheetInfo *)psInfo)->ppshheader.u5.hbmHeader = 
1535         CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT_PTR)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0);
1536     }
1537   }
1538 }
1539
1540
1541 /******************************************************************************
1542  *            PROPSHEET_ShowPage
1543  *
1544  * Displays or creates the specified page.
1545  */
1546 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
1547 {
1548   HWND hwndTabCtrl;
1549   HWND hwndLineHeader;
1550   LPCPROPSHEETPAGEW ppshpage;
1551
1552   TRACE("active_page %d, index %d\n", psInfo->active_page, index);
1553   if (index == psInfo->active_page)
1554   {
1555       if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage)
1556           SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
1557       return TRUE;
1558   }
1559
1560   ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1561   if (psInfo->proppage[index].hwndPage == 0)
1562   {
1563      PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
1564   }
1565
1566   if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD)
1567   {
1568      PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags,
1569                          psInfo->proppage[index].pszText);
1570   }
1571
1572   if (psInfo->active_page != -1)
1573      ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE);
1574
1575   ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW);
1576
1577   /* Synchronize current selection with tab control
1578    * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */
1579   hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
1580   SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0);
1581
1582   psInfo->active_page = index;
1583   psInfo->activeValid = TRUE;
1584
1585   if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) )
1586   {
1587       hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
1588       ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
1589       
1590       if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) )
1591           ShowWindow(hwndLineHeader, SW_HIDE);
1592       else
1593           ShowWindow(hwndLineHeader, SW_SHOW);
1594   }
1595
1596   return TRUE;
1597 }
1598
1599 /******************************************************************************
1600  *            PROPSHEET_Back
1601  */
1602 static BOOL PROPSHEET_Back(HWND hwndDlg)
1603 {
1604   PSHNOTIFY psn;
1605   HWND hwndPage;
1606   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1607                                                     PropSheetInfoStr);
1608   LRESULT result;
1609   int idx;
1610
1611   TRACE("active_page %d\n", psInfo->active_page);
1612   if (psInfo->active_page < 0)
1613      return FALSE;
1614
1615   psn.hdr.code     = PSN_WIZBACK;
1616   psn.hdr.hwndFrom = hwndDlg;
1617   psn.hdr.idFrom   = 0;
1618   psn.lParam       = 0;
1619
1620   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1621
1622   result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1623   if (result == -1)
1624     return FALSE;
1625   else if (result == 0)
1626      idx = psInfo->active_page - 1;
1627   else
1628      idx = PROPSHEET_FindPageByResId(psInfo, result);
1629
1630   if (idx >= 0 && idx < psInfo->nPages)
1631   {
1632      if (PROPSHEET_CanSetCurSel(hwndDlg))
1633         PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0);
1634   }
1635   return TRUE;
1636 }
1637
1638 /******************************************************************************
1639  *            PROPSHEET_Next
1640  */
1641 static BOOL PROPSHEET_Next(HWND hwndDlg)
1642 {
1643   PSHNOTIFY psn;
1644   HWND hwndPage;
1645   LRESULT msgResult = 0;
1646   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1647                                                     PropSheetInfoStr);
1648   int idx;
1649
1650   TRACE("active_page %d\n", psInfo->active_page);
1651   if (psInfo->active_page < 0)
1652      return FALSE;
1653
1654   psn.hdr.code     = PSN_WIZNEXT;
1655   psn.hdr.hwndFrom = hwndDlg;
1656   psn.hdr.idFrom   = 0;
1657   psn.lParam       = 0;
1658
1659   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1660
1661   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1662   if (msgResult == -1)
1663     return FALSE;
1664   else if (msgResult == 0)
1665      idx = psInfo->active_page + 1;
1666   else
1667      idx = PROPSHEET_FindPageByResId(psInfo, msgResult);
1668
1669   if (idx < psInfo->nPages )
1670   {
1671      if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
1672         PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
1673   }
1674
1675   return TRUE;
1676 }
1677
1678 /******************************************************************************
1679  *            PROPSHEET_Finish
1680  */
1681 static BOOL PROPSHEET_Finish(HWND hwndDlg)
1682 {
1683   PSHNOTIFY psn;
1684   HWND hwndPage;
1685   LRESULT msgResult = 0;
1686   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1687                                                     PropSheetInfoStr);
1688
1689   TRACE("active_page %d\n", psInfo->active_page);
1690   if (psInfo->active_page < 0)
1691      return FALSE;
1692
1693   psn.hdr.code     = PSN_WIZFINISH;
1694   psn.hdr.hwndFrom = hwndDlg;
1695   psn.hdr.idFrom   = 0;
1696   psn.lParam       = 0;
1697
1698   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1699
1700   msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1701
1702   TRACE("msg result %ld\n", msgResult);
1703
1704   if (msgResult != 0)
1705     return FALSE;
1706
1707   if (psInfo->isModeless)
1708     psInfo->activeValid = FALSE;
1709   else
1710     psInfo->ended = TRUE;
1711
1712   return TRUE;
1713 }
1714
1715 /******************************************************************************
1716  *            PROPSHEET_Apply
1717  */
1718 static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam)
1719 {
1720   int i;
1721   HWND hwndPage;
1722   PSHNOTIFY psn;
1723   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1724                                                     PropSheetInfoStr);
1725
1726   TRACE("active_page %d\n", psInfo->active_page);
1727   if (psInfo->active_page < 0)
1728      return FALSE;
1729
1730   psn.hdr.hwndFrom = hwndDlg;
1731   psn.hdr.idFrom   = 0;
1732   psn.lParam       = 0;
1733
1734
1735   /*
1736    * Send PSN_KILLACTIVE to the current page.
1737    */
1738   psn.hdr.code = PSN_KILLACTIVE;
1739
1740   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1741
1742   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE)
1743     return FALSE;
1744
1745   /*
1746    * Send PSN_APPLY to all pages.
1747    */
1748   psn.hdr.code = PSN_APPLY;
1749   psn.lParam   = lParam;
1750
1751   for (i = 0; i < psInfo->nPages; i++)
1752   {
1753     hwndPage = psInfo->proppage[i].hwndPage;
1754     if (hwndPage)
1755     {
1756        switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1757        {
1758        case PSNRET_INVALID:
1759            PROPSHEET_ShowPage(hwndDlg, i, psInfo);
1760            /* fall through */
1761        case PSNRET_INVALID_NOCHANGEPAGE:
1762            return FALSE;
1763        }
1764     }
1765   }
1766
1767   if(lParam)
1768   {
1769      psInfo->activeValid = FALSE;
1770   }
1771   else if(psInfo->active_page >= 0)
1772   {
1773      psn.hdr.code = PSN_SETACTIVE;
1774      psn.lParam   = 0;
1775      hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1776      SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1777   }
1778
1779   return TRUE;
1780 }
1781
1782 /******************************************************************************
1783  *            PROPSHEET_Cancel
1784  */
1785 static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam)
1786 {
1787   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1788                                                     PropSheetInfoStr);
1789   HWND hwndPage;
1790   PSHNOTIFY psn;
1791   int i;
1792
1793   TRACE("active_page %d\n", psInfo->active_page);
1794   if (psInfo->active_page < 0)
1795      return;
1796
1797   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1798   psn.hdr.code     = PSN_QUERYCANCEL;
1799   psn.hdr.hwndFrom = hwndDlg;
1800   psn.hdr.idFrom   = 0;
1801   psn.lParam       = 0;
1802
1803   if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn))
1804     return;
1805
1806   psn.hdr.code = PSN_RESET;
1807   psn.lParam   = lParam;
1808
1809   for (i = 0; i < psInfo->nPages; i++)
1810   {
1811     hwndPage = psInfo->proppage[i].hwndPage;
1812
1813     if (hwndPage)
1814        SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1815   }
1816
1817   if (psInfo->isModeless)
1818   {
1819      /* makes PSM_GETCURRENTPAGEHWND return NULL */
1820      psInfo->activeValid = FALSE;
1821   }
1822   else
1823     psInfo->ended = TRUE;
1824 }
1825
1826 /******************************************************************************
1827  *            PROPSHEET_Help
1828  */
1829 static void PROPSHEET_Help(HWND hwndDlg)
1830 {
1831   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1832                                                     PropSheetInfoStr);
1833   HWND hwndPage;
1834   PSHNOTIFY psn;
1835
1836   TRACE("active_page %d\n", psInfo->active_page);
1837   if (psInfo->active_page < 0)
1838      return;
1839
1840   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1841   psn.hdr.code     = PSN_HELP;
1842   psn.hdr.hwndFrom = hwndDlg;
1843   psn.hdr.idFrom   = 0;
1844   psn.lParam       = 0;
1845
1846   SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1847 }
1848
1849 /******************************************************************************
1850  *            PROPSHEET_Changed
1851  */
1852 static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage)
1853 {
1854   int i;
1855   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1856                                                     PropSheetInfoStr);
1857
1858   TRACE("\n");
1859   if (!psInfo) return;
1860   /*
1861    * Set the dirty flag of this page.
1862    */
1863   for (i = 0; i < psInfo->nPages; i++)
1864   {
1865     if (psInfo->proppage[i].hwndPage == hwndDirtyPage)
1866       psInfo->proppage[i].isDirty = TRUE;
1867   }
1868
1869   /*
1870    * Enable the Apply button.
1871    */
1872   if (psInfo->hasApply)
1873   {
1874     HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1875
1876     EnableWindow(hwndApplyBtn, TRUE);
1877   }
1878 }
1879
1880 /******************************************************************************
1881  *            PROPSHEET_UnChanged
1882  */
1883 static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage)
1884 {
1885   int i;
1886   BOOL noPageDirty = TRUE;
1887   HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON);
1888   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1889                                                     PropSheetInfoStr);
1890
1891   TRACE("\n");
1892   if ( !psInfo ) return;
1893   for (i = 0; i < psInfo->nPages; i++)
1894   {
1895     /* set the specified page as clean */
1896     if (psInfo->proppage[i].hwndPage == hwndCleanPage)
1897       psInfo->proppage[i].isDirty = FALSE;
1898
1899     /* look to see if there's any dirty pages */
1900     if (psInfo->proppage[i].isDirty)
1901       noPageDirty = FALSE;
1902   }
1903
1904   /*
1905    * Disable Apply button.
1906    */
1907   if (noPageDirty)
1908     EnableWindow(hwndApplyBtn, FALSE);
1909 }
1910
1911 /******************************************************************************
1912  *            PROPSHEET_PressButton
1913  */
1914 static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID)
1915 {
1916   TRACE("buttonID %d\n", buttonID);
1917   switch (buttonID)
1918   {
1919     case PSBTN_APPLYNOW:
1920       PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON);
1921       break;
1922     case PSBTN_BACK:
1923       PROPSHEET_Back(hwndDlg);
1924       break;
1925     case PSBTN_CANCEL:
1926       PROPSHEET_DoCommand(hwndDlg, IDCANCEL);
1927       break;
1928     case PSBTN_FINISH:
1929       PROPSHEET_Finish(hwndDlg);
1930       break;
1931     case PSBTN_HELP:
1932       PROPSHEET_DoCommand(hwndDlg, IDHELP);
1933       break;
1934     case PSBTN_NEXT:
1935       PROPSHEET_Next(hwndDlg);
1936       break;
1937     case PSBTN_OK:
1938       PROPSHEET_DoCommand(hwndDlg, IDOK);
1939       break;
1940     default:
1941       FIXME("Invalid button index %d\n", buttonID);
1942   }
1943 }
1944
1945
1946 /*************************************************************************
1947  * BOOL PROPSHEET_CanSetCurSel [Internal]
1948  *
1949  * Test whether the current page can be changed by sending a PSN_KILLACTIVE
1950  *
1951  * PARAMS
1952  *     hwndDlg        [I] handle to a Dialog hWnd
1953  *
1954  * RETURNS
1955  *     TRUE if Current Selection can change
1956  *
1957  * NOTES
1958  */
1959 static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg)
1960 {
1961   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
1962                                                     PropSheetInfoStr);
1963   HWND hwndPage;
1964   PSHNOTIFY psn;
1965   BOOL res = FALSE;
1966
1967   TRACE("active_page %d\n", psInfo->active_page);
1968   if (!psInfo)
1969   {
1970      res = FALSE;
1971      goto end;
1972   }
1973
1974   if (psInfo->active_page < 0)
1975   {
1976      res = TRUE;
1977      goto end;
1978   }
1979
1980   /*
1981    * Notify the current page.
1982    */
1983   hwndPage = psInfo->proppage[psInfo->active_page].hwndPage;
1984   psn.hdr.code     = PSN_KILLACTIVE;
1985   psn.hdr.hwndFrom = hwndDlg;
1986   psn.hdr.idFrom   = 0;
1987   psn.lParam       = 0;
1988
1989   res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
1990
1991 end:
1992   TRACE("<-- %d\n", res);
1993   return res;
1994 }
1995
1996 /******************************************************************************
1997  *            PROPSHEET_SetCurSel
1998  */
1999 static BOOL PROPSHEET_SetCurSel(HWND hwndDlg,
2000                                 int index,
2001                                 int skipdir,
2002                                 HPROPSHEETPAGE hpage
2003                                 )
2004 {
2005   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2006   HWND hwndHelp  = GetDlgItem(hwndDlg, IDHELP);
2007   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2008
2009   TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage);
2010   /* hpage takes precedence over index */
2011   if (hpage != NULL)
2012     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2013
2014   if (index < 0 || index >= psInfo->nPages)
2015   {
2016     TRACE("Could not find page to select!\n");
2017     return FALSE;
2018   }
2019
2020   while (1) {
2021     int result;
2022     PSHNOTIFY psn;
2023     RECT rc;
2024     LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2025
2026     if (hwndTabControl)
2027         SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0);
2028
2029     psn.hdr.code     = PSN_SETACTIVE;
2030     psn.hdr.hwndFrom = hwndDlg;
2031     psn.hdr.idFrom   = 0;
2032     psn.lParam       = 0;
2033
2034     if (!psInfo->proppage[index].hwndPage) {
2035       PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage);
2036     }
2037
2038     /* Resize the property sheet page to the fit in the Tab control
2039      * (for regular property sheets) or to fit in the client area (for
2040      * wizards).
2041      * NOTE: The resizing happens every time the page is selected and
2042      * not only when it's created (some applications depend on it). */
2043     PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage);
2044     TRACE("setting page %p, rc (%d,%d)-(%d,%d) w=%d, h=%d\n",
2045           psInfo->proppage[index].hwndPage, rc.left, rc.top, rc.right, rc.bottom,
2046           rc.right - rc.left, rc.bottom - rc.top);
2047     SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP,
2048                  rc.left, rc.top,
2049                  rc.right - rc.left, rc.bottom - rc.top, 0);
2050
2051     result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn);
2052     if (!result)
2053       break;
2054     if (result == -1) {
2055       index+=skipdir;
2056       if (index < 0) {
2057         index = 0;
2058         WARN("Tried to skip before first property sheet page!\n");
2059         break;
2060       }
2061       if (index >= psInfo->nPages) {
2062         WARN("Tried to skip after last property sheet page!\n");
2063         index = psInfo->nPages-1;
2064         break;
2065       }
2066     }
2067     else if (result != 0)
2068     {
2069       int old_index = index;
2070       index = PROPSHEET_FindPageByResId(psInfo, result);
2071       if(index >= psInfo->nPages) {
2072         index = old_index;
2073         WARN("Tried to skip to nonexistant page by res id\n");
2074         break;
2075       }
2076       continue;
2077     }
2078   }
2079
2080   /* Invalidate the header area */
2081   if ( (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) &&
2082        (psInfo->ppshheader.dwFlags & PSH_HEADER) )
2083   {
2084     HWND hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER);
2085     RECT r;
2086
2087     GetClientRect(hwndLineHeader, &r);
2088     MapWindowPoints(hwndLineHeader, hwndDlg, (LPPOINT) &r, 2);
2089     SetRect(&r, 0, 0, r.right + 1, r.top - 1);
2090
2091     InvalidateRect(hwndDlg, &r, TRUE);
2092   }
2093
2094   /*
2095    * Display the new page.
2096    */
2097   PROPSHEET_ShowPage(hwndDlg, index, psInfo);
2098
2099   if (psInfo->proppage[index].hasHelp)
2100     EnableWindow(hwndHelp, TRUE);
2101   else
2102     EnableWindow(hwndHelp, FALSE);
2103
2104   return TRUE;
2105 }
2106
2107 /******************************************************************************
2108  *            PROPSHEET_SetCurSelId
2109  *
2110  * Selects the page, specified by resource id.
2111  */
2112 static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id)
2113 {
2114       int idx;
2115       PropSheetInfo* psInfo =
2116           (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2117
2118       idx = PROPSHEET_FindPageByResId(psInfo, id);
2119       if (idx < psInfo->nPages )
2120       {
2121           if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE)
2122               PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0);
2123       }
2124 }
2125
2126 /******************************************************************************
2127  *            PROPSHEET_SetTitleA
2128  */
2129 static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText)
2130 {
2131   if(HIWORD(lpszText))
2132   {
2133      WCHAR szTitle[256];
2134      MultiByteToWideChar(CP_ACP, 0, lpszText, -1,
2135                          szTitle, sizeof(szTitle)/sizeof(WCHAR));
2136      PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle);
2137   }
2138   else
2139   {
2140      PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText);
2141   }
2142 }
2143
2144 /******************************************************************************
2145  *            PROPSHEET_SetTitleW
2146  */
2147 static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText)
2148 {
2149   PropSheetInfo*        psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2150   WCHAR                 szTitle[256];
2151
2152   TRACE("'%s' (style %08x)\n", debugstr_w(lpszText), dwStyle);
2153   if (HIWORD(lpszText) == 0) {
2154     if (!LoadStringW(psInfo->ppshheader.hInstance,
2155                      LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR)))
2156       return;
2157     lpszText = szTitle;
2158   }
2159   if (dwStyle & PSH_PROPTITLE)
2160   {
2161     WCHAR* dest;
2162     int lentitle = strlenW(lpszText);
2163     int lenprop  = strlenW(psInfo->strPropertiesFor);
2164
2165     dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR));
2166     wsprintfW(dest, psInfo->strPropertiesFor, lpszText);
2167
2168     SetWindowTextW(hwndDlg, dest);
2169     Free(dest);
2170   }
2171   else
2172     SetWindowTextW(hwndDlg, lpszText);
2173 }
2174
2175 /******************************************************************************
2176  *            PROPSHEET_SetFinishTextA
2177  */
2178 static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText)
2179 {
2180   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2181   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2182
2183   TRACE("'%s'\n", lpszText);
2184   /* Set text, show and enable the Finish button */
2185   SetWindowTextA(hwndButton, lpszText);
2186   ShowWindow(hwndButton, SW_SHOW);
2187   EnableWindow(hwndButton, TRUE);
2188
2189   /* Make it default pushbutton */
2190   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2191
2192   /* Hide Back button */
2193   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2194   ShowWindow(hwndButton, SW_HIDE);
2195
2196   if (!psInfo->hasFinish)
2197   {
2198     /* Hide Next button */
2199     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2200     ShowWindow(hwndButton, SW_HIDE);
2201   }
2202 }
2203
2204 /******************************************************************************
2205  *            PROPSHEET_SetFinishTextW
2206  */
2207 static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText)
2208 {
2209   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2210   HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2211
2212   TRACE("'%s'\n", debugstr_w(lpszText));
2213   /* Set text, show and enable the Finish button */
2214   SetWindowTextW(hwndButton, lpszText);
2215   ShowWindow(hwndButton, SW_SHOW);
2216   EnableWindow(hwndButton, TRUE);
2217
2218   /* Make it default pushbutton */
2219   SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2220
2221   /* Hide Back button */
2222   hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2223   ShowWindow(hwndButton, SW_HIDE);
2224
2225   if (!psInfo->hasFinish)
2226   {
2227     /* Hide Next button */
2228     hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2229     ShowWindow(hwndButton, SW_HIDE);
2230   }
2231 }
2232
2233 /******************************************************************************
2234  *            PROPSHEET_QuerySiblings
2235  */
2236 static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg,
2237                                        WPARAM wParam, LPARAM lParam)
2238 {
2239   int i = 0;
2240   HWND hwndPage;
2241   LRESULT msgResult = 0;
2242   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr);
2243
2244   while ((i < psInfo->nPages) && (msgResult == 0))
2245   {
2246     hwndPage = psInfo->proppage[i].hwndPage;
2247     msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam);
2248     i++;
2249   }
2250
2251   return msgResult;
2252 }
2253
2254
2255 /******************************************************************************
2256  *            PROPSHEET_AddPage
2257  */
2258 static BOOL PROPSHEET_AddPage(HWND hwndDlg,
2259                               HPROPSHEETPAGE hpage)
2260 {
2261   PropPageInfo * ppi;
2262   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2263                                                      PropSheetInfoStr);
2264   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2265   TCITEMW item;
2266   LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage;
2267
2268   TRACE("hpage %p\n", hpage);
2269   /*
2270    * Allocate and fill in a new PropPageInfo entry.
2271    */
2272   ppi = (PropPageInfo*) ReAlloc(psInfo->proppage,
2273                                 sizeof(PropPageInfo) *
2274                                 (psInfo->nPages + 1));
2275   if (!ppi)
2276       return FALSE;
2277
2278   psInfo->proppage = ppi;
2279   if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages))
2280       return FALSE;
2281
2282   psInfo->proppage[psInfo->nPages].hpage = hpage;
2283
2284   if (ppsp->dwFlags & PSP_PREMATURE)
2285   {
2286      /* Create the page but don't show it */
2287      PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp);
2288   }
2289
2290   /*
2291    * Add a new tab to the tab control.
2292    */
2293   item.mask = TCIF_TEXT;
2294   item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText;
2295   item.cchTextMax = MAX_TABTEXT_LENGTH;
2296
2297   if (psInfo->hImageList)
2298   {
2299     SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList);
2300   }
2301
2302   if ( psInfo->proppage[psInfo->nPages].hasIcon )
2303   {
2304     item.mask |= TCIF_IMAGE;
2305     item.iImage = psInfo->nPages;
2306   }
2307
2308   SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1,
2309                (LPARAM)&item);
2310
2311   psInfo->nPages++;
2312
2313   /* If it is the only page - show it */
2314   if(psInfo->nPages == 1)
2315      PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0);
2316   return TRUE;
2317 }
2318
2319 /******************************************************************************
2320  *            PROPSHEET_RemovePage
2321  */
2322 static BOOL PROPSHEET_RemovePage(HWND hwndDlg,
2323                                  int index,
2324                                  HPROPSHEETPAGE hpage)
2325 {
2326   PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2327                                                      PropSheetInfoStr);
2328   HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL);
2329   PropPageInfo* oldPages;
2330
2331   TRACE("index %d, hpage %p\n", index, hpage);
2332   if (!psInfo) {
2333     return FALSE;
2334   }
2335   /*
2336    * hpage takes precedence over index.
2337    */
2338   if (hpage != 0)
2339   {
2340     index = PROPSHEET_GetPageIndex(hpage, psInfo);
2341   }
2342
2343   /* Make sure that index is within range */
2344   if (index < 0 || index >= psInfo->nPages)
2345   {
2346       TRACE("Could not find page to remove!\n");
2347       return FALSE;
2348   }
2349
2350   TRACE("total pages %d removing page %d active page %d\n",
2351         psInfo->nPages, index, psInfo->active_page);
2352   /*
2353    * Check if we're removing the active page.
2354    */
2355   if (index == psInfo->active_page)
2356   {
2357     if (psInfo->nPages > 1)
2358     {
2359       if (index > 0)
2360       {
2361         /* activate previous page  */
2362         PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0);
2363       }
2364       else
2365       {
2366         /* activate the next page */
2367         PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0);
2368         psInfo->active_page = index;
2369       }
2370     }
2371     else
2372     {
2373       psInfo->active_page = -1;
2374       if (!psInfo->isModeless)
2375       {
2376          psInfo->ended = TRUE;
2377          return TRUE;
2378       }
2379     }
2380   }
2381   else if (index < psInfo->active_page)
2382     psInfo->active_page--;
2383
2384   /* Unsubclass the page dialog window */
2385   if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) &&
2386      (psInfo->ppshheader.dwFlags & PSH_WATERMARK) &&
2387      ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER))
2388   {
2389      RemoveWindowSubclass(psInfo->proppage[index].hwndPage,
2390                           PROPSHEET_WizardSubclassProc, 1);
2391   }
2392
2393   /* Destroy page dialog window */
2394   DestroyWindow(psInfo->proppage[index].hwndPage);
2395
2396   /* Free page resources */
2397   if(psInfo->proppage[index].hpage)
2398   {
2399      PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage;
2400
2401      if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText)
2402         Free ((LPVOID)psInfo->proppage[index].pszText);
2403
2404      DestroyPropertySheetPage(psInfo->proppage[index].hpage);
2405   }
2406
2407   /* Remove the tab */
2408   SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0);
2409
2410   oldPages = psInfo->proppage;
2411   psInfo->nPages--;
2412   psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages);
2413
2414   if (index > 0)
2415     memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo));
2416
2417   if (index < psInfo->nPages)
2418     memcpy(&psInfo->proppage[index], &oldPages[index + 1],
2419            (psInfo->nPages - index) * sizeof(PropPageInfo));
2420
2421   Free(oldPages);
2422
2423   return FALSE;
2424 }
2425
2426 /******************************************************************************
2427  *            PROPSHEET_SetWizButtons
2428  *
2429  * This code will work if (and assumes that) the Next button is on top of the
2430  * Finish button. ie. Finish comes after Next in the Z order.
2431  * This means make sure the dialog template reflects this.
2432  *
2433  */
2434 static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags)
2435 {
2436   PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2437                                                     PropSheetInfoStr);
2438   HWND hwndBack   = GetDlgItem(hwndDlg, IDC_BACK_BUTTON);
2439   HWND hwndNext   = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON);
2440   HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON);
2441
2442   TRACE("%d\n", dwFlags);
2443
2444   EnableWindow(hwndBack, FALSE);
2445   EnableWindow(hwndNext, FALSE);
2446   EnableWindow(hwndFinish, FALSE);
2447
2448   /* set the default pushbutton to an enabled button */
2449   if (((dwFlags & PSWIZB_FINISH) || psInfo->hasFinish) && !(dwFlags & PSWIZB_DISABLEDFINISH))
2450     SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0);
2451   else if (dwFlags & PSWIZB_NEXT)
2452     SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0);
2453   else if (dwFlags & PSWIZB_BACK)
2454     SendMessageW(hwndDlg, DM_SETDEFID, IDC_BACK_BUTTON, 0);
2455   else
2456     SendMessageW(hwndDlg, DM_SETDEFID, IDCANCEL, 0);
2457
2458
2459   if (dwFlags & PSWIZB_BACK)
2460     EnableWindow(hwndBack, TRUE);
2461
2462   if (dwFlags & PSWIZB_NEXT)
2463     EnableWindow(hwndNext, TRUE);
2464
2465   if (!psInfo->hasFinish)
2466   {
2467     if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH))
2468     {
2469       /* Hide the Next button */
2470       ShowWindow(hwndNext, SW_HIDE);
2471       
2472       /* Show the Finish button */
2473       ShowWindow(hwndFinish, SW_SHOW);
2474
2475       if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2476         EnableWindow(hwndFinish, TRUE);
2477     }
2478     else
2479     {
2480       /* Hide the Finish button */
2481       ShowWindow(hwndFinish, SW_HIDE);
2482       /* Show the Next button */
2483       ShowWindow(hwndNext, SW_SHOW);
2484     }
2485   }
2486   else if (!(dwFlags & PSWIZB_DISABLEDFINISH))
2487     EnableWindow(hwndFinish, TRUE);
2488 }
2489
2490 /******************************************************************************
2491  *            PROPSHEET_InsertPage
2492  */
2493 static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage)
2494 {
2495     if (!HIWORD(hpageInsertAfter))
2496         FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage);
2497     else
2498         FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage);
2499     return FALSE;
2500 }
2501
2502 /******************************************************************************
2503  *            PROPSHEET_SetHeaderTitleW
2504  */
2505 static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle)
2506 {
2507     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle));
2508 }
2509
2510 /******************************************************************************
2511  *            PROPSHEET_SetHeaderTitleA
2512  */
2513 static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle)
2514 {
2515     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle));
2516 }
2517
2518 /******************************************************************************
2519  *            PROPSHEET_SetHeaderSubTitleW
2520  */
2521 static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle)
2522 {
2523     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle));
2524 }
2525
2526 /******************************************************************************
2527  *            PROPSHEET_SetHeaderSubTitleA
2528  */
2529 static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle)
2530 {
2531     FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle));
2532 }
2533
2534 /******************************************************************************
2535  *            PROPSHEET_HwndToIndex
2536  */
2537 static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg)
2538 {
2539     int index;
2540     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2541                                                        PropSheetInfoStr);
2542
2543     TRACE("(%p, %p)\n", hwndDlg, hPageDlg);
2544
2545     for (index = 0; index < psInfo->nPages; index++)
2546         if (psInfo->proppage[index].hwndPage == hPageDlg)
2547             return index;
2548     WARN("%p not found\n", hPageDlg);
2549     return -1;
2550 }
2551
2552 /******************************************************************************
2553  *            PROPSHEET_IndexToHwnd
2554  */
2555 static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex)
2556 {
2557     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2558                                                        PropSheetInfoStr);
2559     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2560     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2561         WARN("%d out of range.\n", iPageIndex);
2562         return 0;
2563     }
2564     return (LRESULT)psInfo->proppage[iPageIndex].hwndPage;
2565 }
2566
2567 /******************************************************************************
2568  *            PROPSHEET_PageToIndex
2569  */
2570 static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage)
2571 {
2572     int index;
2573     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2574                                                        PropSheetInfoStr);
2575
2576     TRACE("(%p, %p)\n", hwndDlg, hPage);
2577
2578     for (index = 0; index < psInfo->nPages; index++)
2579         if (psInfo->proppage[index].hpage == hPage)
2580             return index;
2581     WARN("%p not found\n", hPage);
2582     return -1;
2583 }
2584
2585 /******************************************************************************
2586  *            PROPSHEET_IndexToPage
2587  */
2588 static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex)
2589 {
2590     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2591                                                        PropSheetInfoStr);
2592     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2593     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2594         WARN("%d out of range.\n", iPageIndex);
2595         return 0;
2596     }
2597     return (LRESULT)psInfo->proppage[iPageIndex].hpage;
2598 }
2599
2600 /******************************************************************************
2601  *            PROPSHEET_IdToIndex
2602  */
2603 static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId)
2604 {
2605     int index;
2606     LPCPROPSHEETPAGEW psp;
2607     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2608                                                        PropSheetInfoStr);
2609     TRACE("(%p, %d)\n", hwndDlg, iPageId);
2610     for (index = 0; index < psInfo->nPages; index++) {
2611         psp = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage;
2612         if (psp->u.pszTemplate == MAKEINTRESOURCEW(iPageId))
2613             return index;
2614     }
2615
2616     return -1;
2617 }
2618
2619 /******************************************************************************
2620  *            PROPSHEET_IndexToId
2621  */
2622 static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex)
2623 {
2624     PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg,
2625                                                        PropSheetInfoStr);
2626     LPCPROPSHEETPAGEW psp;
2627     TRACE("(%p, %d)\n", hwndDlg, iPageIndex);
2628     if (iPageIndex<0 || iPageIndex>=psInfo->nPages) {
2629         WARN("%d out of range.\n", iPageIndex);
2630         return 0;
2631     }
2632     psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage;
2633     if (psp->dwFlags & PSP_DLGINDIRECT || HIWORD(psp->u.pszTemplate)) {
2634         return 0;
2635     }
2636     return (LRESULT)psp->u.pszTemplate;
2637 }
2638
2639 /******************************************************************************
2640  *            PROPSHEET_GetResult
2641  */
2642 static LRESULT PROPSHEET_GetResult(HWND hwndDlg)
2643 {
2644     FIXME("(%p): stub\n", hwndDlg);
2645     return -1;
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 }