Windows对象、句柄与MFC对象
(2009-04-28 22:11:34)
Windows对象是以句柄来标识的,对应的MFC类就是这些句柄的C++包装。内存中的Windows对象一定有唯一的句柄来标识,但不 一定有对应的MFC类对象在内存中。当需要获取Windows对象的对应MFC类对象而内存中又没有此对象时,系统会创建一个临时MFC类对象返回给用 户,并在之后某个空闲时刻进行回收。
Windows对象句柄及其对应的MFC类如下表所示:
HWND
|
CWnd及派生类
|
HDC
|
CDC及派生类
|
HMENU
|
CMenu
|
HPEN、HBRUSH、HFONT、HBITMAP、HPALETTE、HRGN
|
CGdiObject
|
HIMAGELIST
|
CImageList
|
SOCKET
|
CSocket
|
如果你拥有上面的任何一个Windows对象句柄,你可以调用对应类的静态成员函数FromHandle来查找对应的MFC对象(系统为每个
线程维护了一个从Windows对象句柄到MFC对象的映射,一个持久的map和一个临时的map);如果你拥有上面的MFC对象,你也可以通过MFC类
的公有成员变量来获取对应的Windows对象句柄。
例如,给定一个HWND类型的句柄hWnd,可以通过
来获得CWnd对象的指针。如果hWnd没有对应的CWnd对象,则系统会产生一个临时CWnd对象与hWnd关联,并返回该对象的指针。在获得CWnd对象后,你可以通过CWnd的公有成员m_hWnd获得窗口对象的句柄。
如果在调用FromHandle时产生临时MFC对象,句柄和MFC对象之间的映射被保存在系统的临时map中。默认情况
下,CWinThread::OnIdle自动为那些支持临时句柄映射的MFC类调用DeleteTempMap函数。在DeleteTempMap函数
中,这些临时对象将被取消与句柄的关联,然后被销毁。
如果你拥有一个Windows对象句柄,那么你可以创建一个对应的MFC对象,然后把该MFC对象与该Windows对象句柄进行关联。此时,该MFC对象与Windows对象相互建立起映射关系。
例如,对于如下代码:
CWnd myWnd;
myWnd.Attach(hWnd);
|
将建立起hWnd到myWnd的映射。此后,你调用CWnd::FromHandle(hWnd)将返回myWnd对象的指针。如果myWnd
对象被销毁,它的析构函数将自动通过调用DestroyWindow来销毁该hWnd所指Windows对象。如果该行为不是所期望的,则需要在
myWnd销毁之前调用Detach成员函数解除两者之间的关联(映射),如 myWnd.Detach()。
所有临时MFC对象和持久(permanent)MFC对象都是以线程为单位进行维护管理的。也就是说,一个线程不能够访问另一个线程的MFC包装类对象,不管它是临时的还是持久的。
为了在不同的线程间传递这些Windows对象,总是应该通过HANDLE类型传递。从一个线程向另一个线程传递MFC包装对象将可能引起不可预料的结果。
由于MFC包装类对象是以线程为单位进行管理的,因此,在程序中的不同线程中可能有多个MFC对象与同一个句柄对应。
存在的疑问:如果同一线程中有多个MFC对象Attach同一句柄,那么对该句柄调用FromHandle将返回哪个MFC对象呢?未定义行为?