Code Search for Developers
 
 
  

atldlgs.h from bccSDK at Krugle


Show atldlgs.h syntax highlighted

// Windows Template Library - WTL version 8.0
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// This file is a part of the Windows Template Library.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license. You must not remove this notice, or
// any other, from this software.

#ifndef __ATLDLGS_H__
#define __ATLDLGS_H__

#pragma once

#ifndef __cplusplus
	#error ATL requires C++ compilation (use a .cpp suffix)
#endif

#ifndef __ATLAPP_H__
	#error atldlgs.h requires atlapp.h to be included first
#endif

#ifndef __ATLWIN_H__
	#error atldlgs.h requires atlwin.h to be included first
#endif

#include <commdlg.h>
#include <shlobj.h>


///////////////////////////////////////////////////////////////////////////////
// Classes in this file:
//
// CFileDialogImpl<T>
// CFileDialog
// CFolderDialogImpl<T>
// CFolderDialog
// CFontDialogImpl<T>
// CFontDialog
// CRichEditFontDialogImpl<T>
// CRichEditFontDialog
// CColorDialogImpl<T>
// CColorDialog
// CPrintDialogImpl<T>
// CPrintDialog
// CPrintDialogExImpl<T>
// CPrintDialogEx
// CPageSetupDialogImpl<T>
// CPageSetupDialog
// CFindReplaceDialogImpl<T>
// CFindReplaceDialog
//
// CPropertySheetWindow
// CPropertySheetImpl<T, TBase>
// CPropertySheet
// CPropertyPageWindow
// CPropertyPageImpl<T, TBase>
// CPropertyPage<t_wDlgTemplateID>
// CAxPropertyPageImpl<T, TBase>
// CAxPropertyPage<t_wDlgTemplateID>
//
// CWizard97SheetWindow
// CWizard97SheetImpl<T, TBase>
// CWizard97Sheet
// CWizard97PageWindow
// CWizard97PageImpl<T, TBase>
// CWizard97ExteriorPageImpl<T, TBase>
// CWizard97InteriorPageImpl<T, TBase>


namespace WTL
{

///////////////////////////////////////////////////////////////////////////////
// CFileDialogImpl - used for File Open or File Save As

// compatibility with the old (vc6.0) headers
#if (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)
  #ifndef CDSIZEOF_STRUCT
    #define CDSIZEOF_STRUCT(structname, member)  (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
  #endif
  #define OPENFILENAME_SIZE_VERSION_400A  CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
  #define OPENFILENAME_SIZE_VERSION_400W  CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
  #ifdef UNICODE
    #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400W
  #else
    #define OPENFILENAME_SIZE_VERSION_400  OPENFILENAME_SIZE_VERSION_400A
  #endif // !UNICODE
#endif // (_WIN32_WINNT >= 0x0500) && !defined(OPENFILENAME_SIZE_VERSION_400)

template <class T>
class ATL_NO_VTABLE CFileDialogImpl : public ATL::CDialogImplBase
{
public:
	OPENFILENAME m_ofn;
	BOOL m_bOpenFileDialog;            // TRUE for file open, FALSE for file save
	TCHAR m_szFileTitle[_MAX_FNAME];   // contains file title after return
	TCHAR m_szFileName[_MAX_PATH];     // contains full path name after return

	CFileDialogImpl(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
			LPCTSTR lpszDefExt = NULL,
			LPCTSTR lpszFileName = NULL,
			DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
			LPCTSTR lpszFilter = NULL,
			HWND hWndParent = NULL)
	{
		memset(&m_ofn, 0, sizeof(m_ofn)); // initialize structure to 0/NULL
		m_szFileName[0] = _T('\0');
		m_szFileTitle[0] = _T('\0');

		m_bOpenFileDialog = bOpenFileDialog;

		m_ofn.lStructSize = sizeof(m_ofn);
#if (_WIN32_WINNT >= 0x0500)
		// adjust struct size if running on older version of Windows
		if(AtlIsOldWindows())
		{
			ATLASSERT(sizeof(m_ofn) > OPENFILENAME_SIZE_VERSION_400);   // must be
			m_ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
		}
#endif // (_WIN32_WINNT >= 0x0500)
		m_ofn.lpstrFile = m_szFileName;
		m_ofn.nMaxFile = _MAX_PATH;
		m_ofn.lpstrDefExt = lpszDefExt;
		m_ofn.lpstrFileTitle = (LPTSTR)m_szFileTitle;
		m_ofn.nMaxFileTitle = _MAX_FNAME;
#ifndef _WIN32_WCE
		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_ENABLESIZING;
#else // CE specific
		m_ofn.Flags = dwFlags | OFN_EXPLORER | OFN_ENABLEHOOK;
#endif // !_WIN32_WCE
		m_ofn.lpstrFilter = lpszFilter;
#if (_ATL_VER >= 0x0700)
		m_ofn.hInstance = ATL::_AtlBaseModule.GetResourceInstance();
#else // !(_ATL_VER >= 0x0700)
		m_ofn.hInstance = _Module.GetResourceInstance();
#endif // !(_ATL_VER >= 0x0700)
		m_ofn.lpfnHook = (LPOFNHOOKPROC)T::StartDialogProc;
		m_ofn.hwndOwner = hWndParent;

		// setup initial file name
		if(lpszFileName != NULL)
			lstrcpyn(m_szFileName, lpszFileName, _MAX_PATH);
	}

	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT((m_ofn.Flags & OFN_ENABLEHOOK) != 0);
		ATLASSERT(m_ofn.lpfnHook != NULL);   // can still be a user hook

		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		if(m_ofn.hwndOwner == NULL)   // set only if not specified before
			m_ofn.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (ATL::CDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)

		BOOL bRet;
		if(m_bOpenFileDialog)
			bRet = ::GetOpenFileName(&m_ofn);
		else
			bRet = ::GetSaveFileName(&m_ofn);

		m_hWnd = NULL;

		return bRet ? IDOK : IDCANCEL;
	}

// Attributes
	ATL::CWindow GetFileDialogWindow() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return ATL::CWindow(GetParent());
	}

	int GetFilePath(LPTSTR lpstrFilePath, int nLength) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		return (int)GetFileDialogWindow().SendMessage(CDM_GETFILEPATH, nLength, (LPARAM)lpstrFilePath);
	}

	int GetFolderIDList(LPVOID lpBuff, int nLength) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERIDLIST, nLength, (LPARAM)lpBuff);
	}

	int GetFolderPath(LPTSTR lpstrFolderPath, int nLength) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		return (int)GetFileDialogWindow().SendMessage(CDM_GETFOLDERPATH, nLength, (LPARAM)lpstrFolderPath);
	}

	int GetSpec(LPTSTR lpstrSpec, int nLength) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		return (int)GetFileDialogWindow().SendMessage(CDM_GETSPEC, nLength, (LPARAM)lpstrSpec);
	}

	void SetControlText(int nCtrlID, LPCTSTR lpstrText)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		GetFileDialogWindow().SendMessage(CDM_SETCONTROLTEXT, nCtrlID, (LPARAM)lpstrText);
	}

	void SetDefExt(LPCTSTR lpstrExt)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		GetFileDialogWindow().SendMessage(CDM_SETDEFEXT, 0, (LPARAM)lpstrExt);
	}

	BOOL GetReadOnlyPref() const	// return TRUE if readonly checked
	{
		return ((m_ofn.Flags & OFN_READONLY) != 0) ? TRUE : FALSE;
	}

// Operations
	void HideControl(int nCtrlID)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((m_ofn.Flags & OFN_EXPLORER) != 0);

		GetFileDialogWindow().SendMessage(CDM_HIDECONTROL, nCtrlID);
	}

// Special override for common dialogs
	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		GetFileDialogWindow().SendMessage(WM_COMMAND, MAKEWPARAM(IDCANCEL, 0));
		return TRUE;
	}

// Message map and handlers
	BEGIN_MSG_MAP(CFileDialogImpl)
		NOTIFY_CODE_HANDLER(CDN_FILEOK, _OnFileOK)
		NOTIFY_CODE_HANDLER(CDN_FOLDERCHANGE, _OnFolderChange)
		NOTIFY_CODE_HANDLER(CDN_HELP, _OnHelp)
		NOTIFY_CODE_HANDLER(CDN_INITDONE, _OnInitDone)
		NOTIFY_CODE_HANDLER(CDN_SELCHANGE, _OnSelChange)
		NOTIFY_CODE_HANDLER(CDN_SHAREVIOLATION, _OnShareViolation)
		NOTIFY_CODE_HANDLER(CDN_TYPECHANGE, _OnTypeChange)
	END_MSG_MAP()

	LRESULT _OnFileOK(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		return !pT->OnFileOK((LPOFNOTIFY)pnmh);
	}

	LRESULT _OnFolderChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		pT->OnFolderChange((LPOFNOTIFY)pnmh);
		return 0;
	}

	LRESULT _OnHelp(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		pT->OnHelp((LPOFNOTIFY)pnmh);
		return 0;
	}

	LRESULT _OnInitDone(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		pT->OnInitDone((LPOFNOTIFY)pnmh);
		return 0;
	}

	LRESULT _OnSelChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		pT->OnSelChange((LPOFNOTIFY)pnmh);
		return 0;
	}

	LRESULT _OnShareViolation(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		return pT->OnShareViolation((LPOFNOTIFY)pnmh);
	}

	LRESULT _OnTypeChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		T* pT = static_cast<T*>(this);
		pT->OnTypeChange((LPOFNOTIFY)pnmh);
		return 0;
	}

// Overrideables
	BOOL OnFileOK(LPOFNOTIFY /*lpon*/)
	{
		return TRUE;
	}

	void OnFolderChange(LPOFNOTIFY /*lpon*/)
	{
	}

	void OnHelp(LPOFNOTIFY /*lpon*/)
	{
	}

	void OnInitDone(LPOFNOTIFY /*lpon*/)
	{
	}

	void OnSelChange(LPOFNOTIFY /*lpon*/)
	{
	}

	int OnShareViolation(LPOFNOTIFY /*lpon*/)
	{
		return 0;
	}

	void OnTypeChange(LPOFNOTIFY /*lpon*/)
	{
	}
};


class CFileDialog : public CFileDialogImpl<CFileDialog>
{
public:
	CFileDialog(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs
		LPCTSTR lpszDefExt = NULL,
		LPCTSTR lpszFileName = NULL,
		DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
		LPCTSTR lpszFilter = NULL,
		HWND hWndParent = NULL)
		: CFileDialogImpl<CFileDialog>(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, hWndParent)
	{ }

	// override base class map and references to handlers
	DECLARE_EMPTY_MSG_MAP()
};


///////////////////////////////////////////////////////////////////////////////
// CFolderDialogImpl - used for browsing for a folder

#ifndef _WIN32_WCE

template <class T>
class ATL_NO_VTABLE CFolderDialogImpl
{
public:
	BROWSEINFO m_bi;
	LPCTSTR m_lpstrInitialFolder;
	TCHAR m_szFolderDisplayName[MAX_PATH];
	TCHAR m_szFolderPath[MAX_PATH];
	HWND m_hWnd;   // used only in the callback function

// Constructor
	CFolderDialogImpl(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS) : 
			m_lpstrInitialFolder(NULL), m_hWnd(NULL)
	{
		memset(&m_bi, 0, sizeof(m_bi)); // initialize structure to 0/NULL

		m_bi.hwndOwner = hWndParent;
		m_bi.pidlRoot = NULL;
		m_bi.pszDisplayName = m_szFolderDisplayName;
		m_bi.lpszTitle = lpstrTitle;
		m_bi.ulFlags = uFlags;
		m_bi.lpfn = BrowseCallbackProc;
		m_bi.lParam = (LPARAM)static_cast<T*>(this);

		m_szFolderPath[0] = 0;
		m_szFolderDisplayName[0] = 0;
	}

// Operations
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		if(m_bi.hwndOwner == NULL)   // set only if not specified before
			m_bi.hwndOwner = hWndParent;

		INT_PTR nRet = -1;
		LPITEMIDLIST pItemIDList = ::SHBrowseForFolder(&m_bi);
		if(pItemIDList != NULL)
		{
			if(::SHGetPathFromIDList(pItemIDList, m_szFolderPath))
			{
				IMalloc* pMalloc = NULL;
				if(SUCCEEDED(::SHGetMalloc(&pMalloc)))
				{
					pMalloc->Free(pItemIDList);
					pMalloc->Release();
				}
				nRet = IDOK;
			}
			else
			{
				nRet = IDCANCEL;
			}
		}

		return nRet;
	}

	void SetInitialFolder(LPCTSTR lpstrInitialFolder)
	{
		m_lpstrInitialFolder = lpstrInitialFolder;
	}

	// filled after a call to DoModal
	LPCTSTR GetFolderPath() const
	{
		return m_szFolderPath;
	}

	LPCTSTR GetFolderDisplayName() const
	{
		return m_szFolderDisplayName;
	}

	int GetFolderImageIndex() const
	{
		return m_bi.iImage;
	}

