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++/CLI Discussion :

Native C++ Callbacks in C# Code


Sujet :

C++/CLI

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 4
    Par défaut Native C++ Callbacks in C# Code
    Bonjour à tous,

    Dans un programme C# j'appelle une dll C++ native dans laquelle j'installe un hook qui leve un callback que je souhaite recupérer dans mon code C#.

    Soyez indulgent...

    Voici le code 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
    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
    // NativeDll.cpp*: définit les fonctions exportées pour l'application DLL.
    #include "stdafx.h"
    #include <windows.h>
     
    #define NATIVEDLL_API extern "C" __declspec(dllexport) 
    typedef void (* FPCallback)(int code);
     
    HHOOK hookCbt = NULL;  //Identificateur hook cbt
    HINSTANCE appInstance = NULL;  //pointeur sur instance
    FPCallback fCallback = NULL;
     
    LRESULT CALLBACK CbtHookCallback(int code, WPARAM wparam, LPARAM lparam);
     
    // Point d'entrée de la Dll
    BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
    {
    	switch (ul_reason_for_call)
    	{
    		case DLL_PROCESS_ATTACH:
    			if(appInstance == NULL) appInstance = hModule;
    			break;
    		case DLL_THREAD_ATTACH:
    			break;
    		case DLL_THREAD_DETACH:
    			break;
    		case DLL_PROCESS_DETACH:
    			break;
    	}
    	return TRUE;
    }
     
    NATIVEDLL_API bool Init(FPCallback callback)
    {
    	hookCbt = SetWindowsHookEx(WH_CBT,(HOOKPROC)CbtHookCallback, appInstance, 0);
    	fCallback = callback;
    	return (hookCbt != NULL);
    }
     
    NATIVEDLL_API void Uninit()
    {
    	if (hookCbt != NULL)
    		UnhookWindowsHookEx(hookCbt); // Arrêt du hook CBT 
    	hookCbt = NULL;
    	fCallback = NULL;
    }
     
    LRESULT CALLBACK CbtHookCallback(int code, WPARAM wparam, LPARAM lparam)
    {
    	if (code >= 0) 
    		fCallback(code);
    	return CallNextHookEx(hookCbt, code, wparam, lparam); // Rappel du hook
    }
    Et le code C# de la form :

    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
    using System;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;
     
    namespace Test
    {
        public enum WH_CBT : int
        {
            WH_CBT_MOVESIZE = 0,
            WH_CBT_MINMAX,
            WH_CBT_QS,
            WH_CBT_CREATEWND,
            WH_CBT_DESTROYWND,
            WH_CBT_ACTIVATE,
            WH_CBT_CLICKSKIPPED,
            WH_CBT_KEYSKIPPED,
            WH_CBT_SYSCOMMAND,
            WH_CBT_SETFOCUS
        }
     
        public partial class Form1 : Form
        {
            [UnmanagedFunctionPointer(CallingConvention.Cdecl)]        
            public delegate void OnHookCbtEvent(int code);
     
            [DllImport("NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
            static extern bool Init([MarshalAs(UnmanagedType.FunctionPtr)]OnHookCbtEvent cbt);
     
            [DllImport("NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
            static extern void Uninit();
     
            [MarshalAs(UnmanagedType.FunctionPtr)]
            private OnHookCbtEvent onCbt;
     
            public Form1()
            {
                InitializeComponent();
                this.onCbt = new OnHookCbtEvent(OnCbtDelegate);
                Init(onCbt);
            }
     
            public void OnCbtDelegate(int code)
            {
                listBox1.Items.Add(Enum.GetName(typeof(WH_CBT), (WH_CBT)code));
            }
     
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                Uninit();
            }
        }
    }
    Le probleme est qu'a l'exécution le code fonctionne mais pas longtemps, au bout d'un moment le callback n'est plus appellé. Auriez vous une idée ?

    Merci de m'aider.

  2. #2
    Expert confirmé
    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
    Par défaut
    Je pense que le [MarshalAs(UnmanagedType.FunctionPtr)] de private OnHookCbtEvent onCbt n'est pas nécessaire.

    Citation Envoyé par railarmenien Voir le message
    Le probleme est qu'a l'exécution le code fonctionne mais pas longtemps, au bout d'un moment le callback n'est plus appellé.
    ça voudrait peut être dire que ton délégué s'est fait collecté par le GC, mais en même temps vu que tu as une variable onCbt ça ne devrait pas être le cas ...
    Juste pour vérifier, tu pourrai appeler, juste après ton Init pour voir ce que ça fait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    GC.Collect();
    GC.WaitForPendingFinalizers();
    ?

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 4
    Par défaut
    Je pense aussi que mon callback s'est fait collecter part le GC. Mais je ne comprends pas pourquoi.

    Sinon j'ai essayé
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    GC.Collect();
    GC.WaitForPendingFinalizers();
    après l'appel a init() mais ca ne change rien.



    Pour info, j'ai essayé d'installer et de desinstaller le hook grace a des clics de boutons. A ce moment la le callback est appellé un peu plus longtemps mais semble tout de même collecté rapidement par le GC. Ce que je ne comprends pas c'est que j' ai une instance de ce déléguée privée dans ma Form donc je devrais en théorie la conserver durant toute l'exécution.

  4. #4
    Expert confirmé
    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
    Par défaut
    et avec Marshal.GetFunctionPointerForDelegate ?

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 4
    Par défaut
    Je ne sais pas ou placer ce Marshal.GetFunctionPointerForDelegate()

    - C'est la première fois que je 'amuse avec le marshalling en fait ^^ etje balise un peu au petit bonheur la chance. J'ai dailleurs retirer l'attribut [(MarshallAs(Unmanagedtype.FunctionPtr)] du membre privé onCbt comme conseillé plus haut.

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2009
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2009
    Messages : 4
    Par défaut Suppression de "up" du message
    Concernant Marshal.GetFunctionPointerForDelegate, si je l'utilise je ne sais pas quel prototype conserver pour l'import de la fonction Init dans le code C#
    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    [DllImport("NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
            static extern bool Init(OnHookCbtEvent cbt);
    soit
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    [DllImport("NativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
            static extern bool Init(IntPtr cbt);//IntPtr correspond au type retourné par Marshal.GetFunctionPointerForDelegate.
    Quelqu'un aurait il le correctif à apporter à mon code ou un exemple avec le même type d'implémentation ( callback C# appellé dans une fonction d'une dll C++ non managée) ?

Discussions similaires

  1. Réponses: 4
    Dernier message: 11/10/2011, 14h34
  2. Réponses: 2
    Dernier message: 13/03/2009, 11h11
  3. utiliser un callback C++ natif avec du code .NET (en C#)
    Par nicolasflasque dans le forum C++/CLI
    Réponses: 3
    Dernier message: 28/11/2008, 11h58
  4. Réponses: 2
    Dernier message: 26/06/2007, 17h46
  5. DLL Native chargeant et appelant du code dans une DLL.NET
    Par cinemania dans le forum C++/CLI
    Réponses: 3
    Dernier message: 17/04/2007, 07h12

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