Partager via


TN006 : tables des messages

Cette remarque décrit la fonctionnalité de table des messages MFC.

Le problème

Microsoft Windows implémente des fonctions virtuelles dans les classes de fenêtres qui utilisent son dextérité de messagerie.En raison de le grand nombre de messages impliqués, en fournissant une fonction virtuelle séparée pour chaque boîte de message windows créerait un vtable prohibitivement grand.

Étant donné que le nombre de messages définis par le système windows change avec le temps, et comme les applications peuvent définir leurs propres messages windows, les tables des messages fournissent un niveau d'indirection qui empêché les modifications de l'interface d'arrêt du code existant.

Vue d'ensemble

MFC fournit une alternative à l'instruction switch utilisée dans des programmes Windows traditionnels pour traiter les messages envoyés vers une fenêtre.Un mappage des messages aux méthodes peut être défini de telle sorte que lorsqu'un message est reçu par une fenêtre, la méthode appropriée soit appelée automatiquement.Cette fonctionnalité de table des messages est conçue pour ressembler à des fonctions virtuelles mais a des allocations supplémentaires non possibles avec les fonctions virtuelles C++.

Définir une table des messages

La macro de DECLARE_MESSAGE_MAP déclare trois membres pour une classe.

  • Un tableau privé d'entrées d' AFX_MSGMAP_ENTRY a appelé _messageEntries.

  • Une structure protégée d' AFX_MSGMAP a appelé messageMap qui indique _messageEntries tableau.

  • Une fonction virtuelle protégée a appelé GetMessageMap qui retourne l'adresse d' messageMap.

Cette macro doit être mise dans la déclaration d'une classe à l'aide de tables des messages.Par convention, il se trouve à la fin de la déclaration de classe.Par exemple :

class CMyWnd : public CMyParentWndClass
{
    // my stuff...

protected:
    //{{AFX_MSG(CMyWnd)
    afx_msg void OnPaint();
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

Il s'agit du format généré par AppWizard et ClassWizard lorsqu'ils créent de nouvelles classes.Les parenthèses de //{{et}} //sont nécessaires pour l'assistant classe.

Le tableau de la table des messages est défini à l'aide d'un ensemble de macros qui se traduit par des entrées de la table des messages.Démarrage d'un tableau avec une macro-instruction de BEGIN_MESSAGE_MAP , qui définit la classe qui est gérée par cette table des messages et la classe parente auxquelles les messages non pris en charge sont passés.La table se termine par la macro-instruction d' END_MESSAGE_MAP .

Entre ces deux macro-instructions est une entrée pour chaque message est géré par cette table des messages.Chaque message windows standard possède une macro du formulaire ON_WM_MESSAGE_NAME qui génère une entrée pour ce message.

Une signature de fonction standard a été définie pour décompacter les paramètres de chaque message windows et fournissent la sécurité de type.Ces signatures peuvent se trouver dans le fichier Afxwin.h dans la déclaration de CWnd.Chaque est marqué avec le mot clé afx_msg pour faciliter l'identification.

[!REMARQUE]

ClassWizard requiert que vous utilisez le mot clé d' afx_msg dans vos déclarations de gestionnaires de table des messages.

Ces signatures de la fonction était dérivées à l'aide d'une convention simple.Le nom de la fonction commence toujours par "On ».Suit le nom du message windows par « WM_ » supprimés et de la première lettre de chaque mot en majuscules.L'ordre des paramètres est wParam suivi d' LOWORD(lParam) puis HIWORD(lParam).Les paramètres inutilisés ne sont pas réussi.Tous les handles qui sont encapsulés par les classes MFC sont convertis aux pointeurs vers des objets appropriés MFC.l'exemple suivant montre comment traiter le message d' WM_PAINT et provoquer la fonction d' CMyWnd::OnPaint à appeler :

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    //{{AFX_MSG_MAP(CMyWnd)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

La table de correspondance des messages doit être défini en dehors de toute fonction ou définition de classe.Il ne doit pas être placés dans un bloc extern « C ».

[!REMARQUE]

ClassWizard modifie les entrées de la table des messages qui se produisent entre la parenthèse de commentaire de //{{et}} //.

Messages définis par l'utilisateur windows

Les messages définis par l'utilisateur peuvent être inclus dans une table des messages à l'aide de la macro de ON_MESSAGE .Cette macro reçoit un numéro du message et une méthode de formulaire :

    // inside the class declaration
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

    #define WM_MYMESSAGE (WM_USER + 100)

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()

Dans cet exemple, nous établissons un gestionnaire pour un message personnalisé qui a un ID de message windows dérivé de la base standard d' WM_USER pour les messages définis par l'utilisateur.l'exemple suivant montre comment appeler ce gestionnaire :

CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);

La plage de messages définis par l'utilisateur qui utilisent cette approche doit être comprise entre WM_USER à 0x7fff.

[!REMARQUE]

Assistant classe ne prend pas en charge l'écriture des routines de gestionnaire d' ON_MESSAGE de l'interface utilisateur de l'assistant classe.Vous devez manuellement les entrer de l'éditeur Visual C++.ClassWizard quelconque ces entrées et vous permettra de parcourir tout comme les autres entrées de la table des messages.

Messages stockés windows

La fonction de RegisterWindowMessage est utilisée pour définir un message de nouvelle fenêtre qui est obligatoirement unique dans tout le système.Macro ON_REGISTERED_MESSAGE est utilisé pour gérer ces messages.Cette macro accepte un nom d'une variable d' UINT NEAR contenant l'ID de message stockée windowsExemple :

class CMyWnd : public CMyParentWndClass
{
public:
    CMyWnd();

