I'm working on project which includes DLL written in C++ and a C# code. Lets say that that DLL has a function:
MyStruct* GetPointer(); // returns pointer to MyStruct structure
MyStruct structure looks like this:
struct MyStruct
{
OtherStruct1 *data1;
OtherStruct2 *data2;
};
And OtherStruct1 and OtherStruct2 structures look like this:
struct OtherStruct1
{
public:
double x;
char y;
};
struct OtherStruct2
{
public:
float a;
float b;
float c;
float d;
};
My question is - what's the best way to handle all of these pointers in a C# code? By "handling" i mean operations of reading from and writing to memory. Structures in C# can't simply contain pointer variables. What am I supposed to do? What's the most elegant way?
Ok, I rezlized a way to do it.
[StructLayout(LayoutKind.Sequential)]
struct MyStruct
{
OtherStruct1 *data1;
OtherStruct2 *data2;
};
[StructLayout(LayoutKind.Sequential)]
struct OtherStruct1
{
public:
double x;
char y;
};
[StructLayout(LayoutKind.Sequential)]
struct OtherStruct2
{
public:
float a;
float b;
float c;
float d;
};
And then:
unsafe
{
MyStruct *tmp = (MyStruct*) GetPointer();
tmp->data2[0].a = 1.0F;
}
[DllImport(DLL_PATH, CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern MyStruct* GetPointer();
Works like a charm. :)
You can use the Microsoft (now open source) PInvoke Interop Assistant tool to convert your C/C++ code to C# or VB. Running your example code gives:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MyStruct {
/// OtherStruct1*
public System.IntPtr data1;
/// OtherStruct2*
public System.IntPtr data2;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OtherStruct1 {
/// double
public double x;
/// char
public byte y;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct OtherStruct2 {
/// float
public float a;
/// float
public float b;
/// float
public float c;
/// float
public float d;
}
public partial class NativeMethods {
/// Return Type: MyStruct*
[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="GetPointer")]
public static extern System.IntPtr GetPointer() ;
}
Replace "Unknown" in the DllImportAttribute with your dll name, and make sure it's referenced in the project. You should now be able to access your structs in managed code.
Then to read/write from/to memory you will need to use the methods in the System.Runtime.InteropServices.Marshal namespace. The following code snippet shows how to use your GetPointer function to get your unmanaged struct into a managed one:
IntPtr myPtr = NativeMethods.GetPointer(); // Call native code to retrieve pointer to unmanaged memory where the struct lives
MyStruct myStruct = new MyStruct(); // Create a new managed struct
myStruct = Marshal.PtrToStructure<MyStruct>(myPtr);
And here is how you would pass a managed struct to an unmanaged method:
MyStruct myStruct = new MyStruct(); // Create the managed struct
myStruct.data1 = new OtherStruct1(); // Create a managed OtherStruct1
myStruct.data2 = new OtherStruct2(); // Create a managed OtherStruct2
IntPtr myStructPtr = Marshal.AllocHGlobal(Marshal.SizeOf<MyStruct>()); // Allocate unmanaged memory for the struct
Marshal.StructureToPtr<MyStruct>(myStruct, myStructPtr, false);
try
{
NativeMethodThatUsesMyStructPtr(myStructPtr);
}
finally
{
Marshal.FreeHGlobal(myStructPtr); // *** You have to free unmanaged memory manually, or you will get a memory leak! ***
}
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