在 .NET 中,将托管对象存储在非托管代码中以提供来自非托管代码的回调存在一个相对众所周知的问题gcroot<ManagedObject>
:非托管代码在调用托管代码时不知道要使用哪个 AppDomain,有时它会选择错误的一个,导致“无法跨 AppDomains 传递 GCHandle”错误。
该问题的标准解决方法是使用指向委托的函数指针,因为委托可用于“记住”正确的 AppDomain:请参阅http://lambert.geek.nz/2007/05/29/unmanaged-appdomain -callback/以获得完整的解释。
然而,这个解决方案有点复杂,需要对委托进行仔细的生命周期管理。
似乎对托管对象使用 COM 可调用包装器也同样有效:与其存储 a gcroot<ManagedObject>
,不如将指针存储为IUnknown *
using GetIUnknownForObject
:
m_value =
static_cast<IUnknown*> (Marshal::GetIUnknownForObject(value).ToPointer());
然后我们可以GetObjectForIUnknown
在进行回调之前进行反向翻译。缺点是失去了一点类型安全性,因为IUnknown *
失去了实际的对象类型,你以后不得不使用类似的东西向下转换
IDisposable^ value =
(IDisposable^) (Marshal::GetObjectForIUnknown(IntPtr(m_value)));
哪里m_value
是IUnknown*
,但这似乎是一个很小的代价。
我已经尝试过了,在我的用例中似乎可以正常工作,但是采用这种方法有什么问题吗?似乎它适用于任何可能使用委托解决方案的地方,所以我想知道我是否遗漏了一些关于它的东西。