袁创:使用反射动态调用ActiveX控件

■■■■前言web

目前的基于.NET平台的软件研发中仍然存在大量的对COMActiveX控件的调用。使用C#调用ActiveX控件时通常是使用vs.net工具自动生成的互操做性程序集。这种方法操做简单,能保证必定的性能。但会产生额外的程序文件,不利于应用软件的简洁部署,还容易产生和ActiveX控件版本相关的错误。本文就提出使用反射技术动态调用ActiveX控件的方式来解决这些问题。ide

 

■■■■问题描述:函数

目前的基于.NET平台的软件研发中仍然存在大量的对COMActiveX控件的调用。使用C#调用ActiveX控件时通常是使用vs.net工具的添加COM引用时自动生成的互操做性程序集。这种方法操做简单,能保证必定的性能。但会产生额外的程序文件,不利于应用软件的简洁部署。并且当开发环境和运行环境使用的ActiveX控件的版本不一致[袁永福原创]时还容易出错。工具

笔者长期从事基于.NET平台的通用产品类软件研发。[袁永福原创]产品类软件要求部署简洁,为此笔者都会将多个工程编译生成的多个.NET程序集文件合并成一个.NET程序集文件来作到简洁部署。性能

实践中发现自动生成的互操做性程序集没法合并。另外产品类软件应该能适应各类复杂的开发和生产环境,甚至ActiveX控件的CLSID 都有可能变化。ui

例如,对于COM类库“HebcaFormSealLib”,VS.NET会自动生成程序集文件“AxInterop.HebcaFormSealLib.dll”、“Interop.HebcaFormSealLib.dll”。这些程序集文件没法进行程序集合并,并且对于32位或64位的工程项目类型敏感,容易致使错误。this

■■■■技术改进:spa

所以笔者不采用这种自动生成的互操做性程序集。转而采用自定义的反射来调用ActiveX控件。.net

后期绑定ActiveX 控件主要知识点为System.Windows.Forms.AxHost类型和Type.InvokeMember方法。orm

AxHost类型是从System.Windows.Forms.Control类型[袁永福原创]派生出来的,专门用于承载ActiveX控件。它是一个抽象类,有一个受保护的构造函数,函数参数是一个guid格式的ActiveX控件的CLSID字符串。还有一个GetOcx内部方法用于建立ActiveX控件的对象实例,它是一个COM对象引用。

建立了这个COM对象引用后就能够调用Type.InvokerMember方法来动态的调用指定名称的方法和属性。

■■■■范例:

笔者最近在使用某电子签名的ActiveX控件来实现文档签名的功能。笔者写出如下接口代码

 
[System.Runtime.InteropServices.ComVisible(false)]
public class DCHebeiCAControl System.Windows.Forms.AxHost
{
     public DCHebeiCAControl()
        base("{e4ee564c-0845-4404-91ee-0c206113333f}")
     }
     public object _ocx null;
     protected override void AttachInterfaces()
     {
        this._ocx base.GetOcx();
     }
     private void CheckOCX()
     {
        if (this._ocx == null)
        {
            throw new System.NullReferenceException("_ocx");
        }
     }
     public VersionType GetBaseVersionType()
     {
        this.CheckOCX();
        VersionType result (VersionType)this._ocx.GetType().InvokeMember(
            "GetBaseVersionType",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[});
        return result;
     }
     public string GetCert(string sealSN)
     {
        this.CheckOCX();
        string result (string)this._ocx.GetType().InvokeMember(
            "GetCert",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[sealSN });
        return result;
     }
     public string GetClientDetailVersionInfo()
     {
        this.CheckOCX();
        string result (string)this._ocx.GetType().InvokeMember(
            "GetClientDetailVersionInfo",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[});
        return result;
     }
     public int GetClientVersion()
     {
        this.CheckOCX();
        int result (int)this._ocx.GetType().InvokeMember(
            "GetClientVersion",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[});
        return result;
     }
     public string GetClientVersionInfo()
     {
        this.CheckOCX();
        string result (string)this._ocx.GetType().InvokeMember(
            "GetClientVersionInfo",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[});
        return result;
     }
     public object GetConfig(string argName)
     {
        this.CheckOCX();
        object result (object)this._ocx.GetType().InvokeMember(
            "GetConfig",
            BindingFlags.InvokeMethod,
            null,
            this._ocx,
            new object[argName });
        return result;
     }
     // ----------- 口 -----------------------------
}//classDCHebeiCAControl
 

 

上述代码中各个功能函数内部代码结构简单[袁永福原创],之间有很大的类似性,所以彻底能够编写一个代码生成器来自动生成上述代码。

完成自定义的控件后,笔者再建立一个WinForm 窗体,在其Load事件中建立控件并添加到窗体上,其代码以下

这样无需使用自动生成的COM接口程序集便可调用ActiveX控件,大幅提升程序 

private DCHebeiCAControl _Control null;
private void frmTest_Load(object senderEventArgs e)
{
     this._Control new DCHebeiCAControl();
     this._Control.Size new Size(200200);
     this._Control.Location new Point(00);
     this.Controls.Add(this._Control);
}
 

的通用性,并且对于32位和64位的项目类型不敏感。方便部署和更新。

不过这样因为采用后期绑定而带来必定的性能[袁永福原创]问题,所以对于性能敏感而又频繁调用ActiveX控件的场景下须要谨慎采用这种模式。

 

■■■■小结:

.net开发中调用旧的ActiveX控件是不少开发场景中不得不作的事情。在本文中,笔者介绍了在C#中调用ActiveX控件的标准模式,并提出了一种[袁永福原创]改良模式来提升程序的通用性。为操做ActiveX控件的.NET程序开发提供了一种新的技术手段。

相关文章
相关标签/搜索