1502 lines
54 KiB
C#
1502 lines
54 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Xml.Linq;
|
||
|
||
using AddinManager.Models;
|
||
|
||
using Newtonsoft.Json;
|
||
|
||
namespace AddinManager.Services
|
||
{
|
||
/// <summary>
|
||
/// 插件管理服务
|
||
/// </summary>
|
||
public class AddinManagerService
|
||
{
|
||
private readonly string _revitVersion;
|
||
private readonly List<string> _addinFolderPaths;
|
||
private readonly string _configPath;
|
||
private readonly Dictionary<string, Assembly> _loadedAssemblies = new Dictionary<string, Assembly>();
|
||
|
||
public AddinManagerService(string revitVersion = null)
|
||
{
|
||
_revitVersion = revitVersion ?? DetectCurrentRevitVersion();
|
||
_addinFolderPaths = GetAllAddinDirectories(_revitVersion);
|
||
|
||
// 配置文件放在用户目录下
|
||
var userAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "Revit", "Addins", _revitVersion);
|
||
_configPath = Path.Combine(userAddinPath, "AddinManagerConfig.json");
|
||
|
||
EnsureDirectoriesExist();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 动态检测当前运行的Revit版本
|
||
/// </summary>
|
||
private string DetectCurrentRevitVersion()
|
||
{
|
||
try
|
||
{
|
||
// 方法1:从当前运行的Revit进程检测
|
||
var revitProcesses = Process.GetProcessesByName("Revit");
|
||
if (revitProcesses.Length > 0)
|
||
{
|
||
var process = revitProcesses[0];
|
||
var version = ExtractVersionFromProcess(process);
|
||
if (!string.IsNullOrEmpty(version))
|
||
{
|
||
return version;
|
||
}
|
||
}
|
||
|
||
// 方法2:从Revit API获取版本(如果在Revit环境中运行)
|
||
try
|
||
{
|
||
var app = AddinManagerApp.UiApplication.Application;
|
||
return app.VersionNumber;
|
||
}
|
||
catch
|
||
{
|
||
// 忽略Revit API获取失败
|
||
}
|
||
// 方法3:从注册表获取最新安装的版本
|
||
var installedVersions = GetInstalledRevitVersions();
|
||
if (installedVersions.Count > 0)
|
||
{
|
||
return installedVersions.OrderByDescending(v => v).First();
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略检测失败
|
||
}
|
||
|
||
// 默认返回2024版本
|
||
return "2024";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从进程信息中提取Revit版本
|
||
/// </summary>
|
||
private string ExtractVersionFromProcess(Process process)
|
||
{
|
||
try
|
||
{
|
||
var fileName = process.MainModule?.FileName;
|
||
if (!string.IsNullOrEmpty(fileName))
|
||
{
|
||
var directory = Path.GetDirectoryName(fileName);
|
||
if (directory != null)
|
||
{
|
||
// 从路径中提取版本号
|
||
for (int year = 2018; year <= 2030; year++)
|
||
{
|
||
if (directory.Contains(year.ToString()))
|
||
{
|
||
return year.ToString();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 从文件版本信息中获取
|
||
var versionInfo = FileVersionInfo.GetVersionInfo(fileName);
|
||
if (versionInfo.ProductVersion != null)
|
||
{
|
||
var match = System.Text.RegularExpressions.Regex.Match(versionInfo.ProductVersion, @"(\d{4})");
|
||
if (match.Success)
|
||
{
|
||
return match.Groups[1].Value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略错误
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取系统中安装的所有Revit版本
|
||
/// </summary>
|
||
private List<string> GetInstalledRevitVersions()
|
||
{
|
||
var versions = new HashSet<string>();
|
||
|
||
try
|
||
{
|
||
// 从注册表获取
|
||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Autodesk\Revit"))
|
||
{
|
||
if (key != null)
|
||
{
|
||
foreach (var subKeyName in key.GetSubKeyNames())
|
||
{
|
||
if (int.TryParse(subKeyName, out int year) && year >= 2018 && year <= 2030)
|
||
{
|
||
versions.Add(subKeyName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 从WOW6432Node获取
|
||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Autodesk\Revit"))
|
||
{
|
||
if (key != null)
|
||
{
|
||
foreach (var subKeyName in key.GetSubKeyNames())
|
||
{
|
||
if (int.TryParse(subKeyName, out int year) && year >= 2018 && year <= 2030)
|
||
{
|
||
versions.Add(subKeyName);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 从文件系统检查
|
||
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||
var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
|
||
|
||
foreach (var baseDir in new[] { programFiles, programFilesX86 })
|
||
{
|
||
if (string.IsNullOrEmpty(baseDir)) continue;
|
||
|
||
var autodeskDir = Path.Combine(baseDir, "Autodesk");
|
||
if (Directory.Exists(autodeskDir))
|
||
{
|
||
foreach (var dir in Directory.GetDirectories(autodeskDir, "Revit *"))
|
||
{
|
||
var dirName = Path.GetFileName(dir);
|
||
var match = System.Text.RegularExpressions.Regex.Match(dirName, @"Revit (\d{4})");
|
||
if (match.Success)
|
||
{
|
||
versions.Add(match.Groups[1].Value);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略错误
|
||
}
|
||
|
||
return versions.ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有可能的插件目录
|
||
/// </summary>
|
||
private List<string> GetAllAddinDirectories(string revitVersion)
|
||
{
|
||
var directories = new List<string>();
|
||
|
||
// 1. 用户级插件目录 (当前用户) - .addin文件
|
||
var userAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "Revit", "Addins", revitVersion);
|
||
directories.Add(userAddinPath);
|
||
|
||
// 2. 用户级ApplicationPlugins目录 - .bundle文件夹
|
||
var userAppPluginsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "ApplicationPlugins");
|
||
directories.Add(userAppPluginsPath);
|
||
|
||
// 3. 全局插件目录 (所有用户) - .addin文件
|
||
var globalAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
||
"Autodesk", "Revit", "Addins", revitVersion);
|
||
directories.Add(globalAddinPath);
|
||
|
||
// 4. 全局ApplicationPlugins目录 - .bundle文件夹
|
||
var globalAppPluginsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
|
||
"Autodesk", "ApplicationPlugins");
|
||
directories.Add(globalAppPluginsPath);
|
||
|
||
// 5. 程序文件目录下的通用插件目录
|
||
var programFilesAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||
"Autodesk", $"Revit {revitVersion}", "AddIns");
|
||
if (Directory.Exists(programFilesAddinPath))
|
||
{
|
||
directories.Add(programFilesAddinPath);
|
||
}
|
||
|
||
// 6. 程序文件(x86)目录下的插件目录
|
||
var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
|
||
if (!string.IsNullOrEmpty(programFilesX86))
|
||
{
|
||
var programFilesX86AddinPath = Path.Combine(programFilesX86, "Autodesk", $"Revit {revitVersion}", "AddIns");
|
||
if (Directory.Exists(programFilesX86AddinPath))
|
||
{
|
||
directories.Add(programFilesX86AddinPath);
|
||
}
|
||
}
|
||
|
||
// 去重并返回存在的目录
|
||
return directories.Distinct().Where(Directory.Exists).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取Revit的安装路径
|
||
/// </summary>
|
||
private List<string> GetRevitInstallPaths(string revitVersion)
|
||
{
|
||
var installPaths = new List<string>();
|
||
|
||
try
|
||
{
|
||
// 从注册表查找Revit安装路径
|
||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Autodesk\Revit\{revitVersion}"))
|
||
{
|
||
if (key != null)
|
||
{
|
||
var installPath = key.GetValue("InstallationPath") as string;
|
||
if (!string.IsNullOrEmpty(installPath) && Directory.Exists(installPath))
|
||
{
|
||
installPaths.Add(installPath);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 从注册表查找其他可能的路径 (WOW6432Node for 32-bit apps on 64-bit Windows)
|
||
using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey($@"SOFTWARE\WOW6432Node\Autodesk\Revit\{revitVersion}"))
|
||
{
|
||
if (key != null)
|
||
{
|
||
var installPath = key.GetValue("InstallationPath") as string;
|
||
if (!string.IsNullOrEmpty(installPath) && Directory.Exists(installPath))
|
||
{
|
||
installPaths.Add(installPath);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略注册表读取错误
|
||
}
|
||
|
||
// 如果注册表查找失败,尝试常见的安装路径
|
||
var commonPaths = new[]
|
||
{
|
||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Autodesk", $"Revit {revitVersion}"),
|
||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Autodesk", $"Revit {revitVersion}"),
|
||
Path.Combine("C:", "Program Files", "Autodesk", $"Revit {revitVersion}"),
|
||
Path.Combine("C:", "Program Files (x86)", "Autodesk", $"Revit {revitVersion}")
|
||
};
|
||
|
||
foreach (var path in commonPaths)
|
||
{
|
||
if (Directory.Exists(path))
|
||
{
|
||
installPaths.Add(path);
|
||
}
|
||
}
|
||
|
||
return installPaths.Distinct().ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有已安装的插件(包括已禁用的和Bundle格式的)
|
||
/// </summary>
|
||
public List<AddinInfo> GetInstalledAddins()
|
||
{
|
||
var addins = new List<AddinInfo>();
|
||
|
||
// 扫描所有插件目录
|
||
foreach (var addinFolderPath in _addinFolderPaths)
|
||
{
|
||
if (!Directory.Exists(addinFolderPath))
|
||
continue;
|
||
|
||
try
|
||
{
|
||
// 检查是否是ApplicationPlugins目录(Bundle格式)
|
||
if (addinFolderPath.Contains("ApplicationPlugins"))
|
||
{
|
||
// 扫描Bundle格式插件
|
||
var bundleAddins = ScanBundlePlugins(addinFolderPath);
|
||
addins.AddRange(bundleAddins);
|
||
}
|
||
else
|
||
{
|
||
// 扫描传统.addin文件格式
|
||
var traditionalAddins = ScanTraditionalAddins(addinFolderPath);
|
||
addins.AddRange(traditionalAddins);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 记录目录访问错误
|
||
var errorAddin = new AddinInfo
|
||
{
|
||
Name = $"目录访问错误: {Path.GetFileName(addinFolderPath)}",
|
||
AddinFilePath = addinFolderPath,
|
||
SourceDirectory = addinFolderPath,
|
||
HasErrors = true,
|
||
ErrorMessages = new List<string> { $"无法访问目录: {ex.Message}" },
|
||
Status = "访问错误",
|
||
IsEnabled = false
|
||
};
|
||
addins.Add(errorAddin);
|
||
}
|
||
}
|
||
|
||
return addins;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扫描传统.addin文件格式的插件
|
||
/// </summary>
|
||
private List<AddinInfo> ScanTraditionalAddins(string addinFolderPath)
|
||
{
|
||
var addins = new List<AddinInfo>();
|
||
|
||
// 扫描所有.addin文件(包括.disabled文件)
|
||
var addinFiles = Directory.GetFiles(addinFolderPath, "*.addin", SearchOption.AllDirectories)
|
||
.Concat(Directory.GetFiles(addinFolderPath, "*.addin.disabled", SearchOption.AllDirectories))
|
||
.ToArray();
|
||
|
||
foreach (var addinFile in addinFiles)
|
||
{
|
||
try
|
||
{
|
||
var addinInfos = ParseAddinFile(addinFile);
|
||
foreach (var addinInfo in addinInfos)
|
||
{
|
||
// 标记插件来源目录
|
||
addinInfo.SourceDirectory = addinFolderPath;
|
||
addins.Add(addinInfo);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 记录解析错误
|
||
var errorAddin = new AddinInfo
|
||
{
|
||
Name = Path.GetFileNameWithoutExtension(addinFile),
|
||
AddinFilePath = addinFile,
|
||
SourceDirectory = addinFolderPath,
|
||
HasErrors = true,
|
||
ErrorMessages = new List<string> { ex.Message },
|
||
Status = "解析错误",
|
||
IsEnabled = false
|
||
};
|
||
addins.Add(errorAddin);
|
||
}
|
||
}
|
||
|
||
return addins;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 扫描Bundle格式的插件(.bundle文件夹)
|
||
/// </summary>
|
||
private List<AddinInfo> ScanBundlePlugins(string appPluginsPath)
|
||
{
|
||
var addins = new List<AddinInfo>();
|
||
|
||
// 查找所有.bundle文件夹
|
||
var bundleFolders = Directory.GetDirectories(appPluginsPath, "*.bundle", SearchOption.TopDirectoryOnly);
|
||
|
||
foreach (var bundleFolder in bundleFolders)
|
||
{
|
||
try
|
||
{
|
||
// 查找PackageContents.xml文件
|
||
var packageContentsPath = Path.Combine(bundleFolder, "PackageContents.xml");
|
||
if (File.Exists(packageContentsPath))
|
||
{
|
||
var bundleAddins = ParseBundlePackage(packageContentsPath, bundleFolder);
|
||
addins.AddRange(bundleAddins);
|
||
}
|
||
else
|
||
{
|
||
// 如果没有PackageContents.xml,记录为错误
|
||
var errorAddin = new AddinInfo
|
||
{
|
||
Name = Path.GetFileNameWithoutExtension(bundleFolder),
|
||
AddinFilePath = bundleFolder,
|
||
SourceDirectory = appPluginsPath,
|
||
HasErrors = true,
|
||
ErrorMessages = new List<string> { "Bundle文件夹中缺少PackageContents.xml文件" },
|
||
Status = "Bundle格式错误",
|
||
IsEnabled = false
|
||
};
|
||
addins.Add(errorAddin);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 记录Bundle解析错误
|
||
var errorAddin = new AddinInfo
|
||
{
|
||
Name = Path.GetFileNameWithoutExtension(bundleFolder),
|
||
AddinFilePath = bundleFolder,
|
||
SourceDirectory = appPluginsPath,
|
||
HasErrors = true,
|
||
ErrorMessages = new List<string> { $"Bundle解析错误: {ex.Message}" },
|
||
Status = "Bundle解析错误",
|
||
IsEnabled = false
|
||
};
|
||
addins.Add(errorAddin);
|
||
}
|
||
}
|
||
|
||
return addins;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解析Bundle格式的PackageContents.xml文件
|
||
/// </summary>
|
||
private List<AddinInfo> ParseBundlePackage(string packageContentsPath, string bundleFolder)
|
||
{
|
||
var addins = new List<AddinInfo>();
|
||
var doc = XDocument.Load(packageContentsPath);
|
||
|
||
// 获取Bundle的基本信息
|
||
var packageElement = doc.Element("ApplicationPackage");
|
||
if (packageElement == null) return addins;
|
||
|
||
var bundleName = packageElement.Attribute("Name")?.Value ?? Path.GetFileNameWithoutExtension(bundleFolder);
|
||
var bundleVersion = packageElement.Attribute("Version")?.Value ?? "Unknown";
|
||
var bundleDescription = packageElement.Attribute("Description")?.Value ?? "";
|
||
var bundleAuthor = packageElement.Attribute("Author")?.Value ?? "Unknown";
|
||
|
||
// 查找支持的Revit版本
|
||
var supportedVersions = new List<string>();
|
||
var componentsElement = packageElement.Element("Components");
|
||
if (componentsElement != null)
|
||
{
|
||
foreach (var runtimeRequirements in componentsElement.Descendants("RuntimeRequirements"))
|
||
{
|
||
var platform = runtimeRequirements.Attribute("Platform")?.Value;
|
||
var version = runtimeRequirements.Attribute("Version")?.Value;
|
||
|
||
if (platform == "Revit" && !string.IsNullOrEmpty(version))
|
||
{
|
||
supportedVersions.Add(version);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 查找所有的AddIn元素
|
||
foreach (var componentElement in componentsElement?.Elements("ComponentEntry") ?? Enumerable.Empty<XElement>())
|
||
{
|
||
var moduleType = componentElement.Attribute("ModuleType")?.Value;
|
||
if (moduleType != "Managed") continue; // 只处理托管代码插件
|
||
|
||
var appName = componentElement.Attribute("AppName")?.Value ?? bundleName;
|
||
var appDescription = componentElement.Attribute("AppDescription")?.Value ?? bundleDescription;
|
||
|
||
// 检查是否被禁用(通过重命名bundle文件夹)
|
||
bool isDisabled = bundleFolder.EndsWith(".bundle.disabled") || bundleFolder.EndsWith(".disabled");
|
||
|
||
var addin = new AddinInfo
|
||
{
|
||
Name = appName,
|
||
Description = appDescription,
|
||
Version = bundleVersion,
|
||
Developer = bundleAuthor,
|
||
AddinFilePath = packageContentsPath,
|
||
SourceDirectory = Path.GetDirectoryName(bundleFolder),
|
||
Type = AddinType.Application, // Bundle通常是Application类型
|
||
CurrentRevitVersion = _revitVersion,
|
||
LastModified = File.GetLastWriteTime(packageContentsPath),
|
||
IsEnabled = !isDisabled,
|
||
Status = isDisabled ? "已禁用" : "已启用"
|
||
};
|
||
|
||
// 添加支持的版本
|
||
foreach (var version in supportedVersions)
|
||
{
|
||
addin.SupportedRevitVersions.Add(version);
|
||
}
|
||
|
||
// 查找程序集路径
|
||
var appModule = componentElement.Element("AppModule");
|
||
if (appModule != null)
|
||
{
|
||
var relativePath = appModule.Value;
|
||
if (!string.IsNullOrEmpty(relativePath))
|
||
{
|
||
var assemblyPath = Path.Combine(bundleFolder, "Contents", relativePath);
|
||
addin.AssemblyPath = assemblyPath;
|
||
|
||
// 尝试获取程序集版本信息
|
||
if (File.Exists(assemblyPath))
|
||
{
|
||
try
|
||
{
|
||
var assembly = Assembly.LoadFrom(assemblyPath);
|
||
var assemblyVersion = assembly.GetName().Version?.ToString();
|
||
if (!string.IsNullOrEmpty(assemblyVersion))
|
||
{
|
||
addin.Version = assemblyVersion;
|
||
}
|
||
|
||
// 查找主类
|
||
var types = assembly.GetTypes();
|
||
var appType = types.FirstOrDefault(t => t.GetInterfaces()
|
||
.Any(i => i.Name.Contains("IExternalApplication")));
|
||
if (appType != null)
|
||
{
|
||
addin.ClassName = appType.FullName;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略程序集加载错误
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
addins.Add(addin);
|
||
}
|
||
|
||
return addins;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启用插件 - 支持传统.addin文件和Bundle格式
|
||
/// </summary>
|
||
public bool EnableAddin(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
// 检查是否是Bundle格式插件
|
||
if (IsBundlePlugin(addin))
|
||
{
|
||
return EnableBundlePlugin(addin);
|
||
}
|
||
else
|
||
{
|
||
return EnableTraditionalPlugin(addin);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
addin.ErrorMessages.Add($"启用失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 禁用插件 - 支持传统.addin文件和Bundle格式
|
||
/// </summary>
|
||
public bool DisableAddin(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
// 检查是否是Bundle格式插件
|
||
if (IsBundlePlugin(addin))
|
||
{
|
||
return DisableBundlePlugin(addin);
|
||
}
|
||
else
|
||
{
|
||
return DisableTraditionalPlugin(addin);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
addin.ErrorMessages.Add($"禁用失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否是Bundle格式插件
|
||
/// </summary>
|
||
private bool IsBundlePlugin(AddinInfo addin)
|
||
{
|
||
return addin.AddinFilePath.Contains("ApplicationPlugins") &&
|
||
addin.AddinFilePath.EndsWith("PackageContents.xml");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启用传统.addin文件格式插件
|
||
/// </summary>
|
||
private bool EnableTraditionalPlugin(AddinInfo addin)
|
||
{
|
||
if (!File.Exists(addin.AddinFilePath))
|
||
return false;
|
||
|
||
// 如果文件以.disabled结尾,重命名回.addin
|
||
if (addin.AddinFilePath.EndsWith(".disabled"))
|
||
{
|
||
string enabledPath = addin.AddinFilePath.Replace(".addin.disabled", ".addin");
|
||
File.Move(addin.AddinFilePath, enabledPath);
|
||
addin.AddinFilePath = enabledPath;
|
||
}
|
||
|
||
addin.IsEnabled = true;
|
||
SaveAddinState(addin);
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 禁用传统.addin文件格式插件
|
||
/// </summary>
|
||
private bool DisableTraditionalPlugin(AddinInfo addin)
|
||
{
|
||
if (!File.Exists(addin.AddinFilePath))
|
||
return false;
|
||
|
||
// 如果文件以.addin结尾,重命名为.addin.disabled
|
||
if (addin.AddinFilePath.EndsWith(".addin"))
|
||
{
|
||
string disabledPath = addin.AddinFilePath + ".disabled";
|
||
File.Move(addin.AddinFilePath, disabledPath);
|
||
addin.AddinFilePath = disabledPath;
|
||
}
|
||
|
||
addin.IsEnabled = false;
|
||
SaveAddinState(addin);
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启用Bundle格式插件
|
||
/// </summary>
|
||
private bool EnableBundlePlugin(AddinInfo addin)
|
||
{
|
||
var bundleFolder = Path.GetDirectoryName(addin.AddinFilePath);
|
||
if (!Directory.Exists(bundleFolder))
|
||
return false;
|
||
|
||
// 如果Bundle文件夹以.disabled结尾,重命名回.bundle
|
||
if (bundleFolder.EndsWith(".disabled"))
|
||
{
|
||
string enabledPath = bundleFolder.Replace(".bundle.disabled", ".bundle");
|
||
Directory.Move(bundleFolder, enabledPath);
|
||
|
||
// 更新插件信息中的路径
|
||
addin.AddinFilePath = Path.Combine(enabledPath, "PackageContents.xml");
|
||
addin.SourceDirectory = Path.GetDirectoryName(enabledPath);
|
||
}
|
||
else if (bundleFolder.EndsWith(".bundle.disabled"))
|
||
{
|
||
string enabledPath = bundleFolder.Replace(".bundle.disabled", ".bundle");
|
||
Directory.Move(bundleFolder, enabledPath);
|
||
|
||
// 更新插件信息中的路径
|
||
addin.AddinFilePath = Path.Combine(enabledPath, "PackageContents.xml");
|
||
addin.SourceDirectory = Path.GetDirectoryName(enabledPath);
|
||
}
|
||
|
||
addin.IsEnabled = true;
|
||
SaveAddinState(addin);
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 禁用Bundle格式插件
|
||
/// </summary>
|
||
private bool DisableBundlePlugin(AddinInfo addin)
|
||
{
|
||
var bundleFolder = Path.GetDirectoryName(addin.AddinFilePath);
|
||
if (!Directory.Exists(bundleFolder))
|
||
return false;
|
||
|
||
// 如果Bundle文件夹以.bundle结尾,重命名为.bundle.disabled
|
||
if (bundleFolder.EndsWith(".bundle"))
|
||
{
|
||
string disabledPath = bundleFolder + ".disabled";
|
||
Directory.Move(bundleFolder, disabledPath);
|
||
|
||
// 更新插件信息中的路径
|
||
addin.AddinFilePath = Path.Combine(disabledPath, "PackageContents.xml");
|
||
addin.SourceDirectory = Path.GetDirectoryName(disabledPath);
|
||
}
|
||
|
||
addin.IsEnabled = false;
|
||
SaveAddinState(addin);
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 卸载插件
|
||
/// </summary>
|
||
public bool UninstallAddin(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
// 删除.addin文件
|
||
if (File.Exists(addin.AddinFilePath))
|
||
{
|
||
File.Delete(addin.AddinFilePath);
|
||
}
|
||
|
||
// 删除程序集文件(如果在插件目录下)
|
||
if (File.Exists(addin.AssemblyPath) &&
|
||
_addinFolderPaths.Any(path => addin.AssemblyPath.StartsWith(path)))
|
||
{
|
||
File.Delete(addin.AssemblyPath);
|
||
}
|
||
|
||
RemoveAddinState(addin);
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
addin.ErrorMessages.Add($"卸载失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 热重载插件 - 增强版本
|
||
/// </summary>
|
||
public bool HotReloadAddin(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
// 先禁用插件
|
||
if (addin.IsEnabled)
|
||
{
|
||
DisableAddin(addin);
|
||
}
|
||
|
||
// 卸载已加载的程序集
|
||
if (_loadedAssemblies.ContainsKey(addin.AssemblyPath))
|
||
{
|
||
_loadedAssemblies.Remove(addin.AssemblyPath);
|
||
}
|
||
|
||
// 等待一段时间确保<E7A1AE><E4BF9D><EFBFBD>件释放
|
||
System.Threading.Thread.Sleep(500);
|
||
|
||
// 重新启用插件
|
||
EnableAddin(addin);
|
||
|
||
addin.LastModified = File.GetLastWriteTime(addin.AssemblyPath);
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
addin.ErrorMessages.Add($"热重载失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 安装插件
|
||
/// </summary>
|
||
public bool InstallAddin(string addinFilePath, string targetDirectory = null)
|
||
{
|
||
try
|
||
{
|
||
if (targetDirectory == null)
|
||
{
|
||
// 默认安装到用户插件目录(第一个目录)
|
||
targetDirectory = _addinFolderPaths.FirstOrDefault() ??
|
||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "Revit", "Addins", _revitVersion);
|
||
}
|
||
|
||
var fileName = Path.GetFileName(addinFilePath);
|
||
var targetPath = Path.Combine(targetDirectory, fileName);
|
||
|
||
File.Copy(addinFilePath, targetPath, true);
|
||
return true;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查插件兼容性
|
||
/// </summary>
|
||
public bool CheckCompatibility(AddinInfo addin)
|
||
{
|
||
return addin.SupportedRevitVersions.Contains(_revitVersion) ||
|
||
addin.SupportedRevitVersions.Count == 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取插件错误日志
|
||
/// </summary>
|
||
public List<string> GetAddinErrors(AddinInfo addin)
|
||
{
|
||
return addin.ErrorMessages;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 安装临时调试插件 - 直接加载到Revit中
|
||
/// </summary>
|
||
public bool InstallTemporaryDebugAddin(CommandInfo commandInfo, string commandName)
|
||
{
|
||
try
|
||
{
|
||
#if REVIT_API_AVAILABLE
|
||
// 直接通过Revit API加载插件
|
||
var uiApp = AddinManagerApp.UiApplication;
|
||
if (uiApp == null)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine("Revit应用程序未初始化");
|
||
return false;
|
||
}
|
||
|
||
// 加载程序集
|
||
var assembly = Assembly.LoadFrom(commandInfo.AssemblyPath);
|
||
var commandType = assembly.GetType(commandInfo.ClassName);
|
||
|
||
if (commandType == null)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"无法找到类型: {commandInfo.ClassName}");
|
||
return false;
|
||
}
|
||
|
||
// 创建外部命令数据
|
||
var commandData = new Autodesk.Revit.UI.ExternalCommandData();
|
||
|
||
// 将命令添加到临时调试命令列表
|
||
var tempCommandId = $"DebugCmd_{DateTime.Now:yyyyMMdd_HHmmss}_{Guid.NewGuid().ToString("N")[..8]}";
|
||
|
||
// 创建临时按钮(可选,用于UI访问)
|
||
try
|
||
{
|
||
var ribbonTab = uiApp.GetRibbonTabs().FirstOrDefault(t => t == "调试") ??
|
||
uiApp.CreateRibbonTab("调试");
|
||
|
||
var panel = uiApp.GetRibbonPanels("调试").FirstOrDefault(p => p.Name == "临时命令") ??
|
||
uiApp.CreateRibbonPanel("调试", "临时命令");
|
||
|
||
var buttonData = new Autodesk.Revit.UI.PushButtonData(
|
||
tempCommandId,
|
||
commandName,
|
||
commandInfo.AssemblyPath,
|
||
commandInfo.ClassName);
|
||
|
||
var button = panel.AddItem(buttonData) as Autodesk.Revit.UI.PushButton;
|
||
if (button != null)
|
||
{
|
||
button.ToolTip = $"临时调试命令: {commandName}";
|
||
button.LongDescription = $"从 {Path.GetFileName(commandInfo.AssemblyPath)} 加载的调试命令";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"创建临时按钮失败: {ex.Message}");
|
||
// 即使按钮创建失败,命令仍然可以通过其他方式调用
|
||
}
|
||
|
||
// 记录已加载的临时命令
|
||
if (!_loadedAssemblies.ContainsKey(commandInfo.AssemblyPath))
|
||
{
|
||
_loadedAssemblies.Add(commandInfo.AssemblyPath, assembly);
|
||
}
|
||
|
||
return true;
|
||
#else
|
||
// 在没有Revit API的环境中,仍然创建.addin文件作为fallback
|
||
return CreateTemporaryAddinFile(commandInfo, commandName);
|
||
#endif
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"直接加载插件失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建临时.addin文件作为备用方案
|
||
/// </summary>
|
||
private bool CreateTemporaryAddinFile(CommandInfo commandInfo, string commandName)
|
||
{
|
||
try
|
||
{
|
||
// 确保用户插件目录存在
|
||
var userAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "Revit", "Addins", _revitVersion);
|
||
|
||
if (!Directory.Exists(userAddinPath))
|
||
{
|
||
Directory.CreateDirectory(userAddinPath);
|
||
}
|
||
|
||
// 生成临时插件的唯一标识
|
||
var tempAddinId = $"DebugAddin_{DateTime.Now:yyyyMMdd_HHmmss}_{Guid.NewGuid().ToString("N")[..8]}";
|
||
var tempAddinFileName = $"{tempAddinId}.addin";
|
||
var tempAddinFilePath = Path.Combine(userAddinPath, tempAddinFileName);
|
||
|
||
// 创建临时.addin文件内容
|
||
var addinXml = CreateDebugAddinXml(commandInfo, commandName, tempAddinId);
|
||
|
||
// 写入.addin文件
|
||
File.WriteAllText(tempAddinFilePath, addinXml);
|
||
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"创建临时addin文件失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直接执行命令(用于调试测试)
|
||
/// </summary>
|
||
public bool ExecuteCommand(CommandInfo commandInfo)
|
||
{
|
||
try
|
||
{
|
||
#if REVIT_API_AVAILABLE
|
||
var uiApp = AddinManagerApp.UiApplication;
|
||
if (uiApp == null) return false;
|
||
|
||
// 加载程序集
|
||
var assembly = Assembly.LoadFrom(commandInfo.AssemblyPath);
|
||
var commandType = assembly.GetType(commandInfo.ClassName);
|
||
|
||
if (commandType == null) return false;
|
||
|
||
// 创建命令实例
|
||
var commandInstance = Activator.CreateInstance(commandType) as Autodesk.Revit.UI.IExternalCommand;
|
||
if (commandInstance == null) return false;
|
||
|
||
// 准备命令数据
|
||
var commandData = new Autodesk.Revit.UI.ExternalCommandData
|
||
{
|
||
Application = uiApp,
|
||
JournalData = new Autodesk.Revit.DB.NameValueMap()
|
||
};
|
||
|
||
var message = string.Empty;
|
||
var elementSet = new Autodesk.Revit.DB.ElementSet();
|
||
|
||
// 执行命令
|
||
var result = commandInstance.Execute(commandData, ref message, elementSet);
|
||
|
||
return result == Autodesk.Revit.UI.Result.Succeeded;
|
||
#else
|
||
return false;
|
||
#endif
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"执行命令失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 卸载临时调试插件
|
||
/// </summary>
|
||
public bool UnloadTemporaryDebugAddin(string assemblyPath)
|
||
{
|
||
try
|
||
{
|
||
// 从已加载程序集列表中移除
|
||
if (_loadedAssemblies.ContainsKey(assemblyPath))
|
||
{
|
||
_loadedAssemblies.Remove(assemblyPath);
|
||
}
|
||
|
||
// 释放程序集引用
|
||
ReleaseDllReferences();
|
||
|
||
return true;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"卸载临时插件失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建调试插件的XML内容
|
||
/// </summary>
|
||
private string CreateDebugAddinXml(CommandInfo commandInfo, string commandName, string addinId)
|
||
{
|
||
var xml = $@"<?xml version=""1.0"" encoding=""utf-8""?>
|
||
<RevitAddIns>
|
||
<AddIn Type=""Command"">
|
||
<Name>{commandName}</Name>
|
||
<Assembly>{commandInfo.AssemblyPath}</Assembly>
|
||
<FullClassName>{commandInfo.ClassName}</FullClassName>
|
||
<Description>临时调试插件 - {commandName}</Description>
|
||
<VendorId>AddinManager.Debug</VendorId>
|
||
<VendorDescription>Revit插件管理器调试功能</VendorDescription>
|
||
<SupportedVersion>{_revitVersion}</SupportedVersion>
|
||
<Transaction>{commandInfo.TransactionMode}</Transaction>
|
||
</AddIn>
|
||
</RevitAddIns>";
|
||
|
||
return xml;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从DLL中获取命令信息
|
||
/// </summary>
|
||
public List<CommandInfo> GetCommandsFromDll(string dllPath)
|
||
{
|
||
var commands = new List<CommandInfo>();
|
||
|
||
try
|
||
{
|
||
if (!File.Exists(dllPath))
|
||
{
|
||
return commands;
|
||
}
|
||
|
||
// 加载程序集
|
||
var assembly = Assembly.LoadFrom(dllPath);
|
||
|
||
// 查找实现IExternalCommand接口的类
|
||
foreach (var type in assembly.GetTypes())
|
||
{
|
||
if (type.IsClass && !type.IsAbstract)
|
||
{
|
||
// 检查是否实现了IExternalCommand接口
|
||
var interfaces = type.GetInterfaces();
|
||
bool implementsIExternalCommand = false;
|
||
|
||
foreach (var interfaceType in interfaces)
|
||
{
|
||
if (interfaceType.Name == "IExternalCommand" ||
|
||
interfaceType.FullName?.Contains("IExternalCommand") == true)
|
||
{
|
||
implementsIExternalCommand = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (implementsIExternalCommand)
|
||
{
|
||
var commandInfo = new CommandInfo
|
||
{
|
||
ClassName = type.FullName,
|
||
AssemblyPath = dllPath,
|
||
Assembly = assembly,
|
||
Type = type,
|
||
TransactionMode = GetTransactionMode(type)
|
||
};
|
||
|
||
commands.Add(commandInfo);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 返回错误信息
|
||
var errorCommand = new CommandInfo
|
||
{
|
||
ClassName = "Error",
|
||
AssemblyPath = dllPath,
|
||
HasErrors = true,
|
||
ErrorMessage = ex.Message
|
||
};
|
||
commands.Add(errorCommand);
|
||
}
|
||
|
||
return commands;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取命令的事务模式
|
||
/// </summary>
|
||
private string GetTransactionMode(Type type)
|
||
{
|
||
try
|
||
{
|
||
// 查找Transaction特性
|
||
var transactionAttribute = type.GetCustomAttributes(false)
|
||
.FirstOrDefault(attr => attr.GetType().Name.Contains("Transaction"));
|
||
|
||
if (transactionAttribute != null)
|
||
{
|
||
// 尝试获取事务模式值
|
||
var modeProperty = transactionAttribute.GetType().GetProperty("Mode");
|
||
if (modeProperty != null)
|
||
{
|
||
var modeValue = modeProperty.GetValue(transactionAttribute);
|
||
return modeValue?.ToString() ?? "Manual";
|
||
}
|
||
}
|
||
|
||
return "Manual"; // 默认事务模式
|
||
}
|
||
catch
|
||
{
|
||
return "Manual";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 附加到Revit进程进行调试
|
||
/// </summary>
|
||
public bool AttachToRevitProcess()
|
||
{
|
||
try
|
||
{
|
||
var revitProcesses = Process.GetProcessesByName("Revit");
|
||
if (revitProcesses.Length == 0)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 如果有多个Revit进程,选择第一个
|
||
var revitProcess = revitProcesses[0];
|
||
var processId = revitProcess.Id;
|
||
|
||
// 尝试启动Visual Studio并附加到进程
|
||
var vsInstances = GetVisualStudioInstances();
|
||
if (vsInstances.Count > 0)
|
||
{
|
||
var vsPath = vsInstances.First();
|
||
var startInfo = new ProcessStartInfo
|
||
{
|
||
FileName = vsPath,
|
||
Arguments = $"/debugexe",
|
||
UseShellExecute = true
|
||
};
|
||
|
||
Process.Start(startInfo);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
catch
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取已安装的Visual Studio实例
|
||
/// </summary>
|
||
private List<string> GetVisualStudioInstances()
|
||
{
|
||
var instances = new List<string>();
|
||
|
||
try
|
||
{
|
||
// 查找Visual Studio的常见安装路径
|
||
var possiblePaths = new[]
|
||
{
|
||
@"Microsoft Visual Studio\2022\Enterprise\Common7\IDE\devenv.exe",
|
||
@"Microsoft Visual Studio\2022\Professional\Common7\IDE\devenv.exe",
|
||
@"Microsoft Visual Studio\2022\Community\Common7\IDE\devenv.exe",
|
||
@"Microsoft Visual Studio\2019\Enterprise\Common7\IDE\devenv.exe",
|
||
@"Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv.exe",
|
||
@"Microsoft Visual Studio\2019\Community\Common7\IDE\devenv.exe"
|
||
};
|
||
|
||
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||
var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
|
||
|
||
foreach (var basePath in new[] { programFiles, programFilesX86 })
|
||
{
|
||
if (string.IsNullOrEmpty(basePath)) continue;
|
||
|
||
foreach (var relativePath in possiblePaths)
|
||
{
|
||
var fullPath = Path.Combine(basePath, relativePath);
|
||
if (File.Exists(fullPath))
|
||
{
|
||
instances.Add(fullPath);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略错误
|
||
}
|
||
|
||
return instances;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理临时调试插件
|
||
/// </summary>
|
||
public void CleanupTemporaryDebugAddins()
|
||
{
|
||
try
|
||
{
|
||
var userAddinPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||
"Autodesk", "Revit", "Addins", _revitVersion);
|
||
|
||
if (!Directory.Exists(userAddinPath)) return;
|
||
|
||
// 查找所有临时调试插件文件
|
||
var tempFiles = Directory.GetFiles(userAddinPath, "DebugAddin_*.addin");
|
||
|
||
foreach (var tempFile in tempFiles)
|
||
{
|
||
try
|
||
{
|
||
// 检查文件是否超过1天,如果是则删除
|
||
var fileInfo = new FileInfo(tempFile);
|
||
if (DateTime.Now - fileInfo.CreationTime > TimeSpan.FromDays(1))
|
||
{
|
||
File.Delete(tempFile);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略单个文件删除失败
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略清理错误
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放程序集引用以便重新编译
|
||
/// </summary>
|
||
public void ReleaseDllReferences()
|
||
{
|
||
try
|
||
{
|
||
_loadedAssemblies.Clear();
|
||
|
||
// 强制垃圾回收
|
||
GC.Collect();
|
||
GC.WaitForPendingFinalizers();
|
||
GC.Collect();
|
||
}
|
||
catch
|
||
{
|
||
// 忽略错误
|
||
}
|
||
}
|
||
|
||
private void EnsureDirectoriesExist()
|
||
{
|
||
foreach (var directory in _addinFolderPaths)
|
||
{
|
||
if (!Directory.Exists(directory))
|
||
{
|
||
try
|
||
{
|
||
Directory.CreateDirectory(directory);
|
||
}
|
||
catch
|
||
{
|
||
// 忽略创建目录失败
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void SaveAddinState(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
var states = new Dictionary<string, bool>();
|
||
|
||
if (File.Exists(_configPath))
|
||
{
|
||
var json = File.ReadAllText(_configPath);
|
||
states = JsonConvert.DeserializeObject<Dictionary<string, bool>>(json) ?? new Dictionary<string, bool>();
|
||
}
|
||
|
||
var key = $"{addin.ClassName}|{Path.GetFileNameWithoutExtension(addin.AddinFilePath)}";
|
||
states[key] = addin.IsEnabled;
|
||
|
||
var updatedJson = JsonConvert.SerializeObject(states, Formatting.Indented);
|
||
File.WriteAllText(_configPath, updatedJson);
|
||
}
|
||
catch
|
||
{
|
||
// 忽略保存错误
|
||
}
|
||
}
|
||
|
||
private void RemoveAddinState(AddinInfo addin)
|
||
{
|
||
try
|
||
{
|
||
if (!File.Exists(_configPath))
|
||
return;
|
||
|
||
var json = File.ReadAllText(_configPath);
|
||
var states = JsonConvert.DeserializeObject<Dictionary<string, bool>>(json);
|
||
|
||
if (states != null)
|
||
{
|
||
var key = $"{addin.ClassName}|{Path.GetFileNameWithoutExtension(addin.AddinFilePath)}";
|
||
if (states.ContainsKey(key))
|
||
{
|
||
states.Remove(key);
|
||
var updatedJson = JsonConvert.SerializeObject(states, Formatting.Indented);
|
||
File.WriteAllText(_configPath, updatedJson);
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略错误
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解析.addin文件
|
||
/// </summary>
|
||
private List<AddinInfo> ParseAddinFile(string addinFilePath)
|
||
{
|
||
var addins = new List<AddinInfo>();
|
||
var doc = XDocument.Load(addinFilePath);
|
||
|
||
// 判断文件是否被禁用(通过文件扩展名)
|
||
bool isDisabled = addinFilePath.EndsWith(".disabled");
|
||
|
||
foreach (var addinElement in doc.Descendants("AddIn"))
|
||
{
|
||
var addin = new AddinInfo
|
||
{
|
||
AddinFilePath = addinFilePath,
|
||
CurrentRevitVersion = _revitVersion,
|
||
LastModified = File.GetLastWriteTime(addinFilePath),
|
||
IsEnabled = !isDisabled
|
||
};
|
||
|
||
// 解析类型
|
||
var typeAttr = addinElement.Attribute("Type")?.Value;
|
||
switch (typeAttr)
|
||
{
|
||
case "Command":
|
||
addin.Type = AddinType.Command;
|
||
break;
|
||
case "Application":
|
||
addin.Type = AddinType.Application;
|
||
break;
|
||
case "ExternalDBApplication":
|
||
addin.Type = AddinType.ExternalDBApplication;
|
||
break;
|
||
default:
|
||
addin.Type = AddinType.Unknown;
|
||
break;
|
||
}
|
||
|
||
addin.Name = addinElement.Element("Name")?.Value ?? "Unknown";
|
||
addin.Description = addinElement.Element("Description")?.Value ?? "";
|
||
addin.AssemblyPath = addinElement.Element("Assembly")?.Value ?? "";
|
||
addin.ClassName = addinElement.Element("FullClassName")?.Value ?? "";
|
||
addin.Developer = addinElement.Element("VendorId")?.Value ?? "Unknown";
|
||
|
||
// 解析版本兼容性
|
||
var versionElements = addinElement.Elements("SupportedVersion");
|
||
foreach (var versionElement in versionElements)
|
||
{
|
||
addin.SupportedRevitVersions.Add(versionElement.Value);
|
||
}
|
||
|
||
// 如果程序集路径是相对路径,转换为绝对路径
|
||
if (!Path.IsPathRooted(addin.AssemblyPath))
|
||
{
|
||
addin.AssemblyPath = Path.Combine(Path.GetDirectoryName(addinFilePath), addin.AssemblyPath);
|
||
}
|
||
|
||
// 尝试获取程序集版本信息
|
||
if (File.Exists(addin.AssemblyPath))
|
||
{
|
||
try
|
||
{
|
||
var assembly = Assembly.LoadFrom(addin.AssemblyPath);
|
||
addin.Version = assembly.GetName().Version?.ToString() ?? "Unknown";
|
||
}
|
||
catch
|
||
{
|
||
addin.Version = "Unknown";
|
||
}
|
||
}
|
||
|
||
addins.Add(addin);
|
||
}
|
||
|
||
return addins;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取正在运行的Revit进程
|
||
/// </summary>
|
||
public List<ProcessInfo> GetRevitProcesses()
|
||
{
|
||
var processes = new List<ProcessInfo>();
|
||
|
||
try
|
||
{
|
||
var revitProcesses = Process.GetProcessesByName("Revit");
|
||
|
||
foreach (var process in revitProcesses)
|
||
{
|
||
try
|
||
{
|
||
var processInfo = new ProcessInfo
|
||
{
|
||
Id = process.Id,
|
||
ProcessName = process.ProcessName,
|
||
WindowTitle = process.MainWindowTitle,
|
||
StartTime = process.StartTime
|
||
};
|
||
processes.Add(processInfo);
|
||
}
|
||
catch
|
||
{
|
||
// 忽略无法访问的进程
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略获取进程失败
|
||
}
|
||
|
||
return processes;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清理调试插件
|
||
/// </summary>
|
||
public void CleanupDebugAddins()
|
||
{
|
||
try
|
||
{
|
||
// 清理临时调试文件
|
||
CleanupTemporaryDebugAddins();
|
||
|
||
// 释放程序集引用
|
||
ReleaseDllReferences();
|
||
|
||
System.Diagnostics.Debug.WriteLine("调试插件清理完成");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"清理调试插件失败: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 进程信息模型
|
||
/// </summary>
|
||
public class ProcessInfo
|
||
{
|
||
public int Id { get; set; }
|
||
public string ProcessName { get; set; }
|
||
public string WindowTitle { get; set; }
|
||
public DateTime StartTime { get; set; }
|
||
}
|
||
}
|