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:
nativedep
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:
nativedep.so
/nativedep.dylib
libnativedep.so
/libnativedep.dylib
1nativedep
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:
nativedep.so.6
libnativedep.so.6
1nativedep.so.6.so
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;
}
}
}