Исправлено утверждение с неровным массивом - PullRequest
3 голосов
/ 27 октября 2010

У меня есть неровный массив, который мне нужно передать внешнему методу.

[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);
}

Проблема в том, что ptr не используется и удаляется из-за компиляции.Также устраняется фиксированное утверждение в соответствии с ним.Поэтому GC перемещает массив таким образом, что элементы ptrArray становятся недействительными.

Каков наилучший способ передачи зубчатых массивов как одномерных массивов указателей на нативные методы?

Обновление:

Вот код C ++ для NativeMethod:

NativeClass::NativeMethod(const int* array)

Ответы [ 2 ]

3 голосов
/ 27 октября 2010

Ваша проблема в том, что вам нужно исправить массив, так как это тот, который вы используете. Вы можете закрепить массив так, чтобы GC не собирал его:

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

UPDATE

Как вы правильно указали, каждый массив внутри массива также нуждается в закреплении.

0 голосов
/ 14 октября 2011

Мне удалось передать неровный массив C # в C ++ с помощью внешнего метода Pinvoke без использования небезопасного кода C #, как в примере кода ниже.Но у меня все еще есть опасения относительно GC в режиме без отладки, вызывающего нежелательный побочный эффект.Вот фрагмент тестового кода (который работает в режиме отладки):

[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];
}

Если я должен раскомментировать часть mainHandle, я получу исключение аргумента «Объект содержит не примитивные или неблизкие данные». Так можно ли закрепить jaggedArray и действительно ли это нужно? (Я смутно напоминаю, что GC в режиме выпуска может вспомнить память уже в методах, если она больше не используется.) Хотя я думаю, что поворотВместо этого jaggedArray в переменную поля класса сделает его безопасным с точки зрения GC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...