■■■■前言

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

 

■■■■问题描述:

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

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

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);
}
 

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

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

■■■■小结:

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

袁创:使用反射动态调用ActiveX控件的更多相关文章

  1. 使用反射动态调用ActiveX控件

    使用反射动态调用ActiveX控件 袁永福 2018-3-2 ■■■■问题描述: 目前的基于.NET平台的软件研发中仍然存在大量的对COM及ActiveX控件的调用.使用C#调用ActiveX控件时一 ...

  2. 【VS开发】使用MFC创建并调用ActiveX控件

    使用MFC创建并调用ActiveX控件 今天做了一下ActiveX的使用测试,总结一下: 首先使用MFC创建一个activeX的控件譬如ActiveXTest,编译成ocx并注册,然后另外编写一个测试 ...

  3. C#调用ActiveX控件

    背景:最近项目中需要用到ActiveX控件,项目是在.Net平台下开发的.因此就直接在项目中添加了对ActiveX控件的引用,添加引用成功.在代码中实例化类的实例也没有问题,但在调用其方法或属性时总是 ...

  4. ie 64bit调用activex控件

    1,首先,这是可能的.不要被网上一堆ie64调不了activex控件的文章误导了.flash就是一个现成的例子,flash支持ie64. 2,ie64只能调用64bit的activex控件.网上那些说 ...

  5. 【VS开发】动态创建ActiveX控件

    bool CCollectDataDlgDlg::CreateMyCtrl(LPRECT lpRect, UINT nID, CWnd *pParent) {  CLSID clsid;  wstri ...

  6. 谷歌浏览器调用activex控件方法

    原文转自 https://jingyan.baidu.com/article/af9f5a2d0ebe5543140a4596.html activex是由微软开发,所以在支持上,目前原生态支持的只有 ...

  7. 【转】Win32程序中调用ActiveX控件

    #include "stdafx.h" #include <iostream> #include <windows.h> #include <comd ...

  8. 让动态创建的ActiveX控件响应Windows消息

    当我们通过 CWnd::CreateControl() 动态创建 ActiveX   控件时, Windows 消息并不会被发送给我 们的由   CWnd 派生得控件类.例如,即使我们为 WM_KIL ...

  9. Qt开发Activex笔记(二):Qt调用Qt开发的Activex控件

    若该文为原创文章,转载请注明原文出处本文章博客地址:https://blog.csdn.net/qq21497936/article/details/113789693 长期持续带来更多项目与技术分享 ...

随机推荐

  1. Spring基础系列-容器启动流程(1)

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9870339.html 概述 ​ 我说的容器启动流程涉及两种情况,SSM开发模式和Spri ...

  2. [转]react 部署在ngnix上(windows环境)

    本文转自:https://blog.csdn.net/wly_er/article/details/82348593 目录 1.下载nginx. 2.测试nginx 3.配置react项目 4.ngi ...

  3. php-fpm 的优化

    pid = /usr/local/php/var/run/php-fpm.pid error_log = /usr/local/php/var/log/php-fpm.log log_level = ...

  4. [Redis] redis的设计与实现-对象系统

    1.redis并没有直接使用前面的数据结构实现键值对数据库,而是基于数据结构创建了一个对象系统,字符串对象/列表对象/哈希对象/集合对象/有序集合对象都用到了至少一种前面的数据结构2.针对不同的使用场 ...

  5. C# 合并Excel工作表

    文档合并.拆分是实现文档管理的一种有效方式.在工作中,我们可能会遇到需要将多个文档合并的情况,那如何来实现呢,本文将进一步介绍.关于拆分Excel工作表,可参见这篇文章——C#如何拆分EXCEL工作表 ...

  6. Java开发笔记(四十八)类的简单继承

    前面介绍了类的基本用法,主要是如何封装一个类的各项要素,包括成员属性.成员方法.构造方法等,想必大家对类的简单运用早已驾轻就熟.所谓“物以类聚,人以群分”,之所以某些事物会聚在一起,乃是因为它们拥有类 ...

  7. import提升导致Fundebug报错:“请配置apikey”

    摘要: 解释一下"请配置apikey"报错的原因. 部分Fundebug用户使用import来导入js文件时,出现了"请配置apikey"的报错,这是由于imp ...

  8. 把vux中的@font-face为base64格式的字体信息解码成可用的字体文件

    在最近移动端项目中用到了vux,感觉用着还习惯,当把vux使用到PC端的时候出现了IE浏览器出现,这样的错误信息: CSS3114: @font-face 未能完成 OpenType 嵌入权限检查.权 ...

  9. 驰骋工作流引擎JFlow与activiti的对比 -总结

    共同点: 1. 嵌入式的工作流引擎,降低集群复杂性. 2. 严格而灵活的流程版本控制 3. 支持多种数据库 4. 支持多种流程设计模式 5. 成熟度高的开源工作流,具有可靠的稳定性和性能. 区别: 1 ...

  10. java新知识系列 三

    1:trycatch中需要注意的地方. 2:ServletConfig以及ServletContext对象. 3: Spring事务属性的种类:   传播行为.隔离级别.只读和事务超时. 5:关于程序 ...