// Callback function and overrideables
	static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
	{
#ifndef BFFM_VALIDATEFAILED
  #ifdef UNICODE
		const int BFFM_VALIDATEFAILED = 4;
  #else
		const int BFFM_VALIDATEFAILED = 3;
  #endif
#endif // !BFFM_VALIDATEFAILED
#ifndef BFFM_IUNKNOWN
		const int BFFM_IUNKNOWN = 5;
#endif // !BFFM_IUNKNOWN
#ifndef BIF_NEWDIALOGSTYLE
		const UINT BIF_NEWDIALOGSTYLE = 0x0040;
#endif // !BIF_NEWDIALOGSTYLE

		int nRet = 0;
		T* pT = (T*)lpData;
		bool bClear = false;
		if(pT->m_hWnd == NULL)
		{
			pT->m_hWnd = hWnd;
			bClear = true;
		}
		else
		{
			ATLASSERT(pT->m_hWnd == hWnd);
		}

		switch(uMsg)
		{
		case BFFM_INITIALIZED:
			if(pT->m_lpstrInitialFolder != NULL)
			{
				if((pT->m_bi.ulFlags & BIF_NEWDIALOGSTYLE) != 0)
					pT->SetExpanded(pT->m_lpstrInitialFolder);
				else
					pT->SetSelection(pT->m_lpstrInitialFolder);
			}
			pT->OnInitialized();
			break;
		case BFFM_SELCHANGED:
			pT->OnSelChanged((LPITEMIDLIST)lParam);
			break;
		case BFFM_VALIDATEFAILED:
			nRet = pT->OnValidateFailed((LPCTSTR)lParam);
			break;
		case BFFM_IUNKNOWN:
			pT->OnIUnknown((IUnknown*)lParam);
			break;
		default:
			ATLTRACE2(atlTraceUI, 0, _T("Unknown message received in CFolderDialogImpl::BrowseCallbackProc\n"));
			break;
		}

		if(bClear)
			pT->m_hWnd = NULL;
		return nRet;
	}

	void OnInitialized()
	{
	}

	void OnSelChanged(LPITEMIDLIST /*pItemIDList*/)
	{
	}

	int OnValidateFailed(LPCTSTR /*lpstrFolderPath*/)
	{
		return 1;   // 1=continue, 0=EndDialog
	}

	void OnIUnknown(IUnknown* /*pUnknown*/)
	{
	}

	// Commands - valid to call only from handlers
	void EnableOK(BOOL bEnable)
	{
		ATLASSERT(m_hWnd != NULL);
		::SendMessage(m_hWnd, BFFM_ENABLEOK, 0, bEnable);
	}

	void SetSelection(LPITEMIDLIST pItemIDList)
	{
		ATLASSERT(m_hWnd != NULL);
		::SendMessage(m_hWnd, BFFM_SETSELECTION, FALSE, (LPARAM)pItemIDList);
	}

	void SetSelection(LPCTSTR lpstrFolderPath)
	{
		ATLASSERT(m_hWnd != NULL);
		::SendMessage(m_hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpstrFolderPath);
	}

	void SetStatusText(LPCTSTR lpstrText)
	{
		ATLASSERT(m_hWnd != NULL);
		::SendMessage(m_hWnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)lpstrText);
	}

	void SetOKText(LPCTSTR lpstrOKText)
	{
#ifndef BFFM_SETOKTEXT
		const UINT BFFM_SETOKTEXT = WM_USER + 105;
#endif
		ATLASSERT(m_hWnd != NULL);
		USES_CONVERSION;
		LPCWSTR lpstr = T2CW(lpstrOKText);
		::SendMessage(m_hWnd, BFFM_SETOKTEXT, (WPARAM)lpstr, 0L);
	}

	void SetExpanded(LPITEMIDLIST pItemIDList)
	{
#ifndef BFFM_SETEXPANDED
		const UINT BFFM_SETEXPANDED = WM_USER + 106;
#endif
		ATLASSERT(m_hWnd != NULL);
		::SendMessage(m_hWnd, BFFM_SETEXPANDED, FALSE, (LPARAM)pItemIDList);
	}

	void SetExpanded(LPCTSTR lpstrFolderPath)
	{
#ifndef BFFM_SETEXPANDED
		const UINT BFFM_SETEXPANDED = WM_USER + 106;
#endif
		ATLASSERT(m_hWnd != NULL);
		USES_CONVERSION;
		LPCWSTR lpstr = T2CW(lpstrFolderPath);
		::SendMessage(m_hWnd, BFFM_SETEXPANDED, TRUE, (LPARAM)lpstr);
	}
};

class CFolderDialog : public CFolderDialogImpl<CFolderDialog>
{
public:
	CFolderDialog(HWND hWndParent = NULL, LPCTSTR lpstrTitle = NULL, UINT uFlags = BIF_RETURNONLYFSDIRS)
		: CFolderDialogImpl<CFolderDialog>(hWndParent, lpstrTitle, uFlags)
	{ }
};

#endif // !_WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CCommonDialogImplBase - base class for common dialog classes

class ATL_NO_VTABLE CCommonDialogImplBase : public ATL::CWindowImplBase
{
public:
	static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		if(uMsg != WM_INITDIALOG)
			return 0;
#if (_ATL_VER >= 0x0700)
		CCommonDialogImplBase* pT = (CCommonDialogImplBase*)ATL::_AtlWinModule.ExtractCreateWndData();
#else // !(_ATL_VER >= 0x0700)
		CCommonDialogImplBase* pT = (CCommonDialogImplBase*)_Module.ExtractCreateWndData();
#endif // !(_ATL_VER >= 0x0700)
		ATLASSERT(pT != NULL);
		ATLASSERT(pT->m_hWnd == NULL);
		ATLASSERT(::IsWindow(hWnd));
		// subclass dialog's window
		if(!pT->SubclassWindow(hWnd))
		{
			ATLTRACE2(atlTraceUI, 0, _T("Subclassing a common dialog failed\n"));
			return 0;
		}
		// check message map for WM_INITDIALOG handler
		LRESULT lRes = 0;
		if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
			return 0;
		return lRes;
	}

// Special override for common dialogs
	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
		return TRUE;
	}

// Implementation - try to override these, to prevent errors
	HWND Create(HWND, ATL::_U_RECT, LPCTSTR, DWORD, DWORD, ATL::_U_MENUorID, ATOM, LPVOID)
	{
		ATLASSERT(FALSE);   // should not be called
		return NULL;
	}

	static LRESULT CALLBACK StartWindowProc(HWND /*hWnd*/, UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/)
	{
		ATLASSERT(FALSE);   // should not be called
		return 0;
	}
};


///////////////////////////////////////////////////////////////////////////////
// CFontDialogImpl - font selection dialog

#ifndef _WIN32_WCE

template <class T>
class ATL_NO_VTABLE CFontDialogImpl : public CCommonDialogImplBase
{
public:
	enum { _cchStyleName = 64 };

	CHOOSEFONT m_cf;
	TCHAR m_szStyleName[_cchStyleName];  // contains style name after return
	LOGFONT m_lf;                        // default LOGFONT to store the info

// Constructors
	CFontDialogImpl(LPLOGFONT lplfInitial = NULL,
			DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
			HDC hDCPrinter = NULL,
			HWND hWndParent = NULL)
	{
		memset(&m_cf, 0, sizeof(m_cf));
		memset(&m_lf, 0, sizeof(m_lf));
		memset(&m_szStyleName, 0, sizeof(m_szStyleName));

		m_cf.lStructSize = sizeof(m_cf);
		m_cf.hwndOwner = hWndParent;
		m_cf.rgbColors = RGB(0, 0, 0);
		m_cf.lpszStyle = (LPTSTR)&m_szStyleName;
		m_cf.Flags = dwFlags | CF_ENABLEHOOK;
		m_cf.lpfnHook = (LPCFHOOKPROC)T::HookProc;

		if(lplfInitial != NULL)
		{
			m_cf.lpLogFont = lplfInitial;
			m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
			memcpy(&m_lf, m_cf.lpLogFont, sizeof(m_lf));
		}
		else
		{
			m_cf.lpLogFont = &m_lf;
		}

		if(hDCPrinter != NULL)
		{
			m_cf.hDC = hDCPrinter;
			m_cf.Flags |= CF_PRINTERFONTS;
		}
	}

// Operations
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT((m_cf.Flags & CF_ENABLEHOOK) != 0);
		ATLASSERT(m_cf.lpfnHook != NULL);   // can still be a user hook

		if(m_cf.hwndOwner == NULL)          // set only if not specified before
			m_cf.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)

		BOOL bRet = ::ChooseFont(&m_cf);

		m_hWnd = NULL;

		if(bRet)   // copy logical font from user's initialization buffer (if needed)
			memcpy(&m_lf, m_cf.lpLogFont, sizeof(m_lf));

		return bRet ? IDOK : IDCANCEL;
	}

	// Get the selected font (works during DoModal displayed or after)
	void GetCurrentFont(LPLOGFONT lplf) const
	{
		ATLASSERT(lplf != NULL);

		if(m_hWnd != NULL)
			::SendMessage(m_hWnd, WM_CHOOSEFONT_GETLOGFONT, 0, (LPARAM)lplf);
		else
			*lplf = m_lf;
	}

	// Helpers for parsing information after successful return
	LPCTSTR GetFaceName() const   // return the face name of the font
	{
		return (LPCTSTR)m_cf.lpLogFont->lfFaceName;
	}

	LPCTSTR GetStyleName() const  // return the style name of the font
	{
		return m_cf.lpszStyle;
	}

	int GetSize() const           // return the pt size of the font
	{
		return m_cf.iPointSize;
	}

	COLORREF GetColor() const     // return the color of the font
	{
		return m_cf.rgbColors;
	}

	int GetWeight() const         // return the chosen font weight
	{
		return (int)m_cf.lpLogFont->lfWeight;
	}

	BOOL IsStrikeOut() const      // return TRUE if strikeout
	{
		return (m_cf.lpLogFont->lfStrikeOut) ? TRUE : FALSE;
	}

	BOOL IsUnderline() const      // return TRUE if underline
	{
		return (m_cf.lpLogFont->lfUnderline) ? TRUE : FALSE;
	}

	BOOL IsBold() const           // return TRUE if bold font
	{
		return (m_cf.lpLogFont->lfWeight == FW_BOLD) ? TRUE : FALSE;
	}

	BOOL IsItalic() const         // return TRUE if italic font
	{
		return m_cf.lpLogFont->lfItalic ? TRUE : FALSE;
	}
};

class CFontDialog : public CFontDialogImpl<CFontDialog>
{
public:
	CFontDialog(LPLOGFONT lplfInitial = NULL,
		DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS,
		HDC hDCPrinter = NULL,
		HWND hWndParent = NULL)
		: CFontDialogImpl<CFontDialog>(lplfInitial, dwFlags, hDCPrinter, hWndParent)
	{ }

	DECLARE_EMPTY_MSG_MAP()
};

#endif // _WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CRichEditFontDialogImpl - font selection for the Rich Edit ctrl

#if defined(_RICHEDIT_) && !defined(_WIN32_WCE)

template <class T>
class ATL_NO_VTABLE CRichEditFontDialogImpl : public CFontDialogImpl< T >
{
public:
	CRichEditFontDialogImpl(const CHARFORMAT& charformat,
			DWORD dwFlags = CF_SCREENFONTS,
			HDC hDCPrinter = NULL,
			HWND hWndParent = NULL)
			: CFontDialogImpl< T >(NULL, dwFlags, hDCPrinter, hWndParent)
	{
		m_cf.Flags |= CF_INITTOLOGFONTSTRUCT;
		m_cf.Flags |= FillInLogFont(charformat);
		m_cf.lpLogFont = &m_lf;

		if((charformat.dwMask & CFM_COLOR) != 0)
			m_cf.rgbColors = charformat.crTextColor;
	}

	void GetCharFormat(CHARFORMAT& cf) const
	{
		USES_CONVERSION;
		cf.dwEffects = 0;
		cf.dwMask = 0;
		if((m_cf.Flags & CF_NOSTYLESEL) == 0)
		{
			cf.dwMask |= CFM_BOLD | CFM_ITALIC;
			cf.dwEffects |= IsBold() ? CFE_BOLD : 0;
			cf.dwEffects |= IsItalic() ? CFE_ITALIC : 0;
		}
		if((m_cf.Flags & CF_NOSIZESEL) == 0)
		{
			cf.dwMask |= CFM_SIZE;
			// GetSize() returns in tenths of points so mulitply by 2 to get twips
			cf.yHeight = GetSize() * 2;
		}

		if((m_cf.Flags & CF_NOFACESEL) == 0)
		{
			cf.dwMask |= CFM_FACE;
			cf.bPitchAndFamily = m_cf.lpLogFont->lfPitchAndFamily;
#if (_RICHEDIT_VER >= 0x0200)
			lstrcpy(cf.szFaceName, GetFaceName());
#else
			lstrcpyA(cf.szFaceName, T2A((LPTSTR)(LPCTSTR)GetFaceName()));
#endif // (_RICHEDIT_VER >= 0x0200)
		}

		if((m_cf.Flags & CF_EFFECTS) != 0)
		{
			cf.dwMask |= CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR;
			cf.dwEffects |= IsUnderline() ? CFE_UNDERLINE : 0;
			cf.dwEffects |= IsStrikeOut() ? CFE_STRIKEOUT : 0;
			cf.crTextColor = GetColor();
		}
		if((m_cf.Flags & CF_NOSCRIPTSEL) == 0)
		{
			cf.bCharSet = m_cf.lpLogFont->lfCharSet;
			cf.dwMask |= CFM_CHARSET;
		}
		cf.yOffset = 0;
	}

	DWORD FillInLogFont(const CHARFORMAT& cf)
	{
		USES_CONVERSION;
		DWORD dwFlags = 0;
		if((cf.dwMask & CFM_SIZE) != 0)
		{
			HDC hDC = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
			LONG yPerInch = ::GetDeviceCaps(hDC, LOGPIXELSY);
			m_lf.lfHeight = -(int)((cf.yHeight * yPerInch) / 1440);
		}
		else
			m_lf.lfHeight = 0;

		m_lf.lfWidth = 0;
		m_lf.lfEscapement = 0;
		m_lf.lfOrientation = 0;

		if((cf.dwMask & (CFM_ITALIC | CFM_BOLD)) == (CFM_ITALIC | CFM_BOLD))
		{
			m_lf.lfWeight = ((cf.dwEffects & CFE_BOLD) != 0) ? FW_BOLD : FW_NORMAL;
			m_lf.lfItalic = (BYTE)(((cf.dwEffects & CFE_ITALIC) != 0) ? TRUE : FALSE);
		}
		else
		{
			dwFlags |= CF_NOSTYLESEL;
			m_lf.lfWeight = FW_DONTCARE;
			m_lf.lfItalic = FALSE;
		}

		if((cf.dwMask & (CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR)) == (CFM_UNDERLINE|CFM_STRIKEOUT|CFM_COLOR))
		{
			dwFlags |= CF_EFFECTS;
			m_lf.lfUnderline = (BYTE)(((cf.dwEffects & CFE_UNDERLINE) != 0) ? TRUE : FALSE);
			m_lf.lfStrikeOut = (BYTE)(((cf.dwEffects & CFE_STRIKEOUT) != 0) ? TRUE : FALSE);
		}
		else
		{
			m_lf.lfUnderline = (BYTE)FALSE;
			m_lf.lfStrikeOut = (BYTE)FALSE;
		}

		if((cf.dwMask & CFM_CHARSET) != 0)
			m_lf.lfCharSet = cf.bCharSet;
		else
			dwFlags |= CF_NOSCRIPTSEL;
		m_lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
		m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
		m_lf.lfQuality = DEFAULT_QUALITY;
		if((cf.dwMask & CFM_FACE) != 0)
		{
			m_lf.lfPitchAndFamily = cf.bPitchAndFamily;
#if (_RICHEDIT_VER >= 0x0200)
			lstrcpy(m_lf.lfFaceName, cf.szFaceName);
#else
			lstrcpy(m_lf.lfFaceName, A2T((LPSTR)cf.szFaceName));
#endif // (_RICHEDIT_VER >= 0x0200)
		}
		else
		{
			m_lf.lfPitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
			m_lf.lfFaceName[0] = (TCHAR)0;
		}
		return dwFlags;
	}
};

