CLR via C#:生成,打包,部署和管理應用程序和類型

PE文件結構:PE文件也叫做可移植執行體文件,其結構如下所示:
1.PE文件由程序集組成。
2.程序集由託管模塊和資源文件以及元數據清單表組成。
3.託管模塊由PE32或者PE32+頭,CLR頭,元數據,IL組成。
4.PE32或者PE32+頭是windows要求的標準信息。負責創建對應位數的進程,並在進程中加載MSCorEE.dll。
5.CLR頭是由CorHdr.h中定義的IMAGE_COR20_HEADER結構體組成。負責由MSCorEE.dll初始化CLR。
6.元數據是由元數據定義表和元數據引用表組成。負責描述託管模塊中定義了什麼以及引用了什麼。
7.IL是由編譯器將源碼編譯成的中間語言代碼,運行時由CLR編譯成機器碼。
8.元數據清單表描述了程序集的版本信息以及有哪些文件,導出了哪些公有類型等。

PE文件類型:PE文件可以是DLL,EXE,netmodule。類型區別如下所示:
1.netmodule的PE文件不包含元數據清單表,通常被添加到其他的程序集中。
2.EXE的PE文件必須包含主入口。

元數據特性:如下所示:
1.元數據定義表用來記錄託管模塊中定義的數據信息。常用的定義表如下所示:

名稱 說明
ModuleDef 模塊定義表。該表會爲託管模塊生成一條記錄項。記錄項中包含託管模塊的文件名和擴展名以及模塊版本標識
TypeDef 類型定義表。託管模塊中的每一個類型在該表中都有一條記錄項。每條記錄項中包含類型的名稱,基類型,標誌 (如:訪問權限)以及一些索引值(如:方法,屬性,字段,事件等地方使用該類型的索引值)
MethodDef 方法定義表。託管模塊中的每一個方法在該表中都有一條記錄項。每條記錄項中包含方法的名稱,標誌 (如:訪問權限),簽名(參數(參數定義表中的記錄項)和返回類型)以及方法對應的IL在託管模塊中的偏移值
FieldDef 字段定義表。託管模塊中的每一個字段在該表中都有一條記錄項。每條記錄項中包含字段的名稱,類型和標誌 (如:訪問權限)
ParamDef 參數定義表。託管模塊中的每一個參數在該表中都有一條記錄項。每條記錄項中包含參數的標誌(如:in,out,retval),類型和名稱
PropertyDef 屬性定義表。託管模塊中的每一個屬性在該表中都有一條記錄項。每條記錄項中包含屬性的標誌(如:訪問權限),類型和名稱
EventDef 事件定義表。託管模塊中的每一個事件在該表中都有一條記錄項。每條記錄項中包含事件的標誌(如:訪問權限)和名稱

2.元數據引用表用來記錄託管模塊中引用的數據信息。常用的引用表如下所示:

名稱 說明
AssemblyRef 程序集引用表。託管模塊中引用的每一個程序集在該表中都有一條記錄項。每條記錄項中包含程序集的名稱,版本號,語言文化,公鑰,標誌以及校驗哈希值
ModuleRef 模塊引用表。託管模塊中引用的每一個其他託管模塊在該表中都有一條記錄項。每條記錄項中包含引用託管模塊的文件名和擴展名
TypeRef 類型引用表。託管模塊中引用的每一個類型在該表中都有一條記錄項。每條記錄項中包含類型的名稱和指向類型位置的引用(引用的類型在不同程序集中實現時,引用就等於程序集引用表記錄項;引用的類型在不同類型中實現時,引用就等於類型引用表記錄項;其他情況下引用就等於模塊引用表記錄項。)
MemberRef 成員引用表。託管模塊中引用的每一個成員(字段和方法)在該表中都有一條記錄項。每條記錄項中包含成員的名稱和簽名以及類型引用表記錄項

3.元數據清單表用來記錄程序集中文件集的表。常用的清單表如下所示:

名稱 說明
Assembly 程序集清單表。該表會爲程序集生成一條記錄項。記錄項中包含程序集的名稱,版本號,語言文化,公鑰,標誌以及校驗哈希值
File 文件清單表。除了文件清單表外,其他的資源文件和託管模塊中的文件在該表中都有一條記錄項。每條記錄項中包含文件名和擴展名,哈希值和一些標誌。
ManifestResource 資源清單表。程序集中的每一個資源在該表中都有一條記錄項。每條記錄項中包含資源名稱,一些標誌(如:訪問權限),以及文件清單表中該資源文件的索引或者程序集中該資源流的偏移位置。
ExportedType 導出類型清單表。程序集中導出的每一個公有類型在該表中都有一條記錄項。每條記錄項中包含類型名稱,文件清單表中的索引(類型在哪個文件中定義)以及類型定義表中的索引(具體類型定義信息)。

