Écriture de la procédure de fenêtre
La fonction DispatchMessage appelle la procédure de fenêtre de la fenêtre qui est la cible du message. La procédure de fenêtre a la signature suivante.
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Il existe quatre paramètres :
- hwnd est un handle de la fenêtre.
- uMsg est le code du message ; par exemple, le message WM_SIZE indique que la fenêtre a été redimensionnée.
- wParam et lParam contiennent des données supplémentaires relatives au message. La signification exacte dépend du code du message.
LRESULT est une valeur entière que votre programme retourne à Windows. Il contient la réponse de votre programme à un message particulier. La signification de cette valeur dépend du code du message. CALLBACK est la convention d’appel de la fonction.
Une procédure de fenêtre classique est simplement une instruction switch volumineuse qui active le code du message. Ajoutez des cas pour chaque message que vous souhaitez gérer.
switch (uMsg)
{
case WM_SIZE: // Handle window resizing
// etc
}
Les données supplémentaires du message sont contenues dans les paramètres lParam et wParam. Les deux paramètres sont des valeurs entières de la taille d’une largeur de pointeur (32 bits ou 64 bits). La signification de chacun dépend du code du message (uMsg). Pour chaque message, vous devrez rechercher le code du message et convertir les paramètres au type de données correct. En règle générale, les données sont une valeur numérique ou un pointeur vers une structure. Certains messages n’ont pas de données.
Par exemple, la documentation du message WM_SIZE indique que :
- wParam est un indicateur qui indique si la fenêtre a été réduite, agrandie ou redimensionnée.
- lParam contient les nouvelles largeur et hauteur de la fenêtre sous forme de valeurs 16 bits regroupées dans un nombre de 32 ou 64 bits. Vous devrez effectuer un décalage de bits pour obtenir ces valeurs. Heureusement, le fichier d’en-tête WinDef.h inclut des macros d’assistance qui effectuent cette opération.
Une procédure de fenêtre classique gère des dizaines de messages, de sorte qu’elle peut être très longue. Une façon de rendre votre code plus modulaire consiste à placer la logique de gestion de chaque message dans une fonction distincte. Dans la procédure de fenêtre, castez les paramètres wParam et lParam vers le type de données approprié, puis transmettez ces valeurs à la fonction. Par exemple, pour gérer le message WM_SIZE, la procédure de fenêtre se présente comme suit :
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
{
int width = LOWORD(lParam); // Macro to get the low-order word.
int height = HIWORD(lParam); // Macro to get the high-order word.
// Respond to the message:
OnSize(hwnd, (UINT)wParam, width, height);
}
break;
}
}
void OnSize(HWND hwnd, UINT flag, int width, int height)
{
// Handle resizing
}
Les macros LOWORD et HIWORD obtiennent les valeurs de largeur et de hauteur 16 bits de lParam. La procédure de fenêtre extrait la largeur et la hauteur, puis transmet ces valeurs à la fonction OnSize
.
Gestion des messages par défaut
Si vous ne gérez pas un message particulier dans votre procédure de fenêtre, passez les paramètres de message directement à la fonction DefWindowProc. Cette fonction effectue l’action par défaut pour le message, qui varie selon le type de message.
return DefWindowProc(hwnd, uMsg, wParam, lParam);
Éviter les goulots d’étranglement dans votre procédure de fenêtre
Pendant qu’elle s’exécute, votre procédure de fenêtre bloque tous les autres messages pour les fenêtres créées sur le même thread. Ainsi, évitez les traitements longs à l’intérieur de votre procédure de fenêtre. Par exemple, supposons que votre programme ouvre une connexion TCP et attend indéfiniment que le serveur réponde. Si vous effectuez cette opération à l’intérieur de la procédure de fenêtre, votre interface utilisateur ne répond pas tant que la demande n’est pas terminée. Pendant ce temps, la fenêtre ne peut pas traiter l’entrée de la souris ou du clavier, se repeindre elle-même ou même se fermer.
Au lieu de cela, vous devez déplacer le travail vers un autre thread, en utilisant l’une des fonctionnalités multitâche intégrées à Windows :
- Créer un thread.
- Utiliser un pool de threads.
- Utiliser des appels d’E/S asynchrones.
- Utiliser des appels de procédure asynchrones.