From 7ac3a22fa6c86c7b4ceadc4adae2b1c3705f3ff3 Mon Sep 17 00:00:00 2001
From: unknown <2564608840@qq.com>
Date: Thu, 17 Jul 2025 22:30:12 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E6=8F=92=E4=BB=B6=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Helpers/Plugins/ICCPPPluginAdapter.cs | 169 +++++++++++++++
Ink Canvas/Helpers/Plugins/PluginManager.cs | 196 +++++++++---------
.../Windows/PluginSettingsWindow.xaml.cs | 9 +-
3 files changed, 271 insertions(+), 103 deletions(-)
create mode 100644 Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs
diff --git a/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs b/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs
new file mode 100644
index 00000000..1d28d50f
--- /dev/null
+++ b/Ink Canvas/Helpers/Plugins/ICCPPPluginAdapter.cs
@@ -0,0 +1,169 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+namespace Ink_Canvas.Helpers.Plugins
+{
+ ///
+ /// ICCPP 插件适配器,用于加载和管理 .iccpp 格式的插件
+ ///
+ public class ICCPPPluginAdapter : PluginBase
+ {
+ private readonly byte[] _pluginData;
+ private readonly string _pluginPath;
+ private readonly string _pluginName;
+ private readonly Version _pluginVersion;
+ private bool _isInitialized = false;
+
+ ///
+ /// 创建 ICCPP 插件适配器
+ ///
+ /// 插件文件路径
+ /// 插件文件数据
+ public ICCPPPluginAdapter(string pluginPath, byte[] pluginData)
+ {
+ _pluginPath = pluginPath;
+ _pluginData = pluginData;
+ PluginPath = pluginPath;
+
+ // 从文件名获取插件名称
+ _pluginName = Path.GetFileNameWithoutExtension(pluginPath);
+ _pluginVersion = new Version(1, 0, 0); // 默认版本
+
+ // 尝试从插件数据中读取更多信息
+ TryReadPluginMetadata();
+ }
+
+ ///
+ /// 尝试从插件数据中读取元数据
+ ///
+ private void TryReadPluginMetadata()
+ {
+ try
+ {
+ // 这里可以根据 .iccpp 文件的实际格式解析元数据
+ // 例如,如果文件有特定的头部结构,可以在这里解析
+
+ // 示例:如果前100字节包含元数据
+ if (_pluginData.Length > 100)
+ {
+ // 解析元数据的代码...
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"解析插件 {_pluginName} 元数据时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ #region IPlugin 接口实现
+
+ ///
+ /// 插件名称
+ ///
+ public override string Name => _pluginName;
+
+ ///
+ /// 插件描述
+ ///
+ public override string Description => $"{_pluginName} (ICCPP 格式插件)";
+
+ ///
+ /// 插件版本
+ ///
+ public override Version Version => _pluginVersion;
+
+ ///
+ /// 插件作者
+ ///
+ public override string Author => "未知";
+
+ ///
+ /// 是否为内置插件
+ ///
+ public override bool IsBuiltIn => false;
+
+ ///
+ /// 初始化插件
+ ///
+ public override void Initialize()
+ {
+ if (_isInitialized) return;
+
+ try
+ {
+ // 这里可以添加 .iccpp 插件的初始化逻辑
+ // 例如,根据文件格式加载特定资源
+
+ LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已初始化", LogHelper.LogType.Info);
+ _isInitialized = true;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"初始化 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 启用插件
+ ///
+ public override void Enable()
+ {
+ if (IsEnabled) return;
+
+ try
+ {
+ // 这里可以添加 .iccpp 插件的启用逻辑
+ // 例如,加载动态库、注册事件等
+
+ base.Enable(); // 设置启用状态并触发事件
+ LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已启用", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"启用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 禁用插件
+ ///
+ public override void Disable()
+ {
+ if (!IsEnabled) return;
+
+ try
+ {
+ // 这里可以添加 .iccpp 插件的禁用逻辑
+ // 例如,卸载动态库、注销事件等
+
+ base.Disable(); // 设置禁用状态并触发事件
+ LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已禁用", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"禁用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 清理插件资源
+ ///
+ public override void Cleanup()
+ {
+ try
+ {
+ // 这里可以添加 .iccpp 插件的清理逻辑
+ // 例如,释放资源等
+
+ LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已清理资源", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"清理 ICCPP 插件 {Name} 资源时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Helpers/Plugins/PluginManager.cs b/Ink Canvas/Helpers/Plugins/PluginManager.cs
index c43e0283..2055cc68 100644
--- a/Ink Canvas/Helpers/Plugins/PluginManager.cs
+++ b/Ink Canvas/Helpers/Plugins/PluginManager.cs
@@ -195,8 +195,12 @@ namespace Ink_Canvas.Helpers.Plugins
return;
}
- // 获取所有插件文件
- var pluginFiles = Directory.GetFiles(PluginsDirectory, "*.iccpp", SearchOption.TopDirectoryOnly);
+ // 获取所有插件文件(支持 .iccpp 和 .dll 格式)
+ var pluginFiles = Directory.GetFiles(PluginsDirectory, "*.iccpp", SearchOption.TopDirectoryOnly)
+ .Concat(Directory.GetFiles(PluginsDirectory, "*.dll", SearchOption.TopDirectoryOnly))
+ .ToArray();
+
+ LogHelper.WriteLogToFile($"发现 {pluginFiles.Length} 个外部插件文件", LogHelper.LogType.Info);
foreach (var pluginFile in pluginFiles)
{
@@ -222,6 +226,14 @@ namespace Ink_Canvas.Helpers.Plugins
string fileHash = CalculateFileHash(pluginPath);
_pluginHashes[pluginPath] = fileHash;
+ // 检查文件扩展名
+ string extension = Path.GetExtension(pluginPath).ToLowerInvariant();
+ if (extension == ".iccpp")
+ {
+ // 创建 ICCPP 插件适配器
+ return CreateICCPPPluginAdapter(pluginPath);
+ }
+
// 加载插件程序集
Assembly pluginAssembly = LoadPluginAssembly(pluginPath);
if (pluginAssembly == null) return null;
@@ -253,16 +265,48 @@ namespace Ink_Canvas.Helpers.Plugins
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"实例化插件 {pluginType.Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ LogHelper.WriteLogToFile($"实例化插件类型 {pluginType.Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
+
+ LogHelper.WriteLogToFile($"在程序集 {Path.GetFileName(pluginPath)} 中未找到有效的插件类型", LogHelper.LogType.Warning);
+ return null;
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"加载插件 {Path.GetFileName(pluginPath)} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ LogHelper.WriteLogToFile($"加载外部插件 {Path.GetFileName(pluginPath)} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
+ ///
+ /// 创建 ICCPP 插件适配器
+ ///
+ /// 插件文件路径
+ /// 适配的插件实例
+ private IPlugin CreateICCPPPluginAdapter(string pluginPath)
+ {
+ try
+ {
+ // 读取插件文件内容
+ byte[] pluginData = File.ReadAllBytes(pluginPath);
+
+ // 创建适配器插件实例
+ var pluginAdapter = new ICCPPPluginAdapter(pluginPath, pluginData);
+
+ // 添加到插件列表
+ Plugins.Add(pluginAdapter);
+
+ LogHelper.WriteLogToFile($"已创建 ICCPP 插件适配器: {pluginAdapter.Name} 来自 {Path.GetFileName(pluginPath)}",
+ LogHelper.LogType.Info);
+
+ return pluginAdapter;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"创建 ICCPP 插件适配器时出错: {ex.Message}", LogHelper.LogType.Error);
+ return null;
}
-
- return null;
}
///
@@ -280,7 +324,7 @@ namespace Ink_Canvas.Helpers.Plugins
return loadedAssembly;
}
- // 加载程序集
+ // 直接加载程序集
Assembly pluginAssembly = Assembly.LoadFrom(pluginPath);
_loadedAssemblies[pluginPath] = pluginAssembly;
@@ -483,117 +527,63 @@ namespace Ink_Canvas.Helpers.Plugins
{
try
{
- LogHelper.WriteLogToFile($"开始重载插件: {plugin.Name}", LogHelper.LogType.Info);
-
- // 记录插件状态和信息
- bool wasEnabled = plugin.IsEnabled;
string pluginPath = plugin.PluginPath;
- string pluginTypeName = plugin.GetType().FullName;
-
- // 记录日志,方便排查问题
- LogHelper.WriteLogToFile($"重载前插件状态 - 类型: {pluginTypeName}, 状态: {(wasEnabled ? "启用" : "禁用")}", LogHelper.LogType.Info);
-
- // 如果配置中有该插件的状态,记录配置中的状态
- if (PluginStates.TryGetValue(pluginTypeName, out bool currentConfigState))
+ if (string.IsNullOrEmpty(pluginPath) || !File.Exists(pluginPath))
{
- LogHelper.WriteLogToFile($"配置中插件状态: {(currentConfigState ? "启用" : "禁用")}", LogHelper.LogType.Info);
+ LogHelper.WriteLogToFile($"无法重新加载插件 {plugin.Name}: 插件文件不存在", LogHelper.LogType.Error);
+ return;
}
- // 卸载插件,但不从PluginStates中移除状态信息
- UnloadPlugin(plugin);
+ LogHelper.WriteLogToFile($"开始热重载插件: {plugin.Name} ({Path.GetFileName(pluginPath)})", LogHelper.LogType.Info);
- // 清除程序集缓存,确保加载最新版本
- _loadedAssemblies.Remove(pluginPath);
+ // 保存插件的当前状态
+ bool wasEnabled = plugin.IsEnabled;
+ string pluginTypeName = plugin.GetType().FullName;
+
+ // 卸载插件
+ UnloadPlugin(plugin, false);
+
+ // 从加载缓存中移除
+ if (_loadedAssemblies.ContainsKey(pluginPath))
+ {
+ _loadedAssemblies.Remove(pluginPath);
+ }
+
+ // 计算新的文件哈希
+ string newHash = CalculateFileHash(pluginPath);
+ _pluginHashes[pluginPath] = newHash;
// 重新加载插件
IPlugin newPlugin = LoadExternalPlugin(pluginPath);
if (newPlugin != null)
{
- // 更新配置中的插件状态
- string newPluginTypeName = newPlugin.GetType().FullName;
+ // 恢复插件状态
+ if (wasEnabled)
+ {
+ newPlugin.Enable();
+ }
- // 如果插件类型名称变化,需要更新配置
- if (newPluginTypeName != pluginTypeName && PluginStates.ContainsKey(pluginTypeName))
+ // 更新配置(如果类型名称变化)
+ string newPluginTypeName = newPlugin.GetType().FullName;
+ if (pluginTypeName != newPluginTypeName && PluginStates.ContainsKey(pluginTypeName))
{
bool state = PluginStates[pluginTypeName];
PluginStates.Remove(pluginTypeName);
PluginStates[newPluginTypeName] = state;
- LogHelper.WriteLogToFile($"插件类型名称已变更: {pluginTypeName} -> {newPluginTypeName}, 已更新配置", LogHelper.LogType.Info);
+ _configDirty = true;
+ SaveConfig();
}
- // 应用正确的状态
- bool shouldBeEnabled = false;
- if (PluginStates.TryGetValue(newPluginTypeName, out bool storedConfigState))
- {
- shouldBeEnabled = storedConfigState;
- LogHelper.WriteLogToFile($"从配置获取插件状态: {(shouldBeEnabled ? "启用" : "禁用")}", LogHelper.LogType.Info);
- }
- else
- {
- shouldBeEnabled = wasEnabled;
- PluginStates[newPluginTypeName] = shouldBeEnabled;
- LogHelper.WriteLogToFile($"使用之前的状态: {(shouldBeEnabled ? "启用" : "禁用")}", LogHelper.LogType.Info);
- }
+ LogHelper.WriteLogToFile($"插件 {newPlugin.Name} v{newPlugin.Version} 热重载成功", LogHelper.LogType.Info);
- // 获取重载后的实际状态
- bool currentState = newPlugin is PluginBase pluginBaseState && pluginBaseState.IsEnabled;
- LogHelper.WriteLogToFile($"重载后实际状态: {(currentState ? "启用" : "禁用")}", LogHelper.LogType.Info);
-
- // 根据应该启用的状态启用或禁用插件
- if (shouldBeEnabled != currentState)
- {
- if (shouldBeEnabled)
- {
- newPlugin.Enable();
- LogHelper.WriteLogToFile($"插件 {newPlugin.Name} 已重载并启用", LogHelper.LogType.Info);
- }
- else
- {
- newPlugin.Disable();
- LogHelper.WriteLogToFile($"插件 {newPlugin.Name} 已重载并禁用", LogHelper.LogType.Info);
- }
-
- // 检查状态是否正确应用
- currentState = newPlugin is PluginBase reloadedBase && reloadedBase.IsEnabled;
- LogHelper.WriteLogToFile($"应用状态后实际状态: {(currentState ? "启用" : "禁用")}", LogHelper.LogType.Info);
-
- if (currentState != shouldBeEnabled)
- {
- LogHelper.WriteLogToFile($"警告: 插件状态应用失败,目标状态: {(shouldBeEnabled ? "启用" : "禁用")}, 实际状态: {(currentState ? "启用" : "禁用")}", LogHelper.LogType.Warning);
- }
- }
- else
- {
- LogHelper.WriteLogToFile($"插件 {newPlugin.Name} 已重载并保持{(shouldBeEnabled ? "启用" : "禁用")}状态", LogHelper.LogType.Info);
- }
-
- // 保存插件设置
- if (newPlugin is PluginBase pluginBaseInstance)
- {
- try
- {
- // 保存插件设置(与启用状态无关)
- pluginBaseInstance.SavePluginSettings();
- LogHelper.WriteLogToFile($"已保存插件 {newPlugin.Name} 设置", LogHelper.LogType.Info);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"保存插件 {newPlugin.Name} 设置时出错: {ex.Message}", LogHelper.LogType.Error);
- }
- }
-
- // 立即保存配置
- LogHelper.WriteLogToFile($"重载后保存插件配置...", LogHelper.LogType.Info);
- SaveConfig();
+ // 通知UI刷新
+ NotifyUIRefresh();
}
else
{
- LogHelper.WriteLogToFile($"插件 {plugin.Name} 重载失败: 无法加载新插件", LogHelper.LogType.Error);
+ LogHelper.WriteLogToFile($"插件 {plugin.Name} 热重载失败", LogHelper.LogType.Error);
}
-
- // 更新UI
- NotifyUIRefresh();
}
catch (Exception ex)
{
@@ -605,11 +595,14 @@ namespace Ink_Canvas.Helpers.Plugins
/// 卸载插件
///
/// 要卸载的插件
- /// 是否从配置中移除插件状态(默认为false)
+ /// 是否从配置中移除
public void UnloadPlugin(IPlugin plugin, bool removeFromConfig = false)
{
try
{
+ // 保存插件名称,以便在卸载后使用
+ string pluginName = plugin.Name;
+
// 如果插件已启用,先禁用它
if (plugin is PluginBase pluginBase && pluginBase.IsEnabled)
{
@@ -633,11 +626,11 @@ namespace Ink_Canvas.Helpers.Plugins
}
}
- LogHelper.WriteLogToFile($"已卸载插件: {plugin.Name}", LogHelper.LogType.Info);
+ LogHelper.WriteLogToFile($"已卸载插件: {pluginName}", LogHelper.LogType.Info);
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"卸载插件 {plugin.Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ LogHelper.WriteLogToFile($"卸载插件时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
@@ -656,6 +649,9 @@ namespace Ink_Canvas.Helpers.Plugins
return false;
}
+ // 保存插件名称,以便在删除后使用
+ string pluginName = plugin.Name;
+
// 获取插件路径
string pluginPath = null;
if (plugin is PluginBase pluginBase)
@@ -681,12 +677,12 @@ namespace Ink_Canvas.Helpers.Plugins
// 保存配置
SaveConfig();
- LogHelper.WriteLogToFile($"已删除插件: {plugin.Name}", LogHelper.LogType.Info);
+ LogHelper.WriteLogToFile($"已删除插件: {pluginName}", LogHelper.LogType.Info);
return true;
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"删除插件 {plugin.Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ LogHelper.WriteLogToFile($"删除插件时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
diff --git a/Ink Canvas/Windows/PluginSettingsWindow.xaml.cs b/Ink Canvas/Windows/PluginSettingsWindow.xaml.cs
index 55b2b927..c43c7d3c 100644
--- a/Ink Canvas/Windows/PluginSettingsWindow.xaml.cs
+++ b/Ink Canvas/Windows/PluginSettingsWindow.xaml.cs
@@ -292,9 +292,12 @@ namespace Ink_Canvas.Windows
return;
}
+ // 保存插件名称,以便在删除后使用
+ string pluginName = SelectedPlugin.Name;
+
// 确认删除
MessageBoxResult result = MessageBox.Show(
- $"确定要删除插件 {SelectedPlugin.Name} 吗?\n此操作将永久删除插件文件,无法恢复。",
+ $"确定要删除插件 {pluginName} 吗?\n此操作将永久删除插件文件,无法恢复。",
"删除确认",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
@@ -315,11 +318,11 @@ namespace Ink_Canvas.Windows
PluginListView.SelectedIndex = 0;
}
- MessageBox.Show($"插件 {SelectedPlugin.Name} 已成功删除。", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
+ MessageBox.Show($"插件 {pluginName} 已成功删除。", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
else
{
- MessageBox.Show("删除插件失败,请稍后重试。", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ MessageBox.Show($"删除插件 {pluginName} 失败,请稍后重试。", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}