C#调用含void*成员结构体数组的C DLL时遇内存访问错误
问题:C#调用C编写的DLL函数时触发访问违规异常
C端函数与结构体定义
C DLL中的函数签名及结构体定义如下:
unsigned long MyFunc(mystruct *arr, unsigned long arrLen); typedef struct mystruct { unsigned long type; void* val; unsigned long valLen; } mystruct;
其中type用于标识val的实际指针类型,valLen是val指向值的字节大小。
C#端声明
C#中对应的结构体与P/Invoke声明:
[StructLayout(LayoutKind.Sequential)] public struct mystruct{ public uint type; public IntPtr val; public uint valLen; } [DllImport("mydll.dll")] public static extern uint MyFunc(mystruct[] arr, uint arrLen);
错误信息
调用时触发以下异常:
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
测试场景与排查结果
- 尝试传递3个元素的数组:分别对应C的
unsigned long*类型的uint、unsigned char的byte、char*的byte数组;仅传递单个uint元素的数组时也会报错。 - 注释DLL中解引用
val的代码后,调用无错误;传递null数组时也无错误,因此问题出在指针传递方式上。
已尝试的两种传递方式
0- 手动固定托管内存
mystruct[] arr = new mystruct[3]; arr[0].type = 0; uint my_uint = 10; GCHandle handle_uint = GCHandle.Alloc(my_uint, GCHandleType.Pinned); arr[0].val = handle_uint.AddrOfPinnedObject(); arr[0].valLen = sizeof(uint); arr[1].type = 1; byte my_byte= 1; GCHandle handle_byte = GCHandle.Alloc(my_byte, GCHandleType.Pinned); arr[1].val= handle_byte.AddrOfPinnedObject(); arr[1].valLen= sizeof(byte); arr[2].type = 2; byte[] my_byte_arr = new byte[32]; for (int i = 0; i < 32; i++) { my_byte_arr[i] = 255; } GCHandle handle_byte_arr = GCHandle.Alloc(my_byte_arr, GCHandleType.Pinned); arr[2].val = handle_byte_arr.AddrOfPinnedObject(); arr[2].valLen = (uint) my_byte_arr.Length; MyFunc(arr, (uint) arr.Length); handle_uint.Free(); handle_byte.Free(); handle_byte_arr.Free();
1- 手动分配非托管内存(仅展示uint的情况)
mystruct[] arr = new mystruct[1]; arr[0].valLen = sizeof(uint); arr[0].type = 0; arr[0].val = Marshal.AllocCoTaskMem((int) arr[0].valLen); Marshal.WriteInt32(arr[0].val, 10); MyFunc(arr, (uint) arr.Length); Marshal.FreeCoTaskMem(arr[0].val);
补充说明
曾参考相关问题,但现有方案不适用:能正常调用DLL的其他函数,仅该函数在解引用val时出错。
内容的提问来源于stack exchange,提问作者chilliefiber
相关产品推荐
相关产品推荐

