IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Passer Double[][][][][][] de C# a C++


Sujet :

C#

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut Passer Double[][][][][][] de C# a C++
    Bonjour
    Donc voici mon problème je travaille actuellement sur un programme C# utilisant une dll C++. La dll aurait besoin d'un double[][][][][][] afin de fonctionner mais je ne sais pas comment lui faire passer, j'ai essayer avec un marshaller personnalisé mais je n'ai pas réussi a le faire fonctionner: cf le code ci dessous ou d'aplatir le tableau en un double[] mais cette solution est trop lourde pour le programme. Avez vous des solutions?
    Merci d'avance
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    public class JaggedArrayMarshaler : ICustomMarshaler
        {
            static ICustomMarshaler GetInstance(string cookie)
            {
                return new JaggedArrayMarshaler();
            }
            GCHandle[] handles;
            GCHandle[] handles2;
            GCHandle[] handles3;
            GCHandle[] handles4;
            GCHandle[] handles5;
            GCHandle buffer;
            Array[] array;
            Array[] array2;
            Array[] array3;
            Array[] array4;
            Array[] array5;
            public void CleanUpManagedData(object ManagedObj)
            {
            }
            public void CleanUpNativeData(IntPtr pNativeData)
            {
                buffer.Free();
                foreach (GCHandle handle in handles)
                {
                    handle.Free();
                }
                foreach (GCHandle handle in handles2)
                {
                    handle.Free();
                }
                foreach (GCHandle handle in handles3)
                {
                    handle.Free();
                }
                foreach (GCHandle handle in handles4)
                {
                    handle.Free();
                }
                foreach (GCHandle handle in handles5)
                {
                    handle.Free();
                }
            }
            public int GetNativeDataSize()
            {
                return IntPtr.Size;
            }
     
            public IntPtr MarshalManagedToNative(object ManagedObj)
            {
                array = (Array[])ManagedObj;
     
                handles = new GCHandle[array.Length];
                for (int i = 0; i < array.Length; i++)
                {
                    array2 = (Array[])array[i];
                    handles2 = new GCHandle[array2.Length];
                    for (int j = 0; j < array2.Length; j++)
                    {
                        array3 = (Array[])array2[j];
                        handles3 = new GCHandle[array3.Length];
                        for (int k = 0; k < array3.Length; k++)
                        {
                            array4 = (Array[])array3[k];
                            handles4 = new GCHandle[array4.Length];
                            for (int l = 0; l < array4.Length; l++)
                            {
                                array5 = (Array[])array4[l];
                                handles5 = new GCHandle[array5.Length];
                                for (int m = 0; m < array5.Length; m++)
                                {
                                    handles5[m] = GCHandle.Alloc(array5[m], GCHandleType.Pinned);
     
                                }
                                IntPtr[] pointers5 = new IntPtr[handles5.Length];
                                for (int m = 0; m < handles5.Length; m++)
                                {
                                    pointers5[m] = handles5[m].AddrOfPinnedObject();
                                }
                                handles4[l] = GCHandle.Alloc(pointers5, GCHandleType.Pinned);
                            }
                            IntPtr[] pointers4 = new IntPtr[handles4.Length];
                            for (int l = 0; l < handles4.Length; l++)
                            {
                                pointers4[l] = handles4[l].AddrOfPinnedObject();
                            }
                            handles3[k] = GCHandle.Alloc(pointers4, GCHandleType.Pinned);
                        }
                        IntPtr[] pointers3 = new IntPtr[handles3.Length];
                        for (int k = 0; k < handles3.Length; k++)
                        {
                            pointers3[k] = handles3[k].AddrOfPinnedObject();
                        }
                        handles2[j] = GCHandle.Alloc(pointers3, GCHandleType.Pinned);
                    }
                    IntPtr[] pointers2 = new IntPtr[handles2.Length];
                    for (int j = 0; j < handles2.Length; j++)
                    {
                        pointers2[j] = handles2[j].AddrOfPinnedObject();
                    }
                    handles[i] = GCHandle.Alloc(pointers2, GCHandleType.Pinned);
                }
                IntPtr[] pointers = new IntPtr[handles.Length];
                for (int i = 0; i < handles.Length; i++)
                {
                    pointers[i] = handles[i].AddrOfPinnedObject();
                }
                buffer = GCHandle.Alloc(pointers, GCHandleType.Pinned);
                return buffer.AddrOfPinnedObject();
            }
            public object MarshalNativeToManaged(IntPtr pNativeData)
            {
                return array;
            }
        }

  2. #2
    Expert confirmé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 065
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 065
    Points : 4 229
    Points
    4 229
    Par défaut
    Bonjour,
    je crois que ce que tu cherches est les tableaux multidimensionnels en c# http://msdn.microsoft.com/fr-fr/library/2yd9wwz4.aspx après je suis pas un connaisseur en c++ mais je pense que c'est ça.

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    Non malheureusement, cette variable double[][][][][][] existe déjà dans le programme que je modifie, je ne peux donc pas le modifier en tableaux multi-dimensions, réecrire cette variable dans un double[,,,,,] reviendrait à la même chose que de l'aplatir en une dimension. c'est pour ça que j'essaie de le faire passer comme sa en renvoyant un IntPtr grace au Marshaller.

  4. #4
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Bonjour.

    Je n'ai pas pris le temps de le tester mais ça doit fonctionner. Note que la liste de handles peut, elle, être aplatie. En revanche les tableaux de IntPtr sont correctement imbriqués.

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    IntPtr Marshal(Array sourceArray)
    {
        if (sourceArray is double[]) return Pin(sourceArray);
     
        int targetIndex = 0;
        var targetArray = new IntPtr[sourceArray.Length];
     
        foreach (Array sourceChild in sourceArray)
        {
            targetArray[targetIndex++] = Marshal(sourceChild);
        }
     
        return Pin(targetArray);
    }
     
    IntPtr Pin(Array array)
    {
        var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
        Handles.Add(handle);
        return handle.AddrOfPinnedObject();
    }
     
    readonly List<GCHandle> Handles = new List<GCHandle>();

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    Merci de ta réponse mais ne connaissant pas tellement les Intptr , je ne sais pas si c'est pas moi qui ne sais pas utilisé correctement ce code ou si il ne marche pas. Etant donné que je passe un tableau de double [][][][][][], suis-je censé prévoir en entrée de la dll un pointeur double* ou un pointeur de pointeur...
    Passé le intPtr que la fonction IntPtr Marshal(Array sourceArray) a la fonction de ma dll est il correct (elle prend pour l'instant un double*) ?

  6. #6
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Je recommande d'utiliser IntPtr. IntPtr représente n'importe quel pointeur et peut toujours être substitué à ces derniers dans les signatures d'importation (du moins pour les paramètres d'entrée). A vrai dire je déconseille d'importer des fonctions en déclarant des pointeurs, à moins de vouloir expressément utiliser ces fonctions dans des blocs de code unsafe (dans ce cas la bonne signature serait double******).

    Cela dit on peut très facilement passer d'un pointeur à un IntPtr via les opérateurs de conversion puisque ceux-ci désignent la même chose. IntPtr n'est qu'une facilité donnée pour faire circuler des adresses dans du code managé

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    double* ptr = (double*)(void*)IntPtr.Zero;
    IntPtr intPtr = (IntPtr)(void*)ptr;

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    merci encore, donc dans la signature de ma fonction d'entrée en C# il faut que je mette un IntPtr, ce qui va représenter mon pointeur de tableau si j'ai bien compris, et dans ma dll C++, c'est un double****** qui doit l’accueillir pour s'en servir correctement? Le tableau est passé avec les donné du C# ou je dois encore faire une opération?

    Pour illustrer un peu mes propos:
    pour l'instant voila un peu le genre de fonction dans le C#:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [DllImport("Dll .dll", EntryPoint = "_Calculation", CallingConvention = CallingConvention.Cdecl)]
            private static extern int _Calculation([In, Out] Intptr MonTableau);
    et ma fonction en C++:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    extern "C" {
    	MON_API int _Calculation(double****** MonTableau);
    }
    Dans ce cas le tableau se lira comme un tableau a six dimensions?

  8. #8
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    C'est bien ça, si ce n'est que MonTableau est un paramètre d'entrée seulement, pas besoin d'attribut Out.

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    Hum, mais les modifications faites par la dll C++ impacteront aussi le tableau dans le C#?

  10. #10
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Citation Envoyé par miyoku Voir le message
    Hum, mais les modifications faites par la dll C++ impacteront aussi le tableau dans le C#?
    IntPtr est un type valeur et le marshaller n'en sait pas davantage. L'attribut out n'a aucun sens pour un type valeur si tu ne passes pas ce type via "ref" ou "out". D'ailleurs tu aurais sans doute eu une erreur à l'exécution.

    Les choses sont différentes quand tu passes directement un tableau : selon que tu appliques ou non l'attribut out et selon le type de l'élément du tableau, le marshaller pourrait choisir de l'épingler ("pin", comme nous l'avons fait) ou de le dupliquer.

    (note que j'ai de très légers doutes sur ces sujets).


    Tout ça étant dit, revenons à ton cas précis : tous les tableaux ont été épinglés, donc ton code managé et ton code natif vont partager les mêmes espaces mémoires. Tout modification réalisée en C sera automatiquement visible en C#.

    Cela dit il peut y avoir un problème si ton code natif remplace certains sous-tableaux: dans un tel cas tes tableaux contiendront des pointeurs vers des zones qui n'ont pas de correspondance en C#. Si c'est le cas il faut que tu mettes en place un dictionnaire de (IntPtr, Array) et qu'au retour tu visites tes tableaux, que tu vérifies chaque IntPtr et que tu crées éventuellement de nouveaux tableaux managés.

  11. #11
    Membre à l'essai
    Profil pro
    Inscrit en
    Octobre 2011
    Messages
    25
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 25
    Points : 15
    Points
    15
    Par défaut
    Merci de tes réponses, ça marche bien effectivement

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Passer un Double en paramètre dans un setText()
    Par jesuislibre15 dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 13/04/2012, 23h12
  2. Réponses: 1
    Dernier message: 25/01/2009, 01h10
  3. Réponses: 17
    Dernier message: 26/02/2007, 17h45
  4. Passer de DOUBLE PRECISION en NUMERIC
    Par alex4 dans le forum SQL
    Réponses: 5
    Dernier message: 18/10/2004, 16h24
  5. Passer en mode 800*600
    Par flavien tetart dans le forum Assembleur
    Réponses: 8
    Dernier message: 30/05/2002, 23h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo