mfc里实现句柄映射借助了两个类:句柄映射辅助类,模块--线程状态类
1.句柄映射辅助类:
class CHandleMap
{
private: // implementation
CFixedAllocNoSync m_alloc;
void (PASCAL* m_pfnConstructObject)(CObject* pObject);
void (PASCAL* m_pfnDestructObject)(CObject* pObject);
CMapPtrToPtr m_permanentMap; //永久映射
CMapPtrToPtr m_temporaryMap; //临时映射
CRuntimeClass* m_pClass;
size_t m_nOffset; // offset of handles in the object
int m_nHandles; // 1 or 2 (for CDC)
// Constructor/Destructor
public:
CHandleMap(CRuntimeClass* pClass,
void (PASCAL* pfnConstructObject)(CObject* pObject),
void (PASCAL* pfnDestructObject)(CObject* pObject),
size_t nOffset, int nHandles = 1);
#ifdef _AFXDLL
~CHandleMap()
#else
virtual ~CHandleMap()
#endif
{ DeleteTemp(); }
// Operations
public:
CObject* FromHandle(HANDLE h); //从句柄获取MFC对象
void DeleteTemp(); //删除临时句柄
void SetPermanent(HANDLE h, CObject* permOb); //向永久映射中添加一个记录
void RemoveHandle(HANDLE h); //从永久映射里删除一个记录
CObject* LookupPermanent(HANDLE h); //查找永久映射表
CObject* LookupTemporary(HANDLE h); //查处临时映射表
friend class CWinThread;
};
2.模板--线程状态类
class AFX_MODULE_THREAD_STATE : public CNoTrackObject
{
public:
AFX_MODULE_THREAD_STATE();
virtual ~AFX_MODULE_THREAD_STATE();
// current CWinThread pointer
CWinThread* m_pCurrentWinThread;
// list of CFrameWnd objects for thread
CTypedSimpleList<CFrameWnd*> m_frameList;
// temporary/permanent map state
DWORD m_nTempMapLock; // if not 0, temp maps locked
CHandleMap* m_pmapHWND;
CHandleMap* m_pmapHMENU;
CHandleMap* m_pmapHDC;
CHandleMap* m_pmapHGDIOBJ;
CHandleMap* m_pmapHIMAGELIST;
..........................................................
模板--线程状态的初始化在CWinApp的构造函数里完成,也就是说它比WinMain更早,构造函数主要完成模块状态,模板--线程状态,
以及线程和全局对象的初始化。
每当一个窗口类调用Create或CreateEx时,都要设置钩子:
AfxHookWindowCreate(this);这个函数的作用在这不多讲了,总之它在执行过程中调用了:Attach(m_hWnd);
Attach()的定义如下:
BOOL CWnd::Attach(HWND hWndNew)
{
ASSERT(m_hWnd == NULL);
ASSERT(FromHandlePermanent(hWndNew) == NULL);
if (hWndNew == NULL)
return FALSE;
CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist
ASSERT(pMap != NULL);
pMap->SetPermanent(m_hWnd = hWndNew, this); //加入到永久映射中
#ifndef _AFX_NO_OCC_SUPPORT
AttachControlSite(pMap);
#endif
return TRUE;
}
CWnd有这样几个函数:FromHandle(HWND hWnd),FromHandlePermanent(HWND hWnd).它们都用到CHandleMap类
函数定义如下:
CWnd* PASCAL CWnd::FromHandle(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND(TRUE); //如果不存在就创建它:afxMapHWND的作用
ASSERT(pMap != NULL);
CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd); //先从永久里找,再从临时中找,都找不到就创建一个Cwnd返回
#ifndef _AFX_NO_OCC_SUPPORT
pWnd->AttachControlSite(pMap);
#endif
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
return pWnd;
}
CWnd* PASCAL CWnd::FromHandlePermanent(HWND hWnd)
{
CHandleMap* pMap = afxMapHWND();
CWnd* pWnd = NULL;
if (pMap != NULL)
{
// only look in the permanent map - does no allocations
pWnd = (CWnd*)pMap->LookupPermanent(hWnd); //只从永久映射里找,如果找不到就返回NULL.
ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);
}
return pWnd;
}
当一个窗口函数要销毁的时候,也就是在它接收的最后一个WMNCDESTROY里会调用Detach()来解除窗口对象与CWnd对象的关系。
Detach()的定义如下:
HWND CWnd::Detach()
{
HWND hWnd = m_hWnd;
if (hWnd != NULL)
{
CHandleMap* pMap = afxMapHWND(); // don't create if not exist
if (pMap != NULL)
pMap->RemoveHandle(m_hWnd); //从永久映射里删除。
m_hWnd = NULL;
}
#ifndef _AFX_NO_OCC_SUPPORT
m_pCtrlSite = NULL;
#endif
return hWnd;
}
在程序空闲的时候,也就是在OnIdle函数,会自动删除临时的映射。