从x64回调调用托管代理? (rdx中的参数被删除)

时间:2011-11-17 03:17:52

标签: delegates c++-cli 64-bit

我有一个公开回调函数的库,需要从托管代码和本机代码中调用。我通过这样做实现了这个:

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错误?

2 个答案:

答案 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。