[转]C# 互操作性入门系列(一):C#中互操作性介绍

传送门

C#互操作系列文章:

  1. C# 互操作性入门系列(一):C#中互操作性介绍
  2. C# 互操作性入门系列(二):使用平台调用调用Win32 函数
  3. C# 互操作性入门系列(三):平台调用中的数据封送处理
  4. C# 互操作性入门系列(四):在C#中调用COM组件

本专题概要:

  • 引言
  • 平台调用
  • C++ Interop(互操作)
  • COM Interop(互操作)

一、引言

  这个系列是在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 提供的互操作的技术做了一个总的概括,在后面的专题中将会对具体的技术进行详细的介绍和给出一些简单的使用例子。

时间: 2024-10-10 00:29:15

[转]C# 互操作性入门系列(一):C#中互操作性介绍的相关文章

[转]C# 互操作性入门系列(四):在C# 中调用COM组件

传送门 C#互操作系列文章: C#互操作性入门系列(一):C#中互操作性介绍 C#互操作性入门系列(二):使用平台调用调用Win32 函数 C# 互操作性入门系列(三):平台调用中的数据封送处理 C#互操作性入门系列(四):在C# 中调用COM组件 本专题概要: 引言 如何在C#中调用COM组件--访问Office 互操作对象 在C# 中调用COM组件的实现原理剖析 错误处理 小结 一.引言 COM(Component Object Modele,组件对象模型)是微软以前推崇的一个开发技术,所以

[转]C# 互操作性入门系列(三):平台调用中的数据封送处理

传送门 C#互操作系列文章: C#互操作性入门系列(一):C#中互操作性介绍 C#互操作性入门系列(二):使用平台调用调用Win32 函数 C#互操作性入门系列(三):平台调用中的数据封送处理 C#互操作性入门系列(四):在C# 中调用COM组件 本专题概要 数据封送介绍 封送Win32数据类型 封送字符串的处理 封送结构体的处理 封送类的处理 小结 一.数据封送介绍 看到这个专题时,大家的第一个疑问肯定是--什么是数据封送呢?(这系列专题中采用假设朋友的提问方式来解说概念,就是希望大家带着问题

C# 互操作性入门系列(三):平台调用中的数据封送处理

好文章搬用工模式启动ing ..... { 文章中已经包含了原文链接 就不再次粘贴了 言明 改文章是一个系列,但只收录了2篇,原因是 够用了 } --------------------------------------------------------------------------------------- C#互操作系列文章: C#互操作性入门系列(一):C#中互操作性介绍 C#互操作性入门系列(二):使用平台调用调用Win32 函数 C#互操作性入门系列(三):平台调用中的数据封

C# 互操作性入门系列(二):使用平台调用调用Win32 函数

好文章搬用工模式启动ing ..... { 文章中已经包含了原文链接 就不再次粘贴了 言明 改文章是一个系列,但只收录了2篇,原因是 够用了 } --------------------------------------------------------------------------------------- C#互操作系列文章: C#互操作性入门系列(一):C#中互操作性介绍 C#互操作性入门系列(二):使用平台调用调用Win32 函数 C#互操作性入门系列(三):平台调用中的数据封

RxJava入门系列四,Android中的响应式编程

RxJava入门系列四,Android中的响应式编程 在入门系列1,2,3中,我基本介绍了RxJava是如何使用的.但是作为一名Android开发人员,你怎么让RxJava能为你所用呢?这篇博客我将针对Android开发来介绍一下RxJava的使用场景. RxAndroid RxAndroid是为Android打造的RxJava扩展.通过RxAndroid可以让你的Android开发变得更轻松. 首先,RxAndroid中提供了AndroidSchedulers,你可以用它来切换Android线

python入门系列:Python中一切皆对象

引言 Java语言也是面向对象的语言,但是Python要更加彻底Python的面向对象特性,是它使用起来灵活的根本所在对象的特点 可以赋值给一个变量 函数也是对象 def test(name):print(name) my_func = test # 注意 只写函数名 和 函数名加括号 的区别my_func("MetaTian") # 打印:MetaTian可以添加到集合中去 def plus(a, b):print(a+b) def minus(a, b):print(a-b)fun

<转载> [unreal4入门系列之七] UE4中的Actor类和Pawn类

原文地址: http://www.52vr.com/article-558-1.html 现在我们开始进入UE4的代码开发工作.首先,UE4的类框架是非常庞大的,看起来有点让人措手不及.不过正因为UE4的类框架很完善,有很多常用的代码 (函数和类)是已经提供给我们了,我们只需要简单地调用来完成游戏开发的任务.所以我们可以将注意力集中于游戏功能和玩法上,而不是繁琐的实现细节上.这 里介绍两个很重要的类: Actor类 在UE4中,Actor类是可以放到游戏场景中的游戏对象的基本类型.你如果想放置任

转:[Silverlight入门系列]使用MVVM模式(9): 想在ViewModel中控制TreeView节点展开?

很多童鞋看了我的博客以后也去实践MVVM,但却发现Silverlight实践中的MVVM很难实现,比纯粹的CodeBehind难度大很多.首先是原来在xaml.cs的CodeBehind部分很容易控制界面逻辑,现在这部分逻辑移到ViewModel里面去了以后,就很难调用CodeBind的部分;其次是很多View和ViewModel.或者一个ViewModel多个View,他们之间如何通 很多童鞋看了我的博客以后也去实践MVVM,但却发现Silverlight实践中的MVVM很难实现,比纯粹的Co

ASP.NET AJAX入门系列(9):在母版页中使用UpdatePanel

ASP.NET AJAX入门系列(9):在母版页中使用UpdatePanel 本文简单介绍一下在母版页中使用UpdatePanel控件,翻译自官方文档. 主要内容 1.添加UpdatePanel控件到Content Page 2.通过Master Page刷新UpdatePanel 一.添加UpdatePanel控件到Content-Page 1.添加一个新的Master Page,并切换到设计视图. 2.在工具箱中AJAX Extensions标签下双击ScriptManager控件添加到页面