IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Principe du Hook et utilisation d'un Hook souris

Principe du Hook et utilisation d'un Hook souris


précédentsommairesuivant

IV. Implémentation

IV-A. Introduction

Nous allons présenter ici, les différentes API mises en oeuvre dans le cadre de la création d'un Hook.

IV-B. SetWindowsHookEx

IV-B-1. Présentation

Cette API permet la mise en place d'une procédure de traitement au sein d'une des chaînes de traitement de messages :

SetWindowsHookEx
Sélectionnez
    <DllImport("user32")> _
    Public Shared Function SetWindowsHookEx( _
        ByVal idHook As Integer, _
        ByVal lpfn As HookProc, _
        ByVal hMod As IntPtr, _
        ByVal dwThreadId As Integer) As Integer
    End Function

La procédure de traitement installée par le Hook l'est toujours en début de chaîne.
(Cela signifie que c'est toujours la procédure de traitement installée par le dernier Hook qui est déclenchée la première).

IV-B-2. Paramètres

IV-B-2-a. idHook

Il s'agit du type de Hook à mettre en place :

  • Hook sur les messages clavier (WH_KEYBOARD_LL et WH_KEYBOARD),
  • Hook sur les messages souris (WH_MOUSE_LL et WH_MOUSE),
  • Hook sur les messages de création/destruction de fenêtres de premier plan (WH_SHELL),
  • etc.

IV-B-2-b. lpfn

C'est un pointeur sur la procédure de traitement à inscrire dans la chaîne de traitement.

Comme pour toute utilisation d'un délégué passé à du code non managé, l'application devra s'assurer du maintien du pointeur sur ce délégué afin d'éviter sa collecte inopinée par le Garbage Collector.

Le passage d'un "AddressOf NomDeLaProcédure" est donc à proscrire, et il convient d'utiliser une fonction déléguée déclarée explicitement.

La signature de la procédure de traitement ne dépendant pas du type de Hook, on pourra utiliser le délégué suivant :

Hook Procedure
Sélectionnez
	Public Delegate Function HookProc _
	(ByVal nCode As Integer, _ 
	 ByVal wParam As Integer, _ 
	 ByVal lParam As IntPtr) As Integer

Les valeurs des paramètres passés à la fonction seront par contre dépendantes du type de Hook.

Cette procédure pourra retourner une valeur différente de 0 pour indiquer au système que le message a été traité (celui-ci ne communiquera alors pas ce message à la fenêtre cible).

Toutefois, elle ne devra traiter le message que si le paramétre ncode est supérieur à 0. Dans le cas contraire, elle devra retourner le résultat de l'appel à l'API CallNextHookEx (décrite plus loin).

IV-B-2-c. hMod

C'est le Handle de la DLL contenant la procédure pointée par lpfn.

Ce paramètre peut être omis (par cela entendez, valorisé à IntPtr.Zero) dans le cas où cette procédure de traitement se trouve dans le même module que l'installation via SetWindowsHookEx.

Ceci est vrai qu'il s'agisse d'un Hook Global ou d'un Hook Local.

A titre personnel, je n'utilise donc pas ce paramètre car il me semble opportun de gérer la mise en place et la suppression du Hook au travers d'un objet levant au besoin un événement. L'ensemble du code de Hooking s'en trouve donc intégralement dans le même module.

IV-B-2-d. dwthreadId

C'est l'identifiant du thread pour lequel le Hook est positionné.

Ce paramètre valorisé à 0 équivaut à positionner un Hook pour l'ensemble des threads.

Donc :

  • Si dwthreadId est alimenté avec l'identifiant d'un thread, il s'agira d'un Hook Local, i.e. localisé sur ce thread,
  • Si dwthreadId n'est pas défini (0), il s'agira d'un Hook Global, i.e. pour l'ensemble des threads.

IV-B-3. Valeur retournée

Si le positionnement de la procédure de traitement au sein de la chaîne a réussi, SetWindowsHookEx retourne le Handle de la procédure de Hook.

En cas d'échec, la valeur retournée est 0 et le code erreur peut être obtenu via l'API GetLastError.

GetLastError
Sélectionnez
	<DllImport("kernel32")> _
	Public Shared Function GetLastError() As Integer
	End Function

IV-B-4. Utilisation

Dans le cadre d'un Hook souris global, l'utilisation de SetWindowsHookEx peut se présenter ainsi :

Utilisation de SetWindowsHookEx
Sélectionnez
	Public Delegate Function HookProc(ByVal nCode As Integer, _
		ByVal wParam As Integer, _
		ByVal lParam As IntPtr) As Integer
	Private Shared hMouseHook As Integer
	Private Shared MouseHookProcedure As HookProc

	<DllImport("user32")> _
	Public Shared Function SetWindowsHookEx( _
		ByVal idHook As Integer, _
		ByVal lpfn As HookProc, _
		ByVal hMod As IntPtr, _
		ByVal dwThreadId As Integer) As Integer
	End Function
	<DllImport("kernel32")> _
	Public Shared Function GetLastError() As Integer
	End Function
	#Region "Declaration constantes"
	    Protected Const WH_MOUSE_LL As Integer = 14
	#End Region
	
	Protected Sub StartHookingInternal()
	    ' Evite le CallbackOnCollectedDelegate
	    MouseHookProcedure = New HookProc(AddressOf MouseHookProc)
	    hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, _
	    IntPtr.Zero, 0)
	    If hMouseHook = 0 Then
	        MessageBox.Show("Echec de l'installation du hook : " & GetLastError())
	    Else
	        MessageBox.Show("Start effectué")
	    End If
	End Sub
	
	Private Function MouseHookProc(ByVal nCode As Integer, _
		ByVal wParam As Integer, _
		ByVal lParam As IntPtr) As Integer
	
	    ' Traitement
	    ' --> ici
	
	End Function