    //{{AFX_MSG(CMyWnd)
    afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

static UINT NEAR WM_FIND = RegisterWindowMessage("COMMDLG_FIND");

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    //{{AFX_MSG_MAP(CMyWnd)
    ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

La variable stockée d'ID de message windows (WM_FIND dans cet exemple) doit être une variable d' NEAR en raison de la façon dont ON_REGISTERED_MESSAGE est implémenté.

La plage de messages définis par l'utilisateur qui utilisent cette approche est dans la plage 0xC000 à 0xFFFF.

[!REMARQUE]

Assistant classe ne prend pas en charge l'écriture des routines de gestionnaire d' ON_REGISTERED_MESSAGE de l'interface utilisateur de l'assistant classe.Vous devez manuellement les entrer de l'éditeur de texte.ClassWizard quelconque ces entrées et vous permettra de parcourir tout comme les autres entrées de la table des messages.

Messages de commande

Les messages de commande les menus et les accélérateurs sont traités dans les tables des messages avec la macro d' ON_COMMAND .Cette macro accepte un ID de commande et une méthode.Seul le message spécifique d' WM_COMMAND qui a wParam égal à l'ID de commande spécifié est traité par la méthode spécifiée dans l'entrée de la table des messages.Les fonctions membres du gestionnaire de commandes ne prennent pas de paramètres et voidde retour.La macro a la forme suivante :

ON_COMMAND(id, memberFxn)

Les messages de mise à jour de commande sont routés dans le même mécanisme, mais utilisez la macro d' ON_UPDATE_COMMAND_UI à la place.Les fonctions membres du gestionnaire de mise à jour de commande prennent un paramètre unique, un pointeur vers un objet de CCmdUI , et voidde retour.La macro possède le formulaire

ON_UPDATE_COMMAND_UI(id, memberFxn)

Les utilisateurs expérimentés peuvent utiliser le d' ON_COMMAND_EX , qui est une forme étendue des gestionnaires de messages de commande.Le fournit un sur-ensemble de la fonctionnalité d' ON_COMMAND .Les fonctions membres étendues de gestionnaire de commandes prennent un paramètre unique, UINT qui contient l'ID de commande, et retournent BOOL.La valeur de retour doit être TRUE pour indiquer que la commande a été gérée.Sinon le routage continuera à d'autres objets de cible de la commande.

Exemples de ces formes :

  • Resource.h intérieur (généralement généré par Visual C++)

    #define    ID_MYCMD      100
    #define    ID_COMPLEX    101
    
  • à l'intérieur de la déclaration de classe

    afx_msg void OnMyCommand();
    afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI);
    afx_msg BOOL OnComplexCommand(UINT nID);
    
  • Dans la définition de table des messages

    ON_COMMAND(ID_MYCMD, OnMyCommand)
    ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand)
    ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)
    
  • Dans le fichier d'implémentation

    void CMyClass::OnMyCommand()
    {
        // handle the command
    }
    
    void CMyClass::OnUpdateMyCommand(CCmdUI* pCmdUI)
    {
        // set the UI state with pCmdUI
    }
    
    BOOL CMyClass::OnComplexCommand(UINT nID)
    {
        // handle the command
        return TRUE;
    }
    

Les utilisateurs expérimentés peuvent gérer une plage de commandes à l'aide d'un gestionnaire de commandes unique : ON_COMMAND_RANGE ou ON_COMMAND_RANGE_EX.Consultez la documentation du produit pour plus d'informations sur ces macros.

[!REMARQUE]

Assistant classe prend en charge la création ON_COMMAND et des gestionnaires d' ON_UPDATE_COMMAND_UI , mais il ne prend pas en charge la création ON_COMMAND_EX ou d' ON_COMMAND_RANGE .Toutefois, l'Assistant de classe vous quelconque et permet de parcourir les quatre variantes du gestionnaire de commandes.

Messages de notification de contrôle

Les messages envoyés des contrôles enfants à une fenêtre ont un bit supplémentaire des informations dans leur entrée de la table des messages : l'ID du contrôleLe gestionnaire de messages spécifié dans une entrée de la table des messages est appelé uniquement si les conditions suivantes sont remplies :

  • Le code de notification de contrôle (mot élevé d' lParam), telle que BN_CLICKED, correspond au code de notification spécifié dans l'entrée de la table des messages.

  • l'ID du contrôle (wParam) correspond à l'ID du contrôle spécifié dans l'entrée de la table des messages.

Les messages de notification de contrôles personnalisés peuvent utiliser la macro d' ON_CONTROL pour définir une entrée de la table des messages avec le code de notification personnalisé.Cette macro possède le formulaire

ON_CONTROL(wNotificationCode, id, memberFxn)

Pour l'utilisation avancée ON_CONTROL_RANGE peut être utilisé pour gérer une notification de contrôle spécifique d'une plage des contrôles avec le même gestionnaire.

[!REMARQUE]

Assistant classe ne prend pas en charge la création d'un gestionnaire d' ON_CONTROL ou d' ON_CONTROL_RANGE dans l'interface utilisateur.Vous devez manuellement les présenter avec l'éditeur de texte.ClassWizard quelconque ces entrées et vous permettra de parcourir tout comme les autres entrées de la table des messages.

Les contrôles communs Windows utilisent WM_NOTIFY plus puissant pour les notifications de contrôle complexe.Cette version MFC dispose de la prise en charge directe pour ce nouveau message en utilisant des macros d' ON_NOTIFY et d' ON_NOTIFY_RANGE .Consultez la documentation du produit pour plus d'informations sur ces macros.

Voir aussi

Autres ressources

Notes techniques de nombres

Notes techniques de catégorie