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