Question

I have a library of c functions I am trying to access from c#. I have tried the PInvoke route but there were structs containing variable length arrays so this approach wasn't working and I was advised to try c++/cli. After looking into it (and asking a lot more questions) I have created a wrapper class for one of my c functions. The input to the c function is a struct that contains two double arrays and the length of one of the arrays (the other being fixed size), as well as a double. I was able to create a little test app (clr console) for my wrapper so I know that its calling the c code and doing what its supposed to, I now just need to figure out how to call it from c#. As its now a managed dll I have added it to my references and I can put it in the code but the method signature has transformed the arrays into pointers whch I cant do in c#. I tried just apssing the arrays, using ref, cant figure out how to make this work.

c++ signature:

static void test_wrapper(double prefix[], double arr[], int arrayLength, double value);

so when I call this in c# its:

Test_Wrapper_Class.test_wrapper(???, ???, array.Length, 2.2);

however the ??? is showing its expecting a double* and I'm not quite sure what to put in for that.

for bonus points I would like to return a double array but not sure about which way to do it. Options for this would be:

  1. just reuse arr as the returned array will be same size
  2. add another double[] in input and fill that one
  3. return a double[]
Was it helpful?

Solution

It is not terribly clear why are making it difficult for the C# to use your function. Keep in mind that the C++/CLI language allows you to either use managed or unmanaged arrays. You are using an unmanaged array as an argument now, so giving the C# code a hard time to call the function. It isn't impossible with unsafe code:

    static unsafe void Main(string[] args) {      // NOTE unsafe keyword
        var arg1 = new double[] { 1, 2, 3 };
        var arg2 = new double[] { 4, 5, 6 };
        fixed (double* arg1ptr = arg1)
        fixed (double* arg2ptr = arg2) {
            Test_Wrapper_Class.test_wrapper(arg1ptr, arg2ptr, arg1.Length, 42.0);
        }
    }

Note how the C# code needs to use the unsafe keyword. And how it is truly unsafe, you didn't include an argument that says how long the 2nd array is so the native code can easily scribble into the GC heap and corrupt it.

But that isn't necessary when you declare the arguments as managed arrays:

static void test_wrapper(array<double>^ prefix, array<double>^ arr, double value);

Safe and easy to call from C#. Note how you no longer need to pass the array length argument, you already know it from prefix->Length. If necessary at all, you can use pin_ptr<> in your C++/CLI code to get a double* that native code can use. Be careful, it is only pinned temporarily.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top