将 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
根据我对它的搜索,它让我相信我的结构转换是错误的。
- 我转换的结构有什么问题?
关于结构:
Vehicle.Info
是一个指针,所以需要声明为IntPtr Info
,然后在managed中用Marshal.PtrToStructure / Marshal.StructureToPtr
到read/write它的值代码;
Vehicle.something2
是字节数组,不是字节,所以需要这样声明:
[MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
byte[] something2=new byte[20];
Vehicle.Data
- 参见#1,同样的问题
Info.Name
- .NET 不为 std::string 提供编组,因此您需要编写自己的编组器(请参阅:Custom Marshaler for PInvoke with std::string)或将类型更改为某些内容就像你的 C++ 库中的 char*。
Info.BuffCollection
也应该是 IntPtr 或 BuffCollection[](取决于 BuffCollection 类型是什么——你的问题中没有提供)
关于GetVehicle();
方法的签名和调用:
很可能方法 returns 指向结构的指针,而不是结构本身(只是推测,请仔细检查)。如果是这样,您需要将其声明为
static extern IntPtr GetVehicle();
然后使用 Marshal.PtrToStructure
将其转换为您的结构,如下所示:
var vehiclePtr=GetVehicle();
var vehicle = (Vehicle)Marshal.PtrToStructure(vehiclePtr, typeof(Vehicle));
我有一个 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
根据我对它的搜索,它让我相信我的结构转换是错误的。
- 我转换的结构有什么问题?
关于结构:
Vehicle.Info
是一个指针,所以需要声明为IntPtr Info
,然后在managed中用Marshal.PtrToStructure / Marshal.StructureToPtr
到read/write它的值代码;Vehicle.something2
是字节数组,不是字节,所以需要这样声明:[MarshalAs(UnmanagedType.ByValArray, SizeConst=20)]
byte[] something2=new byte[20];Vehicle.Data
- 参见#1,同样的问题Info.Name
- .NET 不为 std::string 提供编组,因此您需要编写自己的编组器(请参阅:Custom Marshaler for PInvoke with std::string)或将类型更改为某些内容就像你的 C++ 库中的 char*。Info.BuffCollection
也应该是 IntPtr 或 BuffCollection[](取决于 BuffCollection 类型是什么——你的问题中没有提供)
关于GetVehicle();
方法的签名和调用:
很可能方法 returns 指向结构的指针,而不是结构本身(只是推测,请仔细检查)。如果是这样,您需要将其声明为
static extern IntPtr GetVehicle();
然后使用 Marshal.PtrToStructure
将其转换为您的结构,如下所示:
var vehiclePtr=GetVehicle();
var vehicle = (Vehicle)Marshal.PtrToStructure(vehiclePtr, typeof(Vehicle));