你的程序中必然对你的主窗口Attach(这是由Framework完成的),这样的话,假如你又得到了你程序的主窗口句柄hwndMain,你如果再调用FromHandle(hwndMain),它返回的将是你的App中的m_pMainWnd,原因就是FromHandle会维持一个内部的列表,纪录每个hwnd与CWnd的关联情况,如果一旦一个hwnd早已与某个CWnd对象相关连,它会返回该CWnd对象的指针。既然如此,FromHandle返回的便是m_pMainWnd,而此对象Framework会自动析构,因此你只是得到了该指针的一个副本,不能对其作析沟操作,否则会导致你的程序运行不正常。 
   考虑另外一种情况,就是一个hwnd与任何对象都没有关联(比如,你用API CreateWindow新建了一个窗口),此时的hwnd尚未与任何CWnd对象关联,如果你用FromHandle(hwnd),FromHandle便会临时new一个CWnd对象,并Attatch到此hwnd,然后返回给你。我刚才说了,FromHandle会维持一个hwnd与CWnd关联的列表,每当Framework OnIdle时,它便会检查此列表,一旦发现某个CWnd是FromHandle临时创建的对象,它便会首先Detach此对象,然后delete之。因此,你在程序中也不必delete从FromHandle得到的对象指针,但这种指针只在一次消息处理过程中有效。 
   另外还有FromHandlePermanent函数,它当且仅当hwnd已与某个CWnd对象关联时才返回此对象的指针,否则返回NULL。这也是它为什么叫Permanent——区别于FromHandle会new一个临时的CWnd对象。 
   对于GDI对象,以上的分析也是适用的。

   另外,以上只是一种比较抽象的理解,具体MFC的实现,你看一下MFC的源代码,应该会有很大的帮助(MFC公开源代码,真是太好不过了)。

CBitmap::FromHandle

static CBitmap* PASCAL FromHandle( HBITMAP hBitmap );

返回值:调用成功时返回一个指向CBitmap对象的指针,否则返回NULL。

参数:

hBitmap 指定一个Windows GDI 位图的句柄。

说明:
本函数在调用时指定一个Windows GDI 位图的句柄,返回一个指向CBitmap对象的指针。如果该句柄上没有相联系的CBitmap对象,则为该句柄建立一个临时CBitmap对象。该临时CBitmap对象保持有效,直到应用在它的事件循环中出现空闲时间,此时Windows会删除所有的临时图形对象。换句话说,临时对象仅在一个Windows消息的处理过程中有效。

MFC 对 Windows API 进行了封装,在很多方面都会提供便利。用 FromHandle 返回零时对象的指针,就可以调用各种类的方法。临时对象会在 OnIdle 中销毁。这里对 FromHandle 的实现原理从源码上进行解析。

// 
// 1 
// 
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 的 FromHandle 方法,大致的意思为从 CHandleMap 中获取临时 CWnd 对象的指针。

// 
// 2 
// 
CHandleMap* PASCAL afxMapHWND(BOOL bCreate) 

    AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState(); 
    if (pState->m_pmapHWND == NULL && bCreate) 
    { 
        BOOL bEnable = AfxEnableMemoryTracking(FALSE); 
#ifndef _AFX_PORTABLE 
        _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler); 
#endif

pState->m_pmapHWND = new CHandleMap(RUNTIME_CLASS(CTempWnd), 
            offsetof(CWnd, m_hWnd)); 
#ifndef _AFX_PORTABLE 
        AfxSetNewHandler(pnhOldHandler); 
#endif 
        AfxEnableMemoryTracking(bEnable); 
    } 
    return pState->m_pmapHWND; 
}

再看

#define offsetof(s,m)   (size_t)&(((s *)0)->m)

继续

// 
// 3 
// 
CObject* CHandleMap::FromHandle(HANDLE h) 

    ASSERT(m_pClass != NULL); 
    ASSERT(m_nHandles == 1 || m_nHandles == 2);

if (h == NULL) 
        return NULL;

CObject* pObject = LookupPermanent(h); 
    if (pObject != NULL) 
        return pObject;   // return permanent one 
    else if ((pObject = LookupTemporary(h)) != NULL) 
    { 
        HANDLE* ph = (HANDLE*)((BYTE*)pObject + m_nOffset); 
        ASSERT(ph[0] == h || ph[0] == NULL); 
        ph[0] = h; 
        if (m_nHandles == 2) 
        { 
            ASSERT(ph[1] == h || ph[1] == NULL); 
            ph[1] = h; 
        } 
        return pObject;   // return current temporary one 
    }

// This handle wasn't created by us, so we must create a temporary 
    // C++ object to wrap it.  We don't want the user to see this memory 
    // allocation, so we turn tracing off.

BOOL bEnable = AfxEnableMemoryTracking(FALSE); 
#ifndef _AFX_PORTABLE 
    _PNH pnhOldHandler = AfxSetNewHandler(&AfxCriticalNewHandler); 
#endif

CObject* pTemp = NULL; 
    TRY 
    { 
        pTemp = m_pClass->CreateObject(); 
        if (pTemp == NULL) 
            AfxThrowMemoryException();

m_temporaryMap.SetAt((LPVOID)h, pTemp); 
    } 
    CATCH_ALL(e) 
    { 
#ifndef _AFX_PORTABLE 
        AfxSetNewHandler(pnhOldHandler); 
#endif 
        AfxEnableMemoryTracking(bEnable); 
        THROW_LAST(); 
    } 
    END_CATCH_ALL

