.Net CLR Hosting原理及實(shí)踐
在開(kāi)發(fā)CLR的時(shí)候,MS實(shí)際上是將CLR相關(guān)的功能作為一個(gè)COM服務(wù)實(shí)現(xiàn)在一個(gè)DLL里面。對(duì)這個(gè)DLL的選擇,是由墊片來(lái)選擇的。
MS為CLR定義了一個(gè)標(biāo)準(zhǔn)的COM接口,并且為該接口和COM服務(wù)指定了GUID。
雖然沒(méi)有墊片mscoree.dll的實(shí)現(xiàn)代碼,但是咱可以看看頭文件….
在MSCorEE頭文件里面,定義了一些GUID和非托管的最重要的ICorRuntimeHost接口。
任何windows應(yīng)用程序,都可以編程實(shí)現(xiàn)hosting CLR,可以調(diào)用MSCorEE里面的CorBindToRuntime方法來(lái)實(shí)現(xiàn)寄宿托管程序。在寄宿托管程序的時(shí)候,process里面眾多的thread只有兩種可以執(zhí)行托管代碼:
HRESULT CorBindToRuntimeEx (
LPWSTR pwszVersion,
LPWSTR pwszBuildFlavor,
DWORD flags,
REFCLSID rclsid,
REFIID riid,
LPVOID* ppv
);
調(diào)用上面的這個(gè)函數(shù)的時(shí)候,這個(gè)函數(shù)允許指定期望加載的CLR的版本(pwszVersion,Null表示希望加載最新版本的CLR),加載服務(wù)器版本的ee還是工作站版本的ee,控制執(zhí)行是并發(fā)垃圾回收還是非并發(fā)的垃圾回收,控制程序集是否以非特定與域的方式進(jìn)行加載。
最后一個(gè)參數(shù)的含義,是獲取一個(gè)接口的指針,該指針可以指向其它設(shè)置選項(xiàng)的ICorRuntimeHost。這些選項(xiàng),允許在宿主啟動(dòng)之前對(duì)他們進(jìn)行配置。
ICorRuntimeHost是hosting APIs里面的一個(gè)初始化COM interface。之所以說(shuō)是初始化的COM interface,是因?yàn)檫@個(gè)接口,是在hosting CLR的時(shí)候需要用到的第一個(gè)接口。
在MSCorEE.h中,找到了ICorRuntimeHost的定義和主要功能:
MIDL_INTERFACE("90F1A06C-7712-4762-86B5-7A5EBA6BDB02")
ICLRRuntimeHost : public IUnknown
{
public
//Start and Stop the CLR run in a Process
virtual HRESULT STDMETHODCALLTYPE Start( void) = 0;
virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
virtual HRESULT STDMETHODCALLTYPE SetHostControl(
/* [in] */ IHostControl *pHostControl) = 0;
//CLR Host用來(lái)獲取CLR實(shí)現(xiàn)了哪些寄宿的應(yīng)用程序接口。
virtual HRESULT STDMETHODCALLTYPE GetCLRControl(
/* [out] */ ICLRControl **pCLRControl) = 0;
//從一個(gè)Process里面卸載一個(gè)AppDomain
virtual HRESULT STDMETHODCALLTYPE UnloadAppDomain(
/* [in] */ DWORD dwAppDomainId,
/* [in] */ BOOL fWaitUntilDone) = 0;
//在一個(gè)特定的應(yīng)用程序域里面執(zhí)行一個(gè)回調(diào)函數(shù)。
virtual HRESULT STDMETHODCALLTYPE ExecuteInAppDomain(
/* [in] */ DWORD dwAppDomainId,
/* [in] */ FExecuteInAppDomainCallback pCallback,
/* [in] */ void *cookie) = 0;
//返回給當(dāng)前Calling Thread某個(gè)特定的應(yīng)用程序域的獨(dú)一無(wú)二的Domain Id
virtual HRESULT STDMETHODCALLTYPE GetCurrentAppDomainId(
/* [out] */ DWORD *pdwAppDomainId) = 0;
//執(zhí)行一個(gè)由外部的Manifest定義的一個(gè)標(biāo)準(zhǔn)的2.0里面的Applicaiton
virtual HRESULT STDMETHODCALLTYPE ExecuteApplication(
/* [in] */ LPCWSTR pwzAppFullName,
/* [in] */ DWORD dwManifestPaths,
/* [in] */ LPCWSTR *ppwzManifestPaths,
/* [in] */ DWORD dwActivationData,
/* [in] */ LPCWSTR *ppwzActivationData,
/* [out] */ int *pReturnValue) = 0;
//在默認(rèn)的應(yīng)用程序域里面執(zhí)行一個(gè)特定的方法。這個(gè)方法,對(duì)于只有一個(gè)AppDomian的CLR Host來(lái)說(shuō)比較的方便。
virtual HRESULT STDMETHODCALLTYPE ExecuteInDefaultAppDomain(
/* [in] */ LPCWSTR pwzAssemblyPath,
/* [in] */ LPCWSTR pwzTypeName,
/* [in] */ LPCWSTR pwzMethodName,
/* [in] */ LPCWSTR pwzArgument,
/* [out] */ DWORD *pReturnValue) = 0;
};
這里,返回了這個(gè)接口之后,如何使用CLR提供的一系列功能呢?這里就涉及到一個(gè)非常重要的概念:Hosting Manager。
關(guān)于這方面的資料,說(shuō)實(shí)話見(jiàn)到的不多,大多在一些msdn blogs的隱蔽的角落里面。中文方面,比較好的有一篇臺(tái)灣的蔡學(xué)鏞的大內(nèi)高手專(zhuān)欄中的.NET CLR Hosting 簡(jiǎn)介,還有就是filer和MS的zhangyi在blog上面也介紹過(guò)。
Hosting Manager是干嘛的呢?簡(jiǎn)單的來(lái)說(shuō),就是把一系列的CLR提供的功能組織到一起。把他們組織成為一個(gè)邏輯功能的邏輯組合。
在所有的CLR Hosting APIs里面提供的功能,主要包括:CLR的啟動(dòng)和關(guān)閉,App Domain相關(guān),自定義錯(cuò)誤處理,編程模型的執(zhí)行,對(duì)調(diào)試器的支持,Assembly的Load相關(guān),CLR的內(nèi)部事件,CLR Engine相關(guān),內(nèi)存管理和垃圾回收,Threading,同步,I/O的支持等。
這里,copy一個(gè)提供了CLR的各個(gè)功能的接口層次結(jié)構(gòu)圖:

