![]()
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
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).
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.
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.
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.
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.
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 !
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_ .
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]
[Actualités]
[Trucs
& Astuces]
[Astuces Windows]
[ActiveX-Ocx/Dll]
[Articles]
[Codes Sources]
[VB
Games]
[Fichiers Sons]
[Fichiers Icônes]
[Programmes & Sources]
[Mailing-List]
[Divers]
[A Propos]