Хостинг CLR в неуправляемом приложении

30 марта 2011 г.

.NET Framework предоставляет большое количество способов взаимодействия управляемого и неуправляемого кода, включая COM Interop и P/Invoke. Существует много материалов, посвящённых данному вопросу. Однако о такой возможности, как запуск CRL в неуправляемом процессе посредством CLR Hosting API, написано сравнительно немного. Запуск среды выполнения в неуправляемом приложении может быть полезен, в следующих случаях:

  • поддержка расширений, написанных на управляемых языках;
  • создание навесных защит для управляемых приложений;
  • управление работой CLR;
  • сложные случаи отладки;
  • постепенный перевод большого неуправляемого приложения на .NET.

Например, хостинг CLR используется в приложениях Microsoft Office (управляемые надстройки) и Microsoft SQL Server (CLR Stored Procedures).

Развитие CLR Hosting API

.NET Framework 1.x

В первой версия CLR Hosting API для взаимодействия со средой выполнения используется интерфейс ICorRuntimeHost, который можно получить при помощи статических функций CorBindTo* (например, CorBindToRuntie) библиотеки MSCorEE.dll.

.NET Framework 2.0

В этой версии многие аспекты хостинга CLR перенесены из неуправляемого в управляемый код (программист может управлять хостингом при помощи наследника класса AppDomainManager). Появился новый интерфейс ICLRRuntimeHost.

.NET Framework 4.0 и In-Process Side-by-Side

Предыдущие версии CLR Hosting API имели важное ограничение – было невозможно запустить более одной версии CLR в одном процессе. Это означает, что если есть две надстройки, написанные с использованием разных версий CLR, то, как минимум, одну из них придется запускать не под той версией исполняющей среды, для которой она разрабатывалась. Начиная с .NET Framework 4.0 появилась возможность загрузить нескольких версий CLR в одном процессе, при этом одновременно смогут работать сколько угодно версий исполняющей среды (начиная c 4.0) и одна из старых версий (CLR1.1 или CLR2.0). Старые статические функции (CorBindTo*) объявлены устаревшими, вместо них предлагается использовать функцию CLRCreateInstance и методы интерфейсов ICLRMetaHost и ICLRRuntimeInfo.

Управление работой CLR

В CLR Hosting API можно выделить две большие группы интерфейсов:

  • интерфейсы хост-диспетчеров (host managers), их имена начинаются с префикса IHost, они реализуются на стороне неуправляемого приложения и вызываются CLR;
  • интерфейсы диспетчеров CLR (CLR managers), которые реализуются CLR и вызываются на стороне неуправляемого приложения.

При помощи этих интерфейсов можно контролировать такие аспекты работы CLR, как:

  • работа с памятью (ICLRGCManager, ICLRMemoryNotificationCallback, IHostGCManager, IHostMAlloc, IHostMemoryManager);
  • работа с потоками(ICLRTaskManager, IHostTaskManager, IHostThreadPoolManger);
  • синхронизация потоков(ICLRSyncManager, IHostCrst, IHostSyncManager, IHostManualEvent);
  • загрузка сборок (ICLRAssemblyIdentityManager, IHostAssemblyStore, IHostAssemblyManager);
  • настройка CLR (ICLRControl, ICLRPolicyManager, ICLRDebugManager).

Пример использования CLR Hosting API

#include <metahost.h>
#pragma comment(lib, "mscoree.lib")

int wmain( int argc, wchar_t** argv )
{
 ICLRMetaHost *pMetaHost = nullptr;
 ICLRRuntimeInfo *pCLRRuntimeInfo = nullptr;
 ICLRRuntimeHost *pCLRRuntimeHost = nullptr;
 __try
 {
 HRESULT hr;
 // Получаем среду выполнения
 hr = CLRCreateInstance( CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost );
 if ( FAILED(hr) ) return -1;

hr = pMetaHost->GetRuntime( L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pCLRRuntimeInfo );

BOOL bCLRIsLoadable;
 hr = pCLRRuntimeInfo->IsLoadable( &bCLRIsLoadable );
 if ( FAILED( hr ) ) return -1;
 if ( ! bCLRIsLoadable ) return -1;
 
 hr = pCLRRuntimeInfo->GetInterface( CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pCLRRuntimeHost );
 if ( FAILED(hr) ) return -1; 
 
 // Запускаем CLR
 hr = pCLRRuntimeHost->Start();
 if ( FAILED(hr) ) return -1; 

// Загружаем сборку и вызываем в ней метод
 DWORD nRet;
 hr = pCLRRuntimeHost->ExecuteInDefaultAppDomain( L"TestLib.dll", L"TestLib.Foo", L"Bar", L"", &nRet );
 if ( FAILED(hr) ) return -1; 
 }
 __finally
 {
 // Освобождаем ресурсы
 if ( pCLRRuntimeHost ) { pCLRRuntimeHost->Release(); pCLRRuntimeHost = nullptr; }
 if ( pCLRRuntimeInfo ) { pCLRRuntimeInfo->Release(); pCLRRuntimeInfo = nullptr; }
 if ( pMetaHost ) { pMetaHost->Release(); pMetaHost = nullptr; }
 }
 return 0;
}

Литература

Для всех источников, кроме первого, есть переводы на русский язык.

Теги: рубрика Интернет