TN003:将 Windows 句柄映射到对象
此说明介绍了支持将 Windows 对象句柄映射到 C++ 对象的 MFC 例程。
问题
Windows 对象通常由各种 HANDLE 对象表示。MFC 类使用 C++ 对象包装 Windows 对象句柄。 通过 MFC 类库的句柄包装函数,可以找到包装具有特定句柄的 Windows 对象的 C++ 对象。 但是,有时对象没有 C++ 包装对象,而此时系统会创建一个临时对象来充当 C++ 包装器。
使用句柄映射的 Windows 对象如下所示:
HWND(CWnd 和
CWnd
派生类)HDC(CDC 和
CDC
派生类)HMENU (CMenu)
HPEN (CGdiObject)
HBRUSH (
CGdiObject
)HFONT (
CGdiObject
)HBITMAP (
CGdiObject
)HPALETTE (
CGdiObject
)HRGN (
CGdiObject
)HIMAGELIST (CImageList)
SOCKET (CSocket)
对于其中任一对象的句柄,都可通过调用静态方法 FromHandle
找到包装句柄的 MFC 对象。 例如,给定名为 hWnd 的 HWND,以下行将返回指向包装 hWnd 的 CWnd
的指针:
CWnd::FromHandle(hWnd)
如果 hWnd 没有特定的包装对象,则会创建一个临时对象 CWnd
来包装 hWnd。 这样就可以从任何句柄获取有效的 C++ 对象。
具备包装对象后,可以从包装类的公共成员变量中检索其句柄。 对于 CWnd
,m_hWnd 包含该对象的 HWND。
将句柄附加到 MFC 对象
对于新创建的句柄包装对象和 Windows 对象的句柄,可以通过调用 Attach
函数将两者关联起来,如以下示例所示:
CWnd myWnd;
myWnd.Attach(hWnd);
这会在永久映射中创建一个关联 myWnd 和 hWnd 的条目。 现在调用 CWnd::FromHandle(hWnd)
将返回指向 myWnd 的指针。 删除 myWnd 后,析构函数会通过调用 Windows DestroyWindow 函数自动销毁 hWnd。 如果不希望这样做,则必须在 myWnd 被销毁之前将 hWnd 与 myWnd 拆离(通常在离开定义 myWnd 的范围时)。 Detach
方法负责执行此操作。
myWnd.Detach();
有关临时对象的详细信息
只要为 FromHandle
提供没有包装对象的句柄,就会创建临时对象。 这些临时对象与它们的句柄分离,并由 DeleteTempMap
函数删除。 默认情况下,CWinThread::OnIdle 为每个支持临时句柄映射的类自动调用 DeleteTempMap
。 这意味着不能假设指向临时对象的指针在获得指针的函数退出之后仍然有效。
包装对象和多线程
临时对象和永久性对象均按线程维护。 也就是说,无论它是临时还是永久的,一个线程都无法访问另一个线程的 C++ 包装对象。
若要将这些对象从一个线程传递到另一个线程,请始终将它们作为其本机 HANDLE
类型发送。 将 C++ 包装对象从一个线程传递到另一个线程通常会导致意外结果。