如何在C#中封送C++结构体并访问其填充数据?
解决C++ DLL结构体在C#中无法访问数据的问题
1. 先修正C++代码的笔误
原C结构体Info的成员是midcycle,但初始化函数里写的是lp->mycycle = NOES;,这是拼写错误,必须改为lp->midcycle = NOES;,否则C侧的初始化逻辑本身就不生效。
2. 在C#中正确映射C++类型
要访问C结构体数据,必须在C#中精准复刻C的类型定义,包括枚举、数组、结构体的内存布局:
2.1 映射枚举类型
C++的MYCYCLETYPE枚举直接对应C#的enum,确保枚举值和底层类型匹配:
public enum MYCYCLETYPE { NOES = 0, LET = 1, WARN = 2, GRACE = 3, EXP = 4 }
2.2 映射自定义日期数组
C++的CusDate是长度为11的char数组(sizeof("2023-02-02")包含末尾的\0,共11个字符),在C#中用ByValTStr修饰字符串来对应:
// 对应C++的char[11] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string sedate;
2.3 完整映射结构体SINFO
指定结构体的内存布局为顺序排列,字符集匹配C的ANSI char,成员顺序必须和C完全一致:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct SINFO { public MYCYCLETYPE midcycle; public int type; public int porotype; public long sways; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string sedate; public long days; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string elate; public long edays; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string edate; [MarshalAs(UnmanagedType.LPStr)] public string feature; [MarshalAs(UnmanagedType.LPStr)] public string ver; [MarshalAs(UnmanagedType.LPStr)] public string hid; }
const char*类型对应C#的string,用LPStr标记为ANSI字符串指针;- 若C++使用了内存对齐指令(如
#pragma pack(4)),需在StructLayout中添加Pack = 4参数。
3. 修正DllImport和调用逻辑
调整DllImport的字符集设置,确保结构体初始化后再传入:
[DllImport("abc.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] static extern int Initialize(ref SINFO lp); static void Main() { // C#结构体是值类型,必须初始化后再传递 SINFO mydata = new SINFO(); int result = Initialize(ref mydata); // 现在可以直接访问结构体成员 Console.WriteLine($"周期类型: {mydata.midcycle}"); Console.WriteLine($"硬件ID: {mydata.hid}"); Console.WriteLine($"起始日期: {mydata.sedate}"); // 其他成员同理访问 }
额外注意事项
- 若C++的
long是32位(如32位系统或特定编译器),C#需用int代替long,因为C#的long是64位; - 若C++的
const char*指向动态分配的内存,需确保DLL负责内存释放,或在C#中调用Marshal.FreeHGlobal手动释放(需确认内存分配方式)。
内容的提问来源于stack exchange,提问作者Indrasen
相关产品推荐
相关产品推荐