class CRichEditFontDialog : public CRichEditFontDialogImpl<CRichEditFontDialog>
{
public:
	CRichEditFontDialog(const CHARFORMAT& charformat,
		DWORD dwFlags = CF_SCREENFONTS,
		HDC hDCPrinter = NULL,
		HWND hWndParent = NULL)
		: CRichEditFontDialogImpl<CRichEditFontDialog>(charformat, dwFlags, hDCPrinter, hWndParent)
	{ }

	DECLARE_EMPTY_MSG_MAP()
};

#endif // defined(_RICHEDIT_) && !defined(_WIN32_WCE)


///////////////////////////////////////////////////////////////////////////////
// CColorDialogImpl - color selection

#ifndef _WIN32_WCE

template <class T>
class ATL_NO_VTABLE CColorDialogImpl : public CCommonDialogImplBase
{
public:
	CHOOSECOLOR m_cc;

// Constructor
	CColorDialogImpl(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
	{
		memset(&m_cc, 0, sizeof(m_cc));

		m_cc.lStructSize = sizeof(m_cc);
		m_cc.lpCustColors = GetCustomColors();
		m_cc.hwndOwner = hWndParent;
		m_cc.Flags = dwFlags | CC_ENABLEHOOK;
		m_cc.lpfnHook = (LPCCHOOKPROC)T::HookProc;

		if(clrInit != 0)
		{
			m_cc.rgbResult = clrInit;
			m_cc.Flags |= CC_RGBINIT;
		}
	}

// Operations
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT((m_cc.Flags & CC_ENABLEHOOK) != 0);
		ATLASSERT(m_cc.lpfnHook != NULL);   // can still be a user hook

		if(m_cc.hwndOwner == NULL)          // set only if not specified before
			m_cc.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)

		BOOL bRet = ::ChooseColor(&m_cc);

		m_hWnd = NULL;

		return bRet ? IDOK : IDCANCEL;
	}

	// Set the current color while dialog is displayed
	void SetCurrentColor(COLORREF clr)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		SendMessage(_GetSetRGBMessage(), 0, (LPARAM)clr);
	}

	// Get the selected color after DoModal returns, or in OnColorOK
	COLORREF GetColor() const
	{
		return m_cc.rgbResult;
	}

// Special override for the color dialog
	static UINT_PTR APIENTRY HookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		if(uMsg != WM_INITDIALOG && uMsg != _GetColorOKMessage())
			return 0;

		LPCHOOSECOLOR lpCC = (LPCHOOSECOLOR)lParam;
		CCommonDialogImplBase* pT = NULL;

		if(uMsg == WM_INITDIALOG)
		{
#if (_ATL_VER >= 0x0700)
			pT = (CCommonDialogImplBase*)ATL::_AtlWinModule.ExtractCreateWndData();
#else // !(_ATL_VER >= 0x0700)
			pT = (CCommonDialogImplBase*)_Module.ExtractCreateWndData();
#endif // !(_ATL_VER >= 0x0700)
			lpCC->lCustData = (LPARAM)pT;
			ATLASSERT(pT != NULL);
			ATLASSERT(pT->m_hWnd == NULL);
			ATLASSERT(::IsWindow(hWnd));
			// subclass dialog's window
			if(!pT->SubclassWindow(hWnd))
			{
				ATLTRACE2(atlTraceUI, 0, _T("Subclassing a Color common dialog failed\n"));
				return 0;
			}
		}
		else if(uMsg == _GetColorOKMessage())
		{
			pT = (CCommonDialogImplBase*)lpCC->lCustData;
			ATLASSERT(pT != NULL);
			ATLASSERT(::IsWindow(pT->m_hWnd));
		}

		// pass to the message map
		LRESULT lRes;
		if(pT->ProcessWindowMessage(pT->m_hWnd, uMsg, wParam, lParam, lRes, 0) == FALSE)
			return 0;
		return lRes;
	}

// Helpers
	static COLORREF* GetCustomColors()
	{
		static COLORREF rgbCustomColors[16] =
		{
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
			RGB(255, 255, 255), RGB(255, 255, 255), 
		};

		return rgbCustomColors;
	}

	static UINT _GetSetRGBMessage()
	{
		static UINT uSetRGBMessage = 0;
		if(uSetRGBMessage == 0)
		{
			CStaticDataInitCriticalSectionLock lock;
			if(FAILED(lock.Lock()))
			{
				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetSetRGBMessage.\n"));
				ATLASSERT(FALSE);
				return 0;
			}

			if(uSetRGBMessage == 0)
				uSetRGBMessage = ::RegisterWindowMessage(SETRGBSTRING);

			lock.Unlock();
		}
		ATLASSERT(uSetRGBMessage != 0);
		return uSetRGBMessage;
	}

	static UINT _GetColorOKMessage()
	{
		static UINT uColorOKMessage = 0;
		if(uColorOKMessage == 0)
		{
			CStaticDataInitCriticalSectionLock lock;
			if(FAILED(lock.Lock()))
			{
				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CColorDialogImpl::_GetColorOKMessage.\n"));
				ATLASSERT(FALSE);
				return 0;
			}

			if(uColorOKMessage == 0)
				uColorOKMessage = ::RegisterWindowMessage(COLOROKSTRING);

			lock.Unlock();
		}
		ATLASSERT(uColorOKMessage != 0);
		return uColorOKMessage;
	}

// Message map and handlers
	BEGIN_MSG_MAP(CColorDialogImpl)
		MESSAGE_HANDLER(_GetColorOKMessage(), _OnColorOK)
	END_MSG_MAP()

	LRESULT _OnColorOK(UINT, WPARAM, LPARAM, BOOL&)
	{
		T* pT = static_cast<T*>(this);
		return pT->OnColorOK();
	}

// Overrideable
	BOOL OnColorOK()        // validate color
	{
		return FALSE;
	}
};

class CColorDialog : public CColorDialogImpl<CColorDialog>
{
public:
	CColorDialog(COLORREF clrInit = 0, DWORD dwFlags = 0, HWND hWndParent = NULL)
		: CColorDialogImpl<CColorDialog>(clrInit, dwFlags, hWndParent)
	{ }

	// override base class map and references to handlers
	DECLARE_EMPTY_MSG_MAP()
};

#endif // _WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CPrintDialogImpl - used for Print... and PrintSetup...

#ifndef _WIN32_WCE

// global helper
static HDC _AtlCreateDC(HGLOBAL hDevNames, HGLOBAL hDevMode)
{
	if(hDevNames == NULL)
		return NULL;

	LPDEVNAMES lpDevNames = (LPDEVNAMES)::GlobalLock(hDevNames);
	LPDEVMODE  lpDevMode = (hDevMode != NULL) ? (LPDEVMODE)::GlobalLock(hDevMode) : NULL;

	if(lpDevNames == NULL)
		return NULL;

	HDC hDC = ::CreateDC((LPCTSTR)lpDevNames + lpDevNames->wDriverOffset,
					  (LPCTSTR)lpDevNames + lpDevNames->wDeviceOffset,
					  (LPCTSTR)lpDevNames + lpDevNames->wOutputOffset,
					  lpDevMode);

	::GlobalUnlock(hDevNames);
	if(hDevMode != NULL)
		::GlobalUnlock(hDevMode);
	return hDC;
}

template <class T>
class ATL_NO_VTABLE CPrintDialogImpl : public CCommonDialogImplBase
{
public:
	// print dialog parameter block (note this is a reference)
	PRINTDLG& m_pd;

// Constructors
	CPrintDialogImpl(BOOL bPrintSetupOnly = FALSE,	// TRUE for Print Setup, FALSE for Print Dialog
			DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
			HWND hWndParent = NULL)
			: m_pd(m_pdActual)
	{
		memset(&m_pdActual, 0, sizeof(m_pdActual));

		m_pd.lStructSize = sizeof(m_pdActual);
		m_pd.hwndOwner = hWndParent;
		m_pd.Flags = (dwFlags | PD_ENABLEPRINTHOOK | PD_ENABLESETUPHOOK);
		m_pd.lpfnPrintHook = (LPPRINTHOOKPROC)T::HookProc;
		m_pd.lpfnSetupHook = (LPSETUPHOOKPROC)T::HookProc;

		if(bPrintSetupOnly)
			m_pd.Flags |= PD_PRINTSETUP;
		else
			m_pd.Flags |= PD_RETURNDC;

		m_pd.Flags &= ~PD_RETURNIC; // do not support information context
	}

// Operations
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT((m_pd.Flags & PD_ENABLEPRINTHOOK) != 0);
		ATLASSERT((m_pd.Flags & PD_ENABLESETUPHOOK) != 0);
		ATLASSERT(m_pd.lpfnPrintHook != NULL);   // can still be a user hook
		ATLASSERT(m_pd.lpfnSetupHook != NULL);   // can still be a user hook
		ATLASSERT((m_pd.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this

		if(m_pd.hwndOwner == NULL)   // set only if not specified before
			m_pd.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)

		BOOL bRet = ::PrintDlg(&m_pd);

		m_hWnd = NULL;

		return bRet ? IDOK : IDCANCEL;
	}

	// GetDefaults will not display a dialog but will get device defaults
	BOOL GetDefaults()
	{
		m_pd.Flags |= PD_RETURNDEFAULT;
		ATLASSERT(m_pd.hDevMode == NULL);    // must be NULL
		ATLASSERT(m_pd.hDevNames == NULL);   // must be NULL

		return ::PrintDlg(&m_pd);
	}

	// Helpers for parsing information after successful return num. copies requested
	int GetCopies() const
	{
		if((m_pd.Flags & PD_USEDEVMODECOPIES) != 0)
		{
			LPDEVMODE lpDevMode = GetDevMode();
			return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
		}

		return m_pd.nCopies;
	}

