diff --git a/PluginLoader/Plugin.cs b/PluginLoader/Plugin.cs index ffc332f..f1abbee 100644 --- a/PluginLoader/Plugin.cs +++ b/PluginLoader/Plugin.cs @@ -218,6 +218,37 @@ private bool LoadDll(string relativePath, string[] requiredFiles, ICollection pluginInterface, HashSet loaded, int depth, string fullPath) + { if (requiredFiles != null) foreach (string fileName in requiredFiles) { @@ -233,31 +264,46 @@ private bool LoadDll(string relativePath, string[] requiredFiles, ICollection + /// Try to load an assembly, resolving references from the plugin's directory. + /// + private Assembly LoadDllAutoResolve(string fullPath) + { + AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve; + try { return TryLoadAssembly(fullPath); } + finally { AppDomain.CurrentDomain.AssemblyResolve -= AssemblyResolve; } + } - Logger.WriteLine("Loading plugins from " + fullPath); + private Assembly AssemblyResolve(object sender, ResolveEventArgs args) + { + string name = new AssemblyName(args.Name).Name; + string[] assemblyPath = Directory.GetFiles(directory, name + ".dll", SearchOption.AllDirectories); - Assembly assembly = Assembly.LoadFrom(fullPath); - if (assembly == null) + switch (assemblyPath.Length) { - LogFailedToLoadFile(fullPath, "could not load assembly"); - return false; + case 0: + Logger.WriteLine("No assembly named " + name + " could be located"); + return null; + case 1: + Logger.WriteLine("Located assembly " + name + " in " + directory); + return TryLoadAssembly(assemblyPath[0]); + default: + Logger.WriteLine("Multiple files match " + name + ":\n" + string.Join("\n\t", assemblyPath)); + return null; } - foreach (Type t in assembly.ExportedTypes) - if (typeof(IPlugin).IsAssignableFrom(t)) - { - try { pluginInterface.Add((IPlugin)Activator.CreateInstance(t)); } - catch (Exception ex) - { - LogFailedToLoadFile(fullPath, "exception while creating instance of " + t.FullName + ":\n" + ex); - return false; - } - Logger.WriteLine("Loaded \"" + t.FullName + '"'); - } + } - return true; + private Assembly TryLoadAssembly(string fullPath) + { + try { return Assembly.LoadFrom(fullPath); } + catch (Exception ex) + { + Logger.WriteLine(ex.ToString()); + return null; + } } private void LogFailedToLoadFile(string fullPath, string reason) diff --git a/PluginLoader/PluginBuilder.cs b/PluginLoader/PluginBuilder.cs index 99dfb87..50596ba 100644 --- a/PluginLoader/PluginBuilder.cs +++ b/PluginLoader/PluginBuilder.cs @@ -1,4 +1,5 @@ -using System.Runtime.Serialization; +using System; +using System.Runtime.Serialization; namespace Rynchodon.PluginLoader { @@ -19,6 +20,7 @@ public sealed class File public string targetFolder; /// Names of files in this plugin that must be loaded before this one. [DataMember] + [Obsolete("references are resolved automatically")] public string[] requires; public File(string source, string targetFolder, string[] requires)