4.元數據token是一個四字節的值。其中高位字節是由CorHdr.h文件中的CorTokenType枚舉指明的元數據表類型;低位三字節指明對應元數據表中的行。

編譯&鏈接PE文件:如下所示:
1.net framework在安裝時,會在%SystemRoot%\MicroSoft.NET\Framework(64)\vX.X.X目錄下生成csc.exe和csc.rsp文件。這些文件的描述如下所示:
1>.csc.exe是編譯器執行文件,負責將c#源文件編譯成程序集,並由該程序集來生成PE文件。常見的編譯參數如下表所示:

參數 描述
/out PE文件名。如:源文件名.exe,源文件名.dll
/t PE文件類型。如:exe(控制檯程序),library(動態鏈接庫),winexe(圖形程序), appcontainerexe(windows store程序) ,module(生成的PE文件不包含元數據清單表且後綴名爲.netmodule)
/r 引用程序集,如:mscorlib.dll(包含所有核心類型動態鏈接庫)。csc.exe會嘗試在以下目錄查找程序集:1.指定的文件名是否爲完整路徑;2.工作目錄;3.csc.exe所在的目錄(包含CLR的各種DLL文件);4.使用/lib編譯器開關指定的任何目錄;5.使用LIB環境變量指定的任何目錄。
/nostdlib 不自動引用標準動態鏈接庫
/noconfig 忽略全局和本地響應文件
/addmodule 將PE文件(如.netmodule後綴的文件)添加到程序集。編譯器會將該PE文件添加到程序集的文件清單表以及把該PE文件中公共導出類型添加到導出類型清單表。
/resource 將資源文件嵌入到程序集中,並在資源清單表中添加該資源記錄項信息。
/linkresource 在資源清單表和文件清單表中添加該資源記錄項信息。不必將資源文件嵌入到程序集中,因爲通過該資源在文件清單表的記錄項就可以知道位置信息。
/win32icon 將資源類型爲ico的文件嵌入到程序集中。
/win32res 將資源類型爲res的文件嵌入到程序集中。
/nowin32manifest 不生成win32資源清單表。
/keyfile 使用簽名文件中的私鑰對程序集進行簽名並將簽名文件中的公鑰寫入到元數據清單表中。
/keycontainer 使用CSP容器中的簽名文件中的私鑰對程序集進行簽名並將簽名文件中的公鑰寫入到元數據清單表中。
/delaysign 使用延遲簽名技術。

2>.csc.rsp是全局響應文件,負責將編譯參數傳遞給csc.exe。當csc.exe在執行編譯操作時會優先查找全局的csc.rsp響應文件;然後再查找編譯命令中@後面的本地響應文件;最後將兩個響應文件的編譯參數進行合併,如果有相同的編譯參數時就以本地響應文件的配置爲準。

2.net framework在安裝時,會在C:\Program Files(x86)\MicroSoft SDKs\Windows\vX.X\bin\NETFX X.X.X Tools目錄下生成al.exe文件。該文件就是用來將託管模塊和資源文件鏈接成程序集,並由該程序集來生成PE文件。具有以下特性:
1>.只對資源文件進行鏈接生成的程序集叫做附屬程序集,通常用於本地化。

2>.常見的鏈接參數如下表所示:

參數 描述
/out PE文件名。如:源文件名.exe,源文件名.dll
/t PE文件類型。如:exe(控制檯程序),library(動態鏈接庫),winexe(圖形程序), appcontainerexe(windows store程序)
/main 在生成exe的PE文件時,需要指定主入口函數
/embed 將資源文件嵌入到程序集中,並在資源清單表中添加該資源記錄項信息。
/link 在資源清單表和文件清單表中添加該資源記錄項信息。不必將資源文件嵌入到程序集中,因爲通過該資源在文件清單表的記錄項就可以知道位置信息。
/win32icon 將資源類型爲ico的文件嵌入到程序集中。
/win32res 將資源類型爲res的文件嵌入到程序集中。
/algid 將文件名加入到字段定義表中時使用的哈希算法,默認是SHA-1。當然也可以使用AlgorithmIdAttribute定製特性來進行設置。
/keyfile 使用簽名文件中的私鑰對程序集進行簽名並將簽名文件中的公鑰寫入到元數據清單表中。
/keyname 使用CSP容器中的簽名文件中的私鑰對程序集進行簽名並將簽名文件中的公鑰寫入到元數據清單表中。
/delay[sign] 使用延遲簽名技術。

程序集特性:如下所示:
1.程序集的版本資源字段可以使用AL.exe的命令開關(如:/version:“3.0.0.0”)來進行設置,也可以在源文中使用定製特性(如:[assembly: AssemblyFileVersion(“3.0.0.0”)])進行設置。對應關係如下表所示:

