Bagikan melalui


Pemuatan pustaka asli

Artikel ini menjelaskan jalur mana yang dicari runtime saat memuat pustaka asli melalui P/Invoke. Ini juga menunjukkan cara menggunakan SetDllImportResolver.

Variasi nama pustaka

Untuk memfasilitasi kode P/Invoke lintas platform yang lebih sederhana, runtime menambahkan ekstensi pustaka bersama kanonis (.dll, .so atau .dylib) ke nama pustaka asli. Pada platform berbasis Unix, runtime juga akan mencoba prepending lib. Variasi nama pustaka ini secara otomatis dicari saat Anda menggunakan API yang memuat pustaka asli, seperti DllImportAttribute.

Catatan

Jalur absolut dalam nama pustaka (misalnya, /usr/lib/libc.so) diperlakukan apa adanya dan tidak ada variasi yang akan dicari.

Pertimbangkan contoh penggunaan P/Invoke berikut:

[DllImport("nativedep")]
static extern int ExportedFunction();

Saat berjalan di Windows, DLL dicari dalam urutan berikut:

  1. nativedep
  2. nativedep.dll (jika nama pustaka belum diakhiri dengan .dll atau .exe)

Saat berjalan di Linux atau macOS, runtime akan mencoba menambahkan lib di bagian depan dan menambahkan ekstensi pustaka bersama kanonis. Pada OS ini, variasi nama pustaka dicoba dalam urutan berikut:

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

Di Linux, urutan pencarian berbeda jika nama pustaka berakhir dengan .so atau berisi .so. (perhatikan trailing .). Pertimbangkan contoh berikut:

[DllImport("nativedep.so.6")]
static extern int ExportedFunction();

Pada OS ini, variasi nama pustaka dicoba dalam urutan berikut:

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

1 Jalur dicentang hanya jika nama pustaka tidak berisi karakter pemisah direktori (/).

Pemecah masalah impor kustom

Dalam skenario yang lebih kompleks, Anda dapat menggunakan SetDllImportResolver untuk mengatasi impor DLL pada durasi. Dalam contoh berikut, nativedep diselesaikan menjadi nativedep_avx2 jika CPU mendukungnya.

Tip

Fungsionalitas ini hanya tersedia di .NET Core 3.1 dan .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;
        }
    }
}

Lihat juga