Question

Je déchiquetée que je tableau besoin de passer à la méthode externe.

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

Le problème est que ptr est utilisé et est retiré compilation due. Que la déclaration fixe selon elle est supprimée aussi. Donc, être déplacé par tableau GC de cette façon que les éléments ptrArray deviennent invalides.

Quelle est la meilleure façon de passer des tableaux déchiquetés sous forme de tableaux unidimensionnelles de pointeurs vers des méthodes natives?

Mise à jour:

Voici le code C ++ pour NativeMethod:

NativeClass::NativeMethod(const int* array)
Était-ce utile?

La solution

Votre problème est le fait que vous avez besoin tableau à être fixé puisque c'est celui que vous utilisez. Vous pouvez épingler le tableau de sorte que GC ne les collectons:

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

UPDATE

Comme vous l'avez souligné à juste titre, chaque tableau à l'intérieur des besoins de tableau épinglant ainsi.

Autres conseils

nous avons été en mesure de transmettre un C # tableau en escalier à C ++ via une méthode Pinvoke externe sans utiliser de code non sécurisé C # comme dans l'exemple de code ci-dessous. Mais j'ai encore mes préoccupations concernant le GC en mode non-debug entraînant côté effet secondaire indésirable. Voici le morceau de code de test (qui fonctionne en mode débogage):

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

Si je devais décommenter la partie mainHandle, je reçois une exception d'argument « objet contient des données non-primitive ou non blittable ». Est-il possible d'épingler la jaggedArray et est-il vraiment nécessaire? (je me rappelle vaguement que GC en mode de libération peut se rappeler la mémoire déjà dans les méthodes si elle n'est pas utilisé plus longtemps.) Je pense cependant que tournant la jaggedArray dans une variable de champ de classe serait plutôt le rendre sûr du point de vue de la GC.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top