将 C++ 结构转换为 C# 并使用它?

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

我有一个 C++ 结构如下:

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,我明白了u32,u8等的意思,我想我明白了。

然后我尝试用它制作我自己的 C# 结构:

[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;
    }
}

但是,当我尝试读取车辆时:

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

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

我收到以下错误:

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

根据我对它的搜索,它让我相信我的结构转换是错误的。

关于结构:

  1. Vehicle.Info是一个指针,所以需要声明为IntPtr Info,然后在managed中用Marshal.PtrToStructure / Marshal.StructureToPtr到read/write它的值代码;

  2. Vehicle.something2是字节数组,不是字节,所以需要这样声明:

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

  3. Vehicle.Data - 参见#1,同样的问题

  4. Info.Name - .NET 不为 std::string 提供编组,因此您需要编写自己的编组器(请参阅:Custom Marshaler for PInvoke with std::string)或将类型更改为某些内容就像你的 C++ 库中的 char*。
  5. Info.BuffCollection 也应该是 IntPtr 或 BuffCollection[](取决于 BuffCollection 类型是什么——你的问题中没有提供)

关于GetVehicle();方法的签名和调用:

很可能方法 returns 指向结构的指针,而不是结构本身(只是推测,请仔细检查)。如果是这样,您需要将其声明为

static extern IntPtr GetVehicle();

然后使用 Marshal.PtrToStructure 将其转换为您的结构,如下所示:

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