zoukankan      html  css  js  c++  java
  • 使用反射动态调用ActiveX控件

    使用反射动态调用ActiveX控件

    袁永福 2018-3-2

    ■■■■问题描述:

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

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

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

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

    ■■■■技术改进:

    因此笔者不采用这种自动生成的互操作性程序集。转而采用自定义的反射来调用ActiveX控件。

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

    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事件中创建控件并添加到窗体上,其代码如下

    private DCHebeiCAControl _Control = null;
    
    private void frmTest_Load(object sender, EventArgs e)
    {
        this._Control = new DCHebeiCAControl();
        this._Control.Size = new Size(200, 200);
        this._Control.Location = new Point(0, 0);
        this.Controls.Add(this._Control);
    }
    

    这样无需使用自动生成的COM接口程序集即可调用ActiveX控件,大幅提高程序的通用性,而且对于32位和64位的项目类型不敏感。方便部署和更新。

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

    ■■■■小结:

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

  • 相关阅读:
    求最大公约数伪代码
    XOR加密
    20201225张晓平第五周学习
    pep9课下作业 张晓平
    20201225 张晓平《信息安全专业导论》第四周学习总结
    寻找黑客偶像 20201225张晓平
    《信息安全专业导论》第九周学习总结
    《信息安全专业导论》第八周学习总结
    《信息安全专业导论》第七周学习总结
    《信息安全专业导论》第6周学习总结
  • 原文地址:https://www.cnblogs.com/xdesigner/p/8504652.html
Copyright © 2011-2022 走看看