	BOOL PrintCollate() const       // TRUE if collate checked
	{
		return ((m_pd.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
	}

	BOOL PrintSelection() const     // TRUE if printing selection
	{
		return ((m_pd.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
	}

	BOOL PrintAll() const           // TRUE if printing all pages
	{
		return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
	}

	BOOL PrintRange() const         // TRUE if printing page range
	{
		return ((m_pd.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
	}

	BOOL PrintToFile() const        // TRUE if printing to a file
	{
		return ((m_pd.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
	}

	int GetFromPage() const         // starting page if valid
	{
		return PrintRange() ? m_pd.nFromPage : -1;
	}

	int GetToPage() const           // ending page if valid
	{
		return PrintRange() ? m_pd.nToPage : -1;
	}

	LPDEVMODE GetDevMode() const    // return DEVMODE
	{
		if(m_pd.hDevMode == NULL)
			return NULL;

		return (LPDEVMODE)::GlobalLock(m_pd.hDevMode);
	}

	LPCTSTR GetDriverName() const   // return driver name
	{
		if(m_pd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
	}

	LPCTSTR GetDeviceName() const   // return device name
	{
		if(m_pd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
	}

	LPCTSTR GetPortName() const     // return output port name
	{
		if(m_pd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pd.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
	}

	HDC GetPrinterDC() const        // return HDC (caller must delete)
	{
		ATLASSERT((m_pd.Flags & PD_RETURNDC) != 0);
		return m_pd.hDC;
	}

	// This helper creates a DC based on the DEVNAMES and DEVMODE structures.
	// This DC is returned, but also stored in m_pd.hDC as though it had been
	// returned by CommDlg.  It is assumed that any previously obtained DC
	// has been/will be deleted by the user.  This may be
	// used without ever invoking the print/print setup dialogs.
	HDC CreatePrinterDC()
	{
		m_pd.hDC = _AtlCreateDC(m_pd.hDevNames, m_pd.hDevMode);
		return m_pd.hDC;
	}

// Implementation
	PRINTDLG m_pdActual; // the Print/Print Setup need to share this

	// The following handle the case of print setup... from the print dialog
	CPrintDialogImpl(PRINTDLG& pdInit) : m_pd(pdInit)
	{ }

	BEGIN_MSG_MAP(CPrintDialogImpl)
#ifdef psh1
		COMMAND_ID_HANDLER(psh1, OnPrintSetup) // print setup button when print is displayed
#else // !psh1
		COMMAND_ID_HANDLER(0x0400, OnPrintSetup) // value from dlgs.h
#endif // !psh1
	END_MSG_MAP()

	LRESULT OnPrintSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& /*bHandled*/)
	{
		T dlgSetup(m_pd);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&dlgSetup.m_thunk.cd, (CCommonDialogImplBase*)&dlgSetup);
#endif // !(_ATL_VER >= 0x0700)
		return DefWindowProc(WM_COMMAND, MAKEWPARAM(wID, wNotifyCode), (LPARAM)hWndCtl);
	}
};

class CPrintDialog : public CPrintDialogImpl<CPrintDialog>
{
public:
	CPrintDialog(BOOL bPrintSetupOnly = FALSE,
		DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION,
		HWND hWndParent = NULL)
		: CPrintDialogImpl<CPrintDialog>(bPrintSetupOnly, dwFlags, hWndParent)
	{ }

	CPrintDialog(PRINTDLG& pdInit) : CPrintDialogImpl<CPrintDialog>(pdInit)
	{ }
};

#endif // _WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CPrintDialogExImpl - new print dialog for Windows 2000

#if (WINVER >= 0x0500) && !defined(_WIN32_WCE)

}; // namespace WTL

#include <atlcom.h>

extern "C" const __declspec(selectany) IID IID_IPrintDialogCallback = {0x5852a2c3, 0x6530, 0x11d1, {0xb6, 0xa3, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};
extern "C" const __declspec(selectany) IID IID_IPrintDialogServices = {0x509aaeda, 0x5639, 0x11d1, {0xb6, 0xa1, 0x0, 0x0, 0xf8, 0x75, 0x7b, 0xf9}};

namespace WTL
{

template <class T>
class ATL_NO_VTABLE CPrintDialogExImpl : 
				public ATL::CWindow,
				public ATL::CMessageMap,
				public IPrintDialogCallback,
				public ATL::IObjectWithSiteImpl< T >
{
public:
	PRINTDLGEX m_pdex;

// Constructor
	CPrintDialogExImpl(DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
				HWND hWndParent = NULL)
	{
		memset(&m_pdex, 0, sizeof(m_pdex));

		m_pdex.lStructSize = sizeof(PRINTDLGEX);
		m_pdex.hwndOwner = hWndParent;
		m_pdex.Flags = dwFlags;
		m_pdex.nStartPage = START_PAGE_GENERAL;
		// callback object will be set in DoModal

		m_pdex.Flags &= ~PD_RETURNIC; // do not support information context
	}

// Operations
	HRESULT DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT(m_hWnd == NULL);
		ATLASSERT((m_pdex.Flags & PD_RETURNDEFAULT) == 0);   // use GetDefaults for this

		if(m_pdex.hwndOwner == NULL)   // set only if not specified before
			m_pdex.hwndOwner = hWndParent;

		T* pT = static_cast<T*>(this);
		m_pdex.lpCallback = (IUnknown*)(IPrintDialogCallback*)pT;

		HRESULT hResult = ::PrintDlgEx(&m_pdex);

		m_hWnd = NULL;

		return hResult;
	}

	BOOL EndDialog(INT_PTR /*nRetCode*/ = 0)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		SendMessage(WM_COMMAND, MAKEWPARAM(IDABORT, 0));
		return TRUE;
	}

	// GetDefaults will not display a dialog but will get device defaults
	HRESULT GetDefaults()
	{
		m_pdex.Flags |= PD_RETURNDEFAULT;
		ATLASSERT(m_pdex.hDevMode == NULL);    // must be NULL
		ATLASSERT(m_pdex.hDevNames == NULL);   // must be NULL

		return ::PrintDlgEx(&m_pdex);
	}

	// Helpers for parsing information after successful return num. copies requested
	int GetCopies() const
	{
		if((m_pdex.Flags & PD_USEDEVMODECOPIES) != 0)
		{
			LPDEVMODE lpDevMode = GetDevMode();
			return (lpDevMode != NULL) ? lpDevMode->dmCopies : -1;
		}

		return m_pdex.nCopies;
	}

	BOOL PrintCollate() const       // TRUE if collate checked
	{
		return ((m_pdex.Flags & PD_COLLATE) != 0) ? TRUE : FALSE;
	}

	BOOL PrintSelection() const     // TRUE if printing selection
	{
		return ((m_pdex.Flags & PD_SELECTION) != 0) ? TRUE : FALSE;
	}

	BOOL PrintAll() const           // TRUE if printing all pages
	{
		return (!PrintRange() && !PrintSelection()) ? TRUE : FALSE;
	}

	BOOL PrintRange() const         // TRUE if printing page range
	{
		return ((m_pdex.Flags & PD_PAGENUMS) != 0) ? TRUE : FALSE;
	}

	BOOL PrintToFile() const        // TRUE if printing to a file
	{
		return ((m_pdex.Flags & PD_PRINTTOFILE) != 0) ? TRUE : FALSE;
	}

	LPDEVMODE GetDevMode() const    // return DEVMODE
	{
		if(m_pdex.hDevMode == NULL)
			return NULL;

		return (LPDEVMODE)::GlobalLock(m_pdex.hDevMode);
	}

	LPCTSTR GetDriverName() const   // return driver name
	{
		if(m_pdex.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
	}

	LPCTSTR GetDeviceName() const   // return device name
	{
		if(m_pdex.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
	}

	LPCTSTR GetPortName() const     // return output port name
	{
		if(m_pdex.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_pdex.hDevNames);
		if(lpDev == NULL)
			return NULL;

		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
	}

	HDC GetPrinterDC() const        // return HDC (caller must delete)
	{
		ATLASSERT((m_pdex.Flags & PD_RETURNDC) != 0);
		return m_pdex.hDC;
	}

	// This helper creates a DC based on the DEVNAMES and DEVMODE structures.
	// This DC is returned, but also stored in m_pdex.hDC as though it had been
	// returned by CommDlg.  It is assumed that any previously obtained DC
	// has been/will be deleted by the user.  This may be
	// used without ever invoking the print/print setup dialogs.
	HDC CreatePrinterDC()
	{
		m_pdex.hDC = _AtlCreateDC(m_pdex.hDevNames, m_pdex.hDevMode);
		return m_pdex.hDC;
	}

// Implementation - interfaces

// IUnknown
	STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject)
	{
		if(ppvObject == NULL)
			return E_POINTER;

		T* pT = static_cast<T*>(this);
		if(IsEqualGUID(riid, IID_IUnknown) || IsEqualGUID(riid, IID_IPrintDialogCallback))
		{
			*ppvObject = (IPrintDialogCallback*)pT;
			// AddRef() not needed
			return S_OK;
		}
		else if(IsEqualGUID(riid, IID_IObjectWithSite))
		{
			*ppvObject = (IObjectWithSite*)pT;
			// AddRef() not needed
			return S_OK;
		}

		return E_NOINTERFACE;
	}

	virtual ULONG STDMETHODCALLTYPE AddRef()
	{
		return 1;
	}

	virtual ULONG STDMETHODCALLTYPE Release()
	{
		return 1;
	}

// IPrintDialogCallback
	STDMETHOD(InitDone)()
	{
		return S_FALSE;
	}

	STDMETHOD(SelectionChange)()
	{
		return S_FALSE;
	}

	STDMETHOD(HandleMessage)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult)
	{
		// set up m_hWnd the first time
		if(m_hWnd == NULL)
			Attach(hWnd);

		// call message map
		HRESULT hRet = ProcessWindowMessage(hWnd, uMsg, wParam, lParam, *plResult, 0) ? S_OK : S_FALSE;
		if(hRet == S_OK && uMsg == WM_NOTIFY)   // return in DWLP_MSGRESULT
			::SetWindowLongPtr(GetParent(), DWLP_MSGRESULT, (LONG_PTR)*plResult);

		if(uMsg == WM_INITDIALOG && hRet == S_OK && (BOOL)*plResult != FALSE)
			hRet = S_FALSE;

		return hRet;
	}
};

class CPrintDialogEx : public CPrintDialogExImpl<CPrintDialogEx>
{
public:
	CPrintDialogEx(
		DWORD dwFlags = PD_ALLPAGES | PD_USEDEVMODECOPIES | PD_NOPAGENUMS | PD_NOSELECTION | PD_NOCURRENTPAGE,
		HWND hWndParent = NULL)
		: CPrintDialogExImpl<CPrintDialogEx>(dwFlags, hWndParent)
	{ }

	DECLARE_EMPTY_MSG_MAP()
};

#endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)


///////////////////////////////////////////////////////////////////////////////
// CPageSetupDialogImpl - Page Setup dialog

#ifndef _WIN32_WCE

template <class T>
class ATL_NO_VTABLE CPageSetupDialogImpl : public CCommonDialogImplBase
{
public:
	PAGESETUPDLG m_psd;
	ATL::CWndProcThunk m_thunkPaint;

// Constructors
	CPageSetupDialogImpl(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
	{
		memset(&m_psd, 0, sizeof(m_psd));

		m_psd.lStructSize = sizeof(m_psd);
		m_psd.hwndOwner = hWndParent;
                #ifndef __BORLANDC__ //Temporary fix for page setup dialog
		m_psd.Flags = (dwFlags | PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGEPAINTHOOK);
		m_psd.lpfnPageSetupHook = (LPPAGESETUPHOOK)T::HookProc;
		m_thunkPaint.Init((WNDPROC)T::PaintHookProc, this);
#if (_ATL_VER >= 0x0700)
		m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)m_thunkPaint.GetWNDPROC();
#else
		m_psd.lpfnPagePaintHook = (LPPAGEPAINTHOOK)&(m_thunkPaint.thunk);
#endif
        	#endif
	}

	DECLARE_EMPTY_MSG_MAP()

// Attributes
	LPDEVMODE GetDevMode() const    // return DEVMODE
	{
		if(m_psd.hDevMode == NULL)
			return NULL;

		return (LPDEVMODE)::GlobalLock(m_psd.hDevMode);
	}

	LPCTSTR GetDriverName() const   // return driver name
	{
		if(m_psd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
		return (LPCTSTR)lpDev + lpDev->wDriverOffset;
	}

	LPCTSTR GetDeviceName() const   // return device name
	{
		if(m_psd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
		return (LPCTSTR)lpDev + lpDev->wDeviceOffset;
	}

	LPCTSTR GetPortName() const     // return output port name
	{
		if(m_psd.hDevNames == NULL)
			return NULL;

		LPDEVNAMES lpDev = (LPDEVNAMES)::GlobalLock(m_psd.hDevNames);
		return (LPCTSTR)lpDev + lpDev->wOutputOffset;
	}

	HDC CreatePrinterDC()
	{
		return _AtlCreateDC(m_psd.hDevNames, m_psd.hDevMode);
	}

	SIZE GetPaperSize() const
	{
		SIZE size;
		size.cx = m_psd.ptPaperSize.x;
		size.cy = m_psd.ptPaperSize.y;
		return size;
	}

	void GetMargins(LPRECT lpRectMargins, LPRECT lpRectMinMargins) const
	{
		if(lpRectMargins != NULL)
			memcpy(lpRectMargins, &m_psd.rtMargin, sizeof(RECT));
		if(lpRectMinMargins != NULL)
			memcpy(lpRectMinMargins, &m_psd.rtMinMargin, sizeof(RECT));
	}

// Operations
	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
                #ifndef __BORLANDC__
		ATLASSERT((m_psd.Flags & PSD_ENABLEPAGESETUPHOOK) != 0);
		ATLASSERT((m_psd.Flags & PSD_ENABLEPAGEPAINTHOOK) != 0);
		ATLASSERT(m_psd.lpfnPageSetupHook != NULL);   // can still be a user hook
		ATLASSERT(m_psd.lpfnPagePaintHook != NULL);   // can still be a user hook
                #endif

		if(m_psd.hwndOwner == NULL)   // set only if not specified before
			m_psd.hwndOwner = hWndParent;

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)

		BOOL bRet = ::PageSetupDlg(&m_psd);

		m_hWnd = NULL;

		return bRet ? IDOK : IDCANCEL;
	}

// Implementation
	static UINT_PTR CALLBACK PaintHookProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		T* pT = (T*)hWnd;
		UINT_PTR uRet = 0;
		switch(uMsg)
		{
		case WM_PSD_PAGESETUPDLG:
			uRet = pT->PreDrawPage(LOWORD(wParam), HIWORD(wParam), (LPPAGESETUPDLG)lParam);
			break;
		case WM_PSD_FULLPAGERECT:
		case WM_PSD_MINMARGINRECT:
		case WM_PSD_MARGINRECT:
		case WM_PSD_GREEKTEXTRECT:
		case WM_PSD_ENVSTAMPRECT:
		case WM_PSD_YAFULLPAGERECT:
			uRet = pT->OnDrawPage(uMsg, (HDC)wParam, (LPRECT)lParam);
			break;
		default:
			ATLTRACE2(atlTraceUI, 0, _T("CPageSetupDialogImpl::PaintHookProc - unknown message received\n"));
			break;
		}
		return uRet;
	}

// Overridables
	UINT_PTR PreDrawPage(WORD /*wPaper*/, WORD /*wFlags*/, LPPAGESETUPDLG /*pPSD*/)
	{
		// return 1 to prevent any more drawing
		return 0;
	}

	UINT_PTR OnDrawPage(UINT /*uMsg*/, HDC /*hDC*/, LPRECT /*lpRect*/)
	{
		return 0; // do the default
	}
};

class CPageSetupDialog : public CPageSetupDialogImpl<CPageSetupDialog>
{
public:
	CPageSetupDialog(DWORD dwFlags = PSD_MARGINS | PSD_INWININIINTLMEASURE, HWND hWndParent = NULL)
		: CPageSetupDialogImpl<CPageSetupDialog>(dwFlags, hWndParent)
	{ }

	// override PaintHookProc and references to handlers
	static UINT_PTR CALLBACK PaintHookProc(HWND, UINT, WPARAM, LPARAM)
	{
		return 0;
	}
};

#endif // _WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CFindReplaceDialogImpl - Find/FindReplace modeless dialogs

#ifndef _WIN32_WCE

template <class T>
class ATL_NO_VTABLE CFindReplaceDialogImpl : public CCommonDialogImplBase
{
public:
	enum { _cchFindReplaceBuffer = 128 };

	FINDREPLACE m_fr;
	TCHAR m_szFindWhat[_cchFindReplaceBuffer];
	TCHAR m_szReplaceWith[_cchFindReplaceBuffer];

// Constructors
	CFindReplaceDialogImpl()
	{
		memset(&m_fr, 0, sizeof(m_fr));
		m_szFindWhat[0] = _T('\0');
		m_szReplaceWith[0] = _T('\0');

		m_fr.lStructSize = sizeof(m_fr);
		m_fr.Flags = FR_ENABLEHOOK;
		m_fr.lpfnHook = (LPFRHOOKPROC)T::HookProc;
		m_fr.lpstrFindWhat = (LPTSTR)m_szFindWhat;
		m_fr.wFindWhatLen = _cchFindReplaceBuffer;
		m_fr.lpstrReplaceWith = (LPTSTR)m_szReplaceWith;
		m_fr.wReplaceWithLen = _cchFindReplaceBuffer;
	}

	// Note: You must allocate the object on the heap.
	//       If you do not, you must override OnFinalMessage()
	virtual void OnFinalMessage(HWND /*hWnd*/)
	{
		delete this;
	}

	HWND Create(BOOL bFindDialogOnly, // TRUE for Find, FALSE for FindReplace
			LPCTSTR lpszFindWhat,
			LPCTSTR lpszReplaceWith = NULL,
			DWORD dwFlags = FR_DOWN,
			HWND hWndParent = NULL)
	{
		ATLASSERT((m_fr.Flags & FR_ENABLEHOOK) != 0);
		ATLASSERT(m_fr.lpfnHook != NULL);

		m_fr.Flags |= dwFlags;

		if(hWndParent == NULL)
			m_fr.hwndOwner = ::GetActiveWindow();
		else
			m_fr.hwndOwner = hWndParent;
		ATLASSERT(m_fr.hwndOwner != NULL); // must have an owner for modeless dialog

		if(lpszFindWhat != NULL)
			lstrcpyn(m_szFindWhat, lpszFindWhat, _cchFindReplaceBuffer);

		if(lpszReplaceWith != NULL)
			lstrcpyn(m_szReplaceWith, lpszReplaceWith, _cchFindReplaceBuffer);

		ATLASSERT(m_hWnd == NULL);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&m_thunk.cd, (CCommonDialogImplBase*)this);
#endif // !(_ATL_VER >= 0x0700)
		HWND hWnd;

		if(bFindDialogOnly)
			hWnd = ::FindText(&m_fr);
		else
			hWnd = ::ReplaceText(&m_fr);

		ATLASSERT(m_hWnd == hWnd);
		return hWnd;
	}

	static const UINT GetFindReplaceMsg()
	{
		static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
		return nMsgFindReplace;
	}
	// call while handling FINDMSGSTRING registered message
	// to retreive the object
	static T* PASCAL GetNotifier(LPARAM lParam)
	{
		ATLASSERT(lParam != NULL);
		T* pDlg = (T*)(lParam - offsetof(T, m_fr));
		return pDlg;
	}

// Operations
	// Helpers for parsing information after successful return
	LPCTSTR GetFindString() const    // get find string
	{
		return (LPCTSTR)m_fr.lpstrFindWhat;
	}

	LPCTSTR GetReplaceString() const // get replacement string
	{
		return (LPCTSTR)m_fr.lpstrReplaceWith;
	}

	BOOL SearchDown() const          // TRUE if search down, FALSE is up
	{
		return ((m_fr.Flags & FR_DOWN) != 0) ? TRUE : FALSE;
	}

	BOOL FindNext() const            // TRUE if command is find next
	{
		return ((m_fr.Flags & FR_FINDNEXT) != 0) ? TRUE : FALSE;
	}

	BOOL MatchCase() const           // TRUE if matching case
	{
		return ((m_fr.Flags & FR_MATCHCASE) != 0) ? TRUE : FALSE;
	}

	BOOL MatchWholeWord() const      // TRUE if matching whole words only
	{
		return ((m_fr.Flags & FR_WHOLEWORD) != 0) ? TRUE : FALSE;
	}

	BOOL ReplaceCurrent() const      // TRUE if replacing current string
	{
		return ((m_fr. Flags & FR_REPLACE) != 0) ? TRUE : FALSE;
	}

	BOOL ReplaceAll() const          // TRUE if replacing all occurrences
	{
		return ((m_fr.Flags & FR_REPLACEALL) != 0) ? TRUE : FALSE;
	}

	BOOL IsTerminating() const       // TRUE if terminating dialog
	{
		return ((m_fr.Flags & FR_DIALOGTERM) != 0) ? TRUE : FALSE ;
	}
};

class CFindReplaceDialog : public CFindReplaceDialogImpl<CFindReplaceDialog>
{
public:
	DECLARE_EMPTY_MSG_MAP()
};

#endif // !_WIN32_WCE


///////////////////////////////////////////////////////////////////////////////
// CPropertySheetWindow - client side for a property sheet

class CPropertySheetWindow : public ATL::CWindow
{
public:
// Constructors
	CPropertySheetWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
	{ }

	CPropertySheetWindow& operator =(HWND hWnd)
	{
		m_hWnd = hWnd;
		return *this;
	}

// Attributes
	int GetPageCount() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		HWND hWndTabCtrl = GetTabControl();
		ATLASSERT(hWndTabCtrl != NULL);
		return (int)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L);
	}

	HWND GetActivePage() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L);
	}

	int GetActiveIndex() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		HWND hWndTabCtrl = GetTabControl();
		ATLASSERT(hWndTabCtrl != NULL);
		return (int)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L);
	}

