`
happmaoo
  • 浏览: 4431009 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

手动生成C#的COM包装类的常见问题和解决办法

阅读更多
<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/46860.html" frameborder="0" width="468" scrolling="no" height="60"></iframe>

看一下如下代码:

[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


分享到:
评论

相关推荐

    C++和C#的却别与各自的用法

    12. 包装和命名空间:C#使用using指令引用命名空间,C++使用#include指令包含头文件。 13. 构造与析构:C#的构造函数自动调用基类构造器,析构函数由垃圾回收器自动调用,而C++的析构函数调用时机由程序员控制。 ...

    CLR.via.C#.(中文第3版)(自制详细书签)Part2

    17.7.3 简化语法3:局部变量不需要手动包装到类中即可传给回调方法 17.8 委托和反射 第18章 定制attribute 18.1 使用定制attribute 18.2 定义自己的attribute类 18.3 attribute的构造器和字段/属性的数据类型 ...

    C#中调用OCX控件

    4. **使用生成的包装控件**:为了在C#中正常使用OCX控件,需要先使用`Aximp.exe`生成包装类。这样做的原因是OCX控件本质上是基于COM的技术,而C#是基于.NET Framework的托管代码环境。通过包装类,可以将OCX控件无缝...

    c#调用c++ 动态链接库

    面临的问题和解决方案 - **类型转换**:C#和C++的数据类型不完全相同,需要正确地映射数据类型,例如,`int`在C#中是32位,而在C++中可能是32位或64位,具体取决于平台。 - **异常处理**:C++使用异常处理,而C#...

    managedwinapi WINDOWS API 托管包装类集合

    《深入理解ManagedWinapi:简化Windows API调用的托管包装类》 在Windows应用程序开发中,直接调用操作系统级别的API(Application Programming Interface)是常见且必要的。然而,使用C#等.NET语言时,通常需要...

    C#调用activeX控件方法步骤 (2).docx

    在C#中调用ActiveX控件是一种常见的技术,它允许.NET Framework应用程序利用那些原本设计为在非托管环境中运行的组件。以下是如何在C#中正确调用和使用OCX控件的详细步骤: 1. **注册OCX控件**: 在Windows系统中...

    CLR.via.C#.(中文第3版)(自制详细书签)

    17.7.3 简化语法3:局部变量不需要手动包装到类中即可传给回调方法 17.8 委托和反射 第18章 定制attribute 18.1 使用定制attribute 18.2 定义自己的attribute类 18.3 attribute的构造器和字段/属性的数据类型 ...

    C#调用activeX控件方法步骤.docx

    `AxHost`类是关键,因为它创建了一个包装类,使得ActiveX控件能够作为.NET控件在Windows窗体上使用。 总的来说,调用ActiveX控件在C#中需要理解COM组件的原理,掌握注册、包装和调用的步骤,以及处理可能遇到的设计...

    存储过程代码生成器

    总结一下,wrapsp是面向SQL存储过程的代码生成器,它能自动生成包装器类,使得调用存储过程如同调用普通方法,提高了开发效率,增强了代码的可读性和一致性。在使用wrapsp时,需要了解其配置、分析、生成和集成的...

    Halcon导出的C#代码的调用及讨论

    在本文中,我们将探讨如何将Halcon导出的C#代码集成到C#项目中,并且在此过程中涉及了多个...同时,在处理外部函数和Halcon算子时,需要特别注意它们在C#代码中的引用方式和调用方法,以保证图像处理功能能够正确执行。

    ABAP Webservice接口部分-C#项目文件

    .NET Framework提供了一个名为svcutil的命令行工具,可以生成C#客户端代理类,这些类封装了与Web服务通信的所有细节。只需提供Web服务的WSDL地址,svcutil就能自动生成必要的代码。 4. **SAP .NET Connector**: ...

    C#程序与基于COM的OPC数据存取服务器交换数据

    本文探讨了如何使用C#语言编写基于.NET的应用程序来与基于COM的OPC数据存取服务器进行数据交换,并介绍了解决这一问题的关键技术:COM编排技术和OPC.NET API的设计模式。 #### 关键词 - C# - COM 编排 - 数据存取...

    CLR.via.C#.(中文第3版)(自制详细书签)Part1

    17.7.3 简化语法3:局部变量不需要手动包装到类中即可传给回调方法 17.8 委托和反射 第18章 定制attribute 18.1 使用定制attribute 18.2 定义自己的attribute类 18.3 attribute的构造器和字段/属性的数据类型 ...

    CLR.via.C#.(中文第3版)(自制详细书签)Part3

    17.7.3 简化语法3:局部变量不需要手动包装到类中即可传给回调方法 17.8 委托和反射 第18章 定制attribute 18.1 使用定制attribute 18.2 定义自己的attribute类 18.3 attribute的构造器和字段/属性的数据类型 ...

    C#23种设计模式_示例源代码及PDF

    建造模式: 从而使一个建造过程生成具有不 建造模式 将产品的内部表象和产品的生成过程分割开来, 同的内部表象的产品对象。 建造模式使得产品内部表象可以独立的变化, 客户不必知道产品 内部组成的细节。建造模式...

    同时使用 Visual Basic 6 和 Visual Basic.NET 的最佳做法

    - **手动创建 COM 映射类**:对于复杂或非托管的 .NET 类,可能需要手动创建与 COM 兼容的包装类。 - **使用 COM Interop Assemblies**:这是最常用的方式,通过 `regasm` 工具创建,但需要注意版本管理和安全问题。...

    C# 培训模拟试题 (2)

    在`MyClass`类的`change`方法中,通过`ref`关键字传递的字符串参数实际上是其地址,但在C#中,字符串是不可变的,即使在方法内部修改了字符串引用,外部的原始字符串也会被更新,因为引用指向了一个新的字符串实例。...

    在.NET中激活基于COM的OPC数据存取定制接口

    1. **研究C#接口属性类**:深入理解C#中的接口和属性类的定义方式,以便更好地映射COM接口到.NET环境。 2. **编排IDL**:根据OPC数据存取规范2.0版本,手动编写IDL文件,描述OPC服务器的定制接口。 3. **类型库导入*...

    Customize the Code Generated by the Resources Designer_VB

    1. **手动编辑生成的资源类**:资源设计器生成的代码位于资源文件对应的隐藏.cs或.vb文件中。尽管不推荐直接修改这些文件,但若确实需要,可以在此添加或调整代码。例如,你可能希望为每个资源添加特定的验证逻辑。 ...

Global site tag (gtag.js) - Google Analytics