I am writing a C# API to a C++ library that takes a function pointer with this signature:
typedef int MyCallback(
int n,
int m,
const double * x,
const double * l,
double * c);
Array x
has size n
, array c
has size m
, and array l
has size m + n
.
I cannot change the signature of the C++
MyCallback
function.
The question:
I've passed the arrays from C# using MarshalAs(UnmanagedType.LPArray, SizeParamIndex = <approriate_index>)
. this is fine for x
and c
. How do I marshal l
and keep track of its size, when I don't explicitly have a parameter with its size?
The only solution I know of that works is to pass IntPtr
from C# and use unsafe
and ToPointer()
. Is there a another solution?
An example of what I'm trying to do is below:
C# code:
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);
}
}
}
Header file:
#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++ source:
#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;
}