Search code examples
c#c++arraysunmanagedmanaged

Working with 2D managed and unmanaged 2D arrays


I'm working on a project that requires me to pass 2D arrays between C# and Unmanaged C++.

I need to do this for 2D integer array sand 2D float arrays but right now I'm stuck on the 2D integer arrays.

I have a pattern for 1D integer arrays working just fine....

My demo C# code looks like this

// Test 2D integer Array
int[,] cs2DIntArray = new int[5,2];
cs2DIntArray[0, 0] = 0;
cs2DIntArray[0, 1] = 1;
cs2DIntArray[1, 0] = 10;
cs2DIntArray[1, 1] = 11;
cs2DIntArray[2, 0] = 20;
cs2DIntArray[2, 1] = 21;
cs2DIntArray[3, 0] = 30;
cs2DIntArray[3, 1] = 31;
cs2DIntArray[4, 0] = 40;
cs2DIntArray[4, 1] = 41;


int my2DArrayIntReturn = tess.test2DIntArray(cs2DIntArray, 5, 2); 

"tess" is a managed C++ Wrapper class and implements the test2DIntArray method like this,

int test2DIntArray(array<int, 2>^ my2DIntArray, int rows, int columns){

    using System::Runtime::InteropServices::GCHandle;
    using System::Runtime::InteropServices::GCHandleType;

    GCHandle my2DIntArrayGCHandle = GCHandle::Alloc(my2DIntArray,GCHandleType::Pinned);
    IntPtr my2DIntArrayPtr = my2DIntArrayGCHandle.AddrOfPinnedObject();

    my2DIntArray[0, 0] = 0;
    my2DIntArray[0, 1] = 11;
    my2DIntArray[1, 0] = 110;
    my2DIntArray[1, 1] = 111;
    my2DIntArray[2, 0] = 120;
    my2DIntArray[2, 1] = 121;
    my2DIntArray[3, 0] = 130;
    my2DIntArray[3, 1] = 131;
    my2DIntArray[4, 0] = 140;
    my2DIntArray[4, 1] = 141;

    return pu->uTest2DIntArray((int*)my2DIntArrayPtr.ToPointer(),rows,columns);

};

pu is the unmanaged class and implements uTest2DIntArray like this

int UnmanagedModel::uTest2DIntArray(int* my2DIntArray, int arrayRows, int arrayColumns)
{

            my2DIntArray[0,0] = 20;
            my2DIntArray[0,1] = 21;
            my2DIntArray[1,0] = 210;
            my2DIntArray[1,1] = 211;
            my2DIntArray[2,0] = 220;
            my2DIntArray[2,1] = 221;
            my2DIntArray[3,0] = 230;
            my2DIntArray[3,1] = 231;
            my2DIntArray[4,0] = 240;
            my2DIntArray[4,1] = 241;




        return my2DIntArray[1,1];


}

This compiles and runs without errors or warnings BUT when the code returns to C# only the first two values [0,0] and [0,1] reflect the changes made to the values in the unmanaged code as shown below. All of the other values reflect the changes made in the managed C++ method.

cs2DIntArray    {int[5, 2]} int[,]
        [0, 0]  240 int
        [0, 1]  241 int
        [1, 0]  110 int
        [1, 1]  111 int
        [2, 0]  120 int
        [2, 1]  121 int
        [3, 0]  130 int
        [3, 1]  131 int
        [4, 0]  140 int
        [4, 1]  141 int

Can anyone see/explain what I'm doing wrong and what needs to be done to correct this code? I haven't coded in a while and I did spend quite a while looking for solutions on Google but can't quite get this work as desired.

Any guidance will be gratefully received.

Doug

Further information

  1. If I change the indexing in the unmanaged code to use a single index (from 0 to 9) instead of a 2D index (0,0 to 4,1) then all of the values are updated correctly
  2. In the debugger, when I look at the address of each array value[x,y] - they all show exactly the same address
  3. Using 2D array indexing it seems like the first index is being completely ignored - the only the second index is being used and since this varies from 0 to 1 the code is simply overwriting the first two array values.
  4. Which tells me I do have access to the correct memory for the array inside my unmanaged code, but I can't use 2D indexing to get to it. Which is a pain, and has to fixable.

Solution

  • c++ doesn't have 2-dimensional arrays. The comma-operator turns 4,0 into 0, so my2DIntArray[4,0] is equivalent to my2DIntArray[0].

    Since my2DIntArray is a pointer to a one-dimensional array, you have to simulate 2 dimensions by manually calculating the index like this: my2DIntArray[line * columns + column]