DotNET中的幕後英雄:MSCOREE.DLL

如今作.NET Framework的開發的朋友應該是愈來愈多了,可是可能並不是人人都對MSCOREE.DLL很是瞭解。而事實上,絕不誇張地說,MSCOREE.DLL是.NET Framework中最爲核心的DLL之一,沒有這個DLL,託管程序根本沒法開始執行起來,可是因爲這個DLL藏在System32目錄下,根本無人問津,能夠說是有點委屈了這位.NET Framework中的幕後英雄。本文主要討論MSCOREE.DLL的幾大做用,以及MSCOREE.DLL的兼容性問題。編程

MSCOREE是託管程序的入口點
讓咱們來作一個小實驗:

首先寫一個最最簡單的Hello World程序,用csc編譯(固然你用VS我也沒意見):小程序

public class Program
{

       public static void Main(string[] args)服務器

       {

              System.Console.WriteLine("Hello World!");app

       }
}
 
而後,在命令行中鍵入:
 

C:/Windows/System32> ren mscoree.dll mscoree_.dll函數

 
請注意在Vista系統上需提高權限,不然重命名失敗。
以後,運行剛纔編譯出來的EXE程序。Windows直接報錯:

而後,再把mscoree.dll名字改回去,再次運行A.EXE,此次正確打印出了Hello World。spa

那麼爲何一旦沒有MSCOREE.DLL,就算是最簡單的Hello World也沒法運行呢?命令行

有在Windows用C/C++編程的朋友們應該熟悉上面那個出錯對話框的意思,這個對話框一般在程序找不到所需的DLL的時候出現。咱們能夠經過運行Visual Studio中自帶的Depends.exe來查看A.EXE的對於DLL的依賴關係:線程

能夠看到A.EXE只對一個DLL有依賴關係,也就是MSCOREE.DLL。而且A.EXE只用到了MSCOREE.DLL中的一個函數,即_CorExeMain。而MSCOREE.DLL自己卻輸出了137個函數之多。從這個函數的名字你們能夠猜出,這個函數是EXE的一個入口點。爲了證明這一點,咱們能夠用DumpBin看看內容:

Microsoft (R) COFF/PE Dumper Version 8.00.50727.7623d

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)
 
 
注意這個EXE的入口點的RVA是23DE。
再使用Windbg加載A.EXE,使用lmm (list module match)命令查看A.EXE加載的首地址:
 
0:000> lmm a

start    end        module name

00de0000 00de8000   a          (deferred) 

 
 
能夠看到是0x00de0000,那麼再加上23DE這個RVA值,就是程序的入口點。用u命令反彙編看一下:
 
0:000> u de23de
a+0x23de:

00de23de ff250020de00    jmp     dword ptr [a+0x2000 (00de2000)]

 
能夠看到這就是一個簡單的JUMP指令,跳轉到0x00de2000所指向的位置,那麼這個位置是什麼函數呢?咱們能夠經過dds命令查看:
 
0:000> dds 2000+de0000
00de2000 5b034e50 mscoree!_CorExeMain
 
 
到此事實就很是清楚了,任何託管的EXE程序中的入口點都是一條JMP指令直接跳轉到MSCOREE.DLL的_CorExeMain函數執行。而這個_CorExeMain的地址(也就是00de2000所保存的0x5b034e50)則是由OS Loader填入,由於這個位置正是Import Table的位置。
對於一個託管的DLL而言,狀況也很是相似,入口點則是_CorDllMain:

能夠想象的到,假如你的系統中沒有安裝.NET Framework,那麼執行託管程序也會馬上一樣的對話框。顯然根據這個信息用戶自己很難推斷出發生了什麼問題。一個可行的方案是Windows老是自帶一個MSCOREE.DLL,這個MSCOREE.DLL若是發現沒有.NET Framework則會給出比較清晰的報錯信息。不過因爲從Windows 2003以後(包括Vista)的全部Windows版本都會自帶.Net Framework,那麼這個問題基本上不會出現了。

MSCOREE負責選擇.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調用CLR的提供的功能或者定製CLR

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接口。

MSCOREE提供對COM支持

非託管代碼能夠經過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來講,COM只知道CLSID=0029598F-26Fa-46F7-953B-86E2947AB19F}的COM對象位於MSCOREE.DLL中。而事實上,這個類型位於Microsoft.SqlServer.Replication.dll之中,可是COM並不知道,COM只須要知道從MSCOREE.DLL中能夠得到對應的ClassFactory就能夠了,而後COM會經過IClassFactory接口建立這個託管對象的實例,並返回對應的接口。假定一個非託管程序嘗試經過COM建立這樣一個對象,那麼會發生下面這些事情:
1.     程序調用CoCreateInstance通知COM須要建立這樣一個對象,CLSID=0029598F-26Fa-46F7-953B-86E2947AB19F,須要返回IDispatch接口
2.     COM調用CoGetClassObject函數查找對應的入口DLL
3.     COM找到對應的註冊表,發現對應的DLL爲MSCOREE.DLL
4.     COM加載MSCOREE.DLL,調用DllGetClassObject函數,傳入CLSID
5.     MSCOREE.DLL中的DllGetClassObject函數讀入CLSID,找到對應的註冊表,獲取對象的類型名稱,Assembly名稱,CLR版本等信息
6.     DllGetClassObject加載對應版本的CLR
7.     DllGetClassObject返回一個臨時Class Factory對象的IClassFactory接口
8.     COM調用這個Class Factory對象的IClassFactory::CreateInstance方法
9.     這個Class Factory加載對應的CLR,並建立對象,返回一個對象的CCW (Com Callable Wrapper),並該CCW的返回指定的IDispatch接口
能夠看到,這個狀況下起到最關鍵做用的是MSCOREE.DLL所提供的DllGetClassObject函數。

除了對用戶自定義的託管對象提供COM支持以外,MSCOREE.DLL本身也支持少許COM對象,所以MSCOREE.dll支持DllGetClassObject, DllRegisterServer, DllUnregisterServer, DllCanUnloadNow這些COM DLL所須要支持的標準函數。

MSCOREE.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所提供的各項功能。

相關文章
相關標籤/搜索