在写项目的时候,我需要将C++中接收到的结构体传输到我的C#项目中使用。结构体中基本是int,int[],float类型数据,这些类型在C++和C#中是一样的,可以直接传输,但是结构体怎么传输呢?下面是简单示例:
MyStruct.h
extern "C" {
#pragma pack(1)
typedef struct _data1{
int id[4]; }Data1;
typedef struct _data2{
int aa;}Data2;
typedef struct _data3{
float cc;
} Data3;
typedef struct _data4{
int ee[4]; }Data4;
typedef struct _data5{
int vv[3][3]; }Data5;
typedef struct _data{
Data1 d1;
Data2 d2;
Data3 d3;
Data4 d4;
Data5 d5;
}MyStruct;
#pragma pack()
}
MyStruct.cpp
这里可以看到,我返回一个结构体指针,因为无法直接传递一个结构体。
extern "C"{
__declspec(dllexport) MyStruct* GetStruct();
__declspec(dllexport) void FreeStruct(MyStruct* ptr);//一定不要忘了释放内存函数
}//目的是暴露函数接口,也可以在头文件中声明
MyStruct* GetStruct() {
// 分配并初始化一个MyStruct实例的内存
MyStruct* pStruct = new MyStruct();
//对pStruct指向结构体进行处理,下面是示例
pStruct->d1.id[0] = 123;
pStruct->d1.id[1] = 23;
pStruct->d1.id[3] = 22;
pStruct->d2.aa = 456;
pStruct->d3.cc = 123.123;
pStruct->d5.vv[0][0] = 11;
pStruct->d5.vv[1][1] = 12;
pStruct->d5.vv[2][1] = 13;
return pStruct;
}
void FreeStruct(MyStruct* ptr) {
delete ptr;
}
Class1.cs
在C#中构造一个跟C++一样的结构体
class Class1
{
public struct data1
{
public int[] id;
}
public struct data2
{
public int aa;
}
public struct data3
{
public float cc;
}
public struct data4
{
public int[] ee;
}
public struct data5
{
public int[,] vv;
}
public struct MyStruct
{
public data1 d1;
public data2 d2;
public data3 d3;
public data4 d4;
public data5 d5;
}
public static MyStruct my = new MyStruct();
}
Class2.cs
由于MyStruct是复杂的嵌套结构体,因此创建一个MyStruct1用于接收传过来数据,不能直接传到MyStruct,接收数据会不对。
using System.Runtime.InteropServices;
namespace testdemo
{
class Class2
{
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct1
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] id;
public int aa;
public float uu;
public int[] ee;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] // 3x3总共9个元素,多加2是因为我发现传过来数据往后移了两位
public int[] dd;
// 提供一个属性来方便按二维索引访问
}
public static MyStruct1 my1 = new MyStruct1();
}
}
Ctrl.cs
using System;
using System.Runtime.InteropServices;
namespace testdemo
{
class Ctrl
{
[DllImport("MyStruct.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr GetStruct();
[DllImport("MyStruct.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void FreeStruct(IntPtr ptr);
IntPtr ptr = GetStruct();
if(ptr != IntPtr.Zero) // 确保地址有效
{
Class2.my1 = (Class2.MyStruct1)Marshal.PtrToStructure(ptr, typeof(Class2.MyStruct1));
ExData();//写一个my1数据复制给my的函数
FreeStruct(ptr);//释放内存!!一定不要忘记!!
}
}
}
总结:
- 结构体从C++到C#,用结构体指针。
- 嵌套的复杂结构体传输,要在C#这边构造两个结构体,一个用于接收数据,一个用于还原结构体。
- 传输结束后,记得释放指针指向内存。
注意
上述有个二维数组,因为其在最后,所以好像对后面数据没什么影响,但是在实际项目中,我发现数据复制过程中可能会因为[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] // 3x3总共9个元素,多加2是因为我发现传过来数据往后移了两位 public int[] dd; // 提供一个属性来方便按二维索引访问
出错,这里给大家提个醒,自己试验一下。