Fixed statement with jagged array

女生的网名这么多〃 提交于 2019-12-04 04:41:09

问题


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)

回答1:


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.




回答2:


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.



来源:https://stackoverflow.com/questions/4033054/fixed-statement-with-jagged-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!