#ifndef __ATLGDIX_H__ #define __ATLGDIX_H__ ///////////////////////////////////////////////////////////////////////////// // Additional GDI/USER wrappers // // Written by Bjarke Viksoe (bjarke@viksoe.dk) // Copyright (c) 2001-2002 Bjarke Viksoe. // Thanks to Daniel Bowen for COffscreenDrawRect. // // This code may be used in compiled form in any way you desire. This // file may be redistributed by any means PROVIDING it is // not sold for profit without the authors written consent, and // providing that this notice and the authors name is included. // // This file is provided "as is" with no expressed or implied warranty. // The author accepts no liability if it causes any damage to you or your // computer whatsoever. It's free, so don't hassle me about it. // // Beware of bugs. // #pragma once #ifndef __cplusplus #error ATL requires C++ compilation (use a .cpp suffix) #endif #ifndef __ATLGDI_H__ #error atlgdix.h requires atlgdi.h to be included first #endif namespace WTL { ///////////////////////////////////////////////////////////////////////////// // Macros // The GetXValue macros below are badly designed and emit // compiler warnings e.g. when using RGB(255,255,255)... #pragma warning(disable : 4310) #ifndef BlendRGB #define BlendRGB(c1, c2, factor) \ RGB( GetRValue(c1) + ((GetRValue(c2) - GetRValue(c1)) * factor / 100L), \ GetGValue(c1) + ((GetGValue(c2) - GetGValue(c1)) * factor / 100L), \ GetBValue(c1) + ((GetBValue(c2) - GetBValue(c1)) * factor / 100L) ) #endif #ifndef COLOR_INVALID #define COLOR_INVALID (COLORREF) CLR_INVALID #endif #if(_WTL_VER < 0x0750) ///////////////////////////////////////////////////////////////////////////// // CIcon template< bool t_bManaged > class CIconT { public: HICON m_hIcon; // Constructor/destructor/operators CIconT(HICON hIcon = NULL) : m_hIcon(hIcon) { } ~CIconT() { if( t_bManaged && m_hIcon != NULL ) ::DestroyIcon(m_hIcon); } CIconT& operator=(HICON hIcon) { m_hIcon = hIcon; return *this; } void Attach(HICON hIcon) { if( t_bManaged && m_hIcon != NULL ) ::DestroyIcon(m_hIcon); m_hIcon = hIcon; } HICON Detach() { HICON hIcon = m_hIcon; m_hIcon = NULL; return hIcon; } operator HICON() const { return m_hIcon; } bool IsNull() const { return m_hIcon == NULL; } // Create methods HICON LoadIcon(_U_STRINGorID icon) { ATLASSERT(m_hIcon==NULL); #if (_ATL_VER >= 0x0700) m_hIcon = ::LoadIcon(ATL::_AtlBaseModule.GetResourceInstance(), icon.m_lpstr); #else m_hIcon = ::LoadIcon(_Module.GetResourceInstance(), icon.m_lpstr); #endif return m_hIcon; } HICON LoadIcon(_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0) { ATLASSERT(m_hIcon==NULL); #if (_ATL_VER >= 0x0700) m_hIcon = (HICON) ::LoadImage(ATL::_AtlBaseModule.GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); #else m_hIcon = (HICON) ::LoadImage(_Module.GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad); #endif return m_hIcon; } HICON LoadOEMIcon(UINT nIDIcon) // for IDI_ types { ATLASSERT(m_hIcon==NULL); m_hIcon = ::LoadIcon(NULL, MAKEINTRESOURCE(nIDIcon)); return m_hIcon; } HICON CreateIcon(int nWidth, int nHeight, BYTE cPlanes, BYTE cBitsPixel, CONST BYTE* lpbANDButs, CONST BYTE *lpbXORbits) { ATLASSERT(m_hIcon==NULL); ATLASSERT(lpbANDbits); ATLASSERT(lpbXORbits); #if (_ATL_VER >= 0x0700) m_hIcon = ::CreateIcon(ATL::_AtlBaseModule.GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits); #else m_hIcon = ::CreateIcon(_Module.GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits); #endif return m_hIcon; } HICON CreateIconFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) { ATLASSERT(m_hIcon==NULL); ATLASSERT(pBits); m_hIcon = ::CreateIconFromResource(pBits, dwResSize, TRUE, dwVersion); return m_hIcon; } HICON CreateIconFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) { ATLASSERT(m_hIcon==NULL); ATLASSERT(pbBits); ATLASSERT(cbBits>0); m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, TRUE, dwVersion, cxDesired, cyDesired, uFlags); return m_hIcon; } HICON CreateIconIndirect(PICONINFO pIconInfo) { ATLASSERT(m_hIcon==NULL); ATLASSERT(pIconInfo); m_hIcon = ::CreateIconIndirect(pIconInfo); return m_hIcon; } HICON ExtractIcon(LPCTSTR lpszExeFileName, UINT nIconIndex) { ATLASSERT(m_hIcon==NULL); ATLASSERT(!::IsBadStringPtr(lpszExeFileName,-1)); #if (_ATL_VER >= 0x0700) m_hIcon = ::ExtractIcon(ATL::_AtlBaseModule.GetModuleInstance(), lpszExeFileName, nIconIndex); #else m_hIcon = ::ExtractIcon(_Module.GetModuleInstance(), lpszExeFileName, nIconIndex); #endif return m_hIcon; } HICON ExtractAssociatedIcon(HINSTANCE hInst, LPCTSTR lpIconPath, LPWORD lpiIcon) { ATLASSERT(m_hIcon==NULL); ATLASSERT(!::IsBadStringPtr(lpIconPath,-1)); ATLASSERT(lpiIcon); m_hIcon = ::ExtractAssociatedIcon(hInst, lpIconPath, lpiIcon); return m_hIcon; } // Operations BOOL DestroyIcon() { ATLASSERT(m_hIcon!=NULL); BOOL bRet = ::DestroyIcon(m_hIcon); if( bRet ) m_hIcon = NULL; return bRet; } HICON CopyIcon() { ATLASSERT(m_hIcon!=NULL); return ::CopyIcon(m_hIcon); } HICON DuplicateIcon() { ATLASSERT(m_hIcon!=NULL); return ::DuplicateIcon(NULL, m_hIcon); } BOOL DrawIcon(HDC hDC, int x, int y) { ATLASSERT(m_hIcon!=NULL); return ::DrawIcon(hDC, x, y, m_hIcon); } BOOL DrawIcon(HDC hDC, POINT pt) { ATLASSERT(m_hIcon!=NULL); return ::DrawIcon(hDC, pt.x, pt.y, m_hIcon); } BOOL DrawIconEx(HDC hDC, int x, int y, int cxWidth, int cyWidth, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hIcon!=NULL); return ::DrawIconEx(hDC, x, y, m_hIcon, cxWidth, cyWidth, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } BOOL DrawIconEx(HDC hDC, POINT pt, SIZE size, UINT uStepIfAniCur = 0, HBRUSH hbrFlickerFreeDraw = NULL, UINT uFlags = DI_NORMAL) { ATLASSERT(m_hIcon!=NULL); return ::DrawIconEx(hDC, pt.x, pt.y, m_hIcon, size.cx, size.cy, uStepIfAniCur, hbrFlickerFreeDraw, uFlags); } BOOL GetIconInfo(PICONINFO pIconInfo) { ATLASSERT(m_hIcon!=NULL); ATLASSERT(pIconInfo); return ::GetIconInfo(m_hIcon, pIconInfo); } }; typedef CIconT CIcon; typedef CIconT CIconHandle; ///////////////////////////////////////////////////////////////////////////// // CCursor // Protect template against silly macro #ifdef CopyCursor #undef CopyCursor #endif template< bool t_bManaged > class CCursorT { public: HCURSOR m_hCursor; // Constructor/destructor/operators CCursorT(HCURSOR hCursor = NULL) : m_hCursor(hCursor) { } ~CCursorT() { if( t_bManaged && m_hCursor != NULL ) ::DestroyCursor(m_hCursor); } CCursorT& operator=(HCURSOR hCursor) { m_hCursor = hCursor; return *this; } void Attach(HCURSOR hCursor) { if( t_bManaged && m_hCursor != NULL ) ::DestroyCursor(m_hCursor); m_hCursor = hCursor; } HCURSOR Detach() { HCURSOR hCursor = m_hCursor; m_hCursor = NULL; return hCursor; } operator HCURSOR() const { return m_hCursor; } bool IsNull() const { return m_hCursor == NULL; } // Create methods HCURSOR LoadCursor(_U_STRINGorID cursor) { ATLASSERT(m_hCursor==NULL); #if (_ATL_VER >= 0x0700) m_hCursor = ::LoadCursor(ATL::_AtlBaseModule.GetResourceInstance(), cursor.m_lpstr); #else m_hCursor = ::LoadCursor(_Module.GetResourceInstance(), cursor.m_lpstr); #endif return m_hCursor; } HCURSOR LoadOEMCursor(UINT nIDCursor) // for IDC_ types { ATLASSERT(m_hCursor==NULL); m_hCursor = ::LoadCursor(NULL, MAKEINTRESOURCE(nIDCursor)); return m_hCursor; } HICON LoadCursor(_U_STRINGorID cursor, int cxDesired, int cyDesired, UINT fuLoad = 0) { ATLASSERT(m_hCursor==NULL); #if (_ATL_VER >= 0x0700) m_hCursor = (HCURSOR) ::LoadImage(ATL::_AtlBaseModule.GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); #else m_hCursor = (HCURSOR) ::LoadImage(_Module.GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad); #endif return m_hCursor; } HCURSOR LoadCursorFromFile(LPCTSTR pstrFilename) { ATLASSERT(m_hCursor==NULL); ATLASSERT(!::IsBadStringPtr(pstrFilename,-1)); m_hCursor = ::LoadCursorFromFile(pstrFilename); return m_hCursor; } HCURSOR CreateCursor(int xHotSpot, int yHotSpot, int nWidth, int nHeight, CONST VOID *pvANDPlane, CONST VOID *pvXORPlane) { ATLASSERT(m_hCursor==NULL); #if (_ATL_VER >= 0x0700) m_hCursor = ::CreateCursor(ATL::_AtlBaseModule.GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane); #else m_hCursor = ::CreateCursor(_Module.GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane); #endif return m_hCursor; } HICON CreateCursorFromResource(PBYTE pBits, DWORD dwResSize, DWORD dwVersion = 0x00030000) { ATLASSERT(m_hIcon==NULL); ATLASSERT(pBits); m_hIcon = ::CreateIconFromResource(pBits, dwResSize, FALSE, dwVersion); return m_hIcon; } HICON CreateCursorFromResourceEx(PBYTE pbBits, DWORD cbBits, DWORD dwVersion = 0x00030000, int cxDesired = 0, int cyDesired = 0, UINT uFlags = LR_DEFAULTCOLOR) { ATLASSERT(m_hIcon==NULL); ATLASSERT(pbBits); ATLASSERT(cbBits>0); m_hIcon = ::CreateIconFromResourceEx(pbBits, cbBits, FALSE, dwVersion, cxDesired, cyDesired, uFlags); return m_hIcon; } // Operations BOOL DestroyCursor() { ATLASSERT(m_hCursor!=NULL); BOOL bRet = ::DestroyCursor(m_hCursor); if( bRet ) m_hCursor = NULL; return bRet; } HCURSOR CopyCursor() { ATLASSERT(m_hCursor!=NULL); return (HCURSOR) ::CopyIcon( (HICON) m_hCursor ); } #if(WINVER >= 0x0500) BOOL GetCursorInfo(LPCURSORINFO pCursorInfo) { ATLASSERT(m_hCursor!=NULL); ATLASSERT(pCursorInfo); return ::GetCursorInfo(pCursorInfo); } #endif }; typedef CCursorT CCursor; typedef CCursorT CCursorHandle; ///////////////////////////////////////////////////////////////////////////// // CAccelerator template< bool t_bManaged > class CAcceleratorT { public: HACCEL m_hAccel; // Constructor/destructor/operators CAcceleratorT(HACCEL hAccel = NULL) : m_hAccel(hAccel) { } ~CAcceleratorT() { if( t_bManaged && m_hAccel != NULL ) ::DestroyAcceleratorTable(m_hAccel); } CAcceleratorT& operator=(HACCEL hAccel) { m_hAccel = hAccel; return *this; } void DestroyObject() { if( m_hAccel != NULL ) { ::DestroyAcceleratorTable(m_hAccel); m_hAccel = NULL; } } void Attach(HACCEL hAccel) { if( t_bManaged && m_hAccel != NULL ) ::DestroyAcceleratorTable(m_hAccel); m_hAccel = hAccel; } HCURSOR Detach() { HACCEL hAccel = m_hAccel; m_hAccel = NULL; return hAccel; } operator HACCEL() const { return m_hAccel; } bool IsNull() const { return m_hAccel == NULL; } // Create methods HACCEL LoadAccelerators(_U_STRINGorID accel) { ATLASSERT(m_hAccel==NULL); #if (_ATL_VER >= 0x0700) m_hAccel = ::LoadAccelerators(ATL::_AtlBaseModule.GetResourceInstance(), accel.m_lpstr); #else m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), accel.m_lpstr); #endif return m_hAccel; } HACCEL CreateAcceleratorTable(LPACCEL pAccel, int cEntries) { ATLASSERT(m_hAccel==NULL); ATLASSERT(!::IsBadReadPtr(lpAccelDst, sizeof(ACCEL)*cEntries)); m_hAccel = ::CreateAcceleratorTable(pAccel, cEntries); return m_hAccel; } // Operations int CopyAcceleratorTable(LPACCEL lpAccelDst, int cEntries) { ATLASSERT(m_hAccel!=NULL); ATLASSERT(!::IsBadWritePtr(lpAccelDst, sizeof(ACCEL)*cEntries)); return ::CopyAcceleratorTable(m_hAccel, lpAccelDst, cEntries); } BOOL TranslateAccelerator(HWND hWnd, LPMSG pMsg) { ATLASSERT(m_hAccel!=NULL); ATLASSERT(::IsWindow(hWnd)); ATLASSERT(pMsg); return ::TranslateAccelerator(hWnd, m_hAccel, pMsg); } }; typedef CAcceleratorT CAccelerator; typedef CAcceleratorT CAcceleratorHandle; ///////////////////////////////////////////////////////////////////////////// // CLogFont class CLogFont : public LOGFONT { public: CLogFont() { ::ZeroMemory( (LOGFONT*) this, sizeof(LOGFONT) ); } CLogFont(const LOGFONT& lf) { Copy(&lf); } CLogFont(HFONT hFont) { ATLASSERT(::GetObjectType(hFont)==OBJ_FONT); ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*) this); } HFONT CreateFontIndirect() { return ::CreateFontIndirect(this); } void SetBold() { lfWeight = FW_BOLD; } BOOL IsBold() const { return lfWeight >= FW_BOLD; } void MakeBolder(int iScale = 1) { lfWeight += FW_BOLD * iScale; } void MakeLarger(int iScale) { if( lfHeight > 0 ) lfHeight += iScale; else lfHeight -= iScale; } void SetHeight(long PointSize, HDC hDC = NULL) { // For MM_TEXT mapping mode... // NOTE: MulDiv() gives correct rounding. lfHeight = -MulDiv(PointSize, ::GetDeviceCaps(hDC, LOGPIXELSY), 72); } long GetHeight(HDC hDC = NULL) const { // For MM_TEXT mapping mode... // NOTE: MulDiv() gives correct rounding. return MulDiv(-lfHeight, 72, ::GetDeviceCaps(hDC, LOGPIXELSY)); } long GetDeciPointHeight(HDC hDC = NULL) { POINT ptOrg = { 0, 0 }; ::DPtoLP(hDC, &ptOrg, 1); POINT pt = { 0, 0 }; pt.y = abs(lfHeight) + ptOrg.y; ::LPtoDP(hDC,&pt,1); return MulDiv(pt.y, 720, ::GetDeviceCaps(hDC,LOGPIXELSY)); // 72 points/inch, 10 decipoints/point } void SetHeightFromDeciPoint(long DeciPtHeight, HDC hDC = NULL) { POINT pt; pt.y = MulDiv(::GetDeviceCaps(hDC, LOGPIXELSY), DeciPtHeight, 720); // 72 points/inch, 10 decipoints/point ::DPtoLP(hDC, &pt, 1); POINT ptOrg = { 0, 0 }; ::DPtoLP(hDC, &ptOrg, 1); lfHeight = -abs(pt.y - ptOrg.y); } void SetCaptionFont() { NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(ncm); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); Copy(&ncm.lfCaptionFont); } void SetMenuFont() { NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(ncm); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); Copy(&ncm.lfMenuFont); } void SetStatusFont() { NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(ncm); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); Copy(&ncm.lfStatusFont); } void SetMessageBoxFont() { NONCLIENTMETRICS ncm = { 0 }; ncm.cbSize = sizeof(ncm); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0); Copy(&ncm.lfMessageFont); } void Copy(const LOGFONT* lf) { ATLASSERT(lf); ::CopyMemory( (LOGFONT*) this, lf, sizeof(LOGFONT) ); } CLogFont& operator=(const CLogFont& src) { Copy(&src); return *this; } CLogFont& operator=(const LOGFONT& src) { Copy(&src); return *this; } CLogFont& operator=(HFONT hFont) { ATLASSERT(::GetObjectType(hFont)==OBJ_FONT); ::GetObject(hFont, sizeof(LOGFONT), (LOGFONT*) this); return *this; } bool operator==(const LOGFONT& logfont) const { return( logfont.lfHeight == lfHeight && logfont.lfWidth == lfWidth && logfont.lfEscapement == lfEscapement && logfont.lfOrientation == lfOrientation && logfont.lfWeight == lfWeight && logfont.lfItalic == lfItalic && logfont.lfUnderline == lfUnderline && logfont.lfStrikeOut == lfStrikeOut && logfont.lfCharSet == lfCharSet && logfont.lfOutPrecision == lfOutPrecision && logfont.lfClipPrecision == lfClipPrecision && logfont.lfQuality == lfQuality && logfont.lfPitchAndFamily == lfPitchAndFamily && ::lstrcmp(logfont.lfFaceName, lfFaceName) == 0 ); } }; #endif //(_WTL_VER < 0x0750) ///////////////////////////////////////////////////////////////////////////// // CMemDC class CMemDC : public CDC { public: CDCHandle m_dc; // Owner DC CBitmap m_bitmap; // Offscreen bitmap CBitmapHandle m_hOldBitmap; // Originally selected bitmap RECT m_rc; // Rectangle of drawing area CMemDC(HDC hDC, LPRECT pRect = NULL) { ATLASSERT(hDC!=NULL); m_dc = hDC; if( pRect != NULL ) m_rc = *pRect; else m_dc.GetClipBox(&m_rc); CreateCompatibleDC(m_dc); ::LPtoDP(m_dc, (LPPOINT) &m_rc, sizeof(RECT) / sizeof(POINT)); m_bitmap.CreateCompatibleBitmap(m_dc, m_rc.right - m_rc.left, m_rc.bottom - m_rc.top); m_hOldBitmap = SelectBitmap(m_bitmap); ::DPtoLP(m_dc, (LPPOINT) &m_rc, sizeof(RECT) / sizeof(POINT)); SetWindowOrg(m_rc.left, m_rc.top); } ~CMemDC() { // Copy the offscreen bitmap onto the screen. m_dc.BitBlt(m_rc.left, m_rc.top, m_rc.right - m_rc.left, m_rc.bottom - m_rc.top, m_hDC, m_rc.left, m_rc.top, SRCCOPY); // Swap back the original bitmap. SelectBitmap(m_hOldBitmap); } }; ///////////////////////////////////////////////////////////////////////////// // COffscreenDraw // To use it, derive from it and chain it in the message map. template< class T > class COffscreenDraw { public: BEGIN_MSG_MAP(COffscreenDraw) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) END_MSG_MAP() LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if( wParam != NULL ) { CMemDC memdc( (HDC) wParam, NULL ); pT->DoPaint(memdc.m_hDC); } else { RECT rc; pT->GetClientRect(&rc); CPaintDC dc(pT->m_hWnd); CMemDC memdc(dc.m_hDC, &rc); pT->DoPaint(memdc.m_hDC); } return 0; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // handled; no need to erase background; do it in DoPaint(); } void DoPaint(CDCHandle dc) { ATLASSERT(false); // must override this } }; // To use it, derive from it and chain it in the message map. template< class T > class COffscreenDrawRect { public: BEGIN_MSG_MAP(COffscreenDrawRect) MESSAGE_HANDLER(WM_PAINT, OnPaint) MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) END_MSG_MAP() LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) { T* pT = static_cast(this); if( wParam != NULL ) { CMemDC memdc( (HDC) wParam, NULL ); pT->DoPaint(memdc.m_hDC, memdc.m_rc); } else { CPaintDC dc(pT->m_hWnd); CMemDC memdc(dc.m_hDC, &dc.m_ps.rcPaint); pT->DoPaint(memdc.m_hDC, dc.m_ps.rcPaint); } return 0; } LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { return 1; // handled; no need to erase background; do it in DoPaint(); } void DoPaint(CDCHandle dc, RECT& rcClip) { ATLASSERT(false); // must override this } }; ///////////////////////////////////////////////////////////////////////////// // CSaveDC class CSaveDC { public: HDC m_hDC; int m_iState; CSaveDC(HDC hDC) : m_hDC(hDC) { ATLASSERT(::GetObjectType(m_hDC)==OBJ_DC || ::GetObjectType(m_hDC)==OBJ_MEMDC); m_iState = ::SaveDC(hDC); ATLASSERT(m_iState!=0); } ~CSaveDC() { Restore(); } void Restore() { if( m_iState == 0 ) return; ATLASSERT(::GetObjectType(m_hDC)==OBJ_DC || ::GetObjectType(m_hDC)==OBJ_MEMDC); ::RestoreDC(m_hDC, m_iState); m_iState = 0; } }; ///////////////////////////////////////////////////////////////////////////// // CHandle #if (_ATL_VER < 0x0700) class CHandle { public: HANDLE m_h; CHandle(HANDLE hSrc = INVALID_HANDLE_VALUE) : m_h(hSrc) { } ~CHandle() { Close(); } operator HANDLE() const { return m_h; }; LPHANDLE operator&() { ATLASSERT(!IsValid()); return &m_h; } CHandle& operator=(HANDLE h) { ATLASSERT(!IsValid()); m_h = h; return *this; } bool IsValid() const { return m_h != INVALID_HANDLE_VALUE; }; void Attach(HANDLE h) { if( IsValid() ) ::CloseHandle(m_h); m_h = h; } HANDLE Detach() { HANDLE h = m_h; m_h = INVALID_HANDLE_VALUE; return h; } BOOL Close() { BOOL bRes = FALSE; if( m_h != INVALID_HANDLE_VALUE ) { bRes = ::CloseHandle(m_h); m_h = INVALID_HANDLE_VALUE; } return bRes; } BOOL Duplicate(HANDLE hSource, bool bInherit = false) { ATLASSERT(!IsValid()); HANDLE hOurProcess = ::GetCurrentProcess(); BOOL b = ::DuplicateHandle(hOurProcess, hSource, hOurProcess, &m_h, DUPLICATE_SAME_ACCESS, bInherit, DUPLICATE_SAME_ACCESS); ATLASSERT(b); return b; } }; #endif // _ATL_VER ///////////////////////////////////////////////////////////////////////////// // Mouse Hover helper #ifndef NOTRACKMOUSEEVENT #ifndef WM_MOUSEENTER #define WM_MOUSEENTER WM_USER + 253 #endif // WM_MOUSEENTER // To use it, derive from it and chain it in the message map. // Make sure to set bHandled to FALSE when handling WM_MOUSEMOVE or // the WM_MOUSELEAVE message! template< class T > class CMouseHover { public: bool m_fMouseOver; // Internal mouse-over state bool m_fMouseForceUpdate; // Update window immediately on event CMouseHover() : m_fMouseOver(false), m_fMouseForceUpdate(true) { } void SetForceMouseOverUpdate(bool bForce = false) { m_fMouseForceUpdate = bForce; } BEGIN_MSG_MAP(CMouseHover) MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) END_MSG_MAP() LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { T* pT = static_cast(this); if( !m_fMouseOver ) { m_fMouseOver = true; pT->SendMessage(WM_MOUSEENTER, wParam, lParam); if( m_fMouseForceUpdate ) { pT->Invalidate(); pT->UpdateWindow(); } _StartTrackMouseLeave(pT->m_hWnd); } bHandled = FALSE; return 0; } LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) { T* pT = static_cast(this); if( m_fMouseOver ) { m_fMouseOver = false; if( m_fMouseForceUpdate ) { pT->Invalidate(); pT->UpdateWindow(); } } bHandled = FALSE; return 0; } BOOL _StartTrackMouseLeave(HWND hWnd) const { ATLASSERT(::IsWindow(hWnd)); TRACKMOUSEEVENT tme = { 0 }; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; tme.hwndTrack = hWnd; return _TrackMouseEvent(&tme); } BOOL _CancelTrackMouseLeave(HWND hWnd) const { TRACKMOUSEEVENT tme = { 0 }; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE | TME_CANCEL; tme.hwndTrack = hWnd; return _TrackMouseEvent(&tme); } }; #endif // NOTRACKMOUSEEVENT }; // namespace WTL #endif // __ATLGDIX_H__