1 // Windows Template Library - WTL version 9.10
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8 
9 #ifndef __ATLDLGS_H__
10 #define __ATLDLGS_H__
11 
12 #pragma once
13 
14 #ifndef __ATLAPP_H__
15 	#error atldlgs.h requires atlapp.h to be included first
16 #endif
17 
18 #ifndef __ATLWIN_H__
19 	#error atldlgs.h requires atlwin.h to be included first
20 #endif
21 
22 #include <commdlg.h>
23 #include <shlobj.h>
24 
25 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
26   #include <shobjidl.h>
27 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
28 
29 
30 ///////////////////////////////////////////////////////////////////////////////
31 // Classes in this file:
32 //
33 // CFileDialogImpl<T>
34 // CFileDialog
35 // CFileDialogEx
36 // CMultiFileDialogImpl<T>
37 // CMultiFileDialog
38 // CShellFileDialogImpl<T>
39 // CShellFileOpenDialogImpl<T>
40 // CShellFileOpenDialog
41 // CShellFileSaveDialogImpl<T>
42 // CShellFileSaveDialog
43 // CFolderDialogImpl<T>
44 // CFolderDialog
45 // CFontDialogImpl<T>
46 // CFontDialog
47 // CRichEditFontDialogImpl<T>
48 // CRichEditFontDialog
49 // CColorDialogImpl<T>
50 // CColorDialog
51 // CPrintDialogImpl<T>
52 // CPrintDialog
53 // CPrintDialogExImpl<T>
54 // CPrintDialogEx
55 // CPageSetupDialogImpl<T>
56 // CPageSetupDialog
57 // CFindReplaceDialogImpl<T>
58 // CFindReplaceDialog
59 //
60 // CDialogBaseUnits
61 // CMemDlgTemplate
62 // CIndirectDialogImpl<T, TDlgTemplate, TBase>
63 //
64 // CPropertySheetWindow
65 // CPropertySheetImpl<T, TBase>
66 // CPropertySheet
67 // CPropertyPageWindow
68 // CPropertyPageImpl<T, TBase>
69 // CPropertyPage<t_wDlgTemplateID>
70 // CAxPropertyPageImpl<T, TBase>
71 // CAxPropertyPage<t_wDlgTemplateID>
72 //
73 // CWizard97SheetWindow
74 // CWizard97SheetImpl<T, TBase>
75 // CWizard97Sheet
76 // CWizard97PageWindow
77 // CWizard97PageImpl<T, TBase>
78 // CWizard97ExteriorPageImpl<T, TBase>
79 // CWizard97InteriorPageImpl<T, TBase>
80 //
81 // CAeroWizardFrameWindow
82 // CAeroWizardFrameImpl<T, TBase>
83 // CAeroWizardFrame
84 // CAeroWizardPageWindow
85 // CAeroWizardPageImpl<T, TBase>
86 // CAeroWizardPage<t_wDlgTemplateID>
87 // CAeroWizardAxPageImpl<T, TBase>
88 // CAeroWizardAxPage<t_wDlgTemplateID>
89 //
90 // CTaskDialogConfig
91 // CTaskDialogImpl<T>
92 // CTaskDialog
93 //
94 // Global functions:
95 //   AtlTaskDialog()
96 
97 
98 namespace WTL
99 {
100 
101 ///////////////////////////////////////////////////////////////////////////////
102 // CFileDialogImpl - used for File Open or File Save As
103 
104 // compatibility with the old (vc6.0) headers
105 #if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
106   #ifndef CDSIZEOF_STRUCT
107     #define CDSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
108   #endif
109   #define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
110   #define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
111   #ifdef UNICODE
112     #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400W
113   #else
114     #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400A
115   #endif // !UNICODE
116 #endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
117 
118 #if !defined(_WIN32_WCE) && !defined(CDN_INCLUDEITEM)
119   #define CDN_INCLUDEITEM         (CDN_FIRST - 0x0007)
120 #endif
121 
122 template <class T>
123 class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase
124 {
125 public:
126 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
127 	OPENFILENAMEEX m_ofn;
128 #else
129 	OPENFILENAME m_ofn;
130 #endif
131 	BOOL m_bOpenFileDialog;            // TRUE for file open, FALSE for file save
132 	TCHAR m_szFileTitle[_MAX_FNAME];   // contains file title after return
133 	TCHAR m_szFileName[_MAX_PATH];     // contains full path name after return
134 
135 	CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
136 			LPCTSTR lpszDefExt = NULL,
137 			LPCTSTR lpszFileName = NULL,
138 			DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
139 			LPCTSTR lpszFilter = NULL,
140 			HWND hWndParent = NULL)
141 	{
142 		memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
143 		m_szFileName[0] = _T('\0');
144 		m_szFileTitle[0] = _T('\0');
145 
146 		m_bOpenFileDialog = bOpenFileDialog;
147 
148 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
149 		m_ofn.lStructSize = bOpenFileDialog ? sizeof(m_ofn) : sizeof(OPENFILENAME);
150 #else
151 		m_ofn.lStructSize = sizeof(m_ofn);
152 #endif
153 
154 #if (_WIN32_WINNT >= 0x0500)
155 		// adjust struct size if running on older version of Windows
156 		if(AtlIsOldWindows())
157 		{
158 			ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400);   // must be
159 			m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
160 		}
161 #endif // (_WIN32_WINNT >= 0x0500)
162 		m_ofn.lpstrFile = m_szFileName;
163 		m_ofn.nMaxFile = _MAX_PATH;
164 		m_ofn.lpstrDefExt = lpszDefExt;
165 		m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
166 		m_ofn.nMaxFileTitle = _MAX_FNAME;
167 #ifndef _WIN32_WCE
168 		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;
169 #else // CE specific
170 		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;
171 #endif // !_WIN32_WCE
172 		m_ofn.lpstrFilter = lpszFilter;
173 		m_ofn.hInstance = ModuleHelper::GetResourceInstance();
174 		m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;
175 		m_ofn.hwndOwner = hWndParent;
176 
177 		// setup initial file name
178 		if(lpszFileName != NULL)
179 		SecureHelper::strncpy_x(m_szFileName, _countof(m_szFileName), lpszFileName, _TRUNCATE);
180 	}
181 
182 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
183 	{
184 		ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);
185 		ATLASSERT(m_ofn.lpfnHook != NULL);   // can still be a user hook
186 
187 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
188 
189 		if(m_ofn.hwndOwner == NULL)   // set only if not specified before
190 			m_ofn.hwndOwner = hWndParent;
191 
192 		ATLASSERT(m_hWnd == NULL);
193 
194 #if (_ATL_VER >= 0x0800)
195 		// Allocate the thunk structure here, where we can fail gracefully.
196 		BOOL bRetTh = m_thunk.Init(NULL, NULL);
197 		if(bRetTh == FALSE)
198 		{
199 			::SetLastError(ERROR_OUTOFMEMORY);
200 			return -1;
201 		}
202 #endif // (_ATL_VER >= 0x0800)
203 
204 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);
205 
206 		BOOL bRet;
207 		if(m_bOpenFileDialog)
208 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
209 			bRet = ::GetOpenFileNameEx(&m_ofn);
210 		else
211 			bRet = ::GetSaveFileName((LPOPENFILENAME)&m_ofn);
212 #else
213 			bRet = ::GetOpenFileName(&m_ofn);
214 		else
215 			bRet = ::GetSaveFileName(&m_ofn);
216 #endif
217 
218 		m_hWnd = NULL;
219 
220 		return bRet ? IDOK : IDCANCEL;
221 	}
222 
223 // Attributes
GetFileDialogWindow()224 	ATL::CWindow GetFileDialogWindow() const
225 	{
226 		ATLASSERT(::IsWindow(m_hWnd));
227 		return ATL::CWindow(GetParent());
228 	}
229 
GetFilePath(LPTSTR lpstrFilePath,int nLength)230 	int GetFilePath(LPTSTR lpstrFilePath, int nLength) const
231 	{
232 		ATLASSERT(::IsWindow(m_hWnd));
233 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
234 
235 		return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath);
236 	}
237 
GetFolderIDList(LPVOID lpBuff,int nLength)238 	int GetFolderIDList(LPVOID lpBuff, int nLength) const
239 	{
240 		ATLASSERT(::IsWindow(m_hWnd));
241 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
242 
243 		return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff);
244 	}
245 
GetFolderPath(LPTSTR lpstrFolderPath,int nLength)246 	int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const
247 	{
248 		ATLASSERT(::IsWindow(m_hWnd));
249 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
250 
251 		return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath);
252 	}
253 
GetSpec(LPTSTR lpstrSpec,int nLength)254 	int GetSpec(LPTSTR lpstrSpec, int nLength) const
255 	{
256 		ATLASSERT(::IsWindow(m_hWnd));
257 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
258 
259 		return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec);
260 	}
261 
SetControlText(int nCtrlID,LPCTSTR lpstrText)262 	void SetControlText(int nCtrlID, LPCTSTR lpstrText)
263 	{
264 		ATLASSERT(::IsWindow(m_hWnd));
265 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
266 
267 		GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText);
268 	}
269 
SetDefExt(LPCTSTR lpstrExt)270 	void SetDefExt(LPCTSTR lpstrExt)
271 	{
272 		ATLASSERT(::IsWindow(m_hWnd));
273 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
274 
275 		GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt);
276 	}
277 
GetReadOnlyPref()278 	BOOL GetReadOnlyPref() const	// return TRUE if readonly checked
279 	{
280 		return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE;
281 	}
282 
283 // Operations
HideControl(int nCtrlID)284 	void HideControl(int nCtrlID)
285 	{
286 		ATLASSERT(::IsWindow(m_hWnd));
287 		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);
288 
289 		GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID);
290 	}
291 
292 // Special override for common dialogs
293 	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
294 	{
295 		ATLASSERT(::IsWindow(m_hWnd));
296 		GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0));
297 		return TRUE;
298 	}
299 
300 // Message map and handlers
301 	BEGIN_MSG_MAP(CFileDialogImpl)
NOTIFY_CODE_HANDLER(CDN_FILEOK,_OnFileOK)302 		NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK)
303 		NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange)
304 		NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp)
305 		NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone)
306 		NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange)
307 		NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation)
308 		NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange)
309 #ifndef _WIN32_WCE
310 		NOTIFY_CODE_HANDLER(CDN_INCLUDEITEM, _OnIncludeItem)
311 #endif // !_WIN32_WCE
312 	END_MSG_MAP()
313 
314 	LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
315 	{
316 		ATLASSERT(::IsWindow(m_hWnd));
317 		T* pT = static_cast<T*>(this);
318 		return !pT->OnFileOK((LPOFNOTIFY)pnmh);
319 	}
320 
_OnFolderChange(int,LPNMHDR pnmh,BOOL &)321 	LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
322 	{
323 		ATLASSERT(::IsWindow(m_hWnd));
324 		T* pT = static_cast<T*>(this);
325 		pT->OnFolderChange((LPOFNOTIFY)pnmh);
326 		return 0;
327 	}
328 
_OnHelp(int,LPNMHDR pnmh,BOOL &)329 	LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
330 	{
331 		ATLASSERT(::IsWindow(m_hWnd));
332 		T* pT = static_cast<T*>(this);
333 		pT->OnHelp((LPOFNOTIFY)pnmh);
334 		return 0;
335 	}
336 
_OnInitDone(int,LPNMHDR pnmh,BOOL &)337 	LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
338 	{
339 		ATLASSERT(::IsWindow(m_hWnd));
340 		T* pT = static_cast<T*>(this);
341 		pT->OnInitDone((LPOFNOTIFY)pnmh);
342 		return 0;
343 	}
344 
_OnSelChange(int,LPNMHDR pnmh,BOOL &)345 	LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
346 	{
347 		ATLASSERT(::IsWindow(m_hWnd));
348 		T* pT = static_cast<T*>(this);
349 		pT->OnSelChange((LPOFNOTIFY)pnmh);
350 		return 0;
351 	}
352 
_OnShareViolation(int,LPNMHDR pnmh,BOOL &)353 	LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
354 	{
355 		ATLASSERT(::IsWindow(m_hWnd));
356 		T* pT = static_cast<T*>(this);
357 		return pT->OnShareViolation((LPOFNOTIFY)pnmh);
358 	}
359 
_OnTypeChange(int,LPNMHDR pnmh,BOOL &)360 	LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
361 	{
362 		ATLASSERT(::IsWindow(m_hWnd));
363 		T* pT = static_cast<T*>(this);
364 		pT->OnTypeChange((LPOFNOTIFY)pnmh);
365 		return 0;
366 	}
367 
368 #ifndef _WIN32_WCE
_OnIncludeItem(int,LPNMHDR pnmh,BOOL &)369 	LRESULT _OnIncludeItem(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
370 	{
371 		ATLASSERT(::IsWindow(m_hWnd));
372 		T* pT = static_cast<T*>(this);
373 		return pT->OnIncludeItem((LPOFNOTIFYEX)pnmh);
374 	}
375 #endif // !_WIN32_WCE
376 
377 // Overrideables
OnFileOK(LPOFNOTIFY)378 	BOOL OnFileOK(LPOFNOTIFY /*lpon*/)
379 	{
380 		return TRUE;
381 	}
382 
OnFolderChange(LPOFNOTIFY)383 	void OnFolderChange(LPOFNOTIFY /*lpon*/)
384 	{
385 	}
386 
OnHelp(LPOFNOTIFY)387 	void OnHelp(LPOFNOTIFY /*lpon*/)
388 	{
389 	}
390 
OnInitDone(LPOFNOTIFY)391 	void OnInitDone(LPOFNOTIFY /*lpon*/)
392 	{
393 	}
394 
OnSelChange(LPOFNOTIFY)395 	void OnSelChange(LPOFNOTIFY /*lpon*/)
396 	{
397 	}
398 
OnShareViolation(LPOFNOTIFY)399 	int OnShareViolation(LPOFNOTIFY /*lpon*/)
400 	{
401 		return 0;
402 	}
403 
OnTypeChange(LPOFNOTIFY)404 	void OnTypeChange(LPOFNOTIFY /*lpon*/)
405 	{
406 	}
407 
408 #ifndef _WIN32_WCE
OnIncludeItem(LPOFNOTIFYEX)409 	BOOL OnIncludeItem(LPOFNOTIFYEX /*lponex*/)
410 	{
411 		return TRUE;   // include item
412 	}
413 #endif // !_WIN32_WCE
414 };
415 
416 class CFileDialog : public CFileDialogImpl<CFileDialog>
417 {
418 public:
419 	CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
420 		LPCTSTR lpszDefExt = NULL,
421 		LPCTSTR lpszFileName = NULL,
422 		DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
423 		LPCTSTR lpszFilter = NULL,
424 		HWND hWndParent = NULL)
425 		: CFileDialogImpl<CFileDialog>(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
426 	{ }
427 
428 	// override base class map and references to handlers
429 	DECLARE_EMPTY_MSG_MAP()
430 };
431 
432 #if defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
433 class CFileDialogEx : public CFileDialogImpl<CFileDialogEx>
434 {
435 public:
436 	CFileDialogEx( // Supports only FileOpen
437 		LPCTSTR lpszDefExt = NULL,
438 		LPCTSTR lpszFileName = NULL,
439 		DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
440 		OFN_EXFLAG ExFlags = OFN_EXFLAG_THUMBNAILVIEW,
441 		OFN_SORTORDER dwSortOrder = OFN_SORTORDER_AUTO,
442 		LPCTSTR lpszFilter = NULL,
443 		HWND hWndParent = NULL)
444 		: CFileDialogImpl<CFileDialogEx>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
445 	{
446 		m_ofn.ExFlags = ExFlags;
447 		m_ofn.dwSortOrder = dwSortOrder;
448 	}
449 
450 	// override base class map and references to handlers
451 	DECLARE_EMPTY_MSG_MAP()
452 };
453 #endif // defined(__AYGSHELL_H__) && (_WIN32_WCE >= 0x0501)
454 
455 
456 ///////////////////////////////////////////////////////////////////////////////
457 // Multi File Dialog - Multi-select File Open dialog
458 
459 #ifndef _WIN32_WCE
460 
461 // The class dynamically resizes the buffer as the file selection changes
462 // (as described in Knowledge Base article 131462). It also expands selected
463 // shortcut files to take into account the full path of the target file.
464 // Note that this doesn't work on Win9x for the old style dialogs, as well as
465 // on NT for non-Unicode builds.
466 
467 #ifndef _WTL_FIXED_OFN_BUFFER_LENGTH
468   #define _WTL_FIXED_OFN_BUFFER_LENGTH 0x10000
469 #endif
470 
471 template <class T>
472 class ATL_NO_VTABLE CMultiFileDialogImpl : public CFileDialogImpl< T >
473 {
474 public:
475 	mutable LPCTSTR m_pNextFile;
476 #ifndef _UNICODE
477 	bool m_bIsNT;
478 #endif
479 
480 	CMultiFileDialogImpl(
481 		LPCTSTR lpszDefExt = NULL,
482 		LPCTSTR lpszFileName = NULL,
483 		DWORD dwFlags = OFN_HIDEREADONLY,
484 		LPCTSTR lpszFilter = NULL,
485 		HWND hWndParent = NULL)
486 		: CFileDialogImpl<T>(TRUE, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent),
487 		  m_pNextFile(NULL)
488 	{
489 		m_ofn.Flags |= OFN_ALLOWMULTISELECT;   // Force multiple selection mode
490 
491 #ifndef _UNICODE
492 #ifdef _versionhelpers_H_INCLUDED_
493 		OSVERSIONINFOEX ovi = { sizeof(OSVERSIONINFOEX) };
494 		ovi.dwPlatformId = VER_PLATFORM_WIN32_NT;
495 		DWORDLONG const dwlConditionMask = ::VerSetConditionMask(0, VER_PLATFORMID, VER_EQUAL);
496 		m_bIsNT = (::VerifyVersionInfo(&ovi, VER_PLATFORMID, dwlConditionMask) != FALSE);
497 #else // !_versionhelpers_H_INCLUDED_
498 		OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };
499 		::GetVersionEx(&ovi);
500 		m_bIsNT = (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT);
501 #endif // _versionhelpers_H_INCLUDED_
502 		if (m_bIsNT)
503 		{
504 			// On NT platforms, GetOpenFileNameA thunks to GetOpenFileNameW and there
505 			// is absolutely nothing we can do except to start off with a large buffer.
506 			ATLVERIFY(ResizeFilenameBuffer(_WTL_FIXED_OFN_BUFFER_LENGTH));
507 		}
508 #endif
509 	}
510 
~CMultiFileDialogImpl()511 	~CMultiFileDialogImpl()
512 	{
513 		if (m_ofn.lpstrFile != m_szFileName)   // Free the buffer if we allocated it
514 			delete[] m_ofn.lpstrFile;
515 	}
516 
517 // Operations
518 	// Get the directory that the files were chosen from.
519 	// The function returns the number of characters copied, not including the terminating zero.
520 	// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
521 	// If the function fails, the return value is zero.
GetDirectory(LPTSTR pBuffer,int nBufLen)522 	int GetDirectory(LPTSTR pBuffer, int nBufLen) const
523 	{
524 		if (m_ofn.lpstrFile == NULL)
525 			return 0;
526 
527 		LPCTSTR pStr = m_ofn.lpstrFile;
528 		int nLength = lstrlen(pStr);
529 		if (pStr[nLength + 1] == 0)
530 		{
531 			// The OFN buffer contains a single item so extract its path.
532 			LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\'));
533 			if (pSep != NULL)
534 				nLength = (int)(DWORD_PTR)(pSep - pStr);
535 		}
536 
537 		int nRet = 0;
538 		if (pBuffer == NULL)   // If the buffer is NULL, return the required length
539 		{
540 			nRet = nLength + 1;
541 		}
542 		else if (nBufLen > nLength)
543 		{
544 			SecureHelper::strncpy_x(pBuffer, nBufLen, pStr, nLength);
545 			nRet = nLength;
546 		}
547 
548 		return nRet;
549 	}
550 
551 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
GetDirectory(_CSTRING_NS::CString & strDir)552 	bool GetDirectory(_CSTRING_NS::CString& strDir) const
553 	{
554 		bool bRet = false;
555 
556 		int nLength = GetDirectory(NULL, 0);
557 		if (nLength > 0)
558 		{
559 			bRet = (GetDirectory(strDir.GetBuffer(nLength), nLength) > 0);
560 			strDir.ReleaseBuffer(nLength - 1);
561 		}
562 
563 		return bRet;
564 	}
565 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
566 
567 	// Get the first filename as a pointer into the buffer.
GetFirstFileName()568 	LPCTSTR GetFirstFileName() const
569 	{
570 		if (m_ofn.lpstrFile == NULL)
571 			return NULL;
572 
573 		m_pNextFile = NULL;   // Reset internal buffer pointer
574 
575 		LPCTSTR pStr = m_ofn.lpstrFile;
576 		int nLength = lstrlen(pStr);
577 		if (pStr[nLength + 1] != 0)
578 		{
579 			// Multiple items were selected. The first string is the directory,
580 			// so skip forwards to the second string.
581 			pStr += nLength + 1;
582 
583 			// Set up m_pNext so it points to the second item (or null).
584 			m_pNextFile = pStr;
585 			GetNextFileName();
586 		}
587 		else
588 		{
589 			// A single item was selected. Skip forward past the path.
590 			LPCTSTR pSep = MinCrtHelper::_strrchr(pStr, _T('\\'));
591 			if (pSep != NULL)
592 				pStr = pSep + 1;
593 		}
594 
595 		return pStr;
596 	}
597 
598 	// Get the next filename as a pointer into the buffer.
GetNextFileName()599 	LPCTSTR GetNextFileName() const
600 	{
601 		if (m_pNextFile == NULL)
602 			return NULL;
603 
604 		LPCTSTR pStr = m_pNextFile;
605 		// Set "m_pNextFile" to point to the next file name, or null if we
606 		// have reached the last file in the list.
607 		int nLength = lstrlen(pStr);
608 		m_pNextFile = (pStr[nLength + 1] != 0) ? &pStr[nLength + 1] : NULL;
609 
610 		return pStr;
611 	}
612 
613 	// Get the first filename as a full path.
614 	// The function returns the number of characters copied, not including the terminating zero.
615 	// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
616 	// If the function fails, the return value is zero.
GetFirstPathName(LPTSTR pBuffer,int nBufLen)617 	int GetFirstPathName(LPTSTR pBuffer, int nBufLen) const
618 	{
619 		LPCTSTR pStr = GetFirstFileName();
620 		int nLengthDir = GetDirectory(NULL, 0);
621 		if((pStr == NULL) || (nLengthDir == 0))
622 			return 0;
623 
624 		// Figure out the required length.
625 		int nLengthTotal = nLengthDir + lstrlen(pStr);
626 
627 		int nRet = 0;
628 		if(pBuffer == NULL) // If the buffer is NULL, return the required length
629 		{
630 			nRet = nLengthTotal + 1;
631 		}
632 		else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
633 		{
634 			GetDirectory(pBuffer, nBufLen);
635 			SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
636 			SecureHelper::strcat_x(pBuffer, nBufLen, pStr);
637 			nRet = nLengthTotal;
638 		}
639 
640 		return nRet;
641 	}
642 
643 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
GetFirstPathName(_CSTRING_NS::CString & strPath)644 	bool GetFirstPathName(_CSTRING_NS::CString& strPath) const
645 	{
646 		bool bRet = false;
647 
648 		int nLength = GetFirstPathName(NULL, 0);
649 		if (nLength > 0)
650 		{
651 			bRet = (GetFirstPathName(strPath.GetBuffer(nLength), nLength) > 0);
652 			strPath.ReleaseBuffer(nLength - 1);
653 		}
654 
655 		return bRet;
656 	}
657 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
658 
659 	// Get the next filename as a full path.
660 	// The function returns the number of characters copied, not including the terminating zero.
661 	// If the buffer is NULL, the function returns the required size, in characters, including the terminating zero.
662 	// If the function fails, the return value is zero.
663 	// The internal position marker is moved forward only if the function succeeds and the buffer was large enough.
GetNextPathName(LPTSTR pBuffer,int nBufLen)664 	int GetNextPathName(LPTSTR pBuffer, int nBufLen) const
665 	{
666 		if (m_pNextFile == NULL)
667 			return 0;
668 
669 		int nRet = 0;
670 		LPCTSTR pStr = m_pNextFile;
671 		// Does the filename contain a backslash?
672 		if (MinCrtHelper::_strrchr(pStr, _T('\\')) != NULL)
673 		{
674 			// Yes, so we'll assume it's a full path.
675 			int nLength = lstrlen(pStr);
676 
677 			if (pBuffer == NULL) // If the buffer is NULL, return the required length
678 			{
679 				nRet = nLength + 1;
680 			}
681 			else if (nBufLen > nLength) // The buffer is big enough, so go ahead and copy the filename
682 			{
683 				SecureHelper::strcpy_x(pBuffer, nBufLen, GetNextFileName());
684 				nRet = nBufLen;
685 			}
686 		}
687 		else
688 		{
689 			// The filename is relative, so construct the full path.
690 			int nLengthDir = GetDirectory(NULL, 0);
691 			if (nLengthDir > 0)
692 			{
693 				// Calculate the required space.
694 				int nLengthTotal = nLengthDir + lstrlen(pStr);
695 
696 				if(pBuffer == NULL) // If the buffer is NULL, return the required length
697 				{
698 					nRet = nLengthTotal + 1;
699 				}
700 				else if (nBufLen > nLengthTotal) // If the buffer is big enough, go ahead and construct the path
701 				{
702 					GetDirectory(pBuffer, nBufLen);
703 					SecureHelper::strcat_x(pBuffer, nBufLen, _T("\\"));
704 					SecureHelper::strcat_x(pBuffer, nBufLen, GetNextFileName());
705 					nRet = nLengthTotal;
706 				}
707 			}
708 		}
709 
710 		return nRet;
711 	}
712 
713 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
GetNextPathName(_CSTRING_NS::CString & strPath)714 	bool GetNextPathName(_CSTRING_NS::CString& strPath) const
715 	{
716 		bool bRet = false;
717 
718 		int nLength = GetNextPathName(NULL, 0);
719 		if (nLength > 0)
720 		{
721 			bRet = (GetNextPathName(strPath.GetBuffer(nLength), nLength) > 0);
722 			strPath.ReleaseBuffer(nLength - 1);
723 		}
724 
725 		return bRet;
726 	}
727 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
728 
729 // Implementation
ResizeFilenameBuffer(DWORD dwLength)730 	bool ResizeFilenameBuffer(DWORD dwLength)
731 	{
732 		if (dwLength > m_ofn.nMaxFile)
733 		{
734 			// Free the old buffer.
735 			if (m_ofn.lpstrFile != m_szFileName)
736 			{
737 				delete[] m_ofn.lpstrFile;
738 				m_ofn.lpstrFile = NULL;
739 				m_ofn.nMaxFile = 0;
740 			}
741 
742 			// Allocate the new buffer.
743 			LPTSTR lpstrBuff = NULL;
744 			ATLTRY(lpstrBuff = new TCHAR[dwLength]);
745 			if (lpstrBuff != NULL)
746 			{
747 				m_ofn.lpstrFile = lpstrBuff;
748 				m_ofn.lpstrFile[0] = 0;
749 				m_ofn.nMaxFile = dwLength;
750 			}
751 		}
752 
753 		return (m_ofn.lpstrFile != NULL);
754 	}
755 
OnSelChange(LPOFNOTIFY)756 	void OnSelChange(LPOFNOTIFY /*lpon*/)
757 	{
758 #ifndef _UNICODE
759 		// There is no point resizing the buffer in ANSI builds running on NT.
760 		if (m_bIsNT)
761 			return;
762 #endif
763 
764 		// Get the buffer length required to hold the spec.
765 		int nLength = GetSpec(NULL, 0);
766 		if (nLength <= 1)
767 			return; // no files are selected, presumably
768 
769 		// Add room for the directory, and an extra terminating zero.
770 		nLength += GetFolderPath(NULL, 0) + 1;
771 
772 		if (!ResizeFilenameBuffer(nLength))
773 		{
774 			ATLASSERT(FALSE);
775 			return;
776 		}
777 
778 		// If we are not following links then our work is done.
779 		if ((m_ofn.Flags & OFN_NODEREFERENCELINKS) != 0)
780 			return;
781 
782 		// Get the file spec, which is the text in the edit control.
783 		if (GetSpec(m_ofn.lpstrFile, m_ofn.nMaxFile) <= 0)
784 			return;
785 
786 		// Get the ID-list of the current folder.
787 		int nBytes = GetFolderIDList(NULL, 0);
788 #ifdef STRICT_TYPED_ITEMIDS
789 		CTempBuffer<ITEMIDLIST_RELATIVE> idlist;
790 #else
791 		CTempBuffer<ITEMIDLIST> idlist;
792 #endif
793 		idlist.AllocateBytes(nBytes);
794 		if ((nBytes <= 0) || (GetFolderIDList(idlist, nBytes) <= 0))
795 			return;
796 
797 		// First bind to the desktop folder, then to the current folder.
798 		ATL::CComPtr<IShellFolder> pDesktop, pFolder;
799 		if (FAILED(::SHGetDesktopFolder(&pDesktop)))
800 			return;
801 		if (FAILED(pDesktop->BindToObject(idlist, NULL, IID_IShellFolder, (void**)&pFolder)))
802 			return;
803 
804 		// Work through the file spec, looking for quoted filenames. If we find a shortcut file, then
805 		// we need to add enough extra buffer space to hold its target path.
806 		DWORD nExtraChars = 0;
807 		bool bInsideQuotes = false;
808 		LPCTSTR pAnchor = m_ofn.lpstrFile;
809 		LPCTSTR pChar = m_ofn.lpstrFile;
810 		for ( ; *pChar; ++pChar)
811 		{
812 			// Look for quotation marks.
813 			if (*pChar == _T('\"'))
814 			{
815 				// We are either entering or leaving a passage of quoted text.
816 				bInsideQuotes = !bInsideQuotes;
817 
818 				// Is it an opening or closing quote?
819 				if (bInsideQuotes)
820 				{
821 					// We found an opening quote, so set "pAnchor" to the following character.
822 					pAnchor = pChar + 1;
823 				}
824 				else // closing quote
825 				{
826 					// Each quoted entity should be shorter than MAX_PATH.
827 					if (pChar - pAnchor >= MAX_PATH)
828 						return;
829 
830 					// Get the ID-list and attributes of the file.
831 					USES_CONVERSION;
832 					int nFileNameLength = (int)(DWORD_PTR)(pChar - pAnchor);
833 					TCHAR szFileName[MAX_PATH] = { 0 };
834 					SecureHelper::strncpy_x(szFileName, MAX_PATH, pAnchor, nFileNameLength);
835 #ifdef STRICT_TYPED_ITEMIDS
836 					PIDLIST_RELATIVE pidl = NULL;
837 #else
838 					LPITEMIDLIST pidl = NULL;
839 #endif
840 					DWORD dwAttrib = SFGAO_LINK;
841 					if (SUCCEEDED(pFolder->ParseDisplayName(NULL, NULL, T2W(szFileName), NULL, &pidl, &dwAttrib)))
842 					{
843 						// Is it a shortcut file?
844 						if (dwAttrib & SFGAO_LINK)
845 						{
846 							// Bind to its IShellLink interface.
847 							ATL::CComPtr<IShellLink> pLink;
848 							if (SUCCEEDED(pFolder->BindToObject(pidl, NULL, IID_IShellLink, (void**)&pLink)))
849 							{
850 								// Get the shortcut's target path.
851 								TCHAR szPath[MAX_PATH] = { 0 };
852 								if (SUCCEEDED(pLink->GetPath(szPath, MAX_PATH, NULL, 0)))
853 								{
854 									// If the target path is longer than the shortcut name, then add on the number
855 									// of extra characters that are required.
856 									int nNewLength = lstrlen(szPath);
857 									if (nNewLength > nFileNameLength)
858 										nExtraChars += nNewLength - nFileNameLength;
859 								}
860 							}
861 						}
862 
863 						// Free the ID-list returned by ParseDisplayName.
864 						::CoTaskMemFree(pidl);
865 					}
866 				}
867 			}
868 		}
869 
870 		// If we need more space for shortcut targets, then reallocate.
871 		if (nExtraChars > 0)
872 			ATLVERIFY(ResizeFilenameBuffer(m_ofn.nMaxFile + nExtraChars));
873 	}
874 };
875 
876 class CMultiFileDialog : public CMultiFileDialogImpl<CMultiFileDialog>
877 {
878 public:
879 	CMultiFileDialog(
880 		LPCTSTR lpszDefExt = NULL,
881 		LPCTSTR lpszFileName = NULL,
882 		DWORD dwFlags = OFN_HIDEREADONLY,
883 		LPCTSTR lpszFilter = NULL,
884 		HWND hWndParent = NULL)
885 		: CMultiFileDialogImpl<CMultiFileDialog>(lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
886 	{ }
887 
888 	BEGIN_MSG_MAP(CMultiFileDialog)
889 		CHAIN_MSG_MAP(CMultiFileDialogImpl<CMultiFileDialog>)
890 	END_MSG_MAP()
891 };
892 
893 #endif // !_WIN32_WCE
894 
895 
896 ///////////////////////////////////////////////////////////////////////////////
897 // Shell File Dialog - new Shell File Open and Save dialogs in Vista
898 
899 // Note: Use GetPtr() to access dialog interface methods.
900 // Example:
901 //	CShellFileOpenDialog dlg;
902 //	dlg.GetPtr()->SetTitle(L"MyFileOpenDialog");
903 
904 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
905 
906 ///////////////////////////////////////////////////////////////////////////////
907 // CShellFileDialogImpl - base class for CShellFileOpenDialogImpl and CShellFileSaveDialogImpl
908 
909 template <class T>
910 class ATL_NO_VTABLE CShellFileDialogImpl : public IFileDialogEvents
911 {
912 public:
913 // Operations
914 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
915 	{
916 		INT_PTR nRet = -1;
917 
918 		T* pT = static_cast<T*>(this);
919 		if(pT->m_spFileDlg == NULL)
920 		{
921 			ATLASSERT(FALSE);
922 			return nRet;
923 		}
924 
925 		DWORD dwCookie = 0;
926 		pT->_Advise(dwCookie);
927 
928 		HRESULT hRet = pT->m_spFileDlg->Show(hWndParent);
929 		if(SUCCEEDED(hRet))
930 			nRet = IDOK;
931 		else if(hRet == HRESULT_FROM_WIN32(ERROR_CANCELLED))
932 			nRet = IDCANCEL;
933 		else
934 			ATLASSERT(FALSE);   // error
935 
936 		pT->_Unadvise(dwCookie);
937 
938 		return nRet;
939 	}
940 
IsNull()941 	bool IsNull() const
942 	{
943 		const T* pT = static_cast<const T*>(this);
944 		return (pT->m_spFileDlg == NULL);
945 	}
946 
947 // Operations - get file path after dialog returns
GetFilePath(LPWSTR lpstrFilePath,int cchLength)948 	HRESULT GetFilePath(LPWSTR lpstrFilePath, int cchLength)
949 	{
950 		T* pT = static_cast<T*>(this);
951 		ATLASSERT(pT->m_spFileDlg != NULL);
952 
953 		ATL::CComPtr<IShellItem> spItem;
954 		HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
955 
956 		if(SUCCEEDED(hRet))
957 			hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, lpstrFilePath, cchLength);
958 
959 		return hRet;
960 	}
961 
GetFileTitle(LPWSTR lpstrFileTitle,int cchLength)962 	HRESULT GetFileTitle(LPWSTR lpstrFileTitle, int cchLength)
963 	{
964 		T* pT = static_cast<T*>(this);
965 		ATLASSERT(pT->m_spFileDlg != NULL);
966 
967 		ATL::CComPtr<IShellItem> spItem;
968 		HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
969 
970 		if(SUCCEEDED(hRet))
971 			hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, lpstrFileTitle, cchLength);
972 
973 		return hRet;
974 	}
975 
976 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
GetFilePath(_CSTRING_NS::CString & strFilePath)977 	HRESULT GetFilePath(_CSTRING_NS::CString& strFilePath)
978 	{
979 		T* pT = static_cast<T*>(this);
980 		ATLASSERT(pT->m_spFileDlg != NULL);
981 
982 		ATL::CComPtr<IShellItem> spItem;
983 		HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
984 
985 		if(SUCCEEDED(hRet))
986 			hRet = GetFileNameFromShellItem(spItem, SIGDN_FILESYSPATH, strFilePath);
987 
988 		return hRet;
989 	}
990 
GetFileTitle(_CSTRING_NS::CString & strFileTitle)991 	HRESULT GetFileTitle(_CSTRING_NS::CString& strFileTitle)
992 	{
993 		T* pT = static_cast<T*>(this);
994 		ATLASSERT(pT->m_spFileDlg != NULL);
995 
996 		ATL::CComPtr<IShellItem> spItem;
997 		HRESULT hRet = pT->m_spFileDlg->GetResult(&spItem);
998 
999 		if(SUCCEEDED(hRet))
1000 			hRet = GetFileNameFromShellItem(spItem, SIGDN_NORMALDISPLAY, strFileTitle);
1001 
1002 		return hRet;
1003 	}
1004 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
1005 
1006 // Helpers for IShellItem
GetFileNameFromShellItem(IShellItem * pShellItem,SIGDN type,LPWSTR lpstr,int cchLength)1007 	static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, LPWSTR lpstr, int cchLength)
1008 	{
1009 		ATLASSERT(pShellItem != NULL);
1010 
1011 		LPWSTR lpstrName = NULL;
1012 		HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
1013 
1014 		if(SUCCEEDED(hRet))
1015 		{
1016 			if(lstrlenW(lpstrName) < cchLength)
1017 			{
1018 				SecureHelper::strcpyW_x(lpstr, cchLength, lpstrName);
1019 			}
1020 			else
1021 			{
1022 				ATLASSERT(FALSE);
1023 				hRet = DISP_E_BUFFERTOOSMALL;
1024 			}
1025 
1026 			::CoTaskMemFree(lpstrName);
1027 		}
1028 
1029 		return hRet;
1030 	}
1031 
1032 #if defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
GetFileNameFromShellItem(IShellItem * pShellItem,SIGDN type,_CSTRING_NS::CString & str)1033 	static HRESULT GetFileNameFromShellItem(IShellItem* pShellItem, SIGDN type, _CSTRING_NS::CString& str)
1034 	{
1035 		ATLASSERT(pShellItem != NULL);
1036 
1037 		LPWSTR lpstrName = NULL;
1038 		HRESULT hRet = pShellItem->GetDisplayName(type, &lpstrName);
1039 
1040 		if(SUCCEEDED(hRet))
1041 		{
1042 			str = lpstrName;
1043 			::CoTaskMemFree(lpstrName);
1044 		}
1045 
1046 		return hRet;
1047 	}
1048 #endif // defined(_WTL_USE_CSTRING) || defined(__ATLSTR_H__)
1049 
1050 // Implementation
_Advise(DWORD & dwCookie)1051 	void _Advise(DWORD& dwCookie)
1052 	{
1053 		T* pT = static_cast<T*>(this);
1054 		ATLASSERT(pT->m_spFileDlg != NULL);
1055 		HRESULT hRet = pT->m_spFileDlg->Advise((IFileDialogEvents*)this, &dwCookie);
1056 		ATLVERIFY(SUCCEEDED(hRet));
1057 	}
1058 
_Unadvise(DWORD dwCookie)1059 	void _Unadvise(DWORD dwCookie)
1060 	{
1061 		T* pT = static_cast<T*>(this);
1062 		ATLASSERT(pT->m_spFileDlg != NULL);
1063 		HRESULT hRet = pT->m_spFileDlg->Unadvise(dwCookie);
1064 		ATLVERIFY(SUCCEEDED(hRet));
1065 	}
1066 
_Init(LPCWSTR lpszFileName,DWORD dwOptions,LPCWSTR lpszDefExt,const COMDLG_FILTERSPEC * arrFilterSpec,UINT uFilterSpecCount)1067 	void _Init(LPCWSTR lpszFileName, DWORD dwOptions, LPCWSTR lpszDefExt, const COMDLG_FILTERSPEC* arrFilterSpec, UINT uFilterSpecCount)
1068 	{
1069 		T* pT = static_cast<T*>(this);
1070 		ATLASSERT(pT->m_spFileDlg != NULL);
1071 
1072 		HRESULT hRet = E_FAIL;
1073 
1074 		if(lpszFileName != NULL)
1075 		{
1076 			hRet = pT->m_spFileDlg->SetFileName(lpszFileName);
1077 			ATLASSERT(SUCCEEDED(hRet));
1078 		}
1079 
1080 		hRet = pT->m_spFileDlg->SetOptions(dwOptions);
1081 		ATLASSERT(SUCCEEDED(hRet));
1082 
1083 		if(lpszDefExt != NULL)
1084 		{
1085 			hRet = pT->m_spFileDlg->SetDefaultExtension(lpszDefExt);
1086 			ATLASSERT(SUCCEEDED(hRet));
1087 		}
1088 
1089 		if(arrFilterSpec != NULL && uFilterSpecCount != 0U)
1090 		{
1091 			hRet = pT->m_spFileDlg->SetFileTypes(uFilterSpecCount, arrFilterSpec);
1092 			ATLASSERT(SUCCEEDED(hRet));
1093 		}
1094 	}
1095 
1096 // Implementation - IUnknown interface
STDMETHOD(QueryInterface)1097 	STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
1098 	{
1099 		if(ppvObject == NULL)
1100 			return E_POINTER;
1101 
1102 		T* pT = static_cast<T*>(this);
1103 		if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IFileDialogEvents))
1104 		{
1105 			*ppvObject = (IFileDialogEvents*)pT;
1106 			// AddRef() not needed
1107 			return S_OK;
1108 		}
1109 
1110 		return E_NOINTERFACE;
1111 	}
1112 
AddRef()1113 	virtual ULONG STDMETHODCALLTYPE AddRef()
1114 	{
1115 		return 1;
1116 	}
1117 
Release()1118 	virtual ULONG STDMETHODCALLTYPE Release()
1119 	{
1120 		return 1;
1121 	}
1122 
1123 // Implementation - IFileDialogEvents interface
OnFileOk(IFileDialog * pfd)1124 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFileOk(IFileDialog* pfd)
1125 	{
1126 		T* pT = static_cast<T*>(this);
1127 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1128 		pfd;   // avoid level 4 warning
1129 		return pT->OnFileOk();
1130 	}
1131 
OnFolderChanging(IFileDialog * pfd,IShellItem * psiFolder)1132 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder)
1133 	{
1134 		T* pT = static_cast<T*>(this);
1135 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1136 		pfd;   // avoid level 4 warning
1137 		return pT->OnFolderChanging(psiFolder);
1138 	}
1139 
OnFolderChange(IFileDialog * pfd)1140 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnFolderChange(IFileDialog* pfd)
1141 	{
1142 		T* pT = static_cast<T*>(this);
1143 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1144 		pfd;   // avoid level 4 warning
1145 		return pT->OnFolderChange();
1146 	}
1147 
OnSelectionChange(IFileDialog * pfd)1148 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnSelectionChange(IFileDialog* pfd)
1149 	{
1150 		T* pT = static_cast<T*>(this);
1151 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1152 		pfd;   // avoid level 4 warning
1153 		return pT->OnSelectionChange();
1154 	}
1155 
OnShareViolation(IFileDialog * pfd,IShellItem * psi,FDE_SHAREVIOLATION_RESPONSE * pResponse)1156 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnShareViolation(IFileDialog* pfd, IShellItem* psi, FDE_SHAREVIOLATION_RESPONSE* pResponse)
1157 	{
1158 		T* pT = static_cast<T*>(this);
1159 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1160 		pfd;   // avoid level 4 warning
1161 		return pT->OnShareViolation(psi, pResponse);
1162 	}
1163 
OnTypeChange(IFileDialog * pfd)1164 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnTypeChange(IFileDialog* pfd)
1165 	{
1166 		T* pT = static_cast<T*>(this);
1167 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1168 		pfd;   // avoid level 4 warning
1169 		return pT->OnTypeChange();
1170 	}
1171 
OnOverwrite(IFileDialog * pfd,IShellItem * psi,FDE_OVERWRITE_RESPONSE * pResponse)1172 	virtual HRESULT STDMETHODCALLTYPE IFileDialogEvents::OnOverwrite(IFileDialog* pfd, IShellItem* psi, FDE_OVERWRITE_RESPONSE* pResponse)
1173 	{
1174 		T* pT = static_cast<T*>(this);
1175 		ATLASSERT(pT->m_spFileDlg.IsEqualObject(pfd));
1176 		pfd;   // avoid level 4 warning
1177 		return pT->OnOverwrite(psi, pResponse);
1178 	}
1179 
1180 // Overrideables - Event handlers
OnFileOk()1181 	HRESULT OnFileOk()
1182 	{
1183 		return E_NOTIMPL;
1184 	}
1185 
OnFolderChanging(IShellItem *)1186 	HRESULT OnFolderChanging(IShellItem* /*psiFolder*/)
1187 	{
1188 		return E_NOTIMPL;
1189 	}
1190 
OnFolderChange()1191 	HRESULT OnFolderChange()
1192 	{
1193 		return E_NOTIMPL;
1194 	}
1195 
OnSelectionChange()1196 	HRESULT OnSelectionChange()
1197 	{
1198 		return E_NOTIMPL;
1199 	}
1200 
OnShareViolation(IShellItem *,FDE_SHAREVIOLATION_RESPONSE *)1201 	HRESULT OnShareViolation(IShellItem* /*psi*/, FDE_SHAREVIOLATION_RESPONSE* /*pResponse*/)
1202 	{
1203 		return E_NOTIMPL;
1204 	}
1205 
OnTypeChange()1206 	HRESULT OnTypeChange()
1207 	{
1208 		return E_NOTIMPL;
1209 	}
1210 
OnOverwrite(IShellItem *,FDE_OVERWRITE_RESPONSE *)1211 	HRESULT OnOverwrite(IShellItem* /*psi*/, FDE_OVERWRITE_RESPONSE* /*pResponse*/)
1212 	{
1213 		return E_NOTIMPL;
1214 	}
1215 };
1216 
1217 
1218 ///////////////////////////////////////////////////////////////////////////////
1219 // CShellFileOpenDialogImpl - implements new Shell File Open dialog
1220 
1221 template <class T>
1222 class ATL_NO_VTABLE CShellFileOpenDialogImpl : public CShellFileDialogImpl< T >
1223 {
1224 public:
1225 	ATL::CComPtr<IFileOpenDialog> m_spFileDlg;
1226 
1227 	CShellFileOpenDialogImpl(LPCWSTR lpszFileName = NULL,
1228 	                         DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST,
1229 	                         LPCWSTR lpszDefExt = NULL,
1230 	                         const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
1231 	                         UINT uFilterSpecCount = 0U)
1232 	{
1233 		HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileOpenDialog);
1234 
1235 		if(SUCCEEDED(hRet))
1236 			_Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
1237 	}
1238 
GetPtr()1239 	IFileOpenDialog* GetPtr()
1240 	{
1241 		return m_spFileDlg;
1242 	}
1243 };
1244 
1245 
1246 ///////////////////////////////////////////////////////////////////////////////
1247 // CShellFileOpenDialog - new Shell File Open dialog without events
1248 
1249 class CShellFileOpenDialog : public CShellFileOpenDialogImpl<CShellFileOpenDialog>
1250 {
1251 public:
1252 	CShellFileOpenDialog(LPCWSTR lpszFileName = NULL,
1253 	                     DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST,
1254 	                     LPCWSTR lpszDefExt = NULL,
1255 	                     const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
1256 	                     UINT uFilterSpecCount = 0U) : CShellFileOpenDialogImpl<CShellFileOpenDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
1257 	{ }
1258 
1259 // Implementation (remove _Advise/_Unadvise code using template magic)
_Advise(DWORD &)1260 	void _Advise(DWORD& /*dwCookie*/)
1261 	{ }
1262 
_Unadvise(DWORD)1263 	void _Unadvise(DWORD /*dwCookie*/)
1264 	{ }
1265 };
1266 
1267 
1268 ///////////////////////////////////////////////////////////////////////////////
1269 // CShellFileSaveDialogImpl - implements new Shell File Save dialog
1270 
1271 template <class T>
1272 class ATL_NO_VTABLE CShellFileSaveDialogImpl : public CShellFileDialogImpl< T >
1273 {
1274 public:
1275 	ATL::CComPtr<IFileSaveDialog> m_spFileDlg;
1276 
1277 	CShellFileSaveDialogImpl(LPCWSTR lpszFileName = NULL,
1278 	                         DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
1279 	                         LPCWSTR lpszDefExt = NULL,
1280 	                         const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
1281 	                         UINT uFilterSpecCount = 0U)
1282 	{
1283 		HRESULT hRet = m_spFileDlg.CoCreateInstance(CLSID_FileSaveDialog);
1284 
1285 		if(SUCCEEDED(hRet))
1286 			_Init(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount);
1287 	}
1288 
GetPtr()1289 	IFileSaveDialog* GetPtr()
1290 	{
1291 		return m_spFileDlg;
1292 	}
1293 };
1294 
1295 
1296 ///////////////////////////////////////////////////////////////////////////////
1297 // CShellFileSaveDialog - new Shell File Save dialog without events
1298 
1299 class CShellFileSaveDialog : public CShellFileSaveDialogImpl<CShellFileSaveDialog>
1300 {
1301 public:
1302 	CShellFileSaveDialog(LPCWSTR lpszFileName = NULL,
1303 	                     DWORD dwOptions = FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_OVERWRITEPROMPT,
1304 	                     LPCWSTR lpszDefExt = NULL,
1305 	                     const COMDLG_FILTERSPEC* arrFilterSpec = NULL,
1306 	                     UINT uFilterSpecCount = 0U) : CShellFileSaveDialogImpl<CShellFileSaveDialog>(lpszFileName, dwOptions, lpszDefExt, arrFilterSpec, uFilterSpecCount)
1307 	{ }
1308 
1309 // Implementation (remove _Advise/_Unadvise code using template magic)
_Advise(DWORD &)1310 	void _Advise(DWORD& /*dwCookie*/)
1311 	{ }
1312 
_Unadvise(DWORD)1313 	void _Unadvise(DWORD /*dwCookie*/)
1314 	{ }
1315 };
1316 
1317 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
1318 
1319 
1320 ///////////////////////////////////////////////////////////////////////////////
1321 // CFolderDialogImpl - used for browsing for a folder
1322 
1323 #ifndef _WIN32_WCE
1324 
1325 template <class T>
1326 class ATL_NO_VTABLE CFolderDialogImpl
1327 {
1328 public:
1329 	BROWSEINFO m_bi;
1330 	LPCTSTR m_lpstrInitialFolder;
1331 	LPCITEMIDLIST m_pidlInitialSelection;
1332 	bool m_bExpandInitialSelection;
1333 	TCHAR m_szFolderDisplayName[MAX_PATH];
1334 	TCHAR m_szFolderPath[MAX_PATH];
1335 #ifdef STRICT_TYPED_ITEMIDS
1336 	PIDLIST_ABSOLUTE m_pidlSelected;
1337 #else
1338 	LPITEMIDLIST m_pidlSelected;
1339 #endif
1340 	HWND m_hWnd;   // used only in the callback function
1341 
1342 // Constructor
1343 	CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) :
m_lpstrInitialFolder(NULL)1344 			m_lpstrInitialFolder(NULL), m_pidlInitialSelection(NULL), m_bExpandInitialSelection(false), m_pidlSelected(NULL), m_hWnd(NULL)
1345 	{
1346 		memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL
1347 
1348 		m_bi.hwndOwner = hWndParent;
1349 		m_bi.pidlRoot = NULL;
1350 		m_bi.pszDisplayName = m_szFolderDisplayName;
1351 		m_bi.lpszTitle = lpstrTitle;
1352 		m_bi.ulFlags = uFlags;
1353 		m_bi.lpfn = BrowseCallbackProc;
1354 		m_bi.lParam = (LPARAM)static_cast<T*>(this);
1355 
1356 		m_szFolderPath[0] = 0;
1357 		m_szFolderDisplayName[0] = 0;
1358 	}
1359 
~CFolderDialogImpl()1360 	~CFolderDialogImpl()
1361 	{
1362 		::CoTaskMemFree(m_pidlSelected);
1363 	}
1364 
1365 // Operations
1366 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
1367 	{
1368 		if(m_bi.hwndOwner == NULL)   // set only if not specified before
1369 			m_bi.hwndOwner = hWndParent;
1370 
1371 		// Clear out any previous results
1372 		m_szFolderPath[0] = 0;
1373 		m_szFolderDisplayName[0] = 0;
1374 		::CoTaskMemFree(m_pidlSelected);
1375 
1376 		INT_PTR nRet = IDCANCEL;
1377 		m_pidlSelected = ::SHBrowseForFolder(&m_bi);
1378 
1379 		if(m_pidlSelected != NULL)
1380 		{
1381 			nRet = IDOK;
1382 
1383 			// If BIF_RETURNONLYFSDIRS is set, we try to get the filesystem path.
1384 			// Otherwise, the caller must handle the ID-list directly.
1385 			if((m_bi.ulFlags & BIF_RETURNONLYFSDIRS) != 0)
1386 			{
1387 				if(::SHGetPathFromIDList(m_pidlSelected, m_szFolderPath) == FALSE)
1388 					nRet = IDCANCEL;
1389 			}
1390 		}
1391 
1392 		return nRet;
1393 	}
1394 
1395 	// Methods to call before DoModal
1396 	void SetInitialFolder(LPCTSTR lpstrInitialFolder, bool bExpand = true)
1397 	{
1398 		// lpstrInitialFolder may be a file if BIF_BROWSEINCLUDEFILES is specified
1399 		m_lpstrInitialFolder = lpstrInitialFolder;
1400 		m_bExpandInitialSelection = bExpand;
1401 	}
1402 
1403 	void SetInitialSelection(LPCITEMIDLIST pidl, bool bExpand = true)
1404 	{
1405 		m_pidlInitialSelection = pidl;
1406 		m_bExpandInitialSelection = bExpand;
1407 	}
1408 
1409 #ifdef STRICT_TYPED_ITEMIDS
SetRootFolder(PCIDLIST_ABSOLUTE pidl)1410 	void SetRootFolder(PCIDLIST_ABSOLUTE pidl)
1411 #else
1412 	void SetRootFolder(LPCITEMIDLIST pidl)
1413 #endif
1414 	{
1415 		m_bi.pidlRoot = pidl;
1416 	}
1417 
1418 	// Methods to call after DoModal
1419 	LPITEMIDLIST GetSelectedItem(bool bDetach = false)
1420 	{
1421 		LPITEMIDLIST pidl = m_pidlSelected;
1422 		if(bDetach)
1423 			m_pidlSelected = NULL;
1424 
1425 		return pidl;
1426 	}
1427 
GetFolderPath()1428 	LPCTSTR GetFolderPath() const
1429 	{
1430 		return m_szFolderPath;
1431 	}
1432 
GetFolderDisplayName()1433 	LPCTSTR GetFolderDisplayName() const
1434 	{
1435 		return m_szFolderDisplayName;
1436 	}
1437 
GetFolderImageIndex()1438 	int GetFolderImageIndex() const
1439 	{
1440 		return m_bi.iImage;
1441 	}
1442 
1443 // Callback function and overrideables
BrowseCallbackProc(HWND hWnd,UINT uMsg,LPARAM lParam,LPARAM lpData)1444 	static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
1445 	{
1446 #ifndef BFFM_VALIDATEFAILED
1447   #ifdef UNICODE
1448 		const int BFFM_VALIDATEFAILED = 4;
1449   #else
1450 		const int BFFM_VALIDATEFAILED = 3;
1451   #endif
1452 #endif // !BFFM_VALIDATEFAILED
1453 #ifndef BFFM_IUNKNOWN
1454 		const int BFFM_IUNKNOWN = 5;
1455 #endif // !BFFM_IUNKNOWN
1456 #ifndef BIF_NEWDIALOGSTYLE
1457 		const UINT BIF_NEWDIALOGSTYLE = 0x0040;
1458 #endif // !BIF_NEWDIALOGSTYLE
1459 
1460 		int nRet = 0;
1461 		T* pT = (T*)lpData;
1462 		bool bClear = false;
1463 		if(pT->m_hWnd == NULL)
1464 		{
1465 			pT->m_hWnd = hWnd;
1466 			bClear = true;
1467 		}
1468 		else
1469 		{
1470 			ATLASSERT(pT->m_hWnd == hWnd);
1471 		}
1472 
1473 		switch(uMsg)
1474 		{
1475 		case BFFM_INITIALIZED:
1476 			// Set initial selection
1477 			// Note that m_pidlInitialSelection, if set, takes precedence over m_lpstrInitialFolder
1478 			if(pT->m_pidlInitialSelection != NULL)
1479 				pT->SetSelection(pT->m_pidlInitialSelection);
1480 			else if(pT->m_lpstrInitialFolder != NULL)
1481 				pT->SetSelection(pT->m_lpstrInitialFolder);
1482 
1483 			// Expand initial selection if appropriate
1484 			if(pT->m_bExpandInitialSelection && ((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0))
1485 			{
1486 				if(pT->m_pidlInitialSelection != NULL)
1487 					pT->SetExpanded(pT->m_pidlInitialSelection);
1488 				else if(pT->m_lpstrInitialFolder != NULL)
1489 					pT->SetExpanded(pT->m_lpstrInitialFolder);
1490 			}
1491 			pT->OnInitialized();
1492 			break;
1493 		case BFFM_SELCHANGED:
1494 			pT->OnSelChanged((LPITEMIDLIST)lParam);
1495 			break;
1496 		case BFFM_VALIDATEFAILED:
1497 			nRet = pT->OnValidateFailed((LPCTSTR)lParam);
1498 			break;
1499 		case BFFM_IUNKNOWN:
1500 			pT->OnIUnknown((IUnknown*)lParam);
1501 			break;
1502 		default:
1503 			ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n"));
1504 			break;
1505 		}
1506 
1507 		if(bClear)
1508 			pT->m_hWnd = NULL;
1509 		return nRet;
1510 	}
1511 
OnInitialized()1512 	void OnInitialized()
1513 	{
1514 	}
1515 
OnSelChanged(LPITEMIDLIST)1516 	void OnSelChanged(LPITEMIDLIST /*pItemIDList*/)
1517 	{
1518 	}
1519 
OnValidateFailed(LPCTSTR)1520 	int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/)
1521 	{
1522 		return 1;   // 1=continue, 0=EndDialog
1523 	}
1524 
OnIUnknown(IUnknown *)1525 	void OnIUnknown(IUnknown* /*pUnknown*/)
1526 	{
1527 	}
1528 
1529 	// Commands - valid to call only from handlers
EnableOK(BOOL bEnable)1530 	void EnableOK(BOOL bEnable)
1531 	{
1532 		ATLASSERT(m_hWnd != NULL);
1533 		::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable);
1534 	}
1535 
SetSelection(LPCITEMIDLIST pItemIDList)1536 	void SetSelection(LPCITEMIDLIST pItemIDList)
1537 	{
1538 		ATLASSERT(m_hWnd != NULL);
1539 		::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList);
1540 	}
1541 
SetSelection(LPCTSTR lpstrFolderPath)1542 	void SetSelection(LPCTSTR lpstrFolderPath)
1543 	{
1544 		ATLASSERT(m_hWnd != NULL);
1545 		::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath);
1546 	}
1547 
SetStatusText(LPCTSTR lpstrText)1548 	void SetStatusText(LPCTSTR lpstrText)
1549 	{
1550 		ATLASSERT(m_hWnd != NULL);
1551 		::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText);
1552 	}
1553 
SetOKText(LPCTSTR lpstrOKText)1554 	void SetOKText(LPCTSTR lpstrOKText)
1555 	{
1556 #ifndef BFFM_SETOKTEXT
1557 		const UINT BFFM_SETOKTEXT = WM_USER + 105;
1558 #endif
1559 		ATLASSERT(m_hWnd != NULL);
1560 		USES_CONVERSION;
1561 		LPCWSTR lpstr = T2CW(lpstrOKText);
1562 		::SendMessage(m_hWnd, BFFM_SETOKTEXT, 0, (LPARAM)lpstr);
1563 	}
1564 
SetExpanded(LPCITEMIDLIST pItemIDList)1565 	void SetExpanded(LPCITEMIDLIST pItemIDList)
1566 	{
1567 #ifndef BFFM_SETEXPANDED
1568 		const UINT BFFM_SETEXPANDED = WM_USER + 106;
1569 #endif
1570 		ATLASSERT(m_hWnd != NULL);
1571 		::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList);
1572 	}
1573 
SetExpanded(LPCTSTR lpstrFolderPath)1574 	void SetExpanded(LPCTSTR lpstrFolderPath)
1575 	{
1576 #ifndef BFFM_SETEXPANDED
1577 		const UINT BFFM_SETEXPANDED = WM_USER + 106;
1578 #endif
1579 		ATLASSERT(m_hWnd != NULL);
1580 		USES_CONVERSION;
1581 		LPCWSTR lpstr = T2CW(lpstrFolderPath);
1582 		::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr);
1583 	}
1584 };
1585 
1586 class CFolderDialog : public CFolderDialogImpl<CFolderDialog>
1587 {
1588 public:
1589 	CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS)
1590 		: CFolderDialogImpl<CFolderDialog>(hWndParent, lpstrTitle, uFlags)
1591 	{ }
1592 };
1593 
1594 #endif // !_WIN32_WCE
1595 
1596 
1597 ///////////////////////////////////////////////////////////////////////////////
1598 // CCommonDialogImplBase - base class for common dialog classes
1599 
1600 class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase
1601 {
1602 public:
HookProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1603 	static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1604 	{
1605 		if(uMsg != WM_INITDIALOG)
1606 			return 0;
1607 		CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
1608 		ATLASSERT(pT != NULL);
1609 		ATLASSERT(pT->m_hWnd == NULL);
1610 		ATLASSERT(::IsWindow(hWnd));
1611 		// subclass dialog's window
1612 		if(!pT->SubclassWindow(hWnd))
1613 		{
1614 			ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n"));
1615 			return 0;
1616 		}
1617 		// check message map for WM_INITDIALOG handler
1618 		LRESULT lRes = 0;
1619 		if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
1620 			return 0;
1621 		return lRes;
1622 	}
1623 
1624 // Special override for common dialogs
1625 	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
1626 	{
1627 		ATLASSERT(::IsWindow(m_hWnd));
1628 		SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
1629 		return TRUE;
1630 	}
1631 
1632 // Implementation - try to override these, to prevent errors
Create(HWND,ATL::_U_RECT,LPCTSTR,DWORD,DWORD,ATL::_U_MENUorID,ATOM,LPVOID)1633 	HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID)
1634 	{
1635 		ATLASSERT(FALSE);   // should not be called
1636 		return NULL;
1637 	}
1638 
StartWindowProc(HWND,UINT,WPARAM,LPARAM)1639 	static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
1640 	{
1641 		ATLASSERT(FALSE);   // should not be called
1642 		return 0;
1643 	}
1644 };
1645 
1646 
1647 ///////////////////////////////////////////////////////////////////////////////
1648 // CFontDialogImpl - font selection dialog
1649 
1650 #ifndef _WIN32_WCE
1651 
1652 template <class T>
1653 class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase
1654 {
1655 public:
1656 	enum { _cchStyleName = 64 };
1657 
1658 	CHOOSEFONT m_cf;
1659 	TCHAR m_szStyleName[_cchStyleName];  // contains style name after return
1660 	LOGFONT m_lf;                        // default LOGFONT to store the info
1661 
1662 // Constructors
1663 	CFontDialogImpl(LPLOGFONT lplfInitial = NULL,
1664 			DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
1665 			HDC hDCPrinter = NULL,
1666 			HWND hWndParent = NULL)
1667 	{
1668 		memset(&m_cf, 0, sizeof(m_cf));
1669 		memset(&m_lf, 0, sizeof(m_lf));
1670 		memset(&m_szStyleName, 0, sizeof(m_szStyleName));
1671 
1672 		m_cf.lStructSize = sizeof(m_cf);
1673 		m_cf.hwndOwner = hWndParent;
1674 		m_cf.rgbColors = RGB(0, 0, 0);
1675 		m_cf.lpszStyle = (LPTSTR)&m_szStyleName;
1676 		m_cf.Flags = dwFlags | CF_ENABLEHOOK;
1677 		m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc;
1678 
1679 		if(lplfInitial != NULL)
1680 		{
1681 			m_cf.lpLogFont = lplfInitial;
1682 			m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1683 			m_lf = *lplfInitial;
1684 		}
1685 		else
1686 		{
1687 			m_cf.lpLogFont = &m_lf;
1688 		}
1689 
1690 		if(hDCPrinter != NULL)
1691 		{
1692 			m_cf.hDC = hDCPrinter;
1693 			m_cf.Flags |= CF_PRINTERFONTS;
1694 		}
1695 	}
1696 
1697 // Operations
1698 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
1699 	{
1700 		ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0);
1701 		ATLASSERT(m_cf.lpfnHook != NULL);   // can still be a user hook
1702 
1703 		if(m_cf.hwndOwner == NULL)          // set only if not specified before
1704 			m_cf.hwndOwner = hWndParent;
1705 
1706 		ATLASSERT(m_hWnd == NULL);
1707 
1708 #if (_ATL_VER >= 0x0800)
1709 		// Allocate the thunk structure here, where we can fail gracefully.
1710 		BOOL bRetTh = m_thunk.Init(NULL, NULL);
1711 		if(bRetTh == FALSE)
1712 		{
1713 			::SetLastError(ERROR_OUTOFMEMORY);
1714 			return -1;
1715 		}
1716 #endif // (_ATL_VER >= 0x0800)
1717 
1718 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
1719 
1720 		BOOL bRet = ::ChooseFont(&m_cf);
1721 
1722 		m_hWnd = NULL;
1723 
1724 		if(bRet)   // copy logical font from user's initialization buffer (if needed)
1725 			SecureHelper::memcpy_x(&m_lf, sizeof(m_lf), m_cf.lpLogFont, sizeof(m_lf));
1726 
1727 		return bRet ? IDOK : IDCANCEL;
1728 	}
1729 
1730 	// works only when the dialog is dislayed or after
GetCurrentFont(LPLOGFONT lplf)1731 	void GetCurrentFont(LPLOGFONT lplf) const
1732 	{
1733 		ATLASSERT(lplf != NULL);
1734 
1735 		if(m_hWnd != NULL)
1736 			::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf);
1737 		else
1738 			*lplf = m_lf;
1739 	}
1740 
1741 	// works only when the dialog is dislayed or before
1742 #ifndef _WIN32_WCE
SetLogFont(LPLOGFONT lplf)1743 	void SetLogFont(LPLOGFONT lplf)
1744 	{
1745 		ATLASSERT(lplf != NULL);
1746 #ifndef WM_CHOOSEFONT_SETLOGFONT
1747 		const UINT WM_CHOOSEFONT_SETLOGFONT = (WM_USER + 101);
1748 #endif
1749 		if(m_hWnd != NULL)
1750 		{
1751 			::SendMessage(m_hWnd, WM_CHOOSEFONT_SETLOGFONT, 0, (LPARAM)lplf);
1752 		}
1753 		else
1754 		{
1755 			m_lf = *lplf;
1756 			m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1757 		}
1758 	}
1759 
SetFlags(DWORD dwFlags)1760 	void SetFlags(DWORD dwFlags)
1761 	{
1762 #ifndef WM_CHOOSEFONT_SETFLAGS
1763 		const UINT WM_CHOOSEFONT_SETFLAGS = (WM_USER + 102);
1764 #endif
1765 		if(m_hWnd != NULL)
1766 		{
1767 			CHOOSEFONT cf = { sizeof(CHOOSEFONT) };
1768 			cf.Flags = dwFlags;
1769 			::SendMessage(m_hWnd, WM_CHOOSEFONT_SETFLAGS, 0, (LPARAM)&cf);
1770 		}
1771 		else
1772 		{
1773 			m_cf.Flags = dwFlags;
1774 		}
1775 	}
1776 #endif // !_WIN32_WCE
1777 
1778 	// Helpers for parsing information after successful return
GetFaceName()1779 	LPCTSTR GetFaceName() const   // return the face name of the font
1780 	{
1781 		return (LPCTSTR)m_cf.lpLogFont->lfFaceName;
1782 	}
1783 
GetStyleName()1784 	LPCTSTR GetStyleName() const  // return the style name of the font
1785 	{
1786 		return m_cf.lpszStyle;
1787 	}
1788 
GetSize()1789 	int GetSize() const           // return the pt size of the font
1790 	{
1791 		return m_cf.iPointSize;
1792 	}
1793 
GetColor()1794 	COLORREF GetColor() const     // return the color of the font
1795 	{
1796 		return m_cf.rgbColors;
1797 	}
1798 
GetWeight()1799 	int GetWeight() const         // return the chosen font weight
1800 	{
1801 		return (int)m_cf.lpLogFont->lfWeight;
1802 	}
1803 
IsStrikeOut()1804 	BOOL IsStrikeOut() const      // return TRUE if strikeout
1805 	{
1806 		return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE;
1807 	}
1808 
IsUnderline()1809 	BOOL IsUnderline() const      // return TRUE if underline
1810 	{
1811 		return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE;
1812 	}
1813 
IsBold()1814 	BOOL IsBold() const           // return TRUE if bold font
1815 	{
1816 		return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE;
1817 	}
1818 
IsItalic()1819 	BOOL IsItalic() const         // return TRUE if italic font
1820 	{
1821 		return m_cf.lpLogFont->lfItalic ? TRUE : FALSE;
1822 	}
1823 };
1824 
1825 class CFontDialog : public CFontDialogImpl<CFontDialog>
1826 {
1827 public:
1828 	CFontDialog(LPLOGFONT lplfInitial = NULL,
1829 		DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
1830 		HDC hDCPrinter = NULL,
1831 		HWND hWndParent = NULL)
1832 		: CFontDialogImpl<CFontDialog>(lplfInitial, dwFlags, hDCPrinter, hWndParent)
1833 	{ }
1834 
1835 	DECLARE_EMPTY_MSG_MAP()
1836 };
1837 
1838 #endif // _WIN32_WCE
1839 
1840 
1841 ///////////////////////////////////////////////////////////////////////////////
1842 // CRichEditFontDialogImpl - font selection for the Rich Edit ctrl
1843 
1844 #if defined(_RICHEDIT_) && !defined(_WIN32_WCE)
1845 
1846 template <class T>
1847 class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T >
1848 {
1849 public:
1850 	CRichEditFontDialogImpl(const CHARFORMAT& charformat,
1851 			DWORD dwFlags = CF_SCREENFONTS,
1852 			HDC hDCPrinter = NULL,
1853 			HWND hWndParent = NULL)
1854 			: CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent)
1855 	{
1856 		m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
1857 		m_cf.Flags |= FillInLogFont(charformat);
1858 		m_cf.lpLogFont = &m_lf;
1859 
1860 		if((charformat.dwMask & CFM_COLOR) != 0)
1861 			m_cf.rgbColors = charformat.crTextColor;
1862 	}
1863 
GetCharFormat(CHARFORMAT & cf)1864 	void GetCharFormat(CHARFORMAT& cf) const
1865 	{
1866 		USES_CONVERSION;
1867 		cf.dwEffects = 0;
1868 		cf.dwMask = 0;
1869 		if((m_cf.Flags & CF_NOSTYLESEL) == 0)
1870 		{
1871 			cf.dwMask |= CFM_BOLD | CFM_ITALIC;
1872 			cf.dwEffects |= IsBold() ? CFE_BOLD : 0;
1873 			cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0;
1874 		}
1875 		if((m_cf.Flags & CF_NOSIZESEL) == 0)
1876 		{
1877 			cf.dwMask |= CFM_SIZE;
1878 			// GetSize() returns in tenths of points so mulitply by 2 to get twips
1879 			cf.yHeight = GetSize() * 2;
1880 		}
1881 
1882 		if((m_cf.Flags & CF_NOFACESEL) == 0)
1883 		{
1884 			cf.dwMask |= CFM_FACE;
1885 			cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily;
1886 #if (_RICHEDIT_VER >= 0x0200)
1887 			SecureHelper::strcpy_x(cf.szFaceName, _countof(cf.szFaceName), GetFaceName());
1888 #else // !(_RICHEDIT_VER >= 0x0200)
1889 			SecureHelper::strcpyA_x(cf.szFaceName, _countof(cf.szFaceName), T2A((LPTSTR)(LPCTSTR)GetFaceName()));
1890 #endif // !(_RICHEDIT_VER >= 0x0200)
1891 		}
1892 
1893 		if((m_cf.Flags & CF_EFFECTS) != 0)
1894 		{
1895 			cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
1896 			cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0;
1897 			cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0;
1898 			cf.crTextColor = GetColor();
1899 		}
1900 		if((m_cf.Flags & CF_NOSCRIPTSEL) == 0)
1901 		{
1902 			cf.bCharSet = m_cf.lpLogFont->lfCharSet;
1903 			cf.dwMask |= CFM_CHARSET;
1904 		}
1905 		cf.yOffset = 0;
1906 	}
1907 
FillInLogFont(const CHARFORMAT & cf)1908 	DWORD FillInLogFont(const CHARFORMAT& cf)
1909 	{
1910 		USES_CONVERSION;
1911 		DWORD dwFlags = 0;
1912 		if((cf.dwMask & CFM_SIZE) != 0)
1913 		{
1914 			HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
1915 			LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY);
1916 			m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440);
1917 		}
1918 		else
1919 			m_lf.lfHeight = 0;
1920 
1921 		m_lf.lfWidth = 0;
1922 		m_lf.lfEscapement = 0;
1923 		m_lf.lfOrientation = 0;
1924 
1925 		if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD))
1926 		{
1927 			m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL;
1928 			m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE);
1929 		}
1930 		else
1931 		{
1932 			dwFlags |= CF_NOSTYLESEL;
1933 			m_lf.lfWeight = FW_DONTCARE;
1934 			m_lf.lfItalic = FALSE;
1935 		}
1936 
1937 		if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR))
1938 		{
1939 			dwFlags |= CF_EFFECTS;
1940 			m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE);
1941 			m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE);
1942 		}
1943 		else
1944 		{
1945 			m_lf.lfUnderline = (BYTE)FALSE;
1946 			m_lf.lfStrikeOut = (BYTE)FALSE;
1947 		}
1948 
1949 		if((cf.dwMask & CFM_CHARSET) != 0)
1950 			m_lf.lfCharSet = cf.bCharSet;
1951 		else
1952 			dwFlags |= CF_NOSCRIPTSEL;
1953 		m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
1954 		m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
1955 		m_lf.lfQuality = DEFAULT_QUALITY;
1956 		if((cf.dwMask & CFM_FACE) != 0)
1957 		{
1958 			m_lf.lfPitchAndFamily = cf.bPitchAndFamily;
1959 #if (_RICHEDIT_VER >= 0x0200)
1960 			SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), cf.szFaceName);
1961 #else // !(_RICHEDIT_VER >= 0x0200)
1962 			SecureHelper::strcpy_x(m_lf.lfFaceName, _countof(m_lf.lfFaceName), A2T((LPSTR)cf.szFaceName));
1963 #endif // !(_RICHEDIT_VER >= 0x0200)
1964 		}
1965 		else
1966 		{
1967 			m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
1968 			m_lf.lfFaceName[0] = (TCHAR)0;
1969 		}
1970 		return dwFlags;
1971 	}
1972 };
1973 
1974 class CRichEditFontDialog : public CRichEditFontDialogImpl<CRichEditFontDialog>
1975 {
1976 public:
1977 	CRichEditFontDialog(const CHARFORMAT& charformat,
1978 		DWORD dwFlags = CF_SCREENFONTS,
1979 		HDC hDCPrinter = NULL,
1980 		HWND hWndParent = NULL)
1981 		: CRichEditFontDialogImpl<CRichEditFontDialog>(charformat, dwFlags, hDCPrinter, hWndParent)
1982 	{ }
1983 
1984 	DECLARE_EMPTY_MSG_MAP()
1985 };
1986 
1987 #endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE)
1988 
1989 
1990 ///////////////////////////////////////////////////////////////////////////////
1991 // CColorDialogImpl - color selection
1992 
1993 #if !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
1994 
1995 #ifdef _WIN32_WCE
1996   #pragma comment(lib, "commdlg.lib")
1997 
1998   #ifndef SETRGBSTRING
1999     #define SETRGBSTRING _T("commdlg_SetRGBColor")
2000   #endif
2001 
2002   #ifndef COLOROKSTRING
2003     #define COLOROKSTRING _T("commdlg_ColorOK")
2004   #endif
2005 #endif
2006 
2007 template <class T>
2008 class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase
2009 {
2010 public:
2011 	CHOOSECOLOR m_cc;
2012 
2013 // Constructor
2014 	CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
2015 	{
2016 		memset(&m_cc, 0, sizeof(m_cc));
2017 
2018 		m_cc.lStructSize = sizeof(m_cc);
2019 		m_cc.lpCustColors = GetCustomColors();
2020 		m_cc.hwndOwner = hWndParent;
2021 		m_cc.Flags = dwFlags | CC_ENABLEHOOK;
2022 		m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc;
2023 
2024 		if(clrInit != 0)
2025 		{
2026 			m_cc.rgbResult = clrInit;
2027 			m_cc.Flags |= CC_RGBINIT;
2028 		}
2029 	}
2030 
2031 // Operations
2032 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
2033 	{
2034 		ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0);
2035 		ATLASSERT(m_cc.lpfnHook != NULL);   // can still be a user hook
2036 
2037 		if(m_cc.hwndOwner == NULL)          // set only if not specified before
2038 			m_cc.hwndOwner = hWndParent;
2039 
2040 		ATLASSERT(m_hWnd == NULL);
2041 
2042 #if (_ATL_VER >= 0x0800)
2043 		// Allocate the thunk structure here, where we can fail gracefully.
2044 		BOOL bRetTh = m_thunk.Init(NULL, NULL);
2045 		if(bRetTh == FALSE)
2046 		{
2047 			::SetLastError(ERROR_OUTOFMEMORY);
2048 			return -1;
2049 		}
2050 #endif // (_ATL_VER >= 0x0800)
2051 
2052 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2053 
2054 		BOOL bRet = ::ChooseColor(&m_cc);
2055 
2056 		m_hWnd = NULL;
2057 
2058 		return bRet ? IDOK : IDCANCEL;
2059 	}
2060 
2061 	// Set the current color while dialog is displayed
SetCurrentColor(COLORREF clr)2062 	void SetCurrentColor(COLORREF clr)
2063 	{
2064 		ATLASSERT(::IsWindow(m_hWnd));
2065 		SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr);
2066 	}
2067 
2068 	// Get the selected color after DoModal returns, or in OnColorOK
GetColor()2069 	COLORREF GetColor() const
2070 	{
2071 		return m_cc.rgbResult;
2072 	}
2073 
2074 // Special override for the color dialog
HookProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2075 	static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2076 	{
2077 		if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage())
2078 			return 0;
2079 
2080 		LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam;
2081 		CCommonDialogImplBase* pT = NULL;
2082 
2083 		if(uMsg == WM_INITDIALOG)
2084 		{
2085 			pT = (CCommonDialogImplBase*)ModuleHelper::ExtractCreateWndData();
2086 			lpCC->lCustData = (LPARAM)pT;
2087 			ATLASSERT(pT != NULL);
2088 			ATLASSERT(pT->m_hWnd == NULL);
2089 			ATLASSERT(::IsWindow(hWnd));
2090 			// subclass dialog's window
2091 			if(!pT->SubclassWindow(hWnd))
2092 			{
2093 				ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n"));
2094 				return 0;
2095 			}
2096 		}
2097 		else if(uMsg == _GetColorOKMessage())
2098 		{
2099 			pT = (CCommonDialogImplBase*)lpCC->lCustData;
2100 			ATLASSERT(pT != NULL);
2101 			ATLASSERT(::IsWindow(pT->m_hWnd));
2102 		}
2103 		else
2104 		{
2105 			ATLASSERT(FALSE);
2106 			return 0;
2107 		}
2108 
2109 		// pass to the message map
2110 		LRESULT lRes = 0;
2111 		if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
2112 			return 0;
2113 
2114 		return lRes;
2115 	}
2116 
2117 // Helpers
GetCustomColors()2118 	static COLORREF* GetCustomColors()
2119 	{
2120 		static COLORREF rgbCustomColors[16] =
2121 		{
2122 			RGB(255, 255, 255), RGB(255, 255, 255),
2123 			RGB(255, 255, 255), RGB(255, 255, 255),
2124 			RGB(255, 255, 255), RGB(255, 255, 255),
2125 			RGB(255, 255, 255), RGB(255, 255, 255),
2126 			RGB(255, 255, 255), RGB(255, 255, 255),
2127 			RGB(255, 255, 255), RGB(255, 255, 255),
2128 			RGB(255, 255, 255), RGB(255, 255, 255),
2129 			RGB(255, 255, 255), RGB(255, 255, 255),
2130 		};
2131 
2132 		return rgbCustomColors;
2133 	}
2134 
_GetSetRGBMessage()2135 	static UINT _GetSetRGBMessage()
2136 	{
2137 		static UINT uSetRGBMessage = 0;
2138 		if(uSetRGBMessage == 0)
2139 		{
2140 			CStaticDataInitCriticalSectionLock lock;
2141 			if(FAILED(lock.Lock()))
2142 			{
2143 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n"));
2144 				ATLASSERT(FALSE);
2145 				return 0;
2146 			}
2147 
2148 			if(uSetRGBMessage == 0)
2149 				uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING);
2150 
2151 			lock.Unlock();
2152 		}
2153 		ATLASSERT(uSetRGBMessage != 0);
2154 		return uSetRGBMessage;
2155 	}
2156 
_GetColorOKMessage()2157 	static UINT _GetColorOKMessage()
2158 	{
2159 		static UINT uColorOKMessage = 0;
2160 		if(uColorOKMessage == 0)
2161 		{
2162 			CStaticDataInitCriticalSectionLock lock;
2163 			if(FAILED(lock.Lock()))
2164 			{
2165 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n"));
2166 				ATLASSERT(FALSE);
2167 				return 0;
2168 			}
2169 
2170 			if(uColorOKMessage == 0)
2171 				uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING);
2172 
2173 			lock.Unlock();
2174 		}
2175 		ATLASSERT(uColorOKMessage != 0);
2176 		return uColorOKMessage;
2177 	}
2178 
2179 // Message map and handlers
2180 	BEGIN_MSG_MAP(CColorDialogImpl)
MESSAGE_HANDLER(_GetColorOKMessage (),_OnColorOK)2181 		MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK)
2182 	END_MSG_MAP()
2183 
2184 	LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&)
2185 	{
2186 		T* pT = static_cast<T*>(this);
2187 		return pT->OnColorOK();
2188 	}
2189 
2190 // Overrideable
OnColorOK()2191 	BOOL OnColorOK()        // validate color
2192 	{
2193 		return FALSE;
2194 	}
2195 };
2196 
2197 class CColorDialog : public CColorDialogImpl<CColorDialog>
2198 {
2199 public:
2200 	CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
2201 		: CColorDialogImpl<CColorDialog>(clrInit, dwFlags, hWndParent)
2202 	{ }
2203 
2204 	// override base class map and references to handlers
2205 	DECLARE_EMPTY_MSG_MAP()
2206 };
2207 
2208 #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE > 420) && !(defined(WIN32_PLATFORM_WFSP) && (_WIN32_WCE > 0x0500)))
2209 
2210 
2211 ///////////////////////////////////////////////////////////////////////////////
2212 // CPrintDialogImpl - used for Print... and PrintSetup...
2213 
2214 #ifndef _WIN32_WCE
2215 
2216 // global helper
_AtlCreateDC(HGLOBAL hDevNames,HGLOBAL hDevMode)2217 static inline HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode)
2218 {
2219 	if(hDevNames == NULL)
2220 		return NULL;
2221 
2222 	LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames);
2223 	LPDEVMODE  lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL;
2224 
2225 	if(lpDevNames == NULL)
2226 		return NULL;
2227 
2228 	HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset,
2229 					  (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset,
2230 					  (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset,
2231 					  lpDevMode);
2232 
2233 	::GlobalUnlock(hDevNames);
2234 	if(hDevMode != NULL)
2235 		::GlobalUnlock(hDevMode);
2236 	return hDC;
2237 }
2238 
2239 #pragma warning(push)
2240 #pragma warning(disable: 4512)   // assignment operator could not be generated
2241 
2242 template <class T>
2243 class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase
2244 {
2245 public:
2246 	// print dialog parameter block (note this is a reference)
2247 	PRINTDLG& m_pd;
2248 
2249 // Constructors
2250 	CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE,	// TRUE for Print Setup, FALSE for Print Dialog
2251 			DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
2252 			HWND hWndParent = NULL)
m_pd(m_pdActual)2253 			: m_pd(m_pdActual)
2254 	{
2255 		memset(&m_pdActual, 0, sizeof(m_pdActual));
2256 
2257 		m_pd.lStructSize = sizeof(m_pdActual);
2258 		m_pd.hwndOwner = hWndParent;
2259 		m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);
2260 		m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc;
2261 		m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc;
2262 
2263 		if(bPrintSetupOnly)
2264 			m_pd.Flags |= PD_PRINTSETUP;
2265 		else
2266 			m_pd.Flags |= PD_RETURNDC;
2267 
2268 		m_pd.Flags &= ~PD_RETURNIC; // do not support information context
2269 	}
2270 
2271 // Operations
2272 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
2273 	{
2274 		ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0);
2275 		ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0);
2276 		ATLASSERT(m_pd.lpfnPrintHook != NULL);   // can still be a user hook
2277 		ATLASSERT(m_pd.lpfnSetupHook != NULL);   // can still be a user hook
2278 		ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this
2279 
2280 		if(m_pd.hwndOwner == NULL)   // set only if not specified before
2281 			m_pd.hwndOwner = hWndParent;
2282 
2283 		ATLASSERT(m_hWnd == NULL);
2284 
2285 #if (_ATL_VER >= 0x0800)
2286 		// Allocate the thunk structure here, where we can fail gracefully.
2287 		BOOL bRetTh = m_thunk.Init(NULL, NULL);
2288 		if(bRetTh == FALSE)
2289 		{
2290 			::SetLastError(ERROR_OUTOFMEMORY);
2291 			return -1;
2292 		}
2293 #endif // (_ATL_VER >= 0x0800)
2294 
2295 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2296 
2297 		BOOL bRet = ::PrintDlg(&m_pd);
2298 
2299 		m_hWnd = NULL;
2300 
2301 		return bRet ? IDOK : IDCANCEL;
2302 	}
2303 
2304 	// GetDefaults will not display a dialog but will get device defaults
GetDefaults()2305 	BOOL GetDefaults()
2306 	{
2307 		m_pd.Flags |= PD_RETURNDEFAULT;
2308 		ATLASSERT(m_pd.hDevMode == NULL);    // must be NULL
2309 		ATLASSERT(m_pd.hDevNames == NULL);   // must be NULL
2310 
2311 		return ::PrintDlg(&m_pd);
2312 	}
2313 
2314 	// Helpers for parsing information after successful return num. copies requested
GetCopies()2315 	int GetCopies() const
2316 	{
2317 		if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0)
2318 		{
2319 			LPDEVMODE lpDevMode = GetDevMode();
2320 			return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
2321 		}
2322 
2323 		return m_pd.nCopies;
2324 	}
2325 
PrintCollate()2326 	BOOL PrintCollate() const       // TRUE if collate checked
2327 	{
2328 		return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
2329 	}
2330 
PrintSelection()2331 	BOOL PrintSelection() const     // TRUE if printing selection
2332 	{
2333 		return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
2334 	}
2335 
PrintAll()2336 	BOOL PrintAll() const           // TRUE if printing all pages
2337 	{
2338 		return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
2339 	}
2340 
PrintRange()2341 	BOOL PrintRange() const         // TRUE if printing page range
2342 	{
2343 		return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
2344 	}
2345 
PrintToFile()2346 	BOOL PrintToFile() const        // TRUE if printing to a file
2347 	{
2348 		return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
2349 	}
2350 
GetFromPage()2351 	int GetFromPage() const         // starting page if valid
2352 	{
2353 		return PrintRange() ? m_pd.nFromPage : -1;
2354 	}
2355 
GetToPage()2356 	int GetToPage() const           // ending page if valid
2357 	{
2358 		return PrintRange() ? m_pd.nToPage : -1;
2359 	}
2360 
GetDevMode()2361 	LPDEVMODE GetDevMode() const    // return DEVMODE
2362 	{
2363 		if(m_pd.hDevMode == NULL)
2364 			return NULL;
2365 
2366 		return (LPDEVMODE)::GlobalLock(m_pd.hDevMode);
2367 	}
2368 
GetDriverName()2369 	LPCTSTR GetDriverName() const   // return driver name
2370 	{
2371 		if(m_pd.hDevNames == NULL)
2372 			return NULL;
2373 
2374 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2375 		if(lpDev == NULL)
2376 			return NULL;
2377 
2378 		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2379 	}
2380 
GetDeviceName()2381 	LPCTSTR GetDeviceName() const   // return device name
2382 	{
2383 		if(m_pd.hDevNames == NULL)
2384 			return NULL;
2385 
2386 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2387 		if(lpDev == NULL)
2388 			return NULL;
2389 
2390 		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2391 	}
2392 
GetPortName()2393 	LPCTSTR GetPortName() const     // return output port name
2394 	{
2395 		if(m_pd.hDevNames == NULL)
2396 			return NULL;
2397 
2398 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
2399 		if(lpDev == NULL)
2400 			return NULL;
2401 
2402 		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2403 	}
2404 
GetPrinterDC()2405 	HDC GetPrinterDC() const        // return HDC (caller must delete)
2406 	{
2407 		ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0);
2408 		return m_pd.hDC;
2409 	}
2410 
2411 	// This helper creates a DC based on the DEVNAMES and DEVMODE structures.
2412 	// This DC is returned, but also stored in m_pd.hDC as though it had been
2413 	// returned by CommDlg.  It is assumed that any previously obtained DC
2414 	// has been/will be deleted by the user.  This may be
2415 	// used without ever invoking the print/print setup dialogs.
CreatePrinterDC()2416 	HDC CreatePrinterDC()
2417 	{
2418 		m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode);
2419 		return m_pd.hDC;
2420 	}
2421 
2422 // Implementation
2423 	PRINTDLG m_pdActual; // the Print/Print Setup need to share this
2424 
2425 	// The following handle the case of print setup... from the print dialog
CPrintDialogImpl(PRINTDLG & pdInit)2426 	CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit)
2427 	{ }
2428 
2429 	BEGIN_MSG_MAP(CPrintDialogImpl)
2430 #ifdef psh1
COMMAND_ID_HANDLER(psh1,OnPrintSetup)2431 		COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed
2432 #else // !psh1
2433 		COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h
2434 #endif // !psh1
2435 	END_MSG_MAP()
2436 
2437 	LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
2438 	{
2439 		T dlgSetup(m_pd);
2440 		ModuleHelper::AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);
2441 		return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl);
2442 	}
2443 };
2444 
2445 class CPrintDialog : public CPrintDialogImpl<CPrintDialog>
2446 {
2447 public:
2448 	CPrintDialog(BOOL bPrintSetupOnly = FALSE,
2449 		DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
2450 		HWND hWndParent = NULL)
2451 		: CPrintDialogImpl<CPrintDialog>(bPrintSetupOnly, dwFlags, hWndParent)
2452 	{ }
2453 
CPrintDialog(PRINTDLG & pdInit)2454 	CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl<CPrintDialog>(pdInit)
2455 	{ }
2456 };
2457 
2458 #pragma warning(pop)
2459 
2460 #endif // _WIN32_WCE
2461 
2462 
2463 ///////////////////////////////////////////////////////////////////////////////
2464 // CPrintDialogExImpl - new print dialog for Windows 2000
2465 
2466 #if (WINVER >= 0x0500) && !defined(_WIN32_WCE)
2467 
2468 }; // namespace WTL
2469 
2470 #include <atlcom.h>
2471 
2472 extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
2473 extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
2474 
2475 namespace WTL
2476 {
2477 
2478 template <class T>
2479 class ATL_NO_VTABLE CPrintDialogExImpl :
2480 				public ATL::CWindow,
2481 				public ATL::CMessageMap,
2482 				public IPrintDialogCallback,
2483 				public ATL::IObjectWithSiteImpl< T >
2484 {
2485 public:
2486 	PRINTDLGEX m_pdex;
2487 
2488 // Constructor
2489 	CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
2490 				HWND hWndParent = NULL)
2491 	{
2492 		memset(&m_pdex, 0, sizeof(m_pdex));
2493 
2494 		m_pdex.lStructSize = sizeof(PRINTDLGEX);
2495 		m_pdex.hwndOwner = hWndParent;
2496 		m_pdex.Flags = dwFlags;
2497 		m_pdex.nStartPage = START_PAGE_GENERAL;
2498 		// callback object will be set in DoModal
2499 
2500 		m_pdex.Flags &= ~PD_RETURNIC; // do not support information context
2501 	}
2502 
2503 // Operations
2504 	HRESULT DoModal(HWND hWndParent = ::GetActiveWindow())
2505 	{
2506 		ATLASSERT(m_hWnd == NULL);
2507 		ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this
2508 
2509 		if(m_pdex.hwndOwner == NULL)   // set only if not specified before
2510 			m_pdex.hwndOwner = hWndParent;
2511 
2512 		T* pT = static_cast<T*>(this);
2513 		m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT;
2514 
2515 		HRESULT hResult = ::PrintDlgEx(&m_pdex);
2516 
2517 		m_hWnd = NULL;
2518 
2519 		return hResult;
2520 	}
2521 
2522 	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
2523 	{
2524 		ATLASSERT(::IsWindow(m_hWnd));
2525 		SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
2526 		return TRUE;
2527 	}
2528 
2529 	// GetDefaults will not display a dialog but will get device defaults
GetDefaults()2530 	HRESULT GetDefaults()
2531 	{
2532 		ATLASSERT(m_pdex.hDevMode == NULL);    // must be NULL
2533 		ATLASSERT(m_pdex.hDevNames == NULL);   // must be NULL
2534 
2535 		if(m_pdex.hwndOwner == NULL)   // set only if not specified before
2536 			m_pdex.hwndOwner = ::GetActiveWindow();
2537 
2538 		m_pdex.Flags |= PD_RETURNDEFAULT;
2539 		HRESULT hRet = ::PrintDlgEx(&m_pdex);
2540 		m_pdex.Flags &= ~PD_RETURNDEFAULT;
2541 
2542 		return hRet;
2543 	}
2544 
2545 	// Helpers for parsing information after successful return num. copies requested
GetCopies()2546 	int GetCopies() const
2547 	{
2548 		if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0)
2549 		{
2550 			LPDEVMODE lpDevMode = GetDevMode();
2551 			return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
2552 		}
2553 
2554 		return m_pdex.nCopies;
2555 	}
2556 
PrintCollate()2557 	BOOL PrintCollate() const       // TRUE if collate checked
2558 	{
2559 		return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
2560 	}
2561 
PrintSelection()2562 	BOOL PrintSelection() const     // TRUE if printing selection
2563 	{
2564 		return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
2565 	}
2566 
PrintAll()2567 	BOOL PrintAll() const           // TRUE if printing all pages
2568 	{
2569 		return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
2570 	}
2571 
PrintRange()2572 	BOOL PrintRange() const         // TRUE if printing page range
2573 	{
2574 		return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
2575 	}
2576 
PrintToFile()2577 	BOOL PrintToFile() const        // TRUE if printing to a file
2578 	{
2579 		return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
2580 	}
2581 
GetDevMode()2582 	LPDEVMODE GetDevMode() const    // return DEVMODE
2583 	{
2584 		if(m_pdex.hDevMode == NULL)
2585 			return NULL;
2586 
2587 		return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode);
2588 	}
2589 
GetDriverName()2590 	LPCTSTR GetDriverName() const   // return driver name
2591 	{
2592 		if(m_pdex.hDevNames == NULL)
2593 			return NULL;
2594 
2595 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2596 		if(lpDev == NULL)
2597 			return NULL;
2598 
2599 		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2600 	}
2601 
GetDeviceName()2602 	LPCTSTR GetDeviceName() const   // return device name
2603 	{
2604 		if(m_pdex.hDevNames == NULL)
2605 			return NULL;
2606 
2607 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2608 		if(lpDev == NULL)
2609 			return NULL;
2610 
2611 		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2612 	}
2613 
GetPortName()2614 	LPCTSTR GetPortName() const     // return output port name
2615 	{
2616 		if(m_pdex.hDevNames == NULL)
2617 			return NULL;
2618 
2619 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
2620 		if(lpDev == NULL)
2621 			return NULL;
2622 
2623 		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2624 	}
2625 
GetPrinterDC()2626 	HDC GetPrinterDC() const        // return HDC (caller must delete)
2627 	{
2628 		ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0);
2629 		return m_pdex.hDC;
2630 	}
2631 
2632 	// This helper creates a DC based on the DEVNAMES and DEVMODE structures.
2633 	// This DC is returned, but also stored in m_pdex.hDC as though it had been
2634 	// returned by CommDlg.  It is assumed that any previously obtained DC
2635 	// has been/will be deleted by the user.  This may be
2636 	// used without ever invoking the print/print setup dialogs.
CreatePrinterDC()2637 	HDC CreatePrinterDC()
2638 	{
2639 		m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode);
2640 		return m_pdex.hDC;
2641 	}
2642 
2643 // Implementation - interfaces
2644 
2645 // IUnknown
STDMETHOD(QueryInterface)2646 	STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
2647 	{
2648 		if(ppvObject == NULL)
2649 			return E_POINTER;
2650 
2651 		T* pT = static_cast<T*>(this);
2652 		if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback))
2653 		{
2654 			*ppvObject = (IPrintDialogCallback*)pT;
2655 			// AddRef() not needed
2656 			return S_OK;
2657 		}
2658 		else if(IsEqualGUID(riid, IID_IObjectWithSite))
2659 		{
2660 			*ppvObject = (IObjectWithSite*)pT;
2661 			// AddRef() not needed
2662 			return S_OK;
2663 		}
2664 
2665 		return E_NOINTERFACE;
2666 	}
2667 
AddRef()2668 	virtual ULONG STDMETHODCALLTYPE AddRef()
2669 	{
2670 		return 1;
2671 	}
2672 
Release()2673 	virtual ULONG STDMETHODCALLTYPE Release()
2674 	{
2675 		return 1;
2676 	}
2677 
2678 // IPrintDialogCallback
STDMETHOD(InitDone)2679 	STDMETHOD(InitDone)()
2680 	{
2681 		return S_FALSE;
2682 	}
2683 
STDMETHOD(SelectionChange)2684 	STDMETHOD(SelectionChange)()
2685 	{
2686 		return S_FALSE;
2687 	}
2688 
STDMETHOD(HandleMessage)2689 	STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
2690 	{
2691 		// set up m_hWnd the first time
2692 		if(m_hWnd == NULL)
2693 			Attach(hWnd);
2694 
2695 		// call message map
2696 		HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE;
2697 		if(hRet == S_OK && uMsg == WM_NOTIFY)   // return in DWLP_MSGRESULT
2698 			::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult);
2699 
2700 		if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE)
2701 			hRet = S_FALSE;
2702 
2703 		return hRet;
2704 	}
2705 };
2706 
2707 class CPrintDialogEx : public CPrintDialogExImpl<CPrintDialogEx>
2708 {
2709 public:
2710 	CPrintDialogEx(
2711 		DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
2712 		HWND hWndParent = NULL)
2713 		: CPrintDialogExImpl<CPrintDialogEx>(dwFlags, hWndParent)
2714 	{ }
2715 
2716 	DECLARE_EMPTY_MSG_MAP()
2717 };
2718 
2719 #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)
2720 
2721 
2722 ///////////////////////////////////////////////////////////////////////////////
2723 // CPageSetupDialogImpl - Page Setup dialog
2724 
2725 #ifndef _WIN32_WCE
2726 
2727 template <class T>
2728 class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase
2729 {
2730 public:
2731 	PAGESETUPDLG m_psd;
2732 	ATL::CWndProcThunk m_thunkPaint;
2733 
2734 // Constructors
2735 	CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
2736 	{
2737 		memset(&m_psd, 0, sizeof(m_psd));
2738 
2739 		m_psd.lStructSize = sizeof(m_psd);
2740 		m_psd.hwndOwner = hWndParent;
2741 		m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK);
2742 		m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc;
2743 		m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this);
2744 #if (_ATL_VER >= 0x0700)
2745 		m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC();
2746 #else
2747 		m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk);
2748 #endif
2749 	}
2750 
DECLARE_EMPTY_MSG_MAP()2751 	DECLARE_EMPTY_MSG_MAP()
2752 
2753 // Attributes
2754 	LPDEVMODE GetDevMode() const    // return DEVMODE
2755 	{
2756 		if(m_psd.hDevMode == NULL)
2757 			return NULL;
2758 
2759 		return (LPDEVMODE)::GlobalLock(m_psd.hDevMode);
2760 	}
2761 
GetDriverName()2762 	LPCTSTR GetDriverName() const   // return driver name
2763 	{
2764 		if(m_psd.hDevNames == NULL)
2765 			return NULL;
2766 
2767 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2768 		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
2769 	}
2770 
GetDeviceName()2771 	LPCTSTR GetDeviceName() const   // return device name
2772 	{
2773 		if(m_psd.hDevNames == NULL)
2774 			return NULL;
2775 
2776 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2777 		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
2778 	}
2779 
GetPortName()2780 	LPCTSTR GetPortName() const     // return output port name
2781 	{
2782 		if(m_psd.hDevNames == NULL)
2783 			return NULL;
2784 
2785 		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
2786 		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
2787 	}
2788 
CreatePrinterDC()2789 	HDC CreatePrinterDC()
2790 	{
2791 		return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode);
2792 	}
2793 
GetPaperSize()2794 	SIZE GetPaperSize() const
2795 	{
2796 		SIZE size = { m_psd.ptPaperSize.x, m_psd.ptPaperSize.y };
2797 		return size;
2798 	}
2799 
GetMargins(LPRECT lpRectMargins,LPRECT lpRectMinMargins)2800 	void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const
2801 	{
2802 		if(lpRectMargins != NULL)
2803 			*lpRectMargins = m_psd.rtMargin;
2804 		if(lpRectMinMargins != NULL)
2805 			*lpRectMinMargins = m_psd.rtMinMargin;
2806 	}
2807 
2808 // Operations
2809 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
2810 	{
2811 		ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0);
2812 		ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0);
2813 		ATLASSERT(m_psd.lpfnPageSetupHook != NULL);   // can still be a user hook
2814 		ATLASSERT(m_psd.lpfnPagePaintHook != NULL);   // can still be a user hook
2815 
2816 		if(m_psd.hwndOwner == NULL)   // set only if not specified before
2817 			m_psd.hwndOwner = hWndParent;
2818 
2819 		ATLASSERT(m_hWnd == NULL);
2820 
2821 #if (_ATL_VER >= 0x0800)
2822 		// Allocate the thunk structure here, where we can fail gracefully.
2823 		BOOL bRetTh = m_thunk.Init(NULL, NULL);
2824 		if(bRetTh == FALSE)
2825 		{
2826 			::SetLastError(ERROR_OUTOFMEMORY);
2827 			return -1;
2828 		}
2829 #endif // (_ATL_VER >= 0x0800)
2830 
2831 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2832 
2833 		BOOL bRet = ::PageSetupDlg(&m_psd);
2834 
2835 		m_hWnd = NULL;
2836 
2837 		return bRet ? IDOK : IDCANCEL;
2838 	}
2839 
2840 // Implementation
PaintHookProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2841 	static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
2842 	{
2843 		T* pT = (T*)hWnd;
2844 		UINT_PTR uRet = 0;
2845 		switch(uMsg)
2846 		{
2847 		case WM_PSD_PAGESETUPDLG:
2848 			uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam);
2849 			break;
2850 		case WM_PSD_FULLPAGERECT:
2851 		case WM_PSD_MINMARGINRECT:
2852 		case WM_PSD_MARGINRECT:
2853 		case WM_PSD_GREEKTEXTRECT:
2854 		case WM_PSD_ENVSTAMPRECT:
2855 		case WM_PSD_YAFULLPAGERECT:
2856 			uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam);
2857 			break;
2858 		default:
2859 			ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n"));
2860 			break;
2861 		}
2862 		return uRet;
2863 	}
2864 
2865 // Overridables
PreDrawPage(WORD,WORD,LPPAGESETUPDLG)2866 	UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/)
2867 	{
2868 		// return 1 to prevent any more drawing
2869 		return 0;
2870 	}
2871 
OnDrawPage(UINT,HDC,LPRECT)2872 	UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/)
2873 	{
2874 		return 0; // do the default
2875 	}
2876 };
2877 
2878 class CPageSetupDialog : public CPageSetupDialogImpl<CPageSetupDialog>
2879 {
2880 public:
2881 	CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
2882 		: CPageSetupDialogImpl<CPageSetupDialog>(dwFlags, hWndParent)
2883 	{ }
2884 
2885 	// override PaintHookProc and references to handlers
PaintHookProc(HWND,UINT,WPARAM,LPARAM)2886 	static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM)
2887 	{
2888 		return 0;
2889 	}
2890 };
2891 
2892 #endif // _WIN32_WCE
2893 
2894 
2895 ///////////////////////////////////////////////////////////////////////////////
2896 // CFindReplaceDialogImpl - Find/FindReplace modeless dialogs
2897 
2898 #ifndef _WIN32_WCE
2899 
2900 template <class T>
2901 class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase
2902 {
2903 public:
2904 	enum { _cchFindReplaceBuffer = 128 };
2905 
2906 	FINDREPLACE m_fr;
2907 	TCHAR m_szFindWhat[_cchFindReplaceBuffer];
2908 	TCHAR m_szReplaceWith[_cchFindReplaceBuffer];
2909 
2910 // Constructors
CFindReplaceDialogImpl()2911 	CFindReplaceDialogImpl()
2912 	{
2913 		memset(&m_fr, 0, sizeof(m_fr));
2914 		m_szFindWhat[0] = _T('\0');
2915 		m_szReplaceWith[0] = _T('\0');
2916 
2917 		m_fr.lStructSize = sizeof(m_fr);
2918 		m_fr.Flags = FR_ENABLEHOOK;
2919 		m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc;
2920 		m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat;
2921 		m_fr.wFindWhatLen = _cchFindReplaceBuffer;
2922 		m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith;
2923 		m_fr.wReplaceWithLen = _cchFindReplaceBuffer;
2924 	}
2925 
2926 	// Note: You must allocate the object on the heap.
2927 	//       If you do not, you must override OnFinalMessage()
OnFinalMessage(HWND)2928 	virtual void OnFinalMessage(HWND /*hWnd*/)
2929 	{
2930 		delete this;
2931 	}
2932 
2933 	HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace
2934 			LPCTSTR lpszFindWhat,
2935 			LPCTSTR lpszReplaceWith = NULL,
2936 			DWORD dwFlags = FR_DOWN,
2937 			HWND hWndParent = NULL)
2938 	{
2939 		ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0);
2940 		ATLASSERT(m_fr.lpfnHook != NULL);
2941 
2942 		m_fr.Flags |= dwFlags;
2943 
2944 		if(hWndParent == NULL)
2945 			m_fr.hwndOwner = ::GetActiveWindow();
2946 		else
2947 			m_fr.hwndOwner = hWndParent;
2948 		ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog
2949 
2950 		if(lpszFindWhat != NULL)
2951 			SecureHelper::strncpy_x(m_szFindWhat, _countof(m_szFindWhat), lpszFindWhat, _TRUNCATE);
2952 
2953 		if(lpszReplaceWith != NULL)
2954 			SecureHelper::strncpy_x(m_szReplaceWith, _countof(m_szReplaceWith), lpszReplaceWith, _TRUNCATE);
2955 
2956 		ATLASSERT(m_hWnd == NULL);
2957 
2958 #if (_ATL_VER >= 0x0800)
2959 		// Allocate the thunk structure here, where we can fail gracefully.
2960 		BOOL bRet = m_thunk.Init(NULL, NULL);
2961 		if(bRet == FALSE)
2962 		{
2963 			::SetLastError(ERROR_OUTOFMEMORY);
2964 			return NULL;
2965 		}
2966 #endif // (_ATL_VER >= 0x0800)
2967 
2968 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
2969 
2970 		HWND hWnd = NULL;
2971 		if(bFindDialogOnly)
2972 			hWnd = ::FindText(&m_fr);
2973 		else
2974 			hWnd = ::ReplaceText(&m_fr);
2975 
2976 		ATLASSERT(m_hWnd == hWnd);
2977 		return hWnd;
2978 	}
2979 
GetFindReplaceMsg()2980 	static const UINT GetFindReplaceMsg()
2981 	{
2982 		static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
2983 		return nMsgFindReplace;
2984 	}
2985 	// call while handling FINDMSGSTRING registered message
2986 	// to retreive the object
GetNotifier(LPARAM lParam)2987 	static T* PASCAL GetNotifier(LPARAM lParam)
2988 	{
2989 		ATLASSERT(lParam != NULL);
2990 		T* pDlg = (T*)(lParam - offsetof(T, m_fr));
2991 		return pDlg;
2992 	}
2993 
2994 // Operations
2995 	// Helpers for parsing information after successful return
GetFindString()2996 	LPCTSTR GetFindString() const    // get find string
2997 	{
2998 		return (LPCTSTR)m_fr.lpstrFindWhat;
2999 	}
3000 
GetReplaceString()3001 	LPCTSTR GetReplaceString() const // get replacement string
3002 	{
3003 		return (LPCTSTR)m_fr.lpstrReplaceWith;
3004 	}
3005 
SearchDown()3006 	BOOL SearchDown() const          // TRUE if search down, FALSE is up
3007 	{
3008 		return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE;
3009 	}
3010 
FindNext()3011 	BOOL FindNext() const            // TRUE if command is find next
3012 	{
3013 		return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE;
3014 	}
3015 
MatchCase()3016 	BOOL MatchCase() const           // TRUE if matching case
3017 	{
3018 		return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE;
3019 	}
3020 
MatchWholeWord()3021 	BOOL MatchWholeWord() const      // TRUE if matching whole words only
3022 	{
3023 		return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE;
3024 	}
3025 
ReplaceCurrent()3026 	BOOL ReplaceCurrent() const      // TRUE if replacing current string
3027 	{
3028 		return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE;
3029 	}
3030 
ReplaceAll()3031 	BOOL ReplaceAll() const          // TRUE if replacing all occurrences
3032 	{
3033 		return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE;
3034 	}
3035 
IsTerminating()3036 	BOOL IsTerminating() const       // TRUE if terminating dialog
3037 	{
3038 		return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ;
3039 	}
3040 };
3041 
3042 class CFindReplaceDialog : public CFindReplaceDialogImpl<CFindReplaceDialog>
3043 {
3044 public:
3045 	DECLARE_EMPTY_MSG_MAP()
3046 };
3047 
3048 #endif // !_WIN32_WCE
3049 
3050 
3051 /////////////////////////////////////////////////////////////////////////
3052 // CDialogBaseUnits - Dialog Units helper
3053 //
3054 
3055 class CDialogBaseUnits
3056 {
3057 public:
3058 	SIZE m_sizeUnits;
3059 
3060 // Constructors
CDialogBaseUnits()3061 	CDialogBaseUnits()
3062 	{
3063 		// The base units of the out-dated System Font
3064 		LONG nDlgBaseUnits = ::GetDialogBaseUnits();
3065 		m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
3066 		m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
3067 	}
3068 
CDialogBaseUnits(HWND hWnd)3069 	CDialogBaseUnits(HWND hWnd)
3070 	{
3071 		if(!InitDialogBaseUnits(hWnd)) {
3072 			LONG nDlgBaseUnits = ::GetDialogBaseUnits();
3073 			m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
3074 			m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
3075 		}
3076 	}
3077 
3078 	CDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)
3079 	{
3080 		if(!InitDialogBaseUnits(hFont, hWnd)) {
3081 			LONG nDlgBaseUnits = ::GetDialogBaseUnits();
3082 			m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
3083 			m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
3084 		}
3085 	}
3086 
3087 	CDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)
3088 	{
3089 		if(!InitDialogBaseUnits(lf, hWnd)) {
3090 			LONG nDlgBaseUnits = ::GetDialogBaseUnits();
3091 			m_sizeUnits.cx = LOWORD(nDlgBaseUnits);
3092 			m_sizeUnits.cy = HIWORD(nDlgBaseUnits);
3093 		}
3094 	}
3095 
3096 // Operations
InitDialogBaseUnits(HWND hWnd)3097 	BOOL InitDialogBaseUnits(HWND hWnd)
3098 	{
3099 		ATLASSERT(::IsWindow(hWnd));
3100 		RECT rc = { 0, 0, 4, 8 };
3101 		if(!::MapDialogRect(hWnd, &rc)) return FALSE;
3102 		m_sizeUnits.cx = rc.right;
3103 		m_sizeUnits.cy = rc.bottom;
3104 		return TRUE;
3105 	}
3106 
3107 	BOOL InitDialogBaseUnits(LOGFONT lf, HWND hWnd = NULL)
3108 	{
3109 		CFont font;
3110 		font.CreateFontIndirect(&lf);
3111 		if(font.IsNull()) return FALSE;
3112 		return InitDialogBaseUnits(font, hWnd);
3113 	}
3114 
3115 	BOOL InitDialogBaseUnits(HFONT hFont, HWND hWnd = NULL)
3116 	{
3117 		ATLASSERT(hFont != NULL);
3118 		CWindowDC dc = hWnd;
3119 		TEXTMETRIC tmText = { 0 };
3120 		SIZE sizeText = { 0 };
3121 		HFONT hFontOld = dc.SelectFont(hFont);
3122 		dc.GetTextMetrics(&tmText);
3123 		m_sizeUnits.cy = tmText.tmHeight + tmText.tmExternalLeading;
3124 		dc.GetTextExtent(_T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &sizeText);
3125 		m_sizeUnits.cx = (sizeText.cx + 26) / 52;
3126 		dc.SelectFont(hFontOld);
3127 		return TRUE;
3128 	}
3129 
GetDialogBaseUnits()3130 	SIZE GetDialogBaseUnits() const
3131 	{
3132 		return m_sizeUnits;
3133 	}
3134 
MapDialogPixelsX(INT x)3135 	INT MapDialogPixelsX(INT x) const
3136 	{
3137 		return ::MulDiv(x, 4, m_sizeUnits.cx);  // Pixels X to DLU
3138 	}
3139 
MapDialogPixelsY(INT y)3140 	INT MapDialogPixelsY(INT y) const
3141 	{
3142 		return ::MulDiv(y, 8, m_sizeUnits.cy);  // Pixels Y to DLU
3143 	}
3144 
MapDialogPixels(POINT pt)3145 	POINT MapDialogPixels(POINT pt) const
3146 	{
3147 		POINT out = { MapDialogPixelsX(pt.x), MapDialogPixelsY(pt.y) };
3148 		return out;
3149 	}
3150 
MapDialogPixels(SIZE input)3151 	SIZE MapDialogPixels(SIZE input) const
3152 	{
3153 		SIZE out = { MapDialogPixelsX(input.cx), MapDialogPixelsY(input.cy) };
3154 		return out;
3155 	}
3156 
MapDialogPixels(const RECT & input)3157 	RECT MapDialogPixels(const RECT& input) const
3158 	{
3159 		RECT out = { MapDialogPixelsX(input.left), MapDialogPixelsY(input.top), MapDialogPixelsX(input.right), MapDialogPixelsY(input.bottom) };
3160 		return out;
3161 	}
3162 
MapDialogUnitsX(INT x)3163 	INT MapDialogUnitsX(INT x) const
3164 	{
3165 		return ::MulDiv(x, m_sizeUnits.cx, 4);  // DLU to Pixels X
3166 	}
3167 
MapDialogUnitsY(INT y)3168 	INT MapDialogUnitsY(INT y) const
3169 	{
3170 		return ::MulDiv(y, m_sizeUnits.cy, 8);  // DLU to Pixels Y
3171 	}
3172 
MapDialogUnits(POINT pt)3173 	POINT MapDialogUnits(POINT pt) const
3174 	{
3175 		POINT out = { MapDialogUnitsX(pt.x), MapDialogUnitsY(pt.y) };
3176 		return out;
3177 	}
3178 
MapDialogUnits(SIZE input)3179 	SIZE MapDialogUnits(SIZE input) const
3180 	{
3181 		SIZE out = { MapDialogUnitsX(input.cx), MapDialogUnitsY(input.cy) };
3182 		return out;
3183 	}
3184 
MapDialogUnits(const RECT & input)3185 	RECT MapDialogUnits(const RECT& input) const
3186 	{
3187 		RECT out = { MapDialogUnitsX(input.left), MapDialogUnitsY(input.top), MapDialogUnitsX(input.right), MapDialogUnitsY(input.bottom) };
3188 		return out;
3189 	}
3190 };
3191 
3192 
3193 ///////////////////////////////////////////////////////////////////////////////
3194 // CMemDlgTemplate - in-memory dialog template - DLGTEMPLATE or DLGTEMPLATEEX
3195 
3196 #if (_ATL_VER >= 0x800)
3197   typedef ATL::_DialogSplitHelper::DLGTEMPLATEEX DLGTEMPLATEEX;
3198   typedef ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX DLGITEMTEMPLATEEX;
3199 #else // (_ATL_VER >= 0x800)
3200   typedef ATL::_DialogSizeHelper::_ATL_DLGTEMPLATEEX DLGTEMPLATEEX;
3201   #pragma pack(push, 4)
3202   struct DLGITEMTEMPLATEEX
3203   {
3204 	DWORD helpID;
3205 	DWORD exStyle;
3206 	DWORD style;
3207 	short x;
3208 	short y;
3209 	short cx;
3210 	short cy;
3211 	DWORD id;
3212   };
3213   #pragma pack(pop)
3214 #endif // (_ATL_VER >= 0x800)
3215 
3216 
3217 template <class TWinTraits>
3218 class CMemDlgTemplateT
3219 {
3220 public:
3221 	enum StdCtrlType
3222 	{
3223 		CTRL_BUTTON    = 0x0080,
3224 		CTRL_EDIT      = 0x0081,
3225 		CTRL_STATIC    = 0x0082,
3226 		CTRL_LISTBOX   = 0x0083,
3227 		CTRL_SCROLLBAR = 0x0084,
3228 		CTRL_COMBOBOX  = 0x0085
3229 	};
3230 
3231 	HANDLE m_hData;
3232 	LPBYTE m_pData;
3233 	LPBYTE m_pPtr;
3234 	SIZE_T m_cAllocated;
3235 
CMemDlgTemplateT()3236 	CMemDlgTemplateT() : m_hData(NULL), m_pData(NULL), m_pPtr(NULL), m_cAllocated(0)
3237 	{ }
3238 
~CMemDlgTemplateT()3239 	~CMemDlgTemplateT()
3240 	{
3241 		Reset();
3242 	}
3243 
IsValid()3244 	bool IsValid() const
3245 	{
3246 		return (m_pData != NULL);
3247 	}
3248 
IsTemplateEx()3249 	bool IsTemplateEx() const
3250 	{
3251 		return (IsValid() && ((DLGTEMPLATEEX*)m_pData)->signature == 0xFFFF);
3252 	}
3253 
GetTemplatePtr()3254 	LPDLGTEMPLATE GetTemplatePtr()
3255 	{
3256 		return reinterpret_cast<LPDLGTEMPLATE>(m_pData);
3257 	}
3258 
GetTemplateExPtr()3259 	DLGTEMPLATEEX* GetTemplateExPtr()
3260 	{
3261 		return reinterpret_cast<DLGTEMPLATEEX*>(m_pData);
3262 	}
3263 
Reset()3264 	void Reset()
3265 	{
3266 		if (IsValid()) {
3267 #ifndef UNDER_CE
3268 			::GlobalUnlock(m_pData);
3269 #endif
3270 			ATLVERIFY(::GlobalFree(m_hData) == NULL);
3271 		}
3272 
3273 		m_hData = NULL;
3274 		m_pData = NULL;
3275 		m_pPtr = NULL;
3276 		m_cAllocated = 0;
3277 	}
3278 
3279 	void Create(bool bDlgEx, LPCTSTR lpszCaption, const RECT& rc, DWORD dwStyle = 0, DWORD dwExStyle = 0,
3280 	            LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,
3281 	            ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)
3282 	{
3283 		Create(bDlgEx, lpszCaption, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,
3284 			lpstrFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName.m_lpstr, Menu.m_lpstr);
3285 	}
3286 
3287 	void Create(bool bDlgEx, LPCTSTR lpszCaption, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle = 0, DWORD dwExStyle = 0,
3288 	            LPCTSTR lpstrFontName = NULL, WORD wFontSize = 0, WORD wWeight = 0, BYTE bItalic = 0, BYTE bCharset = 0, DWORD dwHelpID = 0,
3289 	            ATL::_U_STRINGorID ClassName = 0U, ATL::_U_STRINGorID Menu = 0U)
3290 	{
3291 		// Should have DS_SETFONT style to set the dialog font name and size
3292 		if (lpstrFontName != NULL)
3293 		{
3294 			dwStyle |= DS_SETFONT;
3295 		}
3296 		else
3297 		{
3298 			dwStyle &= ~DS_SETFONT;
3299 		}
3300 
3301 		if (bDlgEx)
3302 		{
3303 			DLGTEMPLATEEX dlg = {1, 0xFFFF, dwHelpID, dwExStyle, dwStyle, 0, nX, nY, nWidth, nHeight};
3304 			AddData(&dlg, sizeof(dlg));
3305 		}
3306 		else
3307 		{
3308 			DLGTEMPLATE dlg = {dwStyle, dwExStyle, 0, nX, nY, nWidth, nHeight};
3309 			AddData(&dlg, sizeof(dlg));
3310 		}
3311 
3312 #ifndef _WIN32_WCE
3313 		if (Menu.m_lpstr == NULL)
3314 		{
3315 			WORD menuData = 0;
3316 			AddData(&menuData, sizeof(WORD));
3317 		}
3318 		else if (IS_INTRESOURCE(Menu.m_lpstr))
3319 		{
3320 			WORD menuData[] = { 0xFFFF, LOWORD(Menu.m_lpstr) };
3321 			AddData(menuData, sizeof(menuData));
3322 		}
3323 		else
3324 		{
3325 			AddString(Menu.m_lpstr);
3326 		}
3327 #else // _WIN32_WCE
3328 		// Windows CE doesn't support the addition of menus to a dialog box
3329 		ATLASSERT(Menu.m_lpstr == NULL);
3330 		Menu.m_lpstr;   // avoid level 4 warning
3331 		WORD menuData = 0;
3332 		AddData(&menuData, sizeof(WORD));
3333 #endif // _WIN32_WCE
3334 
3335 		if (ClassName.m_lpstr == NULL)
3336 		{
3337 			WORD classData = 0;
3338 			AddData(&classData, sizeof(WORD));
3339 		}
3340 		else if (IS_INTRESOURCE(ClassName.m_lpstr))
3341 		{
3342 			WORD classData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) };
3343 			AddData(classData, sizeof(classData));
3344 		}
3345 		else
3346 		{
3347 			AddString(ClassName.m_lpstr);
3348 		}
3349 
3350 		// Set dialog caption
3351 		AddString(lpszCaption);
3352 
3353 		if (lpstrFontName != NULL)
3354 		{
3355 			AddData(&wFontSize, sizeof(wFontSize));
3356 
3357 			if (bDlgEx)
3358 			{
3359 				AddData(&wWeight, sizeof(wWeight));
3360 				AddData(&bItalic, sizeof(bItalic));
3361 				AddData(&bCharset, sizeof(bCharset));
3362 			}
3363 
3364 			AddString(lpstrFontName);
3365 		}
3366 	}
3367 
3368 	void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, const RECT& rc, DWORD dwStyle, DWORD dwExStyle,
3369 	                ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
3370 	{
3371 		AddControl(ClassName.m_lpstr, wId, (short) rc.left, (short) rc.top, (short) (rc.right - rc.left), (short) (rc.bottom - rc.top), dwStyle, dwExStyle,
3372 			Text.m_lpstr, pCreationData, nCreationData, dwHelpID);
3373 	}
3374 
3375 	void AddControl(ATL::_U_STRINGorID ClassName, WORD wId, short nX, short nY, short nWidth, short nHeight, DWORD dwStyle, DWORD dwExStyle,
3376 	                ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
3377 	{
3378 		ATLASSERT(IsValid());
3379 
3380 		// DWORD align data
3381 		const DWORD_PTR dwDwordAlignBits = sizeof(DWORD) - 1;
3382 		m_pPtr = (LPBYTE)(((DWORD_PTR)m_pPtr + dwDwordAlignBits) & (~dwDwordAlignBits));
3383 
3384 		if (IsTemplateEx())
3385 		{
3386 			DLGTEMPLATEEX* dlg = (DLGTEMPLATEEX*)m_pData;
3387 			dlg->cDlgItems++;
3388 
3389 			DLGITEMTEMPLATEEX item = {dwHelpID, TWinTraits::GetWndExStyle(0) | dwExStyle, TWinTraits::GetWndStyle(0) | dwStyle, nX, nY, nWidth, nHeight, wId};
3390 			AddData(&item, sizeof(item));
3391 		}
3392 		else
3393 		{
3394 			LPDLGTEMPLATE dlg = (LPDLGTEMPLATE)m_pData;
3395 			dlg->cdit++;
3396 
3397 			DLGITEMTEMPLATE item = {TWinTraits::GetWndStyle(0) | dwStyle, TWinTraits::GetWndExStyle(0) | dwExStyle, nX, nY, nWidth, nHeight, wId};
3398 			AddData(&item, sizeof(item));
3399 		}
3400 
3401 		ATLASSERT(ClassName.m_lpstr != NULL);
3402 		if (IS_INTRESOURCE(ClassName.m_lpstr))
3403 		{
3404 			WORD wData[] = { 0xFFFF, LOWORD(ClassName.m_lpstr) };
3405 			AddData(wData, sizeof(wData));
3406 		}
3407 		else
3408 		{
3409 			AddString(ClassName.m_lpstr);
3410 		}
3411 
3412 		if (Text.m_lpstr == NULL)
3413 		{
3414 			WORD classData = 0;
3415 			AddData(&classData, sizeof(WORD));
3416 		}
3417 		else if (IS_INTRESOURCE(Text.m_lpstr))
3418 		{
3419 			WORD wData[] = { 0xFFFF, LOWORD(Text.m_lpstr) };
3420 			AddData(wData, sizeof(wData));
3421 		}
3422 		else
3423 		{
3424 			AddString(Text.m_lpstr);
3425 		}
3426 
3427 		AddData(&nCreationData, sizeof(nCreationData));
3428 
3429 		if ((nCreationData != 0))
3430 		{
3431 			ATLASSERT(pCreationData != NULL);
3432 			AddData(pCreationData, nCreationData * sizeof(WORD));
3433 		}
3434 	}
3435 
3436 	void AddStdControl(StdCtrlType CtrlType, WORD wId, short nX, short nY, short nWidth, short nHeight,
3437 	                   DWORD dwStyle, DWORD dwExStyle, ATL::_U_STRINGorID Text, const WORD* pCreationData = NULL, WORD nCreationData = 0, DWORD dwHelpID = 0)
3438 	{
3439 		AddControl(CtrlType, wId, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, Text, pCreationData, nCreationData, dwHelpID);
3440 	}
3441 
AddData(LPCVOID pData,size_t nData)3442 	void AddData(LPCVOID pData, size_t nData)
3443 	{
3444 		ATLASSERT(pData != NULL);
3445 
3446 		const SIZE_T ALLOCATION_INCREMENT = 1024;
3447 
3448 		if (m_pData == NULL)
3449 		{
3450 			m_cAllocated = ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
3451 			m_hData = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, m_cAllocated);
3452 			ATLASSERT(m_hData != NULL);
3453 #ifndef UNDER_CE
3454 			m_pPtr = m_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));
3455 #else
3456 			m_pPtr = m_pData = static_cast<LPBYTE>(m_hData);
3457 #endif
3458 			ATLASSERT(m_pData != NULL);
3459 		}
3460 		else if (((m_pPtr - m_pData) + nData) > m_cAllocated)
3461 		{
3462 			SIZE_T ptrPos = (m_pPtr - m_pData);
3463 			m_cAllocated += ((nData / ALLOCATION_INCREMENT) + 1) * ALLOCATION_INCREMENT;
3464 #ifndef UNDER_CE
3465 			::GlobalUnlock(m_pData);
3466 #endif
3467 			m_hData = ::GlobalReAlloc(m_hData, m_cAllocated, GMEM_MOVEABLE | GMEM_ZEROINIT);
3468 			ATLASSERT(m_hData != NULL);
3469 #ifndef UNDER_CE
3470 			m_pData = static_cast<LPBYTE>(::GlobalLock(m_hData));
3471 #else
3472 			m_pData = static_cast<LPBYTE>(m_hData);
3473 #endif
3474 			ATLASSERT(m_pData != NULL);
3475 			m_pPtr = m_pData + ptrPos;
3476 		}
3477 
3478 		SecureHelper::memcpy_x(m_pPtr, m_cAllocated - (m_pPtr - m_pData), pData, nData);
3479 
3480 		m_pPtr += nData;
3481 	}
3482 
AddString(LPCTSTR lpszStr)3483 	void AddString(LPCTSTR lpszStr)
3484 	{
3485 		if (lpszStr == NULL)
3486 		{
3487 			WCHAR szEmpty = 0;
3488 			AddData(&szEmpty, sizeof(szEmpty));
3489 		}
3490 		else
3491 		{
3492 			USES_CONVERSION;
3493 			LPCWSTR lpstr = T2CW(lpszStr);
3494 			int nSize = lstrlenW(lpstr) + 1;
3495 			AddData(lpstr, nSize * sizeof(WCHAR));
3496 		}
3497 	}
3498 };
3499 
3500 typedef CMemDlgTemplateT<ATL::CControlWinTraits>	CMemDlgTemplate;
3501 
3502 
3503 ///////////////////////////////////////////////////////////////////////////////
3504 // Dialog and control macros for indirect dialogs
3505 
3506 // for DLGTEMPLATE
3507 #define BEGIN_DIALOG(x, y, width, height) \
3508 	void DoInitTemplate() \
3509 	{ \
3510 		bool bExTemplate = false; \
3511 		short nX = x, nY = y, nWidth = width, nHeight = height; \
3512 		LPCTSTR szCaption = NULL; \
3513 		DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
3514 		DWORD dwExStyle = 0; \
3515 		LPCTSTR szFontName = NULL; \
3516 		WORD wFontSize = 0; \
3517 		WORD wWeight = 0; \
3518 		BYTE bItalic = 0; \
3519 		BYTE bCharset = 0; \
3520 		DWORD dwHelpID = 0; \
3521 		ATL::_U_STRINGorID Menu = 0U; \
3522 		ATL::_U_STRINGorID ClassName = 0U;
3523 
3524 // for DLGTEMPLATEEX
3525 #define BEGIN_DIALOG_EX(x, y, width, height, helpID) \
3526 	void DoInitTemplate() \
3527 	{ \
3528 		bool bExTemplate = true; \
3529 		short nX = x, nY = y, nWidth = width, nHeight = height; \
3530 		LPCTSTR szCaption = NULL; \
3531 		DWORD dwStyle = WS_POPUP | WS_BORDER | WS_SYSMENU; \
3532 		DWORD dwExStyle = 0; \
3533 		LPCTSTR szFontName = NULL; \
3534 		WORD wFontSize = 0; \
3535 		WORD wWeight = 0; \
3536 		BYTE bItalic = 0; \
3537 		BYTE bCharset = 0; \
3538 		DWORD dwHelpID = helpID; \
3539 		ATL::_U_STRINGorID Menu = 0U; \
3540 		ATL::_U_STRINGorID ClassName = 0U;
3541 
3542 #define END_DIALOG() \
3543 		m_Template.Create(bExTemplate, szCaption, nX, nY, nWidth, nHeight, dwStyle, dwExStyle, szFontName, wFontSize, wWeight, bItalic, bCharset, dwHelpID, ClassName, Menu); \
3544 	};
3545 
3546 #define DIALOG_CAPTION(caption) \
3547 		szCaption = caption;
3548 #define DIALOG_STYLE(style) \
3549 		dwStyle = style;
3550 #define DIALOG_EXSTYLE(exStyle) \
3551 		dwExStyle = exStyle;
3552 #define DIALOG_FONT(pointSize, typeFace) \
3553 		wFontSize = pointSize; \
3554 		szFontName = typeFace;
3555 #define DIALOG_FONT_EX(pointsize, typeface, weight, italic, charset) \
3556 		ATLASSERT(bExTemplate); \
3557 		wFontSize = pointsize; \
3558 		szFontName = typeface; \
3559 		wWeight = weight; \
3560 		bItalic = italic; \
3561 		bCharset = charset;
3562 #define DIALOG_MENU(menuName) \
3563 		Menu = menuName;
3564 #define DIALOG_CLASS(className) \
3565 		ClassName = className;
3566 
3567 #define BEGIN_CONTROLS_MAP() \
3568 	void DoInitControls() \
3569 	{
3570 
3571 #define END_CONTROLS_MAP() \
3572 	};
3573 
3574 
3575 #define CONTROL_LTEXT(text, id, x, y, width, height, style, exStyle) \
3576 	m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_LEFT | WS_GROUP, exStyle, text, NULL, 0);
3577 #define CONTROL_CTEXT(text, id, x, y, width, height, style, exStyle) \
3578 	m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_CENTER | WS_GROUP, exStyle, text, NULL, 0);
3579 #define CONTROL_RTEXT(text, id, x, y, width, height, style, exStyle) \
3580 	m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_RIGHT | WS_GROUP, exStyle, text, NULL, 0);
3581 #define CONTROL_PUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
3582 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3583 #define CONTROL_DEFPUSHBUTTON(text, id, x, y, width, height, style, exStyle) \
3584 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_DEFPUSHBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3585 #ifndef _WIN32_WCE
3586 #define CONTROL_PUSHBOX(text, id, x, y, width, height, style, exStyle) \
3587 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_PUSHBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3588 #endif // !_WIN32_WCE
3589 #define CONTROL_STATE3(text, id, x, y, width, height, style, exStyle) \
3590 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
3591 #define CONTROL_AUTO3STATE(text, id, x, y, width, height, style, exStyle) \
3592 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTO3STATE | WS_TABSTOP, exStyle, text, NULL, 0);
3593 #define CONTROL_CHECKBOX(text, id, x, y, width, height, style, exStyle) \
3594 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_CHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3595 #define CONTROL_AUTOCHECKBOX(text, id, x, y, width, height, style, exStyle) \
3596 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTOCHECKBOX | WS_TABSTOP, exStyle, text, NULL, 0);
3597 #define CONTROL_RADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
3598 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_RADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3599 #define CONTROL_AUTORADIOBUTTON(text, id, x, y, width, height, style, exStyle) \
3600 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_AUTORADIOBUTTON | WS_TABSTOP, exStyle, text, NULL, 0);
3601 #define CONTROL_COMBOBOX(id, x, y, width, height, style, exStyle) \
3602 	m_Template.AddStdControl(m_Template.CTRL_COMBOBOX, (WORD)id, x, y, width, height, style | CBS_DROPDOWN | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
3603 #define CONTROL_EDITTEXT(id, x, y, width, height, style, exStyle) \
3604 	m_Template.AddStdControl(m_Template.CTRL_EDIT, (WORD)id, x, y, width, height, style | ES_LEFT | WS_BORDER | WS_TABSTOP, exStyle, (LPCTSTR)NULL, NULL, 0);
3605 #define CONTROL_GROUPBOX(text, id, x, y, width, height, style, exStyle) \
3606 	m_Template.AddStdControl(m_Template.CTRL_BUTTON, (WORD)id, x, y, width, height, style | BS_GROUPBOX, exStyle, text, NULL, 0);
3607 #define CONTROL_LISTBOX(id, x, y, width, height, style, exStyle) \
3608 	m_Template.AddStdControl(m_Template.CTRL_LISTBOX, (WORD)id, x, y, width, height, style | LBS_NOTIFY | WS_BORDER, exStyle, (LPCTSTR)NULL, NULL, 0);
3609 #define CONTROL_SCROLLBAR(id, x, y, width, height, style, exStyle) \
3610 	m_Template.AddStdControl(m_Template.CTRL_SCROLLBAR, (WORD)id, x, y, width, height, style | SBS_HORZ, exStyle, (LPCTSTR)NULL, NULL, 0);
3611 #define CONTROL_ICON(text, id, x, y, width, height, style, exStyle) \
3612 	m_Template.AddStdControl(m_Template.CTRL_STATIC, (WORD)id, x, y, width, height, style | SS_ICON, exStyle, text, NULL, 0);
3613 #define CONTROL_CONTROL(text, id, className, style, x, y, width, height, exStyle) \
3614 	m_Template.AddControl(className, (WORD)id, x, y, width, height, style, exStyle, text, NULL, 0);
3615 
3616 
3617 ///////////////////////////////////////////////////////////////////////////////
3618 // CIndirectDialogImpl - dialogs with template in memory
3619 
3620 template <class T, class TDlgTemplate = CMemDlgTemplate, class TBase = ATL::CWindow>
3621 class ATL_NO_VTABLE CIndirectDialogImpl : public ATL::CDialogImpl< T, TBase >
3622 {
3623 public:
3624 	enum { IDD = 0 };   // no dialog template resource
3625 
3626 	TDlgTemplate m_Template;
3627 
CreateTemplate()3628 	void CreateTemplate()
3629 	{
3630 		T* pT = static_cast<T*>(this);
3631 		pT->DoInitTemplate();
3632 		pT->DoInitControls();
3633 	}
3634 
3635 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow(), LPARAM dwInitParam = NULL)
3636 	{
3637 		T* pT = static_cast<T*>(this);
3638 		ATLASSERT(pT->m_hWnd == NULL);
3639 
3640 		if(!m_Template.IsValid())
3641 			CreateTemplate();
3642 
3643 #if (_ATL_VER >= 0x0800)
3644 		// Allocate the thunk structure here, where we can fail gracefully.
3645 		BOOL bRet = m_thunk.Init(NULL, NULL);
3646 		if(bRet == FALSE)
3647 		{
3648 			::SetLastError(ERROR_OUTOFMEMORY);
3649 			return -1;
3650 		}
3651 #endif // (_ATL_VER >= 0x0800)
3652 
3653 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT);
3654 
3655 #ifdef _DEBUG
3656 		m_bModal = true;
3657 #endif // _DEBUG
3658 
3659 		return ::DialogBoxIndirectParam(ModuleHelper::GetResourceInstance(), m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
3660 	}
3661 
3662 	HWND Create(HWND hWndParent, LPARAM dwInitParam = NULL)
3663 	{
3664 		T* pT = static_cast<T*>(this);
3665 		ATLASSERT(pT->m_hWnd == NULL);
3666 
3667 		if(!m_Template.IsValid())
3668 			CreateTemplate();
3669 
3670 #if (_ATL_VER >= 0x0800)
3671 		// Allocate the thunk structure here, where we can fail gracefully.
3672 		BOOL bRet = m_thunk.Init(NULL, NULL);
3673 		if(bRet == FALSE)
3674 		{
3675 			::SetLastError(ERROR_OUTOFMEMORY);
3676 			return NULL;
3677 		}
3678 #endif // (_ATL_VER >= 0x0800)
3679 
3680 		ModuleHelper::AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBaseT< TBase >*)pT);
3681 
3682 #ifdef _DEBUG
3683 		m_bModal = false;
3684 #endif // _DEBUG
3685 
3686 		HWND hWnd = ::CreateDialogIndirectParam(ModuleHelper::GetResourceInstance(), (LPCDLGTEMPLATE)m_Template.GetTemplatePtr(), hWndParent, (DLGPROC)T::StartDialogProc, dwInitParam);
3687 		ATLASSERT(m_hWnd == hWnd);
3688 
3689 		return hWnd;
3690 	}
3691 
3692 	// for CComControl
3693 	HWND Create(HWND hWndParent, RECT&, LPARAM dwInitParam = NULL)
3694 	{
3695 		return Create(hWndParent, dwInitParam);
3696 	}
3697 
DoInitTemplate()3698 	void DoInitTemplate()
3699 	{
3700 		ATLASSERT(FALSE);   // MUST be defined in derived class
3701 	}
3702 
DoInitControls()3703 	void DoInitControls()
3704 	{
3705 		ATLASSERT(FALSE);   // MUST be defined in derived class
3706 	}
3707 };
3708 
3709 
3710 ///////////////////////////////////////////////////////////////////////////////
3711 // CPropertySheetWindow - client side for a property sheet
3712 
3713 class CPropertySheetWindow : public ATL::CWindow
3714 {
3715 public:
3716 // Constructors
CWindow(hWnd)3717 	CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
3718 	{ }
3719 
3720 	CPropertySheetWindow& operator =(HWND hWnd)
3721 	{
3722 		m_hWnd = hWnd;
3723 		return *this;
3724 	}
3725 
3726 // Attributes
GetPageCount()3727 	int GetPageCount() const
3728 	{
3729 		ATLASSERT(::IsWindow(m_hWnd));
3730 		HWND hWndTabCtrl = GetTabControl();
3731 		ATLASSERT(hWndTabCtrl != NULL);
3732 		return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);
3733 	}
3734 
GetActivePage()3735 	HWND GetActivePage() const
3736 	{
3737 		ATLASSERT(::IsWindow(m_hWnd));
3738 		return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);
3739 	}
3740 
GetActiveIndex()3741 	int GetActiveIndex() const
3742 	{
3743 		ATLASSERT(::IsWindow(m_hWnd));
3744 		HWND hWndTabCtrl = GetTabControl();
3745 		ATLASSERT(hWndTabCtrl != NULL);
3746 		return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);
3747 	}
3748 
SetActivePage(int nPageIndex)3749 	BOOL SetActivePage(int nPageIndex)
3750 	{
3751 		ATLASSERT(::IsWindow(m_hWnd));
3752 		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L);
3753 	}
3754 
SetActivePage(HPROPSHEETPAGE hPage)3755 	BOOL SetActivePage(HPROPSHEETPAGE hPage)
3756 	{
3757 		ATLASSERT(::IsWindow(m_hWnd));
3758 		ATLASSERT(hPage != NULL);
3759 		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage);
3760 	}
3761 
SetActivePageByID(int nPageID)3762 	BOOL SetActivePageByID(int nPageID)
3763 	{
3764 		ATLASSERT(::IsWindow(m_hWnd));
3765 		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID);
3766 	}
3767 
3768 	void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
3769 	{
3770 		ATLASSERT(::IsWindow(m_hWnd));
3771 		ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
3772 		ATLASSERT(lpszText != NULL);
3773 		::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText);
3774 	}
3775 
GetTabControl()3776 	HWND GetTabControl() const
3777 	{
3778 		ATLASSERT(::IsWindow(m_hWnd));
3779 		return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);
3780 	}
3781 
SetFinishText(LPCTSTR lpszText)3782 	void SetFinishText(LPCTSTR lpszText)
3783 	{
3784 		ATLASSERT(::IsWindow(m_hWnd));
3785 		::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);
3786 	}
3787 
SetWizardButtons(DWORD dwFlags)3788 	void SetWizardButtons(DWORD dwFlags)
3789 	{
3790 		ATLASSERT(::IsWindow(m_hWnd));
3791 		::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);
3792 	}
3793 
3794 // Operations
AddPage(HPROPSHEETPAGE hPage)3795 	BOOL AddPage(HPROPSHEETPAGE hPage)
3796 	{
3797 		ATLASSERT(::IsWindow(m_hWnd));
3798 		ATLASSERT(hPage != NULL);
3799 		return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
3800 	}
3801 
AddPage(LPCPROPSHEETPAGE pPage)3802 	BOOL AddPage(LPCPROPSHEETPAGE pPage)
3803 	{
3804 		ATLASSERT(::IsWindow(m_hWnd));
3805 		ATLASSERT(pPage != NULL);
3806 		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3807 		if(hPage == NULL)
3808 			return FALSE;
3809 		return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
3810 	}
3811 
3812 #ifndef _WIN32_WCE
InsertPage(int nNewPageIndex,HPROPSHEETPAGE hPage)3813 	BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage)
3814 	{
3815 		ATLASSERT(::IsWindow(m_hWnd));
3816 		ATLASSERT(hPage != NULL);
3817 		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
3818 	}
3819 
InsertPage(int nNewPageIndex,LPCPROPSHEETPAGE pPage)3820 	BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage)
3821 	{
3822 		ATLASSERT(::IsWindow(m_hWnd));
3823 		ATLASSERT(pPage != NULL);
3824 		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3825 		if(hPage == NULL)
3826 			return FALSE;
3827 		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
3828 	}
3829 
InsertPage(HPROPSHEETPAGE hPageInsertAfter,HPROPSHEETPAGE hPage)3830 	BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage)
3831 	{
3832 		ATLASSERT(::IsWindow(m_hWnd));
3833 		ATLASSERT(hPage != NULL);
3834 		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
3835 	}
3836 
InsertPage(HPROPSHEETPAGE hPageInsertAfter,LPCPROPSHEETPAGE pPage)3837 	BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage)
3838 	{
3839 		ATLASSERT(::IsWindow(m_hWnd));
3840 		ATLASSERT(pPage != NULL);
3841 		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
3842 		if(hPage == NULL)
3843 			return FALSE;
3844 		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
3845 	}
3846 #endif // !_WIN32_WCE
3847 
RemovePage(int nPageIndex)3848 	void RemovePage(int nPageIndex)
3849 	{
3850 		ATLASSERT(::IsWindow(m_hWnd));
3851 		::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L);
3852 	}
3853 
RemovePage(HPROPSHEETPAGE hPage)3854 	void RemovePage(HPROPSHEETPAGE hPage)
3855 	{
3856 		ATLASSERT(::IsWindow(m_hWnd));
3857 		ATLASSERT(hPage != NULL);
3858 		::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage);
3859 	}
3860 
PressButton(int nButton)3861 	BOOL PressButton(int nButton)
3862 	{
3863 		ATLASSERT(::IsWindow(m_hWnd));
3864 		return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);
3865 	}
3866 
Apply()3867 	BOOL Apply()
3868 	{
3869 		ATLASSERT(::IsWindow(m_hWnd));
3870 		return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L);
3871 	}
3872 
CancelToClose()3873 	void CancelToClose()
3874 	{
3875 		ATLASSERT(::IsWindow(m_hWnd));
3876 		::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L);
3877 	}
3878 
3879 	void SetModified(HWND hWndPage, BOOL bChanged = TRUE)
3880 	{
3881 		ATLASSERT(::IsWindow(m_hWnd));
3882 		ATLASSERT(::IsWindow(hWndPage));
3883 		UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED;
3884 		::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L);
3885 	}
3886 
QuerySiblings(WPARAM wParam,LPARAM lParam)3887 	LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
3888 	{
3889 		ATLASSERT(::IsWindow(m_hWnd));
3890 		return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam);
3891 	}
3892 
RebootSystem()3893 	void RebootSystem()
3894 	{
3895 		ATLASSERT(::IsWindow(m_hWnd));
3896 		::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L);
3897 	}
3898 
RestartWindows()3899 	void RestartWindows()
3900 	{
3901 		ATLASSERT(::IsWindow(m_hWnd));
3902 		::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L);
3903 	}
3904 
IsDialogMessage(LPMSG lpMsg)3905 	BOOL IsDialogMessage(LPMSG lpMsg)
3906 	{
3907 		ATLASSERT(::IsWindow(m_hWnd));
3908 		return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg);
3909 	}
3910 
3911 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
HwndToIndex(HWND hWnd)3912 	int HwndToIndex(HWND hWnd) const
3913 	{
3914 		ATLASSERT(::IsWindow(m_hWnd));
3915 		return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L);
3916 	}
3917 
IndexToHwnd(int nIndex)3918 	HWND IndexToHwnd(int nIndex) const
3919 	{
3920 		ATLASSERT(::IsWindow(m_hWnd));
3921 		return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L);
3922 	}
3923 
PageToIndex(HPROPSHEETPAGE hPage)3924 	int PageToIndex(HPROPSHEETPAGE hPage) const
3925 	{
3926 		ATLASSERT(::IsWindow(m_hWnd));
3927 		return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage);
3928 	}
3929 
IndexToPage(int nIndex)3930 	HPROPSHEETPAGE IndexToPage(int nIndex) const
3931 	{
3932 		ATLASSERT(::IsWindow(m_hWnd));
3933 		return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L);
3934 	}
3935 
IdToIndex(int nID)3936 	int IdToIndex(int nID) const
3937 	{
3938 		ATLASSERT(::IsWindow(m_hWnd));
3939 		return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID);
3940 	}
3941 
IndexToId(int nIndex)3942 	int IndexToId(int nIndex) const
3943 	{
3944 		ATLASSERT(::IsWindow(m_hWnd));
3945 		return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L);
3946 	}
3947 
GetResult()3948 	int GetResult() const
3949 	{
3950 		ATLASSERT(::IsWindow(m_hWnd));
3951 		return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L);
3952 	}
3953 
RecalcPageSizes()3954 	BOOL RecalcPageSizes()
3955 	{
3956 		ATLASSERT(::IsWindow(m_hWnd));
3957 		return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L);
3958 	}
3959 
SetHeaderTitle(int nIndex,LPCTSTR lpstrHeaderTitle)3960 	void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle)
3961 	{
3962 		ATLASSERT(::IsWindow(m_hWnd));
3963 		::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle);
3964 	}
3965 
SetHeaderSubTitle(int nIndex,LPCTSTR lpstrHeaderSubTitle)3966 	void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle)
3967 	{
3968 		ATLASSERT(::IsWindow(m_hWnd));
3969 		::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle);
3970 	}
3971 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
3972 
3973 // Implementation - override to prevent usage
3974 	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
3975 	{
3976 		ATLASSERT(FALSE);
3977 		return NULL;
3978 	}
3979 };
3980 
3981 ///////////////////////////////////////////////////////////////////////////////
3982 // CPropertySheetImpl - implements a property sheet
3983 
3984 template <class T, class TBase = CPropertySheetWindow>
3985 class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase >
3986 {
3987 public:
3988 	PROPSHEETHEADER m_psh;
3989 	ATL::CSimpleArray<HPROPSHEETPAGE> m_arrPages;
3990 
3991 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
3992   #ifndef PROPSHEET_LINK_SIZE
3993 	#define PROPSHEET_LINK_SIZE 128
3994   #endif // PROPSHEET_LINK_SIZE
3995 	TCHAR m_szLink[PROPSHEET_LINK_SIZE];
3996 	static LPCTSTR m_pszTitle;
3997 	static LPCTSTR m_pszLink;
3998 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
3999 
4000 // Construction/Destruction
4001 	CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
4002 	{
4003 		memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
4004 		m_psh.dwSize = sizeof(PROPSHEETHEADER);
4005 		m_psh.dwFlags = PSH_USECALLBACK;
4006 		m_psh.hInstance = ModuleHelper::GetResourceInstance();
4007 		m_psh.phpage = NULL;   // will be set later
4008 		m_psh.nPages = 0;      // will be set later
4009 		m_psh.pszCaption = title.m_lpstr;
4010 		m_psh.nStartPage = uStartPage;
4011 		m_psh.hwndParent = hWndParent;   // if NULL, will be set in DoModal/Create
4012 		m_psh.pfnCallback = T::PropSheetCallback;
4013 
4014 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
4015 		m_psh.dwFlags |= PSH_MAXIMIZE;
4016 		m_szLink[0] = 0;
4017 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
4018 	}
4019 
~CPropertySheetImpl()4020 	~CPropertySheetImpl()
4021 	{
4022 		if(m_arrPages.GetSize() > 0)   // sheet never created, destroy all pages
4023 		{
4024 			for(int i = 0; i < m_arrPages.GetSize(); i++)
4025 				::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]);
4026 		}
4027 	}
4028 
4029 // Callback function and overrideables
PropSheetCallback(HWND hWnd,UINT uMsg,LPARAM lParam)4030 	static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
4031 	{
4032 		lParam;   // avoid level 4 warning
4033 		int nRet = 0;
4034 
4035 		if(uMsg == PSCB_INITIALIZED)
4036 		{
4037 			ATLASSERT(hWnd != NULL);
4038 			T* pT = (T*)ModuleHelper::ExtractCreateWndData();
4039 			// subclass the sheet window
4040 			pT->SubclassWindow(hWnd);
4041 			// remove page handles array
4042 			pT->_CleanUpPages();
4043 
4044 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
4045 			m_pszTitle = pT->m_psh.pszCaption;
4046 			if(*pT->m_szLink != 0)
4047 				m_pszLink = pT->m_szLink;
4048 #endif  // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
4049 
4050 			pT->OnSheetInitialized();
4051 		}
4052 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg
4053 		else
4054 		{
4055 			switch(uMsg)
4056 			{
4057 			case PSCB_GETVERSION :
4058 				nRet = COMCTL32_VERSION;
4059 				break;
4060 			case PSCB_GETTITLE :
4061 				if(m_pszTitle != NULL)
4062 				{
4063 					lstrcpy((LPTSTR)lParam, m_pszTitle);
4064 					m_pszTitle = NULL;
4065 				}
4066 				break;
4067 			case PSCB_GETLINKTEXT:
4068 				if(m_pszLink != NULL)
4069 				{
4070 					lstrcpy((LPTSTR)lParam, m_pszLink);
4071 					m_pszLink = NULL;
4072 				}
4073 				break;
4074 			default:
4075 				break;
4076 			}
4077 		}
4078 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
4079 
4080 		return nRet;
4081 	}
4082 
OnSheetInitialized()4083 	void OnSheetInitialized()
4084 	{
4085 	}
4086 
4087 // Create method
4088 	HWND Create(HWND hWndParent = NULL)
4089 	{
4090 		ATLASSERT(m_hWnd == NULL);
4091 
4092 		m_psh.dwFlags |= PSH_MODELESS;
4093 		if(m_psh.hwndParent == NULL)
4094 			m_psh.hwndParent = hWndParent;
4095 		m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
4096 		m_psh.nPages = m_arrPages.GetSize();
4097 
4098 		T* pT = static_cast<T*>(this);
4099 
4100 #if (_ATL_VER >= 0x0800)
4101 		// Allocate the thunk structure here, where we can fail gracefully.
4102 		BOOL bRet = pT->m_thunk.Init(NULL, NULL);
4103 		if(bRet == FALSE)
4104 		{
4105 			::SetLastError(ERROR_OUTOFMEMORY);
4106 			return NULL;
4107 		}
4108 #endif // (_ATL_VER >= 0x0800)
4109 
4110 		ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
4111 
4112 		HWND hWnd = (HWND)::PropertySheet(&m_psh);
4113 		_CleanUpPages();   // ensure clean-up, required if call failed
4114 
4115 		ATLASSERT(m_hWnd == hWnd);
4116 
4117 		return hWnd;
4118 	}
4119 
4120 	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
4121 	{
4122 		ATLASSERT(m_hWnd == NULL);
4123 
4124 		m_psh.dwFlags &= ~PSH_MODELESS;
4125 		if(m_psh.hwndParent == NULL)
4126 			m_psh.hwndParent = hWndParent;
4127 		m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
4128 		m_psh.nPages = m_arrPages.GetSize();
4129 
4130 		T* pT = static_cast<T*>(this);
4131 
4132 #if (_ATL_VER >= 0x0800)
4133 		// Allocate the thunk structure here, where we can fail gracefully.
4134 		BOOL bRet = pT->m_thunk.Init(NULL, NULL);
4135 		if(bRet == FALSE)
4136 		{
4137 			::SetLastError(ERROR_OUTOFMEMORY);
4138 			return -1;
4139 		}
4140 #endif // (_ATL_VER >= 0x0800)
4141 
4142 		ModuleHelper::AddCreateWndData(&pT->m_thunk.cd, pT);
4143 
4144 		INT_PTR nRet = ::PropertySheet(&m_psh);
4145 		_CleanUpPages();   // ensure clean-up, required if call failed
4146 
4147 		return nRet;
4148 	}
4149 
4150 	// implementation helper - clean up pages array
_CleanUpPages()4151 	void _CleanUpPages()
4152 	{
4153 		m_psh.nPages = 0;
4154 		m_psh.phpage = NULL;
4155 		m_arrPages.RemoveAll();
4156 	}
4157 
4158 // Attributes (extended overrides of client class methods)
4159 // These now can be called before the sheet is created
4160 // Note: Calling these after the sheet is created gives unpredictable results
GetPageCount()4161 	int GetPageCount() const
4162 	{
4163 		if(m_hWnd == NULL)   // not created yet
4164 			return m_arrPages.GetSize();
4165 		return TBase::GetPageCount();
4166 	}
4167 
GetActiveIndex()4168 	int GetActiveIndex() const
4169 	{
4170 		if(m_hWnd == NULL)   // not created yet
4171 			return m_psh.nStartPage;
4172 		return TBase::GetActiveIndex();
4173 	}
4174 
GetPage(int nPageIndex)4175 	HPROPSHEETPAGE GetPage(int nPageIndex) const
4176 	{
4177 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4178 		return (HPROPSHEETPAGE)m_arrPages[nPageIndex];
4179 	}
4180 
GetPageIndex(HPROPSHEETPAGE hPage)4181 	int GetPageIndex(HPROPSHEETPAGE hPage) const
4182 	{
4183 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4184 		return m_arrPages.Find((HPROPSHEETPAGE&)hPage);
4185 	}
4186 
SetActivePage(int nPageIndex)4187 	BOOL SetActivePage(int nPageIndex)
4188 	{
4189 		if(m_hWnd == NULL)   // not created yet
4190 		{
4191 			ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize());
4192 			m_psh.nStartPage = nPageIndex;
4193 			return TRUE;
4194 		}
4195 		return TBase::SetActivePage(nPageIndex);
4196 	}
4197 
SetActivePage(HPROPSHEETPAGE hPage)4198 	BOOL SetActivePage(HPROPSHEETPAGE hPage)
4199 	{
4200 		ATLASSERT(hPage != NULL);
4201 		if (m_hWnd == NULL)   // not created yet
4202 		{
4203 			int nPageIndex = GetPageIndex(hPage);
4204 			if(nPageIndex == -1)
4205 				return FALSE;
4206 
4207 			return SetActivePage(nPageIndex);
4208 		}
4209 		return TBase::SetActivePage(hPage);
4210 
4211 	}
4212 
4213 	void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
4214 	{
4215 		ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0);   // only PSH_PROPTITLE is valid
4216 		ATLASSERT(lpszText != NULL);
4217 
4218 		if(m_hWnd == NULL)
4219 		{
4220 			// set internal state
4221 			m_psh.pszCaption = lpszText;   // must exist until sheet is created
4222 			m_psh.dwFlags &= ~PSH_PROPTITLE;
4223 			m_psh.dwFlags |= nStyle;
4224 		}
4225 		else
4226 		{
4227 			// set external state
4228 			TBase::SetTitle(lpszText, nStyle);
4229 		}
4230 	}
4231 
4232 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field
SetLinkText(LPCTSTR lpszText)4233 	void SetLinkText(LPCTSTR lpszText)
4234 	{
4235 		ATLASSERT(lpszText != NULL);
4236 		ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE);
4237 		lstrcpy(m_szLink, lpszText);
4238 	}
4239 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
4240 
SetWizardMode()4241 	void SetWizardMode()
4242 	{
4243 		m_psh.dwFlags |= PSH_WIZARD;
4244 	}
4245 
EnableHelp()4246 	void EnableHelp()
4247 	{
4248 		m_psh.dwFlags |= PSH_HASHELP;
4249 	}
4250 
4251 // Operations
AddPage(HPROPSHEETPAGE hPage)4252 	BOOL AddPage(HPROPSHEETPAGE hPage)
4253 	{
4254 		ATLASSERT(hPage != NULL);
4255 		BOOL bRet = FALSE;
4256 		if(m_hWnd != NULL)
4257 			bRet = TBase::AddPage(hPage);
4258 		else	// sheet not created yet, use internal data
4259 			bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage);
4260 		return bRet;
4261 	}
4262 
AddPage(LPCPROPSHEETPAGE pPage)4263 	BOOL AddPage(LPCPROPSHEETPAGE pPage)
4264 	{
4265 		ATLASSERT(pPage != NULL);
4266 		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
4267 		if(hPage == NULL)
4268 			return FALSE;
4269 		BOOL bRet = AddPage(hPage);
4270 		if(!bRet)
4271 			::DestroyPropertySheetPage(hPage);
4272 		return bRet;
4273 	}
4274 
RemovePage(HPROPSHEETPAGE hPage)4275 	BOOL RemovePage(HPROPSHEETPAGE hPage)
4276 	{
4277 		ATLASSERT(hPage != NULL);
4278 		if (m_hWnd == NULL)   // not created yet
4279 		{
4280 			int nPage = GetPageIndex(hPage);
4281 			if(nPage == -1)
4282 				return FALSE;
4283 			return RemovePage(nPage);
4284 		}
4285 		TBase::RemovePage(hPage);
4286 		return TRUE;
4287 
4288 	}
4289 
RemovePage(int nPageIndex)4290 	BOOL RemovePage(int nPageIndex)
4291 	{
4292 		BOOL bRet = TRUE;
4293 		if(m_hWnd != NULL)
4294 			TBase::RemovePage(nPageIndex);
4295 		else	// sheet not created yet, use internal data
4296 			bRet = m_arrPages.RemoveAt(nPageIndex);
4297 		return bRet;
4298 	}
4299 
4300 #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
SetHeader(LPCTSTR szbmHeader)4301 	void SetHeader(LPCTSTR szbmHeader)
4302 	{
4303 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4304 
4305 		m_psh.dwFlags &= ~PSH_WIZARD;
4306 		m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97);
4307 		m_psh.pszbmHeader = szbmHeader;
4308 	}
4309 
SetHeader(HBITMAP hbmHeader)4310 	void SetHeader(HBITMAP hbmHeader)
4311 	{
4312 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4313 
4314 		m_psh.dwFlags &= ~PSH_WIZARD;
4315 		m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97);
4316 		m_psh.hbmHeader = hbmHeader;
4317 	}
4318 
4319 	void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL)
4320 	{
4321 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4322 
4323 		m_psh.dwFlags &= ~PSH_WIZARD;
4324 		m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97;
4325 		m_psh.pszbmWatermark = szbmWatermark;
4326 
4327 		if (hplWatermark != NULL)
4328 		{
4329 			m_psh.dwFlags |= PSH_USEHPLWATERMARK;
4330 			m_psh.hplWatermark = hplWatermark;
4331 		}
4332 	}
4333 
4334 	void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL)
4335 	{
4336 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4337 
4338 		m_psh.dwFlags &= ~PSH_WIZARD;
4339 		m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97);
4340 		m_psh.hbmWatermark = hbmWatermark;
4341 
4342 		if (hplWatermark != NULL)
4343 		{
4344 			m_psh.dwFlags |= PSH_USEHPLWATERMARK;
4345 			m_psh.hplWatermark = hplWatermark;
4346 		}
4347 	}
4348 
StretchWatermark(bool bStretchWatermark)4349 	void StretchWatermark(bool bStretchWatermark)
4350 	{
4351 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4352 		if (bStretchWatermark)
4353 			m_psh.dwFlags |= PSH_STRETCHWATERMARK;
4354 		else
4355 			m_psh.dwFlags &= ~PSH_STRETCHWATERMARK;
4356 	}
4357 #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
4358 
4359 // Message map and handlers
4360 	BEGIN_MSG_MAP(CPropertySheetImpl)
MESSAGE_HANDLER(WM_COMMAND,OnCommand)4361 		MESSAGE_HANDLER(WM_COMMAND, OnCommand)
4362 		MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
4363 	END_MSG_MAP()
4364 
4365 	LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
4366 	{
4367 		LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
4368 		if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) &&
4369 		   ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))
4370 			DestroyWindow();
4371 		return lRet;
4372 	}
4373 
OnSysCommand(UINT,WPARAM wParam,LPARAM,BOOL & bHandled)4374 	LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
4375 	{
4376 		if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE))
4377 			SendMessage(WM_CLOSE);
4378 		else
4379 			bHandled = FALSE;
4380 		return 0;
4381 	}
4382 };
4383 
4384 #if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers
4385 template < class T, class TBase >
4386 LPCWSTR CPropertySheetImpl<T,TBase>::m_pszTitle = NULL;
4387 template < class T, class TBase>
4388 LPCWSTR CPropertySheetImpl<T,TBase>::m_pszLink = NULL;
4389 #endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
4390 
4391 // for non-customized sheets
4392 class CPropertySheet : public CPropertySheetImpl<CPropertySheet>
4393 {
4394 public:
4395 	CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
4396 		: CPropertySheetImpl<CPropertySheet>(title, uStartPage, hWndParent)
4397 	{ }
4398 };
4399 
4400 
4401 ///////////////////////////////////////////////////////////////////////////////
4402 // CPropertyPageWindow - client side for a property page
4403 
4404 class CPropertyPageWindow : public ATL::CWindow
4405 {
4406 public:
4407 // Constructors
CWindow(hWnd)4408 	CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
4409 	{ }
4410 
4411 	CPropertyPageWindow& operator =(HWND hWnd)
4412 	{
4413 		m_hWnd = hWnd;
4414 		return *this;
4415 	}
4416 
4417 // Attributes
GetPropertySheet()4418 	CPropertySheetWindow GetPropertySheet() const
4419 	{
4420 		ATLASSERT(::IsWindow(m_hWnd));
4421 		return CPropertySheetWindow(GetParent());
4422 	}
4423 
4424 // Operations
Apply()4425 	BOOL Apply()
4426 	{
4427 		ATLASSERT(::IsWindow(m_hWnd));
4428 		ATLASSERT(GetParent() != NULL);
4429 		return GetPropertySheet().Apply();
4430 	}
4431 
CancelToClose()4432 	void CancelToClose()
4433 	{
4434 		ATLASSERT(::IsWindow(m_hWnd));
4435 		ATLASSERT(GetParent() != NULL);
4436 		GetPropertySheet().CancelToClose();
4437 	}
4438 
4439 	void SetModified(BOOL bChanged = TRUE)
4440 	{
4441 		ATLASSERT(::IsWindow(m_hWnd));
4442 		ATLASSERT(GetParent() != NULL);
4443 		GetPropertySheet().SetModified(m_hWnd, bChanged);
4444 	}
4445 
QuerySiblings(WPARAM wParam,LPARAM lParam)4446 	LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
4447 	{
4448 		ATLASSERT(::IsWindow(m_hWnd));
4449 		ATLASSERT(GetParent() != NULL);
4450 		return GetPropertySheet().QuerySiblings(wParam, lParam);
4451 	}
4452 
RebootSystem()4453 	void RebootSystem()
4454 	{
4455 		ATLASSERT(::IsWindow(m_hWnd));
4456 		ATLASSERT(GetParent() != NULL);
4457 		GetPropertySheet().RebootSystem();
4458 	}
4459 
RestartWindows()4460 	void RestartWindows()
4461 	{
4462 		ATLASSERT(::IsWindow(m_hWnd));
4463 		ATLASSERT(GetParent() != NULL);
4464 		GetPropertySheet().RestartWindows();
4465 	}
4466 
SetWizardButtons(DWORD dwFlags)4467 	void SetWizardButtons(DWORD dwFlags)
4468 	{
4469 		ATLASSERT(::IsWindow(m_hWnd));
4470 		ATLASSERT(GetParent() != NULL);
4471 		GetPropertySheet().SetWizardButtons(dwFlags);
4472 	}
4473 
4474 // Implementation - overrides to prevent usage
4475 	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
4476 	{
4477 		ATLASSERT(FALSE);
4478 		return NULL;
4479 	}
4480 };
4481 
4482 ///////////////////////////////////////////////////////////////////////////////
4483 // CPropertyPageImpl - implements a property page
4484 
4485 template <class T, class TBase = CPropertyPageWindow>
4486 class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase >
4487 {
4488 public:
4489 	PROPSHEETPAGE m_psp;
4490 
4491 	operator PROPSHEETPAGE*() { return &m_psp; }
4492 
4493 // Construction
4494 	CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
4495 	{
4496 		// initialize PROPSHEETPAGE struct
4497 		memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
4498 		m_psp.dwSize = sizeof(PROPSHEETPAGE);
4499 		m_psp.dwFlags = PSP_USECALLBACK;
4500 		m_psp.hInstance = ModuleHelper::GetResourceInstance();
4501 		T* pT = static_cast<T*>(this);
4502 		m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD);
4503 		m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;
4504 		m_psp.pfnCallback = T::PropPageCallback;
4505 		m_psp.lParam = (LPARAM)pT;
4506 
4507 		if(title.m_lpstr != NULL)
4508 			SetTitle(title);
4509 	}
4510 
4511 // Callback function and overrideables
PropPageCallback(HWND hWnd,UINT uMsg,LPPROPSHEETPAGE ppsp)4512 	static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
4513 	{
4514 		hWnd;   // avoid level 4 warning
4515 		ATLASSERT(hWnd == NULL);
4516 		T* pT = (T*)ppsp->lParam;
4517 		UINT uRet = 0;
4518 
4519 		switch(uMsg)
4520 		{
4521 		case PSPCB_CREATE:
4522 			{
4523 				ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT;
4524 				ModuleHelper::AddCreateWndData(&pPage->m_thunk.cd, pPage);
4525 				uRet = pT->OnPageCreate() ? 1 : 0;
4526 			}
4527 			break;
4528 #if (_WIN32_IE >= 0x0500)
4529 		case PSPCB_ADDREF:
4530 			pT->OnPageAddRef();
4531 			break;
4532 #endif // (_WIN32_IE >= 0x0500)
4533 		case PSPCB_RELEASE:
4534 			pT->OnPageRelease();
4535 			break;
4536 		default:
4537 			break;
4538 		}
4539 
4540 		return uRet;
4541 	}
4542 
OnPageCreate()4543 	bool OnPageCreate()
4544 	{
4545 		return true;   // true - allow page to be created, false - prevent creation
4546 	}
4547 
4548 #if (_WIN32_IE >= 0x0500)
OnPageAddRef()4549 	void OnPageAddRef()
4550 	{
4551 	}
4552 #endif // (_WIN32_IE >= 0x0500)
4553 
OnPageRelease()4554 	void OnPageRelease()
4555 	{
4556 	}
4557 
4558 // Create method
Create()4559 	HPROPSHEETPAGE Create()
4560 	{
4561 		return ::CreatePropertySheetPage(&m_psp);
4562 	}
4563 
4564 // Attributes
SetTitle(ATL::_U_STRINGorID title)4565 	void SetTitle(ATL::_U_STRINGorID title)
4566 	{
4567 		m_psp.pszTitle = title.m_lpstr;
4568 		m_psp.dwFlags |= PSP_USETITLE;
4569 	}
4570 
4571 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
SetHeaderTitle(LPCTSTR lpstrHeaderTitle)4572 	void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)
4573 	{
4574 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4575 		m_psp.dwFlags |= PSP_USEHEADERTITLE;
4576 		m_psp.pszHeaderTitle = lpstrHeaderTitle;
4577 	}
4578 
SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)4579 	void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)
4580 	{
4581 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
4582 		m_psp.dwFlags |= PSP_USEHEADERSUBTITLE;
4583 		m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle;
4584 	}
4585 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
4586 
4587 // Operations
EnableHelp()4588 	void EnableHelp()
4589 	{
4590 		m_psp.dwFlags |= PSP_HASHELP;
4591 	}
4592 
4593 // Message map and handlers
4594 	BEGIN_MSG_MAP(CPropertyPageImpl)
MESSAGE_HANDLER(WM_NOTIFY,OnNotify)4595 		MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
4596 	END_MSG_MAP()
4597 
4598 	// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
4599 	// handlers that return direct values without any restrictions
4600 	LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
4601 	{
4602 #ifndef _WIN32_WCE
4603 		// This notification is sometimes received on Windows CE after the window is already destroyed
4604 		ATLASSERT(::IsWindow(m_hWnd));
4605 #endif
4606 		NMHDR* pNMHDR = (NMHDR*)lParam;
4607 
4608 		// don't handle messages not from the page/sheet itself
4609 		if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
4610 		{
4611 			bHandled = FALSE;
4612 			return 1;
4613 		}
4614 #ifdef _WIN32_WCE
4615 		ATLASSERT(::IsWindow(m_hWnd));
4616 #endif
4617 
4618 		T* pT = static_cast<T*>(this);
4619 		LRESULT lResult = 0;
4620 		switch(pNMHDR->code)
4621 		{
4622 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
4623 		case PSN_SETACTIVE:
4624 			lResult = pT->OnSetActive();
4625 			break;
4626 		case PSN_KILLACTIVE:
4627 			lResult = pT->OnKillActive();
4628 			break;
4629 		case PSN_APPLY:
4630 			lResult = pT->OnApply();
4631 			break;
4632 		case PSN_RESET:
4633 			pT->OnReset();
4634 			break;
4635 		case PSN_QUERYCANCEL:
4636 			lResult = pT->OnQueryCancel();
4637 			break;
4638 		case PSN_WIZNEXT:
4639 			lResult = pT->OnWizardNext();
4640 			break;
4641 		case PSN_WIZBACK:
4642 			lResult = pT->OnWizardBack();
4643 			break;
4644 		case PSN_WIZFINISH:
4645 			lResult = pT->OnWizardFinish();
4646 			break;
4647 		case PSN_HELP:
4648 			pT->OnHelp();
4649 			break;
4650 #ifndef _WIN32_WCE
4651 #if (_WIN32_IE >= 0x0400)
4652 		case PSN_GETOBJECT:
4653 			if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
4654 				bHandled = FALSE;
4655 			break;
4656 #endif // (_WIN32_IE >= 0x0400)
4657 #if (_WIN32_IE >= 0x0500)
4658 		case PSN_TRANSLATEACCELERATOR:
4659 			{
4660 				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4661 				lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam);
4662 			}
4663 			break;
4664 		case PSN_QUERYINITIALFOCUS:
4665 			{
4666 				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4667 				lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
4668 			}
4669 			break;
4670 #endif // (_WIN32_IE >= 0x0500)
4671 #endif // !_WIN32_WCE
4672 
4673 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4674 		case PSN_SETACTIVE:
4675 			lResult = pT->OnSetActive() ? 0 : -1;
4676 			break;
4677 		case PSN_KILLACTIVE:
4678 			lResult = !pT->OnKillActive();
4679 			break;
4680 		case PSN_APPLY:
4681 			lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
4682 			break;
4683 		case PSN_RESET:
4684 			pT->OnReset();
4685 			break;
4686 		case PSN_QUERYCANCEL:
4687 			lResult = !pT->OnQueryCancel();
4688 			break;
4689 		case PSN_WIZNEXT:
4690 			lResult = pT->OnWizardNext();
4691 			break;
4692 		case PSN_WIZBACK:
4693 			lResult = pT->OnWizardBack();
4694 			break;
4695 		case PSN_WIZFINISH:
4696 			lResult = !pT->OnWizardFinish();
4697 			break;
4698 		case PSN_HELP:
4699 			pT->OnHelp();
4700 			break;
4701 #ifndef _WIN32_WCE
4702 #if (_WIN32_IE >= 0x0400)
4703 		case PSN_GETOBJECT:
4704 			if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
4705 				bHandled = FALSE;
4706 			break;
4707 #endif // (_WIN32_IE >= 0x0400)
4708 #if (_WIN32_IE >= 0x0500)
4709 		case PSN_TRANSLATEACCELERATOR:
4710 			{
4711 				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4712 				lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
4713 			}
4714 			break;
4715 		case PSN_QUERYINITIALFOCUS:
4716 			{
4717 				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
4718 				lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
4719 			}
4720 			break;
4721 #endif // (_WIN32_IE >= 0x0500)
4722 #endif // !_WIN32_WCE
4723 
4724 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4725 		default:
4726 			bHandled = FALSE;   // not handled
4727 		}
4728 
4729 		return lResult;
4730 	}
4731 
4732 // Overridables
4733 	// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
4734 	// handlers that return direct values without any restrictions
4735 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
OnSetActive()4736 	int OnSetActive()
4737 	{
4738 		// 0 = allow activate
4739 		// -1 = go back that was active
4740 		// page ID = jump to page
4741 		return 0;
4742 	}
4743 
OnKillActive()4744 	BOOL OnKillActive()
4745 	{
4746 		// FALSE = allow deactivate
4747 		// TRUE = prevent deactivation
4748 		return FALSE;
4749 	}
4750 
OnApply()4751 	int OnApply()
4752 	{
4753 		// PSNRET_NOERROR = apply OK
4754 		// PSNRET_INVALID = apply not OK, return to this page
4755 		// PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus
4756 		return PSNRET_NOERROR;
4757 	}
4758 
OnReset()4759 	void OnReset()
4760 	{
4761 	}
4762 
OnQueryCancel()4763 	BOOL OnQueryCancel()
4764 	{
4765 		// FALSE = allow cancel
4766 		// TRUE = prevent cancel
4767 		return FALSE;
4768 	}
4769 
OnWizardBack()4770 	int OnWizardBack()
4771 	{
4772 		// 0  = goto previous page
4773 		// -1 = prevent page change
4774 		// >0 = jump to page by dlg ID
4775 		return 0;
4776 	}
4777 
OnWizardNext()4778 	int OnWizardNext()
4779 	{
4780 		// 0  = goto next page
4781 		// -1 = prevent page change
4782 		// >0 = jump to page by dlg ID
4783 		return 0;
4784 	}
4785 
OnWizardFinish()4786 	INT_PTR OnWizardFinish()
4787 	{
4788 		// FALSE = allow finish
4789 		// TRUE = prevent finish
4790 		// HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only)
4791 		return FALSE;
4792 	}
4793 
OnHelp()4794 	void OnHelp()
4795 	{
4796 	}
4797 
4798 #ifndef _WIN32_WCE
4799 #if (_WIN32_IE >= 0x0400)
OnGetObject(LPNMOBJECTNOTIFY)4800 	BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
4801 	{
4802 		return FALSE;   // not processed
4803 	}
4804 #endif // (_WIN32_IE >= 0x0400)
4805 
4806 #if (_WIN32_IE >= 0x0500)
OnTranslateAccelerator(LPMSG)4807 	int OnTranslateAccelerator(LPMSG /*lpMsg*/)
4808 	{
4809 		// PSNRET_NOERROR - message not handled
4810 		// PSNRET_MESSAGEHANDLED - message handled
4811 		return PSNRET_NOERROR;
4812 	}
4813 
OnQueryInitialFocus(HWND)4814 	HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
4815 	{
4816 		// NULL = set focus to default control
4817 		// HWND = set focus to HWND
4818 		return NULL;
4819 	}
4820 #endif // (_WIN32_IE >= 0x0500)
4821 #endif // !_WIN32_WCE
4822 
4823 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
OnSetActive()4824 	BOOL OnSetActive()
4825 	{
4826 		return TRUE;
4827 	}
4828 
OnKillActive()4829 	BOOL OnKillActive()
4830 	{
4831 		return TRUE;
4832 	}
4833 
OnApply()4834 	BOOL OnApply()
4835 	{
4836 		return TRUE;
4837 	}
4838 
OnReset()4839 	void OnReset()
4840 	{
4841 	}
4842 
OnQueryCancel()4843 	BOOL OnQueryCancel()
4844 	{
4845 		return TRUE;    // ok to cancel
4846 	}
4847 
OnWizardBack()4848 	int OnWizardBack()
4849 	{
4850 		// 0  = goto previous page
4851 		// -1 = prevent page change
4852 		// >0 = jump to page by dlg ID
4853 		return 0;
4854 	}
4855 
OnWizardNext()4856 	int OnWizardNext()
4857 	{
4858 		// 0  = goto next page
4859 		// -1 = prevent page change
4860 		// >0 = jump to page by dlg ID
4861 		return 0;
4862 	}
4863 
OnWizardFinish()4864 	BOOL OnWizardFinish()
4865 	{
4866 		return TRUE;
4867 	}
4868 
OnHelp()4869 	void OnHelp()
4870 	{
4871 	}
4872 
4873 #ifndef _WIN32_WCE
4874 #if (_WIN32_IE >= 0x0400)
OnGetObject(LPNMOBJECTNOTIFY)4875 	BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
4876 	{
4877 		return FALSE;   // not processed
4878 	}
4879 #endif // (_WIN32_IE >= 0x0400)
4880 
4881 #if (_WIN32_IE >= 0x0500)
OnTranslateAccelerator(LPMSG)4882 	BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/)
4883 	{
4884 		return FALSE;   // not translated
4885 	}
4886 
OnQueryInitialFocus(HWND)4887 	HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
4888 	{
4889 		return NULL;   // default
4890 	}
4891 #endif // (_WIN32_IE >= 0x0500)
4892 #endif // !_WIN32_WCE
4893 
4894 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
4895 };
4896 
4897 // for non-customized pages
4898 template <WORD t_wDlgTemplateID>
4899 class CPropertyPage : public CPropertyPageImpl<CPropertyPage<t_wDlgTemplateID> >
4900 {
4901 public:
4902 	enum { IDD = t_wDlgTemplateID };
4903 
4904 	CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<CPropertyPage>(title)
4905 	{ }
4906 
4907 	DECLARE_EMPTY_MSG_MAP()
4908 };
4909 
4910 ///////////////////////////////////////////////////////////////////////////////
4911 // CAxPropertyPageImpl - property page that hosts ActiveX controls
4912 
4913 #ifndef _ATL_NO_HOSTING
4914 
4915 // Note: You must #include <atlhost.h> to use these classes
4916 
4917 template <class T, class TBase = CPropertyPageWindow>
4918 class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase >
4919 {
4920 public:
4921 // Data members
4922 	HGLOBAL m_hInitData;
4923 	HGLOBAL m_hDlgRes;
4924 	HGLOBAL m_hDlgResSplit;
4925 
4926 // Constructor/destructor
4927 	CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) :
4928 			CPropertyPageImpl< T, TBase >(title),
4929 			m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL)
4930 	{
4931 		T* pT = static_cast<T*>(this);
4932 		pT;   // avoid level 4 warning
4933 
4934 		// initialize ActiveX hosting and modify dialog template
4935 		ATL::AtlAxWinInit();
4936 
4937 		HINSTANCE hInstance = ModuleHelper::GetResourceInstance();
4938 		LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD);
4939 		HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG);
4940 		if(hDlg != NULL)
4941 		{
4942 			HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT);
4943 
4944 			BYTE* pInitData = NULL;
4945 			if(hDlgInit != NULL)
4946 			{
4947 				m_hInitData = ::LoadResource(hInstance, hDlgInit);
4948 				pInitData = (BYTE*)::LockResource(m_hInitData);
4949 			}
4950 
4951 			m_hDlgRes = ::LoadResource(hInstance, hDlg);
4952 			DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes);
4953 			LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData);
4954 			if(lpDialogTemplate != pDlg)
4955 				m_hDlgResSplit = GlobalHandle(lpDialogTemplate);
4956 
4957 			// set up property page to use in-memory dialog template
4958 			if(lpDialogTemplate != NULL)
4959 			{
4960 				m_psp.dwFlags |= PSP_DLGINDIRECT;
4961 				m_psp.pResource = lpDialogTemplate;
4962 			}
4963 			else
4964 			{
4965 				ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!"));
4966 			}
4967 		}
4968 		else
4969 		{
4970 			ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!"));
4971 		}
4972 	}
4973 
~CAxPropertyPageImpl()4974 	~CAxPropertyPageImpl()
4975 	{
4976 		if(m_hInitData != NULL)
4977 		{
4978 			UnlockResource(m_hInitData);
4979 			FreeResource(m_hInitData);
4980 		}
4981 		if(m_hDlgRes != NULL)
4982 		{
4983 			UnlockResource(m_hDlgRes);
4984 			FreeResource(m_hDlgRes);
4985 		}
4986 		if(m_hDlgResSplit != NULL)
4987 		{
4988 			::GlobalFree(m_hDlgResSplit);
4989 		}
4990 	}
4991 
4992 // Methods
4993 	// call this one to handle keyboard message for ActiveX controls
PreTranslateMessage(LPMSG pMsg)4994 	BOOL PreTranslateMessage(LPMSG pMsg)
4995 	{
4996 		if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
4997 		   (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
4998 			return FALSE;
4999 		// find a direct child of the dialog from the window that has focus
5000 		HWND hWndCtl = ::GetFocus();
5001 		if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd)
5002 		{
5003 			do
5004 			{
5005 				hWndCtl = ::GetParent(hWndCtl);
5006 			}
5007 			while (::GetParent(hWndCtl) != m_hWnd);
5008 		}
5009 		// give controls a chance to translate this message
5010 		return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg);
5011 	}
5012 
5013 // Overridables
5014 #if (_WIN32_IE >= 0x0500)
5015 	// new default implementation for ActiveX hosting pages
5016 #ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
OnTranslateAccelerator(LPMSG lpMsg)5017 	int OnTranslateAccelerator(LPMSG lpMsg)
5018 	{
5019 		T* pT = static_cast<T*>(this);
5020 		return (pT->PreTranslateMessage(lpMsg) != FALSE) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
5021 	}
5022 #else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
OnTranslateAccelerator(LPMSG lpMsg)5023 	BOOL OnTranslateAccelerator(LPMSG lpMsg)
5024 	{
5025 		T* pT = static_cast<T*>(this);
5026 		return pT->PreTranslateMessage(lpMsg);
5027 	}
5028 #endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
5029 #endif // (_WIN32_IE >= 0x0500)
5030 
5031 // Support for new stuff in ATL7
5032 #if (_ATL_VER >= 0x0700)
GetIDD()5033 	int GetIDD()
5034 	{
5035 		return( static_cast<T*>(this)->IDD );
5036 	}
5037 
GetDialogProc()5038 	virtual DLGPROC GetDialogProc()
5039 	{
5040 		return DialogProc;
5041 	}
5042 
DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)5043 	static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
5044 	{
5045 		CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd;
5046 		if (uMsg == WM_INITDIALOG)
5047 		{
5048 			HRESULT hr;
5049 			if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD())))
5050 			{
5051 				ATLASSERT(FALSE);
5052 				return FALSE;
5053 			}
5054 		}
5055 		return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam);
5056 	}
5057 
5058 // ActiveX controls creation
CreateActiveXControls(UINT nID)5059 	virtual HRESULT CreateActiveXControls(UINT nID)
5060 	{
5061 		// Load dialog template and InitData
5062 		HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT);
5063 		BYTE* pInitData = NULL;
5064 		HGLOBAL hData = NULL;
5065 		HRESULT hr = S_OK;
5066 		if (hDlgInit != NULL)
5067 		{
5068 			hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit);
5069 			if (hData != NULL)
5070 				pInitData = (BYTE*) ::LockResource(hData);
5071 		}
5072 
5073 		HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG);
5074 		if (hDlg != NULL)
5075 		{
5076 			HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg);
5077 			DLGTEMPLATE* pDlg = NULL;
5078 			if (hResource != NULL)
5079 			{
5080 				pDlg = (DLGTEMPLATE*) ::LockResource(hResource);
5081 				if (pDlg != NULL)
5082 				{
5083 					// Get first control on the template
5084 					BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg);
5085 					WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg);
5086 
5087 					// Get first control on the dialog
5088 					DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg);
5089 					HWND hWndPrev = GetWindow(GW_CHILD);
5090 
5091 					// Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order)
5092 					for (WORD nItem = 0; nItem < nItems; nItem++)
5093 					{
5094 						DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id;
5095 						if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx))
5096 						{
5097 							BYTE* pData = NULL;
5098 							DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData);
5099 							ATL::CComPtr<IStream> spStream;
5100 							if (dwLen != 0)
5101 							{
5102 								HGLOBAL h = GlobalAlloc(GHND, dwLen);
5103 								if (h != NULL)
5104 								{
5105 									BYTE* pBytes = (BYTE*) GlobalLock(h);
5106 									BYTE* pSource = pData;
5107 									SecureHelper::memcpy_x(pBytes, dwLen, pSource, dwLen);
5108 									GlobalUnlock(h);
5109 									CreateStreamOnHGlobal(h, TRUE, &spStream);
5110 								}
5111 								else
5112 								{
5113 									hr = E_OUTOFMEMORY;
5114 									break;
5115 								}
5116 							}
5117 
5118 							ATL::CComBSTR bstrLicKey;
5119 							hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str);
5120 							if (SUCCEEDED(hr))
5121 							{
5122 								ATL::CAxWindow2 wnd;
5123 								// Get control caption.
5124 								LPWSTR pszClassName =
5125 									bDialogEx ?
5126 										(LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) :
5127 										(LPWSTR)(pItem + 1);
5128 								// Get control rect.
5129 								RECT rect = { 0 };
5130 								rect.left = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : pItem->x;
5131 								rect.top = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : pItem->y;
5132 								rect.right = rect.left + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : pItem->cx);
5133 								rect.bottom = rect.top + (bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : pItem->cy);
5134 
5135 								// Convert from dialog units to screen units
5136 								MapDialogRect(&rect);
5137 
5138 								// Create AxWindow with a NULL caption.
5139 								wnd.Create(m_hWnd,
5140 									&rect,
5141 									NULL,
5142 									(bDialogEx ?
5143 										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style :
5144 										pItem->style) | WS_TABSTOP,
5145 									bDialogEx ?
5146 										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle :
5147 										0,
5148 									bDialogEx ?
5149 										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id :
5150 										pItem->id,
5151 									NULL);
5152 
5153 								if (wnd != NULL)
5154 								{
5155 #ifndef _WIN32_WCE
5156 									// Set the Help ID
5157 									if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0)
5158 										wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID);
5159 #endif // !_WIN32_WCE
5160 									// Try to create the ActiveX control.
5161 									hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey);
5162 									if (FAILED(hr))
5163 										break;
5164 									// Set the correct tab position.
5165 									if (nItem == 0)
5166 										hWndPrev = HWND_TOP;
5167 									wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
5168 									hWndPrev = wnd;
5169 								}
5170 								else
5171 								{
5172 									hr = ATL::AtlHresultFromLastError();
5173 								}
5174 							}
5175 						}
5176 						else
5177 						{
5178 							if (nItem != 0)
5179 								hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);
5180 						}
5181 						pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx);
5182 					}
5183 				}
5184 				else
5185 					hr = ATL::AtlHresultFromLastError();
5186 			}
5187 			else
5188 				hr = ATL::AtlHresultFromLastError();
5189 		}
5190 		return hr;
5191 	}
5192 
5193 // Event handling support
AdviseSinkMap(bool bAdvise)5194 	HRESULT AdviseSinkMap(bool bAdvise)
5195 	{
5196 		if(!bAdvise && m_hWnd == NULL)
5197 		{
5198 			// window is gone, controls are already unadvised
5199 			ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n"));
5200 			return S_OK;
5201 		}
5202 		HRESULT hRet = E_NOTIMPL;
5203 		__if_exists(T::_GetSinkMapFinder)
5204 		{
5205 			T* pT = static_cast<T*>(this);
5206 			hRet = AtlAdviseSinkMap(pT, bAdvise);
5207 		}
5208 		return hRet;
5209 	}
5210 
5211 // Message map and handlers
5212 	typedef CPropertyPageImpl< T, TBase>   _baseClass;
5213 	BEGIN_MSG_MAP(CAxPropertyPageImpl)
MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)5214 		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
5215 		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
5216 		CHAIN_MSG_MAP(_baseClass)
5217 	END_MSG_MAP()
5218 
5219 	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
5220 	{
5221 		// initialize controls in dialog with DLGINIT resource section
5222 		ExecuteDlgInit(static_cast<T*>(this)->IDD);
5223 		AdviseSinkMap(true);
5224 		bHandled = FALSE;
5225 		return 1;
5226 	}
5227 
OnDestroy(UINT,WPARAM,LPARAM,BOOL & bHandled)5228 	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
5229 	{
5230 		AdviseSinkMap(false);
5231 		bHandled = FALSE;
5232 		return 1;
5233 	}
5234 #endif // (_ATL_VER >= 0x0700)
5235 };
5236 
5237 // for non-customized pages
5238 template <WORD t_wDlgTemplateID>
5239 class CAxPropertyPage : public CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >
5240 {
5241 public:
5242 	enum { IDD = t_wDlgTemplateID };
5243 
5244 	CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl<CAxPropertyPage>(title)
5245 	{ }
5246 
5247 #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
5248 	// not empty so we handle accelerators/create controls
5249 	BEGIN_MSG_MAP(CAxPropertyPage)
5250 		CHAIN_MSG_MAP(CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >)
5251 	END_MSG_MAP()
5252 #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5253 	DECLARE_EMPTY_MSG_MAP()
5254 #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5255 };
5256 
5257 #endif // _ATL_NO_HOSTING
5258 
5259 
5260 ///////////////////////////////////////////////////////////////////////////////
5261 // Wizard97 Support
5262 
5263 #if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
5264 
5265 // Sample wizard dialog resources:
5266 //
5267 // IDD_WIZ97_INTERIOR_BLANK DIALOG  0, 0, 317, 143
5268 // STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
5269 // CAPTION "Wizard97 Property Page - Interior"
5270 // FONT 8, "MS Shell Dlg"
5271 // BEGIN
5272 // END
5273 //
5274 // IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193
5275 // STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
5276 // CAPTION "Wizard97 Property Page - Welcome/Complete"
5277 // FONT 8, "MS Shell Dlg", 0, 0, 0x0
5278 // BEGIN
5279 //    LTEXT           "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8,
5280 //                    195,24
5281 //    LTEXT           "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)",
5282 //                    IDC_STATIC,115,40,195,16
5283 //    LTEXT           "h",IDC_WIZ97_BULLET1,118,64,8,8
5284 //    LTEXT           "List Item 1 (the h is turned into a bullet)",IDC_STATIC,
5285 //                    127,63,122,8
5286 //    LTEXT           "h",IDC_WIZ97_BULLET2,118,79,8,8
5287 //    LTEXT           "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC,
5288 //                    127,78,33,8
5289 //    CONTROL         "&Do not show this Welcome page again",
5290 //                    IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX |
5291 //                    WS_TABSTOP,115,169,138,10
5292 // END
5293 //
5294 // GUIDELINES DESIGNINFO
5295 // BEGIN
5296 //    IDD_WIZ97_INTERIOR_BLANK, DIALOG
5297 //    BEGIN
5298 //        LEFTMARGIN, 7
5299 //        RIGHTMARGIN, 310
5300 //        VERTGUIDE, 21
5301 //        VERTGUIDE, 31
5302 //        VERTGUIDE, 286
5303 //        VERTGUIDE, 296
5304 //        TOPMARGIN, 7
5305 //        BOTTOMMARGIN, 136
5306 //        HORZGUIDE, 8
5307 //    END
5308 //
5309 //    IDD_WIZ97_EXTERIOR_BLANK, DIALOG
5310 //    BEGIN
5311 //        RIGHTMARGIN, 310
5312 //        VERTGUIDE, 115
5313 //        VERTGUIDE, 118
5314 //        VERTGUIDE, 127
5315 //        TOPMARGIN, 7
5316 //        BOTTOMMARGIN, 186
5317 //        HORZGUIDE, 8
5318 //        HORZGUIDE, 32
5319 //        HORZGUIDE, 40
5320 //        HORZGUIDE, 169
5321 //    END
5322 // END
5323 
5324 ///////////////////////////////////////////////////////////////////////////////
5325 // CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet
5326 
5327 class CWizard97SheetWindow : public CPropertySheetWindow
5328 {
5329 public:
5330 // Constructors
CPropertySheetWindow(hWnd)5331 	CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
5332 	{ }
5333 
5334 	CWizard97SheetWindow& operator =(HWND hWnd)
5335 	{
5336 		m_hWnd = hWnd;
5337 		return *this;
5338 	}
5339 
5340 // Operations
GetExteriorPageTitleFont(void)5341 	HFONT GetExteriorPageTitleFont(void)
5342 	{
5343 		ATLASSERT(::IsWindow(m_hWnd));
5344 		return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L);
5345 	}
5346 
GetBulletFont(void)5347 	HFONT GetBulletFont(void)
5348 	{
5349 		ATLASSERT(::IsWindow(m_hWnd));
5350 		return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L);
5351 	}
5352 
5353 // Helpers
GetMessage_GetExteriorPageTitleFont()5354 	static UINT GetMessage_GetExteriorPageTitleFont()
5355 	{
5356 		static UINT uGetExteriorPageTitleFont = 0;
5357 		if(uGetExteriorPageTitleFont == 0)
5358 		{
5359 			CStaticDataInitCriticalSectionLock lock;
5360 			if(FAILED(lock.Lock()))
5361 			{
5362 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n"));
5363 				ATLASSERT(FALSE);
5364 				return 0;
5365 			}
5366 
5367 			if(uGetExteriorPageTitleFont == 0)
5368 				uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12"));
5369 
5370 			lock.Unlock();
5371 		}
5372 		ATLASSERT(uGetExteriorPageTitleFont != 0);
5373 		return uGetExteriorPageTitleFont;
5374 	}
5375 
GetMessage_GetBulletFont()5376 	static UINT GetMessage_GetBulletFont()
5377 	{
5378 		static UINT uGetBulletFont = 0;
5379 		if(uGetBulletFont == 0)
5380 		{
5381 			CStaticDataInitCriticalSectionLock lock;
5382 			if(FAILED(lock.Lock()))
5383 			{
5384 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n"));
5385 				ATLASSERT(FALSE);
5386 				return 0;
5387 			}
5388 
5389 			if(uGetBulletFont == 0)
5390 				uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5"));
5391 
5392 			lock.Unlock();
5393 		}
5394 		ATLASSERT(uGetBulletFont != 0);
5395 		return uGetBulletFont;
5396 	}
5397 
5398 // Implementation - override to prevent usage
5399 	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
5400 	{
5401 		ATLASSERT(FALSE);
5402 		return NULL;
5403 	}
5404 };
5405 
5406 
5407 ///////////////////////////////////////////////////////////////////////////////
5408 // CWizard97SheetImpl - implements a Wizard 97 style wizard sheet
5409 
5410 template <class T, class TBase = CWizard97SheetWindow>
5411 class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase >
5412 {
5413 protected:
5414 // Typedefs
5415 	typedef CWizard97SheetImpl< T, TBase > thisClass;
5416 	typedef CPropertySheetImpl< T, TBase > baseClass;
5417 
5418 // Member variables
5419 	CFont m_fontExteriorPageTitle;   // Welcome and Completion page title font
5420 	CFont m_fontBullet;              // Bullet font (used on static text 'h' to produce a small bullet)
5421 	bool m_bReceivedFirstSizeMessage;
5422 
5423 public:
5424 	CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
baseClass(title,uStartPage,hWndParent)5425 			baseClass(title, uStartPage, hWndParent),
5426 			m_bReceivedFirstSizeMessage(false)
5427 	{
5428 		m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP);
5429 		m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE);
5430 
5431 		m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP);
5432 		m_psh.dwFlags |= PSH_WIZARD97;
5433 
5434 		baseClass::SetHeader(headerBitmap.m_lpstr);
5435 		baseClass::SetWatermark(watermarkBitmap.m_lpstr);
5436 	}
5437 
5438 // Overrides from base class
OnSheetInitialized()5439 	void OnSheetInitialized()
5440 	{
5441 		T* pT = static_cast<T*>(this);
5442 		pT->_InitializeFonts();
5443 
5444 		// We'd like to center the wizard here, but its too early.
5445 		// Instead, we'll do CenterWindow upon our first WM_SIZE message
5446 	}
5447 
5448 // Initialization
_InitializeFonts()5449 	void _InitializeFonts()
5450 	{
5451 		// Setup the Title and Bullet Font
5452 		// (Property pages can send the "get external page title font" and "get bullet font" messages)
5453 		// The derived class needs to do the actual SetFont for the dialog items)
5454 
5455 		CFontHandle fontThisDialog = this->GetFont();
5456 		CClientDC dcScreen(NULL);
5457 
5458 		LOGFONT titleLogFont = {0};
5459 		LOGFONT bulletLogFont = {0};
5460 		fontThisDialog.GetLogFont(&titleLogFont);
5461 		fontThisDialog.GetLogFont(&bulletLogFont);
5462 
5463 		// The Wizard 97 Spec recommends to do the Title Font
5464 		// as Verdana Bold, 12pt.
5465 		titleLogFont.lfCharSet = DEFAULT_CHARSET;
5466 		titleLogFont.lfWeight = FW_BOLD;
5467 		SecureHelper::strcpy_x(titleLogFont.lfFaceName, _countof(titleLogFont.lfFaceName), _T("Verdana Bold"));
5468 		INT titleFontPointSize = 12;
5469 		titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
5470 		m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont);
5471 
5472 		// The Wizard 97 Spec recommends to do Bullets by having
5473 		// static text of "h" in the Marlett font.
5474 		bulletLogFont.lfCharSet = DEFAULT_CHARSET;
5475 		bulletLogFont.lfWeight = FW_NORMAL;
5476 		SecureHelper::strcpy_x(bulletLogFont.lfFaceName, _countof(bulletLogFont.lfFaceName), _T("Marlett"));
5477 		INT bulletFontSize = 8;
5478 		bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
5479 		m_fontBullet.CreateFontIndirect(&bulletLogFont);
5480 	}
5481 
5482 // Message Handling
5483 	BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont (),OnGetExteriorPageTitleFont)5484 		MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont)
5485 		MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont)
5486 		MESSAGE_HANDLER(WM_SIZE, OnSize)
5487 		CHAIN_MSG_MAP(baseClass)
5488 	END_MSG_MAP()
5489 
5490 	LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
5491 	{
5492 		return (LRESULT)(HFONT)m_fontExteriorPageTitle;
5493 	}
5494 
OnGetBulletFont(UINT,WPARAM,LPARAM,BOOL &)5495 	LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
5496 	{
5497 		return (LRESULT)(HFONT)m_fontBullet;
5498 	}
5499 
OnSize(UINT,WPARAM,LPARAM,BOOL & bHandled)5500 	LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
5501 	{
5502 		if(!m_bReceivedFirstSizeMessage)
5503 		{
5504 			m_bReceivedFirstSizeMessage = true;
5505 			this->CenterWindow();
5506 		}
5507 
5508 		bHandled = FALSE;
5509 		return 0;
5510 	}
5511 };
5512 
5513 // for non-customized sheets
5514 class CWizard97Sheet : public CWizard97SheetImpl<CWizard97Sheet>
5515 {
5516 protected:
5517 // Typedefs
5518 	typedef CWizard97Sheet thisClass;
5519 	typedef CWizard97SheetImpl<CWizard97Sheet> baseClass;
5520 
5521 public:
5522 	CWizard97Sheet(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
baseClass(title,headerBitmap,watermarkBitmap,uStartPage,hWndParent)5523 		baseClass(title, headerBitmap, watermarkBitmap, uStartPage, hWndParent)
5524 	{ }
5525 
5526 	BEGIN_MSG_MAP(thisClass)
5527 		CHAIN_MSG_MAP(baseClass)
5528 	END_MSG_MAP()
5529 };
5530 
5531 
5532 ///////////////////////////////////////////////////////////////////////////////
5533 // CWizard97PageWindow - client side for a Wizard 97 style wizard page
5534 
5535 #define WIZARD97_EXTERIOR_CXDLG 317
5536 #define WIZARD97_EXTERIOR_CYDLG 193
5537 
5538 #define WIZARD97_INTERIOR_CXDLG 317
5539 #define WIZARD97_INTERIOR_CYDLG 143
5540 
5541 class CWizard97PageWindow : public CPropertyPageWindow
5542 {
5543 public:
5544 // Constructors
CPropertyPageWindow(hWnd)5545 	CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
5546 	{ }
5547 
5548 	CWizard97PageWindow& operator =(HWND hWnd)
5549 	{
5550 		m_hWnd = hWnd;
5551 		return *this;
5552 	}
5553 
5554 // Attributes
GetPropertySheet()5555 	CWizard97SheetWindow GetPropertySheet() const
5556 	{
5557 		ATLASSERT(::IsWindow(m_hWnd));
5558 		return CWizard97SheetWindow(GetParent());
5559 	}
5560 
5561 // Operations
GetExteriorPageTitleFont(void)5562 	HFONT GetExteriorPageTitleFont(void)
5563 	{
5564 		ATLASSERT(::IsWindow(m_hWnd));
5565 		return GetPropertySheet().GetExteriorPageTitleFont();
5566 	}
5567 
GetBulletFont(void)5568 	HFONT GetBulletFont(void)
5569 	{
5570 		ATLASSERT(::IsWindow(m_hWnd));
5571 		return GetPropertySheet().GetBulletFont();
5572 	}
5573 
5574 // Implementation - overrides to prevent usage
5575 	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
5576 	{
5577 		ATLASSERT(FALSE);
5578 		return NULL;
5579 	}
5580 
5581 };
5582 
5583 
5584 ///////////////////////////////////////////////////////////////////////////////
5585 // CWizard97PageImpl - implements a Wizard 97 style wizard page
5586 
5587 template <class T, class TBase = CWizard97PageWindow>
5588 class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase >
5589 {
5590 protected:
5591 // Typedefs
5592 	typedef CWizard97PageImpl< T, TBase > thisClass;
5593 	typedef CPropertyPageImpl< T, TBase > baseClass;
5594 
5595 public:
baseClass(title)5596 	CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5597 	{ }
5598 
5599 // Message Handling
5600 	BEGIN_MSG_MAP(thisClass)
5601 		CHAIN_MSG_MAP(baseClass)
5602 	END_MSG_MAP()
5603 };
5604 
5605 
5606 ///////////////////////////////////////////////////////////////////////////////
5607 // CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page
5608 
5609 template <class T, class TBase = CWizard97PageWindow>
5610 class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase >
5611 {
5612 protected:
5613 // Typedefs
5614 	typedef CWizard97ExteriorPageImpl< T, TBase > thisClass;
5615 	typedef CPropertyPageImpl< T, TBase > baseClass;
5616 
5617 public:
5618 // Constructors
baseClass(title)5619 	CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5620 	{
5621 		m_psp.dwFlags |= PSP_HASHELP;
5622 		m_psp.dwFlags |= PSP_HIDEHEADER;
5623 	}
5624 
5625 // Message Handling
5626 	BEGIN_MSG_MAP(thisClass)
5627 		CHAIN_MSG_MAP(baseClass)
5628 	END_MSG_MAP()
5629 };
5630 
5631 
5632 ///////////////////////////////////////////////////////////////////////////////
5633 // CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page
5634 
5635 template <class T, class TBase = CWizard97PageWindow>
5636 class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase >
5637 {
5638 protected:
5639 // Typedefs
5640 	typedef CWizard97InteriorPageImpl< T, TBase > thisClass;
5641 	typedef CPropertyPageImpl< T, TBase > baseClass;
5642 
5643 public:
5644 // Constructors
baseClass(title)5645 	CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
5646 	{
5647 		m_psp.dwFlags |= PSP_HASHELP;
5648 		m_psp.dwFlags &= ~PSP_HIDEHEADER;
5649 		m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
5650 
5651 		// Be sure to have the derived class define this in the constructor.
5652 		// We'll default it to something obvious in case its forgotten.
5653 		baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class"));
5654 		baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class."));
5655 	}
5656 
5657 // Message Handling
5658 	BEGIN_MSG_MAP(thisClass)
5659 		CHAIN_MSG_MAP(baseClass)
5660 	END_MSG_MAP()
5661 };
5662 
5663 #endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
5664 
5665 
5666 ///////////////////////////////////////////////////////////////////////////////
5667 // Aero Wizard support
5668 
5669 #if (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
5670 
5671 ///////////////////////////////////////////////////////////////////////////////
5672 // CAeroWizardFrameWindow - client side for an Aero Wizard frame window
5673 
5674 class CAeroWizardFrameWindow : public CPropertySheetWindow
5675 {
5676 public:
5677 // Constructors
CPropertySheetWindow(hWnd)5678 	CAeroWizardFrameWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
5679 	{ }
5680 
5681 	CAeroWizardFrameWindow& operator =(HWND hWnd)
5682 	{
5683 		m_hWnd = hWnd;
5684 		return *this;
5685 	}
5686 
5687 // Operations - new, Aero Wizard only
SetNextText(LPCWSTR lpszText)5688 	void SetNextText(LPCWSTR lpszText)
5689 	{
5690 		ATLASSERT(::IsWindow(m_hWnd));
5691 		::SendMessage(m_hWnd, PSM_SETNEXTTEXT, 0, (LPARAM)lpszText);
5692 	}
5693 
ShowWizardButtons(DWORD dwButtons,DWORD dwStates)5694 	void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
5695 	{
5696 		ATLASSERT(::IsWindow(m_hWnd));
5697 		::PostMessage(m_hWnd, PSM_SHOWWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
5698 	}
5699 
EnableWizardButtons(DWORD dwButtons,DWORD dwStates)5700 	void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
5701 	{
5702 		ATLASSERT(::IsWindow(m_hWnd));
5703 		::PostMessage(m_hWnd, PSM_ENABLEWIZBUTTONS, (WPARAM)dwStates, (LPARAM)dwButtons);
5704 	}
5705 
SetButtonText(DWORD dwButton,LPCWSTR lpszText)5706 	void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
5707 	{
5708 		ATLASSERT(::IsWindow(m_hWnd));
5709 		::SendMessage(m_hWnd, PSM_SETBUTTONTEXT, (WPARAM)dwButton, (LPARAM)lpszText);
5710 	}
5711 };
5712 
5713 
5714 ///////////////////////////////////////////////////////////////////////////////
5715 // CAeroWizardFrameImpl - implements an Aero Wizard frame
5716 
5717 template <class T, class TBase = CAeroWizardFrameWindow>
5718 class ATL_NO_VTABLE CAeroWizardFrameImpl : public CPropertySheetImpl<T, TBase >
5719 {
5720 public:
5721 // Constructor
5722 	CAeroWizardFrameImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL) :
5723 		CPropertySheetImpl<T, TBase >(title, uStartPage, hWndParent)
5724 	{
5725 		m_psh.dwFlags |= PSH_WIZARD | PSH_AEROWIZARD;
5726 	}
5727 
5728 // Operations
EnableResizing()5729 	void EnableResizing()
5730 	{
5731 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5732 		m_psh.dwFlags |= PSH_RESIZABLE;
5733 	}
5734 
UseHeaderBitmap()5735 	void UseHeaderBitmap()
5736 	{
5737 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5738 		m_psh.dwFlags |= PSH_HEADERBITMAP;
5739 	}
5740 
SetNoMargin()5741 	void SetNoMargin()
5742 	{
5743 		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
5744 		m_psh.dwFlags |= PSH_NOMARGIN;
5745 	}
5746 
5747 // Override to prevent use
5748 	HWND Create(HWND /*hWndParent*/ = NULL)
5749 	{
5750 		ATLASSERT(FALSE);   // not supported for Aero Wizard
5751 		return NULL;
5752 	}
5753 };
5754 
5755 
5756 ///////////////////////////////////////////////////////////////////////////////
5757 // CAeroWizardFrame - for non-customized frames
5758 
5759 class CAeroWizardFrame : public CAeroWizardFrameImpl<CAeroWizardFrame>
5760 {
5761 public:
5762 	CAeroWizardFrame(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
5763 		: CAeroWizardFrameImpl<CAeroWizardFrame>(title, uStartPage, hWndParent)
5764 	{ }
5765 
5766 	BEGIN_MSG_MAP(CAeroWizardFrame)
5767 		MESSAGE_HANDLER(WM_COMMAND, CAeroWizardFrameImpl<CAeroWizardFrame>::OnCommand)
5768 	END_MSG_MAP()
5769 };
5770 
5771 
5772 ///////////////////////////////////////////////////////////////////////////////
5773 // CAeroWizardPageWindow - client side for an Aero Wizard page
5774 
5775 class CAeroWizardPageWindow : public CPropertyPageWindow
5776 {
5777 public:
5778 // Constructors
CPropertyPageWindow(hWnd)5779 	CAeroWizardPageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
5780 	{ }
5781 
5782 	CAeroWizardPageWindow& operator =(HWND hWnd)
5783 	{
5784 		m_hWnd = hWnd;
5785 		return *this;
5786 	}
5787 
5788 // Attributes
GetAeroWizardFrame()5789 	CAeroWizardFrameWindow GetAeroWizardFrame() const
5790 	{
5791 		ATLASSERT(::IsWindow(m_hWnd));
5792 		// This is not really top-level frame window, but it processes all frame messages
5793 		return CAeroWizardFrameWindow(GetParent());
5794 	}
5795 
5796 // Operations - new, Aero Wizard only
SetNextText(LPCWSTR lpszText)5797 	void SetNextText(LPCWSTR lpszText)
5798 	{
5799 		ATLASSERT(::IsWindow(m_hWnd));
5800 		ATLASSERT(GetParent() != NULL);
5801 		GetAeroWizardFrame().SetNextText(lpszText);
5802 	}
5803 
ShowWizardButtons(DWORD dwButtons,DWORD dwStates)5804 	void ShowWizardButtons(DWORD dwButtons, DWORD dwStates)
5805 	{
5806 		ATLASSERT(::IsWindow(m_hWnd));
5807 		ATLASSERT(GetParent() != NULL);
5808 		GetAeroWizardFrame().ShowWizardButtons(dwButtons, dwStates);
5809 	}
5810 
EnableWizardButtons(DWORD dwButtons,DWORD dwStates)5811 	void EnableWizardButtons(DWORD dwButtons, DWORD dwStates)
5812 	{
5813 		ATLASSERT(::IsWindow(m_hWnd));
5814 		ATLASSERT(GetParent() != NULL);
5815 		GetAeroWizardFrame().EnableWizardButtons(dwButtons, dwStates);
5816 	}
5817 
SetButtonText(DWORD dwButton,LPCWSTR lpszText)5818 	void SetButtonText(DWORD dwButton, LPCWSTR lpszText)
5819 	{
5820 		ATLASSERT(::IsWindow(m_hWnd));
5821 		ATLASSERT(GetParent() != NULL);
5822 		GetAeroWizardFrame().SetButtonText(dwButton, lpszText);
5823 	}
5824 };
5825 
5826 
5827 ///////////////////////////////////////////////////////////////////////////////
5828 // CAeroWizardPageImpl - implements an Aero Wizard page
5829 
5830 template <class T, class TBase = CAeroWizardPageWindow>
5831 class ATL_NO_VTABLE CAeroWizardPageImpl : public CPropertyPageImpl<T, TBase >
5832 {
5833 public:
5834 	CAeroWizardPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<T, TBase >(title)
5835 	{ }
5836 };
5837 
5838 
5839 ///////////////////////////////////////////////////////////////////////////////
5840 // CAeroWizardPage - for non-customized pages
5841 
5842 template <WORD t_wDlgTemplateID>
5843 class CAeroWizardPage : public CAeroWizardPageImpl<CAeroWizardPage<t_wDlgTemplateID> >
5844 {
5845 public:
5846 	enum { IDD = t_wDlgTemplateID };
5847 
5848 	CAeroWizardPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardPageImpl<CAeroWizardPage>(title)
5849 	{ }
5850 
5851 	DECLARE_EMPTY_MSG_MAP()
5852 };
5853 
5854 
5855 #ifndef _ATL_NO_HOSTING
5856 
5857 // Note: You must #include <atlhost.h> to use these classes
5858 
5859 ///////////////////////////////////////////////////////////////////////////////
5860 // CAeroWizardAxPageImpl - Aero Wizard page that hosts ActiveX controls
5861 
5862 template <class T, class TBase = CAeroWizardPageWindow>
5863 class ATL_NO_VTABLE CAeroWizardAxPageImpl : public CAxPropertyPageImpl< T, TBase >
5864 {
5865 public:
5866 	CAeroWizardAxPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl< T, TBase >(title)
5867 	{ }
5868 };
5869 
5870 
5871 ///////////////////////////////////////////////////////////////////////////////
5872 // CAeroWizardAxPage - for non-customized pages
5873 
5874 template <WORD t_wDlgTemplateID>
5875 class CAeroWizardAxPage : public CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >
5876 {
5877 public:
5878 	enum { IDD = t_wDlgTemplateID };
5879 
5880 	CAeroWizardAxPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAeroWizardAxPageImpl<CAeroWizardAxPage>(title)
5881 	{ }
5882 
5883 #if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
5884 	// not empty so we handle accelerators/create controls
5885 	BEGIN_MSG_MAP(CAeroWizardAxPage)
5886 		CHAIN_MSG_MAP(CAeroWizardAxPageImpl<CAeroWizardAxPage<t_wDlgTemplateID> >)
5887 	END_MSG_MAP()
5888 #else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5889 	DECLARE_EMPTY_MSG_MAP()
5890 #endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
5891 };
5892 
5893 #endif // _ATL_NO_HOSTING
5894 
5895 #endif // (_WIN32_WINNT >= 0x0600) && !defined(_WIN32_WCE)
5896 
5897 
5898 ///////////////////////////////////////////////////////////////////////////////
5899 // TaskDialog support
5900 
5901 #if ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
5902 
5903 ///////////////////////////////////////////////////////////////////////////////
5904 // AtlTaskDialog - support for TaskDialog() function
5905 
5906 inline int AtlTaskDialog(HWND hWndParent,
5907                          ATL::_U_STRINGorID WindowTitle, ATL::_U_STRINGorID MainInstructionText, ATL::_U_STRINGorID ContentText,
5908                          TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons = 0U, ATL::_U_STRINGorID Icon = (LPCTSTR)NULL)
5909 {
5910 	int nRet = -1;
5911 
5912 #ifdef _WTL_TASKDIALOG_DIRECT
5913 	USES_CONVERSION;
5914 	HRESULT hRet = ::TaskDialog(hWndParent, ModuleHelper::GetResourceInstance(),
5915 		IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr),
5916 		IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr),
5917 		IS_INTRESOURCE(ContentText.m_lpstr) ?  (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr),
5918 		dwCommonButtons,
5919 		IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),
5920 		&nRet);
5921 	ATLVERIFY(SUCCEEDED(hRet));
5922 #else
5923 	// This allows apps to run on older versions of Windows
5924 	typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialog)(HWND hwndParent, HINSTANCE hInstance, PCWSTR pszWindowTitle, PCWSTR pszMainInstruction, PCWSTR pszContent, TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons, PCWSTR pszIcon, int* pnButton);
5925 
5926 	HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
5927 	if(m_hCommCtrlDLL != NULL)
5928 	{
5929 		PFN_TaskDialog pfnTaskDialog = (PFN_TaskDialog)::GetProcAddress(m_hCommCtrlDLL, "TaskDialog");
5930 		if(pfnTaskDialog != NULL)
5931 		{
5932 			USES_CONVERSION;
5933 			HRESULT hRet = pfnTaskDialog(hWndParent, ModuleHelper::GetResourceInstance(),
5934 				IS_INTRESOURCE(WindowTitle.m_lpstr) ? (LPCWSTR) WindowTitle.m_lpstr : T2CW(WindowTitle.m_lpstr),
5935 				IS_INTRESOURCE(MainInstructionText.m_lpstr) ? (LPCWSTR) MainInstructionText.m_lpstr : T2CW(MainInstructionText.m_lpstr),
5936 				IS_INTRESOURCE(ContentText.m_lpstr) ?  (LPCWSTR) ContentText.m_lpstr : T2CW(ContentText.m_lpstr),
5937 				dwCommonButtons,
5938 				IS_INTRESOURCE(Icon.m_lpstr) ? (LPCWSTR) Icon.m_lpstr : T2CW(Icon.m_lpstr),
5939 				&nRet);
5940 			ATLVERIFY(SUCCEEDED(hRet));
5941 		}
5942 
5943 		::FreeLibrary(m_hCommCtrlDLL);
5944 	}
5945 #endif
5946 
5947 	return nRet;
5948 }
5949 
5950 
5951 ///////////////////////////////////////////////////////////////////////////////
5952 // CTaskDialogConfig - TASKDIALOGCONFIG wrapper
5953 
5954 class CTaskDialogConfig : public TASKDIALOGCONFIG
5955 {
5956 public:
5957 // Constructor
CTaskDialogConfig()5958 	CTaskDialogConfig()
5959 	{
5960 		Init();
5961 	}
5962 
Init()5963 	void Init()
5964 	{
5965 		memset(this, 0, sizeof(TASKDIALOGCONFIG));   // initialize structure to 0/NULL
5966 		this->cbSize = sizeof(TASKDIALOGCONFIG);
5967 		this->hInstance = ModuleHelper::GetResourceInstance();
5968 	}
5969 
5970 // Operations - setting values
5971 	// common buttons
SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtonsArg)5972 	void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtonsArg)
5973 	{
5974 		this->dwCommonButtons = dwCommonButtonsArg;
5975 	}
5976 
5977 	// window title text
SetWindowTitle(UINT nID)5978 	void SetWindowTitle(UINT nID)
5979 	{
5980 		this->pszWindowTitle = MAKEINTRESOURCEW(nID);
5981 	}
5982 
SetWindowTitle(LPCWSTR lpstrWindowTitle)5983 	void SetWindowTitle(LPCWSTR lpstrWindowTitle)
5984 	{
5985 		this->pszWindowTitle = lpstrWindowTitle;
5986 	}
5987 
5988 	// main icon
SetMainIcon(HICON hIcon)5989 	void SetMainIcon(HICON hIcon)
5990 	{
5991 		this->dwFlags |= TDF_USE_HICON_MAIN;
5992 		this->hMainIcon = hIcon;
5993 	}
5994 
SetMainIcon(UINT nID)5995 	void SetMainIcon(UINT nID)
5996 	{
5997 		this->dwFlags &= ~TDF_USE_HICON_MAIN;
5998 		this->pszMainIcon = MAKEINTRESOURCEW(nID);
5999 	}
6000 
SetMainIcon(LPCWSTR lpstrMainIcon)6001 	void SetMainIcon(LPCWSTR lpstrMainIcon)
6002 	{
6003 		this->dwFlags &= ~TDF_USE_HICON_MAIN;
6004 		this->pszMainIcon = lpstrMainIcon;
6005 	}
6006 
6007 	// main instruction text
SetMainInstructionText(UINT nID)6008 	void SetMainInstructionText(UINT nID)
6009 	{
6010 		this->pszMainInstruction = MAKEINTRESOURCEW(nID);
6011 	}
6012 
SetMainInstructionText(LPCWSTR lpstrMainInstruction)6013 	void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
6014 	{
6015 		this->pszMainInstruction = lpstrMainInstruction;
6016 	}
6017 
6018 	// content text
SetContentText(UINT nID)6019 	void SetContentText(UINT nID)
6020 	{
6021 		this->pszContent = MAKEINTRESOURCEW(nID);
6022 	}
6023 
SetContentText(LPCWSTR lpstrContent)6024 	void SetContentText(LPCWSTR lpstrContent)
6025 	{
6026 		this->pszContent = lpstrContent;
6027 	}
6028 
6029 	// buttons
6030 	void SetButtons(const TASKDIALOG_BUTTON* pButtonsArg, UINT cButtonsArg, int nDefaultButtonArg = 0)
6031 	{
6032 		this->pButtons = pButtonsArg;
6033 		this->cButtons = cButtonsArg;
6034 		if(nDefaultButtonArg != 0)
6035 			this->nDefaultButton = nDefaultButtonArg;
6036 	}
6037 
SetDefaultButton(int nDefaultButtonArg)6038 	void SetDefaultButton(int nDefaultButtonArg)
6039 	{
6040 		this->nDefaultButton = nDefaultButtonArg;
6041 	}
6042 
6043 	// radio buttons
6044 	void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtonsArg, UINT cRadioButtonsArg, int nDefaultRadioButtonArg = 0)
6045 	{
6046 		this->pRadioButtons = pRadioButtonsArg;
6047 		this->cRadioButtons = cRadioButtonsArg;
6048 		if(nDefaultRadioButtonArg != 0)
6049 			this->nDefaultRadioButton = nDefaultRadioButtonArg;
6050 	}
6051 
SetDefaultRadioButton(int nDefaultRadioButtonArg)6052 	void SetDefaultRadioButton(int nDefaultRadioButtonArg)
6053 	{
6054 		this->nDefaultRadioButton = nDefaultRadioButtonArg;
6055 	}
6056 
6057 	// verification text
SetVerificationText(UINT nID)6058 	void SetVerificationText(UINT nID)
6059 	{
6060 		this->pszVerificationText = MAKEINTRESOURCEW(nID);
6061 	}
6062 
SetVerificationText(LPCWSTR lpstrVerificationText)6063 	void SetVerificationText(LPCWSTR lpstrVerificationText)
6064 	{
6065 		this->pszVerificationText = lpstrVerificationText;
6066 	}
6067 
6068 	// expanded information text
SetExpandedInformationText(UINT nID)6069 	void SetExpandedInformationText(UINT nID)
6070 	{
6071 		this->pszExpandedInformation = MAKEINTRESOURCEW(nID);
6072 	}
6073 
SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)6074 	void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
6075 	{
6076 		this->pszExpandedInformation = lpstrExpandedInformation;
6077 	}
6078 
6079 	// expanded control text
SetExpandedControlText(UINT nID)6080 	void SetExpandedControlText(UINT nID)
6081 	{
6082 		this->pszExpandedControlText = MAKEINTRESOURCEW(nID);
6083 	}
6084 
SetExpandedControlText(LPCWSTR lpstrExpandedControlText)6085 	void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
6086 	{
6087 		this->pszExpandedControlText = lpstrExpandedControlText;
6088 	}
6089 
6090 	// collapsed control text
SetCollapsedControlText(UINT nID)6091 	void SetCollapsedControlText(UINT nID)
6092 	{
6093 		this->pszCollapsedControlText = MAKEINTRESOURCEW(nID);
6094 	}
6095 
SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)6096 	void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
6097 	{
6098 		this->pszCollapsedControlText = lpstrCollapsedControlText;
6099 	}
6100 
6101 	// footer icon
SetFooterIcon(HICON hIcon)6102 	void SetFooterIcon(HICON hIcon)
6103 	{
6104 		this->dwFlags |= TDF_USE_HICON_FOOTER;
6105 		this->hFooterIcon = hIcon;
6106 	}
6107 
SetFooterIcon(UINT nID)6108 	void SetFooterIcon(UINT nID)
6109 	{
6110 		this->dwFlags &= ~TDF_USE_HICON_FOOTER;
6111 		this->pszFooterIcon = MAKEINTRESOURCEW(nID);
6112 	}
6113 
SetFooterIcon(LPCWSTR lpstrFooterIcon)6114 	void SetFooterIcon(LPCWSTR lpstrFooterIcon)
6115 	{
6116 		this->dwFlags &= ~TDF_USE_HICON_FOOTER;
6117 		this->pszFooterIcon = lpstrFooterIcon;
6118 	}
6119 
6120 	// footer text
SetFooterText(UINT nID)6121 	void SetFooterText(UINT nID)
6122 	{
6123 		this->pszFooter = MAKEINTRESOURCEW(nID);
6124 	}
6125 
SetFooterText(LPCWSTR lpstrFooterText)6126 	void SetFooterText(LPCWSTR lpstrFooterText)
6127 	{
6128 		this->pszFooter = lpstrFooterText;
6129 	}
6130 
6131 	// width (in DLUs)
SetWidth(UINT cxWidthArg)6132 	void SetWidth(UINT cxWidthArg)
6133 	{
6134 		this->cxWidth = cxWidthArg;
6135 	}
6136 
6137 	// modify flags
ModifyFlags(DWORD dwRemove,DWORD dwAdd)6138 	void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
6139 	{
6140 		this->dwFlags = (this->dwFlags & ~dwRemove) | dwAdd;
6141 	}
6142 };
6143 
6144 
6145 ///////////////////////////////////////////////////////////////////////////////
6146 // CTaskDialogImpl - implements a Task Dialog
6147 
6148 template <class T>
6149 class ATL_NO_VTABLE CTaskDialogImpl
6150 {
6151 public:
6152 	CTaskDialogConfig m_tdc;
6153 	HWND m_hWnd;   // used only in callback functions
6154 
6155 // Constructor
m_hWnd(NULL)6156 	CTaskDialogImpl(HWND hWndParent = NULL) : m_hWnd(NULL)
6157 	{
6158 		m_tdc.hwndParent = hWndParent;
6159 		m_tdc.pfCallback = T::TaskDialogCallback;
6160 		m_tdc.lpCallbackData = (LONG_PTR)static_cast<T*>(this);
6161 	}
6162 
6163 // Operations
6164 	HRESULT DoModal(HWND hWndParent = ::GetActiveWindow(), int* pnButton = NULL, int* pnRadioButton = NULL, BOOL* pfVerificationFlagChecked = NULL)
6165 	{
6166 		if(m_tdc.hwndParent == NULL)
6167 			m_tdc.hwndParent = hWndParent;
6168 
6169 #ifdef _WTL_TASKDIALOG_DIRECT
6170 		return ::TaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
6171 #else
6172 
6173 		// This allows apps to run on older versions of Windows
6174 		typedef HRESULT (STDAPICALLTYPE *PFN_TaskDialogIndirect)(const TASKDIALOGCONFIG* pTaskConfig, int* pnButton, int* pnRadioButton, BOOL* pfVerificationFlagChecked);
6175 
6176 		HRESULT hRet = E_UNEXPECTED;
6177 		HMODULE m_hCommCtrlDLL = ::LoadLibrary(_T("comctl32.dll"));
6178 		if(m_hCommCtrlDLL != NULL)
6179 		{
6180 			PFN_TaskDialogIndirect pfnTaskDialogIndirect = (PFN_TaskDialogIndirect)::GetProcAddress(m_hCommCtrlDLL, "TaskDialogIndirect");
6181 			if(pfnTaskDialogIndirect != NULL)
6182 				hRet = pfnTaskDialogIndirect(&m_tdc, pnButton, pnRadioButton, pfVerificationFlagChecked);
6183 
6184 			::FreeLibrary(m_hCommCtrlDLL);
6185 		}
6186 
6187 		return hRet;
6188 #endif
6189 	}
6190 
6191 // Operations - setting values of TASKDIALOGCONFIG
6192 	// common buttons
SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)6193 	void SetCommonButtons(TASKDIALOG_COMMON_BUTTON_FLAGS dwCommonButtons)
6194 	{	m_tdc.SetCommonButtons(dwCommonButtons); }
6195 	// window title text
SetWindowTitle(UINT nID)6196 	void SetWindowTitle(UINT nID)
6197 	{	m_tdc.SetWindowTitle(nID); }
SetWindowTitle(LPCWSTR lpstrWindowTitle)6198 	void SetWindowTitle(LPCWSTR lpstrWindowTitle)
6199 	{	m_tdc.SetWindowTitle(lpstrWindowTitle); }
6200 	// main icon
SetMainIcon(HICON hIcon)6201 	void SetMainIcon(HICON hIcon)
6202 	{	m_tdc.SetMainIcon(hIcon); }
SetMainIcon(UINT nID)6203 	void SetMainIcon(UINT nID)
6204 	{	m_tdc.SetMainIcon(nID); }
SetMainIcon(LPCWSTR lpstrMainIcon)6205 	void SetMainIcon(LPCWSTR lpstrMainIcon)
6206 	{	m_tdc.SetMainIcon(lpstrMainIcon); }
6207 	// main instruction text
SetMainInstructionText(UINT nID)6208 	void SetMainInstructionText(UINT nID)
6209 	{	m_tdc.SetMainInstructionText(nID); }
SetMainInstructionText(LPCWSTR lpstrMainInstruction)6210 	void SetMainInstructionText(LPCWSTR lpstrMainInstruction)
6211 	{	m_tdc.SetMainInstructionText(lpstrMainInstruction); }
6212 	// content text
SetContentText(UINT nID)6213 	void SetContentText(UINT nID)
6214 	{	m_tdc.SetContentText(nID); }
SetContentText(LPCWSTR lpstrContent)6215 	void SetContentText(LPCWSTR lpstrContent)
6216 	{	m_tdc.SetContentText(lpstrContent); }
6217 	// buttons
6218 	void SetButtons(const TASKDIALOG_BUTTON* pButtons, UINT cButtons, int nDefaultButton = 0)
6219 	{	m_tdc.SetButtons(pButtons, cButtons, nDefaultButton); }
SetDefaultButton(int nDefaultButton)6220 	void SetDefaultButton(int nDefaultButton)
6221 	{	m_tdc.SetDefaultButton(nDefaultButton); }
6222 	// radio buttons
6223 	void SetRadioButtons(const TASKDIALOG_BUTTON* pRadioButtons, UINT cRadioButtons, int nDefaultRadioButton = 0)
6224 	{	m_tdc.SetRadioButtons(pRadioButtons, cRadioButtons, nDefaultRadioButton); }
SetDefaultRadioButton(int nDefaultRadioButton)6225 	void SetDefaultRadioButton(int nDefaultRadioButton)
6226 	{	m_tdc.SetDefaultRadioButton(nDefaultRadioButton); }
6227 	// verification text
SetVerificationText(UINT nID)6228 	void SetVerificationText(UINT nID)
6229 	{	m_tdc.SetVerificationText(nID); }
SetVerificationText(LPCWSTR lpstrVerificationText)6230 	void SetVerificationText(LPCWSTR lpstrVerificationText)
6231 	{	m_tdc.SetVerificationText(lpstrVerificationText); }
6232 	// expanded information text
SetExpandedInformationText(UINT nID)6233 	void SetExpandedInformationText(UINT nID)
6234 	{	m_tdc.SetExpandedInformationText(nID); }
SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)6235 	void SetExpandedInformationText(LPCWSTR lpstrExpandedInformation)
6236 	{	m_tdc.SetExpandedInformationText(lpstrExpandedInformation); }
6237 	// expanded control text
SetExpandedControlText(UINT nID)6238 	void SetExpandedControlText(UINT nID)
6239 	{	m_tdc.SetExpandedControlText(nID); }
SetExpandedControlText(LPCWSTR lpstrExpandedControlText)6240 	void SetExpandedControlText(LPCWSTR lpstrExpandedControlText)
6241 	{	m_tdc.SetExpandedControlText(lpstrExpandedControlText); }
6242 	// collapsed control text
SetCollapsedControlText(UINT nID)6243 	void SetCollapsedControlText(UINT nID)
6244 	{	m_tdc.SetCollapsedControlText(nID); }
SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)6245 	void SetCollapsedControlText(LPCWSTR lpstrCollapsedControlText)
6246 	{	m_tdc.SetCollapsedControlText(lpstrCollapsedControlText); }
6247 	// footer icon
SetFooterIcon(HICON hIcon)6248 	void SetFooterIcon(HICON hIcon)
6249 	{	m_tdc.SetFooterIcon(hIcon); }
SetFooterIcon(UINT nID)6250 	void SetFooterIcon(UINT nID)
6251 	{	m_tdc.SetFooterIcon(nID); }
SetFooterIcon(LPCWSTR lpstrFooterIcon)6252 	void SetFooterIcon(LPCWSTR lpstrFooterIcon)
6253 	{	m_tdc.SetFooterIcon(lpstrFooterIcon); }
6254 	// footer text
SetFooterText(UINT nID)6255 	void SetFooterText(UINT nID)
6256 	{	m_tdc.SetFooterText(nID); }
SetFooterText(LPCWSTR lpstrFooterText)6257 	void SetFooterText(LPCWSTR lpstrFooterText)
6258 	{	m_tdc.SetFooterText(lpstrFooterText); }
6259 	// width (in DLUs)
SetWidth(UINT cxWidth)6260 	void SetWidth(UINT cxWidth)
6261 	{	m_tdc.SetWidth(cxWidth); }
6262 	// modify flags
ModifyFlags(DWORD dwRemove,DWORD dwAdd)6263 	void ModifyFlags(DWORD dwRemove, DWORD dwAdd)
6264 	{	m_tdc.ModifyFlags(dwRemove, dwAdd); }
6265 
6266 // Implementation
TaskDialogCallback(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam,LONG_PTR lpRefData)6267 	static HRESULT CALLBACK TaskDialogCallback(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData)
6268 	{
6269 		T* pT = (T*)lpRefData;
6270 		ATLASSERT(pT->m_hWnd == NULL || pT->m_hWnd == hWnd);
6271 
6272 		BOOL bRet = FALSE;
6273 		switch(uMsg)
6274 		{
6275 		case TDN_DIALOG_CONSTRUCTED:
6276 			pT->m_hWnd = hWnd;
6277 			pT->OnDialogConstructed();
6278 			break;
6279 		case TDN_CREATED:
6280 			pT->OnCreated();
6281 			break;
6282 		case TDN_BUTTON_CLICKED:
6283 			bRet = pT->OnButtonClicked((int)wParam);
6284 			break;
6285 		case TDN_RADIO_BUTTON_CLICKED:
6286 			pT->OnRadioButtonClicked((int)wParam);
6287 			break;
6288 		case TDN_HYPERLINK_CLICKED:
6289 			pT->OnHyperlinkClicked((LPCWSTR)lParam);
6290 			break;
6291 		case TDN_EXPANDO_BUTTON_CLICKED:
6292 			pT->OnExpandoButtonClicked((wParam != 0));
6293 			break;
6294 		case TDN_VERIFICATION_CLICKED:
6295 			pT->OnVerificationClicked((wParam != 0));
6296 			break;
6297 		case TDN_HELP:
6298 			pT->OnHelp();
6299 			break;
6300 		case TDN_TIMER:
6301 			bRet = pT->OnTimer((DWORD)wParam);
6302 			break;
6303 		case TDN_NAVIGATED:
6304 			pT->OnNavigated();
6305 			break;
6306 		case TDN_DESTROYED:
6307 			pT->OnDestroyed();
6308 			pT->m_hWnd = NULL;
6309 			break;
6310 		default:
6311 			ATLTRACE2(atlTraceUI, 0, _T("Unknown notification received in CTaskDialogImpl::TaskDialogCallback\n"));
6312 			break;
6313 		}
6314 
6315 		return (bRet != FALSE) ? S_OK : S_FALSE;
6316 	}
6317 
6318 // Overrideables - notification handlers
OnDialogConstructed()6319 	void OnDialogConstructed()
6320 	{
6321 	}
6322 
OnCreated()6323 	void OnCreated()
6324 	{
6325 	}
6326 
OnButtonClicked(int)6327 	BOOL OnButtonClicked(int /*nButton*/)
6328 	{
6329 		return FALSE;   // don't prevent dialog to close
6330 	}
6331 
OnRadioButtonClicked(int)6332 	void OnRadioButtonClicked(int /*nRadioButton*/)
6333 	{
6334 	}
6335 
OnHyperlinkClicked(LPCWSTR)6336 	void OnHyperlinkClicked(LPCWSTR /*pszHREF*/)
6337 	{
6338 	}
6339 
OnExpandoButtonClicked(bool)6340 	void OnExpandoButtonClicked(bool /*bExpanded*/)
6341 	{
6342 	}
6343 
OnVerificationClicked(bool)6344 	void OnVerificationClicked(bool /*bChecked*/)
6345 	{
6346 	}
6347 
OnHelp()6348 	void OnHelp()
6349 	{
6350 	}
6351 
OnTimer(DWORD)6352 	BOOL OnTimer(DWORD /*dwTickCount*/)
6353 	{
6354 		return FALSE;   // don't reset counter
6355 	}
6356 
OnNavigated()6357 	void OnNavigated()
6358 	{
6359 	}
6360 
OnDestroyed()6361 	void OnDestroyed()
6362 	{
6363 	}
6364 
6365 // Commands - valid to call only from handlers
NavigatePage(TASKDIALOGCONFIG & tdc)6366 	void NavigatePage(TASKDIALOGCONFIG& tdc)
6367 	{
6368 		ATLASSERT(m_hWnd != NULL);
6369 
6370 		tdc.cbSize = sizeof(TASKDIALOGCONFIG);
6371 		if(tdc.hwndParent == NULL)
6372 			tdc.hwndParent = m_tdc.hwndParent;
6373 		tdc.pfCallback = m_tdc.pfCallback;
6374 		tdc.lpCallbackData = m_tdc.lpCallbackData;
6375 		(TASKDIALOGCONFIG)m_tdc = tdc;
6376 
6377 		::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&tdc);
6378 	}
6379 
6380 	// modify TASKDIALOGCONFIG values, then call this to update task dialog
NavigatePage()6381 	void NavigatePage()
6382 	{
6383 		ATLASSERT(m_hWnd != NULL);
6384 		::SendMessage(m_hWnd, TDM_NAVIGATE_PAGE, 0, (LPARAM)&m_tdc);
6385 	}
6386 
ClickButton(int nButton)6387 	void ClickButton(int nButton)
6388 	{
6389 		ATLASSERT(m_hWnd != NULL);
6390 		::SendMessage(m_hWnd, TDM_CLICK_BUTTON, nButton, 0L);
6391 	}
6392 
SetMarqueeProgressBar(BOOL bMarquee)6393 	void SetMarqueeProgressBar(BOOL bMarquee)
6394 	{
6395 		ATLASSERT(m_hWnd != NULL);
6396 		::SendMessage(m_hWnd, TDM_SET_MARQUEE_PROGRESS_BAR, bMarquee, 0L);
6397 	}
6398 
SetProgressBarState(int nNewState)6399 	BOOL SetProgressBarState(int nNewState)
6400 	{
6401 		ATLASSERT(m_hWnd != NULL);
6402 		return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_STATE, nNewState, 0L);
6403 	}
6404 
SetProgressBarRange(int nMinRange,int nMaxRange)6405 	DWORD SetProgressBarRange(int nMinRange, int nMaxRange)
6406 	{
6407 		ATLASSERT(m_hWnd != NULL);
6408 		return (DWORD)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(nMinRange, nMaxRange));
6409 	}
6410 
SetProgressBarPos(int nNewPos)6411 	int SetProgressBarPos(int nNewPos)
6412 	{
6413 		ATLASSERT(m_hWnd != NULL);
6414 		return (int)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_POS, nNewPos, 0L);
6415 	}
6416 
SetProgressBarMarquee(BOOL bMarquee,UINT uSpeed)6417 	BOOL SetProgressBarMarquee(BOOL bMarquee, UINT uSpeed)
6418 	{
6419 		ATLASSERT(m_hWnd != NULL);
6420 		return (BOOL)::SendMessage(m_hWnd, TDM_SET_PROGRESS_BAR_MARQUEE, bMarquee, uSpeed);
6421 	}
6422 
SetElementText(TASKDIALOG_ELEMENTS element,LPCWSTR lpstrText)6423 	void SetElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
6424 	{
6425 		ATLASSERT(m_hWnd != NULL);
6426 		::SendMessage(m_hWnd, TDM_SET_ELEMENT_TEXT, element, (LPARAM)lpstrText);
6427 	}
6428 
ClickRadioButton(int nRadioButton)6429 	void ClickRadioButton(int nRadioButton)
6430 	{
6431 		ATLASSERT(m_hWnd != NULL);
6432 		::SendMessage(m_hWnd, TDM_CLICK_RADIO_BUTTON, nRadioButton, 0L);
6433 	}
6434 
EnableButton(int nButton,BOOL bEnable)6435 	void EnableButton(int nButton, BOOL bEnable)
6436 	{
6437 		ATLASSERT(m_hWnd != NULL);
6438 		::SendMessage(m_hWnd, TDM_ENABLE_BUTTON, nButton, bEnable);
6439 	}
6440 
EnableRadioButton(int nButton,BOOL bEnable)6441 	void EnableRadioButton(int nButton, BOOL bEnable)
6442 	{
6443 		ATLASSERT(m_hWnd != NULL);
6444 		::SendMessage(m_hWnd, TDM_ENABLE_RADIO_BUTTON, nButton, bEnable);
6445 	}
6446 
ClickVerification(BOOL bCheck,BOOL bFocus)6447 	void ClickVerification(BOOL bCheck, BOOL bFocus)
6448 	{
6449 		ATLASSERT(m_hWnd != NULL);
6450 		::SendMessage(m_hWnd, TDM_CLICK_VERIFICATION, bCheck, bFocus);
6451 	}
6452 
UpdateElementText(TASKDIALOG_ELEMENTS element,LPCWSTR lpstrText)6453 	void UpdateElementText(TASKDIALOG_ELEMENTS element, LPCWSTR lpstrText)
6454 	{
6455 		ATLASSERT(m_hWnd != NULL);
6456 		::SendMessage(m_hWnd, TDM_UPDATE_ELEMENT_TEXT, element, (LPARAM)lpstrText);
6457 	}
6458 
SetButtonElevationRequiredState(int nButton,BOOL bElevation)6459 	void SetButtonElevationRequiredState(int nButton, BOOL bElevation)
6460 	{
6461 		ATLASSERT(m_hWnd != NULL);
6462 		::SendMessage(m_hWnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, nButton, bElevation);
6463 	}
6464 
UpdateIcon(TASKDIALOG_ICON_ELEMENTS element,HICON hIcon)6465 	void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, HICON hIcon)
6466 	{
6467 		ATLASSERT(m_hWnd != NULL);
6468 #ifdef _DEBUG
6469 		if(element == TDIE_ICON_MAIN)
6470 			ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) != 0);
6471 		else if(element == TDIE_ICON_FOOTER)
6472 			ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) != 0);
6473 #endif // _DEBUG
6474 		::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)hIcon);
6475 	}
6476 
UpdateIcon(TASKDIALOG_ICON_ELEMENTS element,LPCWSTR lpstrIcon)6477 	void UpdateIcon(TASKDIALOG_ICON_ELEMENTS element, LPCWSTR lpstrIcon)
6478 	{
6479 		ATLASSERT(m_hWnd != NULL);
6480 #ifdef _DEBUG
6481 		if(element == TDIE_ICON_MAIN)
6482 			ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_MAIN) == 0);
6483 		else if(element == TDIE_ICON_FOOTER)
6484 			ATLASSERT((m_tdc.dwFlags & TDF_USE_HICON_FOOTER) == 0);
6485 #endif // _DEBUG
6486 		::SendMessage(m_hWnd, TDM_UPDATE_ICON, element, (LPARAM)lpstrIcon);
6487 	}
6488 };
6489 
6490 
6491 ///////////////////////////////////////////////////////////////////////////////
6492 // CTaskDialog - for non-customized task dialogs
6493 
6494 class CTaskDialog : public CTaskDialogImpl<CTaskDialog>
6495 {
6496 public:
6497 	CTaskDialog(HWND hWndParent = NULL) : CTaskDialogImpl<CTaskDialog>(hWndParent)
6498 	{
6499 		m_tdc.pfCallback = NULL;
6500 	}
6501 };
6502 
6503 #endif // ((_WIN32_WINNT >= 0x0600) || defined(_WTL_TASKDIALOG)) && !defined(_WIN32_WCE)
6504 
6505 }; // namespace WTL
6506 
6507 #endif // __ATLDLGS_H__
6508