Les bases de la programmation sous Windows


précédentsommairesuivant

III. Les messages

III-A. Introduction

Sous Windows, la communication entre une fenêtre et le système se fait par l'intermédiaire de messages. Par exemple, lorsqu'une fenêtre est redimensionnée, Windows envoie à celle-ci le message WM_SIZE pour l'informer de cet événement. Chaque fenêtre doit avoir une fonction, appelée procédure de fenêtre, que Windows appellera automatiquement chaque fois que la fenêtre a reçu un message. Afin qu'un message atteigne effectivement cette procédure de fenêtre, l'application doit explicitement envoyer le message à la procédure en question en appelant la fonction DispatchMessage.

Une procédure de fenêtre doit avoir le prototype suivant :

 
Sélectionnez
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

Bien entendu, on peut appeler la procédure de fenêtre y, Mocassin ou WindowProc au lieu de WndProc mais en l'appelant WndProc, notre code sera plus facile à lire par d'autres programmeurs puisque ce nom est largement utilisé dans la communauté des programmeurs Windows. Parlons maintenant du rôle de chaque paramètre de cette fonction.

Un message est en fait une structure déclarée dans winuser.h comme suit :

 
Sélectionnez
typedef struct tagMSG {
    HWND    hwnd;
    UINT    message;
    WPARAM  wParam;
    LPARAM  lParam;
    DWORD   time;
    POINT   pt;
} MSG;
  • hwnd identifie le destinataire du message.

  • message spécifie le message proprement dit (ex : WM_KEYDOWN, WM_SIZE, etc.).

  • wParam et lParam contiennent d'éventuelles informations supplémentaires concernant le message. Leur signification est donc entièrement dépendante du message.

  • time spécifie quand le message a été envoyé.

  • Et pt est une structure de type POINT qui contient la position du pointeur de la souris au moment où le message a été envoyé.

Lorsqu'on envoie un message à la procédure de fenêtre d'une fenêtre donnée (avec la fonction DispatchMessage), seuls les 4 premiers paramètres à savoir hwnd, message, wParam et lParam sont passés. La procédure de fenêtre étant chargée de traiter tous les messages reçus, son corps ressemble donc la plupart du temps à ceci :

 
Sélectionnez
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)
    {
    case XXXXX:
        /* Traitement du message XXXXX */
        break;

    case YYYYY:
        /* Traitement du message YYYYY */
        break;

    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return 0;
}

Une procédure de fenêtre normalement constituée ne doit jamais ignorer un message (sauf si vous êtes bien conscient de ce que vous faites). Si le message ne nécessite aucun traitement particulier (c'est d'ailleurs le cas de la plupart des messages), alors elle doit renvoyer ce message au système pour que ce dernier puisse effectuer un traitement par défaut. C'est le rôle de la fonction DefWindowProc.

Certains messages placent plus d'une information utile dans le paramètre wParam ou lParam. Par exemple, dans le cas du message WM_SIZE, wParam contient un entier qui spécifie comment la fenêtre a été redimensionnée et lParam les nouvelles dimensions de la fenêtre : la nouvelle largeur dans la partie basse (ou mot de poids le plus faible) et la nouvelle hauteur dans la partie haute (ou mot de poids le plus fort). Un mot représente une valeur sur 16 bits. Les types WPARAM et LPARAM sont définis de la manière suivante :

 
Sélectionnez
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;

Avec les types UINT_PTR et LONG_PTR définis comme suit :

 
Sélectionnez
#ifdef _WIN64
    typedef unsigned __int64 UINT_PTR;
    typedef __int64 LONG_PTR;
#else
    typedef unsigned int UINT_PTR;
    typedef long LONG_PTR;
#endif

Dans les versions 32 bits, WPARAM et LPARAM représentent donc des valeurs 32 bits.

Les macros LOWORD et HIWORD permettent d'extraire respectivement le mot haut et le mot bas d'une valeur DWORD (qui occupe 32 bits).

Comme nous pouvons le constater, les définitions des types et macros Windows peuvent varier d'une cible à une autre (32 ou 64 bits), mais c'est justement pourquoi ils faut les utiliser car ils permettent de compiler le même code pour des processeurs différents sans aucune modification.

Les paragraphes suivants présentent quelques messages assez courants.

III-B. Le message WM_CREATE

Envoyé lorsqu'une fenêtre a été créée, avant même que CreateWindow (ou CreateWindowEx) ne retourne. Paramètres :

  • lParam : adresse d'une structure de type CREATESTRUCT qui contient les paramètres qui ont été passées à CreateWindow (ou CreateWindowEx)

III-C. Le message WM_CLOSE

Envoyé lorsqu'une fenêtre est sur le point d'être fermée. Ce message est envoyé par exemple lorsque l'utilisateur a cliqué sur le bouton fermer. Si on passe ce message à DefWindowProc, la fonction DestroyWindow est appelée et la fenêtre sera donc détruite.

III-D. Le message WM_DESTROY