	BOOL SetActivePage(int nPageIndex)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, nPageIndex, 0L);
	}

	BOOL SetActivePage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(hPage != NULL);
		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSEL, 0, (LPARAM)hPage);
	}

	BOOL SetActivePageByID(int nPageID)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_SETCURSELID, 0, nPageID);
	}

	void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
		ATLASSERT(lpszText != NULL);
		::SendMessage(m_hWnd, PSM_SETTITLE, nStyle, (LPARAM)lpszText);
	}

	HWND GetTabControl() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L);
	}

	void SetFinishText(LPCTSTR lpszText)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText);
	}

	void SetWizardButtons(DWORD dwFlags)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags);
	}

// Operations
	BOOL AddPage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(hPage != NULL);
		return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
	}

	BOOL AddPage(LPCPROPSHEETPAGE pPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(pPage != NULL);
		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
		if(hPage == NULL)
			return FALSE;
		return (BOOL)::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage);
	}

#ifndef _WIN32_WCE
	BOOL InsertPage(int nNewPageIndex, HPROPSHEETPAGE hPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(hPage != NULL);
		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
	}

	BOOL InsertPage(int nNewPageIndex, LPCPROPSHEETPAGE pPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(pPage != NULL);
		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
		if(hPage == NULL)
			return FALSE;
		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, nNewPageIndex, (LPARAM)hPage);
	}

	BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, HPROPSHEETPAGE hPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(hPage != NULL);
		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
	}

	BOOL InsertPage(HPROPSHEETPAGE hPageInsertAfter, LPCPROPSHEETPAGE pPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(pPage != NULL);
		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
		if(hPage == NULL)
			return FALSE;
		return (BOOL)::SendMessage(m_hWnd, PSM_INSERTPAGE, (WPARAM)hPageInsertAfter, (LPARAM)hPage);
	}
#endif // !_WIN32_WCE

	void RemovePage(int nPageIndex)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_REMOVEPAGE, nPageIndex, 0L);
	}

	void RemovePage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(hPage != NULL);
		::SendMessage(m_hWnd, PSM_REMOVEPAGE, 0, (LPARAM)hPage);
	}

	BOOL PressButton(int nButton)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L);
	}

	BOOL Apply()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_APPLY, 0, 0L);
	}

	void CancelToClose()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_CANCELTOCLOSE, 0, 0L);
	}

	void SetModified(HWND hWndPage, BOOL bChanged = TRUE)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(::IsWindow(hWndPage));
		UINT uMsg = bChanged ? PSM_CHANGED : PSM_UNCHANGED;
		::SendMessage(m_hWnd, uMsg, (WPARAM)hWndPage, 0L);
	}

	LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return ::SendMessage(m_hWnd, PSM_QUERYSIBLINGS, wParam, lParam);
	}

	void RebootSystem()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_REBOOTSYSTEM, 0, 0L);
	}

	void RestartWindows()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_RESTARTWINDOWS, 0, 0L);
	}

	BOOL IsDialogMessage(LPMSG lpMsg)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_ISDIALOGMESSAGE, 0, (LPARAM)lpMsg);
	}

#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
	int HwndToIndex(HWND hWnd) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, PSM_HWNDTOINDEX, (WPARAM)hWnd, 0L);
	}

	HWND IndexToHwnd(int nIndex) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HWND)::SendMessage(m_hWnd, PSM_INDEXTOHWND, nIndex, 0L);
	}

	int PageToIndex(HPROPSHEETPAGE hPage) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, PSM_PAGETOINDEX, 0, (LPARAM)hPage);
	}

	HPROPSHEETPAGE IndexToPage(int nIndex) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HPROPSHEETPAGE)::SendMessage(m_hWnd, PSM_INDEXTOPAGE, nIndex, 0L);
	}

	int IdToIndex(int nID) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, PSM_IDTOINDEX, 0, nID);
	}

	int IndexToId(int nIndex) const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, PSM_INDEXTOID, nIndex, 0L);
	}

	int GetResult() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (int)::SendMessage(m_hWnd, PSM_GETRESULT, 0, 0L);
	}

	BOOL RecalcPageSizes()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (BOOL)::SendMessage(m_hWnd, PSM_RECALCPAGESIZES, 0, 0L);
	}

	void SetHeaderTitle(int nIndex, LPCTSTR lpstrHeaderTitle)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_SETHEADERTITLE, nIndex, (LPARAM)lpstrHeaderTitle);
	}

	void SetHeaderSubTitle(int nIndex, LPCTSTR lpstrHeaderSubTitle)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		::SendMessage(m_hWnd, PSM_SETHEADERSUBTITLE, nIndex, (LPARAM)lpstrHeaderSubTitle);
	}
#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)

// Implementation - override to prevent usage
	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
	{
		ATLASSERT(FALSE);
		return NULL;
	}
};

///////////////////////////////////////////////////////////////////////////////
// CPropertySheetImpl - implements a property sheet

template <class T, class TBase = CPropertySheetWindow>
class ATL_NO_VTABLE CPropertySheetImpl : public ATL::CWindowImplBaseT< TBase >
{
public:
	PROPSHEETHEADER m_psh;
	ATL::CSimpleArray<HPROPSHEETPAGE> m_arrPages;

#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
  #ifndef PROPSHEET_LINK_SIZE
	#define PROPSHEET_LINK_SIZE 128
  #endif // PROPSHEET_LINK_SIZE
	TCHAR m_szLink[PROPSHEET_LINK_SIZE];
	static LPCTSTR m_pszTitle;
	static LPCTSTR m_pszLink;
#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 

// Construction/Destruction
	CPropertySheetImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
	{
		memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
		m_psh.dwSize = sizeof(PROPSHEETHEADER);
		m_psh.dwFlags = PSH_USECALLBACK;
#if (_ATL_VER >= 0x0700)
		m_psh.hInstance = ATL::_AtlBaseModule.GetResourceInstance();
#else // !(_ATL_VER >= 0x0700)
		m_psh.hInstance = _Module.GetResourceInstance();
#endif // !(_ATL_VER >= 0x0700)
		m_psh.phpage = NULL;   // will be set later
		m_psh.nPages = 0;      // will be set later
		m_psh.pszCaption = title.m_lpstr;
		m_psh.nStartPage = uStartPage;
		m_psh.hwndParent = hWndParent;   // if NULL, will be set in DoModal/Create
		m_psh.pfnCallback = T::PropSheetCallback;

#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific 
		m_psh.dwFlags |= PSH_MAXIMIZE;
		m_szLink[0] = 0;
#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)
	}

	~CPropertySheetImpl()
	{
		if(m_arrPages.GetSize() > 0)   // sheet never created, destroy all pages
		{
			for(int i = 0; i < m_arrPages.GetSize(); i++)
				::DestroyPropertySheetPage((HPROPSHEETPAGE)m_arrPages[i]);
		}
	}

// Callback function and overrideables
	static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM lParam)
	{
		lParam;   // avoid level 4 warning
		int nRet = 0;

		if(uMsg == PSCB_INITIALIZED)
		{
			ATLASSERT(hWnd != NULL);
#if (_ATL_VER >= 0x0700)
			T* pT = (T*)ATL::_AtlWinModule.ExtractCreateWndData();
#else // !(_ATL_VER >= 0x0700)
			T* pT = (T*)_Module.ExtractCreateWndData();
#endif // !(_ATL_VER >= 0x0700)
			// subclass the sheet window
			pT->SubclassWindow(hWnd);
			// remove page handles array
			pT->_CleanUpPages();

#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific
			m_pszTitle = pT->m_psh.pszCaption;
			if(*pT->m_szLink != 0)
				m_pszLink = pT->m_szLink;
#endif  // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific

			pT->OnSheetInitialized();
		}
#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific uMsg
		else
		{
			switch(uMsg)
			{
			case PSCB_GETVERSION :
				nRet = COMCTL32_VERSION;
				break;
			case PSCB_GETTITLE :
				if(m_pszTitle != NULL)
				{
					lstrcpy((LPTSTR)lParam, m_pszTitle);
					m_pszTitle = NULL;
				}
				break;
			case PSCB_GETLINKTEXT:
				if(m_pszLink != NULL)
				{
					lstrcpy((LPTSTR)lParam, m_pszLink);
					m_pszLink = NULL;
				}
				break;
			default:
				break;
			}
		}
#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 

		return nRet;
	}

	void OnSheetInitialized()
	{
	}

// Create method
	HWND Create(HWND hWndParent = NULL)
	{
		ATLASSERT(m_hWnd == NULL);

		m_psh.dwFlags |= PSH_MODELESS;
		if(m_psh.hwndParent == NULL)
			m_psh.hwndParent = hWndParent;
		m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
		m_psh.nPages = m_arrPages.GetSize();

		T* pT = static_cast<T*>(this);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&pT->m_thunk.cd, pT);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&pT->m_thunk.cd, pT);
#endif // !(_ATL_VER >= 0x0700)

		HWND hWnd = (HWND)::PropertySheet(&m_psh);
		_CleanUpPages();   // ensure clean-up, required if call failed

		ATLASSERT(m_hWnd == hWnd);

		return hWnd;
	}

	INT_PTR DoModal(HWND hWndParent = ::GetActiveWindow())
	{
		ATLASSERT(m_hWnd == NULL);

		m_psh.dwFlags &= ~PSH_MODELESS;
		if(m_psh.hwndParent == NULL)
			m_psh.hwndParent = hWndParent;
		m_psh.phpage = (HPROPSHEETPAGE*)m_arrPages.GetData();
		m_psh.nPages = m_arrPages.GetSize();

		T* pT = static_cast<T*>(this);
#if (_ATL_VER >= 0x0700)
		ATL::_AtlWinModule.AddCreateWndData(&pT->m_thunk.cd, pT);
#else // !(_ATL_VER >= 0x0700)
		_Module.AddCreateWndData(&pT->m_thunk.cd, pT);
#endif // !(_ATL_VER >= 0x0700)

		INT_PTR nRet = ::PropertySheet(&m_psh);
		_CleanUpPages();   // ensure clean-up, required if call failed

		return nRet;
	}

	// implementation helper - clean up pages array
	void _CleanUpPages()
	{
		m_psh.nPages = 0;
		m_psh.phpage = NULL;
		m_arrPages.RemoveAll();
	}

// Attributes (extended overrides of client class methods)
// These now can be called before the sheet is created
// Note: Calling these after the sheet is created gives unpredictable results
	int GetPageCount() const
	{
		if(m_hWnd == NULL)   // not created yet
			return m_arrPages.GetSize();
		return TBase::GetPageCount();
	}

	int GetActiveIndex() const
	{
		if(m_hWnd == NULL)   // not created yet
			return m_psh.nStartPage;
		return TBase::GetActiveIndex();
	}

	HPROPSHEETPAGE GetPage(int nPageIndex) const
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
		return (HPROPSHEETPAGE)m_arrPages[nPageIndex];
	}

	int GetPageIndex(HPROPSHEETPAGE hPage) const
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
		return m_arrPages.Find((HPROPSHEETPAGE&)hPage);
	}

	BOOL SetActivePage(int nPageIndex)
	{
		if(m_hWnd == NULL)   // not created yet
		{
			ATLASSERT(nPageIndex >= 0 && nPageIndex < m_arrPages.GetSize());
			m_psh.nStartPage = nPageIndex;
			return TRUE;
		}
		return TBase::SetActivePage(nPageIndex);
	}

	BOOL SetActivePage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(hPage != NULL);
		if (m_hWnd == NULL)   // not created yet
		{
			int nPageIndex = GetPageIndex(hPage);
			if(nPageIndex == -1)
				return FALSE;

			return SetActivePage(nPageIndex);
		}
		return TBase::SetActivePage(hPage);

	}

	void SetTitle(LPCTSTR lpszText, UINT nStyle = 0)
	{
		ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0);   // only PSH_PROPTITLE is valid
		ATLASSERT(lpszText != NULL);

		if(m_hWnd == NULL)
		{
			// set internal state
			m_psh.pszCaption = lpszText;   // must exist until sheet is created
			m_psh.dwFlags &= ~PSH_PROPTITLE;
			m_psh.dwFlags |= nStyle;
		}
		else
		{
			// set external state
			TBase::SetTitle(lpszText, nStyle);
		}
	}

#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC specific Link field	
	void SetLinkText(LPCTSTR lpszText)
	{
		ATLASSERT(lpszText != NULL);
		ATLASSERT(lstrlen(lpszText) < PROPSHEET_LINK_SIZE);
		lstrcpy(m_szLink, lpszText);
	}
