views:

111

answers:

1

I've a piece of .NET code that for various reasons (reliability, deployment) must run in a separate AppDomain. I've created a proxy object deriving from MBR that delegates the calls to the real stuff so it wont load in the current AppDomain. I create the proxy via the usual CreateInstanceAndUnwrap.

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

This works great when I use it from a .NET client, however when loaded from a COM client the cast fails. I get a failure to cast from a transparent proxy. I validated that the required type is created on the desired AppDomain and the Unwrap succeeds, just the cast fails. Interestingly, it does work when both AppDomain have the same base directory, which points to assembly binding failures. But the Fusion log viewer doesn't mention any issues.

There are two somewhat similar questions here and here, but they provide no answer. Any ideas what is going wrong, or how can I debug it further?

A: 

I ran into this exact problem a few years ago. IIRC, the problem was that the call stack crosses two appdomain boundaries, which causes the proxy to the managed obejct to be marshaled twice (COM->default->yours:new object:->yours->default). Normally not a problem, but there's a special interface that the .NET COM marshaler QIs for that says "hi, I'm a managed object and need special marshaling behavior" (sorry, don't remember the IID- try ComTrace or roll your own IDispatch impl and marshal it through the CLR to see). This is where you're getting hosed- when this runs in the default domain, it knows you're managed then asks for and tries to load your managed type, which will only succeed when your new domain's basedir is the same as the default. This obviously defeats the whole purpose.

There are a couple of ways I've dealt with this. One way is to make the object creation async so I could push the managed proxy out directly to unmanaged code from the new domain (eg, register an unmanaged callback and call it directly from the new domain, bypassing the default domain). This is obviously tricky in an addin scenario where you don't control everything end-to-end.

The other was to have a little slice of unmanaged code that rolled a dumb proxy that DIDN'T respond when the .NET marshaler asked "are you really a managed object?" but would pass through all other QIs and everything on IDispatch unmolested (I limited my hack to IDispatch only, too, which made it much easier). So the new sequence goes: COM->default->yours:new object->new proxy wrapper->default->COM.

Major PITA- I found a blog post back then from a guy on the CLR interop team that was floating some possible fixes for this in a future CLR release, but it was several years ago and I don't remember who it was (sorry, I don't do interop for a living anymore, thank goodness!)

nitzmahone