Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

aKhEnAtHoN's Blog

The samouraï way

Le Hook - Partie1

Le HOOK - Quesako :

   On va commencer en douceur, pour les débutants. Le hook, c'est une méthode utilisée en programmation Windows. Elle permet de recevoir les messages que le système envoie à une application. L'utilisation de cette méthode nécessite une assez bonne connaissance du fonctionnement d'une application Windows. On va donc commencer par expliquer les fondements de communication entre les applications et Windows.

Les messages entre les applications :

   Voilà donc l'OS, et deux applications. Comme on peut le voir, elles s'envoient des messages, et peuvent communiquer avec l'OS.

   Maintenant vous êtes en droit de vous demander pourquoi tous ces logiciels communiquent... Et bien car ils ont besoin d'être pilotés. Une application ne va pas gérer elle-même les événements de la souris. C'est plutôt les drivers qui sont là pour ça (transformer les valeurs des signaux analogiques en valeurs informatiques - un X et Y pour une souris).

   Bref, l'OS va gérer une multitude de signaux, et les redistribuer pour l'application concernée. Attention, on va rentrer dans le vif du sujet (lol).

Le Hook - Méthode :

  Je viens donc de vous expliquer en gros pourquoi on à des messages qui circulent sans cesse entre windows et les applications. Les messages sont des appels vers des fonctions, des points d'entrées dans le logiciel (CF ASM), qui lui saura comment réagir en les recevant. Le hook permet de changer ce point d'entrée, et lui indiquer une fonction que vous aurez à loisir le choix de la modifier.

   Bien entendu vous devrez ensuite rediriger ce message vers le point d'entrée original de l'application, à moins que vous souhaitiez inhiber ce message.

Les APIS de windows :

   Pour parvenir à hooker une application vous devrez utiliser des fonctions de Windows, lui indiquant où causer avec l'application.

   On va prendre un petit exemple, pour créer notre application et le hook. Je souhaite savoir l'événement MouseOut sur un boutton de la feuille. En codant comme un amateur, j'aurais mis mon bouton, une fonction mouse_out par exemple, et je l'aurais appelée quand je recevais un événement MouseMouve sur les autres éléments de la feuille.

Code de bourin :

Private Sub Command1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
   Command1.Caption = "over"
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
   Call BtnMouseOut
End Sub

Public Function BtnMouseOut()
   Command1.Caption = "out"
End Function

   Pourquoi c'est un code de bourrin ? Ben c'est simple, faut écrire 'Call BtnMouseOut' dans tous l'événement MouseMove de tous les objets de la feuille. Imaginons que je veuille avoir 10 boutons avec un mouse out...

   Un peu mieux, j'aurais pu mettre un timer, prendre les coordonnées de la souris, et savoir en fonction de ces coordonnées le handle de l'objet survolé. Pourquoi pas :

Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Sub Timer1_Timer()
   Dim pt As POINTAPI
   Dim
hBtn As Long
   GetCursorPos pt
   hBtn = WindowFromPoint(pt.X, pt.Y)
   If hBtn = Command1.hWnd Then
      Command1.Caption = "over"
   Else
      Command1.Caption = "out"
   End If
