Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

Another WTL Grid

, 1 Jun 2003
A WTL Grid mostly aimed for use against databases.
wtlgrid2_demo.zip
CodeProject
codeproject_template
Northwind Demo
Debug
Release
Northwind.exe
res
Northwind.exe.manifest
Northwind.ico
Toolbar.bmp
Simple Demo
Debug
Release
Simple Demo.exe
res
Simple Demo.exe.manifest
Simple Demo.ico
toolbar.bmp
wtlgrid2_src.zip
#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


/////////////////////////////////////////////////////////////////////////////
// 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<t_bManaged>& 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);
      m_hIcon = ::LoadIcon(_Module.GetResourceInstance(), icon.m_lpstr);
      return m_hIcon;
   }
   HICON LoadIcon(_U_STRINGorID icon, int cxDesired, int cyDesired, UINT fuLoad = 0)
   {
      ATLASSERT(m_hIcon==NULL);
      m_hIcon = (HICON) ::LoadImage(_Module.GetResourceInstance(), icon.m_lpstr, IMAGE_ICON, cxDesired, cyDesired, fuLoad);
      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);
      m_hIcon = ::CreateIcon(_Module.GetResourceInstance(), nWidth, nHeight, cPlanes, cBitsPixel, lpbANDbits, lpbXORbits);
      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));
      m_hIcon = ::ExtractIcon(_Module.GetModuleInstance(), lpszExeFileName, nIconIndex);
      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<true> CIcon;
typedef CIconT<false> 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<t_bManaged>& 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);
      m_hCursor = ::LoadCursor(_Module.GetResourceInstance(), cursor.m_lpstr);
      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);
      m_hCursor = (HCURSOR) ::LoadImage(_Module.GetResourceInstance(), cursor.m_lpstr, IMAGE_CURSOR, cxDesired, cyDesired, fuLoad);
      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);
      m_hCursor = ::CreateCursor(_Module.GetResourceInstance(), xHotSpot, yHotSpot, nWidth, nHeight, pvANDPlane, pvXORPlane);
      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<true> CCursor;
typedef CCursorT<false> 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<t_bManaged>& operator=(HACCEL hAccel)
   {
      m_hAccel = hAccel;
      return *this;
   }

   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);
      m_hAccel = ::LoadAccelerators(_Module.GetResourceInstance(), accel.m_lpstr);
      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<true> CAccelerator;
typedef CAcceleratorT<false> 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 );
   }
};


/////////////////////////////////////////////////////////////////////////////
// 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<T*>(this);
      if( wParam != NULL )
      {
         CMemDC memdc( (HDC) wParam, NULL );
         pT->DoPaint(memdc.m_hDC);
      }
      else
      {
         RECT rc;
         ::GetClientRect(pT->m_hWnd, &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<T*>(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)
   {
   }

   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<T*>(this);
      if( !m_fMouseOver )   {
         m_fMouseOver = true;
         pT->SendMessage(WM_MOUSEENTER, wParam, lParam);
         pT->Invalidate();
         if( m_fMouseForceUpdate ) pT->UpdateWindow();
         _StartTrackMouseLeave(pT->m_hWnd);
      }
      bHandled = FALSE;
      return 0;
   }
   LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
   {
      T* pT = static_cast<T*>(this);
      if( m_fMouseOver ) {
         m_fMouseOver = false;
         pT->Invalidate();
         if( m_fMouseForceUpdate ) 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__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Bjornar Henden
Web Developer
Norway Norway
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 2 Jun 2003
Article Copyright 2003 by Bjornar Henden
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid