共用方式為


原生程式庫載入

本文說明透過 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:

  1. nativedep
  2. nativedep.dll (如果程式庫名稱尚未以 .dllexe 結尾)

在 Linux 或 macOS 上執行時,執行階段會嘗試在前面加上 lib,並附加標準共用程式庫擴充功能。 在這些 OS 上,會依下列順序嘗試程式庫名稱變化:

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

在 Linux 上,如果程式庫名稱結尾為 .so 或包含 .so. (請注意尾端 .),則搜尋順序會有所不同。 請考慮下列範例:

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

在此情況下,會依下列順序嘗試程式庫名稱變化:

  1. nativedep.so.6
  2. libnativedep.so.6 1
  3. nativedep.so.6.so
  4. 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;
        }
    }
}

另請參閱