Callback with unsafe double* to double[] Problem :

B

BlueTrin

I am using a DLL written in C, it uses some pointers on functions, I
have defined a wrapper around it in C# which uses some delegates:

#region Delegates and Marshalling to call solvopt

public delegate double funCallback(double[] x);
public delegate double funcCallback(double[] x);
public delegate void gradCallback(double[] x, double[] v);
public delegate void gradcCallback(double[] x, double[] v);

[DllImport("SolvOpt_C.dll")] //, EntryPoint="useFunc")]
extern static unsafe double* solvopt(UInt16 n, double[] x, funCallback
fun, gradCallback grad, double[] options, funcCallback func,
funcCallback gradc);


public static unsafe double[] SolvOptWrapper(UInt16 n, double[] x,
funCallback fun, gradCallback grad, double[] options, funcCallback
func, funcCallback gradc)
{
double* us_Ret;
double[] retVal = new double[n + 1];
int it = 0;

us_Ret = solvopt(n, x, fun, grad, options, func, gradc);

retVal.Initialize();
for ( it = 0 ; it < n+1 ; ++it )
retVal[it] = us_Ret[it];
return retVal;
}
#endregion

static unsafe double funTest(double[] x)
{
return ( Math.Sqrt(x[0] - 4) + Math.Sqrt(x[1] - 3));
}

public static void TestDelegates()
{
UInt16 n;
double[] x;
funCallback fun = new funCallback(funTest);
gradCallback grad = null;
funcCallback func = null;
funcCallback gradc = null;
double[] solvopt_options = new double[13]{-1.0e+0 , 1.0e-4 , 1.0e-6 ,
15.0e+3 , 0.0e+0,1.0e-8 , 2.5e+0 , 1.0e-11 , 0.0e+0 , 0.0e+0 , 0.0e+0 ,
0.0e+0 , 0.0e+0};

n = 2;
x = new double[2]{ 2.0 , 1.0 };

SolvOptWrapper(n, x, fun, grad, solvopt_options, func, gradc);
}

When I call TestDelegate I get this error:

An unhandled exception of type 'System.IndexOutOfRangeException'
occurred in ConsoleTester.exe

Additional information: Index was outside the bounds of the array.

From what I understand the debugger is telling me that the double[2]
that I pass in parameter is converted to a double* when calling the C
function.

However when the C function (solvopt) calls the Callback function by
the delegate (funTest) the parameter is passed as double[1], probably
because it has no idea about the length of the array.

Anybody knows how I can solve this problem knowing that I cannot know
the size of this array before the function is called (the size is the
UInt16 n).

Cheers
Anthony
 
B

BlueTrin

I found a rather inelegant solution:

- first of all make usre that you use __stdcall option by default for
the C project or the callback function will create an ESP problem.
- instead of using double[], declare it as unsafe and use IntPtr
- convert the IntPtr to a void* using to ToPointer and recast it in
double*
- then iterate the pointer using []

The changes are like the following lines:

public delegate double funCallback(IntPtr x);
public delegate double funcCallback(IntPtr x);

static unsafe double funTest(IntPtr ptr)
{
double* x = (double*)ptr.ToPointer(); // oops ! really dirty cast
Console.WriteLine("x[0] = " + x[0].ToString() + "x[1] = " +
x[1].ToString() + " --> " +(x[0] - 4) * (x[0] - 4) + (x[1] - 3) * (x[1]
- 3) );
return ( (x[0] - 4) * (x[0] - 4) + (x[1] - 3) * (x[1] - 3) );
}

If you know a better solution that would make the callbacks not
declared as unsafe please let me know !

Cheers
Anthony N.
 
M

Mattias Sjögren

- first of all make usre that you use __stdcall option by default for
the C project or the callback function will create an ESP problem.

Does that mean you can modify the C code? If so, changing the callback
signature to include the array size as a separate parameter would
help.

Otherwise if you want to avoid using unsafe in the funTest method (and
I don't quite see why since you're already using unsafe code in
SolvOptWrapper) I think you have to use copy the data from the array
and back with Marshal.Copy().


Mattias
 
B

BlueTrin

Good point, at first I didn't have access to the C code :)

I would like to use unsafe in funTest since the SolvOptWrapper is
supposed to be an interface to the DLL, the classes which will use this
interface will have to define their own funTest method Callback to call
SolvOptWrapper. So it would force the people who will use the interface
to define unsafe methods for each class which will use the wrapper

Thanks for the insight !
Anthony N.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top