.Net CLR Hosting原理及实践

在开发CLR的时候,MS实际上是将CLR相关的功能作为一个COM服务实现在一个DLL里面。对这个DLL的选择,是由垫片来选择的。

MSCLR定义了一个标准的COM接口,并且为该接口和COM服务指定了GUID

虽然没有垫片mscoree.dll的实现代码,但是咱可以看看头文件….

MSCorEE头文件里面,定义了一些GUID和非托管的最重要的ICorRuntimeHost接口。

任何windows应用程序,都可以编程实现hosting CLR,可以调用MSCorEE里面的CorBindToRuntime方法来实现寄宿托管程序。在寄宿托管程序的时候,process里面众多的thread只有两种可以执行托管代码:

 

HRESULT CorBindToRuntimeEx

    LPWSTR pwszVersion,  

    LPWSTR pwszBuildFlavor,

    DWORD flags,           

    REFCLSID rclsid,     

    REFIID riid,   

    LPVOID* ppv

);

 

       调用上面的这个函数的时候,这个函数允许指定期望加载的CLR的版本(pwszVersionNull表示希望加载最新版本的CLR),加载服务器版本的ee还是工作站版本的ee,控制执行是并发垃圾回收还是非并发的垃圾回收,控制程序集是否以非特定与域的方式进行加载。

       最后一个参数的含义,是获取一个接口的指针,该指针可以指向其它设置选项的ICorRuntimeHost。这些选项,允许在宿主启动之前对他们进行配置。

       ICorRuntimeHosthosting APIs里面的一个初始化COM interface。之所以说是初始化的COM interface,是因为这个接口,是在hosting CLR的时候需要用到的第一个接口。

 

       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用来获取CLR实现了哪些寄宿的应用程序接口。

        virtual HRESULT STDMETHODCALLTYPE GetCLRControl(

            /* [out] */ ICLRControl **pCLRControl) = 0;       

            //从一个Process里面卸载一个AppDomain

        virtual HRESULT STDMETHODCALLTYPE UnloadAppDomain(

            /* [in] */ DWORD dwAppDomainId,

            /* [in] */ BOOL fWaitUntilDone) = 0;      

            //在一个特定的应用程序域里面执行一个回调函数。

        virtual HRESULT STDMETHODCALLTYPE ExecuteInAppDomain(

            /* [in] */ DWORD dwAppDomainId,

            /* [in] */ FExecuteInAppDomainCallback pCallback,

            /* [in] */ void *cookie) = 0;       

            //返回给当前Calling Thread某个特定的应用程序域的独一无二的Domain Id

        virtual HRESULT STDMETHODCALLTYPE GetCurrentAppDomainId(

            /* [out] */ DWORD *pdwAppDomainId) = 0;      

            //执行一个由外部的Manifest定义的一个标准的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;       

            //在默认的应用程序域里面执行一个特定的方法。这个方法,对于只有一个AppDomianCLR Host来说比较的方便。

        virtual HRESULT STDMETHODCALLTYPE ExecuteInDefaultAppDomain(

            /* [in] */ LPCWSTR pwzAssemblyPath,

            /* [in] */ LPCWSTR pwzTypeName,

            /* [in] */ LPCWSTR pwzMethodName,

            /* [in] */ LPCWSTR pwzArgument,

            /* [out] */ DWORD *pReturnValue) = 0;        

};

 

这里,返回了这个接口之后,如何使用CLR提供的一系列功能呢?这里就涉及到一个非常重要的概念:Hosting Manager

       关于这方面的资料,说实话见到的不多,大多在一些msdn blogs的隐蔽的角落里面。中文方面,比较好的有一篇台湾的蔡學鏞的大內高手專欄中的.NET CLR Hosting 簡介,还有就是filerMSzhangyiblog上面也介绍过。

Hosting Manager是干嘛的呢?简单的来说,就是把一系列的CLR提供的功能组织到一起。把他们组织成为一个逻辑功能的逻辑组合。

       在所有的CLR Hosting APIs里面提供的功能,主要包括:CLR的启动和关闭,App Domain相关,自定义错误处理,编程模型的执行,对调试器的支持,AssemblyLoad相关,CLR的内部事件,CLR Engine相关,内存管理和垃圾回收,Threading,同步,I/O的支持等。

 

       这里,copy一个提供了CLR的各个功能的接口层次结构图:

      

和这个接口的层次图对应的,是功能的层次结构图:


这里,才回头到最上面ICLRRuntimeHost接口的定义里面的:

virtual HRESULT STDMETHODCALLTYPE SetHostControl

virtual HRESULT STDMETHODCALLTYPE GetCLRControl

 

这里的两个部分,就是把控制权交给了CLR,但是根据不同的功能到底是哪一部分实现的,是CLR实现的,还是Host实现的进行了选择。而在有的地方说的,在托管程序加载了CLR之后,就将控制权交给了CLR,指的起始就是SetCLRControl

 

举一个简单的例子,就说IHostContrl里面的Assembly Loading这个功能的实现。这个功能的实现,是由宿主来实现的。其功能,都可以通过调用IHostAssemblyManager这个基本接口来实现:

 

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;       

};

 

另外有一点需要特别指明一下,如果某一个特定的功能,是由CLR来实现的,调用这个功能的相应的接口就用ICLR来开头,如果这个功能是Host实现的,就调用IHost开头的接口定义的函数。

我们通常说sql server提供了对DotNet的支持,其实就是它实现了这些功能接口的功能,可以直接在CLR中调用相关的功能。

 

IHostAssemblyManager实现了了对Assembly Load功能,同时还有三个另外的接口也实现了Assembly Load相关的功能:IHostAssemblyStore ICLRAssemblyReferenceList

ICLRAssemblyIdentityManager。他们都提供了不同的功能,分别有CLRHost来实现。

      

 

       恩,介绍到这个地方,基本上CLR Hosting的原理和它的一套方法,都说清楚了。接下来,看看一个如何调用CLR功能的一个例子。

       下面展示一下如何采用一个非托管的宿主来加载CLR并且执行里面的一些代码。

      

       首先,在非托管宿主里面加载CLR并且启动:

 

      ICLRRuntimeHost *pCLRHost = NULL;
      HRESULT hr = CorBindToRuntimeEx(

      L"v2.0.40103",                 //需要加载的CLR版本,Null表示最新的

      L"wks",                    //GC的风格,Null表示默认的工作站模式

      STARTUP_CONCURRENT_GC,

      CLSID_CLRRuntimeHost,               //CLRCLSID

      IID_ICLRRuntimeHost,                   //ICLRRuntimeHostIID

      (PVOID*) &pCLRHost);                 //返回的COM接口

 

       初始化并且启动CLR

       pCLRHost->Start();

 

然后执行一段托管代码:

hr = pCLRHost ->ExecuteInDefaultAppDomain(L"test.exe",

                                        L" test.Program",

                                        L"Start",

                                        NULL,

                                        &retVal);

       这里,是实现的硬编码,需要再相同的目录下面有一个test.ext和相关的方法和参数。

 

       从上面可以看到,其实我们如果需要Customzing CLR,调用一些CLR并不展示出来的功能,可以寻求上面的这个思路。

 

       5/17/2008 1:41:30 PM    首发sscli.cnblogs.com

      

      

posted on 2008-05-17 14:07  lbq1221119  阅读(4396)  评论(17编辑  收藏  举报

导航