要使用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应包含:

using System.Runtime.InteropServices;

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

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

using System.Security;

[assembly: AllowPartiallyTrustedCallers()]

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

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

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices; namespace KeyActiveX
{
    [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]
    public partial class IdentityKey : UserControl
    {
    }
}

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

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

<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帮助和支持文档:

How Internet Explorer Determines If ActiveX Controls Are Safe

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

1.Implement the IObjectSafety interface.

2.Provide the following registry keys for the control's CLSID under the Implemented Categories section:

a.The following key marks the control safe for scripting:
          {7DD95801-9882-11CF-9FA9-00AA006C42C4}

b.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对它进行了重定义:

namespace System.Runtime.InteropServices
{
    // 摘要:
    //     Identifies how to expose an interface to COM.
    [Serializable]
    [ComVisible(true)]
    public enum ComInterfaceType
    {
        // 摘要:
        //     Indicates the interface is exposed to COM as a dual interface, which enables
        //     both early and late binding. System.Runtime.InteropServices.ComInterfaceType.InterfaceIsDual
        //     is the default value.
        InterfaceIsDual = 0,
        //
        // 摘要:
        //     Indicates an interface is exposed to COM as an IUnknown -derived interface,
        //     which enables only early binding.
        InterfaceIsIUnknown = 1,
        //
        // 摘要:
        //     Indicates an interface is exposed to COM as a dispinterface, which enables
        //     late binding only.
        InterfaceIsIDispatch = 2,
    }
}

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

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

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

     [
          uuid(C67830E0-D11D-11cf-BD80-00AA00575603),
          helpstring("VB IObjectSafety Interface"),
          version(1.0)
      ]
      library IObjectSafetyTLB
      {
          importlib("stdole2.tlb");
          [
              uuid(CB5BDC81-93C1-11cf-8F20-00805F2CD064),
              helpstring("IObjectSafety Interface"),
              odl
          ]
          interface IObjectSafety:IUnknown {
              [helpstring("GetInterfaceSafetyOptions")]
              HRESULT GetInterfaceSafetyOptions(
                        [in]  long  riid,
                        [in]  long *pdwSupportedOptions,
                        [in]  long *pdwEnabledOptions);               [helpstring("SetInterfaceSafetyOptions")]
              HRESULT SetInterfaceSafetyOptions(
                        [in]  long  riid,
                        [in]  long  dwOptionsSetMask,
                        [in]  long  dwEnabledOptions);
           }
       }

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

使用C#编写IObjectSafety:

using System;
using System.Runtime.InteropServices; namespace KeyActiveX
{
    [ComImport, Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        void GetInterfacceSafyOptions(
            int riid,
            out int pdwSupportedOptions,
            out int pdwEnabledOptions);         [PreserveSig]
        void SetInterfaceSafetyOptions(
            int riid,
            int dwOptionsSetMask,
            int dwEnabledOptions);
    }
}

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

接下来是KeyActiveX的接口实现:

namespace KeyActiveX
{
    [Guid("94882155-3B7C-48e3-B357-234D56D8F15E")]
    public partial class IdentityKey : UserControl, IObjectSafety
    {
        #region IObjectSafety 成员         public void GetInterfacceSafyOptions(int riid, out int pdwSupportedOptions, out int pdwEnabledOptions)
        {
            pdwSupportedOptions = 1;
            pdwEnabledOptions = 2;
        }         public void SetInterfaceSafetyOptions(int riid, int dwOptionsSetMask, int dwEnabledOptions)
        {
            throw new NotImplementedException();
        }         #endregion
    }
}

通过返回一个已定值来告诉IE控件是安全的。具体参见

如何在 VisualBasic 控件实现 IObjectSafety

(三)签名发布

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

  1. 制作客户端安装包,分发给客户机安装;
  2. 制作在线安装包,客户机联机安装;
  3. 使用html中object的codebase指向安装包地址。

前两个比较简单,适合在局域网内实施,生成安装包时需要装Register属性设置为vsdrpCOM;最后一种方式,需要在安装包上进行数字签名,以保证客户机的安全信任。受信任的签名证书应该向证书提供商(如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中引用

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

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

最新文章

  1. 【Pyrosim案例】01:空气流动
  2. js和css文件压缩
  3. 元素定义了position:fixed;后怎么居中
  4. 2016年12月11日 php面向对象
  5. Sqlserver推荐参数配置及日志收缩问题
  6. iOS ASIHTTPRequest用https协议加密请求
  7. iOS开发--基于AFNetWorking3.0的图片缓存分析
  8. 关于python中字典的一些总结
  9. Android 联系人字母排序(仿微信)
  10. Matlab2012a第一次安装打不开 查找程序安装类时出错
  11. mybati的存储过程
  12. Java高级特性之反射
  13. Redis的二八定律
  14. [HNOI2014]道路堵塞
  15. echarts 专题
  16. 机器学习---感知机(Machine Learning Perceptron)
  17. [复试机试]c++读取/写入文本文件
  18. 洛谷P1966 【火柴排队】
  19. vm无法删除干净老版本,新版本无法安装解决
  20. js通过 URL下载文件

热门文章

  1. 在flask中返回requests响应
  2. 进度条算法 progressBar
  3. 2、gitlab 新建项目
  4. java基础4 函数
  5. leetcode 之Remove Duplicates from Sorted Array(1)
  6. CSS3–2.css3 响应式布局
  7. [实战]MVC5+EF6+MySql企业网盘实战(24)——视频列表
  8. 查看loadrunner运行日志
  9. grep 同时排除多个关键字
  10. poj2362 Square(DFS)