9

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

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

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

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

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 仅包含以下两件事:

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

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

public class Controller: IController, MarshalByRefObject

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

为什么会发生这种情况?

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

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

4

3 回答 3

17

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

参考

(TechNet) 进程地址空间

(MSDN) 应用程序域

(MSDN) 边界:进程和 AppDomains

于 2009-11-06T04:43:45.260 回答
3

这是肖恩威尔逊的答案是正确的证据

Com 应用域

于 2013-01-11T17:26:37.437 回答
0

不要让你的控制器 MBR。创建一个小型代理,它将控制器加载到第二个域中并启动它。这样控制器 dll 将不会在第一个域中加载。

于 2008-10-28T15:52:43.070 回答