首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

11.2  .NET程序集的格式

我们已经知道了.NET程序集所带来的好处,现在进一步深入程序集的内部结构。从结构上看,一个.NET程序集(*.dll或者*.exe)包含以下几个部分:

l    Win32文件首部

l    CLR文件首部

l    CIL代码

l    类型元数据

l    程序集清单

l    可选的嵌入资源

文本框:  
图11-1  一个程序集的Win32文件首部信息


通常头两个部分(Win32文件首部和CLR文件首部)容易被忽视,但其实它们是值得简要了解一下的。下面来逐个讲解。

11.2.1  Win32文件首部

Win32文件首部使程序集可以被Windows系列操作系统加载和操作。这些首部信息标识了应用程序将以什么类型(是基于控制台、基于图形界面还是*.dll代码库)驻留于Windows操作系统中。使用dumpbin.exe工具(通过.NET Framework 2.0 SDK命令提示符)结合/headers标记打开一个.NET程序集,我们可以浏览该程序集的Win32文件首部信息。图11-1展示了CarLibrary.dll程序集的部分Win32首部信息,该程序集将在本章的后面创建。

11.2.2  CLR文件首部

为了驻留于CLR中,所有的.NET文件都必须含有CLR首部数据块。简单地讲,CLR文件首部定义了多个标记,它们使得运行库可以了解到托管文件的布局。例如,这些标记标识了文件中元数据和资源的位置、程序集构建的运行库版本、(可选的)公钥值等。使用dumpbin.exe工具结合/clrheader标记打开一个.NET程序集,我们就可以浏览该程序集内部的CLR首部信息,如图11-2所示。

11-2  一个程序集CLR文件首部信息

CLR头数据以非托管C语言形式的结构体(IMAGE_COR20_HEADER)方式被定义在名为corhdr.h的基于C的头文件中。如果对此感兴趣,请看下面结构体的布局。

 

// CLR 2.0 首部结构。

typedef struct IMAGE_COR20_HEADER

{

    // 首部版本(Header versioning)。

  ULONG    cb;             

  USHORT   MajorRuntimeVersion;

  USHORT   MinorRuntimeVersion;

 

    // 符号表和启动信息。

  IMAGE_DATA_DIRECTORY    MetaData;       

  ULONG     Flags;          

  ULONG     EntryPointToken;

 

    // 绑定信息。

  IMAGE_DATA_DIRECTORY    Resources;

  IMAGE_DATA_DIRECTORY    StrongNameSignature;

 

    // 一般的固定信息和绑定信息。

  IMAGE_DATA_DIRECTORY    CodeManagerTable;

  IMAGE_DATA_DIRECTORY    VTableFixups;

  IMAGE_DATA_DIRECTORY    ExportAddressTableJumps;

 

    // 预编译的影像数据(只供内部使用,设为0)。

  IMAGE_DATA_DIRECTORY    ManagedNativeHeader;

} IMAGE_COR20_HEADER;

 

重申一点,作为.NET开发人员,我们并不需要关心Win32首部信息和CLR首部信息的具体细节(除非你需要编写一个新的托管编译器)。只需知道每一个.NET程序集都必须包含这些数据,它们会被.NET运行库和Win32操作系统所使用。

11.2.3  CIL代码、类型元数据和程序集清单

程序集的核心部分包含CIL代码,这些CIL代码是独立于平台和CPU的中间语言。在运行时,程序集内部的CIL代码才被(实时的JIT编译器)编译成特定平台和CPU的指令。在这种机制下,.NET程序集可以在多种不同的架构、设备和操作系统下运行。虽然可以完全不去了解CIL编程语言的细节,但是在第15章还是对其语法和语义进行了介绍。

程序集还包含元数据,这些元数据完整地描述了程序集内含类型和引用外部类型的格式。.NET运行库利用元数据在内存的二进制布局类型中解析类型(以及类型的成员)的位置,使远程方法调用更便利。在第12章探讨反射服务的时候,将会详细讲述.NET元数据的格式。

