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