IV-C. CallNextHookEx

IV-C-1. Présentation

Cette API permet de passer les informations du message en cours de traitement à la procédure suivante dans la chaîne de traitement.

CallNextHookEx
Sélectionnez
    <DllImport("user32")> _
    Public Shared Function CallNextHookEx( _
		ByVal hhk As Integer, _
        ByVal nCode As Integer, _
        ByVal wParam As Integer, _
        ByVal lParam As IntPtr) As Integer
    End Function

L'appel à cette fonction doit être réalisé dans la procédure de traitement positionnée par SetWindowsHookEx (c'est à dire dans la procédure déléguée).

Sa valeur de retour correspond à la réponse fournie par la procédure de traitement du Hook suivant de la chaîne.

Une procédure de traitement retournera une valeur différente de 0 pour indiquer au système que le message a été traité et qu'il n'est pas nécessaire de le communiquer à la fenêtre cible.

En l'absence d'un blocage nécessaire du message dans la procédure de traitement de notre Hook, celle-ci doit rendre le résultat fourni par la procédure de traitement du Hook suivant de la chaîne.

Une chaîne de traitement non bloquante pour le message peut donc se représenter ainsi :
Image non disponible


Ainsi l'utilisation de CallNextHookEx peut de manière générale se décliner à partir de :

Utilisation de CallNextHookEx
Sélectionnez
	Public Delegate Function HookProc _
		(ByVal nCode As Integer, _ 
		ByVal wParam As Integer, _ 
		ByVal lParam As IntPtr) As Integer
	
	Private InternalHookProcedure As HookProc
	Private Shared hHook As Integer
	
	Protected Sub StartHookingInternal()
	    InternalHookProcedure = New HookProc(AddressOf InternalHookProc)
	    hHook = SetWindowsHookEx( xxxxxx , MouseHookProcedure, _
	    yyyy , zzzzz )
	End Sub
	
	Private Function InternalHookProc(ByVal nCode As Integer, _
		ByVal wParam As Integer, _
		ByVal lParam As IntPtr) As Integer
	
	' Traitement du message ici
	
	    Return CallNextHookEx( hHook, nCode, wParam, lParam)
	
	End Function

Se passer de l'appel à CallNextHookEx est fortement déconseillé.
En effet, on ne sait pas dans quelle position de la chaîne se trouve notre Hook et il est donc impossible de déterminer à priori l'effet du non déclenchement des procédures de traitement positionnées en aval de celui-ci par les autres applications.

Ceci sera illustré dans la suite de l'article.

IV-C-2. Paramètres

Les paramètres utilisés sont ceux obtenus par la procédure de traitement auxquels s'ajoute le paramètre hhk qui doit être alimenté avec le Handle de le procédure de Hook courant (retourné par SetWindowsHookEx)

IV-C-3. Valeur retournée

La valeur de retour correspond à la réponse fournie par la procédure de traitement du Hook suivant de la chaîne.

IV-C-4. Utilisation

Dans le cadre de notre exemple pour un Hook souris global, l'utilisation de CallNextHookEx peut se présenter ainsi :

Utilisation de CallNextHookEx
Sélectionnez
	<DllImport("user32")> _
	Public Shared Function CallNextHookEx( _
		ByVal hhk As Integer, _
	    ByVal nCode As Integer, _
	    ByVal wParam As Integer, _
	    ByVal lParam As IntPtr) As Integer
	End Function
	Private Function MouseHookProc(ByVal nCode As Integer, 
		ByVal wParam As Integer, 
		ByVal lParam As IntPtr) As Integer
	
	' Traitement
	' --> ici
	
		Return CallNextHookEx(hMouseHook, nCode, wParam, lParam)
	
	End Function

IV-D. UnhookWindowsHookEx

IV-D-1. Présentation

Cette API permet de retirer la procédure de traitement de la chaîne de procédures de traitement .

Toute installation d'un Hook via SetWindowsHookEx doit être suivie d'une désinstallation via UnhookWindowsHookEx, car le Hook génère un ralentissement du traitement des messages systèmes.

Les règles de "bonne conduite" à retenir sont donc :
- Installer le Hook le plus TARD possible via SetWindowsHookEx,
- Désinstaller le Hook le plus TOT possible via UnhookWindowsHookEx.

UnhookWindowsHookEx
Sélectionnez
    <DllImport("user32")> _
    Public Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
    End Function

IV-D-2. Paramètres

UnhookWindowsHookEx accepte un seul paramètre hhk définissant le Handle de le procédure de Hook à désinstaller (retourné par SetWindowsHookEx)

IV-D-3. Valeur retournée

La fonction retourne True si la désinstallation a réussi, False sinon.

IV-C-4. Utilisation

Dans le cadre de notre exemple pour un Hook souris global, l'utilisation de UnhookWindowsHookEx peut se présenter ainsi :

Utilisation de UnhookWindowsHookEx
Sélectionnez
	<DllImport("user32")> _
	Public Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
	End Function
	Protected Overrides Sub StopHookingInternal()
	    Dim blnUH As Boolean = True
	    blnUH = UnhookWindowsHookEx(hMouseHook)
	    MyBase.OnMouseLog("Stop effectué")
	End Sub

précédentsommairesuivant

Copyright © 2008 Anthony DE DECKER. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.