我有一个公开回调函数的库,需要从托管代码和本机代码中调用。我通过这样做实现了这个:
typedef struct { DWORD blah; } MY_STRUCT;
class ICallbackInterface
{
public:
virtual HRESULT CallbackFunc1(const MY_STRUCT* pStruct) { return S_OK; }
// helper for overriding the vtable (used later on by the managed code)
class VTable
{
public:
void* pfnCallbackFunc1;
};
};
本机代码接收指向ICallbackInterface的指针,并调用CallbackFunc1。
在C ++ / CLI代码中,我正在分配ICallbackInterface,并覆盖其vtable以指向我想要调用的托管函数的委托。 (以下代码段来自构造函数):
public ref class MyManagedClass
{
...
m_pCallbackClass = new ICallbackInterface;
if (!m_pCallbackClass)
return E_OUTOFMEMORY;
m_pNewCallbackVtable = new ICallbackInterface::VTable;
if (!m_pNewCallbackVtable)
{
delete m_pCallbackClass;
m_pCallbackClass = nullptr;
return E_OUTOFMEMORY;
}
// Get the (hidden) pointer to the vtable
ICallbackInterface::VTable** ppAddressOfInternalVtablePointer =
(ICallbackInterface::VTable**)m_pCallbackClass;
ICallbackInterface::VTable* pOldVtable = *ppAddressOfInternalVtablePointer;
// Copy all the functions from the old vtable that we don't want to override
*m_pNewCallbackVtable = *pOldVtable;
// Manually override the vtable entries with our delegate functions
m_pNewCallbackVtable->pfnCallbackFunc1 = Marshal::GetFunctionPointerForDelegate(gcnew delCallbackFunc1(this, &MyManagedClass::CallbackFunc1)).ToPointer();
...
这是回调函数&其代表
[UnmanagedFunctionPointer(CallingConvention::StdCall)]
delegate HRESULT delCallbackFunc1(const MY_STRUCT* pMyStruct);
HRESULT CallbackFunc1(const MY_STRUCT* pMyStruct)
{
// do something with pMyStruct.
}
}
当我为x86编译本机库时,一切正常。 (我不知道为什么在那里使用CallingConvention :: StdCall,但替代方案似乎会导致esp出现问题。)
当我为x64编译它时,回调函数被调用,并且当我返回时rsp很好,但是pMyStruct被删除了。看起来本机代码喜欢将内容传递给rdx,但在native-> managed转换中的某个地方(调试器不会让我介入),rdx充满了垃圾。
我可以在我的代理上使用某些属性来修复x64吗?或者我是否需要做一些不太愉快的事情,比如在本机类中包装我的整个托管类来进行回调?或者我刚刚找到托管的codegen错误?
答案 0 :(得分:0)
您正在左右调用未定义的bwhavior,并依赖于实现细节,例如vtable布局和虚拟成员函数调用约定。毫无疑问,当你改变平台时,事情就会破裂。
如果是原生接口,你需要编写派生的vl lass。实现可以直接调用函数指针或托管代理。并停止搞乱vtsble指针。
答案 1 :(得分:0)
发现问题。 托管代码具有“this”指针,在初始化委托时出现。 但是本机函数有自己的“this”指针,它也被传递。将托管签名更改为以下内容完全修复了该错误,现在该函数可以访问这两个“this”指针。
[UnmanagedFunctionPointer(CallingConvention::ThisCall)]
delegate HRESULT delCallbackFunc1(ICallbackInterface* NativeThis, const MY_STRUCT* pMyStruct);
HRESULT CallbackFunc1(ICallbackInterface* NativeThis, const MY_STRUCT* pMyStruct)
{
// do something with pMyStruct.
}
这适用于x86和x64。