Hosten von .NET CoreHosting .NET Core

Wie alle verwalteten Codes werden .NET Core-Anwendungen von einem Host ausgeführt.Like all managed code, .NET Core applications are executed by a host. Der Host ist verantwortlich für das Starten der Laufzeit (einschließlich Komponenten wie die JIT und Garbage Collector), das Erstellen der AppDomains und das Aufrufen von verwalteten Einstiegspunkten.The host is responsible for starting the runtime (including components like the JIT and garbage collector), creating AppDomains, and invoking managed entry points.

Das Hosten der Laufzeit von .NET Core ist ein erweitertes Szenario, und in den meisten Fällen brauchen sich .NET Core-Entwickler nicht darum kümmern, da die Buildprozesse von .NET Core einen Standardhost bereitstellen, der die .NET Core-Anwendungen ausführt.Hosting the .NET Core runtime is an advanced scenario and, in most cases, .NET Core developers don't need to worry about hosting because .NET Core build processes provide a default host to run .NET Core applications. Unter speziellen Umständen kann es jedoch hilfreich sein, die .NET Core-Laufzeit explizit zu hosten, entweder als Mittel zum Aufrufen von verwalteten Codes in einem nativen Prozess oder um mehr Kontrolle über die Funktionsweise der Laufzeit zu erhalten.In some specialized circumstances, though, it can be useful to explicitly host the .NET Core runtime, either as a means of invoking managed code in a native process or in order to gain more control over how the runtime works.

Dieser Artikel bietet einen Überblick über die erforderlichen Schritte zum Starten der .NET Core-Laufzeit aus nativem Code, Erstellen einer ersten Anwendungsdomäne (AppDomain), und Ausführen von darin enthaltenem, verwalteten Code.This article gives an overview of the steps necessary to start the .NET Core runtime from native code, create an initial application domain (AppDomain), and execute managed code in it.

Erforderliche KomponentenPrerequisites

Da Hosts native Anwendungen sind, wird in diesem Lernprogramm das Erstellen einer C++-Anwendung zum Hosten auf .NET Core behandelt.Because hosts are native applications, this tutorial will cover constructing a C++ application to host .NET Core. Sie benötigen eine C++-Entwicklungsumgebung (z.B. von Visual Studio).You will need a C++ development environment (such as that provided by Visual Studio).

Sie sollten außerdem über eine einfache .NET Core-Anwendung zum Testen des Hosts verfügen, daher sollten Sie die .NET Core SDK installieren und eine kleine .NET Core-Testanwendung erstellen (z.B. die Anwendung „Hello World“).You will also want a simple .NET Core application to test the host with, so you should install the .NET Core SDK and build a small .NET Core test app (such as a 'Hello World' app). Die „Hello World“-Anwendung, die von der neuen Projektvorlage der .NET Core-Konsole erstellt wird, ist ausreichend.The 'Hello World' app created by the new .NET Core console project template is sufficient.

In diesem Tutorial und dem zugehörigen Beispiel wird ein Windows-Host erstellt, jedoch finden Sie in den Hinweisen am Ende dieses Artikels Informationen zum Hosten unter Unix.This tutorial and its associated sample build a Windows host; see the notes at the end of this article about hosting on Unix.

Erstellen des HostsCreating the host

Ein Beispielhost zur Veranschaulichung der Schritte in diesem Artikel steht in unserem Repository „dotnet/docs“ auf GitHub.A sample host demonstrating the steps outlined in this article is available in the dotnet/docs GitHub repository. Kommentare in der Beispieldatei host.cpp ordnen die nummerierten Schritte in diesem Tutorial ihrer Position im Beispiel deutlich zu.Comments in the sample's host.cpp file clearly associate the numbered steps from this tutorial with where they're performed in the sample. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.For download instructions, see Samples and Tutorials.

Bedenken Sie, dass der Beispielhost zu Lernzwecken gedacht und somit bei der Fehlerüberprüfung nachsichtig ist und bessere Lesbarkeit über Effizienz stellt.Keep in mind that the sample host is meant to be used for learning purposes, so it is light on error checking and is designed to emphasize readability over efficiency. Weitere echte Hostbeispiele finden Sie in der Repository dotnet/coreclr.More real-world host samples are available in the dotnet/coreclr repository. Vor allem der CoreRun-Host ist ein guter allgemeiner Host, den Sie nach den einfacheren Beispielen studieren können.The CoreRun host, in particular, is a good general-purpose host to study after reading through the simpler sample.

