机制介绍
有些时候主程序是通过C/C++实现的,但是我们希望通过托管代码来扩展非托管程序,从而也获得托管代码带来的一系列优点。比如开发效率高,自动垃圾回收等。
运行托管与非托管代码根本区别在于托管代码是进程首先加载CLR然后通过CLR运行托管程序,而非托管代码则是操作系统直接根据其PE Header加载程序分配内存从而运行。因此如果需要通过托管代码来扩展非托管程序,首先要加载CLR来使非托管程序获得运行托管代码的能力。
- 调用 CLRCreateInstance 函数以获取 ICLRMetaHost 或 ICLRMetaHostPolicy 接口。 CLRCreateInstance 函数取代 .NET Framework 1.1 和 2.0 承载全局静态函数部分中列出的所有 CorBindTo* 函数。
- 调用 ICLRMetaHost::EnumerateInstalledRuntimes、ICLRMetaHost::GetRuntime 或 ICLRMetaHostPolicy::GetRequestedRuntime 方法以获取有效的 ICLRRuntimeInfo 指针。
- 调用 ICLRRuntimeInfo::GetInterface 方法。 为 rclsid 参数指定 CLSID_CLRRuntimeHost,并为 riid 参数指定 IID_ICLRRuntimeHost。
- 通过调用 ICLRRuntimeHost::Start 方法来启动运行时。
- 执行托管代码。
- 获取指向 ICLRControl 接口(可提供对由公共语言运行时实现的管理器的访问)的指针,以及注册实现 IHostControl 接口的宿主控件对象。 公共语言运行时调用 IHostControl 接口来确定宿主实现的管理器。
参考这里 http://msdn.microsoft.com/en-us/library/01918c6x.aspx
实例代码
以下是C++加载CLR运行托管程序的实例代码,启动CLR之后通过调用ExecuteInDefaultAppDomain来运行托管程序SampleManagedApp.exe中名为Test的程序。这里要注意的是ExecuteInDefaultAppDomain只能执行托管代码签名为static int pwzMethodName (String pwzArgument)的方法。
#include <SDKDDKVer.h> #include <stdio.h> #include <tchar.h> #include <windows.h> #include <metahost.h> #include <mscoree.h> #pragma comment(lib, "mscoree.lib") int _tmain(int argc, _TCHAR* argv[]) { ICLRMetaHost *pMetaHost = nullptr; ICLRMetaHostPolicy *pMetaHostPolicy = nullptr; ICLRRuntimeHost *pRuntimeHost = nullptr; ICLRRuntimeInfo *pRuntimeInfo = nullptr; HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); if(FAILED(hr)) { goto cleanup; } hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost)); hr = pRuntimeHost->Start(); DWORD dwRet = 0; hr = pRuntimeHost->ExecuteInDefaultAppDomain(L"SampleManagedApp.exe", L"SampleManagedApp.Program", L"Test", L"Hello World!", &dwRet); hr = pRuntimeHost->Stop(); cleanup: if(pRuntimeInfo != nullptr) { pRuntimeInfo->Release(); pRuntimeInfo = nullptr; } if(pRuntimeHost != nullptr) { pRuntimeHost->Release(); pRuntimeHost = nullptr; } if(pMetaHost != nullptr) { pMetaHost->Release(); pMetaHost = nullptr; } }相应的托管代码如下,
using System; namespace SampleManagedApp { class Program { static void Main(string[] args) { } public static int Test(string s) { Console.WriteLine(s); return 0; } } }
最终将SampleManagedApp.exe与非托管程序放在同一个路径下运行非托管程序,就会得到最终Console中输出:Hello World!