improve:插件功能

This commit is contained in:
2025-07-17 22:30:12 +08:00
parent 285f211f50
commit 7ac3a22fa6
3 changed files with 271 additions and 103 deletions
@@ -0,0 +1,169 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace Ink_Canvas.Helpers.Plugins
{
/// <summary>
/// ICCPP 插件适配器,用于加载和管理 .iccpp 格式的插件
/// </summary>
public class ICCPPPluginAdapter : PluginBase
{
private readonly byte[] _pluginData;
private readonly string _pluginPath;
private readonly string _pluginName;
private readonly Version _pluginVersion;
private bool _isInitialized = false;
/// <summary>
/// 创建 ICCPP 插件适配器
/// </summary>
/// <param name="pluginPath">插件文件路径</param>
/// <param name="pluginData">插件文件数据</param>
public ICCPPPluginAdapter(string pluginPath, byte[] pluginData)
{
_pluginPath = pluginPath;
_pluginData = pluginData;
PluginPath = pluginPath;
// 从文件名获取插件名称
_pluginName = Path.GetFileNameWithoutExtension(pluginPath);
_pluginVersion = new Version(1, 0, 0); // 默认版本
// 尝试从插件数据中读取更多信息
TryReadPluginMetadata();
}
/// <summary>
/// 尝试从插件数据中读取元数据
/// </summary>
private void TryReadPluginMetadata()
{
try
{
// 这里可以根据 .iccpp 文件的实际格式解析元数据
// 例如,如果文件有特定的头部结构,可以在这里解析
// 示例:如果前100字节包含元数据
if (_pluginData.Length > 100)
{
// 解析元数据的代码...
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"解析插件 {_pluginName} 元数据时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#region IPlugin
/// <summary>
/// 插件名称
/// </summary>
public override string Name => _pluginName;
/// <summary>
/// 插件描述
/// </summary>
public override string Description => $"{_pluginName} (ICCPP 格式插件)";
/// <summary>
/// 插件版本
/// </summary>
public override Version Version => _pluginVersion;
/// <summary>
/// 插件作者
/// </summary>
public override string Author => "未知";
/// <summary>
/// 是否为内置插件
/// </summary>
public override bool IsBuiltIn => false;
/// <summary>
/// 初始化插件
/// </summary>
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);
}
}
/// <summary>
/// 启用插件
/// </summary>
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);
}
}
/// <summary>
/// 禁用插件
/// </summary>
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);
}
}
/// <summary>
/// 清理插件资源
/// </summary>
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
}
}
+95 -99
View File
@@ -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,17 +265,49 @@ 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;
}
}
/// <summary>
/// 创建 ICCPP 插件适配器
/// </summary>
/// <param name="pluginPath">插件文件路径</param>
/// <returns>适配的插件实例</returns>
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;
}
}
/// <summary>
/// 加载插件程序集
@@ -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);
// 清除程序集缓存,确保加载最新版本
// 保存插件的当前状态
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);
}
// 应用正确的状态
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);
}
// 获取重载后的实际状态
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);
_configDirty = true;
SaveConfig();
}
LogHelper.WriteLogToFile($"插件 {newPlugin.Name} v{newPlugin.Version} 热重载成功", LogHelper.LogType.Info);
// 通知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
/// 卸载插件
/// </summary>
/// <param name="plugin">要卸载的插件</param>
/// <param name="removeFromConfig">是否从配置中移除插件状态(默认为false</param>
/// <param name="removeFromConfig">是否从配置中移除</param>
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;
}
}
@@ -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);
}
}
}