Ein Hinweis zur mscoree.hA note about mscoree.h

Die primäre .NET Core-Hostingschnittstelle (ICLRRuntimeHost2) ist in MSCOREE. IDL definiert.The primary .NET Core hosting interface (ICLRRuntimeHost2) is defined in MSCOREE.IDL. MIDL erzeugt eine Headerversion dieser Datei (mscoree.h), auf die Ihr Host verweisen muss, wenn die .NET Core-Laufzeit erstellt wird.A header version of this file (mscoree.h), which your host will need to reference, is produced via MIDL when the .NET Core runtime is built. Wenn Sie die .NET Core-Laufzeit nicht erstellen möchten, steht mscoree.h auch als vorgefertigter Header im Repository Dotnet/Coreclr zur Verfügung.If you do not want to build the .NET Core runtime, mscoree.h is also available as a pre-built header in the dotnet/coreclr repository. Hinweise zum Erstellen der .NET Core-Laufzeit finden Sie in der GitHub-Repository.Instructions on building the .NET Core runtime can be found in its GitHub repository.

Schritt 1: Ermitteln des verwalteten EinstiegspunktsStep 1 - Identify the managed entry point

Nach Verweisen auf die erforderlichen Header (z.B. mscoree.h und stdio.h), muss ein .NET Core-Host als eine der ersten Aktionen den verwalteten Einstiegspunkt suchen, den er verwenden wird.After referencing necessary headers (mscoree.h and stdio.h, for example), one of the first things a .NET Core host must do is locate the managed entry point it will be using. In unserem Beispielhost wird nur das erste Befehlszeilenargument als Pfad zu einer verwalteten Binärdatei verwendet, deren main-Methode ausgeführt wird.In our sample host, this is done by just taking the first command line argument to our host as the path to a managed binary whose main method will be executed.

// The managed application to run should be the first command-line parameter.
// Subsequent command line parameters will be passed to the managed app later in this host.
wchar_t targetApp[MAX_PATH];
GetFullPathNameW(argv[1], MAX_PATH, targetApp, NULL);

Schritt 2: Suchen und Laden von CoreCLR.dllStep 2 - Find and load CoreCLR.dll

Die .NET Core Runtime-APIs befinden sich in CoreCLR.dll (unter Windows).The .NET Core runtime APIs are in CoreCLR.dll (on Windows). Um unsere Hostingschnittstelle (ICLRRuntimeHost2) abzurufen, ist es erforderlich, CoreCLR.dll zu suchen und zu laden.To get our hosting interface (ICLRRuntimeHost2), it's necessary to find and load CoreCLR.dll. Es obliegt dem Host, eine Konvention für das Auffinden von CoreCLR.dll zu definieren.It is up to the host to define a convention for how it will locate CoreCLR.dll. Einige Hosts erwarten, dass die Datei in einem bekannten, computerweiten Speicherort (z.B. %programfiles%\dotnet\shared\Microsoft.NETCore.App\1.1.0) vorhanden ist.Some hosts expect the file to be present in a well-known machine-wide location (such as %programfiles%\dotnet\shared\Microsoft.NETCore.App\1.1.0). Andere erwarten, dass CoreCLR.dll von einem anderen Speicherort neben dem Host selbst oder der zu hostenden Anwendung geladen wird.Others expect that CoreCLR.dll will be loaded from a location next to either the host itself or the app to be hosted. Noch andere konsultieren möglicherweise eine Umgebungsvariable, um die Bibliothek zu finden.Still others might consult an environment variable to find the library.

Unter Linux oder Mac ist die Core Runtime Library jeweils libcoreclr.so oder libcoreclr.dylib.On Linux or Mac, the core runtime library is libcoreclr.so or libcoreclr.dylib, respectively.

Unser Beispielhost prüft einige gängige Speicherorte für CoreCLR.dll.Our sample host probes a few common locations for CoreCLR.dll. Wenn er gefunden wird, muss er geladen werden, über LoadLibrary (oder dlopen auf Linux/Mac).Once found, it must be loaded via LoadLibrary (or dlopen on Linux/Mac).

HMODULE ret = LoadLibraryExW(coreDllPath, NULL, 0);

Schritt 3: Abrufen einer ICLRRuntimeHost2-InstanzStep 3 - Get an ICLRRuntimeHost2 Instance

