[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/sdpython/pythonnet/master/src/runtime/platform/LibraryLoader.cs [Back]  [Original]

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace Python.Runtime.Platform
{
    interface ILibraryLoader
    {
        IntPtr Load(string dllToLoad);

        IntPtr GetFunction(IntPtr hModule, string procedureName);

        void Free(IntPtr hModule);
    }

    static class LibraryLoader
    {
        static ILibraryLoader _instance = null;

        public static ILibraryLoader Instance
        {
            get
            {
                if (_instance == null)
                {
                    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                        _instance = new WindowsLoader();
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                        _instance = new LinuxLoader();
                    else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
                        _instance = new DarwinLoader();
                    else
                        throw new PlatformNotSupportedException(
                            "This operating system is not supported"
                        );
                }

                return _instance;
            }
        }
    }

    class LinuxLoader : ILibraryLoader
    {
        private static int RTLD_NOW = 0x2;
        private static int RTLD_GLOBAL = 0x100;
        private static IntPtr RTLD_DEFAULT = IntPtr.Zero;
        private const string NativeDll = "libdl.so";

        public IntPtr Load(string dllToLoad)
        {
            var filename = $"lib{dllToLoad}.so";
            ClearError();
            var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
            if (res == IntPtr.Zero)
            {
                var err = GetError();
                throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
            }

            return res;
        }

        public void Free(IntPtr handle)
        {
            dlclose(handle);
        }

        public IntPtr GetFunction(IntPtr dllHandle, string name)
        {
            // look in the exe if dllHandle is NULL
            if (dllHandle == IntPtr.Zero)
            {
                dllHandle = RTLD_DEFAULT;
            }

            ClearError();
            IntPtr res = dlsym(dllHandle, name);
            if (res == IntPtr.Zero)
            {
                var err = GetError();
                throw new MissingMethodException($"Failed to load symbol {name}: {err}");
            }
            return res;
        }

        void ClearError()
        {
            dlerror();
        }

        string GetError()
        {
            var res = dlerror();
            if (res != IntPtr.Zero)
                return Marshal.PtrToStringAnsi(res);
            else
                return null;
        }

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern IntPtr dlopen(string fileName, int flags);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        private static extern IntPtr dlsym(IntPtr handle, string symbol);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
        private static extern int dlclose(IntPtr handle);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr dlerror();
    }

    class DarwinLoader : ILibraryLoader
    {
        private static int RTLD_NOW = 0x2;
        private static int RTLD_GLOBAL = 0x8;
        private const string NativeDll = "/usr/lib/libSystem.dylib";
        private static IntPtr RTLD_DEFAULT = new IntPtr(-2);

        public IntPtr Load(string dllToLoad)
        {
            var filename = $"lib{dllToLoad}.dylib";
            ClearError();
            var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
            if (res == IntPtr.Zero)
            {
                var err = GetError();
                throw new DllNotFoundException($"Could not load {filename} with flags RTLD_NOW | RTLD_GLOBAL: {err}");
            }

            return res;
        }

        public void Free(IntPtr handle)
        {
            dlclose(handle);
        }

        public IntPtr GetFunction(IntPtr dllHandle, string name)
        {
            // look in the exe if dllHandle is NULL
            if (dllHandle == IntPtr.Zero)
            {
                dllHandle = RTLD_DEFAULT;
            }

            ClearError();
            IntPtr res = dlsym(dllHandle, name);
            if (res == IntPtr.Zero)
            {
                var err = GetError();
                throw new MissingMethodException($"Failed to load symbol {name}: {err}");
            }
            return res;
        }

        void ClearError()
        {
            dlerror();
        }

        string GetError()
        {
            var res = dlerror();
            if (res != IntPtr.Zero)
                return Marshal.PtrToStringAnsi(res);
            else
                return null;
        }

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern IntPtr dlopen(String fileName, int flags);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        private static extern IntPtr dlsym(IntPtr handle, String symbol);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
        private static extern int dlclose(IntPtr handle);

        [DllImport(NativeDll, CallingConvention = CallingConvention.Cdecl)]
        private static extern IntPtr dlerror();
    }

    class WindowsLoader : ILibraryLoader
    {
        private const string NativeDll = "kernel32.dll";


        public IntPtr Load(string dllToLoad)
        {
            var res = WindowsLoader.LoadLibrary(dllToLoad);
            if (res == IntPtr.Zero)
                throw new DllNotFoundException($"Could not load {dllToLoad}", new Win32Exception());
            return res;
        }

        public IntPtr GetFunction(IntPtr hModule, string procedureName)
        {
            var res = WindowsLoader.GetProcAddress(hModule, procedureName);
            if (res == IntPtr.Zero)
                throw new MissingMethodException($"Failed to load symbol {procedureName}", new Win32Exception());
            return res;
        }

        public void Free(IntPtr hModule) => WindowsLoader.FreeLibrary(hModule);

        [DllImport(NativeDll, SetLastError = true)]
        static extern IntPtr LoadLibrary(string dllToLoad);

        [DllImport(NativeDll, SetLastError = true)]
        static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

        [DllImport(NativeDll)]
        static extern bool FreeLibrary(IntPtr hModule);
    }
}

Web Proxy Viewer  |  New URL  |  Original Page