Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Net als alle beheerde code worden .NET-toepassingen uitgevoerd door een host. De host is verantwoordelijk voor het starten van de runtime (inclusief onderdelen zoals de JIT en garbagecollector) en het aanroepen van beheerde toegangspunten.
Het hosten van de .NET-runtime is een geavanceerd scenario en in de meeste gevallen hoeven .NET-ontwikkelaars zich geen zorgen te maken over hosting, omdat .NET-buildprocessen een standaardhost bieden voor het uitvoeren van .NET-toepassingen. In sommige gespecialiseerde omstandigheden kan het echter handig zijn om de .NET-runtime expliciet te hosten, ofwel als een manier om beheerde code aan te roepen in een systeemeigen proces of om meer controle te krijgen over de werking van de runtime.
Dit artikel bevat een overzicht van de stappen die nodig zijn om de .NET-runtime te starten vanuit systeemeigen code en beheerde code erin uit te voeren.
Vereiste voorwaarden
Omdat hosts systeemeigen toepassingen zijn, wordt in deze zelfstudie beschreven hoe u een C++-toepassing maakt voor het hosten van .NET. U hebt een C++-ontwikkelomgeving nodig (zoals die van Visual Studio).
U moet ook een .NET-onderdeel bouwen om de host te testen, dus moet u de .NET SDK installeren. Het bevat de benodigde headers en bibliotheken waarmee u een koppeling kunt maken. In Windows met de .NET 8 SDK kunt u bijvoorbeeld de bestanden vinden in C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\8.0.4\runtimes\win-x64\native
.
Het hosten van API's
Het hosten van de .NET-runtime in .NET Core 3.0 en hoger gebeurt met de API's van de nethost
- en hostfxr
-bibliotheken. Deze toegangspunten verwerken de complexiteit van het zoeken en instellen van de runtime voor initialisatie en het starten van een beheerde toepassing en het aanroepen van een statische beheerde methode.
Vóór .NET Core 3.0 was de enige optie voor het hosten van de runtime via de coreclrhost.h
API. Deze hosting-API is nu verouderd en mag niet worden gebruikt voor het hosten van .NET Core 3.0 en hogere runtimes.
Een host maken met behulp van nethost.h
en hostfxr.h
Een voorbeeldhost die de stappen laat zien die in de onderstaande zelfstudie worden beschreven, is beschikbaar in de GitHub-opslagplaats dotnet/samples. Opmerkingen in het voorbeeld koppelen duidelijk de genummerde stappen uit deze zelfstudie aan waar ze in het voorbeeld worden uitgevoerd. Zie voorbeelden en zelfstudiesvoor downloadinstructies.
Houd er rekening mee dat de voorbeeldhost bedoeld is om te worden gebruikt voor leerdoeleinden, dus het heeft minimale foutcontrole en is ontworpen om leesbaarheid boven efficiëntie te stellen.
In de volgende stappen wordt beschreven hoe u de bibliotheken nethost
en hostfxr
kunt gebruiken om de .NET-runtime te starten in een systeemeigen toepassing en een beheerde statische methode aan te roepen. In het voorbeeld worden de nethost
headers en bibliotheken en de coreclr_delegates.h
en hostfxr.h
headers gebruikt die zijn geïnstalleerd met de .NET SDK.
Stap 1: hostfxr
laden en de geëxporteerde hostingfuncties ophalen
De nethost
bibliotheek biedt de get_hostfxr_path
-functie om de hostfxr
bibliotheek te lokaliseren. De hostfxr
bibliotheek bevat functies voor het hosten van de .NET-runtime. De volledige lijst met functies vindt u in hostfxr.h
en het systeemeigen ontwerpdocument voor hosting. Het voorbeeld en deze zelfstudie gebruiken het volgende:
-
hostfxr_initialize_for_runtime_config
: initialiseert een hostcontext en bereidt zich voor op initialisatie van de .NET-runtime met behulp van de opgegeven runtimeconfiguratie. -
hostfxr_get_runtime_delegate
: Haalt een gemachtigde op voor runtime-functionaliteit. -
hostfxr_close
: Hiermee sluit u een hostcontext.
De hostfxr
bibliotheek wordt gevonden met behulp van get_hostfxr_path
API uit nethost
de bibliotheek. Het wordt vervolgens geladen en de exporten worden opgehaald.
// 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);
}
In het voorbeeld wordt gebruikgemaakt van het volgende:
#include <nethost.h>
#include <coreclr_delegates.h>
#include <hostfxr.h>
Deze bestanden zijn te vinden op de volgende locaties:
- 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
Of als u de .NET 8 SDK hebt geïnstalleerd in Windows:
C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Host.win-x64\8.0.4\runtimes\win-x64\native
Stap 2: de .NET-runtime initialiseren en starten
De hostfxr_initialize_for_runtime_config
functies hostfxr_get_runtime_delegate
initialiseren en starten de .NET-runtime met behulp van de runtimeconfiguratie voor het beheerde onderdeel dat wordt geladen. De hostfxr_get_runtime_delegate
functie wordt gebruikt om een runtime-delegate op te halen waarmee een beheerde assembly kan worden geladen en een functiepointer naar een statische methode in die assembly verkregen kan worden.
// 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;
}
Stap 3: beheerde assembly laden en functiepointer ophalen naar een beheerde methode
De runtime-gemachtigde wordt aangeroepen om de beheerde assembly te laden en een functiepointer op te halen naar een beheerde methode. Deze delegate vereist het assemblypad, de typenaam en de methodenaam als invoer en retourneert een functie-aanwijzer die kan worden gebruikt om de beheerde methode aan te roepen.
// 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);
Als u de naam van het gemachtigde type doorgeeft nullptr
bij het aanroepen van de runtime-gemachtigde, gebruikt het voorbeeld een standaardhandtekening voor de beheerde methode:
public delegate int ComponentEntryPoint(IntPtr args, int sizeBytes);
Een andere handtekening kan worden gebruikt door de naam van het gemachtigde type op te geven bij het aanroepen van de runtime-gemachtigde.
Stap 4: Beheerde code uitvoeren!
De systeemeigen host kan nu de beheerde methode aanroepen en de gewenste parameters doorgeven.
lib_args args
{
STR("from host!"),
i
};
hello(&args, sizeof(args));
Beperkingen
Slechts één runtime kan binnen één proces worden geladen. Als de hostfxr_initialize_for_runtime_config
API wordt aangeroepen wanneer een runtime al is geladen, wordt gecontroleerd of de bestaande runtime compatibel is met de opgegeven initialisatieparameters. Indien compatibel, wordt de bestaande runtime gebruikt en als deze niet compatibel is, retourneert de API een fout.