Utilisation de procédures de fenêtre
Cette section explique comment effectuer les tâches suivantes associées aux procédures de fenêtre.
- Conception d’une procédure de fenêtre
- Association d’une procédure window à une classe Window
- Sous-classification d’une fenêtre
Conception d’une procédure de fenêtre
L’exemple suivant montre la structure d’une procédure de fenêtre classique. La procédure de fenêtre utilise l’argument message dans une instruction switch avec des messages individuels gérés par des instructions case distinctes. Notez que chaque cas retourne une valeur spécifique pour chaque message. Pour les messages qu’elle ne traite pas, la procédure de fenêtre appelle la fonction DefWindowProc .
LRESULT CALLBACK MainWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
switch (uMsg)
{
case WM_CREATE:
// Initialize the window.
return 0;
case WM_PAINT:
// Paint the window's client area.
return 0;
case WM_SIZE:
// Set the size and position of the window.
return 0;
case WM_DESTROY:
// Clean up window-specific data objects.
return 0;
//
// Process other messages.
//
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
Le message WM_NCCREATE est envoyé juste après la création de votre fenêtre, mais si une application répond à ce message en retournant FALSE, la fonction CreateWindowEx échoue. Le message WM_CREATE est envoyé une fois que votre fenêtre est déjà créée.
Le message WM_DESTROY est envoyé lorsque votre fenêtre est sur le point d’être détruite. La fonction DestroyWindow s’occupe de détruire toutes les fenêtres enfants de la fenêtre en cours de destruction. Le message WM_NCDESTROY est envoyé juste avant la destruction d’une fenêtre.
À tout le moins, une procédure de fenêtre doit traiter le message WM_PAINT pour qu’il se dessine lui-même. En règle générale, il doit également gérer les messages de souris et de clavier. Consultez les descriptions des messages individuels pour déterminer si votre procédure de fenêtre doit les gérer.
Votre application peut appeler la fonction DefWindowProc dans le cadre du traitement d’un message. Dans ce cas, l’application peut modifier les paramètres de message avant de transmettre le message à DefWindowProc, ou elle peut poursuivre le traitement par défaut après avoir effectué ses propres opérations.
Une procédure de boîte de dialogue reçoit un message WM_INITDIALOG au lieu d’un message WM_CREATE et ne transmet pas de messages non traités à la fonction DefDlgProc . Sinon, une procédure de boîte de dialogue est exactement la même qu’une procédure de fenêtre.
Association d’une procédure window à une classe Window
Vous associez une procédure de fenêtre à une classe de fenêtre lors de l’inscription de la classe . Vous devez remplir une structure WNDCLASS avec des informations sur la classe, et le membre lpfnWndProc doit spécifier l’adresse de la procédure de fenêtre. Pour inscrire la classe, passez l’adresse de la structure WNDCLASS à la fonction RegisterClass . Une fois la classe de fenêtre inscrite, la procédure de fenêtre est automatiquement associée à chaque nouvelle fenêtre créée avec cette classe.
L’exemple suivant montre comment associer la procédure de fenêtre dans l’exemple précédent à une classe de fenêtre.
int APIENTRY WinMain(
HINSTANCE hinstance, // handle to current instance
HINSTANCE hinstPrev, // handle to previous instance
LPSTR lpCmdLine, // address of command-line string
int nCmdShow) // show-window type
{
WNDCLASS wc;
// Register the main window class.
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWindowClass";
if (!RegisterClass(&wc))
return FALSE;
//
// Process other messages.
//
}
Sous-classification d’une fenêtre
Pour sous-classer un instance d’une fenêtre, appelez la fonction SetWindowLong et spécifiez le handle de la fenêtre pour sous-classer l’indicateur GWL_WNDPROC et un pointeur vers la procédure de sous-classe. SetWindowLong retourne un pointeur vers la procédure de fenêtre d’origine ; utilisez ce pointeur pour passer des messages à la procédure d’origine. La procédure de fenêtre de sous-classe doit utiliser la fonction CallWindowProc pour appeler la procédure de fenêtre d’origine.
Notes
Pour écrire du code compatible avec les versions 32 bits et 64 bits de Windows, utilisez la fonction SetWindowLongPtr .
L’exemple suivant montre comment sous-classer un instance d’un contrôle d’édition dans une boîte de dialogue. La procédure de fenêtre de sous-classe permet au contrôle d’édition de recevoir toutes les entrées du clavier, y compris les touches ENTRÉE et TAB, chaque fois que le contrôle a le focus d’entrée.
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditBoxProc(
HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
HWND hwndEdit;
switch(uMsg)
{
case WM_INITDIALOG:
// Retrieve the handle to the edit control.
hwndEdit = GetDlgItem(hwndDlg, ID_EDIT);
// Subclass the edit control.
wpOrigEditProc = (WNDPROC) SetWindowLong(hwndEdit,
GWL_WNDPROC, (LONG) EditSubclassProc);
//
// Continue the initialization procedure.
//
return TRUE;
case WM_DESTROY:
// Remove the subclass from the edit control.
SetWindowLong(hwndEdit, GWL_WNDPROC,
(LONG) wpOrigEditProc);
//
// Continue the cleanup procedure.
//
break;
}
return FALSE;
UNREFERENCED_PARAMETER(lParam);
}
// Subclass procedure
LRESULT APIENTRY EditSubclassProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
if (uMsg == WM_GETDLGCODE)
return DLGC_WANTALLKEYS;
return CallWindowProc(wpOrigEditProc, hwnd, uMsg,
wParam, lParam);
}