将带有数组的回调函数从 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")]
我有一个第三方 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")]