1. #1
    Membre éprouvé

    Profil pro
    Inscrit en
    août 2005
    Messages
    621
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 621
    Points : 1 153
    Points
    1 153

    Par défaut [C#][09/01/18 ] Comment accéder à une structure à partir d’un pointeur (IntPtr) sur cette structure

    Bonjour,
    Je m’initie à C#. A titre d’exercice, je développe un programme qui commande un relais via USB. Pour cela je dispose d'une DLL écrite en C++ (disponible sur Git https://github.com/pavel-a/usb-relay-hid) et d'un Wrapper exemple pour utiliser les fonctions de la DLL en c#.

    La première étape consiste à détecter la (les) cartes relais connectées compatibles à l’aide d’une fonction de la DLL . Cette fonction renvoie une structure qui contient le serial de la carte (pour y accéder avec une autre fonction de la DLL), le nombre de relais et un pointeur IntPtr sur la structure de la carte suivante (s’il y en une deuxième ou qui est null s’il n’y a pas d’autre - c'est ce que j'ai compris).
    La déclaration de cette fonction dans c# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [DllImport("usb_relay_device.dll", EntryPoint = "usb_relay_device_enumerate",
    CallingConvention = CallingConvention.Cdecl)]
    //[return: MarshalAs(UnmanagedType.LPStruct)]
    private static extern IntPtr Pusb_relay_device_enumerate();
    public static usb_relay_device_info usb_relay_device_enumerate()
    {
    IntPtr x = RelayDeviceWrapper.Pusb_relay_device_enumerate();
    usb_relay_device_info a = (usb_relay_device_info)Marshal.PtrToStructure(x, typeof(usb_relay_device_info));
    return a;
    }
    La declaration de la structure dans C# :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public struct usb_relay_device_info
    {
    [MarshalAs(UnmanagedType.LPStr)]
    public string serial_number;
    public IntPtr device_path { get; set; }
    public usb_relay_device_type type { get; set; }
    public IntPtr next { get; set; }
    }
    Pour récupérer la structure :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public usb_relay_device_info mydeviceinfo;
     
      private void ButtonFindDevice_Click(object sender, EventArgs e)
            {
                {
                    mydeviceinfo = RelayDeviceWrapper.usb_relay_device_enumerate();
    …
    Je gère sans problème la première carte (excitation et désexcitation du relais)
    Par contre lorsqu’il y a une deuxième carte sur un autre port USB je n’arrive pas à récupérer sa structure à partir de « mydeviceinfo.next » (qui est un IntpTr sur cette structure).

    Nota : La DLL détecte bien si une deuxième carte est connectée
    Je teste avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
                    IntPtr myIntptr = mydeviceinfo.next;
                    if (myIntptr == IntPtr.Zero)
                    {
                        MessageBox.Show("Pas d'autre carte relais");
                    }
                    else
                    {
                        MessageBox.Show("Attention d'autre(s) cartes relais sont connectées");
    Pourriez-vous me dire comment accéder à la structure de la deuxième carte.

  2. #2
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Charente Maritime (Poitou Charente)

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

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 545
    Points : 5 281
    Points
    5 281
    Billets dans le blog
    5

    Par défaut

    Bonjour,

    Je pense que Marshal.PtrToStructure est peut être ce que tu cherches.

    Exemple d'utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    MaStruct s = (MaStruct)Marshal.PtrToStructure(monIntPtr, typeof(MaStruct));
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  3. #3
    Membre éprouvé

    Profil pro
    Inscrit en
    août 2005
    Messages
    621
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 621
    Points : 1 153
    Points
    1 153

    Par défaut

    Bonjour,

    Merci beaucoup Francois DORIN : ça marche, c’est effectivement ce que je cherchais mais que je n’aurais pas trouvé (Marshal.PtrToStructure ça sera en deuxième année ).

    Mais mauvaise surprise, qui n’a rien à voir avec C#, toutes les cartes ont le même serial !
    Je l’ai constaté avec mon programme, mais aussi avec le programme en C++ fourni par l’auteur de la DLL. Les deux cartes connectées à tour de rôle sont détectées et fonctionnent avec le même sérial. Donc une seule à la fois utilisable …

    A priori il n’y a pas moyen de changer le serial d’une carte (pas de switches sur la carte, ni de bornes à relier pour coder, et sans doute pas de possibilité de le programmer par soft (aucune doc) l’unique et microscopique circuit intégré de la carte (qui ne porte d’ailleurs aucun marquage). Je vais quand même chercher.

    Bon, c’est acheté en chine, 4 euros la carte transport compris !

    Le code qui permet d'accéder à la structure de la deuxième carte et d° pour les suivantes (il y a pas mal de demandes sur les forums) :
    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
     
    {
                    mydeviceinfo = RelayDeviceWrapper.usb_relay_device_enumerate();
                    textBoxDevices.Text = mydeviceinfo.serial_number.ToString();
                    comboBoxDevices.Items.Add(mydeviceinfo.serial_number.ToString());
                    comboBoxDevices.SelectedIndex = 0;
     
                    IntPtr myIntptr = mydeviceinfo.next;
                    if (myIntptr == IntPtr.Zero)
                    {
                        MessageBox.Show("une seule carte connectée");
                    }
                    else
                    {
                        // Une autre carte est connectée, on récupère son serial 
                        usb_relay_device_info mydeviceinfo2 = (usb_relay_device_info)Marshal.PtrToStructure(mydeviceinfo.next, typeof(usb_relay_device_info));
                        MessageBox.Show("Une autre carte est connectée dont le sérial est = " + mydeviceinfo2.serial_number.ToString());
                        comboBoxDevices.Items.Add(mydeviceinfo2.serial_number.ToString());
                    }
    Merci encore

  4. #4
    Rédacteur/Modérateur

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    juillet 2016
    Messages
    1 545
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Charente Maritime (Poitou Charente)

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

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 545
    Points : 5 281
    Points
    5 281
    Billets dans le blog
    5

    Par défaut

    Si les relais sont connectés sur des ports différents, il est peut être possible d'en utiliser plusieurs à la fois. Il faut alors utiliser le port pour différencier les cartes, et non les numéros de série. Mais je ne sais pas si l'API de cette bibliothèque permet d'avoir cette information, mais je jetterai un oeil sur l'attribut device_path qui me semble être un bon candidat pour cela.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  5. #5
    Membre éprouvé

    Profil pro
    Inscrit en
    août 2005
    Messages
    621
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 621
    Points : 1 153
    Points
    1 153

    Par défaut

    Bonsoir,
    Pour information
    Je ne sais pas si ça présente un intérêt, mais je récupère pour device_path.ToString() pour les deux cartes 258050228.
    A chaque fois que je débranche et rebranche l’USB de la(des) carte(s) il y a des valeurs différentes comme 268339380, 259360948

    Mais c'est à prendre avec des pincettes : pour le moment il y a quelque chose que je ne fais pas encore avant de récupérer la structure de la (des) carte(s) c’est appeler la fonction :
    /** Free an enumeration Linked List */
    void USBRL_API usb_relay_device_free_enumerate(struct usb_relay_device_info*);

    Alors que dans la doc de la DLL, il est dit que ça doit être systématique ….

    Edit du 11/01/18 : erreur de ma part, après une relecture plus attentive de la doc, il est simplement souhaitable de libérer la structure après utilisation, mais comme je lis dans beaucoup de tutos qu'en C# on ne s'occupe pas de la gestion de la mémoire je ne comprend pas trop ...

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 25/09/2014, 09h16
  2. Réponses: 11
    Dernier message: 19/06/2014, 15h18
  3. Réponses: 1
    Dernier message: 22/09/2009, 14h26
  4. Réponses: 3
    Dernier message: 02/04/2007, 21h37
  5. Comment accéder à une DLL COM depuis un exécutable ?
    Par Denys dans le forum API, COM et SDKs
    Réponses: 10
    Dernier message: 20/09/2005, 09h04

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