深入解析MFC -- 句柄与对象的关系

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。非常简单,不是吗?

时间: 2024-09-20 18:48:11

深入解析MFC -- 句柄与对象的关系的相关文章

全面解析MFC应用程序框架

对于程序员来说,如果要提高编程效率,一个好用的,功能强大的并且可以得心应手使用的编程工具往往会给我们程序员带来莫大的方便.其实对于现在的编程工具来说,使用哪一种工具都不是问题的关键,重要的是你能够使用到什么程度,毕竟现在的工具都是非常的强大,对于一般的编程任务来说还没有不能够胜任的工具,否则的话恐怕他就不可能在这个世界上存在哪怕是只有一个月的生命. 但是根据个人所好以及周围的人的影响,我们都会去使用某一种或者几种工具.比较Visual Basic .C++ Builder和Delphi等编程工具

sdk-RTTI是什么?MFC和它有什么关系?

问题描述 RTTI是什么?MFC和它有什么关系? RTTI是什么呀?和MFC内部机制有什么关系,请简要用易懂的语言说说.我新手. 解决方案 详细去看<深入浅出MFC>(网上有电子版,专门有一章讲RTTI) 简单说下,RTTI就是运行时刻类型识别,它和DC&DI(动态创建)组合在一起,目的是为了让程序在运行的时候(而不是编译的时候)可以使用编译的时候不知道类型的代码. 一个典型的例子就是插件.我们知道,一个程序可以允许第三方编写插件程序,主程序调用.但是插件的代码是在主程序已经编写完成后

使用ibatis处理复杂对象数据关系的实例

如何使用 ibatis 处理复杂对象数据关系 iBatis 是一个开源的对象关系映射程序,其工作是将对象映射到 SQL 语句.和其它 O/R Mapping 框架不同,iBatis 开发者需要自己编写和维护 SQL 语句,这给开发带来了很多的灵活性的同时,也带来了很大的复杂度与工作量.在一个数据库中,常见的对象关系有:1 对 1,1 对多,多对多,单表映射,多表映射,单主键,多主键以及对象主键等种种情况.在使用 ibatis 处理数据映射时,需要跟据不同的情况,写出不同的 sql 语句和 sql

java-Java关于接口和类的对象的关系的问题

问题描述 Java关于接口和类的对象的关系的问题 先上代码 public interface Read{ } public class Student implements Read{ } public class Create{ private Read read; public void setRead(Read read){ this.read=read; } public Read getRead(){ return this.read; } } 现在在另一个类的方法中 Read rea

js对象根据属性名表达式解析成新的对象

问题描述 js对象根据属性名表达式解析成新的对象 如今有一个对象如下 var obj = { "name": "zhansan", "age": 21, "parent.name": "lisi", "parent.age": 44, "girlfriend[0].name": "fanbinbin", "girlfriend[0].ag

js函数和js对象之间关系

问题描述 js函数和js对象之间关系 function Pub(){ } Pub.submit=function(formindex) { document.forms[formindex].submit(); } 上面列子中 Pub是一个函数不是一个对象,为什么可以用Pub.submit= 啊,谁能指教一下啊,在此谢过 解决方案 在js里,函数本身就是类的作用.函数没有new Pub()之前是类还不是对象 直接函数名.属性,类似其他语言的静态属性 解决方案二: js对象 函数js中多层关系窗口

JavaScript中的对象继承关系_javascript技巧

我们今天就来看一下继承中的类继承以及类继承和原型继承的混用,所谓类继承,就是使用call或者apply方法来进行冒充继承: function Desk(size,height){ this.size=size; this.height=height; } function MJDesk(size,height){ Desk.call(this,size,height);//这种就叫类继承. } var mj = new MJDesk(10,123); 像上面这种就是我们要使用的类继承,用这种继承

GSON解析 json转java对象问题

问题描述 GSON解析 json转java对象问题 使用Gson将JSONObject objectObj 对象转换为Charge对象部分代码: Gson gs = new GsonBuilder().setDateFormat("yyyy-MM-dd").create(); Charge charge = gs.fromJson(objectObj.toString(), Charge.class); 问题是结果charge与objectObj结构一致但是某些字段的值不一样了!!!

jQuery解析Json字符串与对象的例子

 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,跟XML不相上下,在当今得到了广泛应用.有人说,当JS遇上Json,小JJ诞生啦:我说,当Json遇上xml,世界上又多了俩兄弟.近期看EasyUi视频里也全是Json作为前后台的数据交互,Json的有两种结构,分别是对象和数组: 1.对象:对象在js中表示为"{}"扩起来的内容,数据结构为: {key:value,key:value,-} 2.数