Native C++ Callback in C# SetWindowsHookEx

railarmenien Messages postés 4 Date d'inscription mercredi 11 octobre 2006 Statut Membre Dernière intervention 17 décembre 2009 - 17 déc. 2009 à 09:54
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 - 17 déc. 2009 à 15:05
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++

/ 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 :
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.

6 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 déc. 2009 à 11:39
Salut, oui c'est classique, ton délégué a été rammassé par le GC. Tu dois le protèger en le gardant en membre de la classe, en C++/CLI il est même conseillé de l'allouer dans un GCHandle mais en C# ça me semble inutile.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 déc. 2009 à 11:49
En fait je vois que tu l'as déja gardé en champ de ta classe .. Es tu sûr de la convention d'appel Cdecl de ton callback et Le MarshalAs(UnmanagedType.FunctionPtr) me surprend, moi je ne l'aurais pas mis.
0
railarmenien Messages postés 4 Date d'inscription mercredi 11 octobre 2006 Statut Membre Dernière intervention 17 décembre 2009
17 déc. 2009 à 13:03
Oui je garde une référence sur mon callback dans le code C#

J'ai d'ailleurs retiré le MarshalAs(UnmanagedType.FunctionPtr) du membre privé référencant le callback en C#

Concernant la convention d'appel du callback je ne suis sur de rien non plus.. l'interop c'est tout nouveau pour moi :)

Sur un autre forum on m'a proposé d'utiliser Marshal.GetFunctionPointerForDelegate mais je n'arrive pas à l'utiliser correctement.

Si quelqu'un avait un exemple complet ou la correction ca mer permettrait de bien avancer sur ce petit developpement.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 déc. 2009 à 14:40
As tu retiré le [MarshalAs(UnmanagedType.FunctionPtr)] de la fonction Init, c'est celui qui me gêne le plus. La définition C++ de HOOKPROC est en __stdcall donc change l'attribut UnmanagedFunctionPointer.

Si ça plante encore test le GCHandle. ( l'exemple est en C++/CLI )

mediaEvent = gcnew MFMediaEvent(
this, &::Windows::Media::MediaPlayer::OnMediaEvent );
GCHandle::Alloc( mediaEvent ); // Prevent GC.
hr = playerPtr->SetMediaEvent( ( MFMEDIAEVENT )
Marshal::GetFunctionPointerForDelegate( mediaEvent ).ToPointer( ) );
Marshal::ThrowExceptionForHR( hr );
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 déc. 2009 à 14:49
ah mince je te parle de HOOKPROC alors que tu ne l'utilise pas directement mais tu utilises ton propre callback.
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
17 déc. 2009 à 15:05
J'avais pas vu non plus mais le prototype managé des fonctions exportées doit être en StdCall ou rien vu que c'est la convention par défaut.
0
Rejoignez-nous