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