"Could not load file or assembly" 使用 COM Interop(DLL 地狱?)
"Could not load file or assembly" using COM Interop (DLL HELL?)
我正在构建一个 COM 可见对象,它需要从一个用 Sybase Powerbuilder 11.5 编写的软件中调用。
我正在使用 C# 和 .Net Framework 4.7.2。
我通常毫无问题地构建这类对象并使用 regasm /codebase 注册它们,因为这是 Powerbuilder 喜欢它们的方式。
现在我正在尝试构建一个引用这些 nuget 包的最新版本的对象:
Microsoft.Graph
Microsoft.Graph.Auth
Microsoft.IdentityModel.Clients.ActiveDirectory
Graph.Community
我的 class 库项目有一个 com 可见 class。
我构建了一个控制台应用程序,它引用该库(它不使用 COM 服务器)来测试代码,并且在我的开发机器上从命令行一切正常。
我还可以 运行 从我的目标机器上运行控制台应用程序,没有任何问题。
当我尝试 运行 使用 COM 对象的 Powerbuilder 应用程序时,它抛出错误:
Could not load file or assembly 'Microsoft.Graph.Core, Version=1.23.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.
我在程序集的文件夹中有那个 dll,但它是 1.24.0.0 版本。
我有两个问题:
- 为什么控制台应用程序工作而 COM 对象不工作,因为它们使用相同的程序集?
- 如何解决对象的 COM 版本中的版本控制问题?
我找到了问题的解决方案,但没有完全理解。
这是一个交叉引用问题,其中包 A 和 B 都依赖于包 C,但需要不同的版本。
我不明白为什么这个错误只在使用 COM 接口而不是控制台应用程序时出现。
这是我解决的问题:
// Define the AssemblyResolve event in the constructor of the COM Object.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
// Get the path where COM Object's dll is
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
_dllPath = System.IO.Path.GetDirectoryName(path);
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Get the name of the assembly that failed loading
var name = new AssemblyName(args.Name);
// Manage the assembly that I know will cause problems
string bindingAssembly = "Microsoft.Graph.Core";
if (name.Name == bindingAssembly)
{
// Load the assembly from the COM Object's folder, and use whatever version there is
return Assembly.LoadFrom(System.IO.Path.Combine(_dllPath, bindingAssembly + ".dll"));
}
// I should not get here. If I do I need to add another manual assembly load for the dll that failed loading
return null;
}
我正在构建一个 COM 可见对象,它需要从一个用 Sybase Powerbuilder 11.5 编写的软件中调用。 我正在使用 C# 和 .Net Framework 4.7.2。 我通常毫无问题地构建这类对象并使用 regasm /codebase 注册它们,因为这是 Powerbuilder 喜欢它们的方式。
现在我正在尝试构建一个引用这些 nuget 包的最新版本的对象:
Microsoft.Graph
Microsoft.Graph.Auth
Microsoft.IdentityModel.Clients.ActiveDirectory
Graph.Community
我的 class 库项目有一个 com 可见 class。 我构建了一个控制台应用程序,它引用该库(它不使用 COM 服务器)来测试代码,并且在我的开发机器上从命令行一切正常。 我还可以 运行 从我的目标机器上运行控制台应用程序,没有任何问题。
当我尝试 运行 使用 COM 对象的 Powerbuilder 应用程序时,它抛出错误:
Could not load file or assembly 'Microsoft.Graph.Core, Version=1.23.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.
我在程序集的文件夹中有那个 dll,但它是 1.24.0.0 版本。 我有两个问题:
- 为什么控制台应用程序工作而 COM 对象不工作,因为它们使用相同的程序集?
- 如何解决对象的 COM 版本中的版本控制问题?
我找到了问题的解决方案,但没有完全理解。 这是一个交叉引用问题,其中包 A 和 B 都依赖于包 C,但需要不同的版本。 我不明白为什么这个错误只在使用 COM 接口而不是控制台应用程序时出现。
这是我解决的问题:
// Define the AssemblyResolve event in the constructor of the COM Object.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
// Get the path where COM Object's dll is
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
_dllPath = System.IO.Path.GetDirectoryName(path);
Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
// Get the name of the assembly that failed loading
var name = new AssemblyName(args.Name);
// Manage the assembly that I know will cause problems
string bindingAssembly = "Microsoft.Graph.Core";
if (name.Name == bindingAssembly)
{
// Load the assembly from the COM Object's folder, and use whatever version there is
return Assembly.LoadFrom(System.IO.Path.Combine(_dllPath, bindingAssembly + ".dll"));
}
// I should not get here. If I do I need to add another manual assembly load for the dll that failed loading
return null;
}