Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Как и весь управляемый код, приложения .NET выполняются узлом. Хост отвечает за запуск среды выполнения (включая такие компоненты, как JIT и сборщик мусора) и вызов управляемых точек входа.
Хостинг среды выполнения .NET — это расширенный сценарий, и в большинстве случаев разработчикам .NET не нужно беспокоиться о хостинге, так как процессы сборки .NET предоставляют хост по умолчанию для запуска приложений .NET. Однако в некоторых специализированных обстоятельствах может быть полезно явно разместить среду выполнения .NET как средство вызова управляемого кода в собственном процессе, так и для получения большего контроля над тем, как работает среда выполнения.
В этой статье приводятся общие сведения о шагах, необходимых для запуска среды выполнения .NET из машинного кода и выполнения управляемого кода в нем.
Предпосылки
Поскольку хосты являются независимыми приложениями, в этом руководстве рассматривается создание приложения C++ для хостинга .NET. Вам нужна среда разработки C++ (например, предоставляемая Visual Studio).
Кроме того, необходимо создать компонент .NET для тестирования узла, поэтому необходимо установить последний пакет SDK для .NET. Он включает необходимые заголовки и библиотеки для линковки.
Размещение API-интерфейсов
Размещение среды выполнения .NET осуществляется с помощью API библиотек nethost и hostfxr. Эти точки входа обрабатывают сложность поиска и настройки среды выполнения для инициализации и позволяют запускать управляемое приложение и вызывать статический управляемый метод.
Это важно
nethost и hostfxr API хостинга поддерживают только развертывания, зависящие от фреймворка. Развертывания автономного типа следует рассматривать как отдельные исполняемые файлы. Если вы оцениваете модели развертывания для приложения, используйте зависимое от платформы развертывание, чтобы обеспечить совместимость с этими собственными API размещения.
Создание узла с помощью nethost.h и hostfxr.h
Пример узла, демонстрирующий шаги, описанные в приведенном ниже руководстве, доступен в репозитории dotnet/samples GitHub. Примечания в примере четко связывают нумерованные шаги из этого руководства с тем, где они выполняются в примере. Инструкции по скачиванию смотрите в разделах Образцы и руководства.
Имейте в виду, что образцовый хост предназначен для обучения, поэтому он легковесен в проверке ошибок и подчеркивающий удобочитаемость за счет эффективности.
Ниже описано, как использовать nethost и hostfxr библиотеки для запуска среды выполнения .NET в собственном приложении и вызова управляемого статического метода. В примере используются nethost заголовки и библиотеки, а также coreclr_delegates.h и hostfxr.h заголовки, установленные с пакетом SDK для .NET.
Шаг 1. Загрузите hostfxr и получите экспортированные функции хостинга
Библиотека nethost предоставляет функцию get_hostfxr_path для поиска библиотеки hostfxr . Библиотека hostfxr предоставляет функции для размещения среды выполнения .NET. Полный список функций можно найти в hostfxr.h и в документе проектирования нативного размещения. В примере и этом руководстве используется следующее:
-
hostfxr_initialize_for_runtime_config: инициализирует контекст узла и готовится к инициализации среды выполнения .NET с помощью указанной конфигурации среды выполнения. -
hostfxr_get_runtime_delegate: получает делегат для функциональности среды выполнения. -
hostfxr_close: закрывает контекст узла.
Библиотека hostfxr найдена с помощью get_hostfxr_path API из nethost библиотеки. Затем его загружают и извлекают экспорт.
// Using the nethost library, discover the location of hostfxr and get exports
bool load_hostfxr()
{
// Pre-allocate a large buffer for the path to hostfxr
char_t buffer[MAX_PATH];
size_t buffer_size = sizeof(buffer) / sizeof(char_t);
int rc = get_hostfxr_path(buffer, &buffer_size, nullptr);
if (rc != 0)
return false;
// Load hostfxr and get desired exports
void *lib = load_library(buffer);
init_fptr = (hostfxr_initialize_for_runtime_config_fn)get_export(lib, "hostfxr_initialize_for_runtime_config");
get_delegate_fptr = (hostfxr_get_runtime_delegate_fn)get_export(lib, "hostfxr_get_runtime_delegate");
close_fptr = (hostfxr_close_fn)get_export(lib, "hostfxr_close");
return (init_fptr && get_delegate_fptr && close_fptr);
}
В примере используются следующие компоненты:
#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>
Эти файлы можно найти в следующих расположениях:
- https://github.com/dotnet/runtime/blob/main/src/native/corehost/nethost/nethost.h
- https://github.com/dotnet/runtime/blob/main/src/native/corehost/coreclr_delegates.h
- https://github.com/dotnet/runtime/blob/main/src/native/corehost/hostfxr.h
Шаг 2. Инициализация и запуск среды выполнения .NET
Функции hostfxr_initialize_for_runtime_config и hostfxr_get_runtime_delegate инициализируют и запускают среду выполнения .NET с использованием конфигурации среды выполнения для управляемого компонента, который будет загружен. Эта hostfxr_get_runtime_delegate функция используется для получения делегата среды выполнения, который позволяет загружать управляемую сборку и получать указатель функции на статический метод в этой сборке.
// Load and initialize .NET Core and get desired function pointer for scenario
load_assembly_and_get_function_pointer_fn get_dotnet_load_assembly(const char_t *config_path)
{
// Load .NET Core
void *load_assembly_and_get_function_pointer = nullptr;
hostfxr_handle cxt = nullptr;
int rc = init_fptr(config_path, nullptr, &cxt);
if (rc != 0 || cxt == nullptr)
{
std::cerr << "Init failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return nullptr;
}
// Get the load assembly function pointer
rc = get_delegate_fptr(
cxt,
hdt_load_assembly_and_get_function_pointer,
&load_assembly_and_get_function_pointer);
if (rc != 0 || load_assembly_and_get_function_pointer == nullptr)
std::cerr << "Get delegate failed: " << std::hex << std::showbase << rc << std::endl;
close_fptr(cxt);
return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}
Шаг 3. Загрузка управляемой сборки и получение указателя на функцию для управляемого метода
Делегат среды выполнения вызывается для загрузки управляемой сборки и получения указателя функции на управляемый метод. Делегату требуется путь сборки, имя типа и имя метода в качестве входных данных и возвращает указатель функции, который можно использовать для вызова управляемого метода.
// Function pointer to managed delegate
component_entry_point_fn hello = nullptr;
int rc = load_assembly_and_get_function_pointer(
dotnetlib_path.c_str(),
dotnet_type,
dotnet_type_method,
nullptr /*delegate_type_name*/,
nullptr,
(void**)&hello);
Передавая nullptr как имя типа делегата при вызове делегата среды выполнения, в примере используется сигнатура по умолчанию для управляемого метода.
public delegate int ComponentEntryPoint(IntPtr args, int sizeBytes);
Другую сигнатуру можно использовать, указав имя типа делегата при вызове делегата среды выполнения.
Шаг 4. Запуск управляемого кода!
Теперь нативный хост может вызвать управляемый метод и передать ему необходимые параметры.
lib_args args
{
STR("from host!"),
i
};
hello(&args, sizeof(args));
Ограничения
В одном процессе можно загрузить только одну среду выполнения.
hostfxr_initialize_for_runtime_config Если API вызывается при загрузке среды выполнения, он проверяет, совместима ли существующая среда выполнения с указанными параметрами инициализации. В случае совместимости существующая среда выполнения будет использоваться и, если она не совместима, API вернет сбой.