深入解析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_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。非常简单,不是吗?
深入解析MFC -- 句柄与对象的关系的更多相关文章
- Celery 源码解析三: Task 对象的实现
Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...
- 浅解析js中的对象
浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...
- O-C相关-06:对象与对象的关系
对象与对象的关系 1.对象与对象的关系 依赖 关联 组合 常常讨论对象与对象关系时会提供两个属于:内聚性,耦合性 内聚一般指功能上的指向性 耦合一般指关联上的依赖性 2.依赖: 对象之间最弱的一种关联 ...
- 如何利用.Net内置类,解析未知复杂Json对象
如何利用.Net内置类,解析未知复杂Json对象 如果你乐意,当然可以使用强大的第三方类库Json.Net中的JObject类解析复杂Json字串 . 我不太希望引入第三方类库,所以在.Net内置类J ...
- FastJson将json解析成含有泛型对象,内部泛型对象再次解析出错的解决办法(Android)
折腾小半天的问题,这里先感谢一下深圳的小伙子,远程帮我搞,虽然也没有搞出来==========FUCK 声明:Android开发下发生此异常,Java开发下并不会有这个问题 异常重现 简单说一下抛出异 ...
- js 原型 函数和对象的关系
函数就是对象的一种 instanceof 可以做判断 var fn = function(){}; fn instanceof Object //true Object构造函数的prototype ...
- 2.java面向对象类与类/类与对象之间关系详解
继承.实现.依赖.关联.聚合.组合的联系与区别 下面的内容很基础,同时也很简单,但是也很重要. 继承 指的是一个类(称为子类.子接口)继承另外的一个类(称为父类.父接口)的功能,并可以增加它自己的新功 ...
- kubernetes之configmap,深度解析mountPath,subPath,key,path的关系和作用
参考:https://www.cnblogs.com/breezey/p/6582082.html 我们知道,在几乎所有的应用开发中,都会涉及到配置文件的变更,比如说在web的程序中,需要连接数据库, ...
- JSON 与 JS 对象的关系
很多人搞不清楚 JSON 和 Js 对象的关系,甚至连谁是谁都不清楚.简单来说: JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串. 如 var obj ...
随机推荐
- 关于Qt信号与槽机制的传递方向性研究(结论其实是错误的,但是可以看看分析过程)
最近由于项目的需求,一直在研究Qt.信号与槽机制是Qt的一大特色,该机制允许两者间传递参数,依次来实现对象间的通信.这个参数会分别存在于信号的参数列表和槽函数的参数列表中.需要注意的是,若将槽函数绑定 ...
- C#获取桌面壁纸图片的路径(Desktop Wallpaper)
原文 C#获取桌面壁纸图片的路径(Desktop Wallpaper) 利用 Windows 的 API 获取桌面壁纸的实际路径,使用的是 SystemParametersInfo 这个API,此AP ...
- json数据与字符串的相互转化
json转成string[需要引用json2.js文件]: var arr=[{id:'id',name:'Spring'},{id:'id2',name:'Jane'}]; var str=JSON ...
- BZOJ 1022 小约翰的游戏 (Anti-Nim游戏)
题解:注意题目中规定取到最后一粒石子的人算输,所以是Anti-Nim游戏,胜负判断为: 先手必胜: 1.所有堆的石子数都为1且游戏的SG值为0: 2.有些堆的石子数大于1且游戏的SG值不为0. #in ...
- Eclipse RCP扩展
它跟普通的插件扩展点是一样的写法,你只需要看 eclipse 自带的源码,打开你的 eclipse 目录,插件 *.exsd 找到后在 eclipse 中查看这个文件夹对应的插件的源码,里面有 plu ...
- 笔试题:金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出
收集这道题目原因是以前做过,但是实现的很麻烦,这次看到别人写的感觉简单易懂. 从一个pdf看到,出处就不贴了 = .= public class RenMingBi { private static ...
- 框架技术--Spring自动加载配置
今天项目中遇到一个问题,一个方法在服务启动后会自动被执行,查看了下配置未发现有定时的配置.但是后来发现是spring配置了启动时默认加载了方法. 代码: <?xml version=" ...
- powershell 生成随机用户信息
#生成随机用户信息,包括姓名.QQ.邮箱,手机号 $nameArr=@('一','丁','三','专','世','业','丝','中','丰','临','丹','丽','举','乃','义', '乐' ...
- leetcode第一刷_Construct Binary Tree from Inorder and Postorder Traversal
这道题是为数不多的感觉在读本科的时候见过的问题. 人工构造的过程是如何呢.兴许遍历最后一个节点一定是整棵树的根节点.从中序遍历中查找到这个元素,就能够把树分为两颗子树,这个元素左側的递归构造左子树,右 ...
- Linux升级Python提示Tkinter模块找不到解决
一.安装tkinter 在Linux中python默认是不安装Tkinter模块, [root@li250- ~]# python Python (r266:, Feb , ::) [GCC (Red ...