ActiveX控件开发实践

要使用C#实现一个ActiveX控件,需要解决三个问题:

1.使.NET组件能够被COM调用

2.在客户机上注册后,ActiveX控件能通过IE的安全认证

3.未在客户机上注册时,安装包能通过IE的签名认证

本程序的开发环境是.NET Framework 3.5,工具是Visual Studio .NET 2008,在安装.NET Framework 3.5的客户机上通过测试。
下面是实现步骤:

 

(一)创建可从COM访问的程序集

首先实现一个对COM可见的程序集,创建类库工程,AssemblyInfo.cs应包含:

  1. using System.Runtime.InteropServices;
  2. //使此程序集中的类型对COM组件可见
  3. [assembly: ComVisible(true)]
  4. // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
  5. [assembly: Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]

加入以下代码到AssemblyInfo.cs确保程序集的可访问性:

  1. using System.Security;
  2. [assembly: AllowPartiallyTrustedCallers()]

注意上面的Guid,如果程序集内部的类未标注Guid,COM注册的Guid是会新生成的,此处的Guid没有作用。

创建用户控件(自定义类待测)IdentityKey.cs,加入:

  1. using System;
  2. using System.ComponentModel;
  3. using System.Windows.Forms;
  4. using System.Runtime.InteropServices;
  5. namespace KeyActiveX
  6. {
  7.     [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]
  8.     public partial class IdentityKey : UserControl
  9.     {
  10.     }
  11. }

这里的Guid和AssemblyInfo.cs一样,它会在COM注册中成为CLSID并被html以clsid调用。

类库工程属性中,选择生成,勾选COM注册,在html文件中加入

  1. <object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" ></object>

在IE中启用不安全控件,查看html页面,应能访问到控件,现在一个在发布时对COM注册的程序集开发完成了。

使用OLE/COM Object Viewer(安装VC自带)可以在.NET Categories中查看组件和CLSID。

 

(二)通过IE安全控件认证

如果客户机的IE未开启访问非安全标记的ActiveX控件,通过IE浏览上面的步骤开发出的ActiveX控件,发现IE会给出警告:

此页上的 ActiveX 对象可能不安全的。 要允许它将初始化并通过脚本访问吗?

或禁止访问。这是客户机IE的安全规则设置的,我们应该在控件开发上解决IE安全认证的问题。首先我们要了解IE是如何判断一个ActiveX控件是不安全的,参见Microsoft帮助和支持文档:

http://support.microsoft.com/kb/216434/en-us

There are two ways to mark a control as safe for scripting and initialization:

  •  Implement the IObjectSafety interface. 
  • Provide the following registry keys for the control's CLSID under the Implemented Categories section:
    The following key marks the control safe for scripting:
    {7DD95801-9882-11CF-9FA9-00AA006C42C4}
    The following key marks the control safe for initialization from persistent data:
    {7DD95802-9882-11CF-9FA9-00AA006C42C4}  
    Microsoft recommends that you implement IObjectSafety to mark a control as safe or unsafe. This prevents other users from repackaging your control and marking it as safe when it is not.

我决定实现IObjectSafety接口来向IE表明ActiveX控件的安全标识,以保证控件再次打包时安全标识不会被被改写。

IObjectSafety是一个COM下的接口,对于C++程序来说,只需要实现它就行了,而.NET之下没有这个接口,在这种情况下,我们的ActiveX控件就是一个不带类型库的COM组件,必须使用C#代码重新定义COM接口。

这里需要了解一点COM的接口知识。接口是COM的核心,它区分了在客户和对象之间使用的契约和实现。COM的接口有三种类型:定制接口÷分派接口和双重接口。.NET Framework使用ComInterfaceType对它进行了重定义:

  1. namespace System.Runtime.InteropServices
  2. {
  3.     // 摘要:
  4.     //     Identifies how to expose an interface to COM.
  5.     [Serializable]
  6.     [ComVisible(true)]
  7.     public enum ComInterfaceType
  8.     {
  9.         // 摘要:
  10.         //     Indicates the interface is exposed to COM as a dual interface, which enables
  11.         //     both early and late binding. System.Runtime.InteropServices.ComInterfaceType.InterfaceIsDual
  12.         //     is the default value.
  13.         InterfaceIsDual = 0,
  14.         //
  15.         // 摘要:
  16.         //     Indicates an interface is exposed to COM as an IUnknown -derived interface,
  17.         //     which enables only early binding.
  18.         InterfaceIsIUnknown = 1,
  19.         //
  20.         // 摘要:
  21.         //     Indicates an interface is exposed to COM as a dispinterface, which enables
  22.         //     late binding only.
  23.         InterfaceIsIDispatch = 2,
  24.     }
  25. }

