source: trunk/src/comctl32/propsheet.c@ 10367

Last change on this file since 10367 was 10165, checked in by sandervl, 22 years ago

KOM: Ascii/Unicode conversion fixes (DBCS)

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