I know this subject was discussed many times here, but I couldn't find the answer for my specific situation.
I need to call in C# an unmanaged C method which takes a pointer on a struct object (I don't speak C fluently :
int doStuff(MYGRID* grid, int x);
But the struct itself references an other struct object :
struct MYGRID {
int hgap;
int vgap;
MYIMAGE* image;
}
struct MYIMAGE {
int res;
int width;
int height;
}
And I also need to set directly the image pointer like this :
MYGRID* pGrid = new MYGRID;
MYIMAGE* pImage = new MYIMAGE;
pGrid->image = pImage;
So, my question is : in C# code, should I use a "struct" object and passing it by "ref" like the P/Invoke Interop Assistant suggests me ? Which means the following code :
MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();
myGrid.image = Marshal.AllocHGlobal(Marshal.SizeOf(image)); // A IntPtr in my struct
myGrid.image = Marshal.StructureToPtr(image, myGrid.image, false);
doStuff(ref myGrid, 0);
Or could I use "class" instead of "struct" in order to have the very simple following code :
MyGrid myGrid = new MyGrid();
MyImage myImage = new MyImage();
myGrid.image = myImage;
doStuff(myGrid, 0);
In the first case I use an "IntPtr" in my struct MyGrid, and just a MyImage object in the second case.
Don't confuse C# struct with C++ struct. They are not the same thing. A C# struct is used to declare a value type. When you aggregate a value type in another type you store it directly in the containing instance instead of storing a reference to an instance stored on the heap. A C++ struct is simply a class where all members by default are public.
In your case, because MYGRID
contains a pointer to MYIMAGE
, you should use class
as you are doing in you second example. However, the ref
on the myGrid
parameter should be removed.
Below is some sample code I have tested. The C++ code:
#include "windows.h"
struct MYIMAGE {
int res;
int width;
int height;
};
struct MYGRID {
int hgap;
int vgap;
MYIMAGE* image;
};
extern "C" __declspec(dllexport) int doStuff(MYGRID* grid, int x) {
return 0;
}
Declaring the C# classes and the external function:
[StructLayout(LayoutKind.Sequential)]
class MyGrid {
public int hgap;
public int vgap;
public IntPtr image;
}
[StructLayout(LayoutKind.Sequential)]
class MyImage {
public int res;
public int width;
public int height;
}
[DllImport("MyDll")]
static extern int doStuff(MyGrid grid, int x);
Calling the external function:
MyImage image = new MyImage();
MyGrid grid = new MyGrid();
grid.image = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MyImage)));
Marshal.StructureToPtr(image, grid.image, false);
doStuff(grid, 0);
If you turn on unmanaged debugging in your C# project you can use the debugger to step into the C++ function and verify that the classes have been correctly marshaled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With