C#中互操作性简介

一、引言

  这个系列是在C#基础知识中遗留下来的一个系列的,因为在C# 4.0中的一个新特性就是对COM互操作改进,然而COM互操作性却是.NET平台下其中一种互操作技术,为了帮助大家更好的了解.NET平台下的互操作技术,所以才有了这个系列。然而有些朋友们可能会有这样的疑问——“为什么我们需要掌握互操作技术的呢?” 对于这个问题的解释就是——掌握了.NET平台下的互操作性技术可以帮助我们在.NET中调用非托管的dll和COM组件。.NET是建立在操作系统的之上的一个开发框架,其中.NET 类库中的类也是对Windows API的抽象封装,然而.NET类库不可能对所有Windows API进行封装,当.NET中没有实现某个功能的类,然而该功能在Windows API被实现了,此时我们完全没必要去自己在.NET中自定义个类,这时候就可以调用Windows  API 中的函数来实现,此时就涉及到托管代码与非托管代码的交互,此时就需要使用到互操作性的技术来实现托管代码和非托管代码更好的交互。.NET 平台下提供了3种互操作性的技术:

  1. Platform Invoke(P/Invoke),即平台调用,主要用于调用C库函数和Windows API
  2. C++ Introp, 主要用于Managed C++(托管C++)中调用C++类库
  3. COM Interop, 主要用于在.NET中调用COM组件和在COM中使用.NET程序集。

下面就对这3种技术分别介绍下。

二、平台调用

  使用平台调用的技术可以在托管代码中调用动态链接库(Dll)中实现的非托管函数,如Win32 Dll和C/C++ 创建的dll。看到这里,有些朋友们应该会有疑问——在怎样的场合我们可以使用平台调用技术来调用动态链接库中的非托管函数呢?

  这个问题就如前面引言中说讲到的一样,当在开发过程中,.NET类库中没有提供相关API然而Win32 API 中提供了相关的函数实现时,此时就可以考虑使用平台调用的技术在.NET开发的应用程序中调用Win32 API中的函数;

  然而还有一个使用场景就是——由于托管代码的效率不如非托管代码,为了提高效率,此时也可以考虑托管代码中调用C库函数。

2.1 在托管代码中通过平台调用来调用非托管代码的步骤

(1).  获得非托管函数的信息,即dll的名称,需要调用的非托管函数名等信息

(2). 在托管代码中对非托管函数进行声明,并且附加平台调用所需要属性

(3). 在托管代码中直接调用第二步中声明的托管函数

2.2 平台调用的调用过程

(1)  查找包含该函数的DLL,当需要调用某个函数时,当然第一步就需要知道包含该函数的DLL的位置,所以平台调用的第一步也就是查找DLL,其实在托管代码中调用非托管代码的调用过程可以想象成叫某个人做事情,首先我们要找到那个人在哪里(即查找函数的DLL过程),找到那个人之后需要把要做的事情告诉他(相当于加载DLL到内存中和传入参数),最后让他去完成需要完成的事情(相当于让非托管函数去执行任务)。

(2) 将找到的DLL加载到内存中。

(3) 查找函数在内存中的地址并把其参数推入堆栈,来封送所需的数据。CLR只会在第一次调用函数时,才会去查找和加载DLL,并查找函数在内存中的地址。当函数被调用过一次之后,CLR会将函数的地址缓存起来,CLR这种机制可以提高平台调用的效率。在应用程序域被卸载之前,找到的DLL都一直存在于内存中。

(4) 执行非托管函数。

平台调用的过程可以通过下图更好地理解:

三、C++ Interop

  第二部分主要向大家介绍了第一种互操作性技术,然后我们也可以使用C++ Interop技术来实现与非托管代码进行交互。然而C++ Interop 方式有一个与平台调用不一样的地方,就是C++ Interop 允许托管代码和非托管代码存在于一个程序集中,甚至同一个文件中。C++ Interop 是在源代码上直接链接和编译非托管代码来实现与非托管代码进行互操作的,而平台调用是加载编译后生成的非托管DLL并查找函数的入口地址来实现与非托管函数进行互操作的。C++ Interop使用托管C++来包装非托管C++代码,然后编译生成程序集,然后再托管代码中引用该程序集,从而来实现与非托管代码的互操作。 关于具体的使用和与平台调用的比较,这里就不多介绍,我将会在后面的专题中具体介绍。

