Reputation: 2557
I have a C library with this function that returns 4 output parameters:
void __declspec(dllexport) demofun(double a[], double b[], double* output1, double* output2, double res[], double* output3)
And I wrote a C# wrapper to call the function:
namespace cwrapper
{
public sealed class CWRAPPER
{
private CWRAPPER() {}
public static void demofun(double[] a, double[] b, double output1,
double output2, double[] res, double output3)
{ // INPUTS: double[] a, double[] b
// OUTPUTS: double[] res, double output1, double output2
// Arrays a, b and res have the same length
// Debug.Assert(a.length == b.length)
int length = a.Length;
CWRAPPERNative.demofun(a, b, length, ref output1, ref output2,
res, ref output3);
}
}
[SuppressUnmanagedCodeSecurity]
internal sealed class CWRAPPERNative
{
private CWRAPPERNative() {}
[DllImport("my_cwrapper.dll", CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, SetLastError=false)]
internal static extern void demofun([In] double[] a, [In] double[] b,
int length, ref double output1, ref double output2,
[Out] double[] res, ref double output3);
}
}
Everything works fine when I call the CWRAPPERNative.demofun
method. However, when I call the CWRAPPER.demofun
method, only the double[] res
is passed through correctly. The output parameters output1
, output2
and output3
are unchanged after the call.
// ...
// Initializing arrays A and B above here
double[] res = new double[A.Length];
double output1 = 0, output2 = 0, output3 = 0;
// Works partially: output1 to 3 unchanged
CWRAPPER.demofun(A, B, output1, output2, res, output3);
// Works correctly: all outputs are changed
CWRAPPERNative.demofun(A, B, A.Length, ref output1, ref output2, res, ref output3);
I'm guessing that I'm marshalling the pointer arguments wrongly, but I cannot figure out the fix. Anyone knows a solution? Thanks!
Upvotes: 1
Views: 4294
Reputation: 1135
All double
parameters to CWRAPPER.demofun
are non-volatile, i.e. the values cannot be changed by the function. To fix this you need a change like this:
public static void demofun(double[] a, double[] b,
out double output1, out double output2, double[] res, out double output3)
There's another problem though. The C function's 5th parameter double res[]
is an input parameter but your P/Invoke declaration has [Out] double[] res
(an output parameter). I'd rewrite the P/Invoke declaration like this:
[DllImport("my_cwrapper.dll", CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, SetLastError=false)]
static extern void demofun([In] double[] a, [In] double[] b, [In] int length,
[Out] double output1, [Out] double output2, [In] double[] res, [Out] double output3);
Example method implementation with out
parameter; OutOutTester
shows that a method with out
parameters need not assign their values directly:
public static void OutTester(out int a)
{
a = 1;
}
public static void OutOutTester(out int a, out int b)
{
OutTester(out a);
b = 1;
}
Upvotes: 0
Reputation: 7935
You are forgetting to pass the values by reference inside of demofun:
public static void demofun(double[] a, double[] b, ref double output1,
ref double output2, double[] res, ref double output3)
The values is changing inside of the method, but not being modified to the original caller.
Upvotes: 1