[英]Pinvoke - callback from C++, arrays passed between functions have unexpected size
EDIT: I've updated the code given the suggestions in @Hans Passant's comment and @David Heffernan's answer. 编辑:我已经更新了代码,给出了@Hans Passant的注释和@David Heffernan的答案中的建议。
The argument c
is no longer null, but both x
and c
still have length one when they are passed back to CallbackFunction
. 参数
c
不再为null,但是x
和c
传递回CallbackFunction
时,它们的长度仍为1。
I am trying to write C# code that passes a function pointer (using a delegate) to a C++ function, which calls the function pointer. 我正在尝试编写将函数指针(使用委托)传递给C ++函数的C#代码,C ++函数调用函数指针。
Code is below. 代码如下。
The problem I'm having is that when the C++ function f
calls fnPtr(x,c)
, in the C# function CallbackFunction
, x
has one element (with the correct value of 1.0), and c
is null. 我遇到的问题是,当C ++函数
f
调用fnPtr(x,c)
,在C#函数CallbackFunction
, x
具有一个元素(正确值为1.0),而c
为null。 I have no idea what the problem is. 我不知道是什么问题。
I can't change the signature of MyCallback. 我无法更改MyCallback的签名。
C# code: 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: 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: 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;
}
Using ref
on your array parameter is wrong. 在数组参数上使用
ref
是错误的。 That's a spurious extra level of indirection. 那是一个虚假的间接附加级别。 You also need to pass the array lengths as parameters and let the marshaller know these lengths.
您还需要将数组长度作为参数传递,并让编组知道这些长度。
The delegate should be: 代表应为:
[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
);
Change CallbackFunction
to match. 更改
CallbackFunction
以匹配。
The "duh" assumption I was making was that C would somehow pass some information on the size of x
and c
arrays, when it's just passing pointers. 我所做的“ duh”假设是C仅在传递指针时就以某种方式传递有关
x
和c
数组大小的信息。 The solution that I found was to mimic the code found in a related SO question . 我找到的解决方案是模仿在一个相关的SO问题中找到的代码。 (I don't know if it's a good way to solve my problem, but it works).
(我不知道这是否是解决我的问题的好方法,但是它可以工作)。
I changed the callback function (and the delegate definition to match) to use an IntPtr
. 我将回调函数(和匹配的委托定义)更改为使用
IntPtr
。 In general, I obviously need to pass information on the sizes of c and x. 通常,我显然需要传递有关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];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.