CWnd::FromHandlePermanent ——根据窗口句柄得到CWnd*指针

This function, unlike FromHandle, does not create temporary objects.

 

CWnd::FromHandle——根据窗口句柄得到CWnd*指针

CWnd* PASCAL CWnd::FromHandle(HWND hWnd)

{

 CHandleMap* pMap = afxMapHWND(TRUE); //create map if not exist

 ASSERT(pMap != NULL);

 CWnd* pWnd = (CWnd*)pMap->FromHandle(hWnd);

#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();  //即,afxMapHWND(FALSE);  

 CWnd* pWnd = NULL;

 if (pMap != NULL)

 {

  // only look in the permanent map - does no allocations

  pWnd = (CWnd*)pMap->LookupPermanent(hWnd);

  ASSERT(pWnd == NULL || pWnd->m_hWnd == hWnd);

 }

 return pWnd;

}

 

 

在Windows体系中,很多对象都是以句柄的形式展示给开发人员的。比如窗口句柄(HWND),绘图设备(HDC)等等。然后大部分的API函数则围绕 这些句柄做文章。比如ShowWindow,SetWindowText,TextOut等等。这些API函数的第一个参数通常就是句柄了。但是在C++ 体系中,这种对于事物细节的访问,往往是有违其封装精神的。因此MFC做了很多的封装类,来隐藏这些细节。应运而生就是CWnd,CDC等类。通过这些类 暴露的方法,可以直接对句柄做操作,而又可以不去关心他。

不过,我们今天的主题不在这里。以下才是真正的内容。

按照C++的理论,被封装的句柄的创建和销毁都应该由类本身来完成,外界不了解其中细节。但是在MFC中,真是这样吗?至少CWnd不是这样,HWND并 不完全在CWnd的掌控之中。在前一章我提到过,MFC中有大量的全局变量,其中一个全局变量是一张HWND与CWnd的Map表。这个Map表的位置不 好找,上章提到过全局对象AFX_MODULE_STATE,他其中有一个成员的类型是AFX_MODULE_THREAD_STATE,在 AFX_MODULE_THREAD_STATE的内部,则有着一群Map表,m_pmapHWND正是其中一个:


CHandleMap m_pmapHWND;

CHandleMap* m_pmapHMENU;

CHandleMap* m_pmapHDC;

CHandleMap* m_pmapHGDIOBJ;

CHandleMap* m_pmapHIMAGELIST;

看到了吗?找起来是比较麻烦,不过MFC提供了全局函数afxMapHWND,无论在哪个地方,调用这个函数都能轻松的获得这个Map表。

那么,这个表到底有什么作用呢?其实非常简单,虽然在MFC中,都是对象在与对象打交道。但是MFC也要与Windows系统打交道。Windows给你的只有句柄,那么如何通过这些句柄找到相对应的类呢?通过Map表就能轻松的解决这个问题。

比如在Windows的消息机制中,当WndProc接收到一个消息的时候,只会得到一个HWND hWnd的目标窗口,如何找到匹配的类?从m_pmapHWND中搜索就行了。通过调用CWnd的静态成员函数FromHandlePermanent,我们就能轻松的从Map表中找到与hWnd相对应的CWnd类。

FromHandlePermanent的实现也非常简单。首先通过afxMapHWND找到m_pmapHWND,然后通过m_pmapHWND的成员函数LookupPermanent查找与hWnd对应的CWnd指针,最后返回他。

m_pmapHWND是什么时候被创建的呢?在第一个窗口被创建出来的时候,会调用CWnd的Attach函数,下面是具体的函数实现:

BOOL CWnd::Attach(HWND hWndNew)

{

if (hWndNew == NULL) return FALSE;

CHandleMap* pMap = afxMapHWND(TRUE); // create map if not exist

pMap->SetPermanent(m_hWnd = hWndNew, this);

return TRUE;

}

注意调用afxMapHWND的传入的参数为TRUE,这表示当Map不存在时,则创建他。再让我们看看afxMapHWND的实现:

CHandleMap* PASCAL afxMapHWND(BOOL bCreate)

{

AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();

if (pState->m_pmapHWND == NULL && bCreate)

{

 pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CWnd),

  ConstructDestruct<CWnd>::Construct, ConstructDestruct<CWnd>::Destruct,

  offsetof(CWnd, m_hWnd));

}

return pState->m_pmapHWND;

}

afxMapHWND首先从我们前面说的地方找到这个指针,如果指针为空,并且bCreate为TRUE,则创建一个新的CHandleMap。非常简单,不是吗?