在VC++6.0的那个年代,MFC是不自带CMemDC操作类的,此类是为了解决双缓存绘图问题,当初因为项目需要自写了一个CMemDC类;现在MFC虽然自带了CMemDC类,但是不支持alpha通道,仍然很是鸡肋, 于是解决当初自写的CMemDC和MFC自带的CMemDC类重新编写了这个类(为了防止名字冲突,重命名CMemoryDC),代码如下:
class CMemoryDC : public CDC
{
public:
CMemoryDC(CDC& dc, CWnd* pWnd):
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_hOldBmp(NULL), m_hBmp(NULL), m_pWnd(pWnd)
{
ASSERT_VALID(pWnd);
pWnd->GetClientRect(m_rect);
m_rect.right += pWnd->GetScrollPos(SB_HORZ);
m_rect.bottom += pWnd->GetScrollPos(SB_VERT);
HDC hdcPaint = NULL;
m_hBufferedPaint = BeginBufferedPaint(dc.GetSafeHdc(), m_rect, BPBF_TOPDOWNDIB, NULL, &hdcPaint);
if (m_hBufferedPaint != NULL && hdcPaint != NULL)
{
m_bMemDC = TRUE;
this->Attach(hdcPaint);
}
else
{
if (this->CreateCompatibleDC(&m_dc))
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biHeight = m_rect.Height();
bi.bmiHeader.biWidth = m_rect.Width();
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biSizeImage = ((m_rect.Width() * 32 + 31) & (~31)) >> 3 * m_rect.Height();
PVOID pvBits = NULL;
m_hBmp = ::CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pvBits, 0, 0);//创建32位位图
m_hOldBmp = (HBITMAP)this->SelectObject((HBITMAP)m_hBmp);
}
}
}
CMemoryDC(CDC& dc, const CRect& rect):
m_dc(dc), m_bMemDC(FALSE), m_hBufferedPaint(NULL), m_hOldBmp(NULL), m_rect(rect), m_hBmp(NULL), m_pWnd(NULL)
{
ASSERT(!m_rect.IsRectEmpty());
m_pWnd = dc.GetWindow();
HDC hdcPaint = NULL;
m_hBufferedPaint = BeginBufferedPaint(dc.GetSafeHdc(), m_rect, BPBF_TOPDOWNDIB, NULL, &hdcPaint);
if (m_hBufferedPaint != NULL && hdcPaint != NULL)
{
m_bMemDC = TRUE;
this->Attach(hdcPaint);
}
else
{
if (this->CreateCompatibleDC(&m_dc))
{
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biHeight = m_rect.Height();
bi.bmiHeader.biWidth = m_rect.Width();
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biSizeImage = ((m_rect.Width() * 32 + 31) & (~31)) >> 3 * m_rect.Height();
PVOID pvBits = NULL;
m_hBmp = ::CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, &pvBits, 0, 0);//创建32位位图
m_hOldBmp = (HBITMAP)this->SelectObject((HBITMAP)m_hBmp);
}
}
}
virtual ~CMemoryDC()
{
if (m_hBufferedPaint != NULL)
{
this->Detach();
EndBufferedPaint(m_hBufferedPaint, TRUE);
}
else if (m_bMemDC)
{
CRect rectClip;
int nClipType = m_dc.GetClipBox(rectClip);
if (nClipType != NULLREGION)
{
if (nClipType != SIMPLEREGION)
{
rectClip = m_rect;
}
// 这种方式绘制会丢失alpha色彩信息
// m_dc.BitBlt(rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), this, rectClip.left, rectClip.top, SRCCOPY);
BLENDFUNCTION blendFunc32bpp;
blendFunc32bpp.AlphaFormat = AC_SRC_ALPHA;
blendFunc32bpp.BlendFlags = 0;
blendFunc32bpp.BlendOp = AC_SRC_OVER;
blendFunc32bpp.SourceConstantAlpha = 255;
::AlphaBlend(m_dc.GetSafeHdc(), rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(),
m_hDC, rectClip.left, rectClip.top, rectClip.Width(), rectClip.Height(), blendFunc32bpp);
//::UpdateLayeredWindow(m_pWnd->GetSafeHwnd(), m_dc.GetSafeHdc(), NULL, &CSize(rectClip.Width(), rectClip.Height()), GetSafeHdc(), &CPoint(rectClip.left, rectClip.top), 0, &blendFunc32bpp, ULW_COLORKEY | ULW_ALPHA);
}
this->SelectObject((HBITMAP)m_hOldBmp);
}
}
CDC& GetDC() { return m_bMemDC ? *this : m_dc; }
BOOL IsMemDC() const { return m_bMemDC; }
BOOL IsVistaDC() const { return m_hBufferedPaint != NULL; }
protected:
CDC& m_dc;
BOOL m_bMemDC;
HANDLE m_hBufferedPaint;
HBITMAP m_hBmp;
HBITMAP m_hOldBmp;
CRect m_rect;
CWnd* m_pWnd;
};