199 lines
8.7 KiB
C#
199 lines
8.7 KiB
C#
// 文件功能:读取应用运行所依赖的托管程序集和原生库版本信息。
|
|
// 优先读取当前 AppDomain 已加载程序集,未加载时回退到应用部署目录,避免主动加载可选依赖。
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace XplorePlane.Services.Helpers
|
|
{
|
|
public sealed record DependencyVersionInfo(
|
|
string Category,
|
|
string Name,
|
|
string Version,
|
|
string Path,
|
|
bool IsLoaded);
|
|
|
|
/// <summary>
|
|
/// Reads dependency versions without forcing optional or cross-process libraries into
|
|
/// the main AppDomain. Loaded assembly metadata is preferred; deployed files are the fallback.
|
|
/// </summary>
|
|
public static class DependencyVersionProvider
|
|
{
|
|
private sealed record DependencyDescriptor(
|
|
string Category,
|
|
string DisplayName,
|
|
params string[] AssemblyNames);
|
|
|
|
private static readonly DependencyDescriptor[] Dependencies =
|
|
{
|
|
new("通信/公共库", "XP.Common", "XP.Common"),
|
|
new("通信/公共库", "BR.AN.PviServices", "BR.AN.PviServices"),
|
|
new("通信/公共库", "Prism.DryIoc", "Prism.DryIoc.Wpf", "Prism.Container.DryIoc"),
|
|
new("通信/公共库", "Prism", "Prism"),
|
|
new("通信/公共库", "DryIoc", "DryIoc"),
|
|
new("通信/公共库", "Serilog", "Serilog"),
|
|
new("通信/公共库", "System.Data.SQLite", "System.Data.SQLite"),
|
|
new("通信/公共库", "Microsoft.Data.Sqlite", "Microsoft.Data.Sqlite"),
|
|
|
|
new("图像处理库", "Emgu.CV", "Emgu.CV"),
|
|
new("图像处理库", "Emgu.CV.Bitmap", "Emgu.CV.Bitmap"),
|
|
new("图像处理库", "XP.ImageProcessing.Core", "XP.ImageProcessing.Core"),
|
|
new("图像处理库", "XP.ImageProcessing.Processors", "XP.ImageProcessing.Processors"),
|
|
new("图像处理库", "XP.ImageProcessing.RoiControl", "XP.ImageProcessing.RoiControl"),
|
|
|
|
new("相机库", "Basler.Pylon", "Basler.Pylon"),
|
|
new("相机库", "XP.Camera", "XP.Camera"),
|
|
|
|
new("UI 框架", "Fluent", "Fluent"),
|
|
new("UI 框架", "Telerik.Windows.Controls", "Telerik.Windows.Controls"),
|
|
new("UI 框架", "Telerik.Windows.Controls.GridView", "Telerik.Windows.Controls.GridView"),
|
|
new("UI 框架", "Telerik.Windows.Controls.Chart", "Telerik.Windows.Controls.Chart"),
|
|
|
|
new("硬件库", "XP.Hardware.RaySource", "XP.Hardware.RaySource"),
|
|
new("运行时", "System.Runtime", "System.Runtime")
|
|
};
|
|
|
|
/// <summary>读取预定义依赖项的版本、路径和加载状态。</summary>
|
|
/// <returns>依赖版本信息列表,包含托管依赖和 OpenCV 原生依赖。</returns>
|
|
public static IReadOnlyList<DependencyVersionInfo> GetVersions()
|
|
{
|
|
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies()
|
|
.Where(assembly => !assembly.IsDynamic)
|
|
.GroupBy(assembly => assembly.GetName().Name ?? string.Empty, StringComparer.OrdinalIgnoreCase)
|
|
.ToDictionary(group => group.Key, group => group.First(), StringComparer.OrdinalIgnoreCase);
|
|
|
|
var versions = Dependencies
|
|
.Select(descriptor => ReadDependency(descriptor, loadedAssemblies))
|
|
.ToList();
|
|
|
|
versions.Add(ReadNativeDependency("图像处理库", "OpenCV (Native/cvextern)", "cvextern.dll"));
|
|
return versions;
|
|
}
|
|
|
|
/// <summary>读取单个托管程序集依赖的版本信息。</summary>
|
|
/// <param name="descriptor">依赖项描述信息。</param>
|
|
/// <param name="loadedAssemblies">按程序集名称索引的已加载程序集。</param>
|
|
/// <returns>找到的依赖版本信息;未找到时返回未部署状态。</returns>
|
|
private static DependencyVersionInfo ReadDependency(
|
|
DependencyDescriptor descriptor,
|
|
IReadOnlyDictionary<string, Assembly> loadedAssemblies)
|
|
{
|
|
foreach (var assemblyName in descriptor.AssemblyNames)
|
|
{
|
|
if (!loadedAssemblies.TryGetValue(assemblyName, out var assembly))
|
|
continue;
|
|
|
|
var path = GetAssemblyLocation(assembly);
|
|
return new DependencyVersionInfo(
|
|
descriptor.Category,
|
|
descriptor.DisplayName,
|
|
ReadVersion(path, assembly.GetName().Version),
|
|
path,
|
|
true);
|
|
}
|
|
|
|
foreach (var assemblyName in descriptor.AssemblyNames)
|
|
{
|
|
var path = FindDeployedAssemblyPath(assemblyName);
|
|
if (!File.Exists(path))
|
|
continue;
|
|
|
|
Version assemblyVersion = null;
|
|
try { assemblyVersion = AssemblyName.GetAssemblyName(path).Version; }
|
|
catch (Exception) { }
|
|
|
|
return new DependencyVersionInfo(
|
|
descriptor.Category,
|
|
descriptor.DisplayName,
|
|
ReadVersion(path, assemblyVersion),
|
|
path,
|
|
false);
|
|
}
|
|
|
|
return new DependencyVersionInfo(
|
|
descriptor.Category,
|
|
descriptor.DisplayName,
|
|
"未部署",
|
|
string.Empty,
|
|
false);
|
|
}
|
|
|
|
private static string FindDeployedAssemblyPath(string assemblyName)
|
|
{
|
|
var fileName = assemblyName + ".dll";
|
|
var roots = new List<string> { AppContext.BaseDirectory };
|
|
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
|
for (var i = 0; i < 6 && current.Parent != null; i++)
|
|
{
|
|
current = current.Parent;
|
|
roots.Add(current.FullName);
|
|
}
|
|
|
|
foreach (var root in roots.Distinct(StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
foreach (var relativeDirectory in new[]
|
|
{
|
|
string.Empty,
|
|
"ExternalLibraries",
|
|
Path.Combine("ExternalLibraries", "Host"),
|
|
"ReleaseFiles",
|
|
Path.Combine("ReleaseFiles", "Host")
|
|
})
|
|
{
|
|
var candidate = Path.Combine(root, relativeDirectory, fileName);
|
|
if (File.Exists(candidate))
|
|
return candidate;
|
|
}
|
|
}
|
|
|
|
return Path.Combine(AppContext.BaseDirectory, fileName);
|
|
}
|
|
|
|
/// <summary>读取应用目录中的原生依赖版本信息。</summary>
|
|
/// <param name="category">依赖类别。</param>
|
|
/// <param name="displayName">显示名称。</param>
|
|
/// <param name="fileName">原生库文件名。</param>
|
|
/// <returns>原生依赖版本信息。</returns>
|
|
private static DependencyVersionInfo ReadNativeDependency(
|
|
string category, string displayName, string fileName)
|
|
{
|
|
var path = Path.Combine(AppContext.BaseDirectory, fileName);
|
|
return File.Exists(path)
|
|
? new DependencyVersionInfo(category, displayName, ReadVersion(path, null), path, false)
|
|
: new DependencyVersionInfo(category, displayName, "未部署", string.Empty, false);
|
|
}
|
|
|
|
/// <summary>获取程序集文件位置;动态程序集或不支持位置查询时返回空字符串。</summary>
|
|
/// <param name="assembly">目标程序集。</param>
|
|
/// <returns>程序集文件路径,无法获取时为空字符串。</returns>
|
|
private static string GetAssemblyLocation(Assembly assembly)
|
|
{
|
|
try { return assembly.Location ?? string.Empty; }
|
|
catch (NotSupportedException) { return string.Empty; }
|
|
}
|
|
|
|
/// <summary>读取文件版本,文件版本不可用时回退到程序集版本。</summary>
|
|
/// <param name="path">程序集或原生库路径。</param>
|
|
/// <param name="assemblyVersion">已读取的程序集版本。</param>
|
|
/// <returns>可显示的版本文本。</returns>
|
|
private static string ReadVersion(string path, Version assemblyVersion)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(path) && File.Exists(path))
|
|
{
|
|
try
|
|
{
|
|
var fileVersion = FileVersionInfo.GetVersionInfo(path).FileVersion;
|
|
if (!string.IsNullOrWhiteSpace(fileVersion))
|
|
return fileVersion;
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
return assemblyVersion?.ToString() ?? "未知";
|
|
}
|
|
}
|
|
}
|