有些時候主程序是通過C/C++實現的,但是我們希望通過托管代碼來擴展非托管程序,從而也獲得托管代碼帶來的一系列優點。比如開發效率高,自動垃圾回收等。
運行托管與非托管代碼根本區別在於托管代碼是進程首先加載CLR然後通過CLR運行托管程序,而非托管代碼則是操作系統直接根據其PE Header加載程序分配內存從而運行。因此如果需要通過托管代碼來擴展非托管程序,首先要加載CLR來使非托管程序獲得運行托管代碼的能力。
可以使用以下過程將 CLR 加載到進程中:
所有這些接口的原型均位於 Metahost.h 文件中,該文件位於 Windows 軟件開發工具包 (SDK) 的 Include 目錄中。 宿主可以使用 ICLRRuntimeInfo 和 ICLRRuntimeHost 接口來控制要加載哪個版本的運行時以及基本功能(如垃圾回收和程序集加載)的行為。使用 ICLRRuntimeHost 接口可以執行以下操作:
參考這裡 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!