繁体   English   中英

将带有数组的回调函数从 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: '试图读取或写入受保护的内存。 这通常表明其他内存已损坏。

我不确定这就是原因。

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

int result = CFunction(arraysLength, solCBDel);

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

编辑:

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

int result = CFunction(arraysLength, solCBDel);

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

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

经过深入研究,我发现了如何从 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")]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM