Laden der nativen Bibliothek
In diesem Artikel wird erläutert, welche Pfade die Runtime beim Laden nativer Bibliotheken über P/Invoke durchsucht. Es wird ferner gezeigt, wie Sie SetDllImportResolver verwenden.
Variationen von Bibliotheksnamen
Um einfacheren plattformübergreifenden P/Invoke-Code zu fördern, fügt die Runtime nativen Bibliotheksnamen die kanonische freigegebene Bibliothekserweiterung (.dll
, .so
oder .dylib
) hinzu. Auf Unix-basierten Plattformen wird die Laufzeit auch versuchen, lib
voranzustellen. Nach diesen Bibliotheksnamenvariationen wird automatisch gesucht, wenn Sie APIs verwenden, die native Bibliotheken laden, z. B. DllImportAttribute.
Hinweis
Absolute Pfade in Bibliotheksnamen (zum Beispiel /usr/lib/libc.so
) werden unverändert übernommen, und es werden keine Variationen gesucht.
Betrachten Sie das folgende Beispiel für die Verwendung von P/Invoke:
[DllImport("nativedep")]
static extern int ExportedFunction();
Bei der Ausführung unter Windows wird die DLL in der folgenden Reihenfolge gesucht:
nativedep
nativedep.dll
(wenn der Bibliotheksname noch nicht auf.dll
oderexe
endet)
Wenn die Runtime unter Linux oder macOS ausgeführt wird, versucht sie, lib
voranzustellen und die kanonische freigegebene Bibliothekserweiterung anzufügen. Unter diesen Betriebssystemen werden Variationen von Bibliotheksnamen in der folgenden Reihenfolge ausprobiert:
nativedep.so
/nativedep.dylib
libnativedep.so
/libnativedep.dylib
1nativedep
libnativedep
1
Unter Linux unterscheidet sich die Suchreihenfolge, wenn der Bibliotheksname auf .so
oder .so.
endet (beachten Sie den nachfolgenden .
). Betrachten Sie das folgende Beispiel:
[DllImport("nativedep.so.6")]
static extern int ExportedFunction();
In diesem Fall werden die Variationen von Bibliotheksnamen in der folgenden Reihenfolge ausprobiert:
nativedep.so.6
libnativedep.so.6
1nativedep.so.6.so
libnativedep.so.6.so
1
1 Der Pfad wird nur überprüft, wenn der Bibliotheksname kein Verzeichnistrennzeichen (/
) enthält.
Benutzerdefinierter Importauflöser
In komplexeren Szenarien können Sie SetDllImportResolver verwenden, um DLL-Importe zur Laufzeit aufzulösen. Im folgenden Beispiel wird nativedep
in nativedep_avx2
aufgelöst, wenn die CPU dies unterstützt.
Tipp
Diese Funktionalität ist nur in .NET Core 3.1 und .NET 5+ verfügbar.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace PInvokeSamples
{
public static partial class Program
{
[LibraryImport("nativedep")]
private static partial int ExportedFunction();
public static void Main(string[] args)
{
// Register the import resolver before calling the imported function.
// Only one import resolver can be set for a given assembly.
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver);
int value = ExportedFunction();
Console.WriteLine(value);
}
private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == "nativedep")
{
// On systems with AVX2 support, load a different library.
if (System.Runtime.Intrinsics.X86.Avx2.IsSupported)
{
return NativeLibrary.Load("nativedep_avx2", assembly, searchPath);
}
}
// Otherwise, fallback to default import resolver.
return IntPtr.Zero;
}
}
}