You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#向C DLL传递含数组参数的回调时触发AccessViolationException如何解决

问题根因及修复方案

1. 调用约定不匹配

从给出的C头文件可以看到,当编译环境为WATCOMC时,导出函数的调用约定被指定为__stdcall,你当前C#代码中DllImport和UnmanagedFunctionPointer特性均指定为Cdecl,调用约定不匹配会直接导致栈不平衡,触发访问冲突。
优先尝试将两处调用约定修改为CallingConvention.StdCall,如果DLL是在非WATCOMC的Windows环境下编译的,再尝试切回Cdecl验证。

2. 数组参数封送逻辑错误

你需要在C#侧分配数组内存的场景下,C DLL传入回调的int*、double*为待赋值的空指针,你当前直接将委托参数声明为托管数组类型,CLR会尝试从空指针读取内存转成托管数组,必然触发访问错误。

正确实现逻辑

  • 委托中的数组参数改为IntPtr类型接收C侧传入的指针
  • 在回调函数内部分配对应长度的托管数组,通过Marshal类将托管数组内容拷贝到非托管指针指向的内存空间,或者直接分配非托管内存赋值给传入的指针
  • 若为C DLL向数组写入数据返回给C#使用的场景,则反过来在回调内通过Marshal.Copy将IntPtr指向的非托管内存拷贝到托管数组中即可

修复后代码示例

// 调用约定优先试StdCall,不生效再切换为Cdecl
[DllImport(@"PathToDLL", EntryPoint = "CFunction", CallingConvention = CallingConvention.StdCall)]
public static extern int CFunction(int callbackArraysLength, [MarshalAs(UnmanagedType.FunctionPtr)] SolutionCallbackFuncDelegate solutionCallbackFunc);

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int SolutionCallbackFuncDelegate(IntPtr intArrPtr, IntPtr doubleArrPtr, double d);

public static int solutionFunction(IntPtr intArrPtr, IntPtr doubleArrPtr, double d) {
    int arraysLength = 5;
    // 场景1:C#侧分配内存,供C DLL写入数据
    int[] intArr = new int[arraysLength];
    double[] doubleArr = new double[arraysLength];
    // 此处填充数组内容逻辑
    // ...
    // 将托管数组拷贝到C侧传入的指针指向的内存
    Marshal.Copy(intArr, 0, intArrPtr, arraysLength);
    Marshal.Copy(doubleArr, 0, doubleArrPtr, arraysLength);

    /* 场景2:C DLL填充数组,C#侧读取
    int[] intArr = new int[arraysLength];
    double[] doubleArr = new double[arraysLength];
    Marshal.Copy(intArrPtr, intArr, 0, arraysLength);
    Marshal.Copy(doubleArrPtr, doubleArr, 0, arraysLength);
    // 后续处理数组内容逻辑
    */
    return 0;
}

static SolutionCallbackFuncDelegate solCBDel;

public static void Main(string[] args)
{
    solCBDel = new SolutionCallbackFuncDelegate(solutionFunction);
    int arraysLength = 5;
    int result = CFunction(arraysLength, solCBDel);
}

内存分配位置说明

内存分配操作在回调函数solutionFunction内部实现即可,你预先定义的静态委托变量已经避免了GC回收委托对象的问题,无需额外处理。


内容的提问来源于stack exchange,提问作者Eran.G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 11:15:01