Хостинг CLR в неуправляемом приложении
.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; }
Литература
- Steven Pratschner, Customizing the Microsoft .NET Framework Common Language Runtime
- Jeffrey Richter, CLR Via C#
- CLR Inside out: CLR Hosting APIs, MSDN Magazine, August 2006
- CLR Inside out: In-Process Side-by-Side, MSDN Magazine, December 2009
Для всех источников, кроме первого, есть переводы на русский язык.