CLR寄宿(上) MSCOREE.DLL

摘要:
这意味着普通的非托管程序也可以调用CLR来运行托管代码。1.1核心组件MSCOREE.DLLMSCOREE_DLL负责选择。NET版本,调用并初始化CLR。如果非托管程序要启动CLR,它还必须引用MSCOREE.DLL并使用其导出的函数加载托管代码并执行自定义CLR等操作。执行以下代码以查看MSCOREE.DLL的导出函数列表:
CLR寄宿() MSCOREE.DLL

托管代码调用非托管代码,.NET提供了P/Invoke(平台调用)方式,它作为.NET的基础出现在各类书籍和网络资源上,这里不再讨论。那么非托管代码如何去调用托管代码呢?我们知道,一个托管应用程序首先被操作系统启动,然后由操作系统调用CLR来托管该程序。那么.NET框架到底以什么方式让操作系统来认识它并且可以启动它呢?微软实际将其作为COM服务器实现在一个DLL中,并提供了标准的COM接口。既然是COM服务,也就意味着普通的非托管程序也可以调用CLR来运行托管代码,把这种调用方式叫做寄宿,把调用CLR的非托管程序叫做宿主。宿主程序不仅可以调用CLR,还可以通过它来进行内存管理、垃圾回收管理、策略管理、事件管理以及线程控制等高级管理。

1.1  核心组件MSCOREE.DLL

MSCOREE.DLL负责选择.NET版本、调用和初始化CLR等工作。非托管程序想要启动CLR也必须引用MSCOREE.DLL,利用它的导出函数加载托管代码和进行定制CLR等操作。既然现在的焦点集中在MSCOREE.DLL,下面一同来看它的庐山真面目。

查看MSCOREE.DLL的头文件

    对于MSCOREE.DLL文件,我们没有办法查看它的源代码,但是FrameWork SDK提供了mscoree.h文件,可以到相关版本的SDK安装目录中查看该文件。由于该文件很大,这里就不贴出源代码进行分析了。接下来会对相关的接口和函数做介绍。

MSCOREE.DLL的导出函数

    在命令行启动DumpBin.exe,执行以下代码查看MSCOREE.DLL的导出函数列表:

 C:\Windows\System32>dumpbin /exports MSCOREE.DLL

结果如图1-3所示。

image

 

1-3  输出MSCOREE.DLL的导出函数列表

从运行的结果可以知道,MSCOREE.DLL中的导出函数有100多个,所有这些函数都可以被公开调用,而且在MSDN上可以找到每个函数的解释。这里只介绍其中几个常用的函数。

CorBindToRuntimeEx函数

该函数由宿主调用来加载CLR,该函数的定义如代码清单1-4所示。

代码清单1-4 CorBindToRuntimeEx函数定义

HRESULT CorBindToRuntimeEx (

        [in]  LPWSTR    pwszVersion,

        [in]  LPWSTR    pwszBuildFlavor,

        [in]  DWORD     startupFlags,

        [in]  REFCLSID  rclsid,

        [in]  REFIID    riid,

        [out] LPVOID*   ppv

);

代码中的CorBindToRuntimeEx函数需要6个参数,每个参数的定义如下:

pwszVersion。一个字符串,描述要加载的 CLR 的版本。

pwszBuildFlavor。一个字符串,指定是加载CLR 的服务器版本还是工作站版本。有效值为:svr wks。服务器版本已经过优化,可以利用多个处理器进行垃圾回收,而工作站版本则针对单处理器计算机上运行的客户端应用程序进行了优化。

startupFlagsSTARTUP_FLAGS 枚举值的组合。这些标志控制并发垃圾回收、非特定于域的代码以及 pwszVersion 参数的行为。如果未设置标志,则默认值为一个域。

rclsid。实现 ICorRuntimeHost 接口的 coclass CLSID。支持的值为 CLSID_CorRuntimeHost CLSID_CLRRuntimeHost

riid。请求自 rclsid 接口的 IID。支持的值为 IID_ICorRuntimeHost IID_ICLRRuntimeHost

ppv。返回的指向 riid 的接口指针。

提示使用CorBindToCurrentRuntime函数并使用存储在 XML文件中的版本信息可以将公共语言运行库 (CLR) 加载到进程中,还可以使用CorBindToRuntimeByCfg 函数从 XML文件中读取的版本信息将公共语言运行库 (CLR) 加载到进程中。

