COM互操作是否遵守.NET AppDomain边界进行程序集加载? [英] Does COM interop respect .NET AppDomain boundaries for assembly loading?

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

问题描述

这是核心问题:我有一个.NET应用程序,它在 COM互操作中使用单独的AppDomain. 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 interop与另一个应用程序进行交互.

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 interop东西):

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.

为什么会这样?

如果您有兴趣,请参考以下背景:

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

最初这是一个1 AppDomain应用程序.它与之交互的COM东西是服务器API,长期使用后不稳定.当COM出现COMException(没有有关其原因的有用诊断信息)时,必须重新启动整个应用程序,然后COM连接才能再次工作.只需重新连接到COM应用服务器,就会再次导致立即的COM异常.为了解决这个问题,我尝试将COM互操作性内容移动到单独的AppDomain中,以便在发生神秘的COMException时,我可以卸载其中发生的AppDomain,创建一个新的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组件被加载在Process Space中,而不是在AppDomain的上下文中.因此,您将需要手动拆卸(释放和卸载)您的本机DLL(适用于COM和P/Invoke).仅仅销毁一个appdomain不会带来任何好处,但是重新设置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)边界:流程和AppDomains

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

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