代码改变世界

1.3 加载公共语言运行时

2011-11-03 14:19  iRead  阅读(880)  评论(0编辑  收藏  举报

  你生成的每个程序集既可以是一个可执行应用程序,也可以是一个DLL(其中含有一组可执行程序使用的类型)。当然,最终是由CLR管理这些程序集中的代码执行。这意味着必须在目标机器上安装好.NET Framework。Microsoft创建了一个重发分包(redistribution package),允许将.NET Framework免费分发并安装到你的用户的计算机上。一些版本的Windows在发售时就已经打包好了.NET Framework。

  要知道是否已安装.NET Framework,只需检查%SystemRoot%System32目录中的MSCorEE.dll文件。存在该文件,表明.NET Framework已安装。然而,一台机器上可能同时安装好几个版本的.NET Framework。要确切了解已安装哪些版本的.NET Framework,请检查以下注册表项的子项。

   KEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\NET Framework Setup\NDP

  .NET Framework SDK提供了一个名为CLRVer.exe的命令行实用程序,它能列出一台机器上安装的所有CLR版本。这个实用程序还能列出机器中正在运行的进程使用的CLR版本,方法是使用-all命令行开关,或指定自己感兴趣的进程的ID。

  在了解CLR具体如何加载之前,需要稍微花一点时间来讨论Windows的32位和64位版本。如果程序集文件包含类型安全的托管代码,那么无论在32位版本的Windows上,还是64位版本的Windows上,所写的代码都应该能正常工作。在这两种版本的Windows上运行,源代码无需进行任何改动。事实上,编译器最终生成的EXE/DLL文件不仅能在32位Windows上运行,还能在64位Windows的x64和IA64版本上运行!也就是说,只要机器上安装了.NET Framework的某个版本,文件就能在这台机器上运行。

  极少情况下,开发人员希望代码只在一个特定版本的Windows上运行。例如,假如要使用不安全的代码,或者要和面向一种特定CPU架构的非托管代码进行互操作,就可能需要这样做。为了帮助这些开发人员,C#编译器提供了一个/platform命令行开关选项。这个开关允许指定最终生成的程序集只能运行在32位Windows版本的x86机器上使用,只能在运行64位Windows的x64机器上使用,或者只能在运行64位Windows的Intel Itanium机器上使用。如果不具体制定一个平台,默认选项就是anycpu,表明最终生成的程序集能在任何版本的Windows上运行。Visual Studio用户要想设置一个项目的目标平台,可以打开项目的属性页,从“生成”选项卡的“目标平台”列表中选择一个选项,如图1-3所示。

图 1-3 使用Visual Studio设置目标平台

  取决于/platform开关选项,C#编译器生成的程序集要么包含一个PE32头,要么包含一个PE32+头。除此之外,编译器还会在头中指定要求什么CPU架构(如果使用默认值anycpu,则不明确指定)。Microsoft发布了SDK命令行实用工具DumpBin.exe和CorFlag.exe,可用它们检查编译器生成的托管模块所嵌入的信息。

  运行一个可执行文件时,Windows会检查这个EXE文件的头,判断应用程序需要的是32位地址空间,还是64位地址空间。具有PE32的文件可在一个32位或64位地址空间中运行,具有PE32+头的文件则需要一个64位地址空间。Windows还会检查头中嵌入的CPU架构信息,确保当前计算机的CPU是符合要求的。最后,Windows的64位版本提供了名位WoW64(Windows on Windows64)的技术,允许运行32位Windows应用程序。该技术甚至允许使用x86本地代码的32位应用程序在在Itanium机器上运行。这是因为WoW64技术能模拟x86指令集,虽然这样做会显著影响性能。

  表1-2总结了这两方面的信息。首先,它总结了为C#编译器指定不同的/platform命令行开关时,会获得哪一种托管模块。其次,它总结了应用程序在不同版本的Windows上如何运行。

   表1-2 /platform开关选项对生成的模块的影响已经在运行时的影响

/platform开关

生成的托管模块

x86 Windows

x64 Windows

IA64 Windows

anycpu(默认)

PE32/不明确指定

作为32位应用程序运行

作为64位应用程序运行

作为64位应用程序运行

x86

PE32/x86

作为32位应用程序运行

作为WoW64应用程序运行

作为WoW64应用程序运行

x64

PE32+/x64

不运行

作为64位应用程序运行

不运行

Itanium

PE32+/Itanium

不运行

不运行

作为64位应用程序运行

  Windows检查好EXE文件头,决定是创建32位、64位还是WoW64进程之后,会在进程的地址空间中加载MSCorEE.dll的x86,x64或IA64版本。如果是Windows的x86版本,MSCorEE.dll的x86版本在C:\Windows\System32目录中。如果是Windows的x64或IA64版本,MSCorEE.dll的x86版本在C:\Windows\SysWow64目录中,64位版本(x64或IA64)则在C:\Windows\System32(为了向后兼容)。然后,进程的主线程调用MSCorEE.dll中定义的一个方法。这个方法初始化CLR,加载EXE程序集,然后调用其入口方法(Main)。随机,托管的应用程序将启用并运行。

注意:在Microsoft C#编译器的1.0或1.1版本所生成的程序集中,包含的是一个PE32头,而且未明确指定CPU架构。但在加载时,CLR认为这些程序集是只用于x86的。对于可执行文件,这增强了应用程序与64位系统的兼容能力,因为可执行文件将在WoW64中加载,为进程和Windows的32位x86版本非常相似的一个环境。

  如果一个非托管应用程序调用LoadLibrary来加载一个托管程序集,Windows会自动加载并初始化CLR(如果尚未加载的话),以便处理程序集中的代码。当然,在这种情况下,进程已经启用并运行了,而这可能限制程序集的可用性。例如,使用/platform:x86开关来编译的一个托管程序集完全没有办法加载到一个64位进程中,而使用同一个开关编译的可执行文件能在64位Windows计算机中作为一个WoW64应用程序运行。

  返回目录页


  注解:

  1、MSCorEE:Microsoft Component Object Execution Engine

  2、Visual Studio 2010正式发布后,Visual Studio团队对新项目的默认设定进行了一处修改。创建一个新的EXE项目时,默认平台是x86(而非anycpu)。这个更改是出于几方面的考虑:支持“编程&继续”,支持IntelliTrace调试,以及在和32位COM组件进行互操作时,让那些组件能正确工作。另外,由于大多数应用程序都不需要一个64位的地址空间,所以默认位x86似乎是一个合理的解决方案(就目前来说)。注意,新DLL项目的默认平台还是anycpu。 

  3、可以在代码中查询Environment的Is64BitOperatingSystem属性,判断是否在Windows的一个64位版本上运行。还可查询Environment的Is64BitProcess属性,判断是否在64位地址空间中运行。