NativeLoader.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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; }
  14. public string Extension { get; }
  15. public Boolean Loaded => intPtr != IntPtr.Zero;
  16. public string SearchPattern { get; set; }
  17. public string LoadedFile =>loadedFile;
  18. private string loadedFile;
  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. Init();
  40. }
  41. public void Init()
  42. {
  43. if (Loaded) return;
  44. if (SearchDirectories.Count == 0) SearchDirectories.Add(AppContext.BaseDirectory);
  45. string path = SearchDirectories.SelectMany(x =>
  46. {
  47. try
  48. {
  49. string[] files = System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.AllDirectories).Where(y=>y.IndexOf(SearchPattern)>=0).ToArray();
  50. return files;
  51. }
  52. catch
  53. {
  54. return System.IO.Directory.GetFiles(x,"*.*", System.IO.SearchOption.TopDirectoryOnly).Where(y=>y.IndexOf(SearchPattern)>=0);
  55. }
  56. })?.FirstOrDefault(x =>
  57. {
  58. MachineType machineType = fileCheck.CheckFile(x);
  59. if (Environment.Is64BitProcess) return machineType == MachineType.Bit64;
  60. else return machineType == MachineType.Bit32;
  61. })??"";
  62. if (!string.IsNullOrEmpty(path))
  63. {
  64. intPtr = nativeLoader.CoreLoadLibrary(path);
  65. loadedFile = path;
  66. }
  67. }
  68. public T LoadFunction<T>(string enterpoint)where T :Delegate
  69. {
  70. if (intPtr == IntPtr.Zero) return default;
  71. var intptr = typeof(T).TypeHandle.Value;
  72. if(_Cache.TryGetValue(intptr,out var del))
  73. {
  74. return (T)del;
  75. }
  76. IntPtr proc = nativeLoader.CoreGetProcAddress(intPtr, enterpoint);
  77. if (proc != IntPtr.Zero)
  78. {
  79. del = Marshal.GetDelegateForFunctionPointer<T>(proc);
  80. _Cache[intptr] = del;
  81. return (T)del;
  82. }
  83. else
  84. {
  85. string s = nativeLoader.CoreGetLastError();
  86. }
  87. return default;
  88. }
  89. public IntPtr LoadFunction(string enterpoint)
  90. {
  91. if (intPtr == IntPtr.Zero) return intPtr;
  92. return nativeLoader.CoreGetProcAddress(intPtr, enterpoint);
  93. }
  94. public void Unload()
  95. {
  96. if(intPtr!=IntPtr.Zero)
  97. {
  98. nativeLoader.CoreFreeLibrary(intPtr);
  99. }
  100. intPtr = IntPtr.Zero;
  101. }
  102. private IFileCheck GetPlatformFileCheck()
  103. {
  104. if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  105. {
  106. return new Windows.PEFileCheck();
  107. }
  108. else if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  109. {
  110. return new Linux.ELFFileCheck();
  111. }
  112. else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  113. {
  114. return new MAC.MachOFileCheck();
  115. }
  116. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  117. }
  118. private INativeLoader GetPlatformLoader()
  119. {
  120. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  121. {
  122. return new Windows.WindowNativeLoader();
  123. }
  124. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  125. {
  126. return new Linux.UnixNativeLoader();
  127. }
  128. else if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX)|| RuntimeInformation.OSDescription.ToUpper().Contains("BSD"))
  129. {
  130. return new MAC.BSDNativeLoader();
  131. }
  132. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  133. }
  134. private string GetPlatformExtension()
  135. {
  136. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  137. {
  138. return "dll";
  139. }
  140. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  141. {
  142. return "so";
  143. }
  144. else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  145. {
  146. return "dylib";
  147. }
  148. throw new PlatformNotSupportedException("This platform cannot load native libraries.");
  149. }
  150. }
  151. }