У меня есть библиотека, которая предоставляет функции обратного вызова и должна вызываться как из управляемого, так и из собственного кода.Я реализовал это, выполнив:
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, но где-то в нативном переходе -> управляемом (в который отладчик не пускает меня), rdx заполняется мусором.
Есть ли какой-нибудь атрибут, который я могу использовать в моем делегате, чтобы исправить это на x64?Или мне нужно сделать что-то менее приятное, например обернуть весь управляемый класс в нативный класс для выполнения обратных вызовов?Или я только что нашел ошибку управляемого кодагена?