Inläsning av inbyggt bibliotek
I den här artikeln förklaras vilka sökvägar som körs vid inläsning av interna bibliotek via P/Invoke. Den visar också hur du använder SetDllImportResolver.
Variationer i biblioteksnamn
För att underlätta enklare P/Invoke-kod mellan plattformar lägger körningen till det kanoniska delade bibliotekstillägget (.dll
eller .so
.dylib
) i interna biblioteksnamn. På Unix-baserade plattformar kommer körningen också att försöka vänta lib
. Dessa variationer av biblioteksnamn söks automatiskt när du använder API:er som läser in inbyggda bibliotek, till exempel DllImportAttribute.
Kommentar
Absoluta sökvägar i biblioteksnamn (till exempel /usr/lib/libc.so
) behandlas som de är och inga variationer söks igenom.
Tänk dig följande exempel på hur du använder P/Invoke:
[DllImport("nativedep")]
static extern int ExportedFunction();
När du kör i Windows söks DLL:en efter i följande ordning:
nativedep
nativedep.dll
(om biblioteksnamnet inte redan slutar med.dll
eller .exe
)
När du kör på Linux eller macOS försöker körningen att vänta lib
och lägga till det kanoniska delade bibliotekstillägget. På dessa operativsystem provas varianter av biblioteksnamn i följande ordning:
nativedep.so
/nativedep.dylib
libnativedep.so
/libnativedep.dylib
1nativedep
libnativedep
1
I Linux skiljer sig sökordningen om biblioteksnamnet slutar med .so
eller innehåller .so.
(observera den avslutande .
). Ta följande som exempel:
[DllImport("nativedep.so.6")]
static extern int ExportedFunction();
I det här fallet provas varianterna av biblioteksnamn i följande ordning:
nativedep.so.6
libnativedep.so.6
1nativedep.so.6.so
libnativedep.so.6.so
1
1 Sökvägen kontrolleras endast om biblioteksnamnet inte innehåller ett katalogavgränsartecken (/
).
Anpassad importlösare
I mer komplexa scenarier kan du använda SetDllImportResolver för att lösa DLL-importer vid körning. I följande exempel nativedep
matchas till nativedep_avx2
om processorn stöder det.
Dricks
Den här funktionen är endast tillgänglig i .NET Core 3.1 och .NET 5+.
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;
}
}
}