Pinvoke - 来自C++的回调,函数之间传递的数组具有意外的大小
本文关键字:数组 意外 之间 来自 C++ 回调 函数 Pinvoke | 更新日期: 2023-09-27 18:35:14
编辑:我已经更新了代码,给出了@Hans Passant的评论中的建议,并@David Heffernan的答案。
参数c
不再为空,但 x
和 c
在传递回 CallbackFunction
时仍然具有 1 的长度。
我正在尝试编写将函数指针(使用委托)传递给C++函数的 C# 代码,该函数调用函数指针。
代码如下。
我遇到的问题是,当C++函数f
调用 fnPtr(x,c)
时,在 C# 函数CallbackFunction
中,x
有一个元素(正确值为 1.0),c
为 null。我不知道问题是什么。
我无法更改 MyCallback 的签名。
C# 代码:
using System.Runtime.InteropServices;
namespace PInvokeTest
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate double MyCallback(
[In] double[] x,
[Out] double[] c);
private static double CallbackFunction(
[In] double[] x,
[Out] double[] c)
{
c[0] = x[0] + x[1] + x[2];
c[1] = x[0] * x[1] * x[2];
return c[0] + c[1];
}
private static MyCallback _myCallback;
[DllImport("NativeLib", CallingConvention = CallingConvention.StdCall)]
private static extern int f(MyCallback cf);
private static void Main()
{
_myCallback = new MyCallback(CallbackFunction);
f(_myCallback);
}
}
}
NativeLib.h:
#ifndef _NATIVELIB_H_
#define _NATIVELIB_H_
#ifndef MYAPI
#define MYAPI
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef _WIN32
#ifdef MAKE_MY_DLL
#define MYAPI __declspec(dllexport) __stdcall
#else
#define MYAPI __stdcall
#endif
#else
#if __GNUC__ >= 4
#define MYAPI __attribute__ ((visibility ("default")))
#else
#define MYAPI
#endif
#endif
typedef int MyCallback(const double * x,
double * c);
MYAPI int f(MyCallback * fnPtr);
#ifdef __cplusplus
}
#endif
#endif // _NATIVELIB_H_
NativeLib.cpp:
#include "NativeLib.h"
#include <stdio.h>
#include <malloc.h>
MYAPI int f(MyCallback * fnPtr)
{
double x[] = { 1.0, 2.0, 3.0 };
double c[] = { 0.0, 0.0, 0.0 };
printf("%e'n", fnPtr(x, c));
return 0;
}
在数组参数上使用ref
是错误的。这是一个虚假的额外间接级别。您还需要将数组长度作为参数传递,并让编组器知道这些长度。
委托人应为:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate double MyCallback(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
[In] double[] x,
[In] int lenx,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=3)]
[Out] double[] c,
[In] int lenc
);
更改CallbackFunction
以匹配。
我所做的"duh"假设是,当 C 只是传递指针时,它会以某种方式传递一些关于x
和c
数组大小的信息。我找到的解决方案是模仿相关SO问题中的代码。(我不知道这是否是解决我问题的好方法,但它有效)。
我更改了回调函数(以及要匹配的委托定义)以使用IntPtr
。一般来说,我显然需要传递有关 c 和 x 大小的信息。
unsafe private static double CallbackFunction(
[In] IntPtr xp,
[Out] IntPtr cp)
{
Double* c = (Double*) cp.ToPointer();
Double* x = (Double*) xp.ToPointer();
c[0] = x[0] + x[1] + x[2];
c[1] = x[0] * x[1] * x[2];
return c[0] + c[1];
}