PluginsLoader.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics.CodeAnalysis;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Runtime.InteropServices;
  8. using System.Runtime.Loader;
  9. namespace ShakerApp.Tools
  10. {
  11. public class PluginsLoader
  12. {
  13. private string ext = "";
  14. private List<Assembly> LoadedAssemblies = new List<Assembly>();
  15. [AllowNull]
  16. private AssemblyDependencyResolver resolver;
  17. private List<string> AllDlls = new List<string>();
  18. private PluginsLoader()
  19. {
  20. }
  21. public List<T> Load<T>(string path)
  22. {
  23. try
  24. {
  25. resolver = new AssemblyDependencyResolver(path);
  26. AssemblyLoadContext.Default.Resolving += Default_Resolving;
  27. AssemblyLoadContext.Default.ResolvingUnmanagedDll += Default_ResolvingUnmanagedDll;
  28. AllDlls.Clear();
  29. AllDlls.AddRange(System.IO.Directory.GetFiles(path, "*.dll", System.IO.SearchOption.AllDirectories));
  30. var result = AllDlls
  31. .SelectMany(x =>
  32. {
  33. try
  34. {
  35. var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(x);
  36. var types = assembly.GetTypes();
  37. return types.Where(x => x.GetInterface(typeof(T).FullName!) != null && x.IsAnsiClass && !x.IsAbstract);
  38. }
  39. catch
  40. {
  41. }
  42. return new Type[0];
  43. })
  44. .Where(x => x != null)
  45. .Select(x =>
  46. {
  47. return (T)Activator.CreateInstance(x!)!;
  48. })
  49. .Where(x => x != null)
  50. .ToList();
  51. //AssemblyLoadContext.Default.Resolving -= Default_Resolving;
  52. return result;
  53. }
  54. catch
  55. {
  56. return new List<T>();
  57. }
  58. }
  59. [DllImport("kernel32.dll")]
  60. private static extern nint LoadLibrary(string path);
  61. private nint Default_ResolvingUnmanagedDll(Assembly arg1, string arg2)
  62. {
  63. var fileinfo = new FileInfo(arg1.Location);
  64. if (fileinfo?.Directory == null) return 0;
  65. string ext = "*.dll";
  66. var file = fileinfo.Directory.GetFiles(ext, SearchOption.AllDirectories).FirstOrDefault(x=>x.Name == arg2)?.FullName;
  67. if (System.IO.File.Exists(file))
  68. {
  69. return LoadLibrary(file);
  70. }
  71. throw new NotImplementedException();
  72. }
  73. private System.Reflection.Assembly? Default_Resolving(AssemblyLoadContext arg1, System.Reflection.AssemblyName arg2)
  74. {
  75. var assembly = AssemblyLoadContext.Default.Assemblies.FirstOrDefault(x => x.FullName == arg2.FullName);
  76. if (assembly != null) return assembly;
  77. assembly = LoadedAssemblies.FirstOrDefault(x => x.FullName == arg2.FullName);
  78. if (assembly != null) return assembly;
  79. string? path = resolver.ResolveAssemblyToPath(arg2);
  80. if (!string.IsNullOrEmpty(path))
  81. {
  82. assembly = arg1.LoadFromAssemblyPath(path);
  83. if (assembly != null)
  84. {
  85. LoadedAssemblies.Add(assembly);
  86. return assembly;
  87. }
  88. }
  89. else
  90. {
  91. var results = AllDlls.Where(x => x.IndexOf(arg2.Name!) >= 0).ToList();
  92. results.ForEach(x =>
  93. {
  94. try
  95. {
  96. var tempassembly = arg1.LoadFromAssemblyPath(x);
  97. if (tempassembly != null)
  98. {
  99. LoadedAssemblies.Add(tempassembly);
  100. }
  101. }
  102. catch
  103. {
  104. }
  105. });
  106. assembly = LoadedAssemblies.FirstOrDefault(x => x.FullName == arg2.FullName);
  107. if (assembly != null) return assembly;
  108. }
  109. return null;
  110. }
  111. static PluginsLoader()
  112. {
  113. }
  114. public static PluginsLoader Defalut { get; } = new PluginsLoader();
  115. }
  116. }