#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) 

	void SetWizardMode()
	{
		m_psh.dwFlags |= PSH_WIZARD;
	}

	void EnableHelp()
	{
		m_psh.dwFlags |= PSH_HASHELP;
	}

// Operations
	BOOL AddPage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(hPage != NULL);
		BOOL bRet = FALSE;
		if(m_hWnd != NULL)
			bRet = TBase::AddPage(hPage);
		else	// sheet not created yet, use internal data
			bRet = m_arrPages.Add((HPROPSHEETPAGE&)hPage);
		return bRet;
	}

	BOOL AddPage(LPCPROPSHEETPAGE pPage)
	{
		ATLASSERT(pPage != NULL);
		HPROPSHEETPAGE hPage = ::CreatePropertySheetPage(pPage);
		if(hPage == NULL)
			return FALSE;
		BOOL bRet = AddPage(hPage);
		if(!bRet)
			::DestroyPropertySheetPage(hPage);
		return bRet;
	}

	BOOL RemovePage(HPROPSHEETPAGE hPage)
	{
		ATLASSERT(hPage != NULL);
		if (m_hWnd == NULL)   // not created yet
		{
			int nPage = GetPageIndex(hPage);
			if(nPage == -1)
				return FALSE;
			return RemovePage(nPage);
		}
		TBase::RemovePage(hPage);
		return TRUE;

	}

	BOOL RemovePage(int nPageIndex)
	{
		BOOL bRet = TRUE;
		if(m_hWnd != NULL)
			TBase::RemovePage(nPageIndex);
		else	// sheet not created yet, use internal data
			bRet = m_arrPages.RemoveAt(nPageIndex);
		return bRet;
	}

#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
	void SetHeader(LPCTSTR szbmHeader)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created

		m_psh.dwFlags &= ~PSH_WIZARD;
		m_psh.dwFlags |= (PSH_HEADER | PSH_WIZARD97);
		m_psh.pszbmHeader = szbmHeader;
	}

	void SetHeader(HBITMAP hbmHeader)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created

		m_psh.dwFlags &= ~PSH_WIZARD;
		m_psh.dwFlags |= (PSH_HEADER | PSH_USEHBMHEADER | PSH_WIZARD97);
		m_psh.hbmHeader = hbmHeader;
	}

	void SetWatermark(LPCTSTR szbmWatermark, HPALETTE hplWatermark = NULL)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created

		m_psh.dwFlags &= ~PSH_WIZARD;
		m_psh.dwFlags |= PSH_WATERMARK | PSH_WIZARD97;
		m_psh.pszbmWatermark = szbmWatermark;

		if (hplWatermark != NULL)
		{
			m_psh.dwFlags |= PSH_USEHPLWATERMARK;
			m_psh.hplWatermark = hplWatermark;
		}
	}

	void SetWatermark(HBITMAP hbmWatermark, HPALETTE hplWatermark = NULL)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created

		m_psh.dwFlags &= ~PSH_WIZARD;
		m_psh.dwFlags |= (PSH_WATERMARK | PSH_USEHBMWATERMARK | PSH_WIZARD97);
		m_psh.hbmWatermark = hbmWatermark;

		if (hplWatermark != NULL)
		{
			m_psh.dwFlags |= PSH_USEHPLWATERMARK;
			m_psh.hplWatermark = hplWatermark;
		}
	}

	void StretchWatermark(bool bStretchWatermark)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
		if (bStretchWatermark)
			m_psh.dwFlags |= PSH_STRETCHWATERMARK;
		else
			m_psh.dwFlags &= ~PSH_STRETCHWATERMARK;
	}
#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)

// Message map and handlers
	BEGIN_MSG_MAP(CPropertySheetImpl)
		MESSAGE_HANDLER(WM_COMMAND, OnCommand)
		MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand)
	END_MSG_MAP()

	LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
		if(HIWORD(wParam) == BN_CLICKED && (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) &&
		   ((m_psh.dwFlags & PSH_MODELESS) != 0) && (GetActivePage() == NULL))
			DestroyWindow();
		return lRet;
	}

	LRESULT OnSysCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(((m_psh.dwFlags & PSH_MODELESS) == PSH_MODELESS) && ((wParam & 0xFFF0) == SC_CLOSE))
			SendMessage(WM_CLOSE);
		else
			bHandled = FALSE;
		return 0;
	}
};

#if defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__) // PPC static pointers
template < class T, class TBase >
LPCWSTR CPropertySheetImpl<T,TBase>::m_pszTitle = NULL;
template < class T, class TBase>
LPCWSTR CPropertySheetImpl<T,TBase>::m_pszLink = NULL;
#endif // defined(_AYGSHELL_H_) || defined(__AYGSHELL_H__)

// for non-customized sheets
class CPropertySheet : public CPropertySheetImpl<CPropertySheet>
{
public:
	CPropertySheet(ATL::_U_STRINGorID title = (LPCTSTR)NULL, UINT uStartPage = 0, HWND hWndParent = NULL)
		: CPropertySheetImpl<CPropertySheet>(title, uStartPage, hWndParent)
	{ }

	BEGIN_MSG_MAP(CPropertySheet)
		MESSAGE_HANDLER(WM_COMMAND, CPropertySheetImpl<CPropertySheet>::OnCommand)
	END_MSG_MAP()
};


///////////////////////////////////////////////////////////////////////////////
// CPropertyPageWindow - client side for a property page

class CPropertyPageWindow : public ATL::CWindow
{
public:
// Constructors
	CPropertyPageWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd)
	{ }

	CPropertyPageWindow& operator =(HWND hWnd)
	{
		m_hWnd = hWnd;
		return *this;
	}

// Attributes
	CPropertySheetWindow GetPropertySheet() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return CPropertySheetWindow(GetParent());
	}

// Operations
	BOOL Apply()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		return GetPropertySheet().Apply();
	}

	void CancelToClose()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		GetPropertySheet().CancelToClose();
	}

	void SetModified(BOOL bChanged = TRUE)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		GetPropertySheet().SetModified(m_hWnd, bChanged);
	}

	LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		return GetPropertySheet().QuerySiblings(wParam, lParam);
	}

	void RebootSystem()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		GetPropertySheet().RebootSystem();
	}

	void RestartWindows()
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		GetPropertySheet().RestartWindows();
	}

	void SetWizardButtons(DWORD dwFlags)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		ATLASSERT(GetParent() != NULL);
		GetPropertySheet().SetWizardButtons(dwFlags);
	}

// Implementation - overrides to prevent usage
	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
	{
		ATLASSERT(FALSE);
		return NULL;
	}
};

///////////////////////////////////////////////////////////////////////////////
// CPropertyPageImpl - implements a property page

template <class T, class TBase = CPropertyPageWindow>
class ATL_NO_VTABLE CPropertyPageImpl : public ATL::CDialogImplBaseT< TBase >
{
public:
	PROPSHEETPAGE m_psp;

	operator PROPSHEETPAGE*() { return &m_psp; }

// Construction
	CPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL)
	{
		// initialize PROPSHEETPAGE struct
		memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
		m_psp.dwSize = sizeof(PROPSHEETPAGE);
		m_psp.dwFlags = PSP_USECALLBACK;
#if (_ATL_VER >= 0x0700)
		m_psp.hInstance = ATL::_AtlBaseModule.GetResourceInstance();
#else // !(_ATL_VER >= 0x0700)
		m_psp.hInstance = _Module.GetResourceInstance();
#endif // !(_ATL_VER >= 0x0700)
		T* pT = static_cast<T*>(this);
		m_psp.pszTemplate = MAKEINTRESOURCE(pT->IDD);
		m_psp.pfnDlgProc = (DLGPROC)T::StartDialogProc;
		m_psp.pfnCallback = T::PropPageCallback;
		m_psp.lParam = (LPARAM)pT;

		if(title.m_lpstr != NULL)
			SetTitle(title);
	}

// Callback function and overrideables
	static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
	{
		hWnd;   // avoid level 4 warning
		ATLASSERT(hWnd == NULL);
		T* pT = (T*)ppsp->lParam;
		UINT uRet = 0;

		switch(uMsg)
		{
		case PSPCB_CREATE:
			{
				ATL::CDialogImplBaseT< TBase >* pPage = (ATL::CDialogImplBaseT< TBase >*)pT;
#if (_ATL_VER >= 0x0700)
				ATL::_AtlWinModule.AddCreateWndData(&pPage->m_thunk.cd, pPage);
#else // !(_ATL_VER >= 0x0700)
				_Module.AddCreateWndData(&pPage->m_thunk.cd, pPage);
#endif // !(_ATL_VER >= 0x0700)
				uRet = pT->OnPageCreate() ? 1 : 0;
			}
			break;
#if (_WIN32_IE >= 0x0500)
		case PSPCB_ADDREF:
			pT->OnPageAddRef();
			break;
#endif // (_WIN32_IE >= 0x0500)
		case PSPCB_RELEASE:
			pT->OnPageRelease();
			break;
		default:
			break;
		}

		return uRet;
	}

	bool OnPageCreate()
	{
		return true;   // true - allow page to be created, false - prevent creation
	}

#if (_WIN32_IE >= 0x0500)
	void OnPageAddRef()
	{
	}
#endif // (_WIN32_IE >= 0x0500)

	void OnPageRelease()
	{
	}

// Create method
	HPROPSHEETPAGE Create()
	{
		return ::CreatePropertySheetPage(&m_psp);
	}

// Attributes
	void SetTitle(ATL::_U_STRINGorID title)
	{
		m_psp.pszTitle = title.m_lpstr;
		m_psp.dwFlags |= PSP_USETITLE;
	}

#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)
	void SetHeaderTitle(LPCTSTR lpstrHeaderTitle)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
		m_psp.dwFlags |= PSP_USEHEADERTITLE;
		m_psp.pszHeaderTitle = lpstrHeaderTitle;
	}

	void SetHeaderSubTitle(LPCTSTR lpstrHeaderSubTitle)
	{
		ATLASSERT(m_hWnd == NULL);   // can't do this after it's created
		m_psp.dwFlags |= PSP_USEHEADERSUBTITLE;
		m_psp.pszHeaderSubTitle = lpstrHeaderSubTitle;
	}
#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)

// Operations
	void EnableHelp()
	{
		m_psp.dwFlags |= PSP_HASHELP;
	}

// Message map and handlers
	BEGIN_MSG_MAP(CPropertyPageImpl)
		MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
	END_MSG_MAP()

	// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
	// handlers that return direct values without any restrictions
	LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		NMHDR* pNMHDR = (NMHDR*)lParam;

		// don't handle messages not from the page/sheet itself
		if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
		{
			bHandled = FALSE;
			return 1;
		}

		T* pT = static_cast<T*>(this);
		LRESULT lResult = 0;
		switch(pNMHDR->code)
		{
#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
		case PSN_SETACTIVE:
			lResult = pT->OnSetActive();
			break;
		case PSN_KILLACTIVE:
			lResult = pT->OnKillActive();
			break;
		case PSN_APPLY:
			lResult = pT->OnApply();
			break;
		case PSN_RESET:
			pT->OnReset();
			break;
		case PSN_QUERYCANCEL:
			lResult = pT->OnQueryCancel();
			break;
		case PSN_WIZNEXT:
			lResult = pT->OnWizardNext();
			break;
		case PSN_WIZBACK:
			lResult = pT->OnWizardBack();
			break;
		case PSN_WIZFINISH:
			lResult = pT->OnWizardFinish();
			break;
		case PSN_HELP:
			pT->OnHelp();
			break;
#ifndef _WIN32_WCE
#if (_WIN32_IE >= 0x0400)
		case PSN_GETOBJECT:
			if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
				bHandled = FALSE;
			break;
#endif // (_WIN32_IE >= 0x0400)
#if (_WIN32_IE >= 0x0500)
		case PSN_TRANSLATEACCELERATOR:
			{
				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
				lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam);
			}
			break;
		case PSN_QUERYINITIALFOCUS:
			{
				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
				lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
			}
			break;
#endif // (_WIN32_IE >= 0x0500)
#endif // !_WIN32_WCE

#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
		case PSN_SETACTIVE:
			lResult = pT->OnSetActive() ? 0 : -1;
			break;
		case PSN_KILLACTIVE:
			lResult = !pT->OnKillActive();
			break;
		case PSN_APPLY:
			lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
			break;
		case PSN_RESET:
			pT->OnReset();
			break;
		case PSN_QUERYCANCEL:
			lResult = !pT->OnQueryCancel();
			break;
		case PSN_WIZNEXT:
			lResult = pT->OnWizardNext();
			break;
		case PSN_WIZBACK:
			lResult = pT->OnWizardBack();
			break;
		case PSN_WIZFINISH:
			lResult = !pT->OnWizardFinish();
			break;
		case PSN_HELP:
			pT->OnHelp();
			break;
#ifndef _WIN32_WCE
#if (_WIN32_IE >= 0x0400)
		case PSN_GETOBJECT:
			if(!pT->OnGetObject((LPNMOBJECTNOTIFY)lParam))
				bHandled = FALSE;
			break;
#endif // (_WIN32_IE >= 0x0400)
#if (_WIN32_IE >= 0x0500)
		case PSN_TRANSLATEACCELERATOR:
			{
				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
				lResult = pT->OnTranslateAccelerator((LPMSG)lpPSHNotify->lParam) ? PSNRET_MESSAGEHANDLED : PSNRET_NOERROR;
			}
			break;
		case PSN_QUERYINITIALFOCUS:
			{
				LPPSHNOTIFY lpPSHNotify = (LPPSHNOTIFY)lParam;
				lResult = (LRESULT)pT->OnQueryInitialFocus((HWND)lpPSHNotify->lParam);
			}
			break;
#endif // (_WIN32_IE >= 0x0500)
#endif // !_WIN32_WCE

#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
		default:
			bHandled = FALSE;   // not handled
		}

		return lResult;
	}

// Overridables
	// NOTE: Define _WTL_NEW_PAGE_NOTIFY_HANDLERS to use new notification
	// handlers that return direct values without any restrictions
#ifdef _WTL_NEW_PAGE_NOTIFY_HANDLERS
	int OnSetActive()
	{
		// 0 = allow activate
		// -1 = go back that was active
		// page ID = jump to page
		return 0;
	}

	BOOL OnKillActive()
	{
		// FALSE = allow deactivate
		// TRUE = prevent deactivation
		return FALSE;
	}

	int OnApply()
	{
		// PSNRET_NOERROR = apply OK
		// PSNRET_INVALID = apply not OK, return to this page
		// PSNRET_INVALID_NOCHANGEPAGE = apply not OK, don't change focus
		return PSNRET_NOERROR;
	}

	void OnReset()
	{
	}

	BOOL OnQueryCancel()
	{
		// FALSE = allow cancel
		// TRUE = prevent cancel
		return FALSE;
	}

	int OnWizardBack()
	{
		// 0  = goto previous page
		// -1 = prevent page change
		// >0 = jump to page by dlg ID
		return 0;
	}

	int OnWizardNext()
	{
		// 0  = goto next page
		// -1 = prevent page change
		// >0 = jump to page by dlg ID
		return 0;
	}

	INT_PTR OnWizardFinish()
	{
		// FALSE = allow finish
		// TRUE = prevent finish
		// HWND = prevent finish and set focus to HWND (CommCtrl 5.80 only)
		return FALSE;
	}

	void OnHelp()
	{
	}

