I've this C-C# code that works:
.h
typedef struct {
float a;
float b;
} MyStruct;
extern MyStruct mystruct;
__declspec(dllexport) void GetMyStruct (MyStruct* s);
__declspec(dllexport) void SetMyStruct (MyStruct* s);
.c
MyStruct mystruct;
void GetMyStruct (MyStruct* s)
{
*s = AeroLink_IOPkt;
}
void SetMyStruct (MyStruct* s)
{
AeroLink_IOPkt = *s;
}
void test()
{
// some code that update element in struct
// mystruct.a = 0.4;
// mystruct.a = 0.1;
}
.cs
public struct MyStruct
{
public float a;
public float b;
}
[DllImport(DLL_NAME, EntryPoint = "GetMyStruct")]
protected static extern void GetMyStruct(ref MyStruct s);
[DllImport(DLL_NAME, EntryPoint = "SetMyStruct")]
protected static extern void SetMyStruct(ref MyStruct s);
This way, every time I need to set data from C# to C, I must call void SetMyStruct
and vice-versa if I want to get data from C (updated from void test) to C# I must call GetMyStruct
. I must do this 50 times per seconds.
Is there a way to avoid calling SetMyStruct
and GetMyStruct
every time? I would like to use SetMyStruct
one time and then have all changes be reflected, from and to. I do not know if this is possible.
You can do this with unsafe
and pointers.
You need to compile your C# program with "Unsafe" enabled.
EDIT: A better way:
Add a following function to the library:
__declspec(dllexport) void GetMyStructRef (MyStruct** s);
void GetMyStructRef(MyStruct** s)
{
*s = &mystruct;
}
In C#:
[DllImport(DLL_NAME, EntryPoint = "GetMyStructRef")]
protected static extern void GetMyStructRef(ref MyStruct* s);
MyStruct* data;
GetMyStructRef(ref data);
Console.WriteLine($"{data->a} {data->b}");
Old answer:
unsafe class MyClass : IDisposable
{
[DllImport(DLL_NAME, EntryPoint = "GetMyStruct")]
protected static extern void GetMyStruct(MyStruct* s);
[DllImport(DLL_NAME, EntryPoint = "SetMyStruct")]
protected static extern void SetMyStruct(MyStruct* s);
GCHandle handle;
MyStruct* structRef;
public void MyClass()
{
//we need to get a pinned reference to your struct
handle = GCHandle.Alloc(new MyStruct(), GCHandleType.Pinned);
structRef = (MyStruct*)handle.AddrOfPinnedObject().ToPointer();
SetMyStruct(structRef);
}
public void Dispose()
{
//We need to free the handle to release memory
//GC will not collect it without this
handle.Free();
}
}