MFC ActiveX 控件:高级主题

本文介绍与开发 ActiveX 控件相关的高级主题。 这些方法包括:

重要

ActiveX 是旧技术,不应用于新开发。 有关取代 ActiveX 的新式技术的详细信息,请参阅 ActiveX 控件

在 ActiveX 控件中使用数据库类

由于 ActiveX 控件类是类库的一部分,因此可以应用与在标准 MFC 应用程序中使用数据库类相同的过程和规则,来开发使用 MFC 数据库类的 ActiveX 控件。

有关 MFC 数据库类的一般概述,请参阅 MFC 数据库类(DAO 和 ODBC)。 本文介绍 MFC ODBC 类和 MFC DAO 类,并指导你更加详细地了解两者。

注意

DAO 通过 Office 2013 获得支持。 DAO 3.6 是最终版本,被视为已过时。 Visual C++ 环境和向导不支持 DAO(尽管包含 DAO 类且你仍可以使用它们)。 Microsoft 建议对新项目使用 OLE DB 模板ODBC 和 MFC。 应只在维护现有应用程序时使用 DAO。

实现参数化属性

参数化属性(有时称为属性数组)是一种将值的同类集合作为控件的单个属性进行公开的方法。 例如,可以使用参数化属性将数组或字典作为属性进行公开。 在 Visual Basic 中,使用数组表示法访问此类属性:

x = o.Array(2, 3) ' gets element of 2D array
o.Array(2, 3) = 7 ' sets element of 2D array

使用添加属性向导可实现参数化属性。 添加属性向导通过添加一对 Get/Set 函数来实现该属性,这对函数使控制用户可以使用以上表示法或标准方式访问属性。

与方法和属性类似,参数化属性也会限制允许的参数数量。 对于参数化属性,限制为 15 个参数(其中一个参数保留用于存储属性值)。

以下过程添加一个名为 Array 的参数化属性,该属性可作为二维整数数组进行访问。

使用添加属性向导添加参数化属性

  1. 加载控件的项目。

  2. 在“类视图”中,展开控件的库节点。

  3. 右键单击控件的接口节点(库节点的第二个节点)以打开快捷菜单。

  4. 从快捷菜单中,单击“添加”,然后单击“添加属性”。

  5. 在“属性名称”框中,键入 Array

  6. 在“属性类型”框中,选择 short

  7. 对于“实现类型”,请单击“Get/Set 方法”

  8. 在“Get 函数”和“Set 函数”框中,为 Get 和 Set 函数键入唯一名称或接受默认名称

  9. 使用“参数名称”和“参数类型”控件添加名为 row(类型为 short)的参数

  10. 添加名为 column(类型为 short)的第二个参数

  11. 单击“完成” 。

添加属性向导进行的更改

添加自定义属性时,添加属性向导会对控件类标头 (.H) 文件和实现 (.CPP) 文件进行更改。

以下行会添加到控件类 .H 文件中:

SHORT GetArray(SHORT row, SHORT column);
void SetArray(SHORT row, SHORT column, SHORT newVal);

此代码声明两个名为 GetArraySetArray 的函数,它们使用户可以在访问属性时请求特定行和列。

此外,添加属性向导会将以下行添加到控件调度映射(位于控件类实现 (.CPP) 文件中):

DISP_PROPERTY_PARAM_ID(CMyAxUICtrl, "Array", dispidArray, GetArray, SetArray, VT_I2, VTS_I2 VTS_I2)

最后,GetArraySetArray 函数的实现会添加到 .CPP 文件末尾。 在大多数情况下,你会修改 Get 函数以返回属性的值。 Set 函数通常包含应在属性更改之前或之后执行的代码。

若要使此属性有用,可以在类型为 short 的控件类中声明二维数组成员变量,以存储参数化属性的值。 随后可以修改 Get 函数以返回存储在正确行和列的值(通过参数指示),并修改 Set 函数以更新行和列参数引用的值。

在 ActiveX 控件中处理错误

如果控件中出现错误条件,则可能需要将错误报告给控件容器。 有两种方法用于报告错误,具体取决于发生错误的情况。 如果错误发生在属性的 Get 或 Set 函数中或是 OLE 自动化方法的实现中,则控件应调用 COleControl::ThrowError,这向控件用户告知发生了错误。 如果错误发生在任何其他时间,则控件应调用 COleControl::FireError,这会引发常用错误事件。

若要指示发生的错误类型,控件必须将错误代码传递给 ThrowErrorFireError。 错误代码是具有 32 位值的 OLE 状态代码。 如果可能,请从 OLECTL.H 头文件中定义的标准代码集中选择错误代码。 下表对这些代码进行了概述。

ActiveX 控件错误代码

