【发布时间】:2015-02-24 16:59:06
【问题描述】:
我正在向一个 C++ 库编写一个 C# API,该库接受一个具有此签名的函数指针:
typedef int MyCallback(
int n,
int m,
const double * x,
const double * l,
double * c);
数组x 的大小为n,数组c 的大小为m,数组l 的大小为m + n。
我不能更改C++ MyCallback 函数的签名。
问题:
我已经使用 MarshalAs(UnmanagedType.LPArray, SizeParamIndex = <approriate_index>) 从 C# 传递了数组。这适用于x 和c。当我没有明确的参数大小时,如何编组 l 并跟踪其大小?
我知道的唯一可行的解决方案是从 C# 传递 IntPtr 并使用 unsafe 和 ToPointer()。有没有其他解决方案?
我正在尝试做的一个例子如下:
C#代码:
using System.Runtime.InteropServices;
namespace PInvokeTest
{
public class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate double MyCallback(
int n,
int m,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] x,
[In, MarshalAs(UnmanagedType.LPArray)] double[] l,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] c);
private static double CallbackFunction(
int n,
int m,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] double[] x,
[In, MarshalAs(UnmanagedType.LPArray)] double[] l,
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] double[] c)
{
// THIS IS WILL NOT WORK, l HAS SIZE 1.
// In this example, only l[0] and l[1] are used, but in general
// the size of l is n + m.
c[0] = x[0] + x[1] + x[2] + l[0]*l[1];
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 = CallbackFunction;
f(_myCallback);
}
}
}
头文件:
#ifndef _NATIVELIB_H_
#define _NATIVELIB_H_
#ifndef MYAPI
#define MYAPI
#endif
#ifdef __cplusplus
extern "C"
{
#endif
typedef int MyCallback(
int n,
int m,
const double * x,
const double * l,
double * c);
MYAPI int f(MyCallback * fnPtr);
#ifdef __cplusplus
}
#endif
#endif // _NATIVELIB_H_
C++ 源代码:
#include "NativeLib.h"
#include <stdio.h>
#include <malloc.h>
MYAPI int f(MyCallback * fnPtr)
{
int n = 3;
int m = 2;
double x[] = { 1.0, 2.0, 3.0 };
double l[] = { 1.0, 1.0, 1.0, 1.0, 1.0 };
double c[] = { 0.0, 0.0};
printf("%e\n", fnPtr(n, m, x, l, c));
printf("the value of c after the function call:\n");
printf("%e %e\n", c[0], c[1]);
return 0;
}
【问题讨论】:
-
我很可能误解了一些东西,但我想知道为什么你说“我已经通过数组 from C# using ...”和“... is传递 IntPtr from C# 和 ..."。你不是说to C#吗?
-
无论如何,您是否可以为 C++ 库编写一个非常薄的 C++ 包装器,在其中定义一个符合 MyCallback 签名的回调函数,然后它会调用更多的编组 -带有一个包含 l 数组长度的额外参数的友好回调函数?
-
是的,你是对的,我想应该是“to”。它们作为指针来自 C++,而作为我编组它们的任何内容来自 C#,但我写了“from”,因为我定义了如何根据 C# 将它们传递给 C#。无论如何...
-
关于第二条评论。负责人希望 C# 界面由“仅 .cs 文件”组成。创建 C++ 包装器会更容易,但我想在试图说服他们我需要一个之前避免使用它。
-
我不建议作弊,(哦,不,不是我),但如果涉及到,请尝试在 Google 上搜索“c# dll 作为嵌入式资源”。例如:stackoverflow.com/questions/72264/…
标签: c# pinvoke marshalling