【问题标题】:Converting c++ struct to c# and using it?将 c++ struct 转换为 c# 并使用它?
【发布时间】:2015-06-07 06:41:24
【问题描述】:

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

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

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

【问题讨论】:

  • 我的问题错了吗?我在没有任何信息的情况下看到投票结束,为什么...是因为在底部我有 3 分吗?如果是这样,我可以删除其他 2 个并让它们成为一个新问题。
  • 函数的 C++ 签名是什么?
  • @TheodorosChatzigiannakis extern "C" __declspec(dllexport) Vehicle* GetVehicle(); 不确定这是否是您要查找的内容,但除了结构之外我只知道这些,因为我无法访问 DLL 源代码。
  • 注意something2 中的Vehicle,因为它是一个数组。
  • @Caramiriel 所以应该是byte[]?

标签: c# c++ struct


【解决方案1】:

关于结构:

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

  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();方法的签名和调用:

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

static extern IntPtr GetVehicle();

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

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

【讨论】:

  • 嗨 Denis,感谢您的详细回答,您能否发布一个示例,说明我将如何在函数上使用 Marshal.PtrToStructure?
  • 好的,已将示例添加到我的回复中
  • 可以用[MarshalAs(UnmanagedType.Struct)] public Info Info;代替IntPtr Data吗?
  • 我不这么认为。 UnmanagedType.Struct 表示变量包含结构,但在您的情况下,它是指向结构的指针(Info *info)。您可以尝试使用 UnmanagedType.LPStruct,但我从未尝试过。 Marshal.PtrToStructure 是更“传统”的方式恕我直言
猜你喜欢
  • 2021-02-20
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多