2018-05-13 19:49:26 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX.WinForms
|
|
|
|
|
{
|
|
|
|
|
public static class PluginLoader
|
|
|
|
|
{
|
2020-10-18 18:02:39 +00:00
|
|
|
|
public static IEnumerable<T> LoadPlugins<T>(string pluginPath) where T : class
|
2018-05-13 19:49:26 +00:00
|
|
|
|
{
|
2019-02-15 19:46:46 +00:00
|
|
|
|
var dllFileNames = !Directory.Exists(pluginPath)
|
2018-07-24 04:47:31 +00:00
|
|
|
|
? Enumerable.Empty<string>()
|
|
|
|
|
: Directory.EnumerateFiles(pluginPath, "*.dll", SearchOption.AllDirectories);
|
2018-05-13 19:49:26 +00:00
|
|
|
|
var assemblies = GetAssemblies(dllFileNames);
|
|
|
|
|
var pluginTypes = GetPluginsOfType<T>(assemblies);
|
|
|
|
|
return LoadPlugins<T>(pluginTypes);
|
|
|
|
|
}
|
2018-07-24 04:36:26 +00:00
|
|
|
|
|
2020-10-18 18:02:39 +00:00
|
|
|
|
private static IEnumerable<T> LoadPlugins<T>(IEnumerable<Type> pluginTypes) where T : class
|
2018-05-13 19:49:26 +00:00
|
|
|
|
{
|
2020-10-18 18:02:39 +00:00
|
|
|
|
foreach (var t in pluginTypes)
|
|
|
|
|
{
|
|
|
|
|
var activate = (T?) Activator.CreateInstance(t);
|
|
|
|
|
if (activate != null)
|
|
|
|
|
yield return activate;
|
|
|
|
|
}
|
2018-05-13 19:49:26 +00:00
|
|
|
|
}
|
2018-07-24 04:36:26 +00:00
|
|
|
|
|
2018-05-13 19:49:26 +00:00
|
|
|
|
private static IEnumerable<Assembly> GetAssemblies(IEnumerable<string> dllFileNames)
|
|
|
|
|
{
|
2018-05-16 03:16:57 +00:00
|
|
|
|
#if UNSAFEDLL
|
2018-07-24 04:36:26 +00:00
|
|
|
|
var assemblies = dllFileNames.Select(Assembly.UnsafeLoadFrom);
|
2018-05-16 03:16:57 +00:00
|
|
|
|
#else
|
2018-07-24 04:36:26 +00:00
|
|
|
|
var assemblies = dllFileNames.Select(Assembly.LoadFrom);
|
|
|
|
|
#endif
|
|
|
|
|
#if MERGED
|
|
|
|
|
assemblies = assemblies.Concat(new[] { Assembly.GetExecutingAssembly() }); // load merged too
|
2018-05-16 03:16:57 +00:00
|
|
|
|
#endif
|
2018-07-24 04:36:26 +00:00
|
|
|
|
return assemblies;
|
2018-05-13 19:49:26 +00:00
|
|
|
|
}
|
2018-07-24 04:36:26 +00:00
|
|
|
|
|
2018-05-13 19:49:26 +00:00
|
|
|
|
private static IEnumerable<Type> GetPluginsOfType<T>(IEnumerable<Assembly> assemblies)
|
|
|
|
|
{
|
|
|
|
|
var pluginType = typeof(T);
|
2018-07-24 04:36:26 +00:00
|
|
|
|
return assemblies.Where(z => z != null).SelectMany(z => GetPluginTypes(z, pluginType));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IEnumerable<Type> GetPluginTypes(Assembly z, Type pluginType)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var types = z.GetTypes();
|
|
|
|
|
return types.Where(type => IsTypePlugin(type, pluginType));
|
|
|
|
|
}
|
2020-09-19 05:11:13 +00:00
|
|
|
|
#pragma warning disable CA1031 // Do not catch general exception types
|
|
|
|
|
// User plugins can be out of date, with mismatching API surfaces.
|
2018-07-24 04:36:26 +00:00
|
|
|
|
catch (Exception ex)
|
2020-09-19 05:11:13 +00:00
|
|
|
|
#pragma warning restore CA1031 // Do not catch general exception types
|
2018-05-13 19:49:26 +00:00
|
|
|
|
{
|
2018-07-24 04:36:26 +00:00
|
|
|
|
System.Diagnostics.Debug.WriteLine($"Unable to load plugin [{pluginType.Name}]: {z.FullName}", ex.Message);
|
|
|
|
|
return Enumerable.Empty<Type>();
|
2018-05-13 19:49:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-24 04:36:26 +00:00
|
|
|
|
|
|
|
|
|
private static bool IsTypePlugin(Type type, Type pluginType)
|
|
|
|
|
{
|
|
|
|
|
if (type.IsInterface || type.IsAbstract)
|
|
|
|
|
return false;
|
2020-10-18 18:02:39 +00:00
|
|
|
|
var name = pluginType.FullName;
|
|
|
|
|
if (name == null)
|
|
|
|
|
return false;
|
|
|
|
|
if (type.GetInterface(name) == null)
|
2018-07-24 04:36:26 +00:00
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-05-13 19:49:26 +00:00
|
|
|
|
}
|
|
|
|
|
}
|