From C# how do I use a native C++ callback with an inherited struct?
From C# I need to setup a callback to C++ where the data received with the callback originates from structs with inheritance (See the distilled code below in the C++ section).
I believe the structs in C++ are collapsed by the compiler because they do not contain any virtual functions? So using the collapsed data class 'CollapsedCallbackInfo' in C# actually works for that specific data class. But having a lot of different data classes with multiple layers of inheritence in the real problem, is there a way solve this challenge? I need some common type to use in my delegate definition.
C#
Callback setup
[DllImport("NativeDLL", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetupCallback(CallbackFunc callback);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackFunc(BaseCallbackInfo baseCallbackInfo);
C# Data classes
[StructLayout(LayoutKind.Sequential)]
public class BaseCallbackInfo
{
public uint base_data;
};
[StructLayout(LayoutKind.Sequential)]
public class ConcreteCallbackInfo : BaseCallbackInfo
{
public uint concrete_data;
};
Collapsed data class
[StructLayout(LayoutKind.Sequential)]
public class CollapsedCallbackInfo
{
public uint base_data;
public uint concrete_data;
};
Test Class that illustrates the callback setup
public class TestClass
{
public void RegisterCallback()
{
SetupCallback(new CallbackFunc(OnCallback));
}
public void OnCallback(BaseCallbackInfo baseCallbackInfo)
{
// In the re开发者_JAVA技巧al problem I know this cast is valid
ConcreteCallbackInfo ccbi = baseCallbackInfo as ConcreteCallbackInfo;
Debug.Log(ccbi.concrete_data)
}
}
C++
Data classes
struct BaseCallbackInfo
{
uint base_data;
};
struct ConcreteCallbackInfo : public BaseCallbackInfo
{
uint concrete_data;
};
C-style Callback definition and external interface
typedef void( *CallbackFunc )( BaseCallbackInfo* in_pCallbackInfo );
extern "C"
__declspec(dllexport) void SetupCallback(CallbackFunc callback);
Just define several DllImports of the same, e.g.
[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);
I would recommend you _stdcall instead of _cdecl.
精彩评论