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