本系列文章来自 CLR VIA C#
.NET FrameWork在Microsoft Windows平台的顶部运行。这意味着.NET必须用Windows可以理解的技术来构建。首先,所有的托管模块和程序集文件都必须使用Windows PE文件格式,而且要么是一个Windows.exe文件,要么是一个DLL文件。
开发CLR时,Microsoft实际是将它实现成包含在一个DLL中的COM服务器。也就是说,Microsoft为CLR定义了一个标志的COM接口,并为该接口和COM服务器分配了GUID(全局通用标识符)。安装.NET FrameWork时,代表CLR的COM服务器和其它COM服务器一样在WINDOW注册表中注册。如果想了解这方面更多的信息,可参考.NET Framework SDK一起发布的C++头文件MetaHost.h。该头文件中定义了GUID和非托管ICLRMetaHost接口。
任何Window应用程序都可以寄宿CLR。但是,不要通过调用CoCreateInstance来创建CLR COM服务器的实例,相反,你的非托管宿主应该调用MetaHost.h文件中声明的CLRCreateInstance函数。CLRCreateInstance函数是在MSCorEE.dll文件中实现的,该文件一般在C:\Windows\System32目录中。这个DLL被人们称为“垫片(shim)”,它的工作决定创建那个版本的CLR;注意垫片本身并不包含CLR COM服务器。
一台机器可安装多个版本的CLR,但只有一个版本的MSCorEE.dll文件(只限于X86架构下)。机器上安装的MSCorEE.dll版本是与机器上安装最新的CLR一起发布的那个版本。因此,该版本的MSCorEE.dll知道如何查找机器上可能安装的以前的版本的CLR。
包含实际CLR代码的文件的名称在不同版本的CLR中是不同的。对于1.0,1.1和2.0版本,CLR代码实在一个名为MSCorWks.dll的文件中;对于4.0版本,CLR代码在一个名为Clr.dll的文件中。由于一个机器上可能安装多个版本的CLR,所以这些文件安装到不同的目录中。
版本1.0 C:\Windows\Microsoft.NET\Framework\v1.0.3705
版本 2.1 C:\Windows\Microsoft.NET\Framework\v1.1.4322
版本2.0 C:\Windows\Microsoft.NET\Framework\v2.0.50727
版本 4.0 C:\Windows\Microsoft.NET\Framework\v4.0.30319
CLRCreateInstance函数可以返回一个ICLRMetaHost接口。宿主应用程序可调用这个接口的GetRuntime函数,指定宿主要创建的CLR的版本。然后,垫片将所需版本的CLR加载到宿主的进程中。
默认情况下,当一个托管的可执行文件启动时,垫片会检查可执行文件,提取当初生成和测试应用程序时使用的CLR的版本信息。但是,应用程序可在它的XML文件中设置requiredRuntime和supportedRuntime这两项来覆盖默认行为。
GetRuntime函数返回指向一个非托管接口ICLRRuntimeInfo的指针。有了这个指针后,就可以利用GetInterface方法获得ICLRRuntimeHost接口了。宿主应用程序可调用这个接口的方法来做下面的事情:
- 设置宿主管理器。告诉CLR,宿主想参与涉及以下操作的决策:内存分配、线程调度/同步以及程序集加载等。宿主还可声明它想获得有关垃圾回收启动和停止以及特定操作超时的通知。
- 获取CLR管理器。告诉CLR阻止使用某些类/成员。另外,宿主能分辨哪些代码可以调试,哪些代码不能,以及当一个特定时间发生时宿主应调用哪些方法。
- 初始化并启动CLR。
- 加载程序集并执行其中的代码。
- 停止CLR,阻止任何更多的托管代码在Windows进程中运行。
注意:当然,Window进程完全可以不加载CLR。只有需要在进程中执行托管代码时,才需要加载它。在CLR 4.0以前,一个Windows进程只允许加载CLR的一个实例。换言之,在一个进程中,要么不包含任何CLR,要么 包含CLR V1.0,CLR V1.1 或者CLR 2.0之一。只允许每个进程包含一个CLR版本之一项巨大的限制。例如,这样一来,Microsift office outlook便不能加载为不同版本的.NET Framework生成和测试项的两个加载项。
但是,随着.NET Framework 4.0的发布,Microsoft支持在一个Windows进程中同时加载CLR V2.0和V4.0,允许为.NET Framework 2.0和4.0写得不同组件同时运行,不会造成任何兼容性问题。
一个CLR加载到一个Windows进程中之后,便永远不能卸载;调用ICLRRuntimeHost接口上的AddRef和Release方法时没有作用的,CLR从进程中卸载的唯一方法就是终止进程,这造成Window清理进程使用的所有资源,包括CLR在内。
有许多原因可以解释寄宿CLR为何很有用。寄宿使任何应用程序都能提供CLR功能和可编程性,而且至少一部分能用托管代码来写。如果开发人员想扩展一个应用程序,寄宿CLR能提供多方面的好处,下面总结一部分好处。
- 可以用任何编程语言来编写。
- 代码在JIT编译后执行,所以速度很快
- 代码使用垃圾回收避免内存泄露和损坏。
- 代码在一个安全的沙箱中运行。
- 宿主不必提供一个丰富的开发环境。宿主利用现有的技术,包括语言、编译器、编辑器、调试器、profiler等。