0

I have legacy c library and exported it all in a c++ class library. So far, I have problem with passing arguments of type double** which simply is an out 2D array. Here is my c++ method signature:

public:  int  GetVariableValues(double **time_values) {
return LegacyGetVariableValues(time_values);}

And here is my c# client call:

double[][] a;
Legacy.GetVariableValues(a);

However it does not work and I get type errors. Anyone knows how to pass **(out) of course without using unsafe tag in C# client.

11
  • Arrays are not pointers in C and C++ both. Not sure about C#. Commented Aug 4, 2014 at 14:25
  • @haccks basically, all objects except structs are pointers in C#. it also does the marshalling and object pinning automatically when you call native code passing one as argument Commented Aug 4, 2014 at 14:30
  • @mersad00 Is the C++ library a C++/CLI library or just native code? Commented Aug 4, 2014 at 14:35
  • What the parameter of GetVariableValues would hold on return (logically)? a pointer to array of doubles? a two-dimensional array of doubles? But most importantly - how on earth can the runtime determine how much elements are in the array? Commented Aug 4, 2014 at 14:36
  • 1
    @TheodorosChatzigiannakis objects always stays on the heap so you can call they all "pointers" in a native code perspective, only type values(structs) that can live in the stack or inside another object. type values only reside in the heap when inside another object, when in arrays or when boxed. Commented Aug 4, 2014 at 14:55

1 Answer 1

2

You don't need the C++/CLI library is this case, pinning a multidimensional array is harder than just pinning a one-dimensional array as you need to pin the inner arrays manually. If you do it with C#, the compiler does it automatically for you.

With C#, you can do this:

[DllImport('legacylibrary.dll')]
public static extern int LegacyGetVariableValues(double[][] timeValues);

For further reading, check http://msdn.microsoft.com/en-us/library/fzhhdwae(v=vs.110).aspx

Edit:

As you need the C++/CLI layer, you need to do something like this:

ref class Legacy {
    public:
    int GetVariableValues(array<array<double> ^> ^values) {
        array<GCHandle> ^handles = gcnew array<GCHandle>(values->Length);
        double **valuesPtr = calloc(sizeof(double *), values->Length);
        int result;

        for (int i = 0; i < values->Length; i++) {
            handles[i] = GCHandle::Alloc(values[i]);
            valuesPtr[i] = (double *)GCHandle::ToIntPtr(handles[i]).GetPointer();
        }

        result = LegacyGetVariableValues(valuesPtr);

        for (int i = 0; i < values->Length; i++) {
            handles[i].Free();
        }

        return result;
    }
}

PS: Don't know if the syntax is completely correct as I don't write C++/CLI in a long time.

Sign up to request clarification or add additional context in comments.

5 Comments

Well I don't want to do that without CLI layer. Do you have any solution with CLI? I need to cast double** to array<double,2> probably...
at handles[i] = GCHandle::Alloc(values[i]); says one dimension specified for two dimensional. Plus to that, (double*)handles[i].AddrOfPinnedObject(); syas no suitable conversion Intptr to (double *). any clue?
Try using array<array<double>> and AddOfPinnedObject().GetPointer().
no it doesn't compile. I used this type instead array<array<double>^>^ but still I get this error: error C2039: 'AddOfPinnedObject' : is not a member of 'System::Runtime::InteropServices::GCHandle',
Oh, it's actually GCHandle::ToIntPtr(handles[i]).ToPointer()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.