另外,程序集必须被关联上一个清单manifest也称程序集元数据)。该清单详细记录了程序集中的每一个模块、构建程序集的版本以及该程序集引用的所有外部程序集(在以往的COM类型库中并不记录这些外部依赖关系)。在本章中,我们将会看到CLR广泛地使用程序集的清单来定位外部程序集引用。

注解    如果想要查看一个程序集的CIL代码、类型元数据或者清单,ildasm.exe工具将会是不二之选。在完成本章所有代码示例的过程中,我们离不开它。

11.2.4  可选的程序集资源

最后,.NET程序集还可以包含一些嵌入资源,如应用程序图标、图像文件、声音片段或者字符串表。事实上,.NET平台支持附属程序集satellite assemblies),这些程序集只包含本地化资源。在构建国际化软件系统的时候,我们可能想基于特定区域(英语、德语等)来对资源进行分类打包,这时候附属程序集就显得非常有用。附属程序集不是本书要讨论的话题,但在第20GDI+部分,我们将介绍如何把应用程序资源嵌入到程序集里面。

11.2.5  单文件程序集和多文件程序集

从技术角度上说,程序集可以由多个模块组成。实际上,模块这个术语一般用于表示一个合法的.NET二进制文件。在大多数情况下,程序集只由一个模块组成。这种情况下,(逻辑)程序集和实际的(物理)二进制文件是一一对应的(因此被称作单文件程序集)。

单文件程序集的所有必要的部分(首部信息、CIL代码、类型元数据、清单和必需的资源)都包含在一个*.exe或者*.dll包中。图11-3展示了一个单文件程序集的组成。

另一方面,多文件程序集是一个.NET *.dll的集合,这些DLL作为单个逻辑单元进行部署和版本化。通常,其中的一个会作为主模块,它将包含程序集级别的清单(以及必要的CIL代码、元数据、头信息和可选资源)。主模块的清单记录了它依赖的每一个*.dll文件。

根据命名习惯,多文件程序集的辅助模块的文件扩展名一般是*.netmodule,但这不并是CLR的强制要求。辅助模块*.netmodules也包含CIL代码和类型元数据,同时还有一个模块级别的清单,该清单只记录了该模块外部引用的程序集。

多文件程序集的主要优点是:提高了程序下载的效率。例如,假设有一个客户端引用了远程的一个多文件程序集(包含3个模块),其中的主模块已经安装在客户端。如果客户端需要使用远程*.netmodule中的类型的话,那么CLR将会按需(仅当要使用时)把二进制模块下载到本地的下载缓存download cache)中。如果每一个*.netmodule模块大小是1MB的话,那么好处显而易见。

多文件程序集的另外一个优点是:允许模块由不同的.NET编程语言进行编写(这一点对大型软件公司非常有用,因为每一个部门都可以使用自己喜欢的.NET语言)。一旦每一个独立的模块被编译好,我们可以使用诸如程序集连接器(al.exe)这样的工具把所有的模块连接成一个逻辑程序集。

无论如何,请记住:组成一个多文件程序集的模块并没有相互连接成一个大文件,相反,它们只是依靠在主模块清单中记录的信息逻辑地连接在一起。图11-4展示了一个包含3个模块的多文件程序集,其中每一个模块都使用不同的.NET编程语言来编写。

类型元数据

 

单文件程序集

CarLibrary.dll

 

CIL代码

 

(选项)资源

 

清单

 

CsharpCarLib.dll

 

PascalCarLib.netmodule

 

VbNetCarLib.netmodule

 

多文件程序集

 

CompanyLogo.bmp

 

CIL代码

 

CIL代码

 

类型元数据

 

CIL代码

 

类型元数据

 

清单

(引用其他相关文件)

 

Type Metadata

 

11-3  单文件程序集

11-4  主模块在程序集清单中记录了所需的辅助模块

到这里,希望读者已经对.NET二进制文件的内部组成有了一个更好的理解。在这些必要的前言介绍之后,我们将进入实际的构建和配置代码库的环节。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论