首页 > 代码库 > c++通过CLRCreateInstance调用托管dll

c++通过CLRCreateInstance调用托管dll

C++手动加载CLR运行托管程序(CLR Hosting) 

非原创,记录方便翻阅(另外一种调用方式为将托管dll封装成com)

 

机制介绍

有些时候主程序是通过C/C++实现的,但是我们希望通过托管代码来扩展非托管程序,从而也获得托管代码带来的一系列优点。比如开发效率高,自动垃圾回收等。

运行托管与非托管代码根本区别在于托管代码是进程首先加载CLR然后通过CLR运行托管程序,而非托管代码则是操作系统直接根据其PE Header加载程序分配内存从而运行。因此如果需要通过托管代码来扩展非托管程序,首先要加载CLR来使非托管程序获得运行托管代码的能力。

 

可以使用以下过程将 CLR 加载到进程中:
  1. 调用 CLRCreateInstance 函数以获取 ICLRMetaHost 或 ICLRMetaHostPolicy 接口。 CLRCreateInstance 函数取代 .NET Framework 1.1 和 2.0 承载全局静态函数部分中列出的所有 CorBindTo* 函数。
  2. 调用 ICLRMetaHost::EnumerateInstalledRuntimes、ICLRMetaHost::GetRuntime 或 ICLRMetaHostPolicy::GetRequestedRuntime 方法以获取有效的 ICLRRuntimeInfo 指针。
  3. 调用 ICLRRuntimeInfo::GetInterface 方法。 为 rclsid 参数指定 CLSID_CLRRuntimeHost,并为 riid 参数指定 IID_ICLRRuntimeHost。
所有这些接口的原型均位于 Metahost.h 文件中,该文件位于 Windows 软件开发工具包 (SDK) 的 Include 目录中。 宿主可以使用 ICLRRuntimeInfo 和 ICLRRuntimeHost 接口来控制要加载哪个版本的运行时以及基本功能(如垃圾回收和程序集加载)的行为。使用 ICLRRuntimeHost 接口可以执行以下操作:
  1. 通过调用 ICLRRuntimeHost::Start 方法来启动运行时。
  2. 执行托管代码。
  3. 获取指向 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)的方法。

 

[cpp] view plain copy
 
  1. #include <SDKDDKVer.h>  
  2.   
  3. #include <stdio.h>  
  4. #include <tchar.h>  
  5. #include <windows.h>  
  6.   
  7. #include <metahost.h>  
  8. #include <mscoree.h>  
  9. #pragma comment(lib, "mscoree.lib")  
  10.   
  11. int _tmain(int argc, _TCHAR* argv[])  
  12. {  
  13.     ICLRMetaHost        *pMetaHost = nullptr;  
  14.     ICLRMetaHostPolicy  *pMetaHostPolicy = nullptr;  
  15.     ICLRRuntimeHost     *pRuntimeHost = nullptr;  
  16.     ICLRRuntimeInfo     *pRuntimeInfo = nullptr;  
  17.   
  18.     HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost);  
  19.     hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo));  
  20.   
  21.     if(FAILED(hr))  
  22.     {  
  23.         goto cleanup;  
  24.     }  
  25.   
  26.     hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pRuntimeHost));  
  27.   
  28.     hr = pRuntimeHost->Start();  
  29.   
  30.     DWORD dwRet = 0;  
  31.     hr = pRuntimeHost->ExecuteInDefaultAppDomain(L"SampleManagedApp.exe",  
  32.                                                  L"SampleManagedApp.Program",   
  33.                                                  L"Test",  
  34.                                                  L"Hello World!",  
  35.                                                  &dwRet);  
  36.   
  37.     hr = pRuntimeHost->Stop();  
  38.   
  39. cleanup:  
  40.     if(pRuntimeInfo != nullptr)  
  41.     {  
  42.         pRuntimeInfo->Release();  
  43.         pRuntimeInfo = nullptr;  
  44.     }  
  45.   
  46.     if(pRuntimeHost != nullptr)  
  47.     {  
  48.         pRuntimeHost->Release();  
  49.         pRuntimeHost = nullptr;  
  50.     }  
  51.   
  52.     if(pMetaHost != nullptr)  
  53.     {  
  54.         pMetaHost->Release();  
  55.         pMetaHost = nullptr;  
  56.     }  
  57. }  
相应的托管代码如下,

 

 

[csharp] view plain copy
 
  1. using System;  
  2.   
  3. namespace SampleManagedApp  
  4. {  
  5.     class Program  
  6.     {  
  7.         static void Main(string[] args)  
  8.         {  
  9.         }  
  10.   
  11.         public static int Test(string s)  
  12.         {  
  13.             Console.WriteLine(s);  
  14.             return 0;  
  15.         }  
  16.     }  
  17. }  

最终将SampleManagedApp.exe与非托管程序放在同一个路径下运行非托管程序,就会得到最终Console中输出:Hello World!

c++通过CLRCreateInstance调用托管dll