1. #1
    Membre du Club
    Inscrit en
    février 2010
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : février 2010
    Messages : 238
    Points : 67
    Points
    67

    Par défaut Comment porter un header C avec des déclarations Inline + Fonction CALLBACK en C#

    Bonjour,

    J'ai a utiliser une librairie C/C++ écrites en utilisant les MFC (c'est donc relativement ancien) et je commence par réécrire le header dont j'ai besoin. Pour les constante classique en #define ca va. Je fais comme ceci:

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
         // en C, j'ai ca: #define  DB_NUMMASK  0x00ff
         // en C# je fais ca:
         public const uint DB_NUMMASK  =  0x00ff;

    Donc ca se fait bien. En revanche lorsque j'ai des définition "inline" je ne peux pas mieux faire que de créer une fonction. Est-ce que il y a mieux ? Je fais comme ca:

    J'ai ça dans le header C
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
       #define   DB_ATTR_NUM(attr)   ((attr >> DB_NUMSHIFT) & DB_NUMMASK)

    J'ai cherché a savoir si on pouvais faire des définition en ligne en C# comme en C. C'est ma question.

    En attendant j'ai fait comme ca, en créant des fonctions dans une classe (dans laquelle j'ai toutes mes constantes de header). Comme ca:

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
       public long DB_ATTR_NUM( uint attr )
       {
          return ( (long) ((attr >> (int) DB_NUMSHIFT) & DB_NUMMASK) );
       }

    Question: Est-ce que il y a mieux que de créer une fonction ? Autrement dit, peut-on faire en C# des déclarations inline comme en C ?

    Merci.

  2. #2
    Membre du Club
    Inscrit en
    février 2010
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : février 2010
    Messages : 238
    Points : 67
    Points
    67

    Par défaut

    Bonjour,

    Personne pour commenter ma solution de contournement pour la définition des #define Inline C ? Vous auriez fait comme moi ou vous avez mieux ?

  3. #3
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 375
    Points : 4 688
    Points
    4 688
    Billets dans le blog
    5

    Par défaut

    Bonjour,

    Citation Envoyé par Jolt0x Voir le message
    J'ai cherché a savoir si on pouvais faire des définition en ligne en C# comme en C. C'est ma question.
    Non, c'est impossible.

    Citation Envoyé par Jolt0x Voir le message
    En attendant j'ai fait comme ca, en créant des fonctions dans une classe (dans laquelle j'ai toutes mes constantes de header). Comme ca:

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
       public long DB_ATTR_NUM( uint attr )
       {
          return ( (long) ((attr >> (int) DB_NUMSHIFT) & DB_NUMMASK) );
       }
    C'est ce qu'il faut faire.
    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

  4. #4
    Membre du Club
    Inscrit en
    février 2010
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : février 2010
    Messages : 238
    Points : 67
    Points
    67

    Par défaut

    Merci.

  5. #5
    Membre du Club
    Inscrit en
    février 2010
    Messages
    238
    Détails du profil
    Informations forums :
    Inscription : février 2010
    Messages : 238
    Points : 67
    Points
    67

    Par défaut Header C et fonctions CallBack en C#

    Bonjour,

    2 questions supplémentaires, toujours pour le portage d'un header C en C# et les fonction passées en paramètre (callback)

    Première question:

    Toujours dans la même idée, je voudrais convertir cette définition d'un header C en C#:

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          typedef long (*eventfunc_t) (long client_arg, long event_class, long event_type, long event_arg);

    J'ai pensé a ca:

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          using eventfunc_t = System.Int64;

    Mais je pense que c'est trop simple. C'était ma première question. Merci.

    Seconde question :

    En réalité la fonction eventfunc est une fonction qui est passée en paramètre d'une autre fonction de cette DLL écrite en C/MFC de Microsoft. Une fonction CallBack. Je ne sais pas bien faire, a vrais dire. Comment passer en paramètre, non pas une variable d'un type C# (int, String, etc.) mais une fonction de type eventfunc_t, défini plus haut ?

    Pour donner plus de précision, la fonction de type "eventfunc " est défini comme ca dans un exemple dans la documentation de la DLL:

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     
    extern “C” {
          long eventfunc ( long arg, long evclass, long evtype, long evarg)
          {
                if (evtype == EVENT_LOGOUT) { 
                // traitement et action sur interception d'un évènement LogOut
                // action, ToDo
                return;
    	}
          }
    }

    Comment porter en C# la fonction juste au dessus ? long eventfunc (long arg, long evclass, long evtype, long evard) ? et pour le extern C ? Merci.

    La fonction qui prends en argument la fonction de type est la suivante en C:

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          HSESS far pascal  dbSessLoginServer(HWND cons_wnd, char *ipAddr, char *user, char *passwd, eventfunc_t func, long client_arg);

    Où HSESS est un type définie égale à *void en C c'est a dire un System.IntPtr en C#. Pas de problème de ce coté là. ON reconnaît le type "eventfunc_t" défini plus haut et "func" la fonction passé en paramètre.

    Est-ce que cela suffit ? Faut-il utiliser la notion de "Delegate" en C# (j'ai fait quelques recherches sur Google sur les fonctions callback en C#, sans vraiment comprendre ce que j'ai lu) ?

  6. #6
    Rédacteur/Modérateur

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

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

    Informations forums :
    Inscription : juillet 2016
    Messages : 1 375
    Points : 4 688
    Points
    4 688
    Billets dans le blog
    5

    Par défaut

    Citation Envoyé par Jolt0x Voir le message
    Première question:

    Toujours dans la même idée, je voudrais convertir cette définition d'un header C en C#:

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          typedef long (*eventfunc_t) (long client_arg, long event_class, long event_type, long event_arg);

    J'ai pensé a ca:

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          using eventfunc_t = System.Int64;

    Mais je pense que c'est trop simple. C'était ma première question. Merci.
    Il s'agit d'un pointeur de fonction. L'équivalent en C# ce sont les delegate. C'est donc ce qu'il faut utiliser.

    Citation Envoyé par Jolt0x Voir le message
    Seconde question :

    En réalité la fonction eventfunc est une fonction qui est passée en paramètre d'une autre fonction de cette DLL écrite en C/MFC de Microsoft. Une fonction CallBack. Je ne sais pas bien faire, a vrais dire. Comment passer en paramètre, non pas une variable d'un type C# (int, String, etc.) mais une fonction de type eventfunc_t, défini plus haut ?

    Pour donner plus de précision, la fonction de type "eventfunc " est défini comme ca dans un exemple dans la documentation de la DLL:

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
     
    extern “C” {
          long eventfunc ( long arg, long evclass, long evtype, long evarg)
          {
                if (evtype == EVENT_LOGOUT) { 
                // traitement et action sur interception d'un évènement LogOut
                // action, ToDo
                return;
    	}
          }
    }

    Comment porter en C# la fonction juste au dessus ? long eventfunc (long arg, long evclass, long evtype, long evard) ? et pour le extern C ? Merci.
    C'est ça. Eventuellement en remplaçant les long par des int (car un long en C est censé être un entier sur 32 bits minimum, et un int en C# est un entier 32 bits).

    Le extern "C" n'a pas d'équivalent et n'aurait pas réellement de sens en .Net. Il permet de préciser que la convention de nommage à utiliser est celle définie par le langage C, ce qui n'est utile que lorsque le code est du code C++.

    Citation Envoyé par Jolt0x Voir le message

    La fonction qui prends en argument la fonction de type est la suivante en C:

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          HSESS far pascal  dbSessLoginServer(HWND cons_wnd, char *ipAddr, char *user, char *passwd, eventfunc_t func, long client_arg);

    Où HSESS est un type définie égale à *void en C c'est a dire un System.IntPtr en C#. Pas de problème de ce coté là. ON reconnaît le type "eventfunc_t" défini plus haut et "func" la fonction passé en paramètre.

    Est-ce que cela suffit ? Faut-il utiliser la notion de "Delegate" en C# (j'ai fait quelques recherches sur Google sur les fonctions callback en C#, sans vraiment comprendre ce que j'ai lu) ?
    Il faut effectivement utiliser un Delegate, car comme dit plus haut, c'est ce qui correspond à un pointeur de fonction en C#
    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

  7. #7
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    juin 2007
    Messages
    367
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : juin 2007
    Messages : 367
    Points : 555
    Points
    555

    Par défaut

    Les delegate ça fait vite des nœuds au cerveau, mais je vais tâcher d'expliquer ça de façon simple. Le plus aisé, je pense, et sans rentrer dans les détails techniques, est de dire que le mot clé delegate permet de créer un type de fonction, de la même manière que le mot class permet de créer un type d'objet. Par exemple si je veux définir une classe qui s'appelle Product et possède des propiétés Id et Name :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
        public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    Si je veux définir un type de fonction qui s'appelle OperationSurDesInt, prend en paramètre deux int et renvoie un int :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public delegate int OperationSurDesInts(int a, int b);
    On va pouvoir utiliser ce delegate avec des méthodes qui respectent sa signature.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static int Max(int a, int b) { return a > b ? a : b; }
    Ou :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public static int Compare(int a, int b) { return a - b; }
    Une fois qu'on a défini un type de méthode on peut le manipuler comme un type d'objet. On peut en faire un champ ou une propriété :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Class1
    {
            private OperationSurDesInts _operation;
     
            public OperationSurDesInts Operation
            {
                get { return _operation; }
                set { _operation = value; }
            }
    }
    On peut l'instancier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _operation = new OperationSurDesInts(Max);
    Ou plus simplement :

    On peut également assigner une lambda expression, c.à.d une fonction improvisée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    _operation = (a, b) => a > b ? a : b;
    Les delegate sont ensuite utiliser pour la conception d'événements (en fait une implémentation du patter Observateur / Observable). Un événement (event) est une sorte de collection qui permet de stocker des méthodes respectant une certaine signature et de les appeler au besoin. Pour une événement de réception de message :

    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
    namespace Samples
    {
     
        public class Message { public string Content { get; set; } }
     
        public delegate void ProcessMessage(Message message);
        public class Messages
        {
            public event ProcessMessage NewMessage;
     
            protected void SignalMessage(Message message)
            {
                NewMessage?.Invoke(message);
            }
     
            public void Send(Message message)
            {
                if (message != null) SignalMessage(message);
            }
        }
    }
    Par convention les événements des classes du framework correspondent à une signature qui ne renvoie pas de valeur et prend en paramètre 1 un objet (sender) et en paramètre 2 une class dérivée de EventArgs. Ainsi le delegate de l'événement standard :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public delegate void EventHandler(object sender, EventArgs e);
    Le delegate PropertyChanged :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public delegate void PropertyChanged(object sender, PropertyChangedEventArgs e);
    Il y a un ensemble de convention sur les noms des événements et de leurs attributs mais je ne les ai pas toutes en tête pour le moment.

    Notons qu'afin de ne pas créer des delegate à tire-larigot le framework met à disposition des delegate générique : Action pour les méthodes n'ayant pas de valeur de retour et Func<TResult> pour celle qui ont une valeur de retour ; elle peuvent prendre jusqu'à une quinzaine de paramètres d'entrée (mais personne ne crée de fait de méthode avec 15 paramètre d'entrée, n'est-ce-pas ?) ; pour Func<TResult> la valeur de retour est portée sur le dernier paramètre.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public Action<int> Execute { get; set; }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public Func<double, double, int> Comparer { get; set; }
    Ainsi ta fonction d'événement pourra être transmise à ce type de méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public void RegisterCallback(Func<long, long, long, long, long> callback) { }
    Mais si tu l'utilises souvent tu voudras sans doute faire un delegate dedié :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public delegate long EventFunc(long arg, long evclass, long evtype, long evarg);
     
    public void RegisterCallback(EventFunc callback) { }
    Enfin pour ceux qui n'ont pas encore perdu toute leur santé mentale, un mot sur (si je me souviens bien de la terminologie) les paramètre contravariant et les retours covariants. Un delegate peux accepter une méthode dont les paramètres d'entrée sont plus permissifs que ceux qu'il fournit (ex : object pour n'importe-quoi d'autre) et dont le type de retour est plus restreint que celui attendu (ex : List pour IEnumerable). L'exemple en code :

    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
    namespace Samples
    {
        public abstract class Animal
        {
            public string Name { get; set; }
        }
     
        public class Human : Animal { }
        public class Frog : Animal { }
     
        public delegate Animal HumanMetamorphosis(Human target);
     
        public static class MyWorldOfMagic
        {
            public static HumanMetamorphosis CurrentMetamorphosis { get; set; }
     
            public static Frog EvilSpell(Animal victim)
            {
                return victim != null ? new Frog { Name = victim.Name } : null;
            }
     
            public static void EvilIsFun()
            {
                CurrentMetamorphosis = EvilSpell;
            }
     
            public static void NightOfTheWitch()
            {
                var witch = new Witch();
                CurrentMetamorphosis = witch.WitchCurse;
            }
        }
     
        public class Witch
        {
            public Frog WitchCurse(Human victim)
            {
                return MyWorldOfMagic.EvilSpell(victim);
            }
        }
    }
    EvilSpell peut être affecté à CurrentMetamorphosis qui est de type HumanMetamorphosis. Le delegate peut passer un Human à la méthode qui attend un Animal ; tandis que l'objet Frog renvoyé au delegate pourra ensuite être renvoyé par le delegate qui expose le type Animal.

    EDIT : en fait j'ai écrit un gros pavé, s'il tombe dans une mare il va faire de sacrés éclaboussures ; en tout cas félicitation a ceux qui l'auront lu en entier

Discussions similaires

  1. Réponses: 3
    Dernier message: 16/12/2006, 12h59
  2. Comment optimiser une lourde requête avec des index
    Par Romalafrite dans le forum Requêtes
    Réponses: 10
    Dernier message: 01/12/2006, 19h18
  3. Comment creer un choix multiple avec des cases a cocher ??
    Par pedrosystem dans le forum Access
    Réponses: 5
    Dernier message: 09/03/2006, 10h36
  4. Réponses: 4
    Dernier message: 07/11/2005, 15h54

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