C# P/Invoke调用C++接口时Struct8非ref传递出现内存损坏问题
问题根本原因
P/Invoke签名与C导出函数的参数类型不匹配:
你C侧导出的Net5_Initialize函数所有结构体参数均为指针类型:
MODULE_API void Net5_Initialize(Struct1* struct1, Struct8* struct8, Struct6* struct6, Struct2Detail* struct2Detail);
但你最初的C# DllImport声明中,Struct1、Struct8是按值传递的:
// 错误声明 [DllImport(LIBNAME, CallingConvention = CallingConvention.Cdecl)] public static extern void Net5_Initialize(Struct1 struct1, Struct8 struct8, out Struct6 struct6, out Struct2Detail struct2Detail);
C#按值传递值类型结构体时,会把结构体完整内容复制到调用栈中,而C侧会把栈上的结构体数据直接当成内存指针访问,必然会访问非法内存,导致参数内容损坏。你给Struct8加上ref修饰后,C#会改为传递结构体的内存地址,刚好匹配C的Struct8*类型,所以调用可以正常运行。
为什么其他参数看起来没出问题?
你代码中out修饰的参数本身就是传地址,天然匹配C++的指针类型,所以没有问题。其他按值传递的结构体参数(比如Create接口中的Struct1、Struct3、Struct5)本质上也存在类型不匹配问题,只是暂时没有触发崩溃,属于不稳定的巧合状态。
修复方案
- 修正所有P/Invoke签名,所有对应C++侧为结构体指针的参数,都加上
ref/out修饰,可额外添加[In]/[Out]特性明确封送方向:
// 修正后的Net5_Initialize声明 [DllImport(LIBNAME, CallingConvention = CallingConvention.Cdecl)] public static extern void Net5_Initialize( [In] ref Struct1 struct1, [In] ref Struct8 struct8, out Struct6 struct6, out Struct2Detail struct2Detail );
- 同步修改上层封装的方法签名:
public static void Initialize( Struct1 struct1, ref Struct8 struct8, out Struct6 struct6, out Struct2Detail struct2Detail ) { Net5_Initialize(ref struct1, ref struct8, out struct6, out struct2Detail); }
- 逐个检查所有P/Invoke接口的参数类型,确保C#侧的参数传递语义和C++侧完全匹配,避免隐藏的崩溃风险。
额外说明
你当前的StructLayout、MarshalAs配置是正确的,C#与C++侧的结构体内存布局完全对齐,不需要修改结构体定义。
内容的提问来源于stack exchange,提问作者VenoMpie
相关产品推荐
相关产品推荐

