using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Linq; using System.Collections.Concurrent; namespace NativeLibraryLoader { public class NativeLoader { private ConcurrentDictionary _Cache = new ConcurrentDictionary(); private IntPtr intPtr; public string DLLName { get; } = string.Empty; public string Extension { get; } = string.Empty; public Boolean Loaded => intPtr != IntPtr.Zero; public string SearchPattern { get; set; } = string.Empty; public string LoadedFile =>loadedFile; private string loadedFile=string.Empty; public List SearchDirectories { get; } = new List(); private IFileCheck fileCheck; private INativeLoader nativeLoader; public NativeLoader(string dllname) { fileCheck = GetPlatformFileCheck(); nativeLoader = GetPlatformLoader(); Extension = GetPlatformExtension(); SearchPattern = dllname; if (System.IO.File.Exists(dllname)) { intPtr = nativeLoader.CoreLoadLibrary(dllname); loadedFile = dllname; } else { DLLName = dllname; SearchDirectories.Add(AppContext.BaseDirectory); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) SearchDirectories.Add(Environment.GetFolderPath(Environment.SpecialFolder.System)); } Init(); } public void Init() { if (Loaded) return; if (SearchDirectories.Count == 0) SearchDirectories.Add(AppContext.BaseDirectory); string path = SearchDirectories.SelectMany(x => { try { string[] files = System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.AllDirectories).Where(y=>y.IndexOf(SearchPattern)>=0).ToArray(); return files; } catch { return System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.TopDirectoryOnly).Where(y=>y.IndexOf(SearchPattern)>=0); } })?.FirstOrDefault(x => { MachineType machineType = fileCheck.CheckFile(x); if (Environment.Is64BitProcess) return machineType == MachineType.Bit64; else return machineType == MachineType.Bit32; })??""; if (!string.IsNullOrEmpty(path)) { intPtr = nativeLoader.CoreLoadLibrary(path); loadedFile = path; } } public T LoadFunction(string enterpoint)where T :Delegate { if (intPtr == IntPtr.Zero) throw new EntryPointNotFoundException(enterpoint); var intptr = typeof(T).TypeHandle.Value; if(_Cache.TryGetValue(intptr,out var del)) { return (T)del; } IntPtr proc = nativeLoader.CoreGetProcAddress(intPtr, enterpoint); if (proc != IntPtr.Zero) { del = Marshal.GetDelegateForFunctionPointer(proc); _Cache[intptr] = del; return (T)del; } else { string s = nativeLoader.CoreGetLastError(); } throw new EntryPointNotFoundException(enterpoint); } public IntPtr LoadFunction(string enterpoint) { if (intPtr == IntPtr.Zero) return intPtr; return nativeLoader.CoreGetProcAddress(intPtr, enterpoint); } public void Unload() { if(intPtr!=IntPtr.Zero) { nativeLoader.CoreFreeLibrary(intPtr); } intPtr = IntPtr.Zero; } private IFileCheck GetPlatformFileCheck() { if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return new Windows.PEFileCheck(); } else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return new Linux.ELFFileCheck(); } else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { return new MAC.MachOFileCheck(); } throw new PlatformNotSupportedException("This platform cannot load native libraries."); } private INativeLoader GetPlatformLoader() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return new Windows.WindowNativeLoader(); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return new Linux.UnixNativeLoader(); } else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)|| RuntimeInformation.OSDescription.ToUpper().Contains("BSD")) { return new MAC.BSDNativeLoader(); } throw new PlatformNotSupportedException("This platform cannot load native libraries."); } private string GetPlatformExtension() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return "dll"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { return "so"; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { return "dylib"; } throw new PlatformNotSupportedException("This platform cannot load native libraries."); } } }