错误 说明
CTL_E_ILLEGALFUNCTIONCALL 非法函数调用
CTL_E_OVERFLOW 溢出
CTL_E_OUTOFMEMORY 内存不足
CTL_E_DIVISIONBYZERO 被零除
CTL_E_OUTOFSTRINGSPACE 字符串空间不足
CTL_E_OUTOFSTACKSPACE 堆栈空间不足
CTL_E_BADFILENAMEORNUMBER 错误的文件名或文件号
CTL_E_FILENOTFOUND 找不到文件
CTL_E_BADFILEMODE 错误的文件模式
CTL_E_FILEALREADYOPEN 文件已打开
CTL_E_DEVICEIOERROR 设备 I/O 错误
CTL_E_FILEALREADYEXISTS 文件已存在
CTL_E_BADRECORDLENGTH 错误的记录长度
CTL_E_DISKFULL 磁盘已满
CTL_E_BADRECORDNUMBER 错误的记录号
CTL_E_BADFILENAME 错误的文件名
CTL_E_TOOMANYFILES 文件太多
CTL_E_DEVICEUNAVAILABLE 设备不可用
CTL_E_PERMISSIONDENIED 权限被拒绝
CTL_E_DISKNOTREADY 磁盘未准备好
CTL_E_PATHFILEACCESSERROR 路径/文件访问错误
CTL_E_PATHNOTFOUND 找不到路径
CTL_E_INVALIDPATTERNSTRING 无效模式字符串
CTL_E_INVALIDUSEOFNULL NULL 的使用无效
CTL_E_INVALIDFILEFORMAT 无效的文件格式
CTL_E_INVALIDPROPERTYVALUE 属性值无效
CTL_E_INVALIDPROPERTYARRAYINDEX 属性数组索引无效
CTL_E_SETNOTSUPPORTEDATRUNTIME 运行时不支持设置。
CTL_E_SETNOTSUPPORTED 不支持 Set 语句(只读属性)
CTL_E_NEEDPROPERTYARRAYINDEX 需要属性数组索引
CTL_E_SETNOTPERMITTED 不允许进行设置
CTL_E_GETNOTSUPPORTEDATRUNTIME 运行时不支持 Get 语句
CTL_E_GETNOTSUPPORTED 不支持 Get(只写属性)
CTL_E_PROPERTYNOTFOUND 找不到属性
CTL_E_INVALIDCLIPBOARDFORMAT 剪贴板格式无效
CTL_E_INVALIDPICTURE 图片无效
CTL_E_PRINTERERROR 打印机错误
CTL_E_CANTSAVEFILETOTEMP 无法将文件保存到 TEMP
CTL_E_SEARCHTEXTNOTFOUND 未找到搜索文本
CTL_E_REPLACEMENTSTOOLONG 替换内容太长

如有必要,可使用 CUSTOM_CTL_SCODE 宏为某个标准代码未涵盖的条件定义自定义错误代码。 此宏的参数应是介于 1000 与 32767 之间的整数(包括 1000 和 32767)。 例如:

#define MYCTL_E_SPECIALERROR CUSTOM_CTL_SCODE(1000)

如果要创建 ActiveX 控件来替换现有 VBX 控件,请使用 VBX 控件所使用的相同数值定义 ActiveX 控件错误代码,以确保错误代码兼容。

在控件中处理特殊键

在某些情况下,你可能希望以特殊方式处理某些击键组合:例如,在多行文本框控件中按 ENTER 键时插入新行,或是在按方向键 ID 时在一组编辑控件之间移动。

如果 ActiveX 控件的基类为 COleControl,则可以替代 CWnd::PreTranslateMessage 以在容器处理消息之前处理它们。 使用此方法时,如果在 PreTranslateMessage 的替代中处理消息,则会始终返回 TRUE

下面的代码示例演示了处理与方向键相关的任何消息的可能方法。

BOOL CMyAxUICtrl::PreTranslateMessage(MSG* pMsg)
{
   BOOL bHandleNow = FALSE;

   switch (pMsg->message)
   {
   case WM_KEYDOWN:
      switch (pMsg->wParam)
      {
      case VK_UP:
      case VK_DOWN:
      case VK_LEFT:
      case VK_RIGHT:
         bHandleNow = TRUE;
         break;
      }
      if (bHandleNow)
      {
         OnKeyDown((UINT)pMsg->wParam, LOWORD(pMsg->lParam), HIWORD(pMsg->lParam));
      }
      break;
   }
   return bHandleNow;
}

有关为 ActiveX 控件处理键盘接口的详细信息,请参阅 ActiveX SDK 文档。

访问在运行时不可见的对话框控件

可以创建没有用户界面并且在运行时不可见的对话框控件。 如果将在运行时不可见的 ActiveX 控件添加到对话框控件,并且使用 CWnd::GetDlgItem 访问控件,则控件会无法正常工作。 相反,应使用以下方法之一来获取表示控件的对象:

  • 使用添加成员变量向导,选择“控件变量”,然后选择控件的 ID。 输入成员变量名称,然后选择控件的包装类作为“控件类型”

    - 或者 -

  • 将局部变量和子类声明为对话框项。 插入类似于以下内容的代码(CMyCtrl 是包装类,IDC_MYCTRL1 是控件的 ID):

    CCirc myCirc;
    myCirc.SubclassDlgItem(IDC_CIRCCTRL2, this);
    // ... use myCirc ...
    myCirc.UnsubclassWindow();
    

另请参阅

MFC ActiveX 控件