一、 ::GetDC 与 ::ReleaseDC
函数原型:
HDC GetDC(HWND hWnd);
int ReleaseDC(HWND hWnd, HDC hDC);
GetDC获取窗口客户区域的设备环境。每次获取一个设备环境时都会用默认属性对它进行初始化。
GetDC与ReleaseDC一定要配对使用,否则GetDC没有ReleaseDC会有资源泄露。
GetDC获取的设备环境变量由Windows系统管理,数量是有限的,Windows开辟一个固定大小的空间存储某一数量的设备环境变量,GetDC会占用一个设备环境变量,只有ReleaseDC了,才能释放了这个环境变量的位置,也才能被后续的程序使用。
对应的CWnd::GetDC 与CWnd::ReleaseDC也需要配对使用。
我们可以看下CWnd::GetDC与CWnd::ReleaseDC的源码
CDC* CWnd::GetDC()
{ return CDC::FromHandle(::GetDC(m_hWnd)); }
int CWnd::ReleaseDC(CDC* pDC)
{ return ::ReleaseDC(m_hWnd, pDC->m_hDC); }
注意:
我们可以对同一个窗口多次调用GetDC获取设备环境句柄,当然每次的句柄值都是不一样的,因为虽然它们是同一个窗口的设备环境变量,但我们可以多次调用获得多个,并且设置每个环境句柄拥有不同的属性值。必须要理解这个。
二、 CDC::FromHandle
先看下源码
CDC* PASCAL CDC::FromHandle(HDC hDC)
{
CHandleMap* pMap = afxMapHDC(TRUE); //create map if not exist
ASSERT(pMap != NULL);
CDC* pDC = (CDC*)pMap->FromHandle(hDC);
ASSERT(pDC == NULL || pDC->m_hDC == hDC);
return pDC;
}
可以看出,程序会从CHandleMap中去寻找和hDC对应的CDC。
MFC程序存在一个全局的CHandleMap变量,它记录程序中和HDC相关联的CDC之间的映射关系。
class CHandleMap
{
private:
CMapPtrToPtr m_permanentMap;
CMapPtrToPtr m_temporaryMap;
};
pMap->FromHandle(hDC)
会先从m_permanentMap中去查找和hDC关联的CDC对象,也就是说先查询看看有没有CDC对象和hDC关联。
如果有则返回该CDC对象的指针。
如果没有则在m_temporaryMap中去查找,如果有则返回该CDC对象的指针,如果没有,则会自动创建一个临时的CDC对象和hDC关联,并在m_temporaryMap中记录映射关系,并返回该CDC对象的句柄。
m_permanentMap和m_temporaryMap有什么区别呢?
一个是临时的映射map对象,一个是永久的映射map对象。
可以这么理解,临时的映射map对象中存储的CDC的指针,该CDC对象是由程序框架创建的,在程序空闲时会自动释放,不用用户自己释放。
而永久的映射map对象中存储的CDC的指针,该CDC对象是由用户自己创建的,需要用户自己释放。当CDC对象是由用户new的时候,一定要调用delete,当然如果CDC对象创建在栈上,在生存周期结束时会自动调用析构函数。
三、 CDC::Attach 与 CDC::Detach
先看下源码:
BOOL CDC::Attach(HDC hDC)
{
m_hDC = hDC;
CHandleMap* pMap = afxMapHDC(TRUE); // create map if not exist
pMap->SetPermanent(m_hDC, this);
return TRUE;
}
HDC CDC::Detach()
{
HDC hDC = m_hDC;
CHandleMap* pMap = afxMapHDC(); // don't create if not exist
if (pMap != NULL)
pMap->RemoveHandle(m_hDC);
m_hDC = NULL;
return hDC;
}
可以看出,Attach用于实现HDC和CDC之间的映射关系。Detach用于解除HDC和CDC之间的映射关系。
都是对CHandleMap中的m_permanentMap进行操作。
class CHandleMap
{
private:
CMapPtrToPtr m_permanentMap;
CMapPtrToPtr m_temporaryMap;
};
四、 CDC::~CDC()
先看下源码:
CDC::~CDC()
{
if (m_hDC != NULL)
::DeleteDC(Detach());
}
看以看出,在析构时会释放HDC资源。