TN003: Mapping of Windows Handles to Objects
技术文章003:Windows句柄到(C++)对象的映射
This note describes the MFC routines that support mapping Windows object handles to C++ objects.
此章节讲述了支持Windows对象句柄到C++对象的映射这一MFC常规内容。
The Problem
Windows objects are normally represented by HANDLEs. The MFC classes wrap Windows object handles with C++ objects. The handle wrapping functions of the MFC class library provide a way to find the C++ object that is wrapping the Windows object with a particular handle. There are times when a Windows object does not have a C++ wrapper object, however, and at these times a temporary object is created to act as the C++ wrapper.
问题
Windows对象通常由HANDLEs来表示。MFC类把Windows对象句柄与C++对象关联在一起。MFC类库的句柄关联函数提供了一种方法来找出与某有着独特句柄的Windows对象相关联C++对象。然而,有时一个Windows对象没有一个与之相关联的C++对象,在这种情况下,一个临时的C++对象会被创建,并用来与之关联。
The Windows objects that use handle maps are:
Windows对象句柄与C++对象的映射关系如下:
- HWND (CWnd and CWnd-derived classes)
- HDC (CDC and CDC-derived classes)
- HMENU (CMenu)
- HPEN (CGdiObject)
- HBRUSH (CGdiObject)
- HFONT (CGdiObject)
- HBITMAP (CGdiObject)
- HPALETTE (CGdiObject)
- HRGN (CGdiObject)
- HIMAGELIST (CImageList)
- SOCKET (CSocket)
Given a handle to any of these objects, you can find the MFC object that wraps the handle by calling the static member function FromHandle. For example, given an HWND called hWnd:
CWnd::FromHandle(hWnd)
will return a pointer to the CWnd that wraps the hWnd. If that hWnd does not have a specific wrapper object, then a temporary CWnd is created to wrap the hWnd. This makes it possible to get a valid C++ object from any handle.
给你指向任意这些对象的一个句柄,你通过调用静态成员函数FromHandle来找出与此句柄关联的MFC对象。例如,给你一个叫做hWnd的HWND,CWnd::FromHandle(hWnd)将会返回一个指针,此指针指向与hWnd相关联的CWnd对象。如果hWnd没有一个明确的与之相关联的对象,那么一个临时的CWnd对象将会被创建,用来与hWnd相关联。这使得从任何句柄得到一个有效的C++对象成为可能。
Once you have a wrapper object, you can get to its handle through a public member variable. In the case of an CWnd, m_hWnd contains the HWND for that object.
一旦你有一个与某句柄相关联的对象,那么你可以通过一个公有的成员变量来得到它的句柄。对于一个CWnd对象而言,m_hWnd表示与之相关联的句柄HWND。
Attaching Handles to MFC Objects
Given a newly created handle-wrapper object and a handle to a Windows object, you can associate the two by calling Attach. For example:
CWnd myWnd;
myWnd.Attach(hWnd);
This makes an entry in the permanent map associating myWnd and hWnd. Calling CWnd::FromHandle(hWnd) will now return a pointer to myWnd. When myWnd is deleted, the destructor will automatically destroy the hWnd by calling the Windows DestroyWindow function. If this is not desired, the hWnd must be detached from myWnd before the myWnd object is destroyed (normally when leaving the scope at which myWnd was defined). The Detach member function does this.
myWnd.Detach();
将句柄与MFC对象关联
给你一个刚刚创建的与某句柄相关联的对象和一个指向Windows对象的句柄,通过调用Attach可使之关联。例如:
CWnd myWnd;
myWnd.Attach(hWnd);
这样就使得myWnd 和 hWnd永久地关联在一起。现在调用CWnd::FromHandle(hWnd)的话将会返回一个指向myWnd的指针。当myWnd被删除时,析构函数会自动地调用Windows的DestroyWindow来销毁hWnd。如果你不想让它这样做,那么在myWnd这个对象销毁(通常情况下,是在离开定义myWnd的范围)之前,必须将hWnd与myWnd分离。成员函数Detach可以帮你实现这一功能。
More About Temporary Objects
Temporary objects are created whenever FromHandle is given a handle that does not already have a wrapper object. These temporary objects are detached from their handle and deleted by the DeleteTempMap functions. The default OnIdle processing in CWinThread automatically calls DeleteTempMap for each class that supports temporary handle maps. This means that you cannot assume a pointer to a temporary object will be valid past the point of exit from the function where the pointer was obtained, as the temporary object will be deleted during the Windows message-loop idle time.
更多信息关于临时对象
每当传递给FromHandle的句柄没有一个与之相关联的对象时,临时对象就会被创建。通过调用DeleteTempMap函数可以将这些临时对象与它们的句柄分离,并将它们删除。在CWinThread 里的OnIdle函数为每个支持临时句柄映射的类自动调用DeleteTempMap。那意味着你不能假定一个指向临时对象的指针一直在程序退出之前都是有效的,因为临时对象会在Windows消息循环的空闲时间里被删除掉。
Wrapper Objects and Multiple Threads
Both temporary and permanent objects are maintained on a per-thread basis. That is, one thread cannot access another thread’s C++ wrapper objects, regardless of whether it is temporary or permanent. As stated above, temporary objects are deleted when the thread which that temporary object belongs enters OnIdle.
To pass these objects from one thread to another, always send them as their native HANDLE type. Passing a C++ wrapper object from one thread to another will often result in unexpected results.
与句柄关联的对象和多线程
不管是临时对象还是持久对象,它们都是基于单线程的基础之上的。那就是说,一个线程不能访问另一个线程的与句柄相关联的C++对象,不管此对象是临时的还是持久的。按照上述规定,临时对象将会在它们所属的线程进入OnIdle时被删除。
为了在线程之间传递这些对象,经常发送它们自己的HANDLE类型。将一个与句柄相关联的C++对象从一个线程传递到另一个线程会经常导致意想不到的结果。