Yerel kitaplığın yüklenmesi

Bu makalede, P/Invoke aracılığıyla yerel kitaplıkları yüklerken çalışma zamanı ortamının hangi yolları taradığı açıklanmaktadır. Ayrıca SetDllImportResolver'nin nasıl kullanılacağını gösterir.

Kitaplık adı çeşitlemeleri

Daha basit platformlar arası P/Invoke kodunu kolaylaştırmak için çalışma zamanı kurallı paylaşılan kitaplık uzantısını (.dll.soveya .dylib) yerel kitaplık adlarına ekler. Unix tabanlı platformlarda çalışma zamanı da ön bağlamayı libdener. Yerel kitaplıkları yükleyen DllImportAttribute gibi API'leri kullandığınızda, bu kitaplık adlarının varyasyonları otomatik olarak aranıyor.

Not

Kitaplık adlarındaki mutlak yollar (örneğin, /usr/lib/libc.so) olduğu gibi kabul edilir ve hiçbir varyasyon aranmayacak.

Aşağıdaki P/Invoke kullanma örneğini göz önünde bulundurun:

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

Windows üzerinde çalışırken, DLL şu sırayla aranıyor:

  1. nativedep
  2. nativedep.dll (kitaplık adı halen .dll veya .exe ile bitmiyorsa)

Linux veya macOS üzerinde çalışırken, çalışma zamanı lib'yi en başa eklemeye ve kurallı paylaşılan kitaplık uzantısını sona eklemeye çalışacaktır. Bu işletim sisteminde, kitaplık adı varyasyonları aşağıdaki sırayla denenir:

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

Linux'ta, kitaplık adı ile .so bitiyorsa veya içeriyorsa .so. arama sırası farklıdır (sonundakine .dikkat edin). Aşağıdaki örneği inceleyin:

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

Bu durumda, kitaplık adı varyasyonları aşağıdaki sırayla denenmektedir:

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

1 Yol yalnızca kitaplık adında dizin ayırıcı karakteri (/) yoksa denetlenilir.

Özel içeri aktarma çözümleyicisi

Daha karmaşık senaryolarda, SetDllImportResolver'i çalışma zamanında DLL içeri aktarmalarını çözümlemek için kullanabilirsiniz. Aşağıdaki örnekte, işlemci destekliyorsa nativedep, nativedep_avx2 olarak çözümlenir.

İpucu

Bu işlev yalnızca .NET Core 3.1 ve .NET 5+ ile kullanılabilir.

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

Ayrıca bkz.