.NET Framework 将促进与 COM 组件、COM+ 服务、外部类型库和许多操作系统服务的交互操作。在托管和非托管对象模型之间,数据类型、方法签名和错误处理机制都存在差异。为了简化 .NET Framework 组件和非托管代码之间的互用并便于进行移植,公共语言运行时将从客户端和服务器中隐藏这两种对象模型之间的差异。
在运行时控制下执行的代码称作托管代码。相反,在运行时之外运行的代码称作非托管代码。COM 组件、ActiveX 接口和 Win32 API 函数都是非托管代码的示例。
与非托管代码交互操作
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.exe和RegAsm.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
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/libright/archive/2009/03/04/3957359.aspx