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