Domanda

Ho un array frastagliato che devo passare al metodo esterno.

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

Il problema è che PTR è inutilizzato e viene rimosso a causa della compilazione. Dell'istruzione fissa in base anche a essa viene rimossa. Quindi l'array deve essere commosso da GC in questo modo che gli elementi di PTraray non diventano validi.

Qual è il modo migliore per passare array frastagliati come matrici monodimensionali di puntatori ai metodi nativi?

Aggiornare:

Ecco il codice C ++ per NativeMethod:

NativeClass::NativeMethod(const int* array)
È stato utile?

Soluzione

Il tuo problema è con il fatto che hai bisogno di un array per essere risolto poiché è quello che stai usando. Puoi appuntare l'array in modo che GC non lo raccolga:

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

AGGIORNARE

Come hai sottolineato correttamente, anche ogni array all'interno dell'array deve essere appuntato.

Altri suggerimenti

Sono stato in grado di passare un array C# Jagged a C ++ tramite un metodo Pinvoke esterno senza utilizzare il codice C# non sicuro come nel campione di codice seguente. Ma ho ancora le mie preoccupazioni riguardo al GC in modalità non debug che causano effetti collaterali indesiderati laterali. Ecco il codice di prova (che funziona in modalità debug):

[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 dovessi disturbare la parte di MainHandle, ricevo un'eccezione argomentazione "L'oggetto contiene dati non prigioni o non slittibili". Quindi è possibile appuntare il jaggedarray ed è davvero necessario? (Ricordo vagamente che GC in modalità di rilascio può ricordare la memoria già all'interno dei metodi se non viene più utilizzata.) Penso che, tuttavia, trasformare il jaggedArray in una variabile di campo di classe invece lo renderebbe al sicuro dal punto di vista GC.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top