将托管引用(this)传递给非托管代码并调用托管回调

时间:2014-03-14 08:41:50

标签: reference unmanaged managed command-line-interface

this是问题的根源。我的回答被删除,提示开始一个新问题。所以,我们走了:

我想将this的托管引用传递给非托管代码。然后从非托管回调中调用托管回调。

public ref class CReader

使用私有字段

private:
    [...]
    void *m_pTag;
    [...]

在托管类的构造函数中,我像这样初始化m_pTag

m_pTag = new gcroot<CReader ^>(this);

稍后,我将此void *m_pTag传递给非托管代码。如果调用了非托管回调,我将void *m_pTag转发回托管引用并调用托管回调

(*(gcroot<CReader ^>*)pTag)->MANAGEDCALLBACKFUNCTION

如果DLL在另一个AppDomain下使用,则抛出异常。调试器在gcroot.h在线

停止
// don't return T& here because & to gc pointer not yet implemented
// (T should be a pointer anyway).
T operator->() const {
    // gcroot is typesafe, so use static_cast
    return static_cast<T>(__VOIDPTR_TO_GCHANDLE(_handle).Target);
}

Cannot pass a GCHandle across AppDomains.

我的问题是,我该怎么办?

诚恳,

塞巴斯蒂安

====================编辑====================

我现在能够重现这个问题。我拍了一些截图,以显示问题。

1st screenshot: constructor

snd screenshot: callback

问题是,回调中value - 结构gcroot的成员是空的。

谢谢。

塞巴斯蒂安

====================编辑====================

推。

1 个答案:

答案 0 :(得分:1)

gcroot&lt;&gt; C ++类是一个使用GCHandle类的包装器。构造函数调用GCHandle.ToIntPtr()将句柄转换为不透明指针,您可以安全地将其存储为非托管结构或C ++类的成员。

然后,使用GCHandle.FromIntPtr()方法将该原始指针转换回句柄。 GCHandle.Target属性为您提供了托管对象引用。

GCHandle.FromIntPtr()确实会失败,通用异常消息是“无法通过AppDomains传递GCHandle”。此消息仅指出此失败的常见原因,它假定GCHandle用于安全代码并且使用不正确。

消息涵盖了在不安全代码中失败的最常见原因。由于堆损坏,代码总是因不可诊断的异常而死亡。换句话说,gcroot&lt;&gt;被任意值覆盖的C ++类或结构的成员。其中当然是GCHandle.FromIntPtr(),CLR无法再从垃圾指针值找回句柄。

您可以通过诊断任何堆损坏问题的方式诊断此错误。首先要确保你得到一个好的repro,这样你就可以可靠地绊倒异常。你在gcroot成员上set a data breakpoint。当成员被不恰当地写入时,调试器会自动中断,调用栈会让你知道为什么会发生这种情况。