本文介绍创建 ActiveX 控件的常见 Windows 控件的子类化过程。 对现有 Windows 控件进行子类化是开发 ActiveX 控件的快速方法。 新控件将具有子类化 Windows 控件(如绘制和响应鼠标单击)的能力。 MFC ActiveX 控件示例 BUTTON 是一个子类化 Windows 控件的示例。
重要
ActiveX 是一项不推荐用于新开发的旧技术。 有关取代 ActiveX 的新式技术的详细信息,请参阅 ActiveX 控件。
若要将 Windows 控件子类化,请完成以下任务:
-
注释
如果你选择控件以使用“控件设置”页上的“选择父窗口类”下拉列表进行子类化,则 ActiveX 控件向导会为你完成大部分工作。
重写 IsSubclassedControl 和 PreCreateWindow
若要重写 PreCreateWindow
,请将 IsSubclassedControl
以下代码行添加到 protected
控件类声明的节:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
BOOL IsSubclassedControl();
在控件实现文件中(。CPP),添加以下代码行来实现两个重写的函数:
// CMyAxSubCtrl::PreCreateWindow - Modify parameters for CreateWindowEx
BOOL CMyAxSubCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
cs.lpszClass = _T("BUTTON");
return COleControl::PreCreateWindow(cs);
}
// CMyAxSubCtrl::IsSubclassedControl - This is a subclassed control
BOOL CMyAxSubCtrl::IsSubclassedControl()
{
return TRUE;
}
请注意,在此示例中,Windows 按钮控件是在 < a0/> 中指定的
对 Windows 控件进行子类化时,可能需要指定用于创建控件窗口窗口的特定窗口样式(WS_)或扩展窗口样式(WS_EX_)标志。 可以通过修改cs.style
成员函数和cs.dwExStyle
结构字段来设置这些参数PreCreateWindow
的值。 应使用 OR 作对这些字段进行修改,以保留由类 COleControl
设置的默认标志。 例如,如果控件正在子类化 BUTTON 控件,并且您希望该控件显示为复选框,请在 return 语句之前将以下代码行插入到实现 CSampleCtrl::PreCreateWindow
中:
cs.style |= BS_CHECKBOX;
此作将添加BS_CHECKBOX样式标志,同时保留类 COleControl
的默认样式标志(WS_CHILD)。
修改 OnDraw 成员函数
如果希望子类化控件保持与相应 Windows 控件相同的外观,控件 OnDraw
的成员函数应仅包含对 DoSuperclassPaint
成员函数的调用,如以下示例所示:
void CMyAxSubCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
DoSuperclassPaint(pdc, rcBounds);
}
DoSuperclassPaint
由其COleControl
实现的成员函数使用 Windows 控件的窗口过程在边界矩形内的指定设备上下文中绘制控件。 这样,即使控件不处于活动状态,控件也可见。
注释
成员 DoSuperclassPaint
函数仅适用于那些允许将设备上下文作为WM_PAINT消息的 wParam 传递的控件类型。 这包括一些标准 Windows 控件,例如 SCROLLBAR 和 BUTTON,以及所有通用控件。 对于不支持此行为的控件,必须提供自己的代码才能正确显示非活动控件。
处理反射窗口消息
Windows 控件通常会将某些窗口消息发送到其父窗口。 其中一些消息(例如WM_COMMAND)向用户提供作通知。 其他方法(如WM_CTLCOLOR)用于从父窗口获取信息。 ActiveX 控件通常通过其他方式与父窗口通信。 通知通过触发事件(发送事件通知)进行通信,并通过访问容器的环境属性获取有关控制容器的信息。 由于存在这些通信技术,因此 ActiveX 控件容器不应处理控件发送的任何窗口消息。
若要防止容器接收子类化 Windows 控件发送的窗口消息, COleControl
请创建一个额外的窗口来充当控件的父级。 此额外的窗口(称为“反射器”)仅为对 Windows 控件进行子类化的 ActiveX 控件创建,其大小和位置与控件窗口相同。 反射器窗口截获某些窗口消息,并将其发送回控件。 然后,控件在其窗口过程中可以通过执行适用于 ActiveX 控件的作(例如触发事件)来处理这些反映的消息。 有关已截获的窗口消息的列表及其对应的反射消息,请参阅 反射窗口消息 ID 。
ActiveX 控件容器可以设计为执行消息反射本身,无需 COleControl
创建反射器窗口并降低子类化 Windows 控件的运行时开销。
COleControl
通过检查值为 TRUE 的 MessageReflect 环境属性,检测容器是否支持此功能。
若要处理反射的窗口消息,请将条目添加到控件消息映射并实现处理程序函数。 由于反映的消息不是 Windows 定义的标准消息集的一部分,因此类视图不支持添加此类消息处理程序。 但是,手动添加处理程序并不困难。
若要手动为反射窗口消息添加消息处理程序,请执行以下作:
在控件类中。H 文件,声明处理程序函数。 该函数应具有一个返回类型的 LRESULT 和两个参数,分别具有 WPARAM 和 LPARAM 类型。 例如:
class CMyAxSubCtrl : public COleControl {
protected: LRESULT OnOcmCommand(WPARAM wParam, LPARAM lParam); };
在控件类中。CPP 文件,将ON_MESSAGE条目添加到消息映射。 此条目的参数应为消息标识符和处理程序函数的名称。 例如:
BEGIN_MESSAGE_MAP(CMyAxSubCtrl, COleControl) ON_MESSAGE(OCM_COMMAND, &CMyAxSubCtrl::OnOcmCommand) END_MESSAGE_MAP()
同样在 .CPP 文件,实现
OnOcmCommand
成员函数来处理反映的消息。 wParam 和 lParam 参数与原始窗口消息的参数相同。
有关如何处理反映的消息的示例,请参阅 MFC ActiveX 控件示例 BUTTON。 它演示了一个 OnOcmCommand
处理程序,该处理程序通过触发(发送)事件 Click
来检测BN_CLICKED通知代码并做出响应。