CorExitProcess函数

该函数用来关闭当前的非托管进程,定义如代码清单1-5所示。

代码清单1-56  CorExitProcess 函数定义

void STDMETHODCALLTYPE CorExitProcess ( 

  [out] int  exitCode

);

其中,参数exitCode表示一个指定进程退出代码的整数。

ClrCreateManagedInstance 函数

该函数用来创建指定托管类型的实例,定义如代码清单1-6所示。

代码清单1-6  ClrCreateManagedInstance 函数定义

STDAPI ClrCreateManagedInstance (

        [in]  LPCWSTR  pTypeName,

        [in]  REFIID   riid,

        [out] void     **ppObject

);

代码中函数ClrCreateManagedInstance的各参数定义如下:

pTypeName。一个指向所请求的实例类型名称的指针。

riid。所请求实例类型的 IID

**ppObject。一个指向指针的指针,它指向的指针指向调用方请求的托管类型实例。

CallFunctionShim函数

该函数用来调用指定库中具有指定名称和参数的函数。定义如代码清单1-7所示。

代码清单1-7  CallFunctionShim 函数定义

HRESULT CallFunctionShim (

        [in] LPCWSTR     szDllName,

        [in] LPCSTR      szFunctionName,

        [in] LPVOID      lpvArgument1,

        [in] LPVOID      lpvArgument2,

        [in] LPCWSTR     szVersion,

        [in] LPVOID      pvReserved

);

代码中函数CallFunctionShim的各参数定义如下:

szDllName。包含函数的库的名称。

szFunctionName。函数的名称。

lpvArgument1。要传递到函数的第一个参数。

lpvArgument2。要传递到函数的第二个参数。

szVersion。包含函数的库的版本。

pvReserved。留作未来使用。在此参数中传递零。

更多的导出函数读者可自行操作获得它们的名称,然后查阅MSDN来进一步了解。

MSCOREE.DLL宿主接口

宿主接口使宿主能够对运行库的更多方面进行控制,从而能够在CLR 和宿主的执行模型之间进行更紧密的集成。在.NET Framework 1 版中,宿主模型使非托管宿主能够将CLR 加载到进程中、配置某些设置以及接收事件通知。但在通常情况下,宿主和CLR 可以在该进程中独立运行。通过.NET Framework 2.0 版及更高版本中新的抽象层,宿主可以提供当前由 Win32 程序集中的类型提供的多种资源,并扩展了宿主可以配置的功能集。

MSCOREE.DLL同样提供了多个宿主接口,这里只介绍较为重要的几个,更多的内容请读者参考MSDN

ICorRuntimeHost 接口

该接口是调用CLR要用到的第一个接口,它负责初始化工作。该接口由上面提到的CorBindToRuntimeEx函数返回,其定义如代码清单1-8所示。

代码清单1-8  ICorRuntimeHost接口定义

interface ICLRRuntimeHost : IUnknown {

    HRESULT ExecuteApplication (

        [in] LPCWSTR                   pwzAppFullName,

        [in] DWORD                     dwManifestPaths,

        [in] LPCWSTR                   *ppwzManifestPaths,  

        [in] DWORD                     dwActivationData,

        [in] LPCWSTR                   *ppwzActivationData, 

        [out] int                      *pReturnValue

    );

       

    HRESULT ExecuteInAppDomain (

        [in] DWORD                     appDomainId,

        [in] FExecuteInDomainCallback  pCallback,

        [in] void*                     cookie

    );

       

    HRESULT ExecuteInDefaultAppDomain (

        [in] LPCWSTR                   pwzAssemblyPath,

        [in] LPCWSTR                   pwzTypeName,

        [in] LPCWSTR                   pwzMethodName,

        [in] LPCWSTR                   pwzArgument,

        [out] DWORD                    *pReturnValue

    );

    HRESULT GetCLRControl (

        [out] ICLRControl              **pCLRControl

    );

    HRESULT GetCurrentAppDomainId (

        [out] DWORD                    *pdwAppDomainId

    );

    HRESULT SetHostControl (

        [in] IHostControl              *pHostControl

    );

    HRESULT Start();

    HRESULT Stop();