End Sub

   Là oui, je peux gérer autant de boutons que je veux... le code est déjà mieux construit. Mais, car il y a toujours un mais :) ... je ne suis pas satisfait. Le timer, je lui met combien d'intervalle ? Et puis si l'intervalle est trop court, il va ramer, trop long, il va pas se rafraichir assez vite. Imaginez au niveau optimisation, le nombre d'instructions qu'il doit faire par milli-seconde pour gérer un mouseover/mouseout sur une feuille pour 10 boutons ... Faudrait compter en temps horloge, mais je pense qu'à vu d'œil ça dépasse le 40 instructions assembleur. Vous vous dites, bof je m'en fout, j'ai un superbe PC, et puis ils boostent les pc de nos jours. Ben je vous dirais, de toute façon pour les applications que tu veux faire (un carnet d'adresse ou un bloc notes) , l'optimisation ne compte pas.

   Maintenant envisageons d'utiliser le hook pour intercepter les événements de la souris. Quel est l'avantage ? Une aussi bonne gestion que dans l'exemple 2, avec un appel vers notre fonction que seulement quand la souris est sur la feuille. En gros, le timer avec un intervalle 1, c'est oublié. On exécute une fonction que quand on en à besoin.

Alors voilà un exemple, je vous l'explique après :

Dans un form nomé Form1 on aura ce code :
Private Const WH_MOUSE = 7

Private Function HookAdr(adr As Long) As Long
   HookAdr = adr
End Function

Private Sub Form_Load()
    Dim hmod As Long
    hmod = HookAdr(AddressOf MouseProc)
    Module1.hHook = SetWindowsHookEx(WH_MOUSE, hmod, App.hInstance, App.ThreadID)
End Sub
Private Sub Form_Unload(Cancel As Integer)
    UnhookWindowsHookEx Module1.hHook
End Sub

Dans un module nomé Module1 on aura ceci :
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Function
SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Type MOUSEHOOK
   pt As POINTAPI
   hWnd As Long
   wHit As Long
   dwExtra As Long
End Type

Public hHook As Long
Const WM_MOUSEMOVE = &H200

Public Function MouseProc(ByVal idHook As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Dim MouseParam As MOUSEHOOK
    If idHook >= 0 Then
      If wParam = WM_MOUSEMOVE Then
         CopyMemory MouseParam, ByVal lParam, Len(MouseParam)
         With Form1
            If MouseParam.hWnd = .Command1.hWnd Then
               If .Command1.Tag <> "over" Then
                  .Command1.Caption = "over"
                  .Command1.Tag = "over"
               End If
            Else
               If .Command1.Tag <> "out" Then
                  .Command1.Caption = "out"
                  .Command1.Tag = "out"
               End If
            End If
         End With
      End If
    End If
    MouseProc = CallNextHookEx(hHook, idHook, wParam, ByVal lParam)
End Function

Vous pouvez télécharger cet exemple en cliquant ici.

   On va commencer par la feuille Form1. Lors de son événement de chargement (FormLoad) on va appeler le Hook. La fonction SetWindowsHookEx permet donc de dire au système que le point d'entrée des événements dans le soft se trouverons à l'adresse de la fonction MouseProc, qui elle sera définie dans le module. Pour avoir l'adresse d'une fonction en VB, il faut utiliser la fonction AdressOf. J'ai implémenté très rapidement une fonction s'appelant HookAdr, celle-ci permettant de récupérer l'adresse de la fonction dans une variable Long.

   Ensuite comme vous pouvez le voir, j'indique au système une fois que le logiciel se termine (FormUnload) de restaurer l'adresse du point d'entrée initial.

   Bon tout ceci est vraiment exhaustif, mais vous pourrez trouver des explications des fonctions que j'ai écrit sur MSDN, VBFrance ou ProgOTop (De plus dans les prochaines parties, je serais plus technique et plus complet - promis)

   On va maintenant passer à la partie Module :) ! Alors le module est composé des déclarations au tout début, puis de cette fameuse fonction MouseProc. Pour les déclarations, je vous conseille un copier/coller... c'est le béa bat de tout codeur de savoir déclarer une fonction d'API.

   Pour ce qui est de la fonction MouseProc elle doit obligatoirement porter la même signature. En gros, elle doit déclarer en entrée 3 variables Long et retourner une variable Long aussi. Dans ces variables on passera en valeur les messages que l'OS veut faire parvenir au logiciel :

      If wParam = WM_MOUSEMOVE Then
         CopyMemory MouseParam, ByVal lParam, Len(MouseParam)

   Par exemple wParam indiquera le type d'événement généré. Ensuite lParam est dans notre cas le pointeur vers la structure déclarée plus haut. Pour retrouver ses valeurs j'utilise donc CopyMemory. Ensuite ce n'est qu'une suite de tests ...

   Je vais essayer de rédiger la suite de cet article dés que j'aurais le temps, car les possibilités du Hook sont immenses, surtout si vous programmez des composants ActiveX ou des classes.

Bonne prog à tous, aKh

 

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: mardi 22 juin 2004 11:40 par akhenathon

Commentaires

TrackBack a dit :

# juin 23, 2004 14:16

akhenathon a dit :

article interessant pour un debutant
# mars 29, 2005 14:27

akhenathon a dit :

interessant
# mars 29, 2005 14:29

akhenathon a dit :

un peu légé !
# mai 4, 2005 21:55
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Merci par Blog de Jérémy Jeanson le 10-01-2019, 20:47

- Office 365: Script PowerShell pour auditer l’usage des Office Groups de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 11:02

- Office 365: Script PowerShell pour auditer l’usage de Microsoft Teams de votre tenant par Blog Technique de Romelard Fabrice le 04-26-2019, 10:39

- Office 365: Script PowerShell pour auditer l’usage de OneDrive for Business de votre tenant par Blog Technique de Romelard Fabrice le 04-25-2019, 15:13

- Office 365: Script PowerShell pour auditer l’usage de SharePoint Online de votre tenant par Blog Technique de Romelard Fabrice le 02-27-2019, 13:39

- Office 365: Script PowerShell pour auditer l’usage d’Exchange Online de votre tenant par Blog Technique de Romelard Fabrice le 02-25-2019, 15:07

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Stream Portal par Blog Technique de Romelard Fabrice le 02-21-2019, 17:56

- Office 365: Script PowerShell pour auditer le contenu de son Office 365 Video Portal par Blog Technique de Romelard Fabrice le 02-18-2019, 18:56

- Office 365: Script PowerShell pour extraire les Audit Log basés sur des filtres fournis par Blog Technique de Romelard Fabrice le 01-28-2019, 16:13

- SharePoint Online: Script PowerShell pour désactiver l’Option IRM des sites SPO non autorisés par Blog Technique de Romelard Fabrice le 12-14-2018, 13:01