简体   繁体   中英

Converting c++ struct to c# and using it?

I have a c++ struct as follow:

struct Vehicle
{
 u32 something;
 Info *info;
 u8 something2[ 0x14 ];
 Vector3f location;
 Template* data;
};

struct Info
{
 u32 speed;
 std::string name;
 BuffCollection** buffCollection;
 void* sectionPtr;
};

struct Template
{
 u32 templateID;
};

From this question , I figured out the meaning of the u32, u8, and so on, or so I think I did.

Then I tried to make my own C# struct out of it:

[StructLayout(LayoutKind.Sequential)]
public struct Vehicle
{
    public uint Something;
    public Info Info;
    public byte Something2;
    public Vector3f Location;
    public Template Data;
}

[StructLayout(LayoutKind.Sequential)]
public struct Info
{
    public uint Speed;
    public string Name;
    public byte[] BuffCollection;
    public IntPtr SectionPointer;
}

[StructLayout(LayoutKind.Sequential)]
public struct Template
{
    public uint TemplateId;
}

public struct Vector3f
{
    public float X, Y, Z;
    public Vector3f(float x, float y, float z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

However, when I try to read the Vehicle:

[DllImport("Core.dll")]
static extern Vehicle GetVehicle();

static void Main() 
{
    var vehicle = GetVehicle();
    Console.WriteLine(vehicle.Info.Name);
    Console.ReadKey();
}

I get the following error:

System.Runtime.InteropServices.MarshalDirectiveException: Method's type signature is not PInvoke compatible

From the search I did on it, it lead me to believe that my structure conversion is wrong.

  • What is wrong with my converted structures?

Regarding structures:

  1. Vehicle.Info is a pointer, so you need to declare it as IntPtr Info , and then use Marshal.PtrToStructure / Marshal.StructureToPtr to read/write its value in managed code;

  2. Vehicle.something2 is a byte array, not a byte, so you need to declare it this way:

    [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
    byte[] something2=new byte[20];

  3. Vehicle.Data - see #1, the same problem

  4. Info.Name - .NET does not provide marshalling for std::string, so you will either need to write your own marshaler (see this: Custom Marshaler for PInvoke with std::string ) or change the type to something like char* in your c++ library.
  5. Info.BuffCollection should also be an IntPtr or BuffCollection[] (depending on what the BuffCollection type is about - it's not provided in your question)

Regarding the signature and invocation of GetVehicle(); method:

it is likely that the method returns the pointer to the structure, not the structure itself (just speculating, please double check). If so, you need to declare it as

static extern IntPtr GetVehicle();

and then use Marshal.PtrToStructure to convert it to your structure like this:

var vehiclePtr=GetVehicle();
var vehicle = (Vehicle)Marshal.PtrToStructure(vehiclePtr, typeof(Vehicle));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM