#c# #c #interop #callback
#c# #c #взаимодействие #обратный вызов
Вопрос:
Из C # мне нужно настроить обратный вызов на C , где данные, полученные с помощью обратного вызова, происходят из структур с наследованием (см. переработанный код ниже в разделе C ).
Я полагаю, что структуры в C сворачиваются компилятором, потому что они не содержат никаких виртуальных функций? Итак, использование свернутого класса данных ‘CollapsedCallbackInfo’ в C # фактически работает для этого конкретного класса данных. Но, имея много разных классов данных с несколькими уровнями наследования в реальной проблеме, есть ли способ решить эту проблему? Мне нужен какой-то общий тип для использования в моем определении делегата.
C#
Настройка обратного вызова
[DllImport("NativeDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetupCallback(CallbackFunc callback);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackFunc(BaseCallbackInfo baseCallbackInfo);
Классы данных C #
[StructLayout(LayoutKind.Sequential)]
public class BaseCallbackInfo
{
public uint base_data;
};
[StructLayout(LayoutKind.Sequential)]
public class ConcreteCallbackInfo : BaseCallbackInfo
{
public uint concrete_data;
};
Свернутый класс данных
[StructLayout(LayoutKind.Sequential)]
public class CollapsedCallbackInfo
{
public uint base_data;
public uint concrete_data;
};
Тестовый класс, иллюстрирующий настройку обратного вызова
public class TestClass
{
public void RegisterCallback()
{
SetupCallback(new CallbackFunc(OnCallback));
}
public void OnCallback(BaseCallbackInfo baseCallbackInfo)
{
// In the real problem I know this cast is valid
ConcreteCallbackInfo ccbi = baseCallbackInfo as ConcreteCallbackInfo;
Debug.Log(ccbi.concrete_data)
}
}
C
Классы данных
struct BaseCallbackInfo
{
uint base_data;
};
struct ConcreteCallbackInfo : public BaseCallbackInfo
{
uint concrete_data;
};
Определение обратного вызова в стиле C и внешний интерфейс
typedef void( *CallbackFunc )( BaseCallbackInfo* in_pCallbackInfo );
extern "C"
__declspec(dllexport) void SetupCallback(CallbackFunc callback);
Ответ №1:
Просто определите несколько одинаковых DllImports, например
[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetupCallback_Base(BaseCallbackFunc callback);
[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetupCallback_Concrete1(Concrete1CallbackFunc callback);
[DllImport("NativeDLL", EntryPoint="SetupCallback", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetupCallback_Concrete2(Concrete2CallbackFunc callback);
Я бы порекомендовал вам _stdcall вместо _cdecl.
Комментарии:
1. Что нужно сделать ‘SetupCallback’? И хорошо … функция обратного вызова имеет соглашение __stdcall, а «обычная функция» имеет соглашение __cdecl. Лучше ли использовать all __stdcall?