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

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

Update: Wine merged our changes

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