话题引入:在C语言时代,当人们使用纯粹的C开发windows应用程序时,只需要通过窗口句柄HWND【HWND是WND的内存句柄,而WND是Windows是一个内部私有数据结构,存储着窗口的相关信息:尺寸信息、标题信息等。一般来说开发人员无法访问这个数据结构,不过可以以HWND为参数调用windows的API函数如:GetWindowRect、GetWindowText等获得对其的访问】即可完成有关窗口的操作。MFC类是C++类机制,MFC的类通过C++的对象方法将窗口的句柄封装起来。存在着窗口句柄(Windows对象)到MFC中C++窗口对象(MFC对象)之间的映射机制,该机制保证了HWND与C++对象之间的双向沟通,从而开辟了程序设计的一种全新模式。句柄映射机制主要包括两个类句柄映射辅助类、模块——线程状态类。参见书《MFC窗口程序设计 姚领田,高守传 中国水利水电出版社》第一章Windows窗口与Cwnd对象。
这个笔记描述了MFC的规则,这个规则支持窗口的对象句柄到C++对象的映射。
问题
窗口对象通常以HANDLEs的方式表示出来,MFC的类通过C++的对象方法将窗口的句柄封装起来。MFC类库的句柄封装函数提供了一个通过特殊的句柄封装窗口对象成C++对象的方法,很多时候窗口的对象并不具有一个C++的封装对象,然而,很多时候一个临时的对象会被建立起来来充当C++封装对象的作用。
The Windows objects that use handle maps are:
使用句柄映射的窗口对象如下:
HWND (CWnd and CWnd-derived classes) /CWnd类封装了HWND,存在窗口句柄HWND到MFC类对象CWnd之间的映射/
HDC (CDC and CDC-derived classes) /同理CDC封装了HDC,存在/
HMENU (CMenu)
HPEN (CGdiObject)
HBRUSH (CGdiObject)
HFONT (CGdiObject)
HBITMAP (CGdiObject)
HPALETTE (CGdiObject)
HRGN (CGdiObject)
HIMAGELIST (CImageList)
SOCKET (CSocket)
HWND是WND的内存句柄,窗体句柄,而WND是Windows是一个内部私有数据结构,存储着窗口的相关信息:尺寸信息、标题信息等。一般来说开发人员无法访问这个数据结构,不过可以以HWND为参数调用windows的API函数如:GetWindowRect、GetWindowText等获得对其的访问
HDC是设备描述表(Device Context)的句柄。设备描述表中记录和此设备相关的各种信息,比如对于显示器来说,记录了显示器的尺寸、分辨率,还有当前选择的画笔、画刷、字体等GDI对象的信息。 可以将HDC理解做一个设备的表面,比如显示器的表明,打印机的表面等等,我们可以使用这个HDC在这些表明上绘制图形——很多GDI绘图函数,都需要使用这个HDC作为参数的。
HMENU是菜单句柄。HPEN是画笔句柄。HBRUSH 画刷句柄。HFONT 字体句柄。HBITMAP位图句柄。HPALETTE 调色板句柄。HRGN 区域 (region)句柄。
通过给以上这些对象赋予句柄,你可以发现MFC的对象的封装操作是通过调用一个静态的成员函数 FromHandle来实现的。举例,已知一个值为hWnd的HWND CWnd::FromHandle(hWnd)
将会返回一个指向CWnd的指针,这个指针封装了hWnd。如果hWnd并没有产生一个明确的对象,那么一个临时的CWnd将被创建出来封装hWnd。这使通过任何句柄获得一个有效的C++对象变得可能。
一点你有了一个被封装的对象,你就能通过一个共有成员变量获得他的句柄。在CWnd这种情况下,m_hWnd包含这个对象的HWND句柄。
Attaching Handles to MFC Objects
已知一个新创建的已封装的句柄对象和一个指向窗口对象的句柄,你可以将这两者通过调用Attach联系起来。例如:
CWnd myWnd;
myWnd.Attach(hWnd);
这会建立起一个项目,这个项目是永久性的关联myWnd 和hWnd的一个映射。调用CWnd::FromHandle(hWnd) 将会返回一个指向myWnd的指针。当myWnd 被删除后,析构函数会自动的通过窗口函数DestroyWindow 销毁hWnd。如果你并不愿意这么做,那么hWnd 必须在myWnd 的对象被销毁之前同myWnd 相分离。(通常离开myWnd 定义的作用域中)
成员函数Detach 做这些工作。
myWnd.Detach();
临时对象
当FromHandle 被付给一个句柄的时候的时候并没有一个已经封装的C++对象,那么就会产生一个临时的对象。这些临时的对象是同他们的句柄相分离的,并且通过调用DeleteTempMap 函数进行删除。默认状况下OnIdle 时刻CWinThread 自动调用DeleteTempMap 来使每一个类都支持临时的句柄映射。这就意味着你不能假定一个指向临时对象的指针可以在获得该指针的函数退出时依然保持有效,在Windows消息循环空闲时间这个临时的对象就会被删除。
封装对象和多线程
临时对象和永久对象都是每一个线程的基础,那就是说,一个线程不能够访问其他线程的C++对象,无论是临时对象还是永久的对象,正如以上所述,当线程进入OnIdle.状态的时候临时的对象就会被删除。
在线程间传递这些对象通常使用他们自身的HANDLE 类型,在线程间传递C++封装的对象经常会造成异常。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sunnymov/archive/2010/05/24/5619699.aspx