0

我有一段 .NET 代码,由于各种原因(可靠性、部署)必须在单独的 AppDomain 中运行。我创建了一个从 MBR 派生的代理对象,它将调用委托给真实的东西,因此它不会加载到当前的 AppDomain 中。我通过通常的 CreateInstanceAndUnwrap 创建代理。

this.eDirectCommunication = (EDirectCommunicationProxy) this.appDomain.CreateInstanceAndUnwrap(x, y);

当我从 .NET 客户端使用它时,这很有效,但是当从 COM 客户端加载时,转换失败。我无法从透明代理进行投射。我验证了所需的类型是在所需的 AppDomain 上创建的,并且 Unwrap 成功,只是强制转换失败。有趣的是,当两个 AppDomain 具有相同的基目录时,它确实有效,这表明程序集绑定失败。但是 Fusion 日志查看器没有提到任何问题。

这里这里有两个有点相似的问题,但它们没有提供答案。任何想法出了什么问题,或者我该如何进一步调试它?

4

1 回答 1

1

几年前我遇到了这个确切的问题。IIRC,问题在于调用堆栈跨越了两个 appdomain 边界,这导致托管对象的代理被编组两次(COM->default->yours:new object:->yours->default)。通常不是问题,但是 .NET COM 封送处理程序 QI 有一个特殊的接口,它说“嗨,我是一个托管对象,需要特殊的封送处理行为”(对不起,不记得 IID-尝试 ComTrace 或滚动你的自己的 IDispatch impl 和 marshal 它通过 CLR 来查看)。这就是你被淹没的地方——当它在默认域中运行时,它知道你是受管理的,然后请求并尝试加载你的托管类型,只有当你的新域的 basedir 与默认值相同时才会成功。这显然违背了整个目的。

我有几种方法来处理这个问题。一种方法是使对象创建异步,以便我可以将托管代理直接推送到来自新域的非托管代码(例如,注册一个非托管回调并直接从新域调用它,绕过默认域)。在您无法端到端控制所有内容的插件场景中,这显然很棘手。

另一个是有一小段非托管代码滚动一个愚蠢的代理,当 .NET 封送器询问“你真的是一个托管对象吗?”时它没有响应。但会不受干扰地通过所有其他 QI 和 IDispatch 上的所有内容(我也将我的 hack 限制为 IDispatch,这使它更容易)。所以新的顺序是:COM->default->yours:new object->new proxy wrapper->default->COM。

PITA 少校——当时我从 CLR 互操作团队的一个人那里找到了一篇博客文章,该文章在未来的 CLR 版本中对此进行了一些可能的修复,但那是几年前的事了,我不记得是谁了(抱歉,我不再以互操作为生了,谢天谢地!)

于 2009-09-28T12:00:39.057 回答