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 :

C# DllImport d'une fonction C utlisant un pointeur de char


Sujet :

C#

  1. #1
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 15
    Par défaut C# DllImport d'une fonction C utlisant un pointeur de char
    Bonjour à tous,

    J'essaye d'utiliser un SDK permettant d'interagir avec les périphériques d'un réseau ArtNet (protocole de communication DMX via le une couche UDP).

    La librairie est écrite en C et se nomme DongleArtNet.dll et j'aimerais pouvoir utiliser au moins quelques une de ces fonctionnalités en C#.

    Le SDK est inclus dans une application appelé DMX-WorkShop

    Une documentation développeur est fournit ainsi que des exemples, notamment un exemple en visualc++ qui fonctionne très bien avec mon VC++ 6.

    Dans la documentation il est expliqué le cycle de fonctionnement du SDK.
    Il faut commencer par appelé une fonction nommé ArtNetInit dont voici la signature en C :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    extern "C" WORD DLL_MODE ArtNetInit(char* NewIp);
    DLL_MODE étant définit comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define DLL_MODE __declspec(dllimport)
    Je ne connais pas grand chose au langage C mais après quelques recherche je suis arrivé à une définition C# :


    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
    using System;
    using System.Text;
    using System.Runtime.InteropServices;
    namespace ArtNetWrapper
    {
        public static class Wrapper
        {
            [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit")]
            public static extern int ArtNetInit(StringBuilder ipPtr);
     
            private static String ip = "2.255.255.255";
            private static StringBuilder builder;
            public static void ArtNetInit()
            {
                Wrapper.builder = new StringBuilder(Wrapper.ip);
                int result = Wrapper.ArtNetInit(Wrapper.builder);
            }
        }
    }
    Cela ne fonctionne pas j'ai un message d'erreurs :
    Un appel à la fonction PInvoke 'ArtNetWrapper!ArtNetWrapper.Wrapper::ArtNetInit' a déséquilibré la pile. Cela peut se produire, car la signature PInvoke managée ne correspond pas à la signature cible non managée. Vérifiez que la convention d'appel et les paramètres de la signature PInvoke correspondent à la signature non managée cible.
    Pourtant une fenêtre blanche s'affiche et une icône apparait dans la zone de notification (cette librairie lorsqu'elle est utilisé dans d'autre application comme DMX-WorkShop affiche un SplashScreen et un icône dans la zone de notification à son démarrage) et Windows me demande même de débloquer le Firewall pour mon application (il y a donc bien tentative d'accès au réseau.)

    Visiblement le paramètre ou la valeur de retour de la fonction n'est pas du bon type.

    J'ai essayé de jouer sur le Charset , sur le Marshalling vers des types différents rien n'y fait.

    Plusieurs questions me viennent :

    - Le type C WORD est-il bien un int16 en C# ?

    - Pourquoi le point d'entrée est _ArtNetInit alors que dans le code C elle est déclarée comme ArtNetInit ?

    - Comment passer un type char* C ?

    - Existe-t-il un tableau de correspondances des types non managés C avec les types managés C# ?

    - il y-as t-il une autre solution ( code unsafe mais c'est pas bien ! ou faire un wrapper en C++ avec des types compréhensible pour le marshalling de .net ) ?

    Pour le contexte le protocole DMX permet de commander des projecteurs de toutes sortes (lumière, vidéo, ...) et leurs paramètres (couleurs, rotation ...) il est très utilisé dans le monde du spectacle. Le protocole ArtNet permet de connecter tout ce beau monde sur un réseau informatique et de communiquer avec. On peut imaginer comme application une console lumière virtuel par exemple (bien loin de mes balbutiements).

    Pour moi, je développe en C# ou en Visual BASIC (pas par choix ) des applications très très métiers (gestion des infrastructures autoroutières). Je ne connais presque rien au C ni au C++.

  2. #2
    Membre expérimenté
    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
    Par défaut
    Salut

    Tout d'abord une grosse erreur a corriger

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    extern "C" WORD DLL_MODE ArtNetInit(char* NewIp);
    Tu ne peux en aucun cas considerer qu'un char *c se traduit en stringbuilder C#

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit")]
            public static extern int ArtNetInit(StringBuilder ipPtr);
    D'apres moi ce serait plutot dans le genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            public static extern int ArtNetInit(IntPtr ipPtr);
    Et Utiliser un Marshall pour transferer ton string ip vers le char *
    Tu peux aussi essayer un bytearray terminé par 0 mais je serais prudent !


    - Le type C WORD est-il bien un int16 en C# ?
    Oui

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par champy_dev Voir le message
    - Le type C WORD est-il bien un int16 en C# ?
    Oui, c'est bien un entier sur 16 bits... donc un short, pas un int !
    D'ailleurs un WORD n'est pas signé, donc ce serait même plutôt ushort

    Citation Envoyé par champy_dev Voir le message
    - Comment passer un type char* C ?
    Ca dépend... En général c'est juste une chaine de caractères qui sera seulement lue par la fonction C, dans ce cas tu peux passer un string. Si c'est un buffer dans lequel la fonction C va écrire, tu utilises plutôt un StringBuilder dans lequel tu réserves la capacité nécessaire.

    Dans ton cas, vu qu'il n'y a pas de paramètre pour indiquer la taille du buffer, je pense que c'est simplement une chaine en entrée, donc déclare plutôt le paramètre de type String.

    Mais à mon avis ça devrait fonctionner aussi avec StringBuilder, le problème doit plutôt être causé par le mauvais type de retour.

    Citation Envoyé par champy_dev Voir le message
    - Existe-t-il un tableau de correspondances des types non managés C avec les types managés C# ?


    Citation Envoyé par champy_dev Voir le message
    - il y-as t-il une autre solution ( code unsafe mais c'est pas bien ! ou faire un wrapper en C++ avec des types compréhensible pour le marshalling de .net ) ?
    Un truc comme ça ?
    http://msdn.microsoft.com/en-us/library/ac7ay120.aspx

    Citation Envoyé par olibara Voir le message
    Tu ne peux en aucun cas considerer qu'un char *c se traduit en stringbuilder C#
    Pourquoi tu dis ça ? En C un char * représente (presque toujours) une chaine de caractères. Le marshalling gère automatiquement la conversion avec le type string ou StringBuilder.

    Citation Envoyé par olibara Voir le message
    D'apres moi ce serait plutot dans le genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            public static extern int ArtNetInit(IntPtr ipPtr);
    [/CODE]Et Utiliser un Marshall pour transferer ton string ip vers le char *
    Tu peux aussi essayer un bytearray terminé par 0 mais je serais prudent !
    Ca me semble bien compliqué
    Je suis quasiment certain que ce ne sera pas nécessaire ici

  4. #4
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 15
    Par défaut
    Re bonjour,

    J'ai essayé les solutions que vous citez :

    Modifier la signature pour lui passer un pointeur de chaine (cette chaine c'est en fait 2.255.255.255 l'adresse de Broadcast par convention d'un réseau ArtNet), correctement 'Marshaller' , au mois avec tout les cas possible pour une chaine.

    Pour ce qui est du nom de la signature il y a aussi un #define dans le code source C qui li le nom _ArtNetInit à la fonction ArtNetInit. Enfin c'est ce que j'en ai déduis. Dans le doute j'ai essayé les deux sans succès.

    J'ai essayé avec une valeur de retour en int, ushort, short ... sans succès.
    Bien sur j'ai croisé entre elles toutes ces possibilités.

    Mais l'apparition brèves du splashscreen sans son image, l'icone dans la zone de notification et le message du firewall de Windows qui me demande si je veux bien que l'application accède a tel port me laisse penser que la fonction est bien appelé, voir l'IP (la chaine qui est passé en char*) correctement parsée, donc ma valeur bien passer ....

    Lorsque je compile le projet d'exemple livré avec le SDK sous VC++6 dans la console j'ai une phase de recherche de driver ArtNet. Peut-être une piste, des fichiers doivent être présent dans le répertoire de mon application ?

    Bref cela devenant compliqué j'ai pris un peu de recul et avec quelques outils d'analyse de réseaux et les spécifications des paquets j'ai carrément implémenté le protocole pour envoyer des datagrammes UDP.

    Et la ca marche je peux itérer les périphériques du réseau ArtNet, il me renvoi leur description, un début.

    Bon en tout cas merci pour votre aide

    Après est-ce que le post est résolu....

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Avec ça, ça fonctionne pas ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit")]
            public static extern ushort ArtNetInit(string ipPtr);

  6. #6
    Membre expérimenté
    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
    Par défaut
    Bonjour TomLev

    uint16, ushort c'est kif kif !

    Par contre j'ai des sérieux doute sur le casting d'un StringBuilder en char *
    Dans tous les cas ou je devais recuperer le contenu d'un Char * en C je passe par un IntPtr voir un IntPtr ** en unsafe dans le cas on la fonction de ma dll rends un tableau de char *

    Ici c'est un peut different car l'allocation du char * se fait en C#
    C s'attends a interpreter un zstring et je ne vois pas par quelle magie un StringBuilder va se caster en zstring !

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par olibara Voir le message
    uint16, ushort c'est kif kif !
    Oui, mais champy_dev a déclaré sa fonction en int (= Int32)

    Citation Envoyé par olibara Voir le message
    Par contre j'ai des sérieux doute sur le casting d'un StringBuilder en char *
    Dans tous les cas ou je devais recuperer le contenu d'un Char * en C je passe par un IntPtr voir un IntPtr ** en unsafe dans le cas on la fonction de ma dll rends un tableau de char *
    Ben tu te compliques beaucoup la vie pour rien... c'est justement le boulot du marshalling de faire ce genre de trucs bas niveau. Regarde par exemple la déclaration de FindWindow sur PInvoke.net, ils utilisent bien string, même si en C les paramètres sont de type LPCSTR (const char *)

    Citation Envoyé par olibara Voir le message
    Ici c'est un peut different car l'allocation du char * se fait en C#
    C s'attends a interpreter un zstring et je ne vois pas par quelle magie un StringBuilder va se caster en zstring !
    Ben par la magie du marshalling... c'est pas un cast, c'est une transformation.
    Ca marche très bien, exemple avec GetMenuString (le type en C est LPTSTR)

  8. #8
    Membre expérimenté
    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
    Par défaut
    Tiens

    J'avais envoyé un message que je ne retrouve pas

    Salut TomLev

    Tu conviendra quand meme que la signature déclarée dans GetMenuString et concernant le le passage du stringbuilder en zstring

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [DllImport("user32.dll")]
    static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out,MarshalAs(UnmanagedType.LPStr)] StringBuilder lpString, int nMaxCount, uint uFlag);
    N'est pas equivallente a celle déclarée par champy

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit")]
            public static extern int ArtNetInit(StringBuilder ipPtr);

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par olibara Voir le message
    Salut TomLev

    Tu conviendra quand meme que la signature déclarée dans GetMenuString et concernant le le passage du stringbuilder en zstring

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [DllImport("user32.dll")]
    static extern int GetMenuString(IntPtr hMenu, uint uIDItem, [Out,MarshalAs(UnmanagedType.LPStr)] StringBuilder lpString, int nMaxCount, uint uFlag);
    N'est pas equivallente a celle déclarée par champy

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
            [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit")]
            public static extern int ArtNetInit(StringBuilder ipPtr);
    Ben y a des attributs en plus, je sais plus s'ils sont indispensables ou pas. Mais dans l'idée, ça reste un StringBuilder

  10. #10
    Membre expérimenté
    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
    Par défaut
    Salut TomLev

    Je pense que l'attribut est tout a fait indispensable dans le cas present !

    selon moi cet attribut

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [Out,MarshalAs(UnmanagedType.LPStr)]
    Note le Out !
    Pemet la generation du code qui implicitement convertira le StringBuilder en LpStr

    Et le out me laisse supposer qu'il s'agit en l'occurence d'un LpStr *

    Et je maintiens qu'il n'est a mon avis pas possible de passer tel quel un String managé encore moins un stringbuilder a une fonction C qui attends un char *

    Tu dois passer par le Marshalling de pointeur explicite d'une maniere ou d'une autre

  11. #11
    Membre expérimenté
    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
    Par défaut
    Bonjour TomLev

    Comme j'ai quand meme grande confiance en ce que tu dis et que cette fois ci ca me semblait bizarre par rapport a ce que j'avais mis en place pour ma part, j'ai continuer a investiguer

    Et je viens de tomber sur ceci

    Citation Envoyé par Chris R. Timmons wrote
    > You can use the either the System.String or System.Text.StringBuilder
    > class. The underlying P/Invoke marshalling code in the .Net
    > framework will do all of the messy character pointer conversions for
    > you. If the string parameter is used as an output or input/output
    > buffer, then use StringBuilder. Otherwise if the string parameter is
    > input-only you can use the String class.
    Cela implique que tu a quand meme raison et et que je fais un détour pour arriver au meme résultat

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par olibara Voir le message
    Je pense que l'attribut est tout a fait indispensable dans le cas present !
    Possible, j'ai pas vérifié

    Citation Envoyé par olibara Voir le message
    Et je maintiens qu'il n'est a mon avis pas possible de passer tel quel un String managé encore moins un stringbuilder a une fonction C qui attends un char *

    Tu dois passer par le Marshalling de pointeur explicite d'une maniere ou d'une autre
    Ben je sais pas ce qu'il te faut... Je t'ai donné un exemple, et il y en a plein d'autres. Je l'ai fait très souvent et je le fais encore régulièrement, ça fonctionne parfaitement. Donc à moins que j'ai réussi à faire quelque chose d'impossible... c'est possible

  13. #13
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    arf, j'avais pas vu que tu avais reposté 2mn avant moi... ça m'aurait évité la peine d'écrire une petite démo

    Bon, je la poste quand même, parce que ça pourra peut-être apporter une réponse à champy_dev :

    testlib.h
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ...
     
    extern "C"
    {
     
    TESTLIB_API void Bar(char * s);
    TESTLIB_API void Foo(char * s);
     
    }


    testlib.cpp

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ...
     
    TESTLIB_API void Bar(char * s)
    {
    	printf(s);
    }
     
    TESTLIB_API void Foo(char * s)
    {
    	strcpy(s, "Hello world");
    }

    Code C#

    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
        internal static class TestPInvoke
        {
            public static void Test()
            {
                StringBuilder sb = new StringBuilder(20);
                Foo(sb);
                Bar(sb.ToString());
            }
     
            [DllImport("testlib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            private static extern void Foo(StringBuilder s);
     
            [DllImport("testlib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            private static extern void Bar(string s);
        }

    Ce code récupère le texte "Hello world" de la librairie C, et l'écrit sur la console, toujours via la librairie C. Pas de IntPtr à l'horizon

    Au passage, ça confirme ce que je soupçonnais : les attributs Out et MarshalAs ne sont pas forcément nécessaires... Je crois que le Out est juste à titre indicatif, et le UnmanagedType.LPStr doit correspondre à ce qu'il utilise par défaut (du moins pour CharSet = Ansi)

    @champy_dev : essaie d'ajouter les paramètres CharSet et CallingConvention comme dans mon code, je pense que le problème vient de là. Au début je les avais pas mis et j'ai eu la même erreur que toi.

  14. #14
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par tomlev Voir le message
    @champy_dev : essaie d'ajouter les paramètres CharSet et CallingConvention comme dans mon code, je pense que le problème vient de là. Au début je les avais pas mis et j'ai eu la même erreur que toi.
    Tu as raison, mais si il s'agit d'une librairie publique, il est hautement improbable qu'elle utilise la "C calling convention". L'usage veut en effet qu'on utilise la convention d'appel dite "convention pascal"(__stdcall) pour les fonctions exportées, et cela pour une raison fort simple : la quasi totalité des langages sont capables d'appeler en "convention pascal" alors que pratiquement seul C (et .Net ....) sont capables de gérér la convention d'appel C.

    Le "extern C" n'a pas d"influence sur la convention d'appel mais il informe le compilateur de supprimer la décoration des noms spécifiiques au C++ permettant d'identifier les paramètres d'appel d'une fonction sans disposer de sa déclaration, ce qui permet au linker de vérifier le typage et le nombre des paramètres, ce que C ne peut pas faire - et qui était d'ailleurs une source inépuisable d'erreurs à "l'époque" (sur l'air de " je-vous-parle-d'un temps-que-les-moins-de-vingt-ans-ne-peuvent-pas-connaitreeeeuuuu" ).

    En "convention pascal", on dispose néanmoins d'un contôle des paramètres passés mais uniquement sous la forme du nombre total de bytes attendus dans la pile d'appel; il est passé en décorant le nom de la fonction en le suffixant avec "@" suivi du nombre d'octets passés.

    Comme toute règle comporte son exception : en Windows Mobile, les API windows sont exposées en convention d'appel C.

  15. #15
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Tu as raison, mais si il s'agit d'une librairie publique, il est hautement improbable qu'elle utilise la "C calling convention". L'usage veut en effet qu'on utilise la convention d'appel dite "convention pascal"(__stdcall) pour les fonctions exportées, et cela pour une raison fort simple : la quasi totalité des langages sont capables d'appeler en "convention pascal" alors que pratiquement seul C (et .Net ....) sont capables de gérér la convention d'appel C.
    Je sais pas, dans mon exemple il a fallu que je mette Cdecl sinon ça marchait pas... Dans le code de la lib C (que j'ai pas sous la main au bureau), je crois que la macro TESTLIB_API était définie avec __cdecl(dllimport) ou un truc comme ça... ça doit venir de là. Je soupçonne que la macro DLL_MODE dans la lib utilisée par champy_dev est aussi définie de cette façon.

  16. #16
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 15
    Par défaut
    Effectivement la syntaxe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetInit", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            private static extern ushort _ArtNetInit(String aString);
    Semble être la bonne Je peut démarrer le serveur, j'ai le splashscreen et l'icône dans la zone de notification.

    Il me reste à "Wrapper" quelques autres fonctions pour accéder aux nœuds Art-Net de mon réseaux.

    Du coup j'ai deux façon d'accéder aux informations du réseau Art-Net, le Wrapper et la petite couche UDP que j'avais commencé à développer ...

    Le threading et la gestion du protocole sont certainement mieux implémenté en C que dans mon code C# ( je ne suis pas un pro du Threading ) je vais donc utiliser mon Wrapper.

    Merci en tout cas pour vos explications fort utile

  17. #17
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 15
    Par défaut
    Une autre question sur le même sujet. Lorsque que j'appelle en C# des méthodes C Wrappé, si la méthode est mal Wrapper ai-je toujours un bug ? Je m'explique ...

    J'ai Wrappé la méthode ci-dessous :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     [DllImport("DongleArtNet.dll", EntryPoint = "_ArtNetSetCallBackFromTimeCode", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
            private static extern void _ArtNetSetCallBackFromTimeCode([MarshalAs(UnmanagedType.FunctionPtr)]ArtNetFromTimeCodeDelegate d);
            public delegate void ArtNetFromTimeCodeDelegate(byte aFrames, byte aSeconds, byte aMinutes, byte aHours, byte aType);
    Sa signature en C est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    extern "C" void DLL_MODE ArtNetSetCallBackFromTimeCode( void(*Function)( uchar Frames, uchar Seconds, uchar Minutes, uchar Hours, uchar Type) );
    J'appelle ma méthode Wrappée comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _ArtNetSetCallBackFromTimeCode(new ArtNetFromTimeCodeDelegate(ArtNetWrapper.ArtNetFromTime));
    Et bien sur j'ai une méthode ArtNetFromTime comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public  static void ArtNetFromTime(byte aFrames, byte aSeconds, byte aMinutes, byte aHours, byte aType)
            {
                Console.WriteLine(String.Format("Frames {0} , Seconds {1} , Minutes {2} , Hours {3} , Type {4}", aFrames,                                    aSeconds, aMinutes, aHours, aType));
            }
    Je suis au bureau ( entre midi et 2 ) et je n'ai pas de périphériques Art-Net sous la main, l'appelle de cette fonction passe mais le délègue n'ai jamais appelé ( ce qui semble logique sans périphérique pour lui envoyer des timecode). Cela suffit-il pour me dire que le Wrapping de cette méthode est correct ?

  18. #18
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    Citation Envoyé par champy_dev Voir le message
    Cela suffit-il pour me dire que le Wrapping de cette méthode est correct ?
    Non, parce que là ça passe juste un pointeur. Il faudrait que le delegate soit appelé pour être sûr que ça marche.

    En tous cas à vue de nez ça a l'air correct. Le [MarshalAs(UnmanagedType.FunctionPtr)] n'est pas obligatoire, ça devrait marcher sans ça.

  19. #19
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2010
    Messages
    15
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2010
    Messages : 15
    Par défaut
    Bon ce n’est pas encore gagné ...

    Le serveur ArtNet démarre, la fonction ArtNetInit renvoie une valeur d'énumération représentant le statut du serveur (pas de driver, driver mais pas de périphérique, périphériques présent ...), je bind cette valeur à mon interface graphique dans laquelle j'affiche le statut du serveur et un bouton arrêter/démarrer qui démarre et arrête le serveur (forcément ) via des RelayCommand.

    Tout cela fonctionne, le texte du bouton change, le texte du statut aussi ... et la à la première interaction avec l'interface graphique j'ai une StackOverflowException :
    Une exception non gérée du type 'System.StackOverflowException' s'est produite dans mscorlib.dll

    {Impossible d'évaluer l'expression, car le thread actuel se trouve dans un état de dépassement de capacité de la pile.}
    Pourtant le statut renvoyé par la fonction est bien correct, pas de périphérique quand je n'en ai pas, 1 périphérique quand il est branché, j'ai même testé pas de driver présent quand je supprime le dongle ArtNet.

    Je n'appelle pas d’autres fonctions de cette librairie C et mon interface fonctionne très bien tant que je ne démarre pas le serveur.

    Je n'ai pas trop de piste, un obscure problème de thread peut-être ..., la librairie C doit certainement (surement en regardant de plus près la documentation développeur du dongle) lancer un (voir plusieurs) thread pour gérer les messages UDP, peut-être prend t-il le pas sur celui de mon application. (Comme je l'ai déjà dit je ne suis pas très fort en thread ...)

    Quelqu'un a-t-il déjà eu ce genre de soucis ?

    Bon au pire il me reste ma propre implémentation UDP du protocole ArtNet mais il y as encore du boulot

  20. #20
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Par défaut
    La plupart du temps, une StackOverflowException est causée par une récursion infinie. Regarde la pile de l'exception (StackTrace) pour voir où ça se passe, et essaie de mettre des points d'arrêt pour exécuter pas à pas

Discussions similaires

  1. Réponses: 3
    Dernier message: 16/03/2011, 15h35
  2. Réponses: 6
    Dernier message: 16/01/2011, 15h33
  3. DLL:exporter une fonction qui retourne un pointeur
    Par ephemeride dans le forum C++
    Réponses: 2
    Dernier message: 29/09/2006, 11h42
  4. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14
  5. Une fonction avec des attributs non obligatoires
    Par YanK dans le forum Langage
    Réponses: 5
    Dernier message: 15/11/2002, 13h39

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