| // 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 | 
 | // Microsoft Permissive License (Ms-PL) which can be found in the file | 
 | // Ms-PL.txt at the root of this distribution. | 
 |  | 
 | #ifndef __ATLTHEME_H__ | 
 | #define __ATLTHEME_H__ | 
 |  | 
 | #pragma once | 
 |  | 
 | #ifndef __cplusplus | 
 | 	#error ATL requires C++ compilation (use a .cpp suffix) | 
 | #endif | 
 |  | 
 | #ifdef _WIN32_WCE | 
 | 	#error atltheme.h is not supported on Windows CE | 
 | #endif | 
 |  | 
 | #ifndef __ATLAPP_H__ | 
 | 	#error atltheme.h requires atlapp.h to be included first | 
 | #endif | 
 |  | 
 | #ifndef __ATLWIN_H__ | 
 | 	#error atltheme.h requires atlwin.h to be included first | 
 | #endif | 
 |  | 
 | #if (_WIN32_WINNT < 0x0501) | 
 | 	#error atltheme.h requires _WIN32_WINNT >= 0x0501 | 
 | #endif // (_WIN32_WINNT < 0x0501) | 
 |  | 
 | #if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN)) | 
 |   #include <vssym32.h> | 
 | #else | 
 |   #include <tmschema.h> | 
 | #endif | 
 |  | 
 | #include <uxtheme.h> | 
 | #pragma comment(lib, "uxtheme.lib") | 
 |  | 
 | // Note: To create an application that also runs on older versions of Windows, | 
 | // use delay load of uxtheme.dll and ensure that no calls to the Theme API are | 
 | // made if theming is not supported. It is enough to check if m_hTheme is NULL. | 
 | // Example: | 
 | //	if(m_hTheme != NULL) | 
 | //	{ | 
 | //		DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL); | 
 | //		DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect); | 
 | //	} | 
 | //	else | 
 | //	{ | 
 | //		dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH); | 
 | //		dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); | 
 | //	} | 
 | // | 
 | // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib,  | 
 | // and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the  | 
 | // project properties. | 
 | #if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) | 
 |   #pragma comment(lib, "delayimp.lib") | 
 |   #pragma comment(linker, "/delayload:uxtheme.dll") | 
 | #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD) | 
 |  | 
 | // Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h | 
 | // is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE | 
 | #ifndef _WTL_NEW_UXTHEME | 
 |   #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) | 
 |     #define _WTL_NEW_UXTHEME | 
 |   #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE) | 
 | #endif // _WTL_NEW_UXTHEME | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // Classes in this file: | 
 | // | 
 | // CTheme | 
 | // CThemeImpl<T, TBase> | 
 | // | 
 | // CBufferedPaint | 
 | // CBufferedPaintImpl<T> | 
 | // CBufferedPaintWindowImpl<T, TBase, TWinTraits> | 
 | // CBufferedAnimation | 
 | // CBufferedAnimationImpl<T, TState> | 
 | // CBufferedAnimationWindowImpl<T, TState, TBase, TWinTraits> | 
 | // | 
 | // Global functions: | 
 | //   AtlDrawThemeClientEdge() | 
 |  | 
 |  | 
 | namespace WTL | 
 | { | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CTheme - wrapper for theme handle | 
 |  | 
 | class CTheme | 
 | { | 
 | public: | 
 | // Data members | 
 | 	HTHEME m_hTheme; | 
 | 	static int m_nIsThemingSupported; | 
 |  | 
 | // Constructor | 
 | 	CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme) | 
 | 	{ | 
 | 		IsThemingSupported(); | 
 | 	} | 
 |  | 
 | // Operators and helpers | 
 | 	bool IsThemeNull() const | 
 | 	{ | 
 | 		return (m_hTheme == NULL); | 
 | 	} | 
 |  | 
 | 	CTheme& operator =(HTHEME hTheme) | 
 | 	{ | 
 | 		m_hTheme = hTheme; | 
 | 		return *this; | 
 | 	} | 
 |  | 
 | 	operator HTHEME() const | 
 | 	{ | 
 | 		return m_hTheme; | 
 | 	} | 
 |  | 
 | 	void Attach(HTHEME hTheme) | 
 | 	{ | 
 | 		m_hTheme = hTheme; | 
 | 	} | 
 |  | 
 | 	HTHEME Detach() | 
 | 	{ | 
 | 		HTHEME hTheme = m_hTheme; | 
 | 		m_hTheme = NULL; | 
 | 		return hTheme; | 
 | 	} | 
 |  | 
 | // Theme support helper | 
 | 	static bool IsThemingSupported() | 
 | 	{ | 
 | 		if(m_nIsThemingSupported == -1) | 
 | 		{ | 
 | 			CStaticDataInitCriticalSectionLock lock; | 
 | 			if(FAILED(lock.Lock())) | 
 | 			{ | 
 | 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n")); | 
 | 				ATLASSERT(FALSE); | 
 | 				return false; | 
 | 			} | 
 |  | 
 | 			if(m_nIsThemingSupported == -1) | 
 | 			{ | 
 | 				HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll")); | 
 | 				m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0; | 
 | 				if(hThemeDLL != NULL) | 
 | 					::FreeLibrary(hThemeDLL); | 
 | 			} | 
 |  | 
 | 			lock.Unlock(); | 
 | 		} | 
 |  | 
 | 		ATLASSERT(m_nIsThemingSupported != -1); | 
 | 		return (m_nIsThemingSupported == 1); | 
 | 	} | 
 |  | 
 | // Operations and theme properties | 
 | 	HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return NULL; | 
 |  | 
 | 		ATLASSERT(m_hTheme == NULL); | 
 | 		m_hTheme = ::OpenThemeData(hWnd, pszClassList); | 
 | 		return m_hTheme; | 
 | 	} | 
 |  | 
 | 	HRESULT CloseThemeData() | 
 | 	{ | 
 | 		HRESULT hRet = S_FALSE; | 
 | 		if(m_hTheme != NULL) | 
 | 		{ | 
 | 			hRet = ::CloseThemeData(m_hTheme); | 
 | 			if(SUCCEEDED(hRet)) | 
 | 				m_hTheme = NULL; | 
 | 		} | 
 | 		return hRet; | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID,  LPCRECT pBoundingRect, LPRECT pContentRect) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID,  pBoundingRect, pContentRect); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT  pBoundingRect, LPRECT pExtentRect) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 		return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric); | 
 | #else // !_WTL_NEW_UXTHEME | 
 | 		// Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW | 
 | 		return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric); | 
 | #endif // !_WTL_NEW_UXTHEME | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion); | 
 | 	} | 
 |  | 
 | 	HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex); | 
 | 	} | 
 |  | 
 | 	BOOL IsThemePartDefined(int nPartID, int nStateID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::IsThemePartDefined(m_hTheme, nPartID, nStateID); | 
 | 	} | 
 |  | 
 | 	BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint); | 
 | 	} | 
 |  | 
 | 	// deprecated | 
 | 	HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); | 
 | #else // !_WTL_NEW_UXTHEME | 
 | 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* | 
 | 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); | 
 | #endif // !_WTL_NEW_UXTHEME | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont); | 
 | #else // !_WTL_NEW_UXTHEME | 
 | 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* | 
 | 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont); | 
 | #endif // !_WTL_NEW_UXTHEME | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars); | 
 | 	} | 
 |  | 
 | 	COLORREF GetThemeSysColor(int nColorID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysColor(m_hTheme, nColorID); | 
 | 	} | 
 |  | 
 | 	HBRUSH GetThemeSysColorBrush(int nColorID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysColorBrush(m_hTheme, nColorID); | 
 | 	} | 
 |  | 
 | 	int GetThemeSysSize(int nSizeID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysSize(m_hTheme, nSizeID); | 
 | 	} | 
 |  | 
 | 	BOOL GetThemeSysBool(int nBoolID) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysBool(m_hTheme, nBoolID); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 		return ::GetThemeSysFont(m_hTheme, nFontID, plf); | 
 | #else // !_WTL_NEW_UXTHEME | 
 | 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW* | 
 | 		return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf); | 
 | #endif // !_WTL_NEW_UXTHEME | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeSysInt(int nIntID, int* pnValue) const | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeSysInt(m_hTheme, nIntID, pnValue); | 
 | 	} | 
 |  | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 	HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return NULL; | 
 |  | 
 | 		ATLASSERT(m_hTheme == NULL); | 
 | 		m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags); | 
 | 		return m_hTheme; | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration); | 
 | 	} | 
 | #endif // _WTL_NEW_UXTHEME | 
 |  | 
 | #if (_WIN32_WINNT >= 0x0600) | 
 | 	HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap); | 
 | 	} | 
 |  | 
 | 	HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance) | 
 | 	{ | 
 | 		ATLASSERT(m_hTheme != NULL); | 
 | 		return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance); | 
 | 	} | 
 | #endif // (_WIN32_WINNT >= 0x0600) | 
 | }; | 
 |  | 
 | __declspec(selectany) int CTheme::m_nIsThemingSupported = -1; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CThemeImpl - theme support implementation | 
 |  | 
 | // Derive from this class to implement window with theme support. | 
 | // Example: | 
 | //	class CMyThemeWindow : public CWindowImpl<CMyThemeWindow>, public CThemeImpl<CMyThemeWindow> | 
 | //	{ | 
 | //	... | 
 | //		BEGIN_MSG_MAP(CMyThemeWindow) | 
 | //			CHAIN_MSG_MAP(CThemeImpl<CMyThemeWindow>) | 
 | //			... | 
 | //		END_MSG_MAP() | 
 | //	... | 
 | //	}; | 
 | // | 
 | // If you set theme class list, the class will automaticaly open/close/reopen theme data. | 
 |  | 
 |  | 
 | // Helper for drawing theme client edge | 
 | inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0) | 
 | { | 
 | 	ATLASSERT(hTheme != NULL); | 
 | 	ATLASSERT(::IsWindow(hWnd)); | 
 |  | 
 | 	CWindowDC dc(hWnd); | 
 | 	if(dc.IsNull()) | 
 | 		return false; | 
 |  | 
 | 	// Get border size | 
 | 	int cxBorder = GetSystemMetrics(SM_CXBORDER); | 
 | 	int cyBorder = GetSystemMetrics(SM_CYBORDER); | 
 | 	if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder))) | 
 | 		cyBorder = cxBorder; | 
 |  | 
 | 	RECT rect; | 
 | 	::GetWindowRect(hWnd, &rect);             | 
 |  | 
 | 	// Remove the client edge from the update region | 
 | 	int cxEdge = GetSystemMetrics(SM_CXEDGE); | 
 | 	int cyEdge = GetSystemMetrics(SM_CYEDGE); | 
 | 	::InflateRect(&rect, -cxEdge, -cyEdge); | 
 | 	CRgn rgn; | 
 | 	rgn.CreateRectRgnIndirect(&rect); | 
 | 	if(rgn.IsNull()) | 
 | 		return false; | 
 |  | 
 | 	if(hRgnUpdate != NULL) | 
 | 		rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND); | 
 |  | 
 | 	::OffsetRect(&rect, -rect.left, -rect.top); | 
 |  | 
 | 	::OffsetRect(&rect, cxEdge, cyEdge); | 
 | 	dc.ExcludeClipRect(&rect); | 
 | 	::InflateRect(&rect, cxEdge, cyEdge); | 
 |  | 
 | 	::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL); | 
 |  | 
 | 	// Use background brush too, since theme border might not cover everything | 
 | 	if(cxBorder < cxEdge && cyBorder < cyEdge) | 
 | 	{ | 
 | 		if(hBrush == NULL) | 
 | // need conditional code because types don't match in winuser.h | 
 | #ifdef _WIN64 | 
 | 			hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND); | 
 | #else | 
 | 			hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND)); | 
 | #endif | 
 |  | 
 | 		::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge); | 
 | 		dc.FillRect(&rect, hBrush); | 
 | 	} | 
 |  | 
 | 	::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L); | 
 |  | 
 | 	return true; | 
 | } | 
 |  | 
 |  | 
 | // Theme extended styles | 
 | #define THEME_EX_3DCLIENTEDGE		0x00000001 | 
 | #define THEME_EX_THEMECLIENTEDGE	0x00000002 | 
 |  | 
 | template <class T, class TBase = CTheme> | 
 | class CThemeImpl : public TBase | 
 | { | 
 | public: | 
 | // Data members | 
 | 	LPWSTR m_lpstrThemeClassList; | 
 | 	DWORD m_dwExtendedStyle;   // theme specific extended styles | 
 |  | 
 | // Constructor & destructor | 
 | 	CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0) | 
 | 	{ } | 
 |  | 
 | 	~CThemeImpl() | 
 | 	{ | 
 | 		delete [] m_lpstrThemeClassList; | 
 | 	} | 
 |  | 
 | // Attributes | 
 | 	bool SetThemeClassList(LPCWSTR lpstrThemeClassList) | 
 | 	{ | 
 | 		if(m_lpstrThemeClassList != NULL) | 
 | 		{ | 
 | 			delete [] m_lpstrThemeClassList; | 
 | 			m_lpstrThemeClassList = NULL; | 
 | 		} | 
 |  | 
 | 		if(lpstrThemeClassList == NULL) | 
 | 			return true; | 
 |  | 
 | 		int cchLen = lstrlenW(lpstrThemeClassList) + 1; | 
 | 		ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]); | 
 | 		if(m_lpstrThemeClassList == NULL) | 
 | 			return false; | 
 |  | 
 | 		SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList); | 
 |  | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const | 
 | 	{ | 
 | 		int cchLen = lstrlenW(m_lpstrThemeClassList) + 1; | 
 | 		if(cchListBuffer < cchLen) | 
 | 			return false; | 
 |  | 
 | 		SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList); | 
 |  | 
 | 		return true; | 
 | 	} | 
 |  | 
 | 	LPCWSTR GetThemeClassList() const | 
 | 	{ | 
 | 		return m_lpstrThemeClassList; | 
 | 	} | 
 |  | 
 | 	DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) | 
 | 	{ | 
 | 		DWORD dwPrevStyle = m_dwExtendedStyle; | 
 | 		if(dwMask == 0) | 
 | 			m_dwExtendedStyle = dwExtendedStyle; | 
 | 		else | 
 | 			m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); | 
 | 		return dwPrevStyle; | 
 | 	} | 
 |  | 
 | 	DWORD GetThemeExtendedStyle() const | 
 | 	{ | 
 | 		return m_dwExtendedStyle; | 
 | 	} | 
 |  | 
 | // Operations | 
 | 	HTHEME OpenThemeData() | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		ATLASSERT(m_lpstrThemeClassList != NULL); | 
 | 		if(m_lpstrThemeClassList == NULL) | 
 | 			return NULL; | 
 | 		CloseThemeData(); | 
 | 		return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList); | 
 | 	} | 
 |  | 
 | 	HTHEME OpenThemeData(LPCWSTR pszClassList) | 
 | 	{ | 
 | 		if(!SetThemeClassList(pszClassList)) | 
 | 			return NULL; | 
 | 		return OpenThemeData(); | 
 | 	} | 
 |  | 
 | 	HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList); | 
 | 	} | 
 |  | 
 | 	HTHEME GetWindowTheme() const | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return NULL; | 
 |  | 
 | 		const T* pT = static_cast<const T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::GetWindowTheme(pT->m_hWnd); | 
 | 	} | 
 |  | 
 | 	HRESULT EnableThemeDialogTexture(DWORD dwFlags) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags); | 
 | 	} | 
 |  | 
 | 	BOOL IsThemeDialogTextureEnabled() const | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return FALSE; | 
 |  | 
 | 		const T* pT = static_cast<const T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::IsThemeDialogTextureEnabled(pT->m_hWnd); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 		return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect); | 
 | #else | 
 | 		return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect); | 
 | #endif | 
 | 	} | 
 |  | 
 | #ifdef _WTL_NEW_UXTHEME | 
 | 	HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute); | 
 | 	} | 
 |  | 
 | 	HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		WTA_OPTIONS opt = { dwAttributes, dwMask }; | 
 | 		return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt)); | 
 | 	} | 
 |  | 
 | 	HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL) | 
 | 	{ | 
 | 		if(!IsThemingSupported()) | 
 | 			return S_FALSE; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect); | 
 | 	} | 
 | #endif // _WTL_NEW_UXTHEME | 
 |  | 
 | // Message map and handlers | 
 | 	// Note: If you handle any of these messages in your derived class, | 
 | 	// it is better to put CHAIN_MSG_MAP at the start of your message map. | 
 | 	BEGIN_MSG_MAP(CThemeImpl) | 
 | 		MESSAGE_HANDLER(WM_CREATE, OnCreate) | 
 | 		MESSAGE_HANDLER(WM_DESTROY, OnDestroy) | 
 | 		MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) | 
 | 		MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | 
 | 	{ | 
 | 		if(m_lpstrThemeClassList != NULL) | 
 | 			OpenThemeData(); | 
 | 		bHandled = FALSE; | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | 
 | 	{ | 
 | 		CloseThemeData(); | 
 | 		bHandled = FALSE; | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) | 
 | 	{ | 
 | 		CloseThemeData(); | 
 | 		if(m_lpstrThemeClassList != NULL) | 
 | 			OpenThemeData(); | 
 | 		bHandled = FALSE; | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		ATLASSERT(::IsWindow(pT->m_hWnd)); | 
 | 		LRESULT lRet = 0; | 
 | 		bHandled = FALSE; | 
 | 		if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0)) | 
 | 		{ | 
 | 			if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0) | 
 | 			{ | 
 | 				lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam); | 
 | 				bHandled = TRUE; | 
 | 			} | 
 | 			else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0)) | 
 | 			{ | 
 | 				HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL; | 
 | 				if(pT->DrawThemeClientEdge(hRgn)) | 
 | 					bHandled = TRUE; | 
 | 			} | 
 | 		} | 
 | 		return lRet; | 
 | 	} | 
 |  | 
 | // Drawing helper | 
 | 	bool DrawThemeClientEdge(HRGN hRgnUpdate) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0); | 
 | 	} | 
 | }; | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // Buffered Paint and Animation | 
 |  | 
 | #ifdef _WTL_NEW_UXTHEME | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedPaintBase - Buffered Paint support for othe classes | 
 |  | 
 | class CBufferedPaintBase | 
 | { | 
 | public: | 
 | 	static int m_nIsBufferedPaintSupported; | 
 |  | 
 | 	CBufferedPaintBase() | 
 | 	{ | 
 | 		if(IsBufferedPaintSupported()) | 
 | 			ATLVERIFY(SUCCEEDED(::BufferedPaintInit())); | 
 | 	} | 
 |  | 
 | 	~CBufferedPaintBase() | 
 | 	{ | 
 | 		if(IsBufferedPaintSupported()) | 
 | 			ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit())); | 
 | 	} | 
 |  | 
 | 	static bool IsBufferedPaintSupported() | 
 | 	{ | 
 | 		if(m_nIsBufferedPaintSupported == -1) | 
 | 		{ | 
 | 			CStaticDataInitCriticalSectionLock lock; | 
 | 			if(FAILED(lock.Lock())) | 
 | 			{ | 
 | 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n")); | 
 | 				ATLASSERT(FALSE); | 
 | 				return false; | 
 | 			} | 
 |  | 
 | 			if(m_nIsBufferedPaintSupported == -1) | 
 | 				m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0; | 
 |  | 
 | 			lock.Unlock(); | 
 | 		} | 
 |  | 
 | 		ATLASSERT(m_nIsBufferedPaintSupported != -1); | 
 | 		return (m_nIsBufferedPaintSupported == 1); | 
 | 	} | 
 | }; | 
 |  | 
 | __declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedPaint - support for buffered paint functions | 
 |  | 
 | class CBufferedPaint | 
 | { | 
 | public: | 
 | 	HPAINTBUFFER m_hPaintBuffer; | 
 |  | 
 | 	CBufferedPaint() : m_hPaintBuffer(NULL) | 
 | 	{ } | 
 |  | 
 | 	~CBufferedPaint() | 
 | 	{ | 
 | 		ATLVERIFY(SUCCEEDED(End())); | 
 | 	} | 
 |  | 
 | 	bool IsNull() const | 
 | 	{ | 
 | 		return (m_hPaintBuffer == NULL); | 
 | 	} | 
 |  | 
 | 	HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint) | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer == NULL); | 
 | 		m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint); | 
 | 		return m_hPaintBuffer; | 
 | 	} | 
 |  | 
 | 	HRESULT End(BOOL bUpdate = TRUE) | 
 | 	{ | 
 | 		HRESULT hRet = S_FALSE; | 
 | 		if(m_hPaintBuffer != NULL) | 
 | 		{ | 
 | 			hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate); | 
 | 			m_hPaintBuffer = NULL; | 
 | 		} | 
 | 		return hRet; | 
 | 	} | 
 |  | 
 | 	HRESULT GetTargetRect(LPRECT pRect) const | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect); | 
 | 	} | 
 |  | 
 | 	HDC GetTargetDC() const | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::GetBufferedPaintTargetDC(m_hPaintBuffer); | 
 | 	} | 
 |  | 
 | 	HDC GetPaintDC() const | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::GetBufferedPaintDC(m_hPaintBuffer); | 
 | 	} | 
 |  | 
 | 	HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow); | 
 | 	} | 
 |  | 
 | 	HRESULT Clear(const RECT* pRect = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::BufferedPaintClear(m_hPaintBuffer, pRect); | 
 | 	} | 
 |  | 
 | 	HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha); | 
 | 	} | 
 |  | 
 | 	HRESULT MakeOpaque(const RECT* pRect = NULL) | 
 | 	{ | 
 | 		ATLASSERT(m_hPaintBuffer != NULL); | 
 | 		return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255); | 
 | 	} | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedPaintImpl - provides buffered paint for any window | 
 |  | 
 | template <class T> | 
 | class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase | 
 | { | 
 | public: | 
 | 	CBufferedPaint m_BufferedPaint; | 
 | 	BP_BUFFERFORMAT m_dwFormat; | 
 | 	BP_PAINTPARAMS m_PaintParams; | 
 |  | 
 | 	CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB) | 
 | 	{ | 
 | 		memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); | 
 | 		m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); | 
 | 	} | 
 |  | 
 | // Message map and handlers | 
 | 	BEGIN_MSG_MAP(CBufferedPaintImpl) | 
 | 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) | 
 | 		MESSAGE_HANDLER(WM_PAINT, OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		return 1;   // no background needed | 
 | 	} | 
 |  | 
 | 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		if(wParam != NULL) | 
 | 		{ | 
 | 			RECT rect = { 0 }; | 
 | 			pT->GetClientRect(&rect); | 
 | 			pT->DoPaint((HDC)wParam, rect); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			CPaintDC dc(pT->m_hWnd); | 
 | 			pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint); | 
 | 		} | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | // Overrideables | 
 | 	void DoBufferedPaint(CDCHandle dc, RECT& rect) | 
 | 	{ | 
 | 		HDC hDCPaint = NULL; | 
 | 		if(IsBufferedPaintSupported()) | 
 | 			m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint); | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		if(hDCPaint != NULL) | 
 | 			pT->DoPaint(hDCPaint, rect); | 
 | 		else | 
 | 			pT->DoPaint(dc.m_hDC, rect); | 
 |  | 
 | 		if(IsBufferedPaintSupported()) | 
 | 			m_BufferedPaint.End(); | 
 | 	} | 
 |  | 
 | 	void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/) | 
 | 	{ | 
 | 		// must be implemented in a derived class | 
 | 		ATLASSERT(FALSE); | 
 | 	} | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedPaintWindowImpl - implements a window that uses buffered paint | 
 |  | 
 | template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CBufferedPaintWindowImpl :  | 
 | 		public ATL::CWindowImpl<T, TBase, TWinTraits>,  | 
 | 		public CBufferedPaintImpl< T > | 
 | { | 
 | public: | 
 | 	BEGIN_MSG_MAP(CBufferedPaintWindowImpl) | 
 | 		CHAIN_MSG_MAP(CBufferedPaintImpl< T >) | 
 | 	END_MSG_MAP() | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedAnimation - support for buffered animation | 
 |  | 
 | class CBufferedAnimation | 
 | { | 
 | public: | 
 | 	HANIMATIONBUFFER m_hAnimationBuffer; | 
 |  | 
 | 	CBufferedAnimation() : m_hAnimationBuffer(NULL) | 
 | 	{ } | 
 |  | 
 | 	~CBufferedAnimation() | 
 | 	{ | 
 | 		ATLVERIFY(SUCCEEDED(End())); | 
 | 	} | 
 |  | 
 | 	bool IsNull() const | 
 | 	{ | 
 | 		return (m_hAnimationBuffer == NULL); | 
 | 	} | 
 |  | 
 | 	HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo) | 
 | 	{ | 
 | 		ATLASSERT(m_hAnimationBuffer == NULL); | 
 | 		m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo); | 
 | 		return m_hAnimationBuffer; | 
 | 	} | 
 |  | 
 | 	HRESULT End(BOOL bUpdate = TRUE) | 
 | 	{ | 
 | 		HRESULT hRet = S_FALSE; | 
 | 		if(m_hAnimationBuffer != NULL) | 
 | 		{ | 
 | 			hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate); | 
 | 			m_hAnimationBuffer = NULL; | 
 | 		} | 
 | 		return hRet; | 
 | 	} | 
 |  | 
 | 	static bool IsRendering(HWND hWnd, HDC hDC) | 
 | 	{ | 
 | 		return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE); | 
 | 	} | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedAnimationImpl - provides buffered animation support for any window | 
 |  | 
 | // Note: You can either use m_State and m_NewState to store the state information | 
 | // for the animation change, or map your state to those data members. DoPaint() | 
 | // should only rely on the state information that is passed to it. | 
 |  | 
 | template <class T, class TState = DWORD_PTR> | 
 | class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase | 
 | { | 
 | public: | 
 | 	BP_BUFFERFORMAT m_dwFormat; | 
 | 	BP_PAINTPARAMS m_PaintParams; | 
 | 	BP_ANIMATIONPARAMS m_AnimationParams; | 
 |  | 
 | 	TState m_State; | 
 | 	TState m_NewState; | 
 |  | 
 | 	CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB) | 
 | 	{ | 
 | 		memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS)); | 
 | 		m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS); | 
 |  | 
 | 		memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS)); | 
 | 		m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS); | 
 | 		m_AnimationParams.style = BPAS_LINEAR; | 
 | 		m_AnimationParams.dwDuration = 500; | 
 |  | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT->SetState(InitialState); | 
 | 		pT->SetNewState(InitialState); | 
 | 	} | 
 |  | 
 | 	DWORD GetDuration() const | 
 | 	{ | 
 | 		return m_AnimationParams.dwDuration; | 
 | 	} | 
 |  | 
 | 	void SetDuration(DWORD dwDuration) | 
 | 	{ | 
 | 		m_AnimationParams.dwDuration = dwDuration; | 
 | 	} | 
 |  | 
 | 	void DoAnimation(TState NewState, const RECT* pRect = NULL) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		pT->SetNewState(NewState); | 
 |  | 
 | 		pT->InvalidateRect(pRect, FALSE); | 
 | 		pT->UpdateWindow(); | 
 |  | 
 | 		pT->SetState(NewState); | 
 | 	} | 
 |  | 
 | // Message map and handlers | 
 | 	BEGIN_MSG_MAP(CBufferedAnimationImpl) | 
 | 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) | 
 | 		MESSAGE_HANDLER(WM_PAINT, OnPaint) | 
 | 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) | 
 | 	END_MSG_MAP() | 
 |  | 
 | 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		return 1;   // no background needed | 
 | 	} | 
 |  | 
 | 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		if(wParam != NULL) | 
 | 		{ | 
 | 			RECT rect = { 0 }; | 
 | 			pT->GetClientRect(&rect); | 
 | 			pT->DoPaint((HDC)wParam, rect, m_NewState); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			CPaintDC dc(pT->m_hWnd); | 
 | 			pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint); | 
 | 		} | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | // Overrideables | 
 | 	void SetState(TState State) | 
 | 	{ | 
 | 		m_State = State; | 
 | 	} | 
 |  | 
 | 	void SetNewState(TState State) | 
 | 	{ | 
 | 		m_NewState = State; | 
 | 	} | 
 |  | 
 | 	bool AreStatesEqual() const | 
 | 	{ | 
 | 		return (m_State == m_NewState); | 
 | 	} | 
 |  | 
 | 	void DoAnimationPaint(CDCHandle dc, RECT& rect) | 
 | 	{ | 
 | 		T* pT = static_cast<T*>(this); | 
 | 		if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc)) | 
 | 			return; | 
 |  | 
 | 		DWORD dwDurationSave = m_AnimationParams.dwDuration; | 
 | 		if(pT->AreStatesEqual()) | 
 | 			m_AnimationParams.dwDuration = 0; | 
 |  | 
 | 		HDC hdcFrom = NULL, hdcTo = NULL; | 
 | 		CBufferedAnimation ba; | 
 | 		if(IsBufferedPaintSupported()) | 
 | 			ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo); | 
 |  | 
 | 		if(!ba.IsNull()) | 
 | 		{ | 
 | 			if(hdcFrom != NULL) | 
 | 				pT->DoPaint(hdcFrom, rect, m_State); | 
 |  | 
 | 			if (hdcTo != NULL) | 
 | 				pT->DoPaint(hdcTo, rect, m_NewState); | 
 | 		} | 
 | 		else | 
 | 		{ | 
 | 			pT->DoPaint(dc.m_hDC, rect, m_NewState); | 
 | 		} | 
 |  | 
 | 		m_AnimationParams.dwDuration = dwDurationSave; | 
 | 	} | 
 |  | 
 | 	void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/) | 
 | 	{ | 
 | 		// must be implemented in a derived class | 
 | 		ATLASSERT(FALSE); | 
 | 	} | 
 | }; | 
 |  | 
 |  | 
 | /////////////////////////////////////////////////////////////////////////////// | 
 | // CBufferedAnimationWindowImpl - implements a window that uses buffered animation | 
 |  | 
 | template <class T, class TState = DWORD_PTR, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> | 
 | class ATL_NO_VTABLE CBufferedAnimationWindowImpl :  | 
 | 		public ATL::CWindowImpl<T, TBase, TWinTraits>,  | 
 | 		public CBufferedAnimationImpl< T, TState > | 
 | { | 
 | public: | 
 | 	CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState) | 
 | 	{ } | 
 |  | 
 | 	typedef CBufferedAnimationImpl< T, TState >   _baseBufferedAnimation; | 
 | 	BEGIN_MSG_MAP(CBufferedAnimationWindowImpl) | 
 | 		CHAIN_MSG_MAP(_baseBufferedAnimation) | 
 | 	END_MSG_MAP() | 
 | }; | 
 |  | 
 | #endif // _WTL_NEW_UXTHEME | 
 |  | 
 | }; // namespace WTL | 
 |  | 
 | #endif // __ATLTHEME_H__ |