窗口创建代码(即调用 CreateWindow时发生的所有内容)执行成本高昂。 用来维护屏幕上的窗口的控件必须管理窗口的消息。 因此,无窗口控件比具有窗口的控件更快。
无窗口控件的进一步优势是,与窗口控件不同,无窗口控件支持透明绘制和非矩形屏幕区域。 透明控件的常见示例是具有透明背景的文本控件。 控件只绘制文本,而不绘制背景,因此文本下方的任何内容都会透出来。 较新的窗体通常使用非矩形控件,如箭头和圆形按钮。
通常,控件不需要自己的窗口,而是可以使用其容器的窗口服务,前提是容器已写入以支持无窗口对象。 无窗口控件与早期的容器向后兼容。 在未写入以支持无窗口控件的旧容器中,无窗口控件在活动时创建窗口。
由于无窗口控件没有自己的窗口,因此容器(它有一个窗口)需要负责提供本该由控件自身窗口提供的服务。 例如,如果控件需要查询键盘焦点、捕获鼠标或获取设备上下文,则这些作由容器管理。 容器使用 IOleInPlaceObjectWindowless 接口将发送到其窗口的用户输入消息路由到相应的无窗口控件。 (有关此接口的说明,请参阅 ActiveX SDK 。 COleControl 成员函数从容器调用这些服务。
若要使控件使用无窗口激活,请在 COleControl::GetControlFlags 返回的标志集中包含 windowlessActivate 标志。 例如:
DWORD CMyAxOptCtrl::GetControlFlags()
{
DWORD dwFlags = COleControl::GetControlFlags();
// The control can activate without creating a window.
dwFlags |= windowlessActivate;
return dwFlags;
}
如果在 MFC ActiveX 控件向导的“控件设置”页上选择“无窗口激活”选项,则自动生成包含此标志的代码。
启用无窗口激活后,容器会将输入消息委托给控件的 IOleInPlaceObjectWindowless 接口。 在相应地调整鼠标坐标后,COleControl 的此接口的实现将会在控件的消息映射中调度消息。 通过将相应的条目添加到消息映射,可以像普通窗口消息一样处理这些消息。 在这些消息的处理程序中,避免使用 m_hWnd 成员变量(或任何使用它的成员函数),而无需首先检查其值是否为 NULL。
COleControl 提供成员函数,用于根据需要从容器调用鼠标捕获、键盘焦点、滚动和其他窗口服务,包括:
应始终在无窗口控件中使用 COleControl 成员函数,而不是相应的 CWnd 成员函数或其相关的 Win32 API 函数。
你可能希望无窗口控件成为 OLE 拖放操作的目标。 通常,这需要将该控件的窗口注册为放置目标。 由于控件没有自己的窗口,因此容器使用其自己的窗口作为拖放目标。 该控件提供了接口IDropTarget的实现,容器可以在适当时间委托调用。 若要将此接口公开到容器,请重写 COleControl::GetWindowlessDropTarget。 例如:
IDropTarget* CMyAxOptCtrl::GetWindowlessDropTarget()
{
m_DropTarget.m_xDropTarget.AddRef();
return &m_DropTarget.m_xDropTarget;
}