using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Loader; namespace ShakerApp.Tools { public class PluginsLoader { private string ext = ""; private List LoadedAssemblies = new List(); [AllowNull] private AssemblyDependencyResolver resolver; private List AllDlls = new List(); private PluginsLoader() { } public List Load(string path) { try { resolver = new AssemblyDependencyResolver(path); AssemblyLoadContext.Default.Resolving += Default_Resolving; AssemblyLoadContext.Default.ResolvingUnmanagedDll += Default_ResolvingUnmanagedDll; AllDlls.Clear(); AllDlls.AddRange(System.IO.Directory.GetFiles(path, "*.dll", System.IO.SearchOption.AllDirectories)); var result = AllDlls .SelectMany(x => { try { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(x); var types = assembly.GetTypes(); return types.Where(x => x.GetInterface(typeof(T).FullName!) != null && x.IsAnsiClass && !x.IsAbstract); } catch { } return new Type[0]; }) .Where(x => x != null) .Select(x => { return (T)Activator.CreateInstance(x!)!; }) .Where(x => x != null) .ToList(); //AssemblyLoadContext.Default.Resolving -= Default_Resolving; return result; } catch { return new List(); } } [DllImport("kernel32.dll")] private static extern nint LoadLibrary(string path); private nint Default_ResolvingUnmanagedDll(Assembly arg1, string arg2) { var fileinfo = new FileInfo(arg1.Location); if (fileinfo?.Directory == null) return 0; string ext = "*.dll"; var file = fileinfo.Directory.GetFiles(ext, SearchOption.AllDirectories).FirstOrDefault(x=>x.Name == arg2)?.FullName; if (System.IO.File.Exists(file)) { return LoadLibrary(file); } throw new NotImplementedException(); } private System.Reflection.Assembly? Default_Resolving(AssemblyLoadContext arg1, System.Reflection.AssemblyName arg2) { var assembly = AssemblyLoadContext.Default.Assemblies.FirstOrDefault(x => x.FullName == arg2.FullName); if (assembly != null) return assembly; assembly = LoadedAssemblies.FirstOrDefault(x => x.FullName == arg2.FullName); if (assembly != null) return assembly; string? path = resolver.ResolveAssemblyToPath(arg2); if (!string.IsNullOrEmpty(path)) { assembly = arg1.LoadFromAssemblyPath(path); if (assembly != null) { LoadedAssemblies.Add(assembly); return assembly; } } else { var results = AllDlls.Where(x => x.IndexOf(arg2.Name!) >= 0).ToList(); results.ForEach(x => { try { var tempassembly = arg1.LoadFromAssemblyPath(x); if (tempassembly != null) { LoadedAssemblies.Add(tempassembly); } } catch { } }); assembly = LoadedAssemblies.FirstOrDefault(x => x.FullName == arg2.FullName); if (assembly != null) return assembly; } return null; } static PluginsLoader() { } public static PluginsLoader Defalut { get; } = new PluginsLoader(); } }