Die ICLRRuntimeHost2-Hostingschnittstelle wird durch den Aufruf von GetProcAddress (oder dlsym auf Linux/Mac) auf GetCLRRuntimeHost abgerufen, und dann wird diese Funktion aufgerufen.The ICLRRuntimeHost2 hosting interface is retrieved by calling GetProcAddress (or dlsym on Linux/Mac) on GetCLRRuntimeHost, and then invoking that function.

ICLRRuntimeHost2* runtimeHost;

FnGetCLRRuntimeHost pfnGetCLRRuntimeHost =
	(FnGetCLRRuntimeHost)::GetProcAddress(coreCLRModule, "GetCLRRuntimeHost");

if (!pfnGetCLRRuntimeHost)
{
	printf("ERROR - GetCLRRuntimeHost not found");
	return -1;
}

// Get the hosting interface
HRESULT hr = pfnGetCLRRuntimeHost(IID_ICLRRuntimeHost2, (IUnknown**)&runtimeHost);

Schritt 4: Festlegen von Startflags und Starten der LaufzeitStep 4 - Setting startup flags and starting the runtime

Mit ICLRRuntimeHost2 können wir jetzt die laufzeitweiten Startflags angeben und die Laufzeit starten.With an ICLRRuntimeHost2 in-hand, we can now specify runtime-wide startup flags and start the runtime. Startflags bestimmen, welchen Garbage Collector (GC) Sie verwenden (gleichzeitig oder Server), ob wir eine einzelne AppDomain oder mehrere verwenden, und welche Ladeoptimierungsrichtlinie (für domänenneutrales Laden von Assemblys) wir verwenden.Startup flags will determine which garbage collector (GC) to use (concurrent or server), whether we will use a single AppDomain or multiple AppDomains, and what loader optimization policy to use (for domain-neutral loading of assemblies).

hr = runtimeHost->SetStartupFlags(
	// These startup flags control runtime-wide behaviors.
	// A complete list of STARTUP_FLAGS can be found in mscoree.h,
	// but some of the more common ones are listed below.
	static_cast<STARTUP_FLAGS>(
		// STARTUP_FLAGS::STARTUP_SERVER_GC |								// Use server GC
		// STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN |		// Maximize domain-neutral loading
		// STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST |	// Domain-neutral loading for strongly-named assemblies
		STARTUP_FLAGS::STARTUP_CONCURRENT_GC |						// Use concurrent GC
		STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN |					// All code executes in the default AppDomain 
																	// (required to use the runtimeHost->ExecuteAssembly helper function)
		STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN	// Prevents domain-neutral loading
	)
);

Die Laufzeit wird durch einen Aufruf der Start-Funktion gestartet.The runtime is started with a call to the Start function.

hr = runtimeHost->Start();

Schritt 5: Vorbereiten der Einstellungen der AppDomainStep 5 - Preparing AppDomain settings

Nachdem die Laufzeit gestartet wurde, möchten wir eine AppDomain einrichten.Once the runtime is started, we will want to set up an AppDomain. Es gibt jedoch eine Reihe von Optionen, die beim Erstellen einer .NET AppDomain angegeben werden müssen, daher ist es erforderlich, diese zuerst vorzubereiten.There are a number of options that must be specified when creating a .NET AppDomain, however, so it's necessary to prepare those first.

AppDomain-Flags geben das Verhalten der AppDomain im Zusammenhang mit der Sicherheit und Interoperabilität an.AppDomain flags specify AppDomain behaviors related to security and interop. Ältere Silverlight-Hosts verwendeten diese Einstellungen für Sandbox-Benutzercodes, aber die meisten modernen .NET Core-Hosts führen den Benutzercode als voll vertrauenswürdig und interoperabel aus.Older Silverlight hosts used these settings to sandbox user code, but most modern .NET Core hosts run user code as full trust and enable interop.

int appDomainFlags =
	// APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS |		// Do not pump messages during wait
	// APPDOMAIN_SECURITY_SANDBOXED |					// Causes assemblies not from the TPA list to be loaded as partially trusted
	APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS |			// Enable platform-specific assemblies to run
	APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP |	// Allow PInvoking from non-TPA assemblies
	APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT;			// Entirely disables transparency checks 