四、COM Interop

  COM(Component Object Model,组件对象模型)是微软之前推荐的一个开发技术,由于微软过去十多年里面开发了大量的COM组件,然而不可能在使用.NET技术重写这些COM组件实现的功能,所以为了解决在.NET中的托管代码能够调用COM组件的问题,.NET 平台下提供了COM Interop,即COM互操作技术,COM Interop不仅支持在托管代码中使用COM组件,而且还支持想CMO组件功能托管对象。下面就这两种支持分别做一个介绍。

4.1 在.NET中使用COM组件

在.NET中使用COM对象,主要有3种方法:

  1. 使用TlbImp工具为COM组件创建一个互操作程序集来绑定早期的COM对象,这样就可以在程序中添加互操作程序集来调用COM对象
  2. 通过反射来后期绑定COM对象
  3. 通过P/Invoke创建COM对象或使用C++ Interop为COM对象编写包装类

但是我们经常使用的都是方法一,下面介绍下使用方法一在.NET 中使用COM对象的步骤:

1.找到要使用的COM 组件并注册它。使用 regsvr32.exe 注册或注销 COM DLL。                               
      2.在项目中添加对 COM 组件或类型库的引用。

  • 添加引用时,Visual Studio 会用到Tlbimp.exe(类型库导入程序),Tlbimp.exe程序将生成一个 .NET Framework 互操作程序集。该程序集又称为运行时可调用包装 (RCW),其中包含了包装COM组件中的类和接口。Visual Studio 将生成组件的引用添加至项目。

3. 创建RCW中类的实例,这样就可以使用托管对象一样来使用COM对象。

下面通过一个图更好地说明在.NET中使用COM组件的过程:

4.2 在COM中使用.NET程序集

  .NET 公共语言运行时通过COM可调用包装(COM Callable Wrapper,即CCW)来完成与COM类型库的交互。CCW可以使COM客户端认为是在与普通的COM类型交互,同时使.NET组件认为它正在与托管应用程序交互。在这里CCW是非托管COM客户端与托管对象之间的一个代理。 CCW既可以维护托管对象的生命周期,也负责数据类型在COM和.NET之间的相互转换。实现在COM使用.NET 类型的基本步骤如:

1. 在C#项目中添加互操作特性

可以修改C#项目属性使程序集对COM可见。右键解决方案选择属性,在“应用程序标签”中选择“程序集信息”按钮,在弹出的对话框中选择 “使程序集COM可见” 选项,如下图所示:

2. 生成COM类型库并对它进行注册以供COM客户端使用

在“生成”标签中,选中 “为COM互操作注册”选项,如下图:

  勾选“为COM互操作注册”选项后,Visual Studio会调用类型库导出工具(Tlbexp.exe)为.NET程序集生成COM类型库再使用程序集注册工具(Regasm.exe)来完成对.NET程序集和生成的COM类型库进行注册,这样COM客户端可以使用CCW服务来对.NET对象进行调用了。

五、总结

  介绍到这里,本专题的内容就结束,本专题主要对.NET 提供的互操作的技术做了一个总的概括,在后面的专题中将会对具体的技术进行详细的介绍和给出一些简单的使用例子。

以上就是C#中互操作性简介的详细内容,更多关于c# 互操作性的资料请关注我们其它相关文章!

(0)