    HRESULT UnloadAppDomain (

        [in] DWORD                     dwAppDomainId

        [in] BOOL                      fWaitUntilDone

    );

};

对代码清单1-8中的各方法说明如下:

q  ICLRRuntimeHost::ExecuteApplication方法

一个字符串,描述要加载基于清单的 ClickOnce 部署方案中用于指定要在新域中激活的应用程序。

q  ICLRRuntimeHost::ExecuteInAppDomain 方法

指定要在其中执行指定托管代码的 AppDomain

q  ICLRRuntimeHost::ExecuteInDefaultAppDomain 方法

调用指定程序集中属于指定类型的指定方法。

q  ICLRRuntimeHost::GetCLRControl 方法

获取一个ICLRControl类型的接口指针,宿主可以使用该类型自定义公共语言运行库 (CLR) 的各个方面。

q  ICLRRuntimeHost::GetCurrentAppDomainId 方法

获取当前正在执行的AppDomain的数字标识符。

q  ICLRRuntimeHost::SetHostControl 方法

设置主机控制接口。在调用 Start 之前必须调用SetHostControl

q  ICLRRuntimeHost::Start 方法

CLR 初始化到进程中。

q  ICLRRuntimeHost::Stop 方法

使运行库停止代码的执行。

q  ICLRRuntimeHost::UnloadAppDomain 方法

卸载与指定的数字标识符对应的 AppDomain

ICLRGCManager接口

该接口提供允许宿主与公共语言运行库的垃圾回收系统进行交互的方法。该接口的定义如代码清单1-9所示。

代码清单1-9  ICLRGCManager接口定义

interface ICLRGCManager : IUnknown {

    HRESULT Collect (

        [in] LONG Generation

    );

    HRESULT GetStats (

        [in, out] COR_GC_STATS *pStats

    );

    HRESULT SetGCStartupLimits (

        [in] DWORD SegmentSize,

        [in] DWORD MaxGen0Size

    );

};

对代码清单1-10ICLRGCManager接口的各方法说明如下:

q  ICLRGCManager::Collect方法

为指定的生成强制执行垃圾回收。

q  ICLRGCManager::GetStats方法

获取有关垃圾回收系统的一组当前统计信息。

q  ICLRGCManager::SetGCStartupLimits方法

设置垃圾回收段的大小和垃圾回收系统零代的最大大小。

IHostControl接口

该接口提供一些方法,以配置程序集的加载和确定宿主支持的宿主接口。该接口的定义如代码清单1-10所示。

代码清单1-10 IHostControl接口定义

interface IHostControl : IUnknown {

    HRESULT GetHostManager (

        [in] REFIID riid,

        [out, iid_is(riid)] IUnknown** ppObject

    );

    HRESULT SetAppDomainManager (

        [in] DWORD dwAppDomainID,

        [in] IUnknown* pUnkAppDomainManager

    );

};

对代码清单1-10IHostControl接口中的方法说明如下:

q  IHostControl::GetHostManager 方法

获取一个接口指针,该指针指向宿主对具有指定 IID 接口的实现。

q  IHostControl::SetAppDomainManager 方法

通知宿主已创建了一个应用程序域。

其他接口

其他接口这里不详细介绍,读者可根据需要按照下面的简介自行查阅相关的文档。

IActionOnCLREvent提供为已注册的事件执行回调的方法。

IApartmentCallback提供用于在单元内进行回调的方法。

IAppDomainBinding提供用于设置运行时配置的方法。

ICatalogServices提供用于编录服务的方法。(此接口支持.NET Framework 基础结构,但不应在代码中直接使用。)

ICLRAssemblyIdentityManager提供支持宿主和 CLR 之间就程序集问题进行通信的方法。

ICLRAssemblyReferenceList管理由CLR(而非宿主)加载的程序集的列表。

ICLRControl提供一些方法,以便宿主可以获取对CLR的访问权限并对CLR的各个方面进行配置。

ICLRDebugManager提供使宿主能够将一组任务与某个标识符及友好名称关联起来的方法。

ICLRErrorReportingManager提供使宿主能够为错误报告配置自定义堆转储的方法。

ICLRHostBindingPolicyManager提供允许宿主计算并传达程序集策略信息中的更改的方法。

ICLRHostProtectionManager使宿主能够阻止特定的托管类、方法、属性和字段在部分受信任的代码中运行。