Nach der Entscheidung, welche der AppDomain-Flags verwendet werden, müssen die AppDomain-Eigenschaften definiert werden.After deciding which AppDomain flags to use, AppDomain properties must be defined. Die Eigenschaften sind Schlüssel-/Wertpaare von Zeichenfolgen.The properties are key/value pairs of strings. Viele der Eigenschaften beziehen sich auf die Art, mit der die AppDomain Assemblys laden wird.Many of the properties relate to how the AppDomain will load assemblies.

Allgemeine AppDomain-Eigenschaften beinhalten:Common AppDomain properties include:

  • TRUSTED_PLATFORM_ASSEMBLIES Dies ist eine Liste von Assemblypfaden (getrennt durch „;“ unter Windows und „:“ unter Unix), die AppDomains laden sollten und denen sie komplett vertrauen (auch in teilweise vertrauenswürdigen Domänen).TRUSTED_PLATFORM_ASSEMBLIES This is a list of assembly paths (delimited by ';' on Windows and ':' on Unix) which the AppDomain should prioritize loading and give full trust to (even in partially-trusted domains). Diese Liste soll „Framework“-Assemblys und andere vertrauenswürdige Module, ähnlich dem GAC in .NET Framework-Szenarios, enthalten.This list is meant to contain 'Framework' assemblies and other trusted modules, similar to the GAC in .NET Framework scenarios. Einige Hosts platzieren eine Bibliothek neben coreclr.dll in dieser Liste, andere haben andere hartcodierte Manifeste, die vertrauenswürdige Assemblys für ihre Zwecke listen.Some hosts will put any library next to coreclr.dll on this list, others have hard-coded manifests listing trusted assemblies for their purposes.
  • APP_PATHS Dies ist eine Liste der Pfade, in denen nach einer Assembly gesucht werden soll, wenn sie in der Liste der vertrauenswürdigen Plattformassemblys (TPA) nicht gefunden werden kann.APP_PATHS This is a list of paths to probe in for an assembly if it can't be found in the trusted platform assemblies (TPA) list. Diese Pfade sollen die Speicherorte sein, in denen die Assemblys der Benutzer gefunden werden können.These paths are meant to be the locations where users' assemblies can be found. In einer Sandbox-AppDomain erhalten Assemblys von diesen Pfaden nur teilweise Vertrauenswürdigkeit.In a sandboxed AppDomain, assemblies loaded from these paths will only be granted partial trust. Allgemeine APP_PATH-Pfade enthalten den Pfad, von dem die Zielanwendung geladen wurde oder andere Speicherorte, in denen Benutzerressourcen vorhanden sind.Common APP_PATH paths include the path the target app was loaded from or other locations where user assets are known to live.
  • APP_NI_PATHS Diese Liste ist APP_PATHS sehr ähnlich, außer dass es Pfade sein sollten, in denen nach nativen Images gesucht werden sollen.APP_NI_PATHS This list is very similar to APP_PATHS except that it's meant to be paths that will be probed for native images.
  • NATIVE_DLL_SEARCH_DIRECTORIES Diese Eigenschaft ist eine Liste der Pfade, die das Ladeprogramm durchsuchen sollte, wenn es nach nativen DLLs sucht, die über p/invoke aufgerufen werden.NATIVE_DLL_SEARCH_DIRECTORIES This property is a list of paths the loader should probe when looking for native DLLs called via p/invoke.
  • PLATFORM_RESOURCE_ROOTS Diese Liste enthält die Pfade, in denen nach Assemblys der Ressourcensatelliten (in kulturspezifischen Unterverzeichnissen) gesucht wird.PLATFORM_RESOURCE_ROOTS This list includes paths to probe in for resource satellite assemblies (in culture-specific sub-directories).
  • AppDomainCompatSwitch Diese Zeichenfolge gibt an, welche Kompatibilitätsquirks für Assemblys ohne eine explizite Zielframeworkmoniker (ein Attribut auf Assemblyebene, das angibt, welches Framework eine Assembly ausführen soll) verwendet werden sollen.AppDomainCompatSwitch This string specifies which compatibility quirks should be used for assemblies without an explicit Target Framework Moniker (an assembly-level attribute indicating which Framework an assembly is meant to run against). Dies sollte in der Regel auf "UseLatestBehaviorWhenTFMNotSpecified" festgelegt werden, aber einige Hosts möchten stattdessen ältere Silverlight- oder Windows Phone-Kompatibilitätsquirks abrufen.Typically, this should be set to "UseLatestBehaviorWhenTFMNotSpecified" but some hosts may prefer to get older Silverlight or Windows Phone compatibility quirks, instead.

