博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
手动生成C#的COM包装类的常见问题和解决办法
阅读量:4189 次
发布时间:2019-05-26

本文共 2138 字,大约阅读时间需要 7 分钟。

看一下如下代码:

    [Guid("25088995-7924-4B15-B01A-EA7C422ADC68")]

    public class CHelloClass : IHello

    {

        [DispId(1)]

        [MethodImplAttribute(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]

        public extern void HelloWorld();

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            CHelloClass obj = new CHelloClass();

            obj.HelloWorld();

        }

    }       

 

这里的CHelloClass是一个COM对象,指定了GUID,实现了IHello接口的HelloWorld函数。然而,当执行这条语句CHelloClass obj = new CHelloClass,会产生如下异常:

Unhandled Exception: System.Security.SecurityException: ECall methods must be packaged into a system module.

 

这里异常信息需要解释一下:ECall是一种内部调用的方式(还存在其它方式如FCall等),由CLR本身实现,而不由用户提供实现。当CHelloClass中缺少ComImportAttrib这个属性的时候,CLR会认为HelloWorld这个函数是在CLR本身实现的,然后又在CLR内部的调用表(这个表维护所有CLR内部调用的函数)无法查到对应的实现,所以才抛出异常。当ComImportAttribute存在的时候,CLR才知道这个class是从COM对象Import过来的,从而作一些特殊处理,并不会对HelloWorld按照ECall方式来处理。

我们再看一下,是否MethodImplAttribute这里真正需要呢?可以试一下加上ComImport然后去掉MethodImplAttri看看:

    [ComImport]

    [Guid("25088995-7924-4B15-B01A-EA7C422ADC68")]

    public class CHelloClass : IHello

    {

        [DispId(1)]

        public extern void HelloWorld();

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            CHelloClass obj = new CHelloClass();

            obj.HelloWorld();

        }

    }       

当到了new CHelloClass这条语句的时候,会产生下面异常:

Unhandled Exception: System.TypeLoadException: Could not load type 'CHelloClass' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' because the method 'HelloWorld' has no implementation (no RVA).   at Program.Main(String[] args)

这一次,CLR则报告HelloWorld函数没有对应的实现代码。没有RVA的意思是CLR无法找到HelloWorld函数代码的位置。这个位置是一个内存的相对位置,因此称之为RVARelative Virtual Address)。由于实际的实现是由CLR提供,准确说是RCW提供,因此这里是需要MethodImplAttrbute的。

最终正确的版本如下:

    [ComImport]

    [Guid("25088995-7924-4B15-B01A-EA7C422ADC68")]

    public class CHelloClass : IHello

    {

        [DispId(1)]

        [MethodImplAttribute(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]

        public extern void HelloWorld();

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            CHelloClass obj = new CHelloClass();

            obj.HelloWorld();

        }

    }       

 

当然了,如果你不自己编写COM Wrapper代码的话则不会遇到类似的问题。所以请尽可能的让Tlbimp替你生成Interop代码,而不是自己手动编写,除非Tlbimpl生成的代码不符合你的要求。

 

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1608022

你可能感兴趣的文章
android中使用TextView来显示某个网址的内容,使用<ScrollView>来生成下拉列表框
查看>>
andorid里关于wifi的分析
查看>>
Hibernate和IBatis对比
查看>>
Spring MVC 教程,快速入门,深入分析
查看>>
Ubuntu Navicat for MySQL安装以及破解方案
查看>>
在C++中如何实现模板函数的外部调用
查看>>
HTML5学习之——HTML 5 应用程序缓存
查看>>
HTML5学习之——HTML 5 服务器发送事件
查看>>
mysql中用命令行复制表结构的方法
查看>>
hbase shell出现ERROR: org.apache.hadoop.hbase.ipc.ServerNotRunningYetException
查看>>
解决Rhythmbox乱码
查看>>
豆瓣爱问共享资料插件发布啦
查看>>
kermit的安装和配置
查看>>
linux中cat命令使用详解
查看>>
java中的异常机制
查看>>
商务智能-基本方法-数据钻取
查看>>
openstack-instance-high-availability-Evacuate
查看>>
evacuate-instance-automatically
查看>>
pycharm常用设置(keymap设置及eclipse常用快捷键总结)
查看>>
关于在openstack的环境变量.bashrc自定自己简化命令
查看>>