NativeLoader.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Text;
  5. using System.Linq;
  6. using System.Collections.Concurrent;
  7. namespace NativeLibraryLoader
  8. {
  9. public class NativeLoader
  10. {
  11. private ConcurrentDictionary<IntPtr, Delegate> _Cache = new ConcurrentDictionary<IntPtr, Delegate>();
  12. private IntPtr intPtr;
  13. public string DLLName { get; } = string.Empty;
  14. public string Extension { get; } = string.Empty;
  15. public Boolean Loaded => intPtr != IntPtr.Zero;
  16. public string SearchPattern { get; set; } = string.Empty;
  17. public string LoadedFile =>loadedFile;
  18. private string loadedFile=string.Empty;
  19. public List<String> SearchDirectories { get; } = new List<string>();
  20. private IFileCheck fileCheck;
  21. private INativeLoader nativeLoader;
  22. public NativeLoader(string dllname)
  23. {
  24. fileCheck = GetPlatformFileCheck();
  25. nativeLoader = GetPlatformLoader();
  26. Extension = GetPlatformExtension();
  27. SearchPattern = dllname;
  28. if (System.IO.File.Exists(dllname))
  29. {
  30. intPtr = nativeLoader.CoreLoadLibrary(dllname);
  31. loadedFile = dllname;
  32. }
  33. else
  34. {
  35. DLLName = dllname;
  36. SearchDirectories.Add(AppContext.BaseDirectory);
  37. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) SearchDirectories.Add(Environment.GetFolderPath(Environment.SpecialFolder.System));
  38. }
  39. }
  40. public void Init()
  41. {
  42. if (Loaded) return;
  43. if (SearchDirectories.Count == 0) SearchDirectories.Add(AppContext.BaseDirectory);
  44. string path = SearchDirectories.SelectMany(x =>
  45. {
  46. try
  47. {
  48. string[] files = System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.AllDirectories).Where(y=>y.IndexOf(SearchPattern)>=0).ToArray();
  49. return files;
  50. }
  51. catch
  52. {
  53. return System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.TopDirectoryOnly).Where(y=>y.IndexOf(SearchPattern)>=0);
  54. }
  55. })?.FirstOrDefault(x =>
  56. {
  57. MachineType machineType = fileCheck.CheckFile(x);
  58. if (Environment.Is64BitProcess) return machineType == MachineType.Bit64;
  59. else return machineType == MachineType.Bit32;
  60. })??"";
  61. if (!string.IsNullOrEmpty(path))
  62. {
  63. intPtr = nativeLoader.CoreLoadLibrary(path);
  64. loadedFile = path;
  65. }
  66. }
  67. public T LoadFunction<T>(string enterpoint)where T :Delegate
  68. {
  69. if (intPtr == IntPtr.Zero) throw new EntryPointNotFoundException(enterpoint);
  70. var intptr = typeof(T).TypeHandle.Value;
  71. if(_Cache.TryGetValue(intptr,out var del))
  72. {
  73. return (T)del;
  74. }
  75. IntPtr proc = nativeLoader.CoreGetProcAddress(intPtr, enterpoint);
  76. if (proc != IntPtr.Zero)
  77. {
  78. del = Marshal.GetDelegateForFunctionPointer<T>(proc);
  79. _Cache[intptr] = del;
  80. return (T)del;
  81. }
  82. else
  83. {
  84. string s = nativeLoader.CoreGetLastError();
  85. }
  86. throw new EntryPointNotFoundException(enterpoint);
  87. }
  88. public IntPtr LoadFunction(string enterpoint)
  89. {
  90. if (intPtr == IntPtr.Zero) return intPtr;
  91. return nativeLoader.CoreGetProcAddress(intPtr, enterpoint);
  92. }
  93. public void Unload()
  94. {
  95. if(intPtr!=IntPtr.Zero)
  96. {
  97. nativeLoader.CoreFreeLibrary(intPtr);
  98. }
  99. intPtr = IntPtr.Zero;
  100. }
  101. private IFileCheck GetPlatformFileCheck()
  102. {
  103. if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  104. {
  105. return new Windows.PEFileCheck();
  106. }
  107. else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  108. {
  109. return new Linux.ELFFileCheck();
  110. }
  111. else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  112. {
  113. return new MAC.MachOFileCheck();
  114. }
  115. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  116. }
  117. public static INativeLoader PlatformLoader()
  118. {
  119. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  120. {
  121. return new Windows.WindowNativeLoader();
  122. }
  123. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  124. {
  125. return new Linux.UnixNativeLoader();
  126. }
  127. else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.OSDescription.ToUpper().Contains("BSD"))
  128. {
  129. return new MAC.BSDNativeLoader();
  130. }
  131. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  132. }
  133. private INativeLoader GetPlatformLoader()
  134. {
  135. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  136. {
  137. return new Windows.WindowNativeLoader();
  138. }
  139. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  140. {
  141. return new Linux.UnixNativeLoader();
  142. }
  143. else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)|| RuntimeInformation.OSDescription.ToUpper().Contains("BSD"))
  144. {
  145. return new MAC.BSDNativeLoader();
  146. }
  147. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  148. }
  149. private string GetPlatformExtension()
  150. {
  151. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  152. {
  153. return "dll";
  154. }
  155. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  156. {
  157. return "so";
  158. }
  159. else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  160. {
  161. return "dylib";
  162. }
  163. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  164. }
  165. }
  166. }