1 // Windows Template Library - WTL version 9.10
2 // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Public License (http://opensource.org/licenses/MS-PL)
7 // which can be found in the file MS-PL.txt at the root folder.
8 
9 #ifndef __ATLTHEME_H__
10 #define __ATLTHEME_H__
11 
12 #pragma once
13 
14 #ifdef _WIN32_WCE
15 	#error atltheme.h is not supported on Windows CE
16 #endif
17 
18 #ifndef __ATLAPP_H__
19 	#error atltheme.h requires atlapp.h to be included first
20 #endif
21 
22 #ifndef __ATLWIN_H__
23 	#error atltheme.h requires atlwin.h to be included first
24 #endif
25 
26 #if (_WIN32_WINNT < 0x0501)
27 	#error atltheme.h requires _WIN32_WINNT >= 0x0501
28 #endif // (_WIN32_WINNT < 0x0501)
29 
30 #if defined(_WTL_USE_VSSYM32) || (defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_LONGHORN))
31   #include <vssym32.h>
32 #else
33   #ifndef TMSCHEMA_H
34     #include <tmschema.h>
35   #endif
36 #endif
37 
38 #include <uxtheme.h>
39 #pragma comment(lib, "uxtheme.lib")
40 
41 // Note: To create an application that also runs on older versions of Windows,
42 // use delay load of uxtheme.dll and ensure that no calls to the Theme API are
43 // made if theming is not supported. It is enough to check if m_hTheme is NULL.
44 // Example:
45 //	if(m_hTheme != NULL)
46 //	{
47 //		DrawThemeBackground(dc, BP_PUSHBUTTON, PBS_NORMAL, &rect, NULL);
48 //		DrawThemeText(dc, BP_PUSHBUTTON, PBS_NORMAL, L"Button", -1, DT_SINGLELINE | DT_CENTER | DT_VCENTER, 0, &rect);
49 //	}
50 //	else
51 //	{
52 //		dc.DrawFrameControl(&rect, DFC_BUTTON, DFCS_BUTTONPUSH);
53 //		dc.DrawText(_T("Button"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
54 //	}
55 //
56 // Delay load is NOT AUTOMATIC for VC++ 7, you have to link to delayimp.lib,
57 // and add uxtheme.dll in the Linker.Input.Delay Loaded DLLs section of the
58 // project properties.
59 #if (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)
60   #pragma comment(lib, "delayimp.lib")
61   #pragma comment(linker, "/delayload:uxtheme.dll")
62 #endif // (_MSC_VER < 1300) && !defined(_WTL_NO_THEME_DELAYLOAD)
63 
64 // Hack: Signatures in uxtheme.h changed - the only way to check which variant of uxtheme.h
65 // is included is to check for presence of new defines MAX_THEMECOLOR and MAX_THEMESIZE
66 // Note: In WinSDK 7.0 (and higher) they are defined with #if (_WIN32_WINNT >= 0x0600),
67 // so you have to compile with _WTL_NEW_UXTHEME defined for _WIN32_WINNT < 0x0600
68 #ifndef _WTL_NEW_UXTHEME
69   #if defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)
70     #define _WTL_NEW_UXTHEME
71   #endif // defined(MAX_THEMECOLOR) && defined(MAX_THEMESIZE)
72 #endif // _WTL_NEW_UXTHEME
73 
74 
75 ///////////////////////////////////////////////////////////////////////////////
76 // Classes in this file:
77 //
78 // CTheme
79 // CThemeImpl<T, TBase>
80 //
81 // CBufferedPaint
82 // CBufferedPaintImpl<T>
83 // CBufferedPaintWindowImpl<T, TBase, TWinTraits>
84 // CBufferedAnimation
85 // CBufferedAnimationImpl<T, TState>
86 // CBufferedAnimationWindowImpl<T, TState, TBase, TWinTraits>
87 //
88 // Global functions:
89 //   AtlDrawThemeClientEdge()
90 
91 
92 namespace WTL
93 {
94 
95 ///////////////////////////////////////////////////////////////////////////////
96 // CTheme - wrapper for theme handle
97 
98 class CTheme
99 {
100 public:
101 // Data members
102 	HTHEME m_hTheme;
103 	static int m_nIsThemingSupported;
104 
105 // Constructor
m_hTheme(hTheme)106 	CTheme(HTHEME hTheme = NULL) : m_hTheme(hTheme)
107 	{
108 		IsThemingSupported();
109 	}
110 
111 // Operators and helpers
IsThemeNull()112 	bool IsThemeNull() const
113 	{
114 		return (m_hTheme == NULL);
115 	}
116 
117 	CTheme& operator =(HTHEME hTheme)
118 	{
119 		m_hTheme = hTheme;
120 		return *this;
121 	}
122 
HTHEME()123 	operator HTHEME() const
124 	{
125 		return m_hTheme;
126 	}
127 
Attach(HTHEME hTheme)128 	void Attach(HTHEME hTheme)
129 	{
130 		m_hTheme = hTheme;
131 	}
132 
Detach()133 	HTHEME Detach()
134 	{
135 		HTHEME hTheme = m_hTheme;
136 		m_hTheme = NULL;
137 		return hTheme;
138 	}
139 
140 // Theme support helper
IsThemingSupported()141 	static bool IsThemingSupported()
142 	{
143 		if(m_nIsThemingSupported == -1)
144 		{
145 			CStaticDataInitCriticalSectionLock lock;
146 			if(FAILED(lock.Lock()))
147 			{
148 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CTheme::IsThemingSupported.\n"));
149 				ATLASSERT(FALSE);
150 				return false;
151 			}
152 
153 			if(m_nIsThemingSupported == -1)
154 			{
155 				HMODULE hThemeDLL = ::LoadLibrary(_T("uxtheme.dll"));
156 				m_nIsThemingSupported = (hThemeDLL != NULL) ? 1 : 0;
157 				if(hThemeDLL != NULL)
158 					::FreeLibrary(hThemeDLL);
159 			}
160 
161 			lock.Unlock();
162 		}
163 
164 		ATLASSERT(m_nIsThemingSupported != -1);
165 		return (m_nIsThemingSupported == 1);
166 	}
167 
168 // Operations and theme properties
OpenThemeData(HWND hWnd,LPCWSTR pszClassList)169 	HTHEME OpenThemeData(HWND hWnd, LPCWSTR pszClassList)
170 	{
171 		if(!IsThemingSupported())
172 			return NULL;
173 
174 		ATLASSERT(m_hTheme == NULL);
175 		m_hTheme = ::OpenThemeData(hWnd, pszClassList);
176 		return m_hTheme;
177 	}
178 
CloseThemeData()179 	HRESULT CloseThemeData()
180 	{
181 		HRESULT hRet = S_FALSE;
182 		if(m_hTheme != NULL)
183 		{
184 			hRet = ::CloseThemeData(m_hTheme);
185 			if(SUCCEEDED(hRet))
186 				m_hTheme = NULL;
187 		}
188 		return hRet;
189 	}
190 
191 	HRESULT DrawThemeBackground(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, LPCRECT pClipRect = NULL)
192 	{
193 		ATLASSERT(m_hTheme != NULL);
194 		return ::DrawThemeBackground(m_hTheme, hDC, nPartID, nStateID, pRect, pClipRect);
195 	}
196 
197 // Missing in original uxtheme.h
198 #ifdef DTBG_CLIPRECT
199 	HRESULT DrawThemeBackgroundEx(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, const DTBGOPTS* pOptions = NULL)
200 	{
201 		ATLASSERT(m_hTheme != NULL);
202 		return ::DrawThemeBackgroundEx(m_hTheme, hDC, nPartID, nStateID, pRect, pOptions);
203 	}
204 #endif // DTBG_CLIPRECT
205 
DrawThemeText(HDC hDC,int nPartID,int nStateID,LPCWSTR pszText,int nCharCount,DWORD dwTextFlags,DWORD dwTextFlags2,LPCRECT pRect)206 	HRESULT DrawThemeText(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, DWORD dwTextFlags2, LPCRECT pRect)
207 	{
208 		ATLASSERT(m_hTheme != NULL);
209 		return ::DrawThemeText(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, dwTextFlags2, pRect);
210 	}
211 
GetThemeBackgroundContentRect(HDC hDC,int nPartID,int nStateID,LPCRECT pBoundingRect,LPRECT pContentRect)212 	HRESULT GetThemeBackgroundContentRect(HDC hDC, int nPartID, int nStateID,  LPCRECT pBoundingRect, LPRECT pContentRect) const
213 	{
214 		ATLASSERT(m_hTheme != NULL);
215 		return ::GetThemeBackgroundContentRect(m_hTheme, hDC, nPartID, nStateID,  pBoundingRect, pContentRect);
216 	}
217 
GetThemeBackgroundExtent(HDC hDC,int nPartID,int nStateID,LPCRECT pContentRect,LPRECT pExtentRect)218 	HRESULT GetThemeBackgroundExtent(HDC hDC, int nPartID, int nStateID, LPCRECT pContentRect, LPRECT pExtentRect) const
219 	{
220 		ATLASSERT(m_hTheme != NULL);
221 		return ::GetThemeBackgroundExtent(m_hTheme, hDC, nPartID, nStateID, pContentRect, pExtentRect);
222 	}
223 
GetThemePartSize(HDC hDC,int nPartID,int nStateID,LPCRECT pRect,enum THEMESIZE eSize,LPSIZE pSize)224 	HRESULT GetThemePartSize(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, enum THEMESIZE eSize, LPSIZE pSize) const
225 	{
226 		ATLASSERT(m_hTheme != NULL);
227 #ifdef _WTL_NEW_UXTHEME
228 		return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, pRect, eSize, pSize);
229 #else // !_WTL_NEW_UXTHEME
230 		// Note: The cast to LPRECT is because uxtheme.h incorrectly uses it instead of LPCRECT
231 		return ::GetThemePartSize(m_hTheme, hDC, nPartID, nStateID, (LPRECT)pRect, eSize, pSize);
232 #endif // !_WTL_NEW_UXTHEME
233 	}
234 
GetThemeTextExtent(HDC hDC,int nPartID,int nStateID,LPCWSTR pszText,int nCharCount,DWORD dwTextFlags,LPCRECT pBoundingRect,LPRECT pExtentRect)235 	HRESULT GetThemeTextExtent(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int nCharCount, DWORD dwTextFlags, LPCRECT  pBoundingRect, LPRECT pExtentRect) const
236 	{
237 		ATLASSERT(m_hTheme != NULL);
238 		return ::GetThemeTextExtent(m_hTheme, hDC, nPartID, nStateID, pszText, nCharCount, dwTextFlags, pBoundingRect, pExtentRect);
239 	}
240 
GetThemeTextMetrics(HDC hDC,int nPartID,int nStateID,PTEXTMETRICW pTextMetric)241 	HRESULT GetThemeTextMetrics(HDC hDC, int nPartID, int nStateID, PTEXTMETRICW pTextMetric) const
242 	{
243 		ATLASSERT(m_hTheme != NULL);
244 #ifdef _WTL_NEW_UXTHEME
245 		return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, pTextMetric);
246 #else // !_WTL_NEW_UXTHEME
247 		// Note: The cast to PTEXTMETRIC is because uxtheme.h incorrectly uses it instead of PTEXTMETRICW
248 		return ::GetThemeTextMetrics(m_hTheme, hDC, nPartID, nStateID, (PTEXTMETRIC)pTextMetric);
249 #endif // !_WTL_NEW_UXTHEME
250 	}
251 
GetThemeBackgroundRegion(HDC hDC,int nPartID,int nStateID,LPCRECT pRect,HRGN * pRegion)252 	HRESULT GetThemeBackgroundRegion(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HRGN* pRegion) const
253 	{
254 		ATLASSERT(m_hTheme != NULL);
255 		return ::GetThemeBackgroundRegion(m_hTheme, hDC, nPartID, nStateID, pRect, pRegion);
256 	}
257 
HitTestThemeBackground(HDC hDC,int nPartID,int nStateID,DWORD dwOptions,LPCRECT pRect,HRGN hrgn,POINT ptTest,WORD * pwHitTestCode)258 	HRESULT HitTestThemeBackground(HDC hDC, int nPartID, int nStateID, DWORD dwOptions, LPCRECT pRect, HRGN hrgn, POINT ptTest, WORD* pwHitTestCode) const
259 	{
260 		ATLASSERT(m_hTheme != NULL);
261 		return ::HitTestThemeBackground(m_hTheme, hDC, nPartID, nStateID, dwOptions, pRect, hrgn, ptTest, pwHitTestCode);
262 	}
263 
264 	HRESULT DrawThemeEdge(HDC hDC, int nPartID, int nStateID, LPCRECT pDestRect, UINT uEdge, UINT uFlags, LPRECT pContentRect = NULL)
265 	{
266 		ATLASSERT(m_hTheme != NULL);
267 		return ::DrawThemeEdge(m_hTheme, hDC, nPartID, nStateID, pDestRect, uEdge, uFlags, pContentRect);
268 	}
269 
DrawThemeIcon(HDC hDC,int nPartID,int nStateID,LPCRECT pRect,HIMAGELIST himl,int nImageIndex)270 	HRESULT DrawThemeIcon(HDC hDC, int nPartID, int nStateID, LPCRECT pRect, HIMAGELIST himl, int nImageIndex)
271 	{
272 		ATLASSERT(m_hTheme != NULL);
273 		return ::DrawThemeIcon(m_hTheme, hDC, nPartID, nStateID, pRect, himl, nImageIndex);
274 	}
275 
IsThemePartDefined(int nPartID,int nStateID)276 	BOOL IsThemePartDefined(int nPartID, int nStateID) const
277 	{
278 		ATLASSERT(m_hTheme != NULL);
279 		return ::IsThemePartDefined(m_hTheme, nPartID, nStateID);
280 	}
281 
IsThemeBackgroundPartiallyTransparent(int nPartID,int nStateID)282 	BOOL IsThemeBackgroundPartiallyTransparent(int nPartID, int nStateID) const
283 	{
284 		ATLASSERT(m_hTheme != NULL);
285 		return ::IsThemeBackgroundPartiallyTransparent(m_hTheme, nPartID, nStateID);
286 	}
287 
GetThemeColor(int nPartID,int nStateID,int nPropID,COLORREF * pColor)288 	HRESULT GetThemeColor(int nPartID, int nStateID, int nPropID, COLORREF* pColor) const
289 	{
290 		ATLASSERT(m_hTheme != NULL);
291 		return ::GetThemeColor(m_hTheme, nPartID, nStateID, nPropID, pColor);
292 	}
293 
GetThemeMetric(HDC hDC,int nPartID,int nStateID,int nPropID,int * pnVal)294 	HRESULT GetThemeMetric(HDC hDC, int nPartID, int nStateID, int nPropID, int* pnVal) const
295 	{
296 		ATLASSERT(m_hTheme != NULL);
297 		return ::GetThemeMetric(m_hTheme, hDC, nPartID, nStateID, nPropID, pnVal);
298 	}
299 
GetThemeString(int nPartID,int nStateID,int nPropID,LPWSTR pszBuff,int cchMaxBuffChars)300 	HRESULT GetThemeString(int nPartID, int nStateID, int nPropID, LPWSTR pszBuff, int cchMaxBuffChars) const
301 	{
302 		ATLASSERT(m_hTheme != NULL);
303 		return ::GetThemeString(m_hTheme, nPartID, nStateID, nPropID, pszBuff, cchMaxBuffChars);
304 	}
305 
GetThemeBool(int nPartID,int nStateID,int nPropID,BOOL * pfVal)306 	HRESULT GetThemeBool(int nPartID, int nStateID, int nPropID, BOOL* pfVal) const
307 	{
308 		ATLASSERT(m_hTheme != NULL);
309 		return ::GetThemeBool(m_hTheme, nPartID, nStateID, nPropID, pfVal);
310 	}
311 
GetThemeInt(int nPartID,int nStateID,int nPropID,int * pnVal)312 	HRESULT GetThemeInt(int nPartID, int nStateID, int nPropID, int* pnVal) const
313 	{
314 		ATLASSERT(m_hTheme != NULL);
315 		return ::GetThemeInt(m_hTheme, nPartID, nStateID, nPropID, pnVal);
316 	}
317 
GetThemeEnumValue(int nPartID,int nStateID,int nPropID,int * pnVal)318 	HRESULT GetThemeEnumValue(int nPartID, int nStateID, int nPropID, int* pnVal) const
319 	{
320 		ATLASSERT(m_hTheme != NULL);
321 		return ::GetThemeEnumValue(m_hTheme, nPartID, nStateID, nPropID, pnVal);
322 	}
323 
GetThemePosition(int nPartID,int nStateID,int nPropID,LPPOINT pPoint)324 	HRESULT GetThemePosition(int nPartID, int nStateID, int nPropID, LPPOINT pPoint) const
325 	{
326 		ATLASSERT(m_hTheme != NULL);
327 		return ::GetThemePosition(m_hTheme, nPartID, nStateID, nPropID, pPoint);
328 	}
329 
330 	// deprecated
GetThemeFont(int nPartID,HDC hDC,int nStateID,int nPropID,LOGFONTW * pFont)331 	HRESULT GetThemeFont(int nPartID, HDC hDC, int nStateID, int nPropID, LOGFONTW* pFont) const
332 	{
333 		ATLASSERT(m_hTheme != NULL);
334 #ifdef _WTL_NEW_UXTHEME
335 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
336 #else // !_WTL_NEW_UXTHEME
337 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
338 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);
339 #endif // !_WTL_NEW_UXTHEME
340 	}
341 
GetThemeFont(HDC hDC,int nPartID,int nStateID,int nPropID,LOGFONTW * pFont)342 	HRESULT GetThemeFont(HDC hDC, int nPartID, int nStateID, int nPropID, LOGFONTW* pFont) const
343 	{
344 		ATLASSERT(m_hTheme != NULL);
345 #ifdef _WTL_NEW_UXTHEME
346 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, pFont);
347 #else // !_WTL_NEW_UXTHEME
348 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
349 		return ::GetThemeFont(m_hTheme, hDC, nPartID, nStateID, nPropID, (LOGFONT*)pFont);
350 #endif // !_WTL_NEW_UXTHEME
351 	}
352 
GetThemeRect(int nPartID,int nStateID,int nPropID,LPRECT pRect)353 	HRESULT GetThemeRect(int nPartID, int nStateID, int nPropID, LPRECT pRect) const
354 	{
355 		ATLASSERT(m_hTheme != NULL);
356 		return ::GetThemeRect(m_hTheme, nPartID, nStateID, nPropID, pRect);
357 	}
358 
GetThemeMargins(HDC hDC,int nPartID,int nStateID,int nPropID,LPRECT pRect,PMARGINS pMargins)359 	HRESULT GetThemeMargins(HDC hDC, int nPartID, int nStateID, int nPropID, LPRECT pRect, PMARGINS pMargins) const
360 	{
361 		ATLASSERT(m_hTheme != NULL);
362 		return ::GetThemeMargins(m_hTheme, hDC, nPartID, nStateID, nPropID, pRect, pMargins);
363 	}
364 
GetThemeIntList(int nPartID,int nStateID,int nPropID,INTLIST * pIntList)365 	HRESULT GetThemeIntList(int nPartID, int nStateID, int nPropID, INTLIST* pIntList) const
366 	{
367 		ATLASSERT(m_hTheme != NULL);
368 		return ::GetThemeIntList(m_hTheme, nPartID, nStateID, nPropID, pIntList);
369 	}
370 
GetThemePropertyOrigin(int nPartID,int nStateID,int nPropID,enum PROPERTYORIGIN * pOrigin)371 	HRESULT GetThemePropertyOrigin(int nPartID, int nStateID, int nPropID, enum PROPERTYORIGIN* pOrigin) const
372 	{
373 		ATLASSERT(m_hTheme != NULL);
374 		return ::GetThemePropertyOrigin(m_hTheme, nPartID, nStateID, nPropID, pOrigin);
375 	}
376 
GetThemeFilename(int nPartID,int nStateID,int nPropID,LPWSTR pszThemeFileName,int cchMaxBuffChars)377 	HRESULT GetThemeFilename(int nPartID, int nStateID, int nPropID, LPWSTR pszThemeFileName, int cchMaxBuffChars) const
378 	{
379 		ATLASSERT(m_hTheme != NULL);
380 		return ::GetThemeFilename(m_hTheme, nPartID, nStateID, nPropID, pszThemeFileName, cchMaxBuffChars);
381 	}
382 
GetThemeSysColor(int nColorID)383 	COLORREF GetThemeSysColor(int nColorID) const
384 	{
385 		ATLASSERT(m_hTheme != NULL);
386 		return ::GetThemeSysColor(m_hTheme, nColorID);
387 	}
388 
GetThemeSysColorBrush(int nColorID)389 	HBRUSH GetThemeSysColorBrush(int nColorID) const
390 	{
391 		ATLASSERT(m_hTheme != NULL);
392 		return ::GetThemeSysColorBrush(m_hTheme, nColorID);
393 	}
394 
GetThemeSysSize(int nSizeID)395 	int GetThemeSysSize(int nSizeID) const
396 	{
397 		ATLASSERT(m_hTheme != NULL);
398 		return ::GetThemeSysSize(m_hTheme, nSizeID);
399 	}
400 
GetThemeSysBool(int nBoolID)401 	BOOL GetThemeSysBool(int nBoolID) const
402 	{
403 		ATLASSERT(m_hTheme != NULL);
404 		return ::GetThemeSysBool(m_hTheme, nBoolID);
405 	}
406 
GetThemeSysFont(int nFontID,LOGFONTW * plf)407 	HRESULT GetThemeSysFont(int nFontID, LOGFONTW* plf) const
408 	{
409 		ATLASSERT(m_hTheme != NULL);
410 #ifdef _WTL_NEW_UXTHEME
411 		return ::GetThemeSysFont(m_hTheme, nFontID, plf);
412 #else // !_WTL_NEW_UXTHEME
413 		// Note: The cast to LOGFONT* is because uxtheme.h incorrectly uses it instead of LOGFONTW*
414 		return ::GetThemeSysFont(m_hTheme, nFontID, (LOGFONT*)plf);
415 #endif // !_WTL_NEW_UXTHEME
416 	}
417 
GetThemeSysString(int nStringID,LPWSTR pszStringBuff,int cchMaxStringChars)418 	HRESULT GetThemeSysString(int nStringID, LPWSTR pszStringBuff, int cchMaxStringChars) const
419 	{
420 		ATLASSERT(m_hTheme != NULL);
421 		return ::GetThemeSysString(m_hTheme, nStringID, pszStringBuff, cchMaxStringChars);
422 	}
423 
GetThemeSysInt(int nIntID,int * pnValue)424 	HRESULT GetThemeSysInt(int nIntID, int* pnValue) const
425 	{
426 		ATLASSERT(m_hTheme != NULL);
427 		return ::GetThemeSysInt(m_hTheme, nIntID, pnValue);
428 	}
429 
430 #ifdef _WTL_NEW_UXTHEME
OpenThemeDataEx(HWND hWnd,LPCWSTR pszClassList,DWORD dwFlags)431 	HTHEME OpenThemeDataEx(HWND hWnd, LPCWSTR pszClassList, DWORD dwFlags)
432 	{
433 		if(!IsThemingSupported())
434 			return NULL;
435 
436 		ATLASSERT(m_hTheme == NULL);
437 		m_hTheme = ::OpenThemeDataEx(hWnd, pszClassList, dwFlags);
438 		return m_hTheme;
439 	}
440 
441 #if (_WIN32_WINNT >= 0x0600)
DrawThemeTextEx(HDC hDC,int nPartID,int nStateID,LPCWSTR pszText,int cchText,DWORD dwTextFlags,LPRECT lpRect,const DTTOPTS * pOptions)442 	HRESULT DrawThemeTextEx(HDC hDC, int nPartID, int nStateID, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT lpRect, const DTTOPTS* pOptions)
443 	{
444 		ATLASSERT(m_hTheme != NULL);
445 		return ::DrawThemeTextEx(m_hTheme, hDC, nPartID, nStateID, pszText, cchText, dwTextFlags, lpRect, pOptions);
446 	}
447 
GetThemeTransitionDuration(int nPartID,int nFromStateID,int nToStateID,int nPropID,DWORD & dwDuration)448 	HRESULT GetThemeTransitionDuration(int nPartID, int nFromStateID, int nToStateID, int nPropID, DWORD& dwDuration)
449 	{
450 		ATLASSERT(m_hTheme != NULL);
451 		return ::GetThemeTransitionDuration(m_hTheme, nPartID, nFromStateID, nToStateID, nPropID, &dwDuration);
452 	}
453 #endif // (_WIN32_WINNT >= 0x0600)
454 #endif // _WTL_NEW_UXTHEME
455 
456 #if (_WIN32_WINNT >= 0x0600)
GetThemeBitmap(int nPartID,int nStateID,int nPropID,ULONG uFlags,HBITMAP & hBitmap)457 	HRESULT GetThemeBitmap(int nPartID, int nStateID, int nPropID, ULONG uFlags, HBITMAP& hBitmap)
458 	{
459 		ATLASSERT(m_hTheme != NULL);
460 		return ::GetThemeBitmap(m_hTheme, nPartID, nStateID, nPropID, uFlags, &hBitmap);
461 	}
462 
GetThemeStream(int nPartID,int nStateID,int nPropID,VOID ** ppvStream,DWORD * pcbStream,HINSTANCE hInstance)463 	HRESULT GetThemeStream(int nPartID, int nStateID, int nPropID, VOID** ppvStream, DWORD* pcbStream, HINSTANCE hInstance)
464 	{
465 		ATLASSERT(m_hTheme != NULL);
466 		return ::GetThemeStream(m_hTheme, nPartID, nStateID, nPropID, ppvStream, pcbStream, hInstance);
467 	}
468 #endif // (_WIN32_WINNT >= 0x0600)
469 
470 #if (_WIN32_WINNT >= 0x0602)
GetThemeAnimationProperty(int iStoryboardId,int iTargetId,TA_PROPERTY eProperty,VOID * pvProperty,DWORD cbSize,DWORD * pcbSizeOut)471 	HRESULT GetThemeAnimationProperty(int iStoryboardId, int iTargetId, TA_PROPERTY eProperty, VOID* pvProperty, DWORD cbSize, DWORD* pcbSizeOut)
472 	{
473 		ATLASSERT(m_hTheme != NULL);
474 		return ::GetThemeAnimationProperty(m_hTheme, iStoryboardId, iTargetId, eProperty, pvProperty, cbSize, pcbSizeOut);
475 	}
476 
GetThemeAnimationTransform(int iStoryboardId,int iTargetId,DWORD dwTransformIndex,TA_TRANSFORM * pTransform,DWORD cbSize,DWORD * pcbSizeOut)477 	HRESULT GetThemeAnimationTransform(int iStoryboardId, int iTargetId, DWORD dwTransformIndex, TA_TRANSFORM* pTransform, DWORD cbSize, DWORD* pcbSizeOut)
478 	{
479 		ATLASSERT(m_hTheme != NULL);
480 		return ::GetThemeAnimationTransform(m_hTheme, iStoryboardId, iTargetId, dwTransformIndex, pTransform, cbSize, pcbSizeOut);
481 	}
482 
GetThemeTimingFunction(int iTimingFunctionId,TA_TIMINGFUNCTION * pTimingFunction,DWORD cbSize,DWORD * pcbSizeOut)483 	HRESULT GetThemeTimingFunction(int iTimingFunctionId, TA_TIMINGFUNCTION* pTimingFunction, DWORD cbSize, DWORD* pcbSizeOut)
484 	{
485 		ATLASSERT(m_hTheme != NULL);
486 		return ::GetThemeTimingFunction(m_hTheme, iTimingFunctionId, pTimingFunction, cbSize, pcbSizeOut);
487 	}
488 #endif // (_WIN32_WINNT >= 0x0602)
489 };
490 
491 __declspec(selectany) int CTheme::m_nIsThemingSupported = -1;
492 
493 
494 ///////////////////////////////////////////////////////////////////////////////
495 // CThemeImpl - theme support implementation
496 
497 // Derive from this class to implement window with theme support.
498 // Example:
499 //	class CMyThemeWindow : public CWindowImpl<CMyThemeWindow>, public CThemeImpl<CMyThemeWindow>
500 //	{
501 //	...
502 //		BEGIN_MSG_MAP(CMyThemeWindow)
503 //			CHAIN_MSG_MAP(CThemeImpl<CMyThemeWindow>)
504 //			...
505 //		END_MSG_MAP()
506 //	...
507 //	};
508 //
509 // If you set theme class list, the class will automaticaly open/close/reopen theme data.
510 
511 
512 // Helper for drawing theme client edge
513 inline bool AtlDrawThemeClientEdge(HTHEME hTheme, HWND hWnd, HRGN hRgnUpdate = NULL, HBRUSH hBrush = NULL, int nPartID = 0, int nStateID = 0)
514 {
515 	ATLASSERT(hTheme != NULL);
516 	ATLASSERT(::IsWindow(hWnd));
517 
518 	CWindowDC dc(hWnd);
519 	if(dc.IsNull())
520 		return false;
521 
522 	// Get border size
523 	int cxBorder = ::GetSystemMetrics(SM_CXBORDER);
524 	int cyBorder = ::GetSystemMetrics(SM_CYBORDER);
525 	if(SUCCEEDED(::GetThemeInt(hTheme, nPartID, nStateID, TMT_SIZINGBORDERWIDTH, &cxBorder)))
526 		cyBorder = cxBorder;
527 
528 	RECT rect = { 0 };
529 	::GetWindowRect(hWnd, &rect);
530 
531 	// Remove the client edge from the update region
532 	int cxEdge = ::GetSystemMetrics(SM_CXEDGE);
533 	int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
534 	::InflateRect(&rect, -cxEdge, -cyEdge);
535 	CRgn rgn;
536 	rgn.CreateRectRgnIndirect(&rect);
537 	if(rgn.IsNull())
538 		return false;
539 
540 	if(hRgnUpdate != NULL)
541 		rgn.CombineRgn(hRgnUpdate, rgn, RGN_AND);
542 
543 	::OffsetRect(&rect, -rect.left, -rect.top);
544 
545 	::OffsetRect(&rect, cxEdge, cyEdge);
546 	dc.ExcludeClipRect(&rect);
547 	::InflateRect(&rect, cxEdge, cyEdge);
548 
549 	::DrawThemeBackground(hTheme, dc, nPartID, nStateID, &rect, NULL);
550 
551 	// Use background brush too, since theme border might not cover everything
552 	if((cxBorder < cxEdge) && (cyBorder < cyEdge))
553 	{
554 		if(hBrush == NULL)
555 // need conditional code because types don't match in winuser.h
556 #ifdef _WIN64
557 			hBrush = (HBRUSH)::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND);
558 #else
559 			hBrush = (HBRUSH)UlongToPtr(::GetClassLongPtr(hWnd, GCLP_HBRBACKGROUND));
560 #endif
561 
562 		::InflateRect(&rect, cxBorder - cxEdge, cyBorder - cyEdge);
563 		dc.FillRect(&rect, hBrush);
564 	}
565 
566 	::DefWindowProc(hWnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0L);
567 
568 	return true;
569 }
570 
571 
572 // Theme extended styles
573 #define THEME_EX_3DCLIENTEDGE		0x00000001
574 #define THEME_EX_THEMECLIENTEDGE	0x00000002
575 
576 template <class T, class TBase = CTheme>
577 class CThemeImpl : public TBase
578 {
579 public:
580 // Data members
581 	LPWSTR m_lpstrThemeClassList;
582 	DWORD m_dwExtendedStyle;   // theme specific extended styles
583 
584 // Constructor & destructor
CThemeImpl()585 	CThemeImpl() : m_lpstrThemeClassList(NULL), m_dwExtendedStyle(0)
586 	{ }
587 
~CThemeImpl()588 	~CThemeImpl()
589 	{
590 		delete [] m_lpstrThemeClassList;
591 	}
592 
593 // Attributes
SetThemeClassList(LPCWSTR lpstrThemeClassList)594 	bool SetThemeClassList(LPCWSTR lpstrThemeClassList)
595 	{
596 		if(m_lpstrThemeClassList != NULL)
597 		{
598 			delete [] m_lpstrThemeClassList;
599 			m_lpstrThemeClassList = NULL;
600 		}
601 
602 		if(lpstrThemeClassList == NULL)
603 			return true;
604 
605 		int cchLen = lstrlenW(lpstrThemeClassList) + 1;
606 		ATLTRY(m_lpstrThemeClassList = new WCHAR[cchLen]);
607 		if(m_lpstrThemeClassList == NULL)
608 			return false;
609 
610 		SecureHelper::strcpyW_x(m_lpstrThemeClassList, cchLen, lpstrThemeClassList);
611 
612 		return true;
613 	}
614 
GetThemeClassList(LPWSTR lpstrThemeClassList,int cchListBuffer)615 	bool GetThemeClassList(LPWSTR lpstrThemeClassList, int cchListBuffer) const
616 	{
617 		int cchLen = lstrlenW(m_lpstrThemeClassList) + 1;
618 		if(cchListBuffer < cchLen)
619 			return false;
620 
621 		SecureHelper::strcpyW_x(lpstrThemeClassList, cchListBuffer, m_lpstrThemeClassList);
622 
623 		return true;
624 	}
625 
GetThemeClassList()626 	LPCWSTR GetThemeClassList() const
627 	{
628 		return m_lpstrThemeClassList;
629 	}
630 
631 	DWORD SetThemeExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
632 	{
633 		DWORD dwPrevStyle = m_dwExtendedStyle;
634 		if(dwMask == 0)
635 			m_dwExtendedStyle = dwExtendedStyle;
636 		else
637 			m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
638 
639 		return dwPrevStyle;
640 	}
641 
GetThemeExtendedStyle()642 	DWORD GetThemeExtendedStyle() const
643 	{
644 		return m_dwExtendedStyle;
645 	}
646 
647 // Operations
OpenThemeData()648 	HTHEME OpenThemeData()
649 	{
650 		T* pT = static_cast<T*>(this);
651 		ATLASSERT(::IsWindow(pT->m_hWnd));
652 		ATLASSERT(m_lpstrThemeClassList != NULL);
653 		if(m_lpstrThemeClassList == NULL)
654 			return NULL;
655 		CloseThemeData();
656 
657 		return TBase::OpenThemeData(pT->m_hWnd, m_lpstrThemeClassList);
658 	}
659 
OpenThemeData(LPCWSTR pszClassList)660 	HTHEME OpenThemeData(LPCWSTR pszClassList)
661 	{
662 		if(!SetThemeClassList(pszClassList))
663 			return NULL;
664 
665 		return OpenThemeData();
666 	}
667 
SetWindowTheme(LPCWSTR pszSubAppName,LPCWSTR pszSubIDList)668 	HRESULT SetWindowTheme(LPCWSTR pszSubAppName, LPCWSTR pszSubIDList)
669 	{
670 		if(!IsThemingSupported())
671 			return S_FALSE;
672 
673 		T* pT = static_cast<T*>(this);
674 		ATLASSERT(::IsWindow(pT->m_hWnd));
675 		return ::SetWindowTheme(pT->m_hWnd, pszSubAppName, pszSubIDList);
676 	}
677 
GetWindowTheme()678 	HTHEME GetWindowTheme() const
679 	{
680 		if(!IsThemingSupported())
681 			return NULL;
682 
683 		const T* pT = static_cast<const T*>(this);
684 		ATLASSERT(::IsWindow(pT->m_hWnd));
685 		return ::GetWindowTheme(pT->m_hWnd);
686 	}
687 
EnableThemeDialogTexture(DWORD dwFlags)688 	HRESULT EnableThemeDialogTexture(DWORD dwFlags)
689 	{
690 		if(!IsThemingSupported())
691 			return S_FALSE;
692 
693 		T* pT = static_cast<T*>(this);
694 		ATLASSERT(::IsWindow(pT->m_hWnd));
695 		return ::EnableThemeDialogTexture(pT->m_hWnd, dwFlags);
696 	}
697 
IsThemeDialogTextureEnabled()698 	BOOL IsThemeDialogTextureEnabled() const
699 	{
700 		if(!IsThemingSupported())
701 			return FALSE;
702 
703 		const T* pT = static_cast<const T*>(this);
704 		ATLASSERT(::IsWindow(pT->m_hWnd));
705 		return ::IsThemeDialogTextureEnabled(pT->m_hWnd);
706 	}
707 
708 	HRESULT DrawThemeParentBackground(HDC hDC, const RECT* pRect = NULL)
709 	{
710 		if(!IsThemingSupported())
711 			return S_FALSE;
712 
713 		T* pT = static_cast<T*>(this);
714 		ATLASSERT(::IsWindow(pT->m_hWnd));
715 #ifdef _WTL_NEW_UXTHEME
716 		return ::DrawThemeParentBackground(pT->m_hWnd, hDC, pRect);
717 #else
718 		return ::DrawThemeParentBackground(pT->m_hWnd, hDC, (RECT*)pRect);
719 #endif
720 	}
721 
722 #if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)
SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type,PVOID pvAttribute,DWORD cbAttribute)723 	HRESULT SetWindowThemeAttribute(WINDOWTHEMEATTRIBUTETYPE type, PVOID pvAttribute, DWORD cbAttribute)
724 	{
725 		if(!IsThemingSupported())
726 			return S_FALSE;
727 
728 		T* pT = static_cast<T*>(this);
729 		ATLASSERT(::IsWindow(pT->m_hWnd));
730 		return ::SetWindowThemeAttribute(pT->m_hWnd, type, pvAttribute, cbAttribute);
731 	}
732 
SetWindowThemeNonClientAttributes(DWORD dwAttributes,DWORD dwMask)733 	HRESULT SetWindowThemeNonClientAttributes(DWORD dwAttributes, DWORD dwMask)
734 	{
735 		if(!IsThemingSupported())
736 			return S_FALSE;
737 
738 		T* pT = static_cast<T*>(this);
739 		ATLASSERT(::IsWindow(pT->m_hWnd));
740 		WTA_OPTIONS opt = { dwAttributes, dwMask };
741 		return ::SetWindowThemeAttribute(pT->m_hWnd, WTA_NONCLIENT, (PVOID)&opt, sizeof(opt));
742 	}
743 
744 	HRESULT DrawThemeParentBackgroundEx(HDC hDC, DWORD dwFlags, const RECT* lpRect = NULL)
745 	{
746 		if(!IsThemingSupported())
747 			return S_FALSE;
748 
749 		T* pT = static_cast<T*>(this);
750 		ATLASSERT(::IsWindow(pT->m_hWnd));
751 		return ::DrawThemeParentBackgroundEx(pT->m_hWnd, hDC, dwFlags, lpRect);
752 	}
753 #endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)
754 
755 // Message map and handlers
756 	// Note: If you handle any of these messages in your derived class,
757 	// it is better to put CHAIN_MSG_MAP at the start of your message map.
758 	BEGIN_MSG_MAP(CThemeImpl)
MESSAGE_HANDLER(WM_CREATE,OnCreate)759 		MESSAGE_HANDLER(WM_CREATE, OnCreate)
760 		MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
761 		MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
762 		MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
763 	END_MSG_MAP()
764 
765 	LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
766 	{
767 		if(m_lpstrThemeClassList != NULL)
768 			OpenThemeData();
769 
770 		bHandled = FALSE;
771 		return 1;
772 	}
773 
OnDestroy(UINT,WPARAM,LPARAM,BOOL & bHandled)774 	LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
775 	{
776 		CloseThemeData();
777 
778 		bHandled = FALSE;
779 		return 1;
780 	}
781 
OnThemeChanged(UINT,WPARAM,LPARAM,BOOL & bHandled)782 	LRESULT OnThemeChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
783 	{
784 		CloseThemeData();
785 		if(m_lpstrThemeClassList != NULL)
786 			OpenThemeData();
787 
788 		bHandled = FALSE;
789 		return 1;
790 	}
791 
OnNcPaint(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL & bHandled)792 	LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
793 	{
794 		T* pT = static_cast<T*>(this);
795 		ATLASSERT(::IsWindow(pT->m_hWnd));
796 		LRESULT lRet = 0;
797 		bHandled = FALSE;
798 		if(IsThemingSupported() && ((pT->GetExStyle() & WS_EX_CLIENTEDGE) != 0))
799 		{
800 			if((m_dwExtendedStyle & THEME_EX_3DCLIENTEDGE) != 0)
801 			{
802 				lRet = ::DefWindowProc(pT->m_hWnd, uMsg, wParam, lParam);
803 				bHandled = TRUE;
804 			}
805 			else if((m_hTheme != NULL) && ((m_dwExtendedStyle & THEME_EX_THEMECLIENTEDGE) != 0))
806 			{
807 				HRGN hRgn = (wParam != 1) ? (HRGN)wParam : NULL;
808 				if(pT->DrawThemeClientEdge(hRgn))
809 					bHandled = TRUE;
810 			}
811 		}
812 
813 		return lRet;
814 	}
815 
816 // Drawing helper
DrawThemeClientEdge(HRGN hRgnUpdate)817 	bool DrawThemeClientEdge(HRGN hRgnUpdate)
818 	{
819 		T* pT = static_cast<T*>(this);
820 		return AtlDrawThemeClientEdge(m_hTheme, pT->m_hWnd, hRgnUpdate, NULL, 0, 0);
821 	}
822 };
823 
824 ///////////////////////////////////////////////////////////////////////////////
825 // Buffered Paint and Animation
826 
827 #if defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)
828 
829 ///////////////////////////////////////////////////////////////////////////////
830 // CBufferedPaintBase - Buffered Paint support for othe classes
831 
832 class CBufferedPaintBase
833 {
834 public:
835 	static int m_nIsBufferedPaintSupported;
836 
CBufferedPaintBase()837 	CBufferedPaintBase()
838 	{
839 		if(IsBufferedPaintSupported())
840 			ATLVERIFY(SUCCEEDED(::BufferedPaintInit()));
841 	}
842 
~CBufferedPaintBase()843 	~CBufferedPaintBase()
844 	{
845 		if(IsBufferedPaintSupported())
846 			ATLVERIFY(SUCCEEDED(::BufferedPaintUnInit()));
847 	}
848 
IsBufferedPaintSupported()849 	static bool IsBufferedPaintSupported()
850 	{
851 		if(m_nIsBufferedPaintSupported == -1)
852 		{
853 			CStaticDataInitCriticalSectionLock lock;
854 			if(FAILED(lock.Lock()))
855 			{
856 				ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CBufferedPaintBase::IsBufferedPaintSupported.\n"));
857 				ATLASSERT(FALSE);
858 				return false;
859 			}
860 
861 			if(m_nIsBufferedPaintSupported == -1)
862 				m_nIsBufferedPaintSupported = RunTimeHelper::IsVista() ? 1 : 0;
863 
864 			lock.Unlock();
865 		}
866 
867 		ATLASSERT(m_nIsBufferedPaintSupported != -1);
868 		return (m_nIsBufferedPaintSupported == 1);
869 	}
870 };
871 
872 __declspec(selectany) int CBufferedPaintBase::m_nIsBufferedPaintSupported = -1;
873 
874 
875 ///////////////////////////////////////////////////////////////////////////////
876 // CBufferedPaint - support for buffered paint functions
877 
878 class CBufferedPaint
879 {
880 public:
881 	HPAINTBUFFER m_hPaintBuffer;
882 
CBufferedPaint()883 	CBufferedPaint() : m_hPaintBuffer(NULL)
884 	{ }
885 
~CBufferedPaint()886 	~CBufferedPaint()
887 	{
888 		ATLVERIFY(SUCCEEDED(End()));
889 	}
890 
IsNull()891 	bool IsNull() const
892 	{
893 		return (m_hPaintBuffer == NULL);
894 	}
895 
Begin(HDC hdcTarget,const RECT * prcTarget,BP_BUFFERFORMAT dwFormat,BP_PAINTPARAMS * pPaintParams,HDC * phdcPaint)896 	HPAINTBUFFER Begin(HDC hdcTarget, const RECT* prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, HDC* phdcPaint)
897 	{
898 		ATLASSERT(m_hPaintBuffer == NULL);
899 		m_hPaintBuffer = ::BeginBufferedPaint(hdcTarget, prcTarget, dwFormat, pPaintParams, phdcPaint);
900 		return m_hPaintBuffer;
901 	}
902 
903 	HRESULT End(BOOL bUpdate = TRUE)
904 	{
905 		HRESULT hRet = S_FALSE;
906 		if(m_hPaintBuffer != NULL)
907 		{
908 			hRet = ::EndBufferedPaint(m_hPaintBuffer, bUpdate);
909 			m_hPaintBuffer = NULL;
910 		}
911 		return hRet;
912 	}
913 
GetTargetRect(LPRECT pRect)914 	HRESULT GetTargetRect(LPRECT pRect) const
915 	{
916 		ATLASSERT(m_hPaintBuffer != NULL);
917 		return ::GetBufferedPaintTargetRect(m_hPaintBuffer, pRect);
918 	}
919 
GetTargetDC()920 	HDC GetTargetDC() const
921 	{
922 		ATLASSERT(m_hPaintBuffer != NULL);
923 		return ::GetBufferedPaintTargetDC(m_hPaintBuffer);
924 	}
925 
GetPaintDC()926 	HDC GetPaintDC() const
927 	{
928 		ATLASSERT(m_hPaintBuffer != NULL);
929 		return ::GetBufferedPaintDC(m_hPaintBuffer);
930 	}
931 
GetBits(RGBQUAD ** ppbBuffer,int * pcxRow)932 	HRESULT GetBits(RGBQUAD** ppbBuffer, int* pcxRow) const
933 	{
934 		ATLASSERT(m_hPaintBuffer != NULL);
935 		return ::GetBufferedPaintBits(m_hPaintBuffer, ppbBuffer, pcxRow);
936 	}
937 
938 	HRESULT Clear(const RECT* pRect = NULL)
939 	{
940 		ATLASSERT(m_hPaintBuffer != NULL);
941 		return ::BufferedPaintClear(m_hPaintBuffer, pRect);
942 	}
943 
944 	HRESULT SetAlpha(BYTE alpha, const RECT* pRect = NULL)
945 	{
946 		ATLASSERT(m_hPaintBuffer != NULL);
947 		return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, alpha);
948 	}
949 
950 	HRESULT MakeOpaque(const RECT* pRect = NULL)
951 	{
952 		ATLASSERT(m_hPaintBuffer != NULL);
953 		return ::BufferedPaintSetAlpha(m_hPaintBuffer, pRect, 255);
954 	}
955 };
956 
957 
958 ///////////////////////////////////////////////////////////////////////////////
959 // CBufferedPaintImpl - provides buffered paint for any window
960 
961 template <class T>
962 class ATL_NO_VTABLE CBufferedPaintImpl : public CBufferedPaintBase
963 {
964 public:
965 	CBufferedPaint m_BufferedPaint;
966 	BP_BUFFERFORMAT m_dwFormat;
967 	BP_PAINTPARAMS m_PaintParams;
968 
CBufferedPaintImpl()969 	CBufferedPaintImpl() : m_dwFormat(BPBF_TOPDOWNDIB)
970 	{
971 		memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
972 		m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
973 	}
974 
975 // Message map and handlers
976 	BEGIN_MSG_MAP(CBufferedPaintImpl)
MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBackground)977 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
978 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
979 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
980 	END_MSG_MAP()
981 
982 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
983 	{
984 		return 1;   // no background needed
985 	}
986 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)987 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
988 	{
989 		T* pT = static_cast<T*>(this);
990 		if(wParam != NULL)
991 		{
992 			RECT rect = { 0 };
993 			pT->GetClientRect(&rect);
994 			pT->DoPaint((HDC)wParam, rect);
995 		}
996 		else
997 		{
998 			CPaintDC dc(pT->m_hWnd);
999 			pT->DoBufferedPaint(dc.m_hDC, dc.m_ps.rcPaint);
1000 		}
1001 
1002 		return 0;
1003 	}
1004 
1005 // Overrideables
DoBufferedPaint(CDCHandle dc,RECT & rect)1006 	void DoBufferedPaint(CDCHandle dc, RECT& rect)
1007 	{
1008 		HDC hDCPaint = NULL;
1009 		if(IsBufferedPaintSupported())
1010 			m_BufferedPaint.Begin(dc, &rect, m_dwFormat, &m_PaintParams, &hDCPaint);
1011 
1012 		T* pT = static_cast<T*>(this);
1013 		if(hDCPaint != NULL)
1014 			pT->DoPaint(hDCPaint, rect);
1015 		else
1016 			pT->DoPaint(dc.m_hDC, rect);
1017 
1018 		if(IsBufferedPaintSupported())
1019 			m_BufferedPaint.End();
1020 	}
1021 
DoPaint(CDCHandle,RECT &)1022 	void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/)
1023 	{
1024 		// must be implemented in a derived class
1025 		ATLASSERT(FALSE);
1026 	}
1027 };
1028 
1029 
1030 ///////////////////////////////////////////////////////////////////////////////
1031 // CBufferedPaintWindowImpl - implements a window that uses buffered paint
1032 
1033 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
1034 class ATL_NO_VTABLE CBufferedPaintWindowImpl :
1035 		public ATL::CWindowImpl<T, TBase, TWinTraits>,
1036 		public CBufferedPaintImpl< T >
1037 {
1038 public:
1039 	BEGIN_MSG_MAP(CBufferedPaintWindowImpl)
1040 		CHAIN_MSG_MAP(CBufferedPaintImpl< T >)
1041 	END_MSG_MAP()
1042 };
1043 
1044 
1045 ///////////////////////////////////////////////////////////////////////////////
1046 // CBufferedAnimation - support for buffered animation
1047 
1048 class CBufferedAnimation
1049 {
1050 public:
1051 	HANIMATIONBUFFER m_hAnimationBuffer;
1052 
CBufferedAnimation()1053 	CBufferedAnimation() : m_hAnimationBuffer(NULL)
1054 	{ }
1055 
~CBufferedAnimation()1056 	~CBufferedAnimation()
1057 	{
1058 		ATLVERIFY(SUCCEEDED(End()));
1059 	}
1060 
IsNull()1061 	bool IsNull() const
1062 	{
1063 		return (m_hAnimationBuffer == NULL);
1064 	}
1065 
Begin(HWND hWnd,HDC hDCTarget,const RECT * pRectTarget,BP_BUFFERFORMAT dwFormat,BP_PAINTPARAMS * pPaintParams,BP_ANIMATIONPARAMS * pAnimationParams,HDC * phdcFrom,HDC * phdcTo)1066 	HANIMATIONBUFFER Begin(HWND hWnd, HDC hDCTarget, const RECT* pRectTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS* pPaintParams, BP_ANIMATIONPARAMS* pAnimationParams, HDC* phdcFrom, HDC* phdcTo)
1067 	{
1068 		ATLASSERT(m_hAnimationBuffer == NULL);
1069 		m_hAnimationBuffer = ::BeginBufferedAnimation(hWnd, hDCTarget, pRectTarget, dwFormat, pPaintParams, pAnimationParams, phdcFrom, phdcTo);
1070 		return m_hAnimationBuffer;
1071 	}
1072 
1073 	HRESULT End(BOOL bUpdate = TRUE)
1074 	{
1075 		HRESULT hRet = S_FALSE;
1076 		if(m_hAnimationBuffer != NULL)
1077 		{
1078 			hRet = ::EndBufferedAnimation(m_hAnimationBuffer, bUpdate);
1079 			m_hAnimationBuffer = NULL;
1080 		}
1081 		return hRet;
1082 	}
1083 
IsRendering(HWND hWnd,HDC hDC)1084 	static bool IsRendering(HWND hWnd, HDC hDC)
1085 	{
1086 		return (::BufferedPaintRenderAnimation(hWnd, hDC) != FALSE);
1087 	}
1088 
StopAllAnimations(HWND hWnd)1089 	static HRESULT StopAllAnimations(HWND hWnd)
1090 	{
1091 		return ::BufferedPaintStopAllAnimations(hWnd);
1092 	}
1093 };
1094 
1095 
1096 ///////////////////////////////////////////////////////////////////////////////
1097 // CBufferedAnimationImpl - provides buffered animation support for any window
1098 
1099 // Note: You can either use m_State and m_NewState to store the state information
1100 // for the animation change, or map your state to those data members. DoPaint()
1101 // should only rely on the state information that is passed to it.
1102 
1103 template <class T, class TState = DWORD_PTR>
1104 class ATL_NO_VTABLE CBufferedAnimationImpl : public CBufferedPaintBase
1105 {
1106 public:
1107 	BP_BUFFERFORMAT m_dwFormat;
1108 	BP_PAINTPARAMS m_PaintParams;
1109 	BP_ANIMATIONPARAMS m_AnimationParams;
1110 
1111 	TState m_State;
1112 	TState m_NewState;
1113 
CBufferedAnimationImpl(TState InitialState)1114 	CBufferedAnimationImpl(TState InitialState) : m_dwFormat(BPBF_TOPDOWNDIB)
1115 	{
1116 		memset(&m_PaintParams, 0, sizeof(BP_PAINTPARAMS));
1117 		m_PaintParams.cbSize = sizeof(BP_PAINTPARAMS);
1118 
1119 		memset(&m_AnimationParams, 0, sizeof(BP_ANIMATIONPARAMS));
1120 		m_AnimationParams.cbSize = sizeof(BP_ANIMATIONPARAMS);
1121 		m_AnimationParams.style = BPAS_LINEAR;
1122 		m_AnimationParams.dwDuration = 500;
1123 
1124 		T* pT = static_cast<T*>(this);
1125 		pT->SetState(InitialState);
1126 		pT->SetNewState(InitialState);
1127 	}
1128 
GetDuration()1129 	DWORD GetDuration() const
1130 	{
1131 		return m_AnimationParams.dwDuration;
1132 	}
1133 
SetDuration(DWORD dwDuration)1134 	void SetDuration(DWORD dwDuration)
1135 	{
1136 		m_AnimationParams.dwDuration = dwDuration;
1137 	}
1138 
1139 	void DoAnimation(TState NewState, const RECT* pRect = NULL)
1140 	{
1141 		T* pT = static_cast<T*>(this);
1142 		pT->SetNewState(NewState);
1143 
1144 		pT->InvalidateRect(pRect, FALSE);
1145 		pT->UpdateWindow();
1146 
1147 		pT->SetState(NewState);
1148 	}
1149 
1150 // Message map and handlers
1151 	BEGIN_MSG_MAP(CBufferedAnimationImpl)
MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBackground)1152 		MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
1153 		MESSAGE_HANDLER(WM_PAINT, OnPaint)
1154 		MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
1155 	END_MSG_MAP()
1156 
1157 	LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1158 	{
1159 		return 1;   // no background needed
1160 	}
1161 
OnPaint(UINT,WPARAM wParam,LPARAM,BOOL &)1162 	LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
1163 	{
1164 		T* pT = static_cast<T*>(this);
1165 		if(wParam != NULL)
1166 		{
1167 			RECT rect = { 0 };
1168 			pT->GetClientRect(&rect);
1169 			pT->DoPaint((HDC)wParam, rect, m_NewState);
1170 		}
1171 		else
1172 		{
1173 			CPaintDC dc(pT->m_hWnd);
1174 			pT->DoAnimationPaint(dc.m_hDC, dc.m_ps.rcPaint);
1175 		}
1176 
1177 		return 0;
1178 	}
1179 
1180 // Overrideables
SetState(TState State)1181 	void SetState(TState State)
1182 	{
1183 		m_State = State;
1184 	}
1185 
SetNewState(TState State)1186 	void SetNewState(TState State)
1187 	{
1188 		m_NewState = State;
1189 	}
1190 
AreStatesEqual()1191 	bool AreStatesEqual() const
1192 	{
1193 		return (m_State == m_NewState);
1194 	}
1195 
DoAnimationPaint(CDCHandle dc,RECT & rect)1196 	void DoAnimationPaint(CDCHandle dc, RECT& rect)
1197 	{
1198 		T* pT = static_cast<T*>(this);
1199 		if(IsBufferedPaintSupported() && CBufferedAnimation::IsRendering(pT->m_hWnd, dc))
1200 			return;
1201 
1202 		DWORD dwDurationSave = m_AnimationParams.dwDuration;
1203 		if(pT->AreStatesEqual())
1204 			m_AnimationParams.dwDuration = 0;
1205 
1206 		HDC hdcFrom = NULL, hdcTo = NULL;
1207 		CBufferedAnimation ba;
1208 		if(IsBufferedPaintSupported())
1209 			ba.Begin(pT->m_hWnd, dc, &rect, m_dwFormat, &m_PaintParams, &m_AnimationParams, &hdcFrom, &hdcTo);
1210 
1211 		if(!ba.IsNull())
1212 		{
1213 			if(hdcFrom != NULL)
1214 				pT->DoPaint(hdcFrom, rect, m_State);
1215 
1216 			if (hdcTo != NULL)
1217 				pT->DoPaint(hdcTo, rect, m_NewState);
1218 		}
1219 		else
1220 		{
1221 			pT->DoPaint(dc.m_hDC, rect, m_NewState);
1222 		}
1223 
1224 		m_AnimationParams.dwDuration = dwDurationSave;
1225 	}
1226 
DoPaint(CDCHandle,RECT &,TState)1227 	void DoPaint(CDCHandle /*dc*/, RECT& /*rect*/, TState /*State*/)
1228 	{
1229 		// must be implemented in a derived class
1230 		ATLASSERT(FALSE);
1231 	}
1232 };
1233 
1234 
1235 ///////////////////////////////////////////////////////////////////////////////
1236 // CBufferedAnimationWindowImpl - implements a window that uses buffered animation
1237 
1238 template <class T, class TState = DWORD_PTR, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
1239 class ATL_NO_VTABLE CBufferedAnimationWindowImpl :
1240 		public ATL::CWindowImpl<T, TBase, TWinTraits>,
1241 		public CBufferedAnimationImpl< T, TState >
1242 {
1243 public:
CBufferedAnimationWindowImpl(TState InitialState)1244 	CBufferedAnimationWindowImpl(TState InitialState) : CBufferedAnimationImpl< T, TState >(InitialState)
1245 	{ }
1246 
1247 	typedef CBufferedAnimationImpl< T, TState >   _baseBufferedAnimation;
1248 	BEGIN_MSG_MAP(CBufferedAnimationWindowImpl)
1249 		CHAIN_MSG_MAP(_baseBufferedAnimation)
1250 	END_MSG_MAP()
1251 };
1252 
1253 #endif // defined(_WTL_NEW_UXTHEME) && (_WIN32_WINNT >= 0x0600)
1254 
1255 }; // namespace WTL
1256 
1257 #endif // __ATLTHEME_H__
1258