相关推荐

  • 简单聊聊c# 事件

    引言: 前面几个专题对委托进行了详细的介绍的,然后我们在编写代码过程中经常会听到"事件"这个概念的,尤其是写UI的时候,当我们点击一个按钮后VS就会自动帮我们生成一些后台的代码,然后我们就只需要在Click方法里面写代码就可以,所以可能有些刚接触C#的朋友就觉得这样很理所当然的,也没有去思考这是为什么的,为什么点击下事件就会触发我们在Click方法里面写的代码呢?事件到底扮演个什么样的角色呢?为了解除大家的这些疑惑,下面就详细介绍了事件,让一些初学者深入理解C#中的事件的概念. 一.为

  • c# 委托的本质是什么

    引言 上一个专题已经和大家分享了我理解的--C#中为什么需要委托,专题中简单介绍了下委托是什么以及委托简单的应用的,在这个专题中将对委托做进一步的介绍的,本专题主要对委本质和委托链进行讨论. 一.委托的本质 平时我们很容易使用委托--用C# delegate关键字定义委托,再用new操作符构造委托实例,然后通过调用委托实例来调用回调方法(就是用一个了委托对象的变量来代替方法名,这句话如果刚接触的人不好理解的话,这里给个例子:MyDelegate mydelegate =new Mydelegat

  • 深入分析c# 继承

    继承是面向对象程序设计中最重要的概念之一.继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易.同时也有利于重用代码和节省开发时间. 当创建一个类时,程序员不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可.这个已有的类被称为的基类,这个新的类被称为派生类. 继承的思想实现了 属于(IS-A) 关系.例如,哺乳动物 属于(IS-A) 动物,狗 属于(IS-A) 哺乳动物,因此狗 属于(IS-A) 动物. 基类和派生类 一个类可以派生自多个

  • C# 一个WCF简单实例

    WCF实例(带步骤) 复制代码 代码如下: <xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" /> 本篇转自百度文档,自己试过,确实可以用. 以订票为例简单应用wcf 新建一个wcf服务应用程序 在IService1.cs定义服务契约 复制代码 代码如下: namespace WcfDemo { // 注意: 如果更改此处的接口名称 "IService

  • C# 引入委托的目的是什么

    引言: 对于一些刚接触C# 不久的朋友可能会对C#中一些基本特性理解的不是很深,然而这些知识也是面试时面试官经常会问到的问题,所以我觉得有必要和一些接触C#不久的朋友分享下关于C#基础知识的文章,所以有了这个系列,希望通过这个系列让朋友对C#的基础知识理解能够更进一步.然而委托又是C#基础知识中比较重要的一点,基本上后面的特性都和委托有点关系,所以这里就和大家先说说委托,为什么我们需要委托. 一.C#委托是什么的? 在正式介绍委托之前,我想下看看生活中委托的例子--生活中,如果如果我们需要打官司

  • 详解c# 委托链

    引言: 上一专题介绍了下编译器是如何来翻译委托的,从中间语言的角度去看委托,希望可以帮助大家进一步的理解委托,然而之前的介绍都是委托只是封装一个方法,那委托能不能封装多个方法呢?因为生活中经常会听到,我代表大家的意见等这样的说话,既然委托也是一个代表,那他如果只能代表一个人,那他的魅力就不是很大了吧,所以我们就会委托能不能代表多个方法的? 答案是可以的,这就是本专题要讲的内容--委托链,委托链也是一个委托,只是因为它是把多个委托链在一起,所以我们就以委托链来这么称呼它的. 一.到底什么是委托链

  • asp.net(c#)网页跳转七种方法小结

    ①response.redirect 这个跳转页面的方法跳转的速度不快,因为它要走2个来回(2次postback),但他可以跳 转到任何页面,没有站点页面限制(即可以由雅虎跳到新浪),同时不能跳过登录保护.但速度慢是其最大缺陷!redirect跳转机制:首先是发送一个http请求到客户端,通知需要跳转到新页面,然后客户端在发送跳转请求到服务器端.需要注意的是跳转后内部空间保存的所有数据信息将会丢失,所以需要用到session. 实例 Example that uses Redirect [C#;

  • C#几种截取字符串的方法小结

    1.根据单个分隔字符用split截取 例如 复制代码 代码如下: string st="GT123_1"; string[] sArray=st.split("_"); 即可得到sArray[0]="GT123",sArray[1]="1"; 2.利用多个字符来分隔字符串 例如 复制代码 代码如下: string str = "GTAZB_JiangjBen_123";string[] sArray = s

  • c#对XML文档的创建与增删改查的示例代码

    一.创建的第一种方式 //1.创建一个XML文档 XmlDocument doc = new XmlDocument(); //2.创建第一行描述信息 XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null); //3.将创建的第一行描述信息添加到文档中 doc.AppendChild(dec); //4.给文档添加根节点 XmlElement Books = doc.CreateElem

  • C# 标准事件流实例代码

    服装价格变动,触发淘宝发布活动和消费者购买衣服事件流 public class EventStandard { public class Clothes { /// <summary> /// 服装编码 /// </summary> public string Id { get; set; } /// <summary> /// 服装名称 /// </summary> public string Name { get; set; } /// <summ

  • C# DataGridView添加新行的2个方法

    可以静态绑定数据源,这样就自动为DataGridView控件添加 相应的行.假如需要动态为DataGridView控件添加新行,方法有很多种,下面简单介绍如何为DataGridView控件动态添加新行的两种方 法: 方法一: 复制代码 代码如下: int index=this.dataGridView1.Rows.Add();this.dataGridView1.Rows[index].Cells[0].Value = "1"; this.dataGridView1.Rows[inde

随机推荐