看完點推薦,推薦數目超過100,打包腳本+工具+運行時 所有分享哈。。。。。(無公司爭議,請放心)html
接上一篇前端
【.Net Framework 體積大?】不安裝.net framework 也能運行!?開篇敘述-1node
下一篇編程
【.Net Framework 體積大?】不安裝.net framework 也能運行!?原理補充-3小程序
昨天寫了一個引子,仍是有讀者對這套「小把戲」感興趣。那麼不辜負你們的但願,爭取博主不作太監........設計模式
注意:筆者不想談Link的方式,雖然很爽,可是不靠譜。畢竟解析翻譯到原生的應用,微軟到如今也就敢在Xaml系的應用作嘗試,不知道是微軟的策略,仍是自身都信心不大......api
至於Mono項目,筆者就不說它了,BUG真的多的一個接一個的,甚至2.0都過去了,3.0尚未修復。雖然它能夠支持Link ,mkbundle 工具,可是bug太多,不當心就是一個雷......服務器
開篇先談下原生的應用和虛機應用。架構
Native的程序,大多基於特定的平臺硬件系統的,這裏的系統 咱們就說三大主流系統中的Win/Mac/Linux。硬件部分嘛,主要是CPU的類型...原生應用跟隨操做系統的兼容性,能夠相似插入內存條同樣,直接跟系統集成,運行速度快,處理數據速度效率高。開發語言:C/C++ 彙編?(呵呵,這都上個世紀的東東) 。基於C/C++ 衍生出來 主流的 QT VC .....VC 裏有衍生出個MFC。。。。。。。app
虛機應用,這類應用大可能是基於虛機運行時,也就是將運行時 Run time SDK 安裝到適配的操做系統後,SDK將硬件 操做系統的不一樣 進行了自適應。應用開發者,只須要關注程序的運行效果。就好像坑坑哇哇的石頭牆,摸了一層水泥,而後上面能夠搭載各類形狀的石頭,而不是特定形狀的石頭(去適應石頭縫大小形狀)。特色是:平臺適應強 開發速度快 迭代週期縮短...。開發語言:Python Java .net Framework node.js .......
虛機應用,又各自有各自的特定。有的是基於腳本執行,有的是強類型的編譯執行。不過大同小異。都離不開運行時!!!
其餘語言的運行時,咱們不談,有興趣,本身研究。咱們專門談一下.net 的運行時 .net Framework.
特色:微軟開發,大品牌。體積大,不能說大,簡直是巨大!前面說了,從2.0 的幾十兆 到3.5的幾百兆 到4.0又回到幾十兆(可是安裝速度真慢的要命,由於要先自解壓)。前面說了,十分佩服微軟的 cab 壓縮,愣是把一個幾百兆的.net 4.0 壓縮到了幾十兆!!!4.5 4.6也都是4系列的。主版本號不變,改變次版本號,說明只是基於4的補丁,可是要親命的是 4.5 拋棄了XP!!!!XP 啊,提到XP 就好像前端開發者對着IE6那個時代!!! 雖然痛苦恐怖,可是,XP在國內的使用羣體依然大的離譜。
雖然 Win7普及的效果不錯,可是那畢竟是XP 啊 XP 啊 ............淚奔。
因此,筆者認爲 .net 4到目前爲止 是兼容最全面的Win 系列的系統。對於開發者來講 4版本無疑是一個劃時代的東東,各類應用框架都有,並且性能比3.5好,並且體積小了好多。可是僅僅是相對小了。筆者認爲,它依然巨大。相比較 Python Ruby Node.js Lua的運行時,都小巧,安裝速度快,運行速度也能夠。憑啥.net 這個鬼 體積那麼大!??
實際上是有緣由的。如圖:
C:\WINDOWS\Microsoft.NET
這個基本就是.net 的運行時集中營了(雖然在System目錄也打入了其餘的dll,後面說)
看到這裏,咱們就須要回憶下,.net 的自身的架構
2.0
3.5
4.0
上圖來自:http://www.cnblogs.com/xiaopin/archive/2011/01/07/1929467.html
是否是相似搭積木的方式,一塊塊的耦合上去的?確實,一個完整的.net framework安裝包,須要把整個積木架構搭建起來。可是大多數狀況下,咱們只須要積木的臺子,也就是到 第一個圖中的程序集那一層就完事,有GAC 有運行時 ,就足夠咱們把程序集經過系統引導到 CLR 運行時解析 IL 中間語言到當前平臺的原生代碼,並執行原生代碼。至關於,咱們只須要僱傭一個翻譯,會翻譯其餘語言便可,不必長得高大威猛帥。。。。
那麼咱們能把上面的枝枝葉葉修建掉麼?筆者測試是能夠的。
咱們只須要把GAC 的相關程序集,還有運行時便可。而後就是特定的引導目錄+註冊表。
筆者沒有找到.net 程序引導的順序,不過從筆者實驗的結果來看。微軟打包的程序的時候,給程序集打上了特殊的標識。而後由系統註冊表註冊的特定應用去解析程序集。相似指定默認程序同樣的效果(不知道表述是否正確,歡迎你們指正)。
好,既然是指定的註冊表來註冊引導程序,那麼哪一個纔是The One? 不賣關子,直接給答案!
註冊表:SOFTWARE\Microsoft\.NETFramework\
這個註冊表項,有一個安裝路徑的項,指定到.net的運行時目錄。筆者的機器是64位機器,x86的機器就沒有64.
而後,註冊完路徑後,還有它下面的一個註冊表鍵值對:policy
注意其中的鍵值對:
這個支持策略,相似設計模式中的策略模式。根據特定的場景,使用特定的策略支撐。咱們註冊4.0後,天然也就支持.net 4.0。
好,註冊表關鍵就這2個,接下來還有關鍵的一個步驟,在系統目錄
一個是箭頭指向的dll 還有一個
100那個是4.0的 120那個是筆者安裝了 VC 分佈包的 VC++2013的。咱們須要的是上面的那個哈。。。
好,把這兩個程序集 在特定的機器上,也打入進去後,好,咱們的精簡版本的.net framework就完成了!!
而後,還能夠在運行時程序集 目錄下,裁剪不須要的程序集 好比什麼 exe的小工具啊 WCF 啊 WPF啊什麼的。最終就能夠粗來一個體積小巧,性能不錯,支持.net 4.0的運行時了。
也就是上面的3步走,有興趣本身嘗試,有疑問,請評論留言。筆者不會發布完整的小安裝包。版權的問題很蛋痛 呵呵,Congratulations..............
囉嗦一下,爲何添加註冊表就能訪問策略進行引導,跟.net的歷史有關係吧,由於XP系統上面,就已經集成了1.X的.net framework.後續系統Vista win7 server03 08 等等也同樣。因此,註冊個版本號,也就能夠識別粗來了。。。。。
註冊表獻上:
Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework";Permissions:admins-full; ValueType: string; ValueName: "InstallRoot"; ValueData: "{win}\Microsoft.NET\Framework\";Check:WebServerRuntimeNotInstall
Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework\policy\v4.0";Permissions:admins-full;Check:WebServerRuntimeNotInstall
Root: HKLM; Subkey: "SOFTWARE\Microsoft\.NETFramework\policy\v4.0"; Permissions:admins-full; ValueType: string; ValueName: "30319"; ValueData: "30319-30319";Check:WebServerRuntimeHasNotV4SubKey
不要問我,上面是什麼鬼,inno setup 又是什麼鬼。盡情享用吧.........
---------------------延伸:mscoree.dll-----------------------------
如今作.NET Framework的開發的朋友應該是愈來愈多了,可是可能並不是人人都對MSCOREE.DLL很是瞭解。而事實上,絕不誇張地說,MSCOREE.DLL是.NET Framework中最爲核心的DLL之一,沒有這個DLL,託管程序根本沒法開始執行起來,可是因爲這個DLL藏在System32目錄下,根本無人問津,能夠說是有點委屈了這位.NET Framework中的幕後英雄。本文主要討論MSCOREE.DLL的幾大做用,以及MSCOREE.DLL的兼容性問題。
首先寫一個最最簡單的Hello World程序,用csc編譯(固然你用VS我也沒意見):
public class Program
{
public static void Main(string[] args)
{
System.Console.WriteLine("Hello World!");
}
}
|
C:/Windows/System32> ren mscoree.dll mscoree_.dll |
而後,再把mscoree.dll名字改回去,再次運行A.EXE,此次正確打印出了Hello World。
那麼爲何一旦沒有MSCOREE.DLL,就算是最簡單的Hello World也沒法運行呢?
有在Windows用C/C++編程的朋友們應該熟悉上面那個出錯對話框的意思,這個對話框一般在程序找不到所需的DLL的時候出現。咱們能夠經過運行Visual Studio中自帶的Depends.exe來查看A.EXE的對於DLL的依賴關係:
Microsoft (R) COFF/PE Dumper Version 8.00.50727.762 Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file a.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
3 number of sections
46C83E12 time date stamp Sun Aug 19 20:56:50 2007
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
10E characteristics
Executable
Line numbers stripped
Symbols stripped
32 bit word machine
OPTIONAL HEADER VALUES
10B magic # (PE32)
8.00 linker version
400 size of code
600 size of initialized data
0 size of uninitialized data
23DE entry point (004023DE)
2000 base of code
4000 base of data
400000 image base (00400000 to 00407FFF)
|
0:000> lmm a
start end module name 00de0000 00de8000 a (deferred) |
0:000> u de23de
a+0x23de:
00de23de ff250020de00 jmp dword ptr [a+0x2000 (00de2000)] |
0:000> dds 2000+de0000
00de2000 5b034e50 mscoree!_CorExeMain
|
能夠想象的到,假如你的系統中沒有安裝.NET Framework,那麼執行託管程序也會馬上一樣的對話框。顯然根據這個信息用戶自己很難推斷出發生了什麼問題。一個可行的方案是Windows老是自帶一個MSCOREE.DLL,這個MSCOREE.DLL若是發現沒有.NET Framework則會給出比較清晰的報錯信息。不過因爲從Windows 2003以後(包括Vista)的全部Windows版本都會自帶.Net Framework,那麼這個問題基本上不會出現了。
MSCOREE.DLL有個很是特殊的地方,也就是它位於C:/Windows/System32目錄下,換句話說,無論你的系統上面安裝了多少個不一樣的.NET Framework版本,這個DLL都最多隻可能有2份(32位/64位各一份),而在C:/Windows/Microsoft.NET/Framework 或者C:/Windows/Microsoft.NET/Framework64下面,則會有多份不一樣的.NET Framework同時存在。那麼,這個MSCOREE.DLL又是如何對應不一樣版本的.NET Framework呢?答案很簡單:MSCOREE.DLL經過註冊表信息肯定系統上面安裝的.NET Framework版本號碼,而後根據應用程序自己的所要求的版原本選擇一個合適的.NET Framework版原本執行。真正的工做則是交給實際的某個版本的 .NET的DLL執行,在一般狀況下,這個DLL是Work Station版本的CLR,名爲MSCORWKS.DLL,而服務器版本的CLR則對應MSCORSVR.DLL
MSCOREE.DLL導出了大量的函數,那麼這些函數是否公開而且能夠調用呢?答案是確定的。幾乎全部這些函數在MSDN中均可以查到對應的文檔,而且在.NET Framework SDK的Include目錄中有一個對應的mscoree.h,提供了這些函數的Prototype。應用程序經過這些函數,能夠訪問CLR提供的各項功能,好比:
函數名
|
用途
|
GetCORSystemDirectory
|
得到進程中加載的CLR的安裝目錄
|
GetCORVersion
|
得到進程中加載的CLR的版本西nxi
|
GetFileVersion
|
得到指定文件的CLR版本信息
|
GetRequestedRuntimeInfo
|
得到指定版本CLR的相關信息
|
GetRequestedRuntimeVersion
|
得到應用程序運行所須要的CLR版本信息
|
ClrCreateManagedInstance
|
建立一個.NET對象並返回指定的接口,使用此函數能夠訪問大量的.NET Framework的已有功能
|
CorBindToRuntime
|
加載指定版本CLR
|
CorBindToRuntimeHost
|
在Host中加載指定版本CLR,Hosting時候使用
|
CreateDebuggingInterfaceFromVersion
|
得到對應版本CLR的ICorDebug接口,用於編寫調試器(好比Visual Studio)
|
CorLaunchApplication
|
以指定參數啓動託管程序
|
除此以外還有不少,這裏只是列了一些比較經常使用的功能而已。能夠看到這些功能都很是有用,特別值得提出的是CorBindToRuntimeHost和CreateDebuggingInterfaceFromVersion。前者提供了對CLR各個方面的定製功能,功能很是強大,有興趣的朋友能夠參考MSDN或者Customizing the Common Language Runtime一書。然後者則提供了對託管程序的調試支持,經過ICorDebug接口。
非託管代碼能夠經過COM直接調用.NET的Assembly中的託管對象。如下面這個對象爲例,該對象CLSID爲{0029598F-26Fa-46F7-953B-86E2947AB19F},類型爲Microsoft.SqlServer.Replication.ComErrorRecord,線程模型爲Both,Assembly名稱爲Microsoft.SqlServer.Replication, Version=9.0.242.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91,所需CLR版本爲v2.0.50727 (2.0 RTM)。最值得注意的是,入口點爲mscoree.dll。
除了對用戶自定義的託管對象提供COM支持以外,MSCOREE.DLL本身也支持少許COM對象,所以MSCOREE.dll支持DllGetClassObject, DllRegisterServer, DllUnregisterServer, DllCanUnloadNow這些COM DLL所須要支持的標準函數。
咱們能夠考慮一下,假如咱們如今有了.NET Framework 1.0,而後安裝了.NET Framework 2.0,那麼MSCOREE.DLL會發生變化嗎。答案是可能會,若是到2.0到1.0發生了改變須要修改MSCOREE.DLL(好比多加了一個函數),那麼確定要更新MSCOREE.DLL,可是這個MSCOREE.DLL必須徹底支持全部.NET Framework 1.0中的MSCOREE.DLL中的函數,不然能夠想象全部依賴於這些變化的MSCOREE.DLL中的函數程序都會出錯。所以MSCOREE.DLL必需要作到徹底向前兼容。
再考慮卸載的狀況,假如這個時候.NET Framework 2.0被卸載,那麼MSCOREE.DLL會被還原成.NET Framework 1.0的嗎?此次答案則是不會。由於2.0的MSCOREE.DLL自己支持.NET Framework 1.0,所以無須替換。這樣最爲簡單。
事實上是,CLR Team通常不多改動MSCOREE.DLL,避免出現兼容性問題,所以能夠預見,MSCOREE.DLL將會是.NET Framework/CLR中變化最少的DLL。換句話說,這篇文章的內容,在能夠預見的將來幾個版本基本上不會過期。OK,對於MSCOREE.DLL的討論到這裏就告一段落,有興趣的朋友能夠本身動手寫一些小程序,實際體會一下MSCOREE.DLL所提供的各項功能。
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/deprecated-clr-hosting-functions
https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/cordllmain-function
Initializes the common language runtime (CLR), locates the managed entry point in the DLL assembly's CLR header, and begins execution.
BOOL STDMETHODCALLTYPE _CorDllMain ( [in] HINSTANCE hInst, [in] DWORD dwReason, [in] LPVOID lpReserved );
hInst
[in] The instance handle of the loaded module.
dwReason
[in]Indicates why the DLL entry-point function is being called. This parameter can be one of the following values: DLL_PROCESS_ATTACH, DLL_THREAD_ATTACH, DLL_THREAD_ATTACH, or DLL_PROCESS_DETACH. For descriptions of these values, see the DllMain
documentation in the Platform SDK.
lpReserved
[in] Unused.
This method returns true
for success and false
if an error occurs.
This function is called by the operating system loader for DLL assemblies. For executable assemblies, the loader calls the _CorExeMain function instead.
The operating system loader calls this method regardless of the entry point specified in the DLL file.
In Windows 98, Windows ME, Windows NT, and Windows 2000, the _CorDllMain
function is called indirectly through a fixupin the operating system loader. In all other versions of Windows, it is called directly by the operating system loader.
For additional information, see the Remarks section in the _CorValidateImage topic.
Platforms: See System Requirements.
Header: Cor.h
Library: Included as a resource in MsCorEE.dll
.NET Framework Versions: Available since 1.0
Metadata Global Static Functions
Initializes the common language runtime (CLR), locates the managed entry point in the executable assembly's CLR header, and begins execution.
__int32 STDMETHODCALLTYPE _CorExeMain ();
This function is called by the loader in processes created from managed executable assemblies. For DLL assemblies, the loader calls the _CorDllMain function instead.
The operating system loader calls this method regardless of the entry point specified in the image file.
In Windows 98, Windows ME, Windows NT, and Windows 2000, the _CorExeMain
function is called indirectly through a fixup in the operating system loader. In all other versions of Windows, it is called directly by the operating system loader.
For additional information, see the Remarks section in the _CorValidateImage topic.
Platforms: See System Requirements.
Header: Cor.h
Library: Included as a resource in MsCorEE.dll
.NET Framework Versions: Available since 1.0