Envoyé lorsqu'une fenêtre est sur le point d'être détruite. Le terme détruire signifie vraiment détruire (c'est-à-dire libérer les ressources utilisées) et pas seulement fermer (cacher).

III-E. Le message WM_SIZE

Envoyé lorsqu'une fenêtre a été redimensionnée. Paramètres :

  • wParam : un entier qui spécifie comment la fenêtre a été redimensionnée. Par exemple :

Valeur Signification
0 Rien à signaler (la fenêtre a été redimensionnée ...)
SIZE_MAXIMIZED La fenêtre a été agrandie
SIZE_MINIMIZED La fenêtre a été réduite
SIZE_RESTORED La fenêtre a été restaurée
  • LOWORD(lParam) : la nouvelle largeur de la zone cliente

  • HIWORD(lParam) : la nouvelle hauteur de la zone cliente

III-F. Les messages provenant du clavier

III-F-1. Généralités

Ces messages sont envoyés à une fenêtre uniquement lorsque celle-ci a le focus de l'utilisateur c'est-à-dire quand elle est active.

III-F-2. Les messages WM_KEYDOWN et WM_KEYUP

Envoyés respectivement lorsqu'une touche a été enfoncée ou relâchée. Les paramètres sont les suivants :

  • wParam : le code (Virtual Key Code) de la touche ayant provoqué le message. Par exemple :
Code Touche
VK_TAB TAB
VK_ESCAPE ECHAP
VK_RETURN ENTREE
VK_BACK BACKSPACE
VK_DELETE DEL
VK_F1 F1
VK_F2 F2
VK_UP Fleche 'Haut'
VK_DOWN Fleche 'Bas'
VK_LEFT Fleche 'Gauche'
VK_RIGHT Fleche 'Droite'
'A' Touche A
'B' Touche B
'C' Touche C
  • lParam : contexte matériel (Repeat Count, Scan Code, etc.). Peu intéressant pour le moment.

Il arrive également assez souvent que l'on veuille connaître l'état d'une ou plusieurs touches auxiliaires (VK_SHIFT, VK_LSHIFT, VK_RSHIFT, VK_CONTROL, etc.) lorsqu'on traite les entrées de l'utilisateur, qu'il s'agisse d'une entrée provenant du clavier ou de la souris. Pour cela, on a la fonction :

 
Sélectionnez
int GetKeyState(int nVirtKey);

Qui retourne un entier indiquant l'état de la touche dont le code a été passé en argument. La signification de la valeur retournée par cette fonction est telle que :

  • Le bit de poids le plus faible indique si la touche est maintenue enfoncée.

  • Le bit de poids le plus fort (et si vous êtes malin, vous remarquez qu'il s'agit du bit de signe !) indique si la touche est togglée (s'utilise normalement avec des touches telles que VK_CAPSLOCK, VK_NUMLOCK, VK_SCROLL, etc.).

On peut également simuler un événement clavier avec la fonction :

 
Sélectionnez
void keybd_event(BYTE bVirtKey, BYTE bScanCode, DWORD dwFlags, DWORD dwExtraInfo);

Le paramètre dwFlags doit avoir la valeur 0 pour simuler l'enfoncement de la touche et KEYEVENTF_KEYUP pour simuler le relâchement de la touche. Il y a également une fonction, SendInput, qui est plus générique (peut simuler de nombreuses entrées et non uniquement des événements clavier) et qui permet de spécifier plus d'options.

III-F-3. Les messages WM_CHAR et WM_DEADCHAR

Ces messages sont générés à partir des messages WM_KEYDOWN et WM_KEYUP en réponse à un TranslateMessage. Les paramètres sont les mêmes sauf que wParam contient le code (ANSI ou Unicode selon le jeu de caractères que vous utilisez) du caractère au lieu de celui de la touche.

III-F-4. Les messages WM_SYSKEYDOWN et WM_SYSKEYUP

Envoyés lorsque la touche ALT (VK_MENU) a été enfoncée au moment de l'événement clavier.

III-G. Les messages provenant de la souris

Les messages suivants sont envoyés à la fenêtre active lorsque le pointeur de la souris se trouve à l'intérieur de sa zone cliente.

Message Evénement
WM_LBUTTONDOWN Bouton gauche enfoncé
WM_RBUTTONDOWN Bouton droit enfoncé
WM_MBUTTONDOWN Bouton du milieu enfoncé
WM_LBUTTONUP Bouton gauche relâché
WM_RBUTTONUP Bouton droit relâché
WM_MBUTTONUP Bouton du milieu relâché
WM_LBUTTONDBLCLK Double-clique avec le bouton gauche
WM_RBUTTONDBLCLK Double-clique avec le bouton droit
WM_MBUTTONDBLCLK Double-clique avec le bouton du milieu
WM_MOUSEMOVE Le curseur s'est déplacé


Les paramètres sont les suivants :

  • wParam : Etat des boutons et/ou de certaines touches clavier. Cette valeur peut être une ou une combinaison des valeurs (indépendantes) suivantes : MK_LBUTTON, MK_RBUTTON, MK_MBUTTON, MK_SHIFT, MK_CONTROL, ...

  • LOWORD(lParam) : Abscisse du pointeur de la souris

  • HIWORD(lParam) : Ordonnée du pointeur de la souris

Les coordonnées sont calculées par rapport au coin supérieur gauche de la zone cliente.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et 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.