INTERCEPTION DES MESSAGES WINDOWS : LE SOUS-CLASSEMENT

Introduction
Changer la Procédure Windows
Création de la nouvelle Procédure Windows
Quelques Messages Windows
Renvoi des messages non-traités
Désactiver le sous-classement
Constantes et Fonctions
Téléchargement

Introduction

Quand Windows envoie un message à une fenêtre de votre application, Visual Basic vous laisse executer quelques commandes dans la procédure d'évènement (ex: form_click, Text1_Change) correspondante et ensuite il gère automatiquement le reste. Certes c'est plus facile de laisser Visual Basic gérer vos messages, mais il y a certains messages que Visual Basic ne vous donne par l'occasion d'intercepter dans votre code à travers les procédures d'évènement.

Retenez tout d'abord qu'une fenêtre peut être un bouton de commande, une feuille, une zone de texte, une zone de liste,... bref tout contrôle. Et qu'une fenêtre est basée sur une classe. Chaque classe (fenêtre) possède une propriété dont la valeur est une adresse vers une "Procédure Windows" (WndProc) qui est chargée de gérer les messages arrivant à cette classe.

Cet article vous montre donc comment intercepter tous les messages parvenant à une fenêtre. Il s'agit d'une technique appelée le sous-classement (subclassing en anglais).

Changer la Procédure Windows

C'est la Procédure Windows d'une fenêtre qui est chargée de gérer tous les messages arrivant à cette fenêtre. L'apparence et le comportement d'une fenêtre dépendent de la réponse de la procédure à ces messages. Visual Basic "associe par défaut" une procédure à chacune des fenêtres (+contrôles) que vous créez pour gérer les messages de ceux-ci.

Vous comprenez donc que pour intercepter tous les messages d'une fenêtre il faut changer la procédure gérant ces messages. L'ancienne Procédure Windows de la fenêtre sera remplacée par une nouvelle Fonction CallBack chargée de gérer les messages. La fonction API SetWindowLong permet de le faire:

Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Le paramètre hwnd

Spécifie le handle de la fenêtre dont vous souhaitez modifier la Procedure Windows. Ex: form1.hwnd, Command1.hwnd, Text1.hwnd...

Le paramètre nIndex

Ce paramètre indique à la fonction SetWindowLong quelle propriété on veut modifier sur la fenêtre spécifiée par hwnd. Il peut prendre une valeur parmi plusieurs constantes. Puisqu'on veut modifier sa Procédure Windows, on doit spécifier la constante GWL_WNDPROC. NOTE: Une liste des déclarations de toutes les constantes utilisées dans cet article figure en bas de page.

Le paramètre dwNewLong

Spécifie la nouvelle valeur à attribuer à la propriété spécifiée par nIndex. Dans ce cas, on doit passer en paramètre l'Adresse Mémoire de la nouvelle Procédure Windows (ici, notre nouvelle Fonction Callback).

Valeur renvoyée

Si la fonction réussit, la valeur renvoyée est l'adresse mémoire de la précédente Procédure Windows.
Si la fonction échoue, la valeur renvoyée est 0. NOTE: la fonction échoue aussi si la fenêtre spécifiée par hwnd n'appartient pas au même process que le thread qui a appelé la fonction.

Exemple

Le code ci-dessous, remplace l'ancienne Procedure Windows par une nouvelle Procédure (la fonction callback MyWndProc). L'adresse de l'ancienne procédure est ensuite gardée dans la variable OldWndProc.

Dim OldWndProc As Long
OldWndProc = SetWindowLong(Form1.hwnd, GWL_WNDPROC, AddressOf MyWndProc)

Il faut maintenant créer la fonction MyWndProc.

Création de la nouvelle Procédure Windows

Pour communiquer avec notre application, Windows va nous envoyer des messages à travers la nouvelle fonction MyWndProc. La structure de la fonction est pré-définie et correspond à celle-ci:

Function MyWndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

End Function

Pour nous contacter, Windows va appeler cette fonction. Voici une explication des valeurs que chacun de ces paramètres peut contenir.

Le paramètre hwnd

Contient le Handle de la fenêtre pour laquelle on fait un sous-classement.

Le paramètre Msg

Contient le message envoyé par Windows. La liste de quelques uns de ces messages figure plus loin dans cet article.

Les paramètres wParam et lParam

Contiennent des données additionnelles. Leurs contenus dépendent du paramètre Msg.

Quelques Messages Windows

Les messages Windows sont des constantes qui ont généralement pour préfixe WM_ . Le paramètre Msg de la fonction WndProc peut contenir la valeur d'une de ces constantes, parmi lesquelles:

La constante WM_MOVE

Ce message est envoyé à une fenêtre après que cette dernière ait été déplacée. Le low-order word (LOWORD) du paramètre lParam contient la nouvelle abscisse de la fenêtre et le high-order word (HIWORD) du paramètre lParam contient la nouvelle ordonnée de la fenêtre. NOTE: Nous verrons plus loin la fonction qui permet de convertir un Long en un LOWORD ou HIWORD.

La constante WM_POWER

