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