ICLRIoCompletionManager实现使宿主能够向 CLR 通知指定 I/O 请求的状态的回调方法。

ICLRMemoryNotificationCallback使宿主能够使用与 Win32 CreateMemoryResourceNotification 函数方法类似的方法报告内存压力情况。

ICLROnEventManager提供使宿主能够为 CLR 事件注册和注销回调的方法。

ICLRPolicyManager提供使宿主能够指定在出现故障和超时的情况下采取的策略操作的方法。

ICLRProbingAssemblyEnum提供方法,这些方法使宿主能够使用 CLR 内部的程序集标识信息来获取该程序集的探测标识,而无需创建或了解该标识。

ICLRReferenceAssemblyEnum提供方法,这些方法使宿主能够对文件或流通过 CLR 内部的程序集标识数据引用的一组程序集进行操作,而无需创建或了解这些标识。

ICLRSyncManager提供方法,以便让宿主在其同步实现中获取有关请求任务的信息并进行死锁检测。

ICLRTask提供方法,这些方法使宿主能够向 CLR 发出请求,或者向 CLR 提供与关联的任务有关的通知。

ICLRTaskManager提供方法,这些方法使宿主能够显式请求 CLR 创建一个新任务,获取当前正在执行的任务,以及设置该任务的地理语言和区域性。

ICLRValidator提供用于验证可移植可执行 (PE) 映像和报告验证错误的方法。

ICorConfiguration提供用于配置 CLR 的方法。

ICorThreadpool提供用于访问线程池的方法。

IDebuggerInfo提供用于获取调试服务状态信息的方法。

IDebuggerThreadControl提供方法,用于向宿主发出有关通过调试服务阻止和取消阻止线程的通知。

IGCHostControl提供使垃圾回收器能够请求宿主更改虚拟内存限制的方法。

IGCThreadControl提供用于参与线程调度的方法,以防止因阻塞而执行垃圾回收。

IHostAssemblyManager提供方法,这些方法使宿主能够指定应由 CLR 或宿主加载的多组程序集。

IHostAssemblyStore提供方法,这些方法使宿主能够独立于 CLR 加载程序集和模块。

IHostAutoEvent提供由宿主实现的自动重置事件的表示形式。

IHostCrst用做线程临界区的宿主表示形式。

IHostIoCompletionManager提供方法,这些方法使 CLR 能够与宿主提供的 I/O 完成端口进行交互。

IHostMAlloc提供一些方法,以便 CLR 可以请求从堆到宿主的细化分配。

IHostManualEvent提供宿主的手动重置事件的表示形式的实现。

IHostMemoryManager提供方法,以便 CLR 可以通过宿主而不是使用标准 Win32 虚拟内存函数来请求虚拟内存。

IHostPolicyManager提供一些方法,以便通知宿主 CLR 在中止、超时或失败时所执行的操作。

IHostSecurityContext使 CLR 能够维护由宿主实现的安全性上下文信息。

IHostSecurityManager提供允许访问和控制当前正在执行的线程的安全性上下文的方法。

IHostSemaphore提供由宿主实现的信号量的表示形式。

IHostSyncManager提供方法,以便 CLR 可以通过调用宿主而不是使用 Win32 同步函数来创建同步基元。

IHostTask提供使 CLR 能够与宿主通信以管理任务的方法。

IHostTaskManager提供方法,这些方法使 CLR 能够通过宿主而不是使用标准操作系统线程或线程函数来处理任务。

IHostThreadPoolManager提供一些方法,以便 CLR 可以配置线程池并对线程池中的工作项进行排队。

IManagedObject提供用于控制托管对象的方法。

IObjectHandle提供用于通过间接寻址打开按值封送对象的方法。

ITypeName提供用于获取类型名称信息的方法。(此接口支持 .NET Framework 基础结构,但不应在代码中直接使用。)

ITypeNameBuilder提供用于生成类型名称的方法。(此接口支持 .NET Framework 基础结构,但不应在代码中直接使用。)

ITypeNameFactory提供用于解构类型名称的方法。(此接口支持 .NET Framework 基础结构,但不应在代码中直接使用。)

IValidator提供用于验证可移植可执行 (PE) 映像和报告验证错误的方法。

1.2  MSCOREE.DLL接口层次模型