Ce message est envoyé à une fenêtre quand le système (généralement alimenté par des bateries) est prêt à entrer en mode suspendu (manque d'energie). Dans ce cas, le paramètre wParam peut contenir la valeur d'une de ces constantes:
PWR_SUSPENDREQUEST : Indique que le système est en train d'entrer en mode suspendu.
PWR_SUSPENDRESUME : Indique que le système est en train de resumer (revenir à une alimentation normale) après être entré en mode suspendu en envoyant un PWR_SUSPENDEDREQUEST.
PWR_CRITICALRESUME : Indique que le système est en train de resumer (alimentation normale) après être entré en mode suspendu sans signaler un PWR_SUSPENDEDREQUEST.
A Chacun de ces messages, il convient de faire les sauvegardes nécessaires.

La constante WM_CAPTURECHANGED

Ce message est envoyé à une fenêtre quand elle perd la capture du pointeur de la souris. Dans ce cas, le paramètre lParam contient le Handle de la fenêtre qui gagne la capture du pointeur de la souris. Ce message vous permet de contrôler les mouvements du pointeur sur votre feuille.

La constante WM_DRAWCLIPBOARD

Ce message est envoyé à la première fenêtre dans la chaîne des visionneurs de presse-papier (Clipboard Viewers) lorsque le contenu du presse-papier change. NOTE: vous devez d'abord enregistrer votre fenêtre dans la liste des Clipboard Viewers avec la fonction API SetClipboardViewer et ensuite utiliser Clipboard.GetText pour récuperer le contenu du clipboard lorsque ce message arrive.

NOTE: il y a encore beaucoup d'autres messages Windows, tous commençant par le préfixe WM_. Ici je n'ai donné que quelques uns des messages que Visual Basic ne vous permet pas d'intercepter à travers les procédures d'évènement normales.

Renvoi des messages non-traités

Nous sommes capables d'intercepter TOUS les messages arrivant à une fenêtre, mais il est préférable de n'intercepter que les messages qu'on trouve utiles d'intercepter et ensuite de laisser Visual Basic gérer à son tour les autres ou les mêmes messages...

Pour permetre à Visual Basic de gérer les messages non-interceptés par notre fonction MyWndProc, on doit appeler à l'interieur de celle-ci la fonction CallWindowProc en passant comme paramètre l'adresse de l'ancienne Procédure Windows, et en recopiant les paramètres de MyWndProc vers les autres paramètres de CallWindowProc.

Exemple d'une Interception

Function MyWndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

On Error Resume Next
Dim retVal As Long

'// Interception des messages
Select Case Msg
'// On intercepte WM_DRAWCLIPBORAD
Case WM_DRAWCLIPBOARD
    frmMain.Label1.Caption = "Contenu Clipboard: " & Clipboard.GetText
Case Else '// Autres WM_XX que vous souhaitez
'// Intercepter
End Select

'// On demande que OldWndProc gère les messages courants
'// tels que les clicks,les Load, et autres...
retVal = CallWindowProc(OldWndProc, hwnd, Msg, wParam, lParam)


'// Retourne la valeur du traitement de OldWndProc à Windows
MyWndProc = retVal
End Function

Cet exemple obtient en temps réel le contenu du clipboard. NOTE: pour cet exemple, la fenêtre frmMain doit être enregistrée dans le Clipboard Viewers avec SetClipboardViewer.

Désactiver le Sous-Classement

Au déchargement de la feuille, il faut toujours Explicitement désactiver le sous-classement d'une fenêtre en lui remettant sa Procédure Windows originale. Si vous ne le faites pas, la procédure d'évènement Form_Unload provoque une erreur de protection générale (GPF).

Pour donc arrêter le sous-classement d'une fenêtre, il faut de nouveau appeler la fonction SetWindowLong dans la procédure Form_Unload de la fenêtre. Mais maintenant vous spécifiez l'ancienne Procédure Windows comme valeur du paramètre dwNewLong.

Dim retValue As Long
retValue = SetWindowLong(Form1.hwnd, GWL_WNDPROC, AddressOf OldWndProc)

N'oubliez surtout pas de le faire !

Constantes et Fonctions

Nous avons utilisé dans cet article des constantes et fonctions de l'API Windows, cette section présente leurs déclarations.

Constantes

Public Const GWL_WNDPROC = (-4)
Public Const WM_MOVE = &H3
Public Const WM_POWER = &H48
Public Const PWR_SUSPENDRESUME = 2
Public Const PWR_SUSPENDREQUEST = 1
Public Const PWR_CRITICALRESUME = 3
Public Const WM_DRAWCLIPBOARD = &H308

Fonctions API

Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long


Public Declare Function SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long

Fonctions LOWORD et HIWORD

Function HiWord(dw As Long) As Integer
  If dw And &H80000000 Then
    HiWord = (dw \ 65535) - 1
  Else
    HiWord = dw \ 65535
  End If
End Function


Function LoWord(dw As Long) As Integer
  If dw And &H8000& Then
    LoWord = &H8000 Or (dw And &H7FFF&)
  Else
    LoWord = dw And &HFFFF&
  End If
End Function

Vous pouvez utiliser la Visionneuse API pour avoir une liste complète des messages Windows. Ces messages commencent par WM_ .

Téléchargement

Pour vous accompagner dans la lecture, voici l'ensemble des programmes et listings présentés dans cet article.

SubClassing.zip - Téléchargez le zip qui contient un programme qui affiche dans la fenêtre debug la totalité des messages qui parviennent à une fenêtre.

SubClassMenu.zip - Téléchargez le zip qui contient un programme qui, avec la technique du sous-classement, affiche dans une barre d'état le texte correspondant à un élément de menu lorsque celui-ci est sélectionné (a le focus).

[Home] lienie.gif (941 octets)[Actualités]  [Trucs & Astuces] [Astuces Windows] [ActiveX-Ocx/Dll] [Articles] [Codes Sources] [VB Games] [Fichiers Sons] [Fichiers Icônes] [Programmes & Sources]  mailing.gif (910 octets)[Mailing-List] smiley.gif (359 octets)[Divers] about.gif (920 octets)[A Propos]