浅谈.NET互操作技术 重点托管代码
创始人
2024-06-28 22:11:13
0

 多年来在程序设计领域微软技术一直引领着每个时代,在每一代的技术背后都有相关的动机,而这些动机及其实现细节往往是大部分的程序设计课程没有涉及的,但是对于我们理解相关的技术又十分重要,本文将对几种相关技术和隐藏在动机背后的细节做简要的阐述,算是抛砖引玉。

COM技术于1993年首次发布,称得上是微软技术的一个里程碑,其意义在于使组件编程化得以实现。COM技术最初的思想起源于将类做成可重用的二进制组件,把类的实现和接口分离以便把类的实现封装到二进制防火墙的背后,而这道防火墙以VPTR和VTBL的形式保证了这个防火墙的不变性。.NET技术则在语言层面上支持了基于组件的程序设计。相对于COM技术,.NET技术就是为基于组件的程序设计而生的,所以其编码效率和语言可读性要高出COM一个等级。但是由于1993年以后的十多年时间里,人们利用基于COM的组件程序设计技术开发了大量的高复杂度,高可用性的代码,并且他们运行良好,效率极高,如果用.NET技术重写这些代码简直就是得不偿失,加之在.NET的实现过程中并不是所有的Windows API都被重写,有些功能是.NET所不能完成的。面对这样的问题, .NET互操作技术应运而生,可见需求才是技术的原动力。

.NET互操作技术主要分为3种,P/Invoke,C++ Interop,COM Interop,其中P/Invoke 主要用于调用C库函数和Windows API。C++ Interop则主要用于Managed C++调用 C++类库和核心算法库,它甚至允许托管代码和非托管代码在同一个文件中。 COM Interop主要包括正向的RCW和反向的CCW。下面以一个简单的例子对互操作中比较重要的数据封送进行简单的介绍。

如何封送字符串(P/Invoke方式)

假设非托管代码定义如下:

  1. void _cdecl stringMarshal( const wchar_t* inString,  wchar_t* outString, int buffersize)  
  2. {  
  3.     If(NULL != inString)  
  4. {  
  5.     wcscpy_s(outString, buffersize, inString);  
  6. }  

这段代码编译生成的文件名为:stringMarshal.dll

在托管代码中其托管定义如下:

  1. [DllImport  
  2. (“stringMarshal.dll”,  
  3. CharSetCharSet = CharSet.Unicode,  
  4. CallingConventionCallingConvention =CallingConvention.Cdecl)  
  5. ]  
  6. public extern static void stringMarshal (string inString, StringBuilder outString, int bufferSize); 

 

这里有几点需要注意:

1.  在声明函数时必须要用extern修饰符,目的是为了告诉编译器此函数是外部实现的,没有方法体,因此不需要在托管代码中搜索这个函数。

2.  在声明函数时必须要用static修饰符,原因是非托管的DLL导出的非托管方法都是可以直接调用的,无需对相关的类进行实例化,大部分情况下根本就不存在类。

3. 因为非托管代码中的字符串为wchar_t*类型,所以CharSet需要设置为CharSet.Unicode。

4. 因为非托管代码的调用方式为_cdecl, 所以托管部分的CallingConvention需要设置为CallingConvention.Cdecl,另外这种类型的调用方式是调用方负责处理堆栈,所以支持可变类型参数函数例如printf()的互操作。

5. 输入字符串需要封装为string是因为这个字符串属于固定字符串,互操作过程中不需要变化,而输出字符串则需要封装为StringBuilder,因为这种字符串默认为具有IN/OUT属性,其内容可变,而且当字符串经常需要变化时效率高。

托管代码中调用非托管代码方式如下:

  1. private static void TestStringMarshal ()  
  2.  {  
  3.     string inString = "Wally input test string.";  
  4.     int bufferSize = inString.Length;  
  5.     StringBuilder strbd = new StringBuilder(bufferSize);  
  6.     stringMarshal (inString, strbd, bufferSize + 1);  
  7.     Console.WriteLine("Wally Input string: {0}", inString);  
  8.     Console.WriteLine("Wally output string: {0}", strbd.ToString());  

总结

本文简要的介绍了.NET托管代码和本地非托管代码的互操作技术,并对数据封送的实现细节做了简单的说明,希望对大家的技术提高有所帮助,算是抛砖引玉,期待大家在这方面写出更多更好的文章。

 

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
30分钟搞定iOS自定义相机 最近公司的项目中用到了相机,由于不用系统的相机,UI给的相机切图,必须自定义才可以。就花时间简单研究...
Intel将Moblin社区控... 本周二,非营利机构Linux基金会宣布,他们将担负起Moblin社区的管理工作,而这之前,Mobli...