C#向C++传递委托数组触发AccessViolationException异常求助
问题根因
你遇到的崩溃主要是2个核心错误导致的:
- C++侧结构体的字段定义类型不匹配,C#封送的函数指针数组是连续存储的函数指针值,而你声明的是
MyCallback* MyHandlers[32](函数指针的指针数组),类型层级多了一层间接寻址,调用时会把指针值当成函数入口地址执行,直接触发访问违规。 - .NET委托实例没有被手动持有强引用,GC在运行时会判定没有被引用的委托实例可回收,导致C++侧持有的函数指针变为野指针。
可行解决方案
步骤1:修正C++侧类型定义
首先修正回调函数的参数类型、调用约定,以及结构体的数组定义:
// 显式指定调用约定,修正字符串参数为指针类型 typedef void* (__cdecl *MyCallback)(const wchar_t* inStringParam, int* outIntParam, wchar_t* outStringParam); // 结构体中直接定义函数指针数组,而非指针的指针数组 struct NativeParameters { // 其他字段... MyCallback MyHandlers[32]; }; // 调用方式不需要额外强转,直接使用即可 initParams->MyHandlers[0](L"test", &outInt, outStrBuf);
步骤2:C#侧手动持有委托强引用
在使用委托数组的类中声明类级别的私有字段持有委托数组,防止GC回收:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)] public delegate IntPtr MyDelegate(string inStringParam, out int outIntParam, out string outStringParam); [StructLayout(LayoutKind.Sequential)] internal struct NativeParameters { // 其他字段... [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.FunctionPtr, SizeConst = 32)] internal MyDelegate[] MyHandlers; } // 类级别字段,持有强引用避免GC回收委托实例 private MyDelegate[] _myHandlersHolder; private NativeParameters _startupParameters; // 初始化逻辑 private void InitParams() { _myHandlersHolder = new MyDelegate[32]; // 赋值委托实例 _myHandlersHolder[0] = OnMyEvent; // 其他委托赋值... // 赋值给结构体字段 _startupParameters = new NativeParameters { MyHandlers = _myHandlersHolder }; // 后续传递结构体到C++的逻辑 }
可选检查项
如果你的out string参数是需要C++侧写入字符串,建议将C#委托的out string改为StringBuilder类型,预先分配缓冲区再传递,避免字符串封送时的内存访问错误。
内容的提问来源于stack exchange,提问作者Mike Yeager
相关产品推荐
相关产品推荐