In unserem einfache Beispielhost sind diese Eigenschaften wie folgt eingerichtet:In our simple sample host, these properties are set up as follows:

// TRUSTED_PLATFORM_ASSEMBLIES
// "Trusted Platform Assemblies" are prioritized by the loader and always loaded with full trust.
// A common pattern is to include any assemblies next to CoreCLR.dll as platform assemblies.
// More sophisticated hosts may also include their own Framework extensions (such as AppDomain managers)
// in this list.
int tpaSize = 100 * MAX_PATH; // Starting size for our TPA (Trusted Platform Assemblies) list
wchar_t* trustedPlatformAssemblies = new wchar_t[tpaSize];
trustedPlatformAssemblies[0] = L'\0';

// Extensions to probe for when finding TPA list files
wchar_t *tpaExtensions[] = {
	L"*.dll",
	L"*.exe",
	L"*.winmd"
};

// Probe next to CoreCLR.dll for any files matching the extensions from tpaExtensions and
// add them to the TPA list. In a real host, this would likely be extracted into a separate function
// and perhaps also run on other directories of interest.
for (int i = 0; i < _countof(tpaExtensions); i++)
{
	// Construct the file name search pattern
	wchar_t searchPath[MAX_PATH];
	wcscpy_s(searchPath, MAX_PATH, coreRoot);
	wcscat_s(searchPath, MAX_PATH, L"\\");
	wcscat_s(searchPath, MAX_PATH, tpaExtensions[i]);

	// Find files matching the search pattern
	WIN32_FIND_DATAW findData;
	HANDLE fileHandle = FindFirstFileW(searchPath, &findData);

	if (fileHandle != INVALID_HANDLE_VALUE)
	{
		do
		{
			// Construct the full path of the trusted assembly
			wchar_t pathToAdd[MAX_PATH];
			wcscpy_s(pathToAdd, MAX_PATH, coreRoot);
			wcscat_s(pathToAdd, MAX_PATH, L"\\");
			wcscat_s(pathToAdd, MAX_PATH, findData.cFileName);

			// Check to see if TPA list needs expanded
			if (wcslen(pathToAdd) + (3) + wcslen(trustedPlatformAssemblies) >= tpaSize)
			{
				// Expand, if needed
				tpaSize *= 2;
				wchar_t* newTPAList = new wchar_t[tpaSize];
				wcscpy_s(newTPAList, tpaSize, trustedPlatformAssemblies);
				trustedPlatformAssemblies = newTPAList;
			}

			// Add the assembly to the list and delimited with a semi-colon
			wcscat_s(trustedPlatformAssemblies, tpaSize, pathToAdd);
			wcscat_s(trustedPlatformAssemblies, tpaSize, L";");

			// Note that the CLR does not guarantee which assembly will be loaded if an assembly
			// is in the TPA list multiple times (perhaps from different paths or perhaps with different NI/NI.dll
			// extensions. Therefore, a real host should probably add items to the list in priority order and only
			// add a file if it's not already present on the list.
			//
			// For this simple sample, though, and because we're only loading TPA assemblies from a single path,
			// we can ignore that complication.
		}
		while (FindNextFileW(fileHandle, &findData));
		FindClose(fileHandle);
	}
}


// APP_PATHS
// App paths are directories to probe in for assemblies which are not one of the well-known Framework assemblies
// included in the TPA list.
//
// For this simple sample, we just include the directory the target application is in.
// More complex hosts may want to also check the current working directory or other
// locations known to contain application assets.
wchar_t appPaths[MAX_PATH * 50];

// Just use the targetApp provided by the user and remove the file name
wcscpy_s(appPaths, targetAppPath);


// APP_NI_PATHS
// App (NI) paths are the paths that will be probed for native images not found on the TPA list. 
// It will typically be similar to the app paths.
// For this sample, we probe next to the app and in a hypothetical directory of the same name with 'NI' suffixed to the end.
wchar_t appNiPaths[MAX_PATH * 50];
wcscpy_s(appNiPaths, targetAppPath);
wcscat_s(appNiPaths, MAX_PATH * 50, L";");
wcscat_s(appNiPaths, MAX_PATH * 50, targetAppPath);
wcscat_s(appNiPaths, MAX_PATH * 50, L"NI");


