Dela via


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 (.dlleller .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:

  1. nativedep
  2. 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:

  1. nativedep.so / nativedep.dylib
  2. libnativedep.so / libnativedep.dylib1
  3. nativedep
  4. libnativedep1

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:

  1. nativedep.so.6
  2. libnativedep.so.61
  3. nativedep.so.6.so
  4. libnativedep.so.6.so1

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;
        }
    }
}

Se även