将c++结构体转换为c#并使用它

本文关键字:c++ 结构体 转换 | 更新日期: 2023-09-27 17:54:05

我有一个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;
};

从这个问题中,我弄明白了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;
    }
}

然而,当我试图读取Vehicle:

[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

从我对它的搜索来看,它使我相信我的结构转换是错误的。

  • 我的转换结构有什么问题?

将c++结构体转换为c#并使用它

结构:

  1. Vehicle.Info是一个指针,所以需要声明为IntPtr Info,然后在托管代码中使用Marshal.PtrToStructure / Marshal.StructureToPtr读写它的值;

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

    [MarshalAs UnmanagedType。ByValArray SizeConst = 20)]

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

  4. Info.Name - . net不提供std::string的封送处理,所以你要么需要编写自己的封送处理(参见:自定义封送处理PInvoke with std::string),要么在你的c++库中将类型更改为char*之类的东西。
  5. Info.BuffCollection也应该是IntPtr或BuffCollection[](取决于BuffCollection类型是什么-它没有在你的问题中提供)

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

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

static extern IntPtr GetVehicle();

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

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