COM 互操作是否尊重 .NET AppDomain 边界以加载程序集? [英] Does COM interop respect .NET AppDomain boundaries for assembly loading?

查看:18
本文介绍了COM 互操作是否尊重 .NET AppDomain 边界以加载程序集?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是核心问题:我有一个 .NET 应用程序,它使用 COM interop单独的应用程序域.COM 内容似乎正在将程序集加载回默认域,而不是从中调用 COM 内容的 AppDomain.

Here's the core problem: I have a .NET application that is using COM interop in a separate AppDomain. The COM stuff seems to be loading assemblies back into the default domain, rather than the AppDomain from which the COM stuff is being called.

我想知道的是:这是预期的行为,还是我做错了什么导致这些与 COM 相关的程序集加载到错误的 AppDomain 中?请参阅下面更详细的情况描述...

What I want to know is: is this expected behaviour, or am I doing something wrong to cause these COM related assemblies to be loaded in the wrong AppDomain? Please see a more detailed description of the situation below...

该应用程序由 3 个程序集组成:- 主 EXE,应用程序的入口点.- common.dll,只包含一个接口 IController(IPlugin 风格)- controller.dll,包含实现 IController 和 MarshalByRefObject 的 Controller 类.此类完成所有工作并使用 COM 互操作与另一个应用程序进行交互.

The application consists of 3 assemblies: - the main EXE, the entry point of the application. - common.dll, containing just an interface IController (in the IPlugin style) - controller.dll, containing a Controller class that implements IController and MarshalByRefObject. This class does all the work and uses COM interop to interact with another application.

主EXE的相关部分如下所示:

The relevant part of the main EXE looks like this:

AppDomain controller_domain = AppDomain.CreateDomain("Controller Domain");
IController c = (IController)controller_domain.CreateInstanceFromAndUnwrap("controller.dll", "MyNamespace.Controller");
result = c.Run();
AppDomain.Unload(controller_domain);

common.dll 只包含以下两件事:

The common.dll only contains these 2 things:

public enum ControllerRunResult{FatalError, Finished, NonFatalError, NotRun}
public interface IController
{
    ControllerRunResult Run();
}

并且 controller.dll 包含这个类(它也调用 COM 互操作的东西):

And the controller.dll contains this class (which also calls the COM interop stuff):

public class Controller: IController, MarshalByRefObject

当第一次运行应用程序时,Assembly.GetAssemblies() 看起来像预期的一样,common.dll 被加载到两个 AppDomains 中,并且 controller.dll 只被加载到控制器域中.但是,在调用 c.Run() 之后,我看到与 COM 互操作相关的程序集已加载到默认的 AppDomain 中,而不是在发生 COM 互操作的 AppDomain 中.

When first running the application, Assembly.GetAssemblies() looks as expected, with common.dll being loaded in both AppDomains, and controller.dll only being loaded into the controller domain. After calling c.Run() however I see that assemblies related to the COM interop stuff have been loaded into the default AppDomain, and NOT in the AppDomain from which the COM interop is taking place.

为什么会发生这种情况?

Why might this be occurring?

如果你有兴趣,这里有一些背景:

And if you're interested, here's a bit of background:

最初这是一个 1 AppDomain 应用程序.它与 COM 接口的东西是一个服务器 API,它在长期使用中不稳定.当 COM 内容发生 COMException(没有关于其原因的有用诊断信息)时,整个应用程序必须重新启动,然后 COM 连接才能再次工作.简单地重新连接到 COM 应用程序服务器会再次立即导致 COM 异常.为了解决这个问题,我试图将 COM 互操作的东西移到一个单独的 AppDomain 中,这样当神秘的 COMExceptions 发生时,我可以卸载它发生的 AppDomain,创建一个新的并重新开始,所有这些都无需手动重新启动应用程序.无论如何,这就是理论......

Originally this was a 1 AppDomain application. The COM stuff it interfaces with is a server API which is not stable over long periods of use. When a COMException (with no useful diagnostic information as to its cause) occurs from the COM stuff, the entire application has to restarted before the COM connection will work again. Simply reconnecting to the COM app server results in immediate COM exceptions again. To cope with this I have tried to move the COM interop stuff into a seperate AppDomain so that when the mystery COMExceptions occur I can unload the AppDomain in which it occurs, create a new one and start again, all without having to manually restart the application. That was the theory anyway...

推荐答案

不幸的是,COM 组件是在进程空间中而不是在 AppDomain 的上下文中加载的.因此,您需要手动拆卸(释放和卸载)您的本机 DLL(适用于 COM 和 P/Invoke).简单地销毁应用程序域对您没有任何好处,但是重新生成整个过程不需要重置 COM 状态(简单地重新创建 COM 对象也应该正常工作,这听起来像是组件提供程序代码中的错误,也许他们可以解决吗?)

Unfortunately, A COM component is loaded within Process Space and not within the context of an AppDomain. Thus, you will need to manually tear-down (Release and Unload) your Native DLLs (applies to both COM and P/Invoke). Simply destroying an appdomain will do you no good, but respawning the whole process shouldn't be necessary to reset COM state (simply recreating the COM object(s) should also normally work, this sounds like a bug within the component providers code, perhaps they can address it?)

参考资料

(TechNet) 进程地址空间

(MSDN) 应用程序域

(MSDN) 边界:进程和应用程序域

这篇关于COM 互操作是否尊重 .NET AppDomain 边界以加载程序集?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