1.11 与非托管代码进行交互

.NET Framework比其他开发平台多提供了很多先进技术, 然而, 很少公司能承受起重新设计和重新实现所有的代码. 微软意识到这点, 因此构建了CLR来提供一种机制允许应用程序可以包含托管代码和非托管的代码. 特别地, CLR支持三种交互场景:

Ÿ   托管代码可以调用DLL中的非托管的函数: 托管代码可以很容易地调哟哦能够包含在DLL中的函数, 这是通过使用一种称为P/Invoke (Platform Invoke) 的机制来实现的. 毕竟, 定义在FCL中的很多类型都内部调用了Kernel32.dll, User32.dll等中的函数. 很多编程语言将暴露一种机制使得托管代码很容易调用包含在DLL中的非托管函数. 例如, 一个C#应用程序可以调用Kernel32.dll中的CreateSemaphore函数.

Ÿ   托管代码可以使用COM组件(server): 很多公司已经实现了很多非托管的COM组件, 使用这些组件中的类型, 可以创建用于描述COM组件的托管的程序集, 托管的代码可以访问这些程序集中的托管的类型, 这就和访问其他托管类型一样. 参考与.NET Framework SDK一起发布的Tlbimp.exe工具. 有时候, 你可能没有一个类型库或者你想对TlbImp.exe产生的东西获得更多的控制, 这样, 你可以手动地构建一个类型, CLR可以使用这个类型来实现适当的互操作. 例如, 你可以在C#应用程序中使用DirectX COM组件.

Ÿ   非托管的代码可以使用托管的类型(server): 很多现有的非托管的代码需要你提供COM组件才能让代码正常地工作. 很容易通过托管代码来实现这些组件, 这样你可避免代码必须处理引用计数和接口. 例如, 你可以用C#创建一个ActiveX控件或者shell extension. 参考TlbExp.exeRegAsm.exe工具.

除了这些场景, 微软的C++/CLI编译器(version 14)支持一个新的/clr命令行开关, 这个开关告诉编译器产生IL代码, 而不是native CPU指令. 如果你有大量已有的C++代码, 你可以使用这个新编译开关重新编译这些代码, 新的代码需要CLR才能执行, 你可以修改代码来充分利用CLR特有的功能.

但是对于下面的方法, /clr开关目前还不能将它们编译成IL代码: 包含内联汇编语言(通过关键字__asm实现); 接受可变数目参数的方法; 调用setjmp的方法; 包含一些内部程序(intrinsic routine)(例如__enable, __disable, __ReturnAddress, __AddressOfReturnAddress)的方法. 对于C++/CLI编译器不能编译成IL的完整列表, 可以参考关于编译器的文档. 当编译器不能编译成IL, 它会将方法编译成x86代码, 使得应用程序仍然能运行.

记住尽管产生的IL代码是托管的, 但是数据并不是, 也就是说数据对象不是从托管堆上分配的, 因此它们不能使用垃圾回收机制. 实际上, 数据类型没有包含在metadata, 并且这些类型的方法名仍然需要经过C++签名编码中转换(mangle).

下面的C代码调用了标准C运行时库函数printf, 也调用了System.Console.WriteLine方法, System.Console类型定义在FCL, 因此C/C++代码可以使用.

#include <stdio.h> // For printf

#using <mscorlib.dll> // For managed types defined in this assembly

using namespace System; // Easily access System namespace types

// Implement a normal C/C++ main function

void main() {

// Call the C runtime library's printf function.

printf("Displayed by printf./r/n");

// Call the FCL's System.Console's WriteLine method.

Console::WriteLine("Displayed by Console::WriteLine.");

}

编译这段代码不是很容易, 如果这个代码是在文件ManagedCApp.cpp, 你会执行如下的命令来编译它:

cl /clr ManagedCApp.cpp

结果是ManagedCApp.exe程序集文件, 如果你运行ManagedCApp.exe, 你将会看到如下的输出:

C:/>ManagedCApp

Displayed by printf.

Displayed by Console::WriteLine.

如果你使用ILDasm.exe来检查这个文件, 你将会看到定义在这个程序集中的所有的全局函数和全局字段, 显然地, 编译器自动地产生了很多填充代码. 如果你双机Main函数, ILDasm会为你显示出IL代码.

.method assembly static int32

modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) main() cil managed

{

  .vtentry 70 : 1

  // Code size 23 (0x17)

  .maxstack 1

  IL_0000: ldsflda valuetype '<CppImplementationDetails>' .$ArrayType$$$BY0BH@$$CBD

                       modopt([mscorlib]System.Runtime.CompilerServices.IsConst)

                       '??_C@_0BH@GBHlFCOF@Displayed?5by?5printf?4?$AN?6?$AA@'

  IL_0005: call     vararg int32

                       modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)

                       printf(

                         int8

                         modopt(

                           [mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte)

                         modopt(

                           [mscorlib]System.Runtime.CompilerServices.IsConst)*

                        )

  IL_000a: pop

  IL_000b: ldstr "Displayed by Console::WriteLine"

  IL_0010: call void [mscorlib]System.Console::WriteLine(string)

  IL_0015: ldc.i4.0

  IL_0016: ret

} // end of method 'Global Functions'::main

我们看到这不是很漂亮, 因为编译器产生了大量特殊的代码来让所有的代码都能运行, 然而, IL代码来看, printfConsole.WriteLine函数都被调用了.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值