#ifndef _WIN32_WCE
#if (_WIN32_IE >= 0x0400)
	BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
	{
		return FALSE;   // not processed
	}
#endif // (_WIN32_IE >= 0x0400)

#if (_WIN32_IE >= 0x0500)
	int OnTranslateAccelerator(LPMSG /*lpMsg*/)
	{
		// PSNRET_NOERROR - message not handled
		// PSNRET_MESSAGEHANDLED - message handled
		return PSNRET_NOERROR;
	}

	HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
	{
		// NULL = set focus to default control
		// HWND = set focus to HWND
		return NULL;
	}
#endif // (_WIN32_IE >= 0x0500)
#endif // !_WIN32_WCE

#else // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
	BOOL OnSetActive()
	{
		return TRUE;
	}

	BOOL OnKillActive()
	{
		return TRUE;
	}

	BOOL OnApply()
	{
		return TRUE;
	}

	void OnReset()
	{
	}

	BOOL OnQueryCancel()
	{
		return TRUE;    // ok to cancel
	}

	int OnWizardBack()
	{
		// 0  = goto previous page
		// -1 = prevent page change
		// >0 = jump to page by dlg ID
		return 0;
	}

	int OnWizardNext()
	{
		// 0  = goto next page
		// -1 = prevent page change
		// >0 = jump to page by dlg ID
		return 0;
	}

	BOOL OnWizardFinish()
	{
		return TRUE;
	}

	void OnHelp()
	{
	}

#ifndef _WIN32_WCE
#if (_WIN32_IE >= 0x0400)
	BOOL OnGetObject(LPNMOBJECTNOTIFY /*lpObjectNotify*/)
	{
		return FALSE;   // not processed
	}
#endif // (_WIN32_IE >= 0x0400)

#if (_WIN32_IE >= 0x0500)
	BOOL OnTranslateAccelerator(LPMSG /*lpMsg*/)
	{
		return FALSE;   // not translated
	}

	HWND OnQueryInitialFocus(HWND /*hWndFocus*/)
	{
		return NULL;   // default
	}
#endif // (_WIN32_IE >= 0x0500)
#endif // !_WIN32_WCE

#endif // !_WTL_NEW_PAGE_NOTIFY_HANDLERS
};

// for non-customized pages
template <WORD t_wDlgTemplateID>
class CPropertyPage : public CPropertyPageImpl<CPropertyPage<t_wDlgTemplateID> >
{
public:
	enum { IDD = t_wDlgTemplateID };

	CPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CPropertyPageImpl<CPropertyPage>(title)
	{ }

	DECLARE_EMPTY_MSG_MAP()
};

///////////////////////////////////////////////////////////////////////////////
// CAxPropertyPageImpl - property page that hosts ActiveX controls

#ifndef _ATL_NO_HOSTING

// Note: You must #include <atlhost.h> to use these classes

template <class T, class TBase = CPropertyPageWindow>
class ATL_NO_VTABLE CAxPropertyPageImpl : public CPropertyPageImpl< T, TBase >
{
public:
// Data members
	HGLOBAL m_hInitData;
	HGLOBAL m_hDlgRes;
	HGLOBAL m_hDlgResSplit;

// Constructor/destructor
	CAxPropertyPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : 
			CPropertyPageImpl< T, TBase >(title),
			m_hInitData(NULL), m_hDlgRes(NULL), m_hDlgResSplit(NULL)
	{
		T* pT = static_cast<T*>(this);
		pT;   // avoid level 4 warning

		// initialize ActiveX hosting and modify dialog template
		ATL::AtlAxWinInit();

#if (_ATL_VER >= 0x0700)
		HINSTANCE hInstance = ATL::_AtlBaseModule.GetResourceInstance();
#else // !(_ATL_VER >= 0x0700)
		HINSTANCE hInstance = _Module.GetResourceInstance();
#endif // !(_ATL_VER >= 0x0700)
		LPCTSTR lpTemplateName = MAKEINTRESOURCE(pT->IDD);
		HRSRC hDlg = ::FindResource(hInstance, lpTemplateName, (LPTSTR)RT_DIALOG);
		if(hDlg != NULL)
		{
			HRSRC hDlgInit = ::FindResource(hInstance, lpTemplateName, (LPTSTR)_ATL_RT_DLGINIT);

			BYTE* pInitData = NULL;
			if(hDlgInit != NULL)
			{
				m_hInitData = ::LoadResource(hInstance, hDlgInit);
				pInitData = (BYTE*)::LockResource(m_hInitData);
			}

			m_hDlgRes = ::LoadResource(hInstance, hDlg);
			DLGTEMPLATE* pDlg = (DLGTEMPLATE*)::LockResource(m_hDlgRes);
			LPCDLGTEMPLATE lpDialogTemplate = ATL::_DialogSplitHelper::SplitDialogTemplate(pDlg, pInitData);
			if(lpDialogTemplate != pDlg)
				m_hDlgResSplit = GlobalHandle(lpDialogTemplate);

			// set up property page to use in-memory dialog template
			if(lpDialogTemplate != NULL)
			{
				m_psp.dwFlags |= PSP_DLGINDIRECT;
				m_psp.pResource = lpDialogTemplate;
			}
			else
			{
				ATLASSERT(FALSE && _T("CAxPropertyPageImpl - ActiveX initializtion failed!"));
			}
		}
		else
		{
			ATLASSERT(FALSE && _T("CAxPropertyPageImpl - Cannot find dialog template!"));
		}
	}

	~CAxPropertyPageImpl()
	{
		if(m_hInitData != NULL)
		{
			UnlockResource(m_hInitData);
			FreeResource(m_hInitData);
		}
		if(m_hDlgRes != NULL)
		{
			UnlockResource(m_hDlgRes);
			FreeResource(m_hDlgRes);
		}
		if(m_hDlgResSplit != NULL)
		{
			::GlobalFree(m_hDlgResSplit);
		}
	}

// Methods
	// call this one to handle keyboard message for ActiveX controls
	BOOL PreTranslateMessage(LPMSG pMsg)
	{
		if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
		   (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
			return FALSE;
		// find a direct child of the dialog from the window that has focus
		HWND hWndCtl = ::GetFocus();
		if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd)
		{
			do
			{
				hWndCtl = ::GetParent(hWndCtl);
			}
			while (::GetParent(hWndCtl) != m_hWnd);
		}
		// give controls a chance to translate this message
		return (BOOL)::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg);
	}

// Overridables
#if (_WIN32_IE >= 0x0500)
	// new default implementation for ActiveX hosting pages
	BOOL OnTranslateAccelerator(LPMSG lpMsg)
	{
		T* pT = static_cast<T*>(this);
		return pT->PreTranslateMessage(lpMsg);
	}
#endif // (_WIN32_IE >= 0x0500)

// Support for new stuff in ATL7
#if (_ATL_VER >= 0x0700)
	int GetIDD()
	{
		return( static_cast<T*>(this)->IDD );
	}

	virtual DLGPROC GetDialogProc()
	{
		return DialogProc;
	}

	static INT_PTR CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		CAxPropertyPageImpl< T, TBase >* pThis = (CAxPropertyPageImpl< T, TBase >*)hWnd;
		if (uMsg == WM_INITDIALOG)
		{
			HRESULT hr;
			if (FAILED(hr = pThis->CreateActiveXControls(pThis->GetIDD())))
			{
				ATLASSERT(FALSE);
				return FALSE;
			}
		}
		return CPropertyPageImpl< T, TBase >::DialogProc(hWnd, uMsg, wParam, lParam);
	}

// ActiveX controls creation
	virtual HRESULT CreateActiveXControls(UINT nID)
	{
		// Load dialog template and InitData
		HRSRC hDlgInit = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)_ATL_RT_DLGINIT);
		BYTE* pInitData = NULL;
		HGLOBAL hData = NULL;
		HRESULT hr = S_OK;
		if (hDlgInit != NULL)
		{
			hData = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlgInit);
			if (hData != NULL)
				pInitData = (BYTE*) ::LockResource(hData);
		}

		HRSRC hDlg = ::FindResource(ATL::_AtlBaseModule.GetResourceInstance(), MAKEINTRESOURCE(nID), (LPTSTR)RT_DIALOG);
		if (hDlg != NULL)
		{
			HGLOBAL hResource = ::LoadResource(ATL::_AtlBaseModule.GetResourceInstance(), hDlg);
			DLGTEMPLATE* pDlg = NULL;
			if (hResource != NULL)
			{
				pDlg = (DLGTEMPLATE*) ::LockResource(hResource);
				if (pDlg != NULL)
				{
					// Get first control on the template
					BOOL bDialogEx = ATL::_DialogSplitHelper::IsDialogEx(pDlg);
					WORD nItems = ATL::_DialogSplitHelper::DlgTemplateItemCount(pDlg);

					// Get first control on the dialog
					DLGITEMTEMPLATE* pItem = ATL::_DialogSplitHelper::FindFirstDlgItem(pDlg);
					HWND hWndPrev = GetWindow(GW_CHILD);

					// Create all ActiveX cotnrols in the dialog template and place them in the correct tab order (z-order)
					for (WORD nItem = 0; nItem < nItems; nItem++)
					{
						DWORD wID = bDialogEx ? ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : pItem->id;
						if (ATL::_DialogSplitHelper::IsActiveXControl(pItem, bDialogEx))
						{
							BYTE* pData = NULL;
							DWORD dwLen = ATL::_DialogSplitHelper::FindCreateData(wID, pInitData, &pData);
							ATL::CComPtr<IStream> spStream;
							if (dwLen != 0)
							{
								HGLOBAL h = GlobalAlloc(GHND, dwLen);
								if (h != NULL)
								{
									BYTE* pBytes = (BYTE*) GlobalLock(h);
									BYTE* pSource = pData; 
									memcpy(pBytes, pSource, dwLen);
									GlobalUnlock(h);
									CreateStreamOnHGlobal(h, TRUE, &spStream);
								}
								else
								{
									hr = E_OUTOFMEMORY;
									break;
								}
							}

							ATL::CComBSTR bstrLicKey;
							hr = ATL::_DialogSplitHelper::ParseInitData(spStream, &bstrLicKey.m_str);
							if (SUCCEEDED(hr))
							{
								ATL::CAxWindow2 wnd;
								// Get control caption.
								LPWSTR pszClassName = 
									bDialogEx ? 
										(LPWSTR)(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem) + 1) :
										(LPWSTR)(pItem + 1);
								// Get control rect.
								RECT rect;
								rect.left = 
									bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->x : 
										pItem->x;
								rect.top = 
									bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->y : 
										pItem->y;
								rect.right = rect.left + 
									(bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cx : 
										pItem->cx);
								rect.bottom = rect.top + 
									(bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->cy : 
										pItem->cy);

								// Convert from dialog units to screen units
								MapDialogRect(&rect);

								// Create AxWindow with a NULL caption.
								wnd.Create(m_hWnd, 
									&rect, 
									NULL, 
									(bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->style : 
										pItem->style) | WS_TABSTOP, 
									bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->exStyle : 
										0,
									bDialogEx ? 
										((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->id : 
										pItem->id,
									NULL);

								if (wnd != NULL)
								{
#ifndef _WIN32_WCE
									// Set the Help ID
									if (bDialogEx && ((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID != 0)
										wnd.SetWindowContextHelpId(((ATL::_DialogSplitHelper::DLGITEMTEMPLATEEX*)pItem)->helpID);
#endif // !_WIN32_WCE
									// Try to create the ActiveX control.
									hr = wnd.CreateControlLic(pszClassName, spStream, NULL, bstrLicKey);
									if (FAILED(hr))
										break;
									// Set the correct tab position.
									if (nItem == 0)
										hWndPrev = HWND_TOP;
									wnd.SetWindowPos(hWndPrev, 0,0,0,0,SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
									hWndPrev = wnd;
								}
								else
								{
									hr = ATL::AtlHresultFromLastError();
								}
							}
						}
						else
						{
							if (nItem != 0)
								hWndPrev = ::GetWindow(hWndPrev, GW_HWNDNEXT);
						}
						pItem = ATL::_DialogSplitHelper::FindNextDlgItem(pItem, bDialogEx);
					}
				}
				else
					hr = ATL::AtlHresultFromLastError();
			}
			else
				hr = ATL::AtlHresultFromLastError();
		}
		return hr;
	}

// Event handling support
	HRESULT AdviseSinkMap(bool bAdvise)
	{
		if(!bAdvise && m_hWnd == NULL)
		{
			// window is gone, controls are already unadvised
			ATLTRACE2(atlTraceUI, 0, _T("CAxPropertyPageImpl::AdviseSinkMap called after the window was destroyed\n"));
			return S_OK;
		}
		HRESULT hRet = E_NOTIMPL;
		__if_exists(T::_GetSinkMapFinder)
		{
			T* pT = static_cast<T*>(this);
			hRet = AtlAdviseSinkMap(pT, bAdvise);
		}
		return hRet;
	}

// Message map and handlers
	typedef CPropertyPageImpl< T, TBase>   _baseClass;
	BEGIN_MSG_MAP(CAxPropertyPageImpl)
		MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
		CHAIN_MSG_MAP(_baseClass)
	END_MSG_MAP()

	LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		// initialize controls in dialog with DLGINIT resource section
		ExecuteDlgInit(static_cast<T*>(this)->IDD);
		AdviseSinkMap(true);
		bHandled = FALSE;
		return 1;
	}

	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		AdviseSinkMap(false);
		bHandled = FALSE;
		return 1;
	}
#endif // (_ATL_VER >= 0x0700)
};

// for non-customized pages
template <WORD t_wDlgTemplateID>
class CAxPropertyPage : public CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >
{
public:
	enum { IDD = t_wDlgTemplateID };

