Is it safe to use COM Callable Wrapper to avoid problems passing GCHandles across app domains?
There is a relatively well-known issue in .NET with storing managed objects in unmanaged code as a way gcroot<ManagedObject>
to provide callbacks from unmanaged code: unmanaged code doesn't know what AppDomain should use when called into managed code, and sometimes it picks the wrong one, which leads to errors. " Unable to pass GCHandle through AppDomains ".
The standard solution to the problem is to use a function pointer to the delegate, since the delegate can be used to "remember" the correct AppDomain: see http://lambert.geek.nz/2007/05/29/unmanaged-appdomain-callback/ for a full explanation.
However, this decision is a little more complicated and requires careful management of the tar's lifetime.
It seems that using the COM-Callable Wrapper for the managed object works just as well: instead of saving gcroot<ManagedObject>
, store the pointer as IUnknown *
with GetIUnknownForObject
:
m_value =
static_cast<IUnknown*> (Marshal::GetIUnknownForObject(value).ToPointer());
We can then do the reverse translation with GetObjectForIUnknown
before executing the callback. The disadvantage loses a bit of type safety because it IUnknown *
loses the actual type of the object and you have to dump later using something like
IDisposable^ value = (IDisposable^) (Marshal::GetObjectForIUnknown(IntPtr(m_value)));
where m_value
- IUnknown*
, but it seems like a small price to pay.
I tried this and it seems to work fine in my use case, but are there any problems with this approach? This seems to apply wherever a delegate solution could be used, so I wonder if I'm missing something on this.
source to share