3

I have jagged array which I need to pass to external method.

[DllImport(...)]
private static extern int NativeMethod(IntPtr[] ptrArray);

...

fixed (ulong* ptr = array[0])
{
    for (int i = 0; i < array.Length; i++)
    {
        fixed (ulong* p = &array[i][0])
        {
            ptrArray[i] = new IntPtr(p);
        }
    }

    NativeMethod(ptrArray);
}

The problem is that ptr is unused and is removed due compilation. Than fixed statement according to it is removed too. So array be moved by GC in that way that ptrArray elements become invalid.

What is the best way for passing jagged arrays as single-dimensional arrays of pointers to native methods?

Update:

Here is the C++ code for NativeMethod:

NativeClass::NativeMethod(const int* array)
4
  • what is your native method looks like what is the real parameter it takes? Commented Oct 27, 2010 at 12:26
  • updated - added C++ code Commented Oct 27, 2010 at 12:31
  • The C++ declaration is not for a jagged array, that would require an int** argument. Hard to help you. Commented Oct 27, 2010 at 13:28
  • Of course its not. I need some conversion. Commented Oct 27, 2010 at 13:51

2 Answers 2

3

Your problem is with the fact that you need array to be fixed since that is the one you are using. You can pin the array so that GC does not collect it:

 GCHandle h = GCHandle.Alloc(array, GCHandleType.Pinned);

UPDATE

As you have correctly pointed out, each array inside the array needs pinning as well.

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

4 Comments

You are right, I was looking for Pinned but could not find it.
Now you just need to pass the h.AddrOfPinnedObject() to the native method.
Thank you! Your idea is very helpful. The only thing I wand to add is that your code will produce exception, because array is array of arrays but not of basic types. You should pin (and then .Free()!) every array[i] but not array itself.
You are right, I will add this note for the sake of completeness
0

I have been able to pass a C# jagged array to C++ via an external Pinvoke method without using unsafe C# code as in the code sample below. But I still have my concerns regarding the GC in non-debug mode causing side undesirable side-effect. Here's the piece of test code (that works in debug mode):

[Test, Ignore]
public void Test_JaggedArrayPInvoke()
{
    var jaggedArray = new int[3][];
    jaggedArray[0] = new int[1] { 9 };
    jaggedArray[1] = new int[4] { 1, 2, 3, 8 };
    jaggedArray[2] = new int[2] { 1, 2 };

    //GCHandle mainHandle = GCHandle.Alloc(jaggedArray, GCHandleType.Pinned);   //This does not work

    var pinnedHandles = new GCHandle[3];                    
    var jaggedArrayPtrs = new IntPtr[3];
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i] = GCHandle.Alloc(jaggedArray[i], GCHandleType.Pinned);
        jaggedArrayPtrs[i] = pinnedHandles[i].AddrOfPinnedObject();
    }

    var result = JaggedArrayPInvoke_TEST(jaggedArrayPtrs);

    Console.WriteLine(result);  //returns 8 as it should.

    //mainHandle.Free();
    for (int i = 0; i < 3; i++)
    {
        pinnedHandles[i].Free();
    }
}

//The C++ test method:

extern "C" __declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray);
__declspec(dllexport) int __stdcall JaggedArrayPInvoke_TEST(int** jaggedArray) 
{ 
   return jaggedArray[1][3];
}

If I was to uncomment the mainHandle part, I get an argument exception "Object contains non-primitive or non-blittable data". So is it possible to pin the jaggedArray and is it really needed? (I vaguely recall that GC in release mode may recollect memory already within methods if it is not used any longer.) I think though that turning the jaggedArray into a class field variable instead would make it safe from a GC perspective.

Comments

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.