30、托管 ActiveX 控件增强页面内容开发指南

托管 ActiveX 控件增强页面内容开发指南

1. 注册与反注册

在开发 ActiveX 控件时,注册和反注册是重要的操作。以下是相关代码示例:

// 注册时设置类型库和版本信息
RegistryKey typelibKey = guidKey.CreateSubKey("TypeLib");
typelibKey.SetValue(String.Empty, typeLibGuid.ToString("B"), RegistryValueKind.String);

int majorVersion;
int minorVersion;
Marshal.GetTypeLibVersionForAssembly(type.Assembly, out majorVersion, out minorVersion);

RegistryKey versionKey = guidKey.CreateSubKey("Version");
versionKey.SetValue("", String.Format("{0}.{1}", majorVersion, minorVersion));

// 反注册函数
[ComUnregisterFunction]
public static void Unregister(Type type)
{
    Registry.ClassesRoot.DeleteSubKeyTree(@"CLSID\" + type.GUID.ToString("B"));
}

注册过程中,会创建类型库子键并设置类型库的 GUID,同时获取应用程序的主版本和次版本号并设置到版本子键中。反注册时,会递归删除控件的 CLSID 键及其所有子键和值。

2. 构建控件

构建和注册控件是创建示例控件的最后一步。通常,IE 中使用的 ActiveX 控件通过 CAB 文件、包含安装可执行文件的 CAB 文件或基本安装可执行文件进行安装。在开发过程中,可以利用 Visual Studio 的后期生成事件来调用注册函数,以下是具体的后期生成事件示例:

"C:\Windows\Microsoft.NET\Framework\{.NET Version}\regasm.exe"  /unregister "$(TargetPath)"
"C:\Windows\Microsoft.NET\Framework\{.NET Version}\regasm.exe"  /register /codebase /tlb "$(TargetPath)"

操作步骤如下:
1. 第一个命令尝试从全局程序集缓存(GAC)中反注册目标程序集,如果不存在则跳过。
2. 第二个命令对新程序集进行不安全注册, /codebase 标签强制在 GAC 目录外注册,此开关不应用于生产环境。

这些路径依赖于目标系统上 .NET Framework 的位置和版本,开发人员在安装应用程序时需要获取这些信息。设置好这些后,控件即可构建,后期生成事件会自动调用 RegAsm.exe 工具进行注册,若未设置则需手动注册。

3. 控件签名

代码签名是 ActiveX 控件开发过程中的重要环节。在默认安装的 IE 中,浏览器不会运行未使用有效代码签名证书正确签名的 ActiveX 控件,未签名的控件在“管理加载项”界面会被标记为未验证。虽然在开发控件的每次编译或测试运行时签名并非必要,但对于要广泛发布的控件则是必需的。开发人员不应鼓励客户关闭阻止未签名控件的 IE 策略,因为更改此设置会使用户面临被恶意方攻击的风险。

拥有有效证书的开发人员可以使用基于命令行的 signtool.exe (Windows SDK、Visual Studio SDK 等包含)或其他签名工具进行签名。

4. 运行控件

测试新构建的控件最简单的方法是使用简单的标记和脚本。示例项目包含一个 HTML 页面,通过 <object> 标签加载控件,以下是示例代码:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
    <title>ActiveX - Basic Demo</title>
</head>
<body>
    <h1>
        ActiveX - Basic Demo
    </h1>
    <object id="TestControl" name="TestControl"  
        classid="clsid:D0E4F5FB-BAB5-45F6-9CF6-ACB1CCB526F1">

    </object>
    <script language="javascript" type="text/javascript">
        // 测试属性读写
        TestControl.IntPropertyTest = 42;
        TestControl.StringPropertyTest = "Hello.";
        alert("Int: " + TestControl.IntPropertyTest +  
              "\nString: " + TestControl.StringPropertyTest);

        // 测试函数输出
        alert(TestControl.StringFunctionTest());

        // 测试函数输入
        TestControl.FunctionInputTest("Some great input.");
    </script>
</body>
</html>

IE 在解析页面遇到 <object> 标签时会加载控件,加载完成后,使用 JavaScript 进行测试:
1. 设置 IntPropertyTest 属性为 42, StringPropertyTest 属性为 “Hello.”,并通过警告框确认设置成功。
2. 调用 StringFunctionTest() 函数获取返回的测试字符串并显示。
3. 调用 FunctionInputTest 函数并传入字符串 “Some great input.”,控件会显示包含该字符串的消息框。

5. 构建用户界面

简单的函数和属性可以增强网页的功能,但在某些情况下还不够。许多控件如原始 Facebook 图像上传器、GE Centricity PACS 系统等都利用了二进制应用程序提供的增强 UI 功能。

5.1 为托管控件添加 UI

使用非托管代码构建 ActiveX 控件时,UI 元素的实现较为复杂,而 Visual Basic 在 20 世纪 90 年代后期引入了用户控件,简化了 ActiveX/COM 开发中的 UI 模型。开发人员可以使用用户控件为托管代码实现的 ActiveX 控件提供 UI。以下是添加 UI 的示例代码:

[ClassInterface(ClassInterfaceType.None)]
[Guid("3AEA8E0C-2AD3-455F-86A0-662A24397B80")]
public partial class AxSampleInterfaceControl : UserControl, IAxSampleInterface
{
    public AxSampleInterfaceControl()
    {
        InitializeComponent();
    }
    ...
}

在类定义中,以 UserControl 类为基类,在构造函数中调用 InitializeComponent() 初始化 UI 元素。同时,通过 IAxSampleInterface 接口暴露一些属性和函数,如 Visible Enabled Refresh() ,方便页面、其他控件和宿主获取控件的状态和可见性信息,并在需要时刷新和重绘对象。

示例代码使用 Visual Studio 设计器创建了一个简单的 UI,包含标题标签、文本框和按钮。编译后,需要重新注册控件以确保使用该控件的应用程序(如 IE)认可最新版本。

以下是按钮点击事件的代码:

private void ShowMessageButton_Click(object sender, EventArgs e)
{
    MessageBox.Show(MessageTextBox.Text);
}

添加此代码后,控件可以编译和测试,输入 “Super test” 并点击按钮,会弹出包含该内容的消息框。

5.2 设置控件的 OLE UI 标志

要使托管 ActiveX 控件在 IE 窗口(或其他 OLE 窗口)中正常工作,需要注册应用程序支持的 OLEMISC 标志,否则控件可能无法从父对象接收正确的焦点或绘制事件。标志注册应在注册过程中完成,以下是示例代码:

[ComRegisterFunction()]
public static void Register(Type type)
{
    ...
    RegistryKey miscStatusKey = guidKey.CreateSubKey("MiscStatus");
    int miscStatus =  
        NativeMethods.OLEMISC.OLEMISC_RECOMPOSEONRESIZE +
        NativeMethods.OLEMISC.OLEMISC_CANTLINKINSIDE +
        NativeMethods.OLEMISC.OLEMISC_INSIDEOUT +
        NativeMethods.OLEMISC.OLEMISC_ACTIVATEWHENVISIBLE +
        NativeMethods.OLEMISC.OLEMISC_SETCLIENTSITEFIRST;
    miscStatusKey.SetValue(String.Empty, miscStatus.ToString(), RegistryValueKind.String);
    ...
}

这些常量包含在示例代码中,使用 RegAsm.exe 注册控件时会将这些值设置到注册表中。

6. 向 ActiveX 宿主暴露事件

前面介绍的示例 ActiveX 控件功能已较为完善,但页面无法接收控件的消息或在控件发生感兴趣的事情时获得通知。以下是添加事件支持的步骤:

6.1 创建事件接口

托管 ActiveX 控件可以通过添加事件接口向宿主应用程序暴露事件。事件接口描述控件类将暴露的每个公共事件,并为每个事件分配 DISPID 值,以便通过 IDispatch 访问。以下是自定义事件接口的示例:

[Guid("F1A732D4-5924-4DA7-85D7-4808BD7E6818")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface AxSampleEventsEvents
{
    [DispId(0x1)]
    void OnClick();
}
6.2 绑定事件

将主 ActiveX 控件与事件接口中的事件绑定,示例代码如下:

[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(AxSampleEventsEvents))]
[Guid("C85CA4EB-3996-444A-91FE-B9045C94AD38")]
public partial class AxSampleEventsControl : UserControl, IAxSampleEvents
{
    public delegate void OnClickEventHandler();
    public new event OnClickEventHandler OnClick = null;
    ...
}

添加 OnClickEventHandler 委托和 OnClick 事件,当按钮点击时触发事件。以下是按钮点击事件处理程序:

private void FireEventButton_Click(object sender, EventArgs e)
{
    if (null != OnClick) OnClick();
}
6.3 测试事件

使用 HTML 页面测试暴露的事件,示例代码如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
    <title>ActiveX - Events Demo</title>
</head>
<body>
    <h1>
        ActiveX - Events Demo
    </h1>
    <object id="TestControl" name="TestControl"  
        classid="clsid:C85CA4EB-3996-444A-91FE-B9045C94AD38" 
        viewastext> 
    </object>
    <script type="text/javascript">
        function TestControl::OnClick()
        {  
            alert("The button was clicked!");
        }
    </script>
</body>
</html>

Microsoft JScript 引擎使用双冒号 :: 语法连接对象定义的事件,当对象加载时,引擎会记录有效的对象事件,解析和执行脚本时,符合 ObjectInstance::ExposedEvent 格式的函数会被视为回调函数,事件触发时会调用这些函数。点击控件内的按钮,浏览器会弹出警告框显示 “The button was clicked!”。

通过以上步骤,我们可以开发出功能丰富的 ActiveX 控件,包括基本交互、UI 界面和事件支持等功能。在实际开发中,需要根据具体需求进行调整和扩展。

托管 ActiveX 控件增强页面内容开发指南(续)

7. 开发流程总结

为了更清晰地展示整个 ActiveX 控件的开发过程,我们可以将其总结为以下流程图:

graph LR
    A[创建控件代码] --> B[构建控件]
    B --> C{是否需要 UI?}
    C -- 是 --> D[添加 UI 元素]
    C -- 否 --> E[注册控件]
    D --> E
    E --> F{是否需要签名?}
    F -- 是 --> G[代码签名]
    F -- 否 --> H[运行测试]
    G --> H
    H --> I{是否需要事件支持?}
    I -- 是 --> J[添加事件接口和绑定]
    I -- 否 --> K[完成开发]
    J --> K

这个流程图展示了从创建控件代码到最终完成开发的整个过程,涵盖了构建、添加 UI、签名、测试和添加事件支持等关键步骤。

8. 常见问题及解决方案

在开发 ActiveX 控件的过程中,可能会遇到一些常见问题,以下是一些问题及对应的解决方案:

问题描述 解决方案
控件无法在 IE 中加载 1. 检查控件是否已正确注册,可以通过查看注册表中相关键值是否存在来确认。
2. 确保控件已正确签名,未签名的控件在默认安装的 IE 中可能无法运行。
3. 检查 RegAsm.exe 注册命令是否正确,路径和参数是否符合目标系统的 .NET Framework 版本。
UI 元素显示异常 1. 检查 InitializeComponent() 方法是否正确调用,该方法用于初始化 UI 元素。
2. 确认 UI 元素的属性设置是否正确,如 Visible Enabled 等。
3. 检查是否有冲突的 CSS 样式影响了 UI 元素的显示。
事件无法触发 1. 检查事件接口是否正确定义,DISPID 值是否正确设置。
2. 确认事件绑定是否正确,确保 ComSourceInterfaces 属性已正确引用事件接口。
3. 检查事件处理程序是否正确编写,是否存在语法错误。
9. 性能优化建议

为了提高 ActiveX 控件的性能,我们可以采取以下优化建议:

9.1 减少不必要的属性和方法

在设计控件时,只暴露必要的属性和方法,避免过多的公共成员导致性能下降。例如,如果某些属性或方法只在内部使用,应将其设置为私有或受保护的。

9.2 优化 UI 绘制

避免在每次绘制时进行复杂的计算和操作,尽量缓存一些常用的数据和结果。例如,如果需要在 UI 中显示大量数据,可以采用分页或虚拟列表的方式,减少一次性绘制的数据量。

9.3 合理使用事件

避免在事件处理程序中执行耗时的操作,以免影响控件的响应性能。如果需要进行耗时操作,可以考虑使用异步编程的方式,如使用 Task BackgroundWorker

10. 兼容性考虑

在开发 ActiveX 控件时,需要考虑不同浏览器和操作系统的兼容性,以下是一些建议:

10.1 浏览器兼容性
  • IE 浏览器 :由于 ActiveX 控件主要在 IE 中使用,需要确保控件在不同版本的 IE 中都能正常工作。不同版本的 IE 对 ActiveX 控件的支持可能存在差异,需要进行充分的测试。
  • 其他浏览器 :现代浏览器如 Chrome、Firefox 等对 ActiveX 控件的支持有限,甚至不支持。如果需要在这些浏览器中使用类似的功能,可以考虑使用 HTML5、JavaScript 等技术替代。
10.2 操作系统兼容性
  • Windows 系统 :确保控件在不同版本的 Windows 操作系统中都能正常运行,不同版本的 Windows 对 .NET Framework 的支持可能不同,需要根据目标系统的版本选择合适的 .NET 版本。
  • 非 Windows 系统 :由于 ActiveX 控件是基于 Windows 平台的技术,在非 Windows 系统中无法直接使用。如果需要跨平台使用,可以考虑使用跨平台的技术,如 Java Applet、WebAssembly 等。
11. 总结与展望

通过本文的介绍,我们详细了解了托管 ActiveX 控件的开发过程,包括注册与反注册、构建控件、签名、运行测试、添加 UI 和事件支持等关键步骤。同时,我们还总结了开发过程中的常见问题及解决方案,以及性能优化和兼容性考虑等方面的建议。

虽然 ActiveX 控件在过去的 Web 开发中发挥了重要作用,但随着 Web 技术的不断发展,如 HTML5、JavaScript 和 WebAssembly 等的兴起,ActiveX 控件的使用场景逐渐减少。然而,在一些特定的企业内部系统或对兼容性要求较高的场景中,ActiveX 控件仍然具有一定的价值。

未来,随着 Web 技术的进一步发展,我们可以期待更多跨平台、高性能的技术来替代 ActiveX 控件,为用户提供更好的 Web 体验。但在当前阶段,掌握 ActiveX 控件的开发技术仍然是有意义的,可以帮助我们解决一些特定的问题。

在实际开发中,我们应根据具体需求选择合适的技术,结合现代 Web 技术的优势,开发出更加高效、稳定和易用的 Web 应用程序。同时,不断学习和掌握新的技术,以适应不断变化的 Web 开发环境。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值