将带有数组的回调函数从 C# 传递到 C DLL

Pass a callback function with arrays from C# to C DLL

我有一个第三方 C DLL,只有,其头文件为 API。我希望能够调用它的功能之一。 C 头文件如下所示:

#ifdef  __cplusplus
    extern "C" {
#endif
    
#ifdef __WATCOMC__
    #define EXPORT extern int __declspec(dllexport) __stdcall
    #define IMPORT extern int __declspec(dllimport) __stdcall
#endif
    
#ifdef _WINDOWS
#ifndef EXPORT
    #define EXPORT extern int
#endif
#endif
    
#ifndef EXPORT
    #define EXPORT int
#endif

#ifndef EXIMPORT
    #define EXIMPORT EXPORT
#endif
.
.
.
EXIMPORT CFunction(
  int callbackArraysLength,
  int (*solutionCallbackFunction)(int*, double*, double)
);

solutionCallbackFunction规格:

int *intArray
double *doubleArray
double doublefield

C#代码:

[DllImport(@"PathToDLL", EntryPoint = "CFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern int CFunction(int callbackArraysLength, [MarshalAs(UnmanagedType.FunctionPtr)]  SolutionCallbackFuncDelegate solutionCallbackFunc);

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int SolutionCallbackFuncDelegate ([In] int[] intArr, [In] double[] doubleArr,[In] double d);

public static int solutionFunction([In] int[] intArr, [In] double[] doubleArr,[In] double d) {
  .
  .
  // Some code that checks the input...
  .
  .
  return 0;
}

static SolutionCallbackFuncDelegate solCBDel;

public static void Main(string[] args)
{
  solCBDel = new SolutionCallbackFuncDelegate(solutionFunction);
  ...
  int arraysLength = 5; //I know the size of the arrays that will be returned from the callback function.
  int result = CFunction(arraysLength, solCBDel);
  ...
}

我是不是做错了什么?我收到此错误:

System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

我不确定是不是这个原因。

调用 Main 中的函数时出现异常:

int result = CFunction(arraysLength, solCBDel);

文档没有说明我是否需要在回调函数中为数组分配内存。
如果是这个原因,我到底应该在哪里分配代码中的数组?

编辑:

@GSerg 建议这个答案: 但是在我的回调函数中,没有字段具有数组的大小:int (*solutionCallbackFunction)(int*, double*, double) 将回调函数作为指针发送的主函数与数组的大小一起发送:

int result = CFunction(arraysLength, solCBDel);

在C#端,我需要分配内存。

当我通过 arraysLength 将其发送到 C++ 时,如果 C++ 和 C# 具有长度,是否有另一种分配回调函数数组的方法??

经过深入研究,我发现了如何从C#调用C DLL。

C#代码应该是:

[DllImport(@"PathToDLL", EntryPoint = "CFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern int CFunction(int callbackArraysLength, [MarshalAs(UnmanagedType.FunctionPtr)]  SolutionCallbackFuncDelegate solutionCallbackFunc);

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

public static int solutionFunction([In] IntPtr intArrPtr, [In] IntPtr doubleArrPtr,[In] double d) {
  
  int[] intArr = new int[arraysLength];
  double[] doubleArr = new double[arraysLength];
  Marshal.Copy(intArrPtr, intArr , 0, arraysLength);
  Marshal.Copy(doubleArrPtr, doubleArr, 0, arraysLength);


  // Some code that checks the input...
  .
  .
  return 0;
}
    
public static int arraysLength = 5; //I know the size of the arrays that will be returned from the callback function. It should be global.
    
public static void Main(string[] args)
{
  ...
  
  int result = CFunction(arraysLength, solutionFunction);
  ...
}

在 C# 回调定义中,我们必须使用 IntPtr,然后使用 Marshal.Copy(...),因为回调函数没有长度参数。 如果回调函数中有长度参数,我们可以使用 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = "Index of the length parameter")]