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

Last change on this file since 8411 was 8411, checked in by sandervl, 23 years ago

resync with latest Wine

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