和這個(gè)接口的層次圖對(duì)應(yīng)的,是功能的層次結(jié)構(gòu)圖:

這里,才回頭到最上面ICLRRuntimeHost接口的定義里面的:
virtual HRESULT STDMETHODCALLTYPE SetHostControl
virtual HRESULT STDMETHODCALLTYPE GetCLRControl
這里的兩個(gè)部分,就是把控制權(quán)交給了CLR,但是根據(jù)不同的功能到底是哪一部分實(shí)現(xiàn)的,是CLR實(shí)現(xiàn)的,還是Host實(shí)現(xiàn)的進(jìn)行了選擇。而在有的地方說(shuō)的,在托管程序加載了CLR之后,就將控制權(quán)交給了CLR,指的起始就是SetCLRControl。
舉一個(gè)簡(jiǎn)單的例子,就說(shuō)IHostContrl里面的Assembly Loading這個(gè)功能的實(shí)現(xiàn)。這個(gè)功能的實(shí)現(xiàn),是由宿主來(lái)實(shí)現(xiàn)的。其功能,都可以通過(guò)調(diào)用IHostAssemblyManager這個(gè)基本接口來(lái)實(shí)現(xiàn):
MIDL_INTERFACE("613dabd7-62b2-493e-9e65-c1e32a1e0c5e")
IHostAssemblyManager : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetNonHostStoreAssemblies(
/* [out] */ ICLRAssemblyReferenceList **ppReferenceList) = 0;
virtual HRESULT STDMETHODCALLTYPE GetAssemblyStore(
/* [out] */ IHostAssemblyStore **ppAssemblyStore) = 0;
};
另外有一點(diǎn)需要特別指明一下,如果某一個(gè)特定的功能,是由CLR來(lái)實(shí)現(xiàn)的,調(diào)用這個(gè)功能的相應(yīng)的接口就用ICLR來(lái)開(kāi)頭,如果這個(gè)功能是Host實(shí)現(xiàn)的,就調(diào)用IHost開(kāi)頭的接口定義的函數(shù)。
我們通常說(shuō)sql server提供了對(duì)DotNet的支持,其實(shí)就是它實(shí)現(xiàn)了這些功能接口的功能,可以直接在CLR中調(diào)用相關(guān)的功能。
IHostAssemblyManager實(shí)現(xiàn)了了對(duì)Assembly Load功能,同時(shí)還有三個(gè)另外的接口也實(shí)現(xiàn)了Assembly Load相關(guān)的功能:IHostAssemblyStore ,ICLRAssemblyReferenceList,
ICLRAssemblyIdentityManager。他們都提供了不同的功能,分別有CLR和Host來(lái)實(shí)現(xiàn)。
恩,介紹到這個(gè)地方,基本上CLR Hosting的原理和它的一套方法,都說(shuō)清楚了。接下來(lái),看看一個(gè)如何調(diào)用CLR功能的一個(gè)例子。
下面展示一下如何采用一個(gè)非托管的宿主來(lái)加載CLR并且執(zhí)行里面的一些代碼。
首先,在非托管宿主里面加載CLR并且啟動(dòng):
ICLRRuntimeHost *pCLRHost = NULL;
HRESULT hr = CorBindToRuntimeEx(
L"v2.0.40103", //需要加載的CLR版本,Null表示最新的
L"wks", //GC的風(fēng)格,Null表示默認(rèn)的工作站模式
STARTUP_CONCURRENT_GC,
CLSID_CLRRuntimeHost, //CLR的CLSID
IID_ICLRRuntimeHost, //ICLRRuntimeHost的IID
(PVOID*) &pCLRHost); //返回的COM接口
初始化并且啟動(dòng)CLR:
pCLRHost->Start();
然后執(zhí)行一段托管代碼:
hr = pCLRHost ->ExecuteInDefaultAppDomain(L"test.exe",
L" test.Program",
L"Start",
NULL,
&retVal);
這里,是實(shí)現(xiàn)的硬編碼,需要再相同的目錄下面有一個(gè)test.ext和相關(guān)的方法和參數(shù)。
從上面可以看到,其實(shí)我們?nèi)绻枰?/span>Customzing CLR,調(diào)用一些CLR并不展示出來(lái)的功能,可以尋求上面的這個(gè)思路。
5/17/2008 1:41:30 PM 首發(fā)sscli.cnblogs.com
posted on 2008-05-17 14:07 lbq1221119 閱讀(4434) 評(píng)論(17) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)