#ifndef _AFX_PORTABLE 
    AfxSetNewHandler(pnhOldHandler); 
#endif 
    AfxEnableMemoryTracking(bEnable);

// now set the handle in the object 
    HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset);  // after CObject 
    ph[0] = h; 
    if (m_nHandles == 2) 
        ph[1] = h;

return pTemp; 
}

转自:http://tsing01.blog.163.com/blog/static/205957283201242454821675/

http://blog.csdn.net/huys03/article/details/4549678

浅谈FromHandle相关推荐

  1. 浅谈MySQL存储引擎-InnoDBMyISAM

    浅谈MySQL存储引擎-InnoDB&MyISAM 存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式 ...

  2. 【大话设计模式】——浅谈设计模式基础

    初学设计模式给我最大的感受是:人类真是伟大啊!单单是设计模式的基础课程就让我感受到了强烈的生活气息. 个人感觉<大话设计模式>这本书写的真好.让貌似非常晦涩难懂的设计模式变的生活化.趣味化 ...

  3. 学校计算机机房好处,浅谈学校计算机机房维护

    浅谈学校计算机机房维护    现在的学校机房都配置了数量较多的计算机,而且机房的使用非常频繁.对于怎样维护好计算机,特别是计算机软件系统,对广大计算机教师来说是一个很重要且非常现实的问题.下面就本人在 ...

  4. java 中的单元测试_浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...

  5. mybatis与php,浅谈mybatis中的#和$的区别

    浅谈mybatis中的#和$的区别 发布于 2016-07-30 11:14:47 | 236 次阅读 | 评论: 0 | 来源: 网友投递 MyBatis 基于Java的持久层框架MyBatis 本 ...

  6. 浅谈GCC预编译头技术

    浅谈GCC预编译头技术 文/jorge --谨以此文,悼念我等待MinGW编译时逝去的那些时间. 其 实刚开始编程的时候,我是丝毫不重视编译速度之类的问题的,原因很简单,因为那时我用BASICA.后来 ...

  7. 【笔记】震惊!世上最接地气的字符串浅谈(HASH+KMP)

    震惊!世上最接地气的字符串浅谈(HASH+KMP) 笔者过于垃圾,肯定会有些错的地方,欢迎各位巨佬指正,感激不尽! 引用:LYD的蓝书,一本通,DFC的讲稿,网上各路巨佬 Luguo id: 章鱼那个 ...

  8. 浅谈几种区块链网络攻击以及防御方案之其它网络攻击

    旧博文,搬到 csdn 原文:http://rebootcat.com/2020/04/16/network_attack_of_blockchain_other_attack/ 写在前面的话 自比特 ...

  9. 浅谈几种区块链网络攻击以及防御方案之拒绝服务攻击

    旧博文,搬到 csdn 原文:http://rebootcat.com/2020/04/14/network_attack_of_blockchain_ddos_attack/ 写在前面的话 自比特币 ...

最新文章

  1. Linux加密和安全
  2. C#播放flash动画即swf文件
  3. python注释_不建议使用Java注释的正确方法
  4. js密码强度正则表达式_这20个正则表达式,能让你少写100行代码
  5. tf.data.Dataset 用法
  6. 圆与平面的接触面积_视频:5.3RJ六年级上册圆的面积例题+习题讲解
  7. SpringBoot 动态创建多定时任务
  8. java 子集_java – 带负数的子集和
  9. Megcup 2017 决赛第一题 规则
  10. 【版本控制工具】svn服务器、客户端安装配置及eclipse的svn检出
  11. 软件工程毕业设计选题java_软件工程毕业设计选题
  12. Liunx free命令
  13. Java面试题-微服务
  14. urllib中urlparse使用技巧以及iter_content图片边下边存到硬盘使用
  15. 智能镜子制作_更智能的镜子及其制作方法
  16. 一位架构师用服务打动客户的故事之二
  17. C++ Primer Plus(第六版)第6章 编程练习答案详解
  18. 京东618叠蛋糕脚本,亲测好用
  19. php mp3文件上传 类,PHP MP3歌曲文件上传
  20. Acwing语法基础课第八次课(1)751. 数组的左方区域最小数和它的位置741. 斐波那契数列740. 数组变换753. 平方矩阵 I

热门文章

  1. 关于医疗AI产品的商业模式的思考
  2. 经常说的ROI是什么,怎么计算
  3. 6月22日!苹果WWDC大会,全球免费参加-首次在线举行!
  4. 【苹果CMS技术教程】苹果CMSV10基础安装过程,如何拥有自己的视频网站
  5. 我们该如何高效的学习?
  6. 关于访问后端接口报404的问题——全网最详细的404错误详解
  7. 将两个各有n个元素的有序表归并成一个有序表,其最多的比较次数
  8. 【英语0基础·读音】【A鹿笔记】Day 1 ee,ea,ache组合
  9. Jmeter接口压力测试(先登录再测接口)
  10. 网络舆情事件热度如何的查询方法