所有的CLR Hosting API提供的主要功能包括:CLR的启动和关闭、App Domain相关、自定义错误处理、编程模型的执行、对调试器的支持、AssemblyLoad相关、CLR的内部事件、CLR Engine相关、内存管理和垃圾回收、Threading、同步和I/O的支持等。图1-4展示了MSCOREE.DLL中接口的层次模型。

image

 

1-4 MSCOREE.DLL中的接口层次模型

和图1-4对应的是MSCOREE.DLL各个接口在应用过程中的功能模型,如图1-5所示。

image

 

1-5  MSCOREE.DLL各个接口在应用过程中的功能模型

现在看代码清单1-8ICLRRuntimeHost接口的定义里面的

HRESULT STDMETHODCALLTYPE SetHostControl方法和HRESULT STDMETHODCALLTYPE GetCLRControl方法。这两个方法根据功能实现者(CLRHost)的不同对控制权进行了选择。将控制权交给CLR的起始是SetCLRControl方法。

注意  如果某一个特定的功能是由CLR来实现的,调用这个功能的相应的接口就用ICLR来开头,如果这个功能是Host实现的,就调用IHost开头的接口定义的函数。

1.3 加载CLR与执行代码实例

下面展示一下如何采用一个非托管的宿主来加载CLR并且执行里面的代码。请看代码清单1-11

     代码清单1-11  加载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);

代码清单1-11只是一个最简单的示例,在实际应用中可以实施更多的配置,由于篇幅所限,本书就不更多地去讲解相关内容了,可以明确的是,一切操作都不会脱离上述接口。

-----------------------注:本文部分内容改编自《.NET安全揭秘》

免责声明:文章转载自《CLR寄宿(上) MSCOREE.DLL》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MVVM模式下实现拖拽kvm安装步骤下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Hive调优实战[转]

Hive优化总结 【转自:http://sznmail.iteye.com/blog/1499789】 优化时,把hive sql当做map reduce程序来读,会有意想不到的惊喜。 理解hadoop的核心能力,是hive优化的根本。这是这一年来,项目组所有成员宝贵的经验总结。   长期观察hadoop处理数据的过程,有几个显著的特征: 1.不怕数据多...

Latex文件分别用Texwork和Winedt打开时,产生中文乱码的解决方法

中文兼容方法(能保证编译成功) usepackage{CJK} egin{document} egin{CJK}{GBK}{kai} ... 中文 ... end{CJK} end{document} 上述tex代码中 ... 表示其他Tex命令 Texworks和Winedt下均使用PdfLatex编译 解决中文乱码,有两种方法: 方...

C#:总结页面传值几种方法

 小知识点: 1.  W7自带 .NetFrameWork 3.5, 兼容模式为 高版本号兼容低版本号; 2. WF和WPF都是基于XAML的,可是两者的用途不同。 WF是一种开发框架,将工作流嵌入在.NET Framework应用程序中,所主要用于开发创建工作流应用程序。WF:http://msdn.microsoft.com/zh-cn/librar...

微信公众号如何使用域名直接调试本地开发环境代码的方案

 微信公众号,必须通过域名才能进行访问。很多人调试时,都是把代码打包放到服务器上来调试,发现问题本地修改,再次上传调试,这样效率非常低。 我们通过这样操作可以实现本地的直接调试: 首先公众号里设置好域名,验证域名所有者。 我们假设,域名为:http://wechat.hz300.com,npm run dev开启的本地代码调试服务为:http://loca...

产品逻辑中的—B端技术常识:同步异步接口模式

参看:http://www.woshipm.com/pd/3085570.html;http://www.woshipm.com/pd/3544202.html 在软件开发中,接口是一个非常重要的概念。所谓接口,是指两个对象进行通信的方式和协议。 软件领域的接口和我们生活中所使用的硬件设备的接口(例如USB接口、苹果的Lighting接口、3.5mm耳机接...

手把手教你进行Pycharm活动模板配置

/1 前言/ 嘿,各位小伙伴大家好,最近后台很多小伙伴加小编微信,说是想使用Pycharm,除了简单的安装Pycharm和设置Pycharm解释器之外,Python环境搭建—安利Python小白的Python和Pycharm安装详细教程,安装好Pycharm后如何配置Python解释器简易教程,有个活动模板配置,小编觉得也还是蛮重要的,这里整理出来给大...