原生程式庫載入
本文說明透過 P/Invoke 載入原生程式庫時,執行階段搜尋的路徑。 它也會示範如何使用 SetDllImportResolver。
程式庫名稱變化
為了簡化跨平台 P/Invoke 程式碼,執行階段會將標準共用程式庫延伸模組 (.dll
、.so
或 .dylib
) 新增至原生程式庫名稱。 在 Unix 平台上,執行階段也會嘗試在前面加上 lib
。 當您使用載入原生程式庫的 API (例如 DllImportAttribute) 時,會自動搜尋這些程式庫名稱變化。
注意
程式庫名稱中的絕對路徑 (例如,/usr/lib/libc.so
) 會視為原狀,而且不會搜尋任何變化。
假設使用 P/Invoke 的下列範例:
[DllImport("nativedep")]
static extern int ExportedFunction();
在 Windows 上執行時,會依下列順序搜尋 DLL:
nativedep
nativedep.dll
(如果程式庫名稱尚未以.dll
或exe
結尾)
在 Linux 或 macOS 上執行時,執行階段會嘗試在前面加上 lib
,並附加標準共用程式庫擴充功能。 在這些 OS 上,會依下列順序嘗試程式庫名稱變化:
nativedep.so
/nativedep.dylib
libnativedep.so
/libnativedep.dylib
1nativedep
libnativedep
1
在 Linux 上,如果程式庫名稱結尾為 .so
或包含 .so.
(請注意尾端 .
),則搜尋順序會有所不同。 請考慮下列範例:
[DllImport("nativedep.so.6")]
static extern int ExportedFunction();
在此情況下,會依下列順序嘗試程式庫名稱變化:
nativedep.so.6
libnativedep.so.6
1nativedep.so.6.so
libnativedep.so.6.so
1
1 只有在程式庫名稱不包含目錄分隔符號字元 (/
) 時,才會檢查路徑。
自訂匯入解析程式
在更複雜的案例中,您可以在執行階段使用 SetDllImportResolver 來解析 DLL 匯入。 在下列範例中,如果 CPU 支援,則 nativedep
會解析為 nativedep_avx2
。
提示
此功能僅適用於 .NET Core 3.1 和 .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;
}
}
}