Pergunta

Eu tenho uma matriz acumulada que preciso passar para o método externo.

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

O problema é que a PTR não é utilizada e é removida devido à compilação. Do que a declaração fixa de acordo com ela também é removida. Portanto, a matriz será movida pela GC dessa maneira que os elementos pTRArray se tornam inválidos.

Qual é a melhor maneira de passar as matrizes irregulares como matrizes unidimensionais de ponteiros para métodos nativos?

Atualizar:

Aqui está o código C ++ para nativemethod:

NativeClass::NativeMethod(const int* array)
Foi útil?

Solução

Seu problema é com o fato de que você precisa ser corrigido, pois é essa que você está usando. Você pode fixar a matriz para que o GC não o colete:

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

ATUALIZAR

Como você apontou corretamente, cada matriz dentro da matriz também precisa fixar.

Outras dicas

Consegui passar uma matriz C# Jagged para C ++ por meio de um método de pinvoke externo sem usar o código C# inseguro, como no exemplo de código abaixo. Mas ainda tenho minhas preocupações com relação ao GC no modo não dedimelhado, causando um efeito colateral indesejável do lado. Aqui está o código de teste (que funciona no modo de depuração):

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

Se eu deveria descomentar a parte da mão-de-obra, recebo uma exceção de argumento "o objeto contém dados não primitivos ou não tomáveis". Então é possível fixar o JaggedArray e é realmente necessário? (Lembro -me vagamente que o GC no modo de liberação pode lembrar a memória já dentro dos métodos se não for mais usada.) Acho que, em vez disso, transformar o JaggedArray em uma variável de campo de classe o tornaria protegido da perspectiva do GC.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top