// NATIVE_DLL_SEARCH_DIRECTORIES
// Native dll search directories are paths that the runtime will probe for native DLLs called via PInvoke
wchar_t nativeDllSearchDirectories[MAX_PATH * 50];
wcscpy_s(nativeDllSearchDirectories, appPaths);
wcscat_s(nativeDllSearchDirectories, MAX_PATH * 50, L";");
wcscat_s(nativeDllSearchDirectories, MAX_PATH * 50, coreRoot);


// PLATFORM_RESOURCE_ROOTS
// Platform resource roots are paths to probe in for resource assemblies (in culture-specific sub-directories)
wchar_t platformResourceRoots[MAX_PATH * 50];
wcscpy_s(platformResourceRoots, appPaths);


// AppDomainCompatSwitch
// Specifies compatibility behavior for the app domain. This indicates which compatibility
// quirks to apply if an assembly doesn't have an explicit Target Framework Moniker. If a TFM is
// present on an assembly, the runtime will always attempt to use quirks appropriate to the version
// of the TFM.
// 
// Typically the latest behavior is desired, but some hosts may want to default to older Silverlight
// or Windows Phone behaviors for compatibility reasons.
wchar_t* appDomainCompatSwitch = L"UseLatestBehaviorWhenTFMNotSpecified";

Schritt 6: Erstellen der AppDomainStep 6 - Create the AppDomain

Sobald alle Flags und Eigenschaften der AppDomain vorbereitet sind, kann ICLRRuntimeHost2::CreateAppDomainWithManager zum Einrichten der AppDomain verwendet werden.Once all AppDomain flags and properties are prepared, ICLRRuntimeHost2::CreateAppDomainWithManager can be used to set up the AppDomain. Diese Funktion hat optional einen vollqualifizierten Assemblynamen und Typnamen, die als AppDomain-Manager der Domäne verwendet werden.This function optionally takes a fully qualified assembly name and type name to use as the domain's AppDomain manager. Ein AppDomain-Manager kann einem Host ermöglichen, einige Aspekte des AppDomain-Verhaltens steuern und möglicherweise Einstiegspunkte für den Start von verwaltetem Code bereitzustellen, wenn der Host den Benutzercode nicht direkt aufrufen möchte.An AppDomain manager can allow a host to control some aspects of AppDomain behavior and may provide entry points for launching managed code if the host doesn't intend to invoke user code directly.

DWORD domainId;

// Setup key/value pairs for AppDomain  properties
const wchar_t* propertyKeys[] = {
	L"TRUSTED_PLATFORM_ASSEMBLIES",
	L"APP_PATHS",
	L"APP_NI_PATHS",
	L"NATIVE_DLL_SEARCH_DIRECTORIES",
	L"PLATFORM_RESOURCE_ROOTS",
	L"AppDomainCompatSwitch"
};

// Property values which were constructed in step 5
const wchar_t* propertyValues[] = {
	trustedPlatformAssemblies,
	appPaths,
	appNiPaths,
	nativeDllSearchDirectories,
	platformResourceRoots,
	appDomainCompatSwitch
};

// Create the AppDomain
hr = runtimeHost->CreateAppDomainWithManager(
	L"Sample Host AppDomain",		// Friendly AD name
	appDomainFlags,
	NULL,							// Optional AppDomain manager assembly name
	NULL,							// Optional AppDomain manager type (including namespace)
	sizeof(propertyKeys)/sizeof(wchar_t*),
	propertyKeys,
	propertyValues,
	&domainId);

Schritt 7: Ausführen von verwaltetem Code!Step 7 - Run managed code!

Mit einer laufenden AppDomain kann der Host jetzt verwalteten Code ausführen.With an AppDomain up and running, the host can now start executing managed code. Die einfachste Möglichkeit hierzu ist die Verwendung von ICLRRuntimeHost2::ExecuteAssembly, um die Einstiegspunktmethode für eine verwaltete Assembly aufzurufen.The easiest way to do this is to use ICLRRuntimeHost2::ExecuteAssembly to invoke a managed assembly's entry point method. Beachten Sie, dass diese Funktion nur in Szenarios mit einzelnen Domänen funktioniert.Note that this function only works in single-domain scenarios.

DWORD exitCode = -1;
hr = runtimeHost->ExecuteAssembly(domainId, targetApp, argc - 1, (LPCWSTR*)(argc > 1 ? &argv[1] : NULL), &exitCode);

