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 == || m_nHandles == );
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[] == h || ph[] == NULL);
ph[] = h;
if (m_nHandles == )
{
ASSERT(ph[] == h || ph[] == NULL);
ph[] = 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[] = h;
if (m_nHandles == )
ph[] = h;
return pTemp;
}

解析 MFC 中的 FromHandle的更多相关文章

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

    CWnd::FromHandlePermanent ——根据窗口句柄得到CWnd*指针 This function, unlike FromHandle, does not create tempor ...

  2. MFC中的一些视图

    本章主要介绍MFC中主要的视图类,这些继承自Cview类. 继承关系如上图所示. 滚动视图 CscrollView给Cview添加了基本的滚动功能,它包含WM_VSCROLL和WM_HSCROLL消息 ...

  3. MFC中线程相关知识

    MFC中把线程分为两种类型,UI线程和工作者线程. MFC中启动一个线程的最好方法是调用AfxBeginThread,有两个版本,一个用于启动Ui线程,另外一个用于启动工作者线程.在MFC程序中,只有 ...

  4. MFC中获取各个窗口之间的句柄或者指针对象的方法

    MFC在非常多的对话框操作中,我们常常要用到在一个对话框中调用还有一个对话框的函数或变量.能够用例如以下方法来解决.    HWND hWnd=::FindWindow(NULL,_T("S ...

  5. 深度解析VC中的消息(转发)

    http://blog.csdn.net/chenlycly/article/details/7586067 这篇转发的文章总结的比较好,但是没有告诉我为什么ON_MESSAGE的返回值必须是LRES ...

  6. C运行时库(C Run-time Library)详解(提供的另一个最重要的功能是为应用程序添加启动函数。Visual C++对控制台程序默认使用单线程的静态链接库,而MFC中的CFile类已暗藏了多线程)

    一.什么是C运行时库 1)C运行时库就是 C run-time library,是 C 而非 C++ 语言世界的概念:取这个名字就是因为你的 C 程序运行时需要这些库中的函数. 2)C 语言是所谓的“ ...

  7. 【VS开发】MFC中调用C函数模块的解决方案

    [VS开发]MFC中调用C函数模块的解决方案 标签(空格分隔): [VS开发] 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 说明:最近调试基于MFC的程序 ...

  8. 浅解析js中的对象

    浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...

  9. MFC中使用FLASH

    一.准备工作 第一步:下载并安装Adobe Flash Player. 从官方网站(http://get.adobe.com/cn/flashplayer/)上下载最新的Flash Player(大约 ...

随机推荐

  1. SVN 如何更换IP地址

    一.进去项目空白处. 二.点击右键TortoiseSVN. 三.选中Relocate. 四.弹出框如下: 把原来的IP地址更换成新的IP地址,再点击OK就可以了.

  2. html中调用本地exe应用程序

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. 关于chrome被篡改主页修复方法

    打开chrome的属性. 在目标框中追加以下内容 "PATH\chrome.exe" --flag-switches-begin --flag-switches-end about ...

  4. jsoup解析xml某片段的问题

    参考: http://blog.csdn.net/qy20115549/article/details/53556928 <tr> <td class='center'> &l ...

  5. mysql创建用户及授权

    创建本地账号 create user 'egon1'@'localhost' identified by '123'; # mysql -uegon1 -p123 创建远程账号 create user ...

  6. Mac中自定义文件夹中文名

    在OSX系统中,我们打开finer,就会看到很多中文名的文件夹,比如“应用程序”.“桌面”等等,而在系统中都是以英文命名的.我们也可以自己去设置中文名. 首先需要找到设置中文的字符串资源文件,路径是/ ...

  7. MySQL之避免插入重复数据

    INSERT ignore INTO `$table_name`($field_name) VALUES(),(),(),()"; //若重复数据可以添加,请在对应的数据表字段中添加数据库索 ...

  8. 用spin和edit控件来用spin控制edit里面小数的增减

    1.响应SPIN的消息,就是点SPIN的上键头和下键头的消息,在这个消息里改变值是以0.1步进量增减.2.使用UpdateData(FALSE)来更新EDIT的关联的double型的变量. 创建步骤 ...

  9. hoj2662 Pieces Assignment

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  10. [HNOI2010] 公交线路 bus

    标签:状态压缩+矩阵快速幂. 题解: 首先看范围,p<=10,那么我们可以想到状态压缩.我们把从一个长度为10的区间进行压缩,1代表可以,那么当值一个区间的1的个数为k个,我们就认为他是合法的. ...