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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: CWnd::FromHandlePermanent ——根据窗口句柄得到CWnd*指针 This function, unlike FromHandle, does not create temporary objects.

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。非常简单,不是吗?
目录
相关文章
|
17天前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
2月前
|
存储 编译器 C语言
C++类与对象深度解析(一):从抽象到实践的全面入门指南
C++类与对象深度解析(一):从抽象到实践的全面入门指南
51 8
|
2月前
|
Python
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
深入解析 Python 中的对象创建与初始化:__new__ 与 __init__ 方法
21 1
|
3月前
|
设计模式 存储 人工智能
深度解析Unity游戏开发:从零构建可扩展与可维护的游戏架构,让你的游戏项目在模块化设计、脚本对象运用及状态模式处理中焕发新生,实现高效迭代与团队协作的完美平衡之路
【9月更文挑战第1天】游戏开发中的架构设计是项目成功的关键。良好的架构能提升开发效率并确保项目的长期可维护性和可扩展性。在使用Unity引擎时,合理的架构尤为重要。本文探讨了如何在Unity中实现可扩展且易维护的游戏架构,包括模块化设计、使用脚本对象管理数据、应用设计模式(如状态模式)及采用MVC/MVVM架构模式。通过这些方法,可以显著提高开发效率和游戏质量。例如,模块化设计将游戏拆分为独立模块。
204 3
|
3月前
|
JavaScript 前端开发 API
Javaweb之javascript的BOM对象的详细解析
BOM为Web开发提供了强大的API,允许开发者与浏览器进行深入的交互。合理使用BOM中的对象和方法,可以极大地增强Web应用的功能性和用户体验。需要注意的是,BOM的某些特征可能会在不同浏览器中表现不一致,因此在开发过程中需要进行仔细的测试和兼容性处理。通过掌握BOM,开发者能够制作出更丰富、更动态、更交互性的JavaWeb应用。
36 1
|
4月前
|
存储 JavaScript 前端开发
一文带你深度解析:JavaScript中对象与数组的威力究竟有多大?
一文带你深度解析:JavaScript中对象与数组的威力究竟有多大?
|
7月前
|
存储 算法 Java
滚雪球学Java(42):探索对象的奥秘:解析Java中的Object类
【5月更文挑战第17天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
56 2
滚雪球学Java(42):探索对象的奥秘:解析Java中的Object类
|
6月前
|
消息中间件 监控 安全
深入解析Linux命令ipcmk:IPC对象管理新视角
`ipcmk`非标准Linux命令,假设的IPC对象创建工具,用于演示如何管理消息队列、信号量和共享内存。虽无此命令,但理解其概念有助于掌握IPC管理。例如,创建命名消息队列`my_mq`,最大1000消息,可模拟使用`ipcmk -t mq -n my_mq -q 1000`。实际操作中,应根据需求选择合适IPC机制,设置安全权限,监控使用并及时清理。
|
6月前
|
存储 缓存 Java
Java对象内存布局深度解析
Java对象内存布局深度解析
|
6月前
|
缓存 Java 数据库连接
解析Hibernate与JPA:Java对象的数据库化之旅
【6月更文挑战第25天】在Java企业开发中,Hibernate和JPA提供优雅的数据持久化方案。Hibernate是JPA规范的强大ORM实现,简化对象与数据库映射。配置环境后,通过@Entity注解定义实体类映射表,如`User`类映射&quot;users&quot;表。利用JPA的EntityManager执行查询和更新,如JPQL查询及对象更新。事务管理和性能优化是关键,确保数据完整性和应用性能。本文揭示了Hibernate与JPA的最佳实践,助开发者从容应对数据持久化。
48 0

推荐镜像

更多