关于三个接口的具体描述,可以参考《C#高级编程第三版》28.1.3 接口。

在MSDN上查找,可以知道IObjectSafety继承自IUnknown,是一个定制接口;通过上一章节,可以发现向COM注册时,需要提供一个Guid作为CLSID来标识程序集中的C#类,事实上在COM中,接口和类型库都是带有Guid作为唯一标识的,分别为IID和typelib id。

这样,通过在C#编写的接口标上需要的COM接口IID,就可以在注册是向COM表明接口身份了。在Microsoft帮助上查找IObjectSafety定义:

  1.       [
  2.           uuid(C67830E0-D11D-11cf-BD80-00AA00575603),
  3.           helpstring("VB IObjectSafety Interface"),
  4.           version(1.0)
  5.       ]
  6.       library IObjectSafetyTLB
  7.       {
  8.           importlib("stdole2.tlb");
  9.           [
  10.               uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),
  11.               helpstring("IObjectSafety Interface"),
  12.               odl
  13.           ]
  14.           interface IObjectSafety:IUnknown {
  15.               [helpstring("GetInterfaceSafetyOptions")]
  16.               HRESULT GetInterfaceSafetyOptions(
  17.                         [in]  long  riid,
  18.                         [in]  long *pdwSupportedOptions,
  19.                         [in]  long *pdwEnabledOptions);
  20.               [helpstring("SetInterfaceSafetyOptions")]
  21.               HRESULT SetInterfaceSafetyOptions(
  22.                         [in]  long  riid,
  23.                         [in]  long  dwOptionsSetMask,
  24.                         [in]  long  dwEnabledOptions);
  25.            }
  26.        }

其中的uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064)就是需要的接口IID。

使用C#编写IObjectSafety:

  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace KeyActiveX
  4. {
  5.     [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
  6.     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  7.     public interface IObjectSafety
  8.     {
  9.         [PreserveSig]
  10.         void GetInterfacceSafyOptions(
  11.             int riid,
  12.             out int pdwSupportedOptions,
  13.             out int pdwEnabledOptions);
  14.         [PreserveSig]
  15.         void SetInterfaceSafetyOptions(
  16.             int riid,
  17.             int dwOptionsSetMask,
  18.             int dwEnabledOptions);
  19.     }
  20. }

InterfaceType中一定要使用ComInterfaceType.InterfaceIsIUnknown,因为IObjectSafety继承自IUnkown。

接下来是KeyActiveX的接口实现:

  1. namespace KeyActiveX
  2. {
  3.     [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]
  4.     public partial class IdentityKey : UserControl, IObjectSafety
  5.     {
  6.         #region IObjectSafety 成员
  7.         public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
  8.         {
  9.             pdwSupportedOptions = 1;
  10.             pdwEnabledOptions = 2;
  11.         }
  12.         public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions)
  13.         {
  14.             throw new NotImplementedException();
  15.         }
  16.         #endregion
  17.     }
  18. }

通过返回一个已定值来告诉IE控件是安全的。具体参见http://support.microsoft.com/kb/182598/

 

(三)签名发布

C#开发的ActiveX控件发布方式有三种:

1.制作客户端安装包,分发给客户机安装;

2.制作在线安装包,客户机联机安装;

3.使用html中object的codebase指向安装包地址。

前两个比较简单,适合在局域网内实施;最后一种方式,需要在安装包上进行数字签名,以保证客户机的安全信任。受信任的签名证书应该向证书提供商(如Versign)购买,然后使用签名工具对安装包进行签名。

下面利用Visual Studio 2008自带的测试证书创建工具MakeCert和签名工具SignTool进行测试,首先创建一个带有公司信息的测试证书,在Visual Studio命令提示符后输入:

makecert -sk ABC -n "CN=ABC Corporation" f:/abccorptest.cer

在F盘上创建了测试证书。然后输入

signtool signwizard

在Signing Options页面上,选择Custom,定义证书文件的位置,再下一步选择一个加密算法(MD5或SHA1),指定应用程序的名称和描述URL,确认。

此时ActiveX控件安装包有了一个被标记为未信任的测试证书,需要将IE设置为启用未信任安装程序,在html中引用

  1. <object id="controlbyid" classid="clsid:{94882155-3B7C-48e3-B357-234D56D8F15E}" codebase="setup.exe" ></object>

客户机安装之后就可以使用ActiveX控件了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值