zoukankan      html  css  js  c++  java
  • 生成、打包、部署和管理应用程序及类型(3):将模块合并成程序集

    Program.exe并非只是含有元数据的PE文件,它还是程序集。程序集是一个或多个类型定义文件及资源文件的集合。在程序集的所有文件中,有一个文件容纳了清单(manifest)。清单也是一个元数据表集合。表中主要包含作为程序集组成部分的那些文件名称。此外,还描述了程序集的版本、语言文化、发布者、公开导出的类型以及构成程序集的所有文件。

    CLR操作的是程序集。也就是说,CLR总是首先加载包含“清单”元数据表的文件,再根据“清单”获取程序集中的其他文件的没名称。程序集的特点如下:

    ●定义了可重用的类型

    ●用一个版本号标记

    ●可以关联安全信息

    这些特点是包含清单的元数据表的文件才具备的。

    使用程序集,可重用类型的逻辑表示和物理表示就可以分开。例如,程序集可能包含多个类型,可以将常用类型放到一个文件中,不常用类型放到另一个文件中。如果程序集要从Internet下载并且部署,那么对于含有不常用类型的文件,加入客户端永远不适用那些类型,该文件就永远不会下载到客户端。

    总结一下使用多文件程序集的理由:

    ●不同的类型用不同的文件,使文件以“增量”下载。另外,将类型划分到不同文件中,可以对购买和安装的应用程序部分或分批打包、部署。

    ●可在程序集中添加资源或数据文件。例如,假定一个类型的作用是计算保险信息,需要访问精度表才能完成计算。在这种情况下,不必在自己的源码中嵌入精度表。相反,可以使用一个工具,使数据文件成为程序集的一部分。BTW,数据文件可以是任意格式,只要程序知道如何解析。

    ●程序集包含的各个类型可以用不同的编程语言来实现。编译不同语言类型的时候会生成不同的模块,然后可以用工具将所有模块合并成单个程序集。

    生成程序集要么选择现有的PE文件作为“清单”的宿主,要么创建单独的PE文件并只在其中包含清单。由于有了清单的存在,程序集的用户不必关心程序集的划分细节。此外,清单也使程序集具有了自描述性。另外,在包含清单的文件中,一些元数据信息描述了哪些文件是程序集的一部分。但是,那些文件本身并不包含元数据来指出他们是程序集的一部分。

     可以通过很多方式将模块添加到程序集。这里使用/addmodule开关。现在有两个源代码:

    Program.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 
     8 namespace Project_1
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             System.Console.WriteLine("HaHa");
    15             Class1 C1 = new Class1();
    16             C1.printHaha();
    17         }
    18     }
    19 }

    Class1.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Project_1
     8 {
     9     public class Class1
    10     {
    11         public void printHaha (){
    12             System.Console.WriteLine("Class1 Haha");
    13         }
    14     }
    15 }

    先将不常用的类型都编译到一个模块:

     

    此时生成一个Class1.netmodule文件。这是一个PE文件,但是不能被CLR加载。

     接着将Program.cs编译到另一个模块。该模块将成为程序集清单的宿主。将该模块命名为MultiFileLibrary.dll:

    上述命令行指示C#编译器编译Program.cs来生成MultiFileLibrary.dll。由于制定了/t:library开关,所以生成的是含有清单元数据表的DLL PE文件。/addmodule:Class1.netmodule 告诉编译器将文件添加到FIleD二分清单源数据表,并将Class1.netmodule的公开导出类型添加到ExportedTypes Def清单元数据表。

    Class1.netmodule文件包含编译Class1.cs所生成的IL代码。该文件还包含一些定义源数据表,描述了Class1.cs定义的类型、方法、字段、属性、事件等。还包含一些引用元数据表,描述了Class1.cs引用的类型、方法等。

    MultiFileLibrary.dll是一个单独的文件。和Class1.netmodule相似,MultiFileLibrary.dll包含编译Program.cs所生成的IL代码以及类似的定义与引用元数据表。此外,MultiFileLibrary.dll还包含额外的清单元数据表,这使得MultiFileLibrary.dll成为程序集。清单元数据表描述了程序集的所有文件(MultiFileLibrary.dll本身和Class1.netmodule)。清单元数据表还包含从Class1.netmodule和MultiFileLibrary.dll导出的所有公共类型。

    可用ILDasm检查元数据清单表(摘取部分):

    File #1 (26000001)
    -------------------------------------------------------
        Token: 0x26000001
        Name : Class1.netmodule
        HashValue Blob : 06 f0 35 e1 e5 70 9e a4  6c 9d 4c dc 6b 40 6f c0  9e b5 09 56 
        Flags : [ContainsMetaData]  (00000000)
    
    
    ExportedType #1 (27000001)
    -------------------------------------------------------
        Token: 0x27000001
        Name: Project_1.Class1
        Implementation token: 0x26000001
        TypeDef token: 0x02000002
        Flags     : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit]  (00100001)
    
    
    User Strings
    -------------------------------------------------------

    从中可以看出,Class1.netmodule文件已经被看成是程序集的一部分。token是0x26000001。在ExportedType 可以看到一个公开导出的类型(只有public会显示在这个数据表中)

    客户端执行代码时会调用方法。一个方法首次被调用时,CLR检测作为参数、返回值或者局部变量而被方法引用的类型。然后,CLR尝试加载所引用程序及中含有的清单文件。如果要访问的类型恰好出现在这个文件中,CLR会执行内部登记工作,允许使用该类型。如果清淡指出被引用的类型在不同文件中,CLR会尝试加载需要的文件,同样执行内部登记,并允许使用该类型。只有在调用方法确实引用了未加载程序集中的类型时,才会加载程序集。

    使用VS IDE将程序集添加到项目中

    这个路径要与生成MultiFileLibrary.dll的路径一致。

    使用程序集链接器

    除了使用C#编译器,还可以使用“程序集链接器”实用程序AL.exe来创建程序集。如果程序集要包含由不同编译器生成的模块,或者生成时不清楚程序集的打包要求,程序集链接器就显得相当有用。还可以使用AL.exe生成只含资源的程序集,也就是附属程序集,通常用于本地化。

    首先,有三个源代码:

    Program.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Project_1
     8 {
     9     public class Program
    10     {
    11         public static void Main(string[] args)
    12         {
    13             System.Console.WriteLine("HaHa");
    14             Class1 C1 = new Class1();
    15             C1.printHaha();
    16             Class2 C2 = new Class2();
    17             C2.printHaha();
    18         }
    19     }
    20 }

    Class1.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Project_1
     8 {
     9     public class Class1
    10     {
    11         public void printHaha (){
    12             System.Console.WriteLine("Class1 Haha");
    13         }
    14     }
    15 }

    Class2.cs:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Project_1
    {
        public class Class2
        {
            public void printHaha()
            {
                System.Console.WriteLine("Class2 Haha");
            }
        }
    }

    为了理解AL.exe的工作原理,先改变MultiFileLibrary.dll的生成方式:

     生成MultiFileLibrary.dll:

    指定入口并得到EXE PE文件:

    (这里在操作的时候,出现了一个问题:指定main函数的时候报错“找不到Program.main”,后来才发现原因有两个:第一个是没有加命名空间Project_1,以及代码中main函数没有写错public,当然现在都加上了。需要指定作用域是因为程序集有可能有多个作用域,所以要指定是哪个作用域下的。但是public这个到现在都没有搞清楚具体原因,不知道有没有懂的大佬解释一下,我只知道和.exe的执行过程有关,但是main是在哪里发生了“外部调用”这个具体的过程还有些模糊)

    可以执行Program.exe:

    为程序集添加资源文件:

    AL.exe创建程序集时,可以用/embed将文件作为资源添加到程序集。该开关获取任意文件,并将文件内容嵌入最终的PE文件。清单中的ManifestResourceDef表会更新以反映资源的存在。

    与AL.exe相似,C#编译器CSC.exe也允许将资源合并到编译器生成的程序集中。/resource开关将指定的资源文件嵌入最终生成的程序集PE中,并更新ManifestResourceDef表。/linkresource开关ManifestResourceDef和FileDef清单表中添加记录项来引用独立存在的资源文件。

  • 相关阅读:
    【转载】 KL距离(相对熵)
    HTML5动画软件工具编辑器 HTML5动画分类 工具推荐
    Flash Actionscript AS3 渐变透明 mask遮罩
    HTML动画分类 HTML5动画 SVG库 SVG工具 Canvas动画工具
    Flash:彻底理解crossdomain.xml、跨swf调用。
    Flash: Event.PASTE Flash获取剪贴板内容 触发paste事件 how to get paste event
    Flash:TextField字体不显示/文字不显示/文字丢失
    Flash 矢量图和位图性能对比 导出为位图/缓存为位图 export as bitmap / cache as bitmap
    验证码去噪 分离背景 分离文字 最大类间方差
    Flash XSS 漏洞详解 根治的好办法
  • 原文地址:https://www.cnblogs.com/renzhoushan/p/10366289.html
Copyright © 2011-2022 走看看