To pass an array of structs from C++ to C#, you can pass a pointer to a C-style array. In C++ you may have a struct, e.g.
#pragma pack(push)
#pragma pack(1)
struct InputEvent
{
uint32_t eventId;
float floatValue;
uint32_t intValue;
};
#pragma pack(pop)
The delegate in C++ is:
typedef void(__stdcall* ProcessNewInputFn) (int numEvents, const InputEvent**);
Telling C++ what C# function to call:
extern "C" __declspec(dllexport) void SetInputProcessingDelegate(ProcessNewInputFn newInputProcessing)
{
processNewInput = newInputProcessing;
}
Using this from C++
std::vector<InputEvent> inputEvents;
const avs::InputEvent *v=inputEvents.data();
processNewInput(inputEvents.size(), &v);
In C# the struct is defined as:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct InputEvent
{
public UInt32 eventId;
public float floatValue;
public UInt32 intValue;
};
Note the packing! It must match what we had in C++. Now C# must declare the the delegate type it will implement:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void OnNewInput(int numEvents, in IntPtr newEvents);
And declare in C# the C++ function that sets the delegate:
[DllImport("dllname")]
static extern void SetInputProcessingDelegate(OnNewInput onNewInput );
This is called with
ok = SetInputProcessingDelegate(ProcessingClass.SetInput);
Where we have a class like this:
class ProcessingClass
{
public static void StaticProcessInput(int numEvents, in IntPtr inputEventsPtr )
{
int EventSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(avs.InputEvent));
avs.InputEvent[] inputEvents = new avs.InputEvent[inputState.numEvents];
IntPtr ptr= inputEventsPtr;
for (int i = 0; i < inputState.numEvents; i++)
{
inputEvents[i]=Marshal.PtrToStructure<avs.InputEvent>(ptr);
ptr += EventSize;
}
}
}
Here, we take the C++ style pointer-to-array, and iterate through the array elements, copying each in turn into the C# style array.