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 :

Declarer un tableau de pointeur


Sujet :

C#

  1. #1
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut Declarer un tableau de pointeur
    Bonjour

    Je fais une operation un peu acrobatique qui est de recuperer un tableau de string donnés par une DLL sous la forme d"un char **

    C'est la DLL qui gere ses buffer et son allocation

    En csharp Je déclare le tableau de pointeurs de pointeur sous la forme d'un tableau de IntPtr

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
          IntPtr[] StrPtr = new IntPtr[8];
    Pratiquement ca marche bien (code ci dessous)
    Le truc qui m'embete c'est normalement je ne devrais pas donner de dimension a mon tableau puisque la DLL va simplement assigner a l'adresse de base de mon tableau l'adresse de son buffer et rendre un count.
    Comment puis-je declarer un array de IntPtr sans le dimensionner et sans facher le compilateur ?

    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
        [DllImport("bcta.Dll")]
        static public extern int bctaGetName(IntPtr hBcta, UInt32 nAttID, ref IntPtr [] StrPtr);
     
     
        static public int TestName()
        {
          char ch = (char)1;
          IntPtr hBcta = (IntPtr)0;
          UInt32 attrId = 0;
          UInt32 attrVal = 0;
          int status;
          IntPtr[] StrPtr = new IntPtr[8];
     
          Routing.bctaOpen(ref hBcta, Environ.RoutingDataPath, ch);
          attrId = 8967209;
          status = bctaGetName(hBcta, attrId, ref StrPtr);
     
          string val = Marshal.PtrToStringAnsi(StrPtr[0]);
     
          Routing.bctaClose(hBcta);
          return 0;
        }
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  2. #2
    Expert éminent
    Avatar de StormimOn
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2005
    Messages
    2 593
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2005
    Messages : 2 593
    Points : 7 660
    Points
    7 660
    Par défaut
    Je ne suis pas un ouf du P/Invoke, mais si tu déclares une string dans le prototype de la méthode native à appeler, le marshalling (si c'est bien le nom du bazar) s'occupe de faire la transition char** vers string non ?
    Pas de questions techniques par MP

  3. #3
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Oui Oui merci,

    Mais le problème n'est pas vraiment là

    Avec le code que j'ai montré ca marche bien pour le PREMIER string mais j'ai du coincer qq chose car s'il y en a plus, ca marche plus


    Voici la synthese minimale du code
    Dans le cas present, bctaGetName rends un count de 2 et a alloué un tableau de deux pointeurs
    mais a mon avis je me plante dans le passage de StrPrt car au retour cet array a une Lenght de 1, le premier string est ok mais je ne sais pas acceder le deuxieme (deuxieme pointeur)
    Je devrais pouvoir fair un truc du genre


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for (int i=0;i<count;i++)
    {
          string val = Marshal.PtrToStringAnsi(StrPtr[i]);
    }

    Mais pour le moment seul le [0] est ok

    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
        [DllImport("bcta.Dll")]
        static public extern int bctaGetName(IntPtr hBcta, UInt32 nAttID, ref IntPtr [] StrPtr);
     
     
        static public int TestName()
        {
          IntPtr hBcta = (IntPtr)0;
          UInt32 attrId = 0;
          int count;
          IntPtr[] StrPtr = new IntPtr[8];
     
          Routing.bctaOpen(ref hBcta);
          attrId = 8967209;
          count = bctaGetName(hBcta, attrId, ref StrPtr);
     
          string val = Marshal.PtrToStringAnsi(StrPtr[0]);
     
          Routing.bctaClose(hBcta);
          return 0;
        }
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  4. #4
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Quelle est la signature de la fonction native que tu désire appeler (car là j'ai du mal à voir ...)

  5. #5
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Salut

    Qu'appelle tu "signature" de la fonction native ?

    dans mon exemple j'ai passé le prototype facon Csharp

    Et voici la fonction native (eprouvée depuis longtemps)
    PSTR = (char *)
    PVOID = (void *);

    c'est le passage de *ppszBuffer ne marche qu'a moité !

    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
    BCAPI(int) bctaGetName (HBCTA hBcta, ULONG nElemID, PSTR *ppszBuffer)
    {
      int         l, 
                  iret;
      PBCTA_DATA  _this = (PBCTA_DATA)hBcta;
      PDATASET    pDs;
     
      for (l=0; l<NB_LANGUAGES; l++)
      {
        memset (_this->_ppnames[l], 0, SZ_NAME);
      }
     
      if ( NULL == (pDs = GetElemDataset (_this, nElemID)) )
        return 0;
     
      dsSetLevel (pDs, _this->_path, _this->_level);
     
      iret= dsGetName (pDs, nElemID, _this->_ppnames);
     
      *ppszBuffer = (PVOID)(_this->_ppnames);
      return iret;
    }
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  6. #6
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Wow ... je sais pas
    une solution pas trop compliquée serai de faire du code unsafe pour récupérer chaque élément du tableau ou de faire une autre fonction dans la dll pour récupérer chaque élément de ton array ...

    En même temps tu es sur que "PSTR *ppszBuffer" c'est la manière de renvoyer un array ? (je ne m'y connais pas beaucoup en C++, donc je demande ...)

  7. #7
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Salut Smiley

    C'est pas du C++ c'est du C

    Tu peux traduire PSTR *ppszBuffer
    par char **ppszBuffer; (PSTR) c'est juste un #define de char *

    Et effectivement passer un char **
    ou char *[] c'est la meme chose (comme dans n'importe quel main C)

    c'est la bonne maniere de passer un array de pointeur (de type char ici)

    Mon probleme c'est que si je passe a cette fonction un IntPtr array assigné avant l'appel il se fait scroutcher dans la fonction

    Au retour csharp n'y voit que du feu et mon Marshal.PtrToStringAnsi(StrPtr[0]); se debrouille tres bien avec l'element [0] qui contient bien ce que j'espere
    Le probleme c'est que comme son Array StrPtr a changé d'adresse il ne connait plus les autres elements

    Idealement je devrais pouvoir declarer un IntPtr [] de dimension inconnue qui sera effectivement assigné par la DLL

    Vois tu une solution ?
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  8. #8
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Smyley !!!

    Sinon j'ai finit par trouver ceci.
    Le gars y emploie une signature de la forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    [DllImport("NativeCDll.dll", CharSet=CharSet.Unicode)]
    extern static int TakesArrayOfStrings([In][Out][MarshalAsAttribute(UnmanagedType.LPArray, 
    ArraySubType=UnmanagedType.LPWStr)] string[] str, ref int size);
    Donc voilà, dit moi si ça t'aide ...

  9. #9
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Salut

    Non en y regardant de plus pres, c'est pour donner a sa dll un array de string
    Moi je dois recuperer un array de pointeurs que je dois ensuite lire comme des strings

    Le problème c'est surtout passer la reference adequate pour la DLL

    J'ai essayé IntPtr [] mais ca donne pas le bon resultat
    Peut etre IntPtr * mais la je sais pas bien comment déclarer du code unsafe et je me casse la gueule.

    Sonc je reste perdu !
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  10. #10
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Oui mais même, si tu garde la signature de l'exemple avec juste [Out] (donc, sans le [In]), ça plante quand même ?

  11. #11
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Salut,

    J'ai essayé en remplacant string [] par IntPtr []

    Mais vraissemblablement ce que je recoit dans l'elément 0 c'est l'adresse du tableau donc pas bon non plus !!


    Pour info voici l'exemple de l'appel en C

    tres simple !!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       char **xptr;
        count=bctaGetName (hBcta, id, &xptr);
    Je retrouve mes chaines dans

    xptr[0]
    xptr[1]
    ..
    xptr[count-1]
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  12. #12
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut Jongleries de Casting
    Salut, en utilisant ta suggestion, je suis parvenu au meme resultat que mon premier essai, mais regarde le casting dans la portion unsafe !! ca vaut un café !

    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
        static public extern int bctaGetName(IntPtr hBcta, UInt32 nAttID, [Out][MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] IntPtr[] str);    
     
        static public int TestName()
        {
          char ch = (char)1;
          IntPtr hBcta = (IntPtr)0;
          UInt32 attrId = 1039;
          UInt32 attrVal = 19;
          int status;
          IntPtr [] StrPtr=new IntPtr[25];
     
            Routing.bctaOpen(ref hBcta, Environ.RoutingDataPath, ch);
            attrId = 8967209;
            status = bctaGetName(hBcta, attrId, StrPtr);
     
            unsafe
            {
              IntPtr x=*(IntPtr *)StrPtr[0];
              string aa = Marshal.PtrToStringAnsi(x);
            }
          Routing.bctaClose(hBcta);
          return 0;
        }
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  13. #13
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    les autres IntPtr sont toujours invalides ?

  14. #14
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut
    Yep !

    Je chasse de tous les cotés mais j'y arrive pas

    A mon avis il y a un problème de fixation

    J'ai un buffer alloué endans ma DLL

    ptr1->zonememoire1
    ptr2->zonememoire2
    ptr3->zonememoire3

    ptr1-3 sont contigus et occuppent 12 bytes

    J'appelle la dll avec mon IntPtr (ppzBuffer)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BCAPI(int) bctaGetName (HBCTA hBcta, ULONG nElemID, PSTR *ppszBuffer)
    dans la dll je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      *ppszBuffer = (PVOID)(_this->_ppnames);
      return iret;
    Ce qui semble se passer c'est que le premier élément du tableau recoit la valeur de ptr1 mais qu'en fait je n'ai pas fait pointer le tableau sur la liste ptr1-3
    Donc je n'ai pas vraiment passé le pointeur sur le tableau

    Je pense que je devrais creuser du coté de UnSafe et faire des ** comme en C
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  15. #15
    Membre émérite
    Profil pro
    Mangeur de gauffre
    Inscrit en
    Octobre 2007
    Messages
    4 413
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Mangeur de gauffre

    Informations forums :
    Inscription : Octobre 2007
    Messages : 4 413
    Points : 2 498
    Points
    2 498
    Par défaut BINGO !!
    Voila !

    Je l'ai eu !!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        static public unsafe extern int bctaGetName(IntPtr hBcta, UInt32 nAttID, out IntPtr** StrPtr);
    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
        unsafe static public int TestName()
        {
          char ch = (char)1;
          IntPtr hBcta = (IntPtr)0;
          int count;
     
          IntPtr** StrPtr;
          Routing.bctaOpen(ref hBcta, Environ.RoutingDataPath, ch);
          attrId = 8967209;
          count = bctaGetName(hBcta, attrId,out StrPtr);
          string aa = Marshal.PtrToStringAnsi((IntPtr)StrPtr[0]);
          aa = Marshal.PtrToStringAnsi((IntPtr)StrPtr[1]);
     
          Routing.bctaClose(hBcta);
          return 0;
        }
    « Ils ne savaient pas que c'était impossible, alors ils l'ont fait ». (Twain)

  16. #16
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut

Discussions similaires

  1. Réponses: 9
    Dernier message: 23/12/2007, 19h51
  2. Tableau de pointeurs sur objets
    Par bassim dans le forum C++
    Réponses: 11
    Dernier message: 13/12/2005, 19h45
  3. [GCC] Tableau de pointeurs pour accès multiples en asm
    Par Flo. dans le forum x86 32-bits / 64-bits
    Réponses: 2
    Dernier message: 12/12/2005, 08h47
  4. tableau de pointeurs
    Par seal3 dans le forum C++
    Réponses: 7
    Dernier message: 01/11/2005, 20h51
  5. Tableau de pointeurs de fonctions
    Par Alp dans le forum C++
    Réponses: 7
    Dernier message: 29/10/2005, 13h19

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