Wenn ExecuteAssembly nicht den Anforderungen Ihres Hosts entspricht, gibt es eine andere Option, bei der Sie CreateDelegate verwenden, um einen Funktionszeiger zu einer statisch verwalteten Methode zu erstellen.Another option, if ExecuteAssembly doesn't meet your host's needs, is to use CreateDelegate to create a function pointer to a static managed method. Dafür muss der Host die Signatur der Methode kennen, die er aufruft (um den Funktionszeigertyp zu erstellen), aber es gibt dem Host die Flexibilität, einen anderen Code als den Assemblyeingangspunkt aufzurufen.This requires the host to know the signature of the method it is calling into (in order to create the function pointer type) but allows hosts the flexibility to invoke code other than an assembly's entry point.

void *pfnDelegate = NULL;
hr = runtimeHost->CreateDelegate(
  domainId,
  L"HW, Version=1.0.0.0, Culture=neutral",  // Target managed assembly
  L"ConsoleApplication.Program",            // Target managed type
  L"Main",                                  // Target entry point (static method)
  (INT_PTR*)&pfnDelegate);

((MainMethodFp*)pfnDelegate)(NULL);

Step 8: BereinigenStep 8 - Clean up

Schließlich sollte der Host die Umgebung hinter sich bereinigen, indem er AppDomains entlädt, die Laufzeit beendet und den ICLRRuntimeHost2-Verweis freigibt.Finally, the host should clean up after itself by unloading AppDomains, stopping the runtime, and releasing the ICLRRuntimeHost2 reference.

runtimeHost->UnloadAppDomain(domainId, true /* Wait until unload complete */);
runtimeHost->Stop();
runtimeHost->Release();

Zum Hosten von .NET Core unter UnixAbout Hosting .NET Core on Unix

.NET Core ist ein plattformübergreifendes Produkt, das auf Windows, Linux und Macintosh-Betriebssystemen ausgeführt wird..NET Core is a cross-platform product, running on Windows, Linux, and Mac operating systems. Als native Anwendungen werden Hosts für verschiedene Plattformen jedoch einige Unterschiede aufweisen.As native applications, though, hosts for different platforms will have some differences between them. Der oben beschriebene Vorgang zur Verwendung von ICLRRuntimeHost2, womit die Laufzeit gestartet, eine AppDomain erstellt und verwalteter Code ausgeführt wird, sollte auf allen beliebigen unterstützten Betriebssystemen funktionieren.The process described above of using ICLRRuntimeHost2 to start the runtime, create an AppDomain, and execute managed code, should work on any supported operating system. Allerdings kann es umständlich sein, mit den Schnittstellen auf Unix-Plattformen zu arbeiten, die in mscoree.h definiert sind, da bei Mscoree von vielen Win32-Annahmen ausgegangen wird.However, the interfaces defined in mscoree.h can be cumbersome to work with on Unix platforms since mscoree makes many Win32 assumptions.

Um das Hosten auf Unix-Plattformen einfacher zu gestalten, stehen weitere plattformneutrale Hosting-API-Wrapper in coreclrhost.h zur Verfügung.To make hosting on Unix platforms easier, a set of more platform-neutral hosting API wrappers are available in coreclrhost.h.

Ein Beispiel zur Verwendung von coreclrhost.h (statt direkt mscoree.h) sehen Sie in UnixCoreRun-Host.An example of using coreclrhost.h (instead of mscoree.h directly) can be seen in the UnixCoreRun host. Die Schritte zur Verwendung der APIs aus coreclrhost.h als Laufzeithost ähneln den Schritten bei der Verwendung von mscoree.h:The steps to use the APIs from coreclrhost.h to host the runtime are similar to the steps when using mscoree.h:

  1. Identifizieren Sie den auszuführenden verwalteten Code (z.B. aus den Befehlszeilenparametern).Identify the managed code to execute (from command line parameters, for example).
  2. Laden der CoreCLR-Bibliothek.Load the CoreCLR library.
    1. dlopen("./libcoreclr.so", RTLD_NOW | RTLD_LOCAL);
  3. Rufen Sie Funktionszeiger für CoreCLRs Funktionen coreclr_initialize, coreclr_create_delegate, coreclr_execute_assembly und coreclr_shutdown mithilfe von dlsym auf.Get function pointers to CoreCLR's coreclr_initialize, coreclr_create_delegate, coreclr_execute_assembly, and coreclr_shutdown functions using dlsym
    1. coreclr_initialize_ptr coreclr_initialize = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
  4. Einrichten von AppDomain-Eigenschaften (z.B. die TPA-Liste).Set up AppDomain properties (such as the TPA list). Dies ist identisch mit Schritt 5 aus dem mscoree-Workflow oben.This is the same as step 5 from the mscoree workflow, above.
  5. Verwenden Sie coreclr_initialize, um die Laufzeit zu starten und eine AppDomain zu erstellen.Use coreclr_initialize to start the runtime and create an AppDomain. Dadurch wird auch ein hostHandle-Zeiger erstellt, der in Zukunft für das Hosten von Aufrufen verwendet wird.This will also create a hostHandle pointer that will be used in future hosting calls.
    1. Beachten Sie, dass diese Funktion die beiden Schritte 4 und 6 aus dem vorherigen Workflow ausführt.Note that this function performs the roles of both steps 4 and 6 from the previous workflow.
  6. Verwenden Sie entweder coreclr_execute_assembly oder coreclr_create_delegate, um verwalteten Code auszuführen.Use either coreclr_execute_assembly or coreclr_create_delegate to execute managed code. Diese Funktionen sind analog zu den ExecuteAssembly- und CreateDelegate-Funktionen von Mscoree aus Schritt 7 des vorherigen Workflows.These functions are analogous to mscoree's ExecuteAssembly and CreateDelegate functions from step 7 of the previous workflow.
  7. Verwenden Sie coreclr_shutdown, um die AppDomain zu entladen und die Laufzeit herunterzufahren.Use coreclr_shutdown to unload the AppDomain and shut down the runtime.

SchlussfolgerungConclusion

Nachdem Ihr Host erstellt wurde, kann er getestet werden, indem er von der Befehlszeile aus ausgeführt wird und Argumente (z.B. die auszuführende verwaltete Anwendung) übergeben werden, die der Host erwartet.Once your host is built, it can be tested by running it from the command line and passing any arguments (like the managed app to run) the host expects. Beim Angeben der .NET Core-Anwendung, die den Host ausführt, müssen Sie die DLL-Datei verwenden, die von dotnet build erzeugt wurde.When specifying the .NET Core app for the host to run, be sure to use the .dll that is produced by dotnet build. Ausführbare Dateien, die für eigenständige Anwendungen von dotnet publish erstellt wurden, sind tatsächlich die Standardeinstellung des .NET Core-Host (sodass die Anwendung direkt über die Befehlszeile in Hauptszenarios gestartet werden kann); der Benutzercode wird in einer DLL mit dem gleichen Namen kompiliert.Executables produced by dotnet publish for self-contained applications are actually the default .NET Core host (so that the app can be launched directly from the command line in mainline scenarios); user code is compiled into a dll of the same name.

Wenn anfangs Funktionsstörungen auftreten, überprüfen Sie, dass coreclr.dll in dem Speicherort zur Verfügung steht, den der Host erwartet, dass sich alle erforderlichen Framework-Bibliotheken in der TPA-Liste befinden, und dass die CoreCLR-Bitanzahl (32 oder 64 Bit) der Erstellungsart des Host entspricht.If things don't work initially, double-check that coreclr.dll is available in the location expected by the host, that all necessary Framework libraries are in the TPA list, and that CoreCLR's bitness (32- or 64-bit) matches how the host was built.

Das Hosten der Laufzeit von .NET Core ist ein erweitertes Szenario, das für viele Entwickler nicht erforderlich ist, aber für diejenigen, die verwalteten Code von einem nativen Prozess starten müssen, oder die mehr Kontrolle über das Verhalten der .NET Core-Laufzeit benötigen, kann es sehr nützlich sein.Hosting the .NET Core runtime is an advanced scenario that many developers won't require, but for those who need to launch managed code from a native process, or who need more control over the .NET Core runtime's behavior, it can be very useful. Da .NET Core Seite-an-Seite mit sich selbst ausgeführt werden kann, ist es sogar möglich, Hosts zu erstellen, die mehrere Versionen der Laufzeit von .NET Core initialisieren und starten und im selben Prozess Anwendungen auf allen ausführen.Because .NET Core is able to run side-by-side with itself, it's even possible to create hosts which initialize and start multiple versions of the .NET Core runtime and execute apps on all of them in the same process.