Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西

导航

CLR 2.0 中的宿主监控和管理接口 [1] 概述

Posted on 2004-08-22 21:53  Flier Lu  阅读(1891)  评论(0编辑  收藏  举报
原文:http://www.blogcn.com/User8/flier_lu/index.html?id=3451359


大概两年多以前我曾写过一篇小文《.Net平台下CLR程序载入原理分析》(以下简称【文1】),简单介绍了 CLR 1.0 中如果以宿主 (Host) 程序身份,通过代码手工加载 CLR 运行时环境。在 Whidbey 发布的测试版 CLR 2.0.40607 中,通过一组宿主管理器接口,大大增强了宿主对 CLR 运行时环境的监控和管理能力。
在【文 1】中,我们知道加载 CLR 运行时环境可以通过 mscoree.dll 提供的 CorBindToRuntimeEx 函数,加载并获取绑定到 CLR 运行时环境的接口。只不过 CLR 2.0 中提供了功能更强大的 ICLRRuntimeHost 接口,以取代 CLR 1.x 中并非那么灵活的 ICorRuntimeHost 接口。
与 CLR 1.x 中不同,CLR 2.0 中的 ICLRRuntimeHost 接口不再只是类似 ICorRuntimeHost 这样的 CLR 加载和启动管理,更是通过主动宿主管理接口 (ICLRHostXXXManager) 和被动宿主监控接口 (IHostXXXManager),能够全方位监控和管理 CLR 运行时环境。
以下内容为程序代码:

//*****************************************************************************
// New interface for hosting mscoree
//*****************************************************************************
[
uuid(90F1A06C-7712-4762-86B5-7A5EBA6BDB01),
version(1.0),
helpstring("Common Language Runtime Hosting Interface"[img]/images/wink.gif[/img],
pointer_default(unique),
local
]
interface ICLRRuntimeHost : IUnknown
{
// Starts the runtime. This is equivalent to CoInitializeCor().
HRESULT Start();

// Terminates the runtime, This is equivalent CoUninitializeCor();
HRESULT Stop();

// Returns an object for configuring runtime, e.g. threading, lock
// prior it starts. If the runtime has been initialized this
// routine returns an error. See IHostControl.
HRESULT SetHostControl([in] IHostControl* pHostControl);

HRESULT GetCLRControl([out] ICLRControl** pCLRControl);

HRESULT UnloadAppDomain([in] DWORD dwAppDomainId);

HRESULT ExecuteInAppDomain([in] DWORD dwAppDomainId,
[in] FExecuteInAppDomainCallback pCallback,
[in] void* cookie);

HRESULT GetCurrentAppDomainId([out] DWORD *pdwAppDomainId);

HRESULT ExecuteApplication([in] LPCWSTR pwzAppFullName,
[in] DWORD dwManifestPaths,
[in] LPCWSTR *ppwzManifestPaths, // optional
[in] DWORD dwActivationData,
[in] LPCWSTR *ppwzActivationData, // optional
[out] int *pReturnValue);

HRESULT ExecuteInDefaultAppDomain([in] LPCWSTR pwzAssemblyPath,
[in] LPCWSTR pwzTypeName,
[in] LPCWSTR pwzMethodName,
[in] LPCWSTR pwzArgument,
[out] DWORD *pReturnValue);
};

ICLRRuntimeHost 接口分为三个部分:

首先是启动和停止 CLR 运行时环境的 Start() 和 Stop() 方法;
其次是 CLR 运行时环境的监控和管理接口的 SetHostControl 和 GetCLRControl 方法;
最后是对 AppDomain 进行控制的 XXXAppDomain() 方法;

除了监控和管理接口的相关方法,其他的与 ICorRuntimeHost 接口大同小异,有兴趣的朋友可以参考【文 1】中的介绍。
而新增的监控和管理接口则分为监控和管理两个部分。前者先 CLR 环境提供若干个回调接口,实现 CLR 运行时诸如内存分配等操作的监控;后者则从 CLR 运行时环境获取若干管理接口,精确控制 CLR 的运行时行为。两者相辅相成,互相配合能非常精确的控制 CLR 的行为,较之以前的 Profiler 和 Debugger 接口一点也不逊色,而且使用更加简便。通过这些强大的接口,.NET 可以说是正式拉开了与现有系统大规模集成的序幕,如正在开发中的 SQL Server 2005 (Yukon) 就完全内建并基于 CLR 运行时环境,连存储过程都可以通过 CLR 直接支持。

就宿主监控和管理接口来说,CLR 将之大概分为以下部分:

功能模块 CLR 管理 Host 监控

内存 IEEMemoryManager IHostMemoryManager
任务 ICLRTaskManager IHostTaskManager
线程池 ICorThreadpool IHostThreadpoolManager
IO ICLRIoCompletionManager IHostIoCompletionManager
同步 ICLRSyncManager IHostSyncManager
Assembly IHostAssemblyManager
跨边界调用 IHostCrossAssemblyCallManager
GC ICLRGCManager IHostGCManager
安全 IHostSecurityManager IHostSecurityManager
策略 ICLRPolicyManager IHostPolicyManager
调试 ICLRDebugManager
CLR 事件 ICLROnEventManager
宿主保护 ICLRHostProtectionManager
绑定与身份 ICLRAssemblyIdentityManager
绑定策略 ICLRHostBindingPolicyManager
类型名称 ITypeNameBuilder

其中部分有些部分只有监控接口,有些部分只有管理接口。

对管理接口,使用上是直接通过通过 ICLRRuntimeHost::GetCLRControl 获得 ICLRControl 接口实例:
以下内容为程序代码:

[
uuid(9065597E-D1A1-4fb2-B6BA-7E1FCE230F61),
version(1.0),
helpstring("Common Language Runtime Control Interface"[img]/images/wink.gif[/img],
pointer_default(unique),
local
]
interface ICLRControl : IUnknown
{
HRESULT GetCLRManager(
[in] REFIID riid,
[out] void **ppObject);

HRESULT SetAppDomainManagerType(
[in] LPCWSTR pwzAppDomainManagerAssembly,
[in] LPCWSTR pwzAppDomainManagerType);
}

而 ICLRControl::GetCLRManager 方法,则可以根据各个接口的 IID 获取相应接口实例。如下列代码演示了如何获取一个 GC 管理接口的实例(为代码简便,对错误和异常检测代码都被忽略):
以下内容为程序代码:

HRESULT hr;

//...

CComPtr<ICLRRuntimeHost> spClrHost;

hr = CorBindToRuntimeEx(NULL, NULL, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&spClrHost);

check(hr, "CorBindToRuntimeEx"[img]/images/wink.gif[/img];

CComPtr<ICLRControl> spClrCtrl;

hr = spClrHost->GetCLRControl(&spClrCtrl);

CComPtr<ICLRGCManager> spGCMgr;

hr = spClrCtrl->GetCLRManager(IID_ICLRGCManager, (LPVOID *)&spGCMgr);

//...

绝大多数的 CLR 管理接口 (名为 ICLRxxxManager) 都可以通过类似的方式获得,不过有的管理接口还需要单独处理,如 ICorThreadpool 等。

对监控接口,使用上则是通过 ICLRRuntimeHost::SetHostControl 将实现了 IHostControl 接口的 COM 对象实例,交给 CLR 运行时环境,由它在合适的使用再通过 IHostControl::GetHostManager 方法获取监控接口实例,如设置代码:
以下内容为程序代码:

class CHostControl : ...
{
template <class C, class I>
static I *CreateComObject()
{
CComObject<C> *pObj;

CComObject<C>::CreateInstance(&pObj);

return static_cast<I *>(pObj);
}
}

HRESULT hr;

//...

CComPtr<ICLRRuntimeHost> spClrHost;

hr = CorBindToRuntimeEx(NULL, NULL, 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&spClrHost);

CComPtr<IHostControl> spHostCtrl(CHostControl::CreateComObject<CHostControl, IHostControl>());

hr = spClrHost->SetHostControl(spHostCtrl);

//...

这儿的 CHostControl 是使用 ATL 完成的一个 IHostControl 接口实现 COM 对象。
以下内容为程序代码:

#pragma once

#include <atlcom.h>

#include <mscoree.h>

class CHostControl : public CComObjectRoot, public IHostControl
{
public:
CHostControl(void)
{
}
virtual ~CHostControl(void)
{
}

BEGIN_COM_MAP(CHostControl)
COM_INTERFACE_ENTRY(IHostControl)
END_COM_MAP()

// IHostControl
HRESULT __stdcall GetHostManager(REFIID riid, void **ppObject);
HRESULT __stdcall SetAppDomainManager(DWORD dwAppDomainID, IUnknown *pUnkAppDomainManager);
HRESULT __stdcall GetDomainNeutralAssemblies(ICLRAssemblyReferenceList **ppReferenceList);
};

其主要功能在于 GetHostManager 方法,根据 CLR 传入的 riid,判断并构造相应的宿主监控管理器接口,其他的函数不实现亦可。
以下内容为程序代码:

HRESULT __stdcall CHostControl::GetHostManager(REFIID riid, void **ppObject)
{
if(riid == IID_IHostMemoryManager)
{
std::cout << "IHostControl::GetHostManager(IHostMemoryManager)" << std::endl;

*ppObject = CreateComObject<HostManager::CHostMemoryManager, IHostMemoryManager>();

return S_OK;
}
else if(riid == IID_IHostTaskManager)
//...
else
{
std::cout << "IHostControl::GetHostManager()" << std::endl;
}

return E_NOTIMPL;
}

HRESULT __stdcall CHostControl::SetAppDomainManager(DWORD dwAppDomainID, IUnknown *pUnkAppDomainManager)
{
std::cout << "IHostControl::SetAppDomainManager()" << std::endl;

return E_NOTIMPL;
}

HRESULT __stdcall CHostControl::GetDomainNeutralAssemblies(ICLRAssemblyReferenceList **ppReferenceList)
{
std::cout << "IHostControl::GetDomainNeutralAssemblies()" << std::endl;

return E_NOTIMPL;
}


这一小节介绍了 CLR 2.0 中的宿主管理接口的相关结构,从下一节开始,将陆续介绍各种监控和管理接口的功能和使用方法。

to be continue...