版本資源字段 AL.exe命令開關 定製特性或者說明
FILEVERSION /fileversion System.Reflection.AssemblyFileVersionAttribute
PRODUCTVERSION /productversion System.Reflection.AssemblyInformationalVersionAttribute
FILEFLAGSMASK 總是設爲VS_FFI_FILEFLAGSMASK,其值爲WinVer.h中定義的0x0000003F
FILEFLAGS 總是設爲0
FILEOS 總是設爲VOS_WINDOWS32
FILETYPE /target 如果指定了/target:exe或者/target:winexe,就設置爲VFT_APP;如果指定了/target:library,就設置爲VFT_DLL
FILESUBTYPE 總是設爲VFT2_UNKNOWN
AssemblyVersion /version System.Reflection.AssemblyVersionAttribute
Comments /description System.Reflection.AssemblyDescriptionAttribute
CompanyName /company System.Reflection.AssemblyCompanyAttribute
FileDescription /title System.Reflection.AssemblyTitleAttribute
FileVersion /version System.Reflection.AssemblyFileVersionAttribute
InternalName /out 無擴展名的輸出文件名稱
LegalCopyright /copyright System.Reflection.AssemblyCopyrightAttribute
LegalTrademarks /trademark System.Reflection.AssemblyTrademarkAttribute
OriginalFilename /out 無路徑的輸出文件名稱
PrivateBuild 總是空白
ProductName /product System.Reflection.AssemblyProductAttribute
ProductVersion /productversion System.Reflection.AssemblyInformationalVersionAttribute
SpecialBuild 總是空白

2.程序集版本號格式爲"major(主版本號).minor(次版本號).build(內部版本號).revision(修訂號)",且存在三種版本號,分別如下所示:
1>.AssemblyFileVersion存儲在win32資源文件中。
2>.AssemblyInformationalVersion存儲在win32資源文件中,主要用來指出包含該程序集的產品的版本。
3>.AssemblyVersion存儲在元數據定義表中,主要用來唯一性的標識程序集。

3.程序集語言文化是由主標記和副標記組成。如下表所示:

主標記 副標記 語言文化
de 德語
de AT 奧地利德語
de CH 瑞士德語
en 英語
en GB 英國英語
en US 美國英語

其中指定語言文化的程序集叫做附屬程序集,而未指定語言文化的程序集叫做語言文化中性。通常使用AL.exe的/c[ulture]:text(就是主標記-副標記字符串,如:en-US)命令或者[assembly:AssemblyCulture(主標記-副標記字符串,如:en-US)]定製特性來生成附屬程序集。一般而言也不要引用附屬程序集,而是通過反射技術來加載附屬程序集。

4.部署程序集時通常有以下方案:
1>.使用vs生成.appx文件併發布到windows store上;然後下載安裝時會將.appx的所有程序集存放在對應的的版本號目錄中。
2>.使用vs生成msi文件併發布到網站,FTP服務器等地方;然後下載安裝時會按需安裝並且利用clickonce技術自動檢查更新等。
3>.使用side-load技術或者批處理文件將所有程序集文件安裝到設備上。

5.CLR查找語言文化中性的程序集流程如下:
1>.首先在應用程序根目錄下查找程序集。
2>.然後在跟程序集同名的應用程序子目錄中查找程序集。
3>.最後在配置文件(xxx.config文件)中的probing元素的privatepath屬性值(用分號分割的相對於應用程序根目錄的路徑名)下面進行查找。其中exe的配置文件爲"exe文件全名.config"並存儲在應用程序根目錄中,而web的配置文件爲Web.config並存儲在Web應用程序虛擬根目錄中。
4>.從頭開始查找同名的其他類型程序集。
5>.找不到就拋出FileNotFoundException異常。

6.CLR查找附屬程序集流程如下:
1>.首先在應用程序根目錄/主標記-副標記目錄下查找程序集。
2>.然後在跟程序集同名的主標記-副標記/應用程序子目錄中查找程序集。
3>.最後在配置文件(xxx.config文件)中的probing元素的privatepath屬性值(用分號分割的相對於應用程序根目錄的路徑名)/主標記-副標記目錄下面進行查找。其中exe的配置文件爲"exe文件全名.config"並存儲在應用程序根目錄中,而web的配置文件爲Web.config並存儲在Web應用程序虛擬根目錄中。
4>.從頭開始查找同名的其他類型程序集。
5>.從頭開始將上述步驟中的主標記-副標記換成主標記來查找程序集。
6>.找不到就拋出FileNotFoundException異常。

7.在編譯程序集時需要程序集和引用程序集的文件清單表中的所有文件都存在,否則就會編譯不過。

8.在加載程序集中的一個文件時,CLR檢查設備的下載緩存中存在該文件時就直接加載該文件;否則就從程序集配置文件中的codeBase元素中指定的URL下載該文件並存儲在設備的下載緩存中,然後加載該文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章