diff --git a/你好插件/你好命令.cs b/你好插件/你好命令.cs new file mode 100644 index 0000000..add96e1 --- /dev/null +++ b/你好插件/你好命令.cs @@ -0,0 +1,21 @@ +using PluginBase; +using System; +using System.Runtime.InteropServices; + +namespace 你好插件 +{ + public class 你好命令 : ICommand + { + public string 名称 { get => "你好"; } + public string 描述 { get => "显示一个你好的消息"; } + + [DllImport("Kernel32.dll")]//引入命名空间 + public static extern bool Beep(int frequency, int duration); + public int 执行() + { + Console.WriteLine("你好 !!!\n"); + Beep(700, 200); + return 0; + } + } +} \ No newline at end of file diff --git a/你好插件/你好插件.csproj b/你好插件/你好插件.csproj new file mode 100644 index 0000000..f210ad1 --- /dev/null +++ b/你好插件/你好插件.csproj @@ -0,0 +1,16 @@ + + + + net6.0 + enable + enable + true + + + + + False + runtime + + + diff --git a/加载dll.sln b/加载dll.sln index e147808..530a927 100644 --- a/加载dll.sln +++ b/加载dll.sln @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.4.33403.182 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "加载dll", "加载dll\加载dll.csproj", "{4E443C0A-8E49-4186-9069-9946B033135E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "加载dll", "加载dll\加载dll.csproj", "{4E443C0A-8E49-4186-9069-9946B033135E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "你好插件", "你好插件\你好插件.csproj", "{748E79C2-35E6-4B25-890A-B88064B47705}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,6 +17,10 @@ Global {4E443C0A-8E49-4186-9069-9946B033135E}.Debug|Any CPU.Build.0 = Debug|Any CPU {4E443C0A-8E49-4186-9069-9946B033135E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4E443C0A-8E49-4186-9069-9946B033135E}.Release|Any CPU.Build.0 = Release|Any CPU + {748E79C2-35E6-4B25-890A-B88064B47705}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {748E79C2-35E6-4B25-890A-B88064B47705}.Debug|Any CPU.Build.0 = Debug|Any CPU + {748E79C2-35E6-4B25-890A-B88064B47705}.Release|Any CPU.ActiveCfg = Release|Any CPU + {748E79C2-35E6-4B25-890A-B88064B47705}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/加载dll/PluginBase.cs b/加载dll/PluginBase.cs new file mode 100644 index 0000000..a478671 --- /dev/null +++ b/加载dll/PluginBase.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PluginBase +{ + public interface ICommand + { + string 名称 { get; }//Name + string 描述 { get; }//Description + + int 执行(); + } +} diff --git a/加载dll/Program.cs b/加载dll/Program.cs index 636b8de..acbb35c 100644 --- a/加载dll/Program.cs +++ b/加载dll/Program.cs @@ -1,11 +1,118 @@ -namespace 加载dll +using PluginBase; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using 加载dll; + +namespace 加载Dll { - internal class Program + class Program { static void Main(string[] args) { - Console.WriteLine("Hello, World!"); + try + { + if (args.Length == 1 && args[0] == "/d") + { + Console.WriteLine("按下任何按钮开始运行..."); + Console.ReadLine(); + } + // 从插件加载指令 + string[] pluginPaths = new string[] + { + "D:\\插件\\你好插件.dll", + "C:\\Users\\misaka20001\\source\\repos\\加载dll\\你好插件\\bin\\Debug\\net6.0\\你好插件.dll" + // Paths to plugins to load. + // 这里填写需要加载插件的路径 + }; + + IEnumerable commands = pluginPaths.SelectMany(pluginPath => + { + Assembly pluginAssembly = 加载插件(pluginPath); + return 创建命令(pluginAssembly); + }).ToList(); + + if (args.Length == 0) + { + Console.WriteLine("命令: "); + // 输出加载的命令. + foreach (ICommand command in commands) + { + Console.WriteLine($"{command.名称}\t - {command.描述}"); + } + } + else + { + foreach (string commandName in args) + { + Console.WriteLine($"-- {commandName} --"); + + // Execute the command with the name passed as an argument. + // 使用作为参数传递的名称执行命令 + ICommand? command = commands.FirstOrDefault(c => c.名称 == commandName); + if (command == null) + { + Console.WriteLine("没有找到任何已知命令"); + return; + } + + command.执行(); + + Console.WriteLine(); + } + } + } + catch (Exception ex) + { + Console.WriteLine(ex); + } } + + static Assembly 加载插件(string 相对路径) + { + //throw new NotImplementedException();//未实现异常 + string? root = Path.GetFullPath(Path.Combine( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName(path:typeof(Program).Assembly.Location))))))); + + string pluginLocation = Path.GetFullPath(Path.Combine(root, 相对路径.Replace('\\', Path.DirectorySeparatorChar))); + Console.WriteLine($"加载插件: {pluginLocation}"); + 加载插件上下文 loadContext = new 加载插件上下文(pluginLocation); + return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation))); + } + + static IEnumerable 创建命令(Assembly 程序集) + { + int count = 0; + + foreach (Type type in 程序集.GetTypes()) + { + if (typeof(ICommand).IsAssignableFrom(type)) + { + ICommand result = Activator.CreateInstance(type) as ICommand; + if (result != null) + { + count++; + yield return result; + } + } + } + + if (count == 0) + { + string availableTypes = string.Join(",", 程序集.GetTypes().Select(t => t.FullName)); + throw new ApplicationException( + $"在{程序集.Location}的{程序集}中找不到实现了ICommand的任何可用类型\n"+ + $"可用类型: {availableTypes}"); + } + } + + } } \ No newline at end of file diff --git a/加载dll/加载插件上下文.cs b/加载dll/加载插件上下文.cs new file mode 100644 index 0000000..3c6977d --- /dev/null +++ b/加载dll/加载插件上下文.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using System.Threading.Tasks; +using 加载Dll; + +namespace 加载dll +{ + + class 加载插件上下文 : AssemblyLoadContext + { + private AssemblyDependencyResolver? _解析器; + + public 加载插件上下文(string 插件路径) + { + _解析器 = new AssemblyDependencyResolver(插件路径); + } + + protected override Assembly? Load(AssemblyName 程序集名称) + { + string? 程序集路径 = _解析器?.ResolveAssemblyToPath(程序集名称); + if (程序集路径 != null) + { + return LoadFromAssemblyPath(程序集路径);//从路径加载程序集 + } + + return null; + } + + protected override IntPtr LoadUnmanagedDll(string 非托管DLL名称)//重写加载非托管DLL方法 + { + string? libraryPath = _解析器?.ResolveUnmanagedDllToPath(非托管DLL名称);//解析非托管类型DLL为路径 + if (libraryPath != null) + { + return LoadUnmanagedDllFromPath(libraryPath);//从路径加载程序集 + } + + return IntPtr.Zero; + } + + static Assembly LoadPlugin(string relativePath) + { + // Navigate up to the solution root + string root = Path.GetFullPath(Path.Combine( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName( + Path.GetDirectoryName(typeof(Program).Assembly.Location))))))); + + string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar))); + Console.WriteLine($"Loading commands from: {pluginLocation}"); + 加载插件上下文 loadContext = new 加载插件上下文(pluginLocation); + return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation))); + } + } + +}