全部博文(56)
分类: C/C++
2010-12-31 16:21:50
TN003: Mapping of Windows Handles to Objects
本文描述了将Windows对象句柄与C++对象映射的MFC方法。
问题的提出Windows对象一般反映为句柄。MFC类用C++对象封装Windows对象。MFC类库的句柄封装函数提供了判断某个C++对象是否封装了某个Windows对象句柄的功能。有时Windows对象并没有被封装的C++对象,但系统会创建一个临时对象,以封装此对象。
Windows对象使用的句柄映射如下:
l HWND(CWnd及其子类)
l HDC(CDC及其子类)
l HMENU(CMenu)
l HPEN(CGdiObject)
l HBRUSH(CGdiObject)
l HFONT(CGdiObject)
l HBITMAP(CGdiObject)
l HPALETTE(CGdiObject)
l HRGN(CGdiObject)
l HIMAGELIST(CImageList)
l SOCKET(CSocket)
给这些对象一个句柄,可以发现MFC对象调用静态成员函数FromHandle以封装此句柄。例如,给定一个HWND类型hWnd:
CWnd::FromHandle(hWnd)
将会返回一个封装了hWnd的CWnd的指针。若hWnd没有指定封装对象,则系统将自动创建一个临时CWnd对象以封装hWnd。这使得从一个句柄获得一个有效的C++对象成为可能。
一旦确定了封装对象,则可以通过其公开成员变量获取它的句柄。以CWnd为例,m_hWnd就是其HWND句柄。
句柄与MFC对象的绑定给定一个新创建的句柄封装对象及一个Windows对象句柄,可以通过调用Attach函数将两者绑定。例如:
CWnd myWnd;
myWnd.Attach(hWnd);
这将创建一个永久性的映射,将myWnd与hWnd相关联。调用CWnd::FromHandle(hWnd)将返回指向myWnd的指针。当myWnd被删除,析构函数将自动调用Windows函数DestoryWindow以销毁hWnd。若不想销毁hWnd,则在销毁myWnd(通常是离开myWnd定义的作用域)之前,必须将hWnd与myWnd解绑定。这可以用Detach成员函数实现:
myWnd.Detach();
当给FromHandle传递的句柄没有封装的对象,则会创建一个临时对象。可用DeleteTempMap函数将这些临时对象与其句柄解绑并销毁。CWinThread的OnIdle默认实现将自动为每一个支持临时句柄映射的类调用DeleteTempMap。这意味着不能假定一个指向临时对象的指针在离开了创建此指针的函数后仍是有效的,因为此临时对象将在Windows消息循环的空闲时刻被删除。
封装对象与多线程无论是临时对象还是永久对象都是以单线程为基础维护的。因此,在一个线程中不能访问另一个线程的C++封装对象,而不管此对象是临时的还是永久的。如上所述,临时对象会在此对象所属的线程进入OnIdle时被删除。
将这些对象从一个线程传递到另一个线程,必须以其本地句柄类型传递。将C++封装对象从一个线程中传递到另一个线程中经常会导致不可预料的异常。