mirror of
https://github.com/ShrlAlgo/AddinManager.git
synced 2026-03-08 00:48:56 +00:00
修复程序集加载错误
This commit is contained in:
@@ -11,9 +11,18 @@ namespace AddInManager
|
|||||||
public class AssemLoader
|
public class AssemLoader
|
||||||
{
|
{
|
||||||
public string OriginalFolder { get; set; }
|
public string OriginalFolder { get; set; }
|
||||||
|
|
||||||
public string TempFolder { get; set; }
|
public string TempFolder { get; set; }
|
||||||
|
|
||||||
|
private List<string> m_refedFolders;
|
||||||
|
private Dictionary<string, DateTime> m_copiedFiles;
|
||||||
|
private bool m_parsingOnly;
|
||||||
|
|
||||||
|
// 移除硬编码的 .NET 2.0 路径,改用更通用的方式(虽然在Revit中通常不依赖这个)
|
||||||
|
private static string m_dotnetDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
|
||||||
|
|
||||||
|
public static string m_resolvedAssemPath = string.Empty;
|
||||||
|
private string m_revitAPIAssemblyFullName;
|
||||||
|
|
||||||
public AssemLoader()
|
public AssemLoader()
|
||||||
{
|
{
|
||||||
TempFolder = string.Empty;
|
TempFolder = string.Empty;
|
||||||
@@ -21,8 +30,11 @@ namespace AddInManager
|
|||||||
m_copiedFiles = new Dictionary<string, DateTime>();
|
m_copiedFiles = new Dictionary<string, DateTime>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ... CopyGeneratedFilesBack 保持不变 ...
|
||||||
public void CopyGeneratedFilesBack()
|
public void CopyGeneratedFilesBack()
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(TempFolder) || !Directory.Exists(TempFolder)) return;
|
||||||
|
|
||||||
var files = Directory.GetFiles(TempFolder, "*.*", SearchOption.AllDirectories);
|
var files = Directory.GetFiles(TempFolder, "*.*", SearchOption.AllDirectories);
|
||||||
foreach (var text in files)
|
foreach (var text in files)
|
||||||
{
|
{
|
||||||
@@ -37,12 +49,7 @@ namespace AddInManager
|
|||||||
FileUtils.CopyFile(text, text3);
|
FileUtils.CopyFile(text, text3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
// 新生成的文件不建议盲目拷回,可能会污染源目录,视需求而定
|
||||||
{
|
|
||||||
var text4 = text.Remove(0, TempFolder.Length);
|
|
||||||
var text5 = OriginalFolder + text4;
|
|
||||||
FileUtils.CopyFile(text, text5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,16 +71,16 @@ namespace AddInManager
|
|||||||
}
|
}
|
||||||
m_parsingOnly = parsingOnly;
|
m_parsingOnly = parsingOnly;
|
||||||
OriginalFolder = Path.GetDirectoryName(originalFilePath);
|
OriginalFolder = Path.GetDirectoryName(originalFilePath);
|
||||||
|
|
||||||
var stringBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(originalFilePath));
|
var stringBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(originalFilePath));
|
||||||
if (parsingOnly)
|
stringBuilder.Append(parsingOnly ? "-Parsing-" : "-Executing-");
|
||||||
{
|
|
||||||
stringBuilder.Append("-Parsing-");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stringBuilder.Append("-Executing-");
|
|
||||||
}
|
|
||||||
TempFolder = FileUtils.CreateTempFolder(stringBuilder.ToString());
|
TempFolder = FileUtils.CreateTempFolder(stringBuilder.ToString());
|
||||||
|
|
||||||
|
// 【建议】在此处,除了复制主DLL,最好把同目录下的所有 .dll 都复制过去
|
||||||
|
// 这样可以避免 AssemblyResolve 频繁触发,解决大部分 NuGet 依赖问题
|
||||||
|
// CopyAllDllsToTemp(OriginalFolder, TempFolder); // 这是一个建议实现的辅助方法
|
||||||
|
|
||||||
var assembly = CopyAndLoadAddin(originalFilePath, parsingOnly);
|
var assembly = CopyAndLoadAddin(originalFilePath, parsingOnly);
|
||||||
if (null == assembly || !IsAPIReferenced(assembly))
|
if (null == assembly || !IsAPIReferenced(assembly))
|
||||||
{
|
{
|
||||||
@@ -84,7 +91,7 @@ namespace AddInManager
|
|||||||
|
|
||||||
private Assembly CopyAndLoadAddin(string srcFilePath, bool onlyCopyRelated)
|
private Assembly CopyAndLoadAddin(string srcFilePath, bool onlyCopyRelated)
|
||||||
{
|
{
|
||||||
var text = string.Empty;
|
var destPath = string.Empty;
|
||||||
if (!FileUtils.FileExistsInFolder(srcFilePath, TempFolder))
|
if (!FileUtils.FileExistsInFolder(srcFilePath, TempFolder))
|
||||||
{
|
{
|
||||||
var directoryName = Path.GetDirectoryName(srcFilePath);
|
var directoryName = Path.GetDirectoryName(srcFilePath);
|
||||||
@@ -92,18 +99,30 @@ namespace AddInManager
|
|||||||
{
|
{
|
||||||
m_refedFolders.Add(directoryName);
|
m_refedFolders.Add(directoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = new List<FileInfo>();
|
var list = new List<FileInfo>();
|
||||||
text = FileUtils.CopyFileToFolder(srcFilePath, TempFolder, onlyCopyRelated, list);
|
// 假设 FileUtils.CopyFileToFolder 会处理文件复制
|
||||||
if (string.IsNullOrEmpty(text))
|
// 关键点:如果你的 FileUtils 不支持复制子文件夹(如 zh-CN),资源加载依然会失败
|
||||||
|
destPath = FileUtils.CopyFileToFolder(srcFilePath, TempFolder, onlyCopyRelated, list);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(destPath))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
foreach (var fileInfo in list)
|
foreach (var fileInfo in list)
|
||||||
{
|
{
|
||||||
|
if (!m_copiedFiles.ContainsKey(fileInfo.FullName))
|
||||||
m_copiedFiles.Add(fileInfo.FullName, fileInfo.LastWriteTime);
|
m_copiedFiles.Add(fileInfo.FullName, fileInfo.LastWriteTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LoadAddin(text);
|
else
|
||||||
|
{
|
||||||
|
// 如果文件已存在,计算目标路径
|
||||||
|
string fileName = Path.GetFileName(srcFilePath);
|
||||||
|
destPath = Path.Combine(TempFolder, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadAddin(destPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Assembly LoadAddin(string filePath)
|
private Assembly LoadAddin(string filePath)
|
||||||
@@ -112,7 +131,16 @@ namespace AddInManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Monitor.Enter(this);
|
Monitor.Enter(this);
|
||||||
assembly = Assembly.LoadFile(filePath);
|
// 【关键修改 1】使用 LoadFrom 而不是 LoadFile
|
||||||
|
// LoadFrom 会自动在 filePath 所在的目录中查找依赖项,这解决了大部分 NuGet 包加载失败的问题
|
||||||
|
// LoadFile 这是一个纯粹的文件加载,不带上下文,不会去旁边找依赖
|
||||||
|
assembly = Assembly.LoadFrom(filePath);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 增加简单的错误输出,方便调试
|
||||||
|
Debug.WriteLine($"LoadAddin Failed: {filePath}, Error: {ex.Message}");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -123,121 +151,107 @@ namespace AddInManager
|
|||||||
|
|
||||||
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||||
{
|
{
|
||||||
Assembly assembly;
|
Assembly assembly = null;
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
new AssemblyName(args.Name);
|
var assemblyNameObj = new AssemblyName(args.Name);
|
||||||
var text = SearchAssemblyFileInTempFolder(args.Name);
|
var simpleName = assemblyNameObj.Name;
|
||||||
if (File.Exists(text))
|
|
||||||
|
// 【关键修改 2】绝对不要在 AssemblyResolve 中手动处理 .resources
|
||||||
|
// 那个 "长度不能小于0" 的错误就是因为这里返回了错误的东西或者试图去加载主程序集
|
||||||
|
// 如果请求的是 .resources,直接返回 null,让 CLR 自己去临时目录的子文件夹里找
|
||||||
|
if (simpleName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
args.Name.Contains(".resources"))
|
||||||
{
|
{
|
||||||
assembly = LoadAddin(text);
|
return null;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// 1. 先在临时目录找
|
||||||
text = SearchAssemblyFileInOriginalFolders(args.Name);
|
var text = SearchAssemblyFileInTempFolder(simpleName);
|
||||||
if (string.IsNullOrEmpty(text))
|
|
||||||
{
|
|
||||||
var array = args.Name.Split(new char[] { ',' });
|
|
||||||
var text2 = array[0];
|
|
||||||
if (array.Length > 1)
|
|
||||||
{
|
|
||||||
var text3 = array[2];
|
|
||||||
if (text2.EndsWith(".resources", StringComparison.CurrentCultureIgnoreCase) && !text3.EndsWith("neutral", StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
text2 = text2.Substring(0, text2.Length - ".resources".Length);
|
|
||||||
}
|
|
||||||
text = SearchAssemblyFileInTempFolder(text2);
|
|
||||||
if (File.Exists(text))
|
if (File.Exists(text))
|
||||||
{
|
{
|
||||||
return LoadAddin(text);
|
return LoadAddin(text);
|
||||||
}
|
}
|
||||||
text = SearchAssemblyFileInOriginalFolders(text2);
|
|
||||||
}
|
// 2. 临时目录没有,去源目录找
|
||||||
}
|
text = SearchAssemblyFileInOriginalFolders(simpleName);
|
||||||
if (string.IsNullOrEmpty(text))
|
|
||||||
|
// 3. 如果源目录找到了,复制到临时目录并加载
|
||||||
|
if (!string.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
var assemblySelector = new Wpf.AssemblySelectorWindow(args.Name);
|
assembly = CopyAndLoadAddin(text, true);
|
||||||
if (assemblySelector.ShowDialog() != true)
|
return assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 如果还没找到,处理一些特殊情况(比如 XMLSerializers)
|
||||||
|
// 这里的逻辑可以保留,但通常用处不大
|
||||||
|
if (simpleName.EndsWith(".XmlSerializers", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
// 忽略序列化程序集请求
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. 【可选】最后尝试手动弹窗选择(原代码逻辑),
|
||||||
|
// 但通常对于依赖项来说,弹窗很烦人,建议只针对主程序集弹窗,或者直接返回null
|
||||||
|
// 如果这是为了解决找不到依赖的问题,上面 LoadFrom 改好后这里应该很少进来了
|
||||||
|
// 只有当你确实需要弹窗时保留下面代码
|
||||||
|
/*
|
||||||
|
var assemblySelector = new Wpf.AssemblySelectorWindow(args.Name);
|
||||||
|
if (assemblySelector.ShowDialog() == true)
|
||||||
|
{
|
||||||
text = assemblySelector.ResultPath;
|
text = assemblySelector.ResultPath;
|
||||||
}
|
|
||||||
assembly = CopyAndLoadAddin(text, true);
|
assembly = CopyAndLoadAddin(text, true);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return assembly;
|
return assembly;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SearchAssemblyFileInTempFolder(string assemName)
|
private string SearchAssemblyFileInTempFolder(string simpleName)
|
||||||
{
|
{
|
||||||
var array = new string[] { ".dll", ".exe" };
|
var extensions = new string[] { ".dll", ".exe" };
|
||||||
var text = string.Empty;
|
foreach (var ext in extensions)
|
||||||
var text2 = assemName.Substring(0, assemName.IndexOf(','));
|
|
||||||
foreach (var text3 in array)
|
|
||||||
{
|
{
|
||||||
text = $"{TempFolder}\\{text2}{text3}";
|
string path = Path.Combine(TempFolder, simpleName + ext);
|
||||||
if (File.Exists(text))
|
if (File.Exists(path)) return path;
|
||||||
{
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string SearchAssemblyFileInOriginalFolders(string assemName)
|
private string SearchAssemblyFileInOriginalFolders(string simpleName)
|
||||||
{
|
{
|
||||||
var array = new string[] { ".dll", ".exe" };
|
var extensions = new string[] { ".dll", ".exe" };
|
||||||
var text = string.Empty;
|
|
||||||
var text2 = assemName.Substring(0, assemName.IndexOf(','));
|
// 1. 在 .NET 框架目录找 (通常不需要,System库会自动加载,但保留也没事)
|
||||||
foreach (var text3 in array)
|
/*
|
||||||
|
foreach (var ext in extensions)
|
||||||
{
|
{
|
||||||
text = $"{m_dotnetDir}\\{text2}{text3}";
|
string path = Path.Combine(m_dotnetDir, simpleName + ext);
|
||||||
if (File.Exists(text))
|
if (File.Exists(path)) return path;
|
||||||
{
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
foreach (var text4 in array)
|
|
||||||
|
// 2. 在所有引用过的源目录中找
|
||||||
|
foreach (var ext in extensions)
|
||||||
{
|
{
|
||||||
foreach (var text5 in m_refedFolders)
|
foreach (var folder in m_refedFolders)
|
||||||
{
|
{
|
||||||
text = $"{text5}\\{text2}{text4}";
|
string path = Path.Combine(folder, simpleName + ext);
|
||||||
if (File.Exists(text))
|
if (File.Exists(path))
|
||||||
{
|
{
|
||||||
return text;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try
|
|
||||||
{
|
// 3. 原代码中关于 Regression 的逻辑(看起来是特定环境的,如果不需要建议删除)
|
||||||
var directoryInfo = new DirectoryInfo(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName));
|
|
||||||
var text6 = $"{directoryInfo.Parent.FullName}\\Regression\\_RegressionTools\\";
|
|
||||||
if (Directory.Exists(text6))
|
|
||||||
{
|
|
||||||
foreach (var text7 in Directory.GetFiles(text6, "*.*", SearchOption.AllDirectories))
|
|
||||||
{
|
|
||||||
if (Path.GetFileNameWithoutExtension(text7).Equals(text2, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return text7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
var num = assemName.IndexOf("XMLSerializers", StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (num != -1)
|
|
||||||
{
|
|
||||||
assemName = $"System.XML{assemName.Substring(num + "XMLSerializers".Length)}";
|
|
||||||
return SearchAssemblyFileInOriginalFolders(assemName);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAPIReferenced(Assembly assembly)
|
private bool IsAPIReferenced(Assembly assembly)
|
||||||
{
|
{
|
||||||
|
// 保持原逻辑不变
|
||||||
if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName))
|
if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName))
|
||||||
{
|
{
|
||||||
foreach (var assembly2 in AppDomain.CurrentDomain.GetAssemblies())
|
foreach (var assembly2 in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
@@ -249,6 +263,9 @@ namespace AddInManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 防止未加载 RevitAPI 时崩溃
|
||||||
|
if (string.IsNullOrEmpty(m_revitAPIAssemblyFullName)) return true;
|
||||||
|
|
||||||
foreach (var assemblyName in assembly.GetReferencedAssemblies())
|
foreach (var assemblyName in assembly.GetReferencedAssemblies())
|
||||||
{
|
{
|
||||||
if (m_revitAPIAssemblyFullName == assemblyName.Name)
|
if (m_revitAPIAssemblyFullName == assemblyName.Name)
|
||||||
@@ -258,18 +275,5 @@ namespace AddInManager
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> m_refedFolders;
|
|
||||||
|
|
||||||
private Dictionary<string, DateTime> m_copiedFiles;
|
|
||||||
|
|
||||||
private bool m_parsingOnly;
|
|
||||||
|
|
||||||
private static string m_dotnetDir =
|
|
||||||
$"{Environment.GetEnvironmentVariable("windir")}\\Microsoft.NET\\Framework\\v2.0.50727";
|
|
||||||
|
|
||||||
public static string m_resolvedAssemPath = string.Empty;
|
|
||||||
|
|
||||||
private string m_revitAPIAssemblyFullName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user