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 的参数化属性,该属性可作为二维整数数组进行访问。
使用添加属性向导添加参数化属性
加载控件的项目。
在“类视图”中,展开控件的库节点。
右键单击控件的接口节点(库节点的第二个节点)以打开快捷菜单。
从快捷菜单中,单击“添加”,然后单击“添加属性”。
在“属性名称”框中,键入
Array
。在“属性类型”框中,选择
short
。对于“实现类型”,请单击“Get/Set 方法”。
在“Get 函数”和“Set 函数”框中,为 Get 和 Set 函数键入唯一名称或接受默认名称。
使用“参数名称”和“参数类型”控件添加名为 row(类型为 short)的参数。
添加名为 column(类型为 short)的第二个参数。
单击“完成” 。
添加属性向导进行的更改
添加自定义属性时,添加属性向导会对控件类标头 (.H) 文件和实现 (.CPP) 文件进行更改。
以下行会添加到控件类 .H 文件中:
SHORT GetArray(SHORT row, SHORT column);
void SetArray(SHORT row, SHORT column, SHORT newVal);
此代码声明两个名为 GetArray
和 SetArray
的函数,它们使用户可以在访问属性时请求特定行和列。
此外,添加属性向导会将以下行添加到控件调度映射(位于控件类实现 (.CPP) 文件中):
DISP_PROPERTY_PARAM_ID(CMyAxUICtrl, "Array", dispidArray, GetArray, SetArray, VT_I2, VTS_I2 VTS_I2)
最后,GetArray
和 SetArray
函数的实现会添加到 .CPP 文件末尾。 在大多数情况下,你会修改 Get 函数以返回属性的值。 Set 函数通常包含应在属性更改之前或之后执行的代码。
若要使此属性有用,可以在类型为 short
的控件类中声明二维数组成员变量,以存储参数化属性的值。 随后可以修改 Get 函数以返回存储在正确行和列的值(通过参数指示),并修改 Set 函数以更新行和列参数引用的值。
在 ActiveX 控件中处理错误
如果控件中出现错误条件,则可能需要将错误报告给控件容器。 有两种方法用于报告错误,具体取决于发生错误的情况。 如果错误发生在属性的 Get 或 Set 函数中或是 OLE 自动化方法的实现中,则控件应调用 COleControl::ThrowError,这向控件用户告知发生了错误。 如果错误发生在任何其他时间,则控件应调用 COleControl::FireError,这会引发常用错误事件。
若要指示发生的错误类型,控件必须将错误代码传递给 ThrowError
或 FireError
。 错误代码是具有 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();