	CAxPropertyPage(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : CAxPropertyPageImpl<CAxPropertyPage>(title)
	{ }

#if (_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700)
	// not empty so we handle accelerators/create controls
	BEGIN_MSG_MAP(CAxPropertyPage)
		CHAIN_MSG_MAP(CAxPropertyPageImpl<CAxPropertyPage<t_wDlgTemplateID> >)
	END_MSG_MAP()
#else // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
	DECLARE_EMPTY_MSG_MAP()
#endif // !((_WIN32_IE >= 0x0500) || (_ATL_VER >= 0x0700))
};

#endif // _ATL_NO_HOSTING


///////////////////////////////////////////////////////////////////////////////
// Wizard97 Support

#if (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)

// Sample wizard dialog resources:
//
// IDD_WIZ97_INTERIOR_BLANK DIALOG  0, 0, 317, 143
// STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
// CAPTION "Wizard97 Property Page - Interior"
// FONT 8, "MS Shell Dlg"
// BEGIN
// END
//
// IDD_WIZ97_EXTERIOR_BLANK DIALOGEX 0, 0, 317, 193
// STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
// CAPTION "Wizard97 Property Page - Welcome/Complete"
// FONT 8, "MS Shell Dlg", 0, 0, 0x0
// BEGIN
//    LTEXT           "Welcome to the X Wizard",IDC_WIZ97_EXTERIOR_TITLE,115,8,
//                    195,24
//    LTEXT           "Wizard Explanation\r\n(The height of the static text should be in multiples of 8 dlus)",
//                    IDC_STATIC,115,40,195,16
//    LTEXT           "h",IDC_WIZ97_BULLET1,118,64,8,8
//    LTEXT           "List Item 1 (the h is turned into a bullet)",IDC_STATIC,
//                    127,63,122,8
//    LTEXT           "h",IDC_WIZ97_BULLET2,118,79,8,8
//    LTEXT           "List Item 2. Keep 7 dlus between paragraphs",IDC_STATIC,
//                    127,78,33,8
//    CONTROL         "&Do not show this Welcome page again",
//                    IDC_WIZ97_WELCOME_NOTAGAIN,"Button",BS_AUTOCHECKBOX | 
//                    WS_TABSTOP,115,169,138,10
// END
//
// GUIDELINES DESIGNINFO 
// BEGIN
//    IDD_WIZ97_INTERIOR_BLANK, DIALOG
//    BEGIN
//        LEFTMARGIN, 7
//        RIGHTMARGIN, 310
//        VERTGUIDE, 21
//        VERTGUIDE, 31
//        VERTGUIDE, 286
//        VERTGUIDE, 296
//        TOPMARGIN, 7
//        BOTTOMMARGIN, 136
//        HORZGUIDE, 8
//    END
//
//    IDD_WIZ97_EXTERIOR_BLANK, DIALOG
//    BEGIN
//        RIGHTMARGIN, 310
//        VERTGUIDE, 115
//        VERTGUIDE, 118
//        VERTGUIDE, 127
//        TOPMARGIN, 7
//        BOTTOMMARGIN, 186
//        HORZGUIDE, 8
//        HORZGUIDE, 32
//        HORZGUIDE, 40
//        HORZGUIDE, 169
//    END
// END

///////////////////////////////////////////////////////////////////////////////
// CWizard97SheetWindow - client side for a Wizard 97 style wizard sheet

class CWizard97SheetWindow : public CPropertySheetWindow
{
public:
// Constructors
	CWizard97SheetWindow(HWND hWnd = NULL) : CPropertySheetWindow(hWnd)
	{ }

	CWizard97SheetWindow& operator =(HWND hWnd)
	{
		m_hWnd = hWnd;
		return *this;
	}

// Operations
	HFONT GetExteriorPageTitleFont(void)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HFONT)::SendMessage(m_hWnd, GetMessage_GetExteriorPageTitleFont(), 0, 0L);
	}

	HFONT GetBulletFont(void)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return (HFONT)::SendMessage(m_hWnd, GetMessage_GetBulletFont(), 0, 0L);
	}

// Helpers
	static UINT GetMessage_GetExteriorPageTitleFont()
	{
		static UINT uGetExteriorPageTitleFont = 0;
		if(uGetExteriorPageTitleFont == 0)
		{
			CStaticDataInitCriticalSectionLock lock;
			if(FAILED(lock.Lock()))
			{
				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont().\n"));
				ATLASSERT(FALSE);
				return 0;
			}

			if(uGetExteriorPageTitleFont == 0)
				uGetExteriorPageTitleFont = ::RegisterWindowMessage(_T("GetExteriorPageTitleFont_531AF056-B8BE-4c4c-B786-AC608DF0DF12"));

			lock.Unlock();
		}
		ATLASSERT(uGetExteriorPageTitleFont != 0);
		return uGetExteriorPageTitleFont;
	}

	static UINT GetMessage_GetBulletFont()
	{
		static UINT uGetBulletFont = 0;
		if(uGetBulletFont == 0)
		{
			CStaticDataInitCriticalSectionLock lock;
			if(FAILED(lock.Lock()))
			{
				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CWizard97SheetWindow::GetMessage_GetBulletFont().\n"));
				ATLASSERT(FALSE);
				return 0;
			}

			if(uGetBulletFont == 0)
				uGetBulletFont = ::RegisterWindowMessage(_T("GetBulletFont_AD347D08-8F65-45ef-982E-6352E8218AD5"));

			lock.Unlock();
		}
		ATLASSERT(uGetBulletFont != 0);
		return uGetBulletFont;
	}

// Implementation - override to prevent usage
	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
	{
		ATLASSERT(FALSE);
		return NULL;
	}
};


///////////////////////////////////////////////////////////////////////////////
// CWizard97SheetImpl - implements a Wizard 97 style wizard sheet

template <class T, class TBase = CWizard97SheetWindow>
class ATL_NO_VTABLE CWizard97SheetImpl : public CPropertySheetImpl< T, TBase >
{
protected:
// Typedefs
	typedef CWizard97SheetImpl< T, TBase > thisClass;
	typedef CPropertySheetImpl< T, TBase > baseClass;

// Member variables
	CFont m_fontExteriorPageTitle;   // Welcome and Completion page title font
	CFont m_fontBullet;              // Bullet font (used on static text 'h' to produce a small bullet)
	bool m_bReceivedFirstSizeMessage;   

public:
	CWizard97SheetImpl(ATL::_U_STRINGorID title, ATL::_U_STRINGorID headerBitmap, ATL::_U_STRINGorID watermarkBitmap, UINT uStartPage = 0, HWND hWndParent = NULL) :
			baseClass(title, uStartPage, hWndParent),
			m_bReceivedFirstSizeMessage(false)
	{
		m_psh.dwFlags &= ~(PSH_NOCONTEXTHELP);
		m_psh.dwFlags &= ~(PSH_WIZARD | PSH_WIZARD_LITE);

		m_psh.dwFlags |= (PSH_HASHELP | PSH_WIZARDCONTEXTHELP);
		m_psh.dwFlags |= PSH_WIZARD97;

		baseClass::SetHeader(headerBitmap.m_lpstr);
		baseClass::SetWatermark(watermarkBitmap.m_lpstr);
	}

// Overrides from base class
	void OnSheetInitialized()
	{
		T* pT = static_cast<T*>(this);
		pT->_InitializeFonts();

		// We'd like to center the wizard here, but its too early.
		// Instead, we'll do CenterWindow upon our first WM_SIZE message
	}

// Initialization
	void _InitializeFonts()
	{
		// Setup the Title and Bullet Font
		// (Property pages can send the "get external page title font" and "get bullet font" messages)
		// The derived class needs to do the actual SetFont for the dialog items)

		CFontHandle fontThisDialog = this->GetFont();
		CClientDC dcScreen(NULL);

		LOGFONT titleLogFont = {0};
		LOGFONT bulletLogFont = {0};
		fontThisDialog.GetLogFont(&titleLogFont);
		fontThisDialog.GetLogFont(&bulletLogFont);

		// The Wizard 97 Spec recommends to do the Title Font
		// as Verdana Bold, 12pt.
		titleLogFont.lfCharSet = DEFAULT_CHARSET;
		titleLogFont.lfWeight = FW_BOLD;
		lstrcpy(titleLogFont.lfFaceName, _T("Verdana Bold"));
		INT titleFontPointSize = 12;
		titleLogFont.lfHeight = -::MulDiv(titleFontPointSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
		m_fontExteriorPageTitle.CreateFontIndirect(&titleLogFont);

		// The Wizard 97 Spec recommends to do Bullets by having
		// static text of "h" in the Marlett font.
		bulletLogFont.lfCharSet = DEFAULT_CHARSET;
		bulletLogFont.lfWeight = FW_NORMAL;
		lstrcpy(bulletLogFont.lfFaceName, _T("Marlett"));
		INT bulletFontSize = 8;
		bulletLogFont.lfHeight = -::MulDiv(bulletFontSize, dcScreen.GetDeviceCaps(LOGPIXELSY), 72);
		m_fontBullet.CreateFontIndirect(&bulletLogFont);
	}

// Message Handling
	BEGIN_MSG_MAP(thisClass)
		MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetExteriorPageTitleFont(), OnGetExteriorPageTitleFont)
		MESSAGE_HANDLER(CWizard97SheetWindow::GetMessage_GetBulletFont(), OnGetBulletFont)
		MESSAGE_HANDLER(WM_SIZE, OnSize)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()

	LRESULT OnGetExteriorPageTitleFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		return (LRESULT)(HFONT)m_fontExteriorPageTitle;
	}

	LRESULT OnGetBulletFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
	{
		return (LRESULT)(HFONT)m_fontBullet;
	}

	LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
	{
		if(!m_bReceivedFirstSizeMessage)
		{
			m_bReceivedFirstSizeMessage = true;
			this->CenterWindow();
		}

		bHandled = FALSE;
		return 0;
	}
};

// for non-customized sheets
class CWizard97Sheet : public CWizard97SheetImpl<CWizard97Sheet>
{
protected:
// Typedefs
	typedef CWizard97Sheet thisClass;
	typedef CWizard97SheetImpl<CWizard97Sheet> baseClass;

public:
	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)
	{ }

	BEGIN_MSG_MAP(thisClass)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()
};


///////////////////////////////////////////////////////////////////////////////
// CWizard97PageWindow - client side for a Wizard 97 style wizard page

#define WIZARD97_EXTERIOR_CXDLG 317
#define WIZARD97_EXTERIOR_CYDLG 193

#define WIZARD97_INTERIOR_CXDLG 317
#define WIZARD97_INTERIOR_CYDLG 143

class CWizard97PageWindow : public CPropertyPageWindow
{
public:
// Constructors
	CWizard97PageWindow(HWND hWnd = NULL) : CPropertyPageWindow(hWnd)
	{ }

	CWizard97PageWindow& operator =(HWND hWnd)
	{
		m_hWnd = hWnd;
		return *this;
	}

// Attributes
	CWizard97SheetWindow GetPropertySheet() const
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return CWizard97SheetWindow(GetParent());
	}

// Operations
	HFONT GetExteriorPageTitleFont(void)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return GetPropertySheet().GetExteriorPageTitleFont();
	}

	HFONT GetBulletFont(void)
	{
		ATLASSERT(::IsWindow(m_hWnd));
		return GetPropertySheet().GetBulletFont();
	}

// Implementation - overrides to prevent usage
	HWND Create(LPCTSTR, HWND, ATL::_U_RECT = NULL, LPCTSTR = NULL, DWORD = 0, DWORD = 0, ATL::_U_MENUorID = 0U, LPVOID = NULL)
	{
		ATLASSERT(FALSE);
		return NULL;
	}

};


///////////////////////////////////////////////////////////////////////////////
// CWizard97PageImpl - implements a Wizard 97 style wizard page

template <class T, class TBase = CWizard97PageWindow>
class ATL_NO_VTABLE CWizard97PageImpl : public CPropertyPageImpl< T, TBase >
{
protected:
// Typedefs
	typedef CWizard97PageImpl< T, TBase > thisClass;
	typedef CPropertyPageImpl< T, TBase > baseClass;

public:
	CWizard97PageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
	{ }

// Message Handling
	BEGIN_MSG_MAP(thisClass)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()
};


///////////////////////////////////////////////////////////////////////////////
// CWizard97ExteriorPageImpl - implements a Wizard 97 style exterior wizard page

template <class T, class TBase = CWizard97PageWindow>
class ATL_NO_VTABLE CWizard97ExteriorPageImpl : public CPropertyPageImpl< T, TBase >
{
protected:
// Typedefs
	typedef CWizard97ExteriorPageImpl< T, TBase > thisClass;
	typedef CPropertyPageImpl< T, TBase > baseClass;

public:
// Constructors
	CWizard97ExteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
	{
		m_psp.dwFlags |= PSP_HASHELP;
		m_psp.dwFlags |= PSP_HIDEHEADER;
	}

// Message Handling
	BEGIN_MSG_MAP(thisClass)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()
};


///////////////////////////////////////////////////////////////////////////////
// CWizard97InteriorPageImpl - implements a Wizard 97 style interior wizard page

template <class T, class TBase = CWizard97PageWindow>
class ATL_NO_VTABLE CWizard97InteriorPageImpl : public CPropertyPageImpl< T, TBase >
{
protected:
// Typedefs
	typedef CWizard97InteriorPageImpl< T, TBase > thisClass;
	typedef CPropertyPageImpl< T, TBase > baseClass;

public:
// Constructors
	CWizard97InteriorPageImpl(ATL::_U_STRINGorID title = (LPCTSTR)NULL) : baseClass(title)
	{
		m_psp.dwFlags |= PSP_HASHELP;
		m_psp.dwFlags &= ~PSP_HIDEHEADER;
		m_psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;

		// Be sure to have the derived class define this in the constructor.
		// We'll default it to something obvious in case its forgotten.
		baseClass::SetHeaderTitle(_T("Call SetHeaderTitle in Derived Class"));
		baseClass::SetHeaderSubTitle(_T("Call SetHeaderSubTitle in the constructor of the Derived Class."));
	}

// Message Handling
	BEGIN_MSG_MAP(thisClass)
		CHAIN_MSG_MAP(baseClass)
	END_MSG_MAP()
};

#endif // (_WIN32_IE >= 0x0500) && !defined(_WIN32_WCE)

}; // namespace WTL

#endif // __ATLDLGS_H__




See more files for this project here

bccSDK

This project has a goal to provide complete port of latest MS Platform SDK along with some other commonly used separate SDK\'s for both older and newer Borland compilers. This includes headers, idl files and static and import lib files.

Project homepage: http://sourceforge.net/projects/bccsdk
Programming language(s): C,C++,IDL
License: mit

  atlapp.h
  atlcrack.h
  atlctrls.h
  atlctrlw.h
  atlctrlx.h
  atlddx.h
  atldlgs.h
  atlframe.h
  atlgdi.h
  atlmisc.h
  atlprint.h
  atlres.h
  atlresce.h
  atlscrl.h
  atlsplit.h
  atltheme.h
  atluser.h
  atlwince.h
  atlwinx.h