通过 COM/Interop 与通过 .NET 应用程序调用 .NET 程序集时,引用的程序集是否使用不同的加载上下文?

发布于 2024-11-02 16:14:57 字数 2132 浏览 5 评论 0原文

我使用 COM Interop 从 VB6 应用程序调用托管代码,该应用程序本身在创建新的 AppDomain 后随后从另一个托管程序集调用代码。这个新的 AppDomain 实际上实例化了正在使用的对象的实例。

为了让这个更容易理解,这些是播放器:

  • VB6 应用程序: LegacyApp.exe
  • 包含所有 .NET 程序集中使用的接口信息的程序集: MeatyInterfaces.dll
  • COM 互操作可见的 .NET 程序集: InteropAssembly.dll
    • 此程序集直接引用 MeatyInterfaces.dll
  • InteropAssembly.dll 使用的程序集: MeatyImplementations.dll
    • 此程序集直接引用 MeatyInterfaces.dll,并实现这些接口
    • 通过实现“MeatyImplementations.ExampleImplementation”实现接口“MeatyInterfaces.IExampleInterface”

为了简化该过程,本质上我们创建一个 AppDomain 并实例化 ExampleImplementation新的 AppDomain 在由 LegacyApp.exe 调用的 InteropAssembly.dll 代码中:

AppDomainSetup domainSetup = GetExampleSetupInfo();
AppDomain domain = AppDomain.CreateDomain(domainSetup.ApplicationName, AppDomain.CurrentDomain.Evidence, domainSetup);
ObjectHandle handle = domain.CreateInstance("MeatyImplementations.dll", "MeatyImplementations.ExampleImplementation");

一旦我们有了这个句柄,我们尝试解开它并将其转换为 IExampleInterface,ExampleImplementation 实现了它。

MeatyInterfaces.IExampleInterface initializer = (MeatyInterfaces.IExampleInterface) handle.Unwrap();

这会引发以下异常:

Exception: "System.InvalidCastException"
Message: "Unable to cast transparent proxy to type 'MeatyInterfaces.IExampleInterface'"

奇怪的是,如果我们运行这段确切的代码,但从托管(.NET)应用程序开始,它工作得很好。

以下是我所知道的:

  • 我知道可以在两个上下文中加载程序集:Load 和 LoadFrom,并且后者对 DLL 的位置敏感。
  • 我知道将对象从一个加载上下文转换到另一个加载上下文似乎是此问题的最常见原因(事实上,这是我能够找到相当详尽的搜索的唯一原因)
  • 我知道,如果我重写 AssemblyResolve 事件正如这里推荐的(http://west-wind.com/weblog/posts/601200.aspx),它解决了问题,这进一步向我表明(尽管我没有实质性证据)InteropAssembly。当以上述方式使用时,dll 必须在与 MeatyImplementations.dll 不同的加载上下文中加载 MeatyInterfaces.dll。

所以这就是我不明白的地方...如果有人可以提供说明,我将不胜感激:

我不明白的是为什么加载上下文会有所不同,具体取决于我是否通过 VB6 使用 InteropAssembly.dll应用程序(使用 COM Interop)与 .NET 应用程序,或者加载上下文的整个概念是否一直只是一个转移注意力的问题,而他的修复只是巧合地解决了我的问题。

I am calling managed code from a VB6 Application using COM Interop, which itself subsequently calls code from another managed assembly after creating a new AppDomain. This new AppDomain is what actually instantiates instances of the objects being used.

To try and make this simpler to understand, these are the players:

  • VB6 Application: LegacyApp.exe
  • Assembly containing Interface information used in all .NET Assemblies: MeatyInterfaces.dll
  • COM Interop-visible .NET Assembly: InteropAssembly.dll
    • This Assembly has a direct reference to MeatyInterfaces.dll
  • Assembly used by InteropAssembly.dll: MeatyImplementations.dll
    • This Assembly has a direct reference to MeatyInterfaces.dll, and implements those interfaces
    • implements the interface "MeatyInterfaces.IExampleInterface" with implementation "MeatyImplementations.ExampleImplementation"

To boil down the process, essentially we create an AppDomain and instantiate the ExampleImplementation from the new AppDomain as such in the InteropAssembly.dll code called by LegacyApp.exe:

AppDomainSetup domainSetup = GetExampleSetupInfo();
AppDomain domain = AppDomain.CreateDomain(domainSetup.ApplicationName, AppDomain.CurrentDomain.Evidence, domainSetup);
ObjectHandle handle = domain.CreateInstance("MeatyImplementations.dll", "MeatyImplementations.ExampleImplementation");

Once we have this handle, we attempt to unwrap it and cast it to IExampleInterface, which ExampleImplementation implements.

MeatyInterfaces.IExampleInterface initializer = (MeatyInterfaces.IExampleInterface) handle.Unwrap();

This throws the following exception:

Exception: "System.InvalidCastException"
Message: "Unable to cast transparent proxy to type 'MeatyInterfaces.IExampleInterface'"

The strange thing is, if we run through this exact code but starting with a Managed (.NET) Application, it works perfectly fine.

Here's what I know:

  • I know that there are two contexts in which Assemblies can be loaded: Load and LoadFrom, and that the latter is sensitive to the location of DLLs.
  • I know that casting an object from one Load Context into another appears to be the most frequent cause of this problem (in fact, the only one I've been able to find fairly exhaustive searching)
  • I know that, if I override the AssemblyResolve event as recommended here (http://west-wind.com/weblog/posts/601200.aspx), it fixes the problem, which further suggests to me (though I have no material evidence) that InteropAssembly.dll must be loading MeatyInterfaces.dll in a different load context than MeatyImplementations.dll does when used in the manner shown above.

So here's what I don't understand... if anyone can provide clarification, I would be most grateful:

What I don't understand is why the load context would be different depending on if I'm using InteropAssembly.dll through a VB6 App (using COM Interop) vs. a .NET App, or whether the whole concept of Load Contexts has just been a red herring all along and his fix only resolved my problem by coincidence.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

榆西 2024-11-09 16:14:57

我找到了答案:

我错误地查看了 Fusion Log:

InteropAssembly.dll 正在 LoadFrom 上下文中加载,但这不是问题所在。问题是,当 InteropAssembly.dll 尝试加载 MeatyInterfaces.dll 时,它找不到它:MeatyInterfaces.dll 位于 InteropAssembly.dll 所在的 bin 文件夹中,但它并没有在那里寻找它:它正在寻找在 LegacyApp.exe 的应用程序路径中。

.NET 应用程序的工作基本上是巧合:这些程序集作为构建过程的一部分添加到 .NET 应用程序的 bin 文件夹中,因此它在它正在检查的文件夹中拥有所需的所有依赖项。

我看到的导致我进入加载上下文路径的异常基本上是一个巧合:加载依赖项失败直到第一次使用它才触发异常,这恰好是发生转换的地方:这引发了在大多数情况下,该异常似乎是由不匹配的加载上下文引起的。

F7U12

是的,这就是原因:我现在已经学到了困难的方法,尽管可以通过 COM Interop 从调用应用程序的路径(或 GAC)以外的位置加载程序集,但程序集的依赖项仍然需要在应用程序的路径中。噢。

I found the answer:

I was looking at the Fusion Log incorrectly:

InteropAssembly.dll was loading in a LoadFrom context, but that wasn't the issue. The issue was that when InteropAssembly.dll tried to load MeatyInterfaces.dll, it couldn't find it: MeatyInterfaces.dll was in the bin folder where InteropAssembly.dll was located, but it wasn't looking there for it: it was looking in LegacyApp.exe's Application Path.

The .NET App was working basically by coincidence: these Assemblies were added to the .NET App's bin folder as part of the build process, so it had all of the dependencies it needed in the folder that it was checking.

The exception I was seeing that led me down the Load context path was basically a coincidence: the failure to load the dependency didn't trigger an exception until the first time it was used, which happened to be where that cast occurred: which threw an exception that appears to be caused by mismatched load contexts in a vast majority of circumstances.

F7U12

Yeah, so that was the cause: I've learned the hard way now that though an Assembly can be loaded via COM Interop from a location other than the calling application's path (or the GAC), the Assembly's dependencies will still need to be in the Application's path. D'oh.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文