Handling pointers to structure in C#

10,772

Solution 1

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! ***
}

Solution 2

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. :)

Share:
10,772
Gont.M
Author by

Gont.M

Updated on June 16, 2022

Comments

  • Gont.M
    Gont.M almost 2 years

    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?

  • Gont.M
    Gont.M over 7 years
    Thanks, that's the more elegant way, without using 'unsafe' block :)
  • BitBot
    BitBot over 7 years
    I edited to show how to free the unmanaged memory after you are finished with it. This is a must, or you will get a memory leak!
  • Gont.M
    Gont.M over 7 years
    Shared memory is free'd with usage of DLL's Clear() function :) But thanks anyway, that's pretty useful knowledge for the future :)