C#调用C++ DLL时结构体封送数据异常,如何修正?
问题分析与修正方案
核心问题
数据错位的根本原因是C#结构体的类型映射和内存对齐规则与C++不匹配:
- 类型不匹配:C++中
unsigned long在32位环境下是4字节无符号整数,你错误地用了C#的long(8字节)来映射,直接导致后续字段的内存偏移全部错乱。 - 内存对齐不匹配:C默认的结构体对齐规则(32位环境)是4字节,你设置了
Pack=8,导致结构体的内存填充逻辑与C不一致,进一步加剧数据错位。
修正后的代码
1. 正确的C#结构体定义
[StructLayout(LayoutKind.Sequential, Pack = 4)] public struct USB_DEVICE_INFO { public byte ucSpeed; // 对应C++的unsigned long(32位环境下4字节无符号整数) public uint ulLength; public byte ucBulkInPipe; public byte ucBulkOutPipe; public byte ucInterruptPipe; }
如果需要显式指定封送类型,也可以写成:
[StructLayout(LayoutKind.Sequential, Pack = 4)] public struct USB_DEVICE_INFO { public byte ucSpeed; [MarshalAs(UnmanagedType.U4)] public uint ulLength; public byte ucBulkInPipe; public byte ucBulkOutPipe; public byte ucInterruptPipe; }
2. 优化后的DLL导入声明(可选但更严谨)
如果C++的_InitialiseDevice使用的是WINAPI(即__stdcall)调用约定,显式指定调用约定可以避免潜在的栈平衡问题:
[DllImport(@"32.dll", CallingConvention = CallingConvention.StdCall)] public static extern bool _InitialiseDevice(out USB_DEVICE_INFO pDevInfo);
验证逻辑
修正后的C#结构体内存布局与C++完全一致(32位环境下):
ucSpeed占1字节,自动填充3字节以对齐到4字节边界ulLength占4字节- 后续三个
byte字段各占1字节,最后填充1字节使整个结构体大小为12字节(4的倍数,符合默认对齐规则)
这样C++填充的字段值就能准确映射到C#结构体的对应成员中。
内容的提问来源于stack exchange,提问作者Nick Pitman
相关产品推荐
相关产品推荐

