歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++手動加載CLR運行托管程序(CLR Hosting)

C++手動加載CLR運行托管程序(CLR Hosting)

日期:2017/3/1 10:08:35   编辑:Linux編程

機制介紹

有些時候主程序是通過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)的方法。

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

相應的托管代碼如下,

  1. using System;
  2. namespace SampleManagedApp
  3. {
  4. class Program
  5. {
  6. static void Main(string[] args)
  7. {
  8. }
  9. public static int Test(string s)
  10. {
  11. Console.WriteLine(s);
  12. return 0;
  13. }
  14. }
  15. }
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!

Copyright © Linux教程網 All Rights Reserved