TN006: Mapas de mensajes

Esta nota describe la función de mapa de mensajes MFC.

El problema

Microsoft Windows implementa lo que son esencialmente funciones virtuales en clases de ventana mediante su servicio de mensajería. Debido a la gran cantidad de mensajes involucrados, proporcionando una función virtual independiente para cada mensaje de Windows resulta en una vtable prohibitivamente grande.

También, puesto que el número de mensajes definidos por el sistema de Windows cambia con el tiempo, y una aplicación específica puede que desee definir algunos mensajes de Windows de su propia, el mecanismo de mapa de mensajes proporciona un nivel de direccionamiento indirecto que impide que los cambios en la interfaz rompiendo el código existente.

Visión general

MFC proporciona una alternativa a la instrucción switch utilizada en los programas tradicionales de Windows para manejar los mensajes enviados a una ventana. Una asignación de mensajes a funciones miembro puede definirse para que cuando un mensaje va a ser manejados por una ventana, se llama automáticamente la función de miembro correspondiente. Este servicio de mapas de mensajes está diseñado para ser similar a las funciones virtuales pero tiene ventajas adicionales no es posibles con funciones virtuales de C++.

Definir un mapa de mensajes

La macro DECLARE_MESSAGE_MAP declara a tres miembros de una clase.

Esta macro debe colocarse en la declaración de cualquier clase utilizando mapas de mensajes. Por Convención, es al final de la declaración de clase. Por ejemplo:

clase CMyW&nd: CMyParentWndClass pública
{
 nbsp;  / / Mis cosas...

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

DECLARE_MESSAGE_MAP()
}

Este es el formato generado por AppWizard y ClassWizard al crear nuevas clases. El / / {{y / /}} entre paréntesis son necesarios para ClassWizard.

Tabla del mapa de mensajes se define con un conjunto de macros que ampliar las entradas de mapa de mensajes. Una tabla comienza con una llamada de macro BEGIN_MESSAGE_MAP , que define la clase que se maneja por este mapa de mensajes y la clase de padre que se pasan mensajes no controlados. La tabla termina con la llamada de macro END_MESSAGE_MAP.

Entre estas dos macros llamadas es una entrada para cada mensaje a ser manipulados por este mapa de mensajes. Cada mensaje de Windows estándar tiene una macro del formulario ON_WM_xxx (donde xxx es el nombre del mensaje) que genera una entrada para ese mensaje.

Una firma de función estándar se ha definido para desempaquetar los parámetros de cada mensaje de Windows y proporciona seguridad de tipos. Estas firmas pueden encontrarse en el archivo AFXWIN.H en la declaración de CWnd. Cada uno está marcado con la palabra afx_msg para facilitar su identificación.

&Notanbsp;  ClassWizard requiere el uso de la palabra clave afx_msg en las declaraciones de controlador del mapa de mensajes.

Estas firmas de función se derivan mediante un simple Convenio. El nombre de la función siempre empieza con "On". Esto es seguido por el nombre del mensaje de Windows con el WM_ eliminado y sólo la primera letra de cada palabra en mayúscula. El orden de los parámetros es wParam seguido por LOWORD (lParam) y HIWORD(lParam). No se pasan parámetros no utilizados. Cualquier asas que están envueltos por clases MFC se convierten en punteros a los objetos correspondientes de MFC. En el ejemplo siguiente se muestra cómo controlar el mensaje WM_PAINT y causar la CMyWnd:: OnPaint función que se llamará

BEGI&N_MESSAGE_MAP (CMyWnd, CMyParentWndClass)
 nbsp;  //{{AFX_MSG_MAP(CMyWnd)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

La tabla de mapa de mensajes debe definirse al margen de cualquier definición de función o de clase. No debe colocarse dentro de un bloque de extern "C".

&Notanbsp;  ClassWizard editará las entradas de mapa de mensajes que se encuentran entre los / / {{y / /}} corchete de comentario.

Mensajes de Windows definida por el usuario

Mensajes definidos por el usuario pueden incluirse en un mapa de mensajes mediante el uso de la macro ON_MESSAGE . Esta macro acepta un número de mensaje y una función miembro del formulario:

nbsp;   / / dentro de la declaración de clase
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

Por ejemplo:
    # define WM_MYMESSAGE (WM_USER + 100)

BEGI&N_MESSAGE_MAP (CMyWnd, CMyParentWndClass)
    ON_MESSAGE (WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()

En este ejemplo, establecemos un controlador para un mensaje personalizado con un ID de mensaje de Windows derivado de la norma WM_USER base de mensajes definidos por el usuario. Puede invocar este controlador con código como:

CWnd * Night =...;
Night-gt;SendMessage(WM_MYMESSA&GE)

El rango de mensajes definidos por el usuario utilizando este enfoque debe estar en el rango WM_USER a 0x7fff.

&Notanbsp;  ClassWizard no admite rutinas de controlador ON_MESSAGE entra desde la interfaz de usuario de ClassWizard: debe escribirlas manualmente desde el editor de Visual C++. Una vez introducido, ClassWizard será analizar estas entradas y le permiten navegar al igual que cualquier otras entradas de mapa de mensajes.

Mensajes de Windows registrado

La :: RegisterWindowMessage función se utiliza para definir un nuevo mensaje de ventana que está garantizado a ser único en todo el sistema. La macro ON_REGISTERED_MESSAGE se utiliza para gestionar estos mensajes. Esta macro acepta un nombre de variable UINT cercano que contiene windows registrado mensaje Id. Por ejemplo

clase CMyWnd: CMyParentWndClass pública
{
público:
 nbsp;  CMyWnd();

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

DECLARE_MESSAGE_MAP()
};

UI&NT estático cerca de 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 del ID del mensaje de Windows registrada (WM_FIND en el ejemplo anterior) debe ser una variable cercana debido a la forma en que se implementa ON_REGISTERED_MESSAGE.

La gama de mensajes definidos por el usuario utilizando este enfoque estará en el rango 0xC000 a 0xFFFF.

&Notanbsp;  ClassWizard no admite rutinas de controlador ON_REGISTERED_MESSAGE entra desde la interfaz de usuario de ClassWizard, deben escribirlos manualmente desde el editor de texto. Una vez introducido, ClassWizard será analizar estas entradas y le permiten navegar al igual que cualquier otras entradas de mapa de mensajes.

Mensajes de comando

Mensajes de comando de los menús y los aceleradores se manejan en mapas de mensajes con la macro ON_COMMAND . Esta macro acepta un identificador de comando, así como una función miembro. Sólo el mensaje WM_COMMAND específico con un wParam igual que el comando especificado que ID es manejado por la función miembro especificado en la entrada de mapa de mensajes. Funciones de miembro de comando controlador no toman parámetros y devolución void. La macro tiene la forma:

 ON_COMMAND (id, memberFxn)

Comando Actualizar mensajes se enrutan a través del mismo mecanismo como controladores de ON_COMMAND . La macro ON_UPDATE_COMMAND_UI se utiliza en su lugar. Funciones de miembro de comando Actualizar controlador toman un solo parámetro, un puntero a un objeto CCmdUI y devolución void. La macro tiene la forma

ON_UPDATE_COMMAND_UI (id, memberFxn)

Una forma extendida de los controladores de mensajes de comando está disponible para usos avanzados. La macro ON_COMMAND_EX se utiliza en su lugar y proporciona un superconjunto de la funcionalidad ON_COMMAND . Funciones extendidas controlador de comandos de miembro toman un parámetro único, un UINT que contiene el identificador de comando y devolución un BOOL. El regreso BOOL debe ser TRUE para indicar que el comando ha sido controlado, de lo contrario el enrutamiento seguirá otros objetos de destino de comando.

Ejemplos de las formas más arriba:

También está disponible para uso avanzado es ON_COMMAND_RANGE y ON_COMMAND_RANGE_EX que le permiten manejar una serie de comandos con un controlador único comando. Consulte la documentación del producto para obtener más información sobre estas macros.

&Notanbsp;  ClassWizard apoya crear controladores de ON_COMMAND y ON_UPDATE_COMMAND_UI , pero no permite crear controladores de ON_COMMAND_EX o ON_COMMAND_RANGE . Sin embargo, Asistente de clase analizar y permitirle examinar todas las variantes de controlador de tres comandos.

Mensajes de notificación de control

Mapa de mensajes que se envían desde los controles secundarios a una ventana ha extra bits de información en su mensaje de entrada: ID del control Se llama al controlador de mensaje especificado en una entrada del mapa de mensaje sólo si (1) el código de notificación de control (palabra alta de lParam), tales como BN_CLICKED, coincide con el código de notificación especificado en la entrada de mapa de mensajes y control (2) ID (wParam) coincide con el ID del control especificado en la entrada de mapa de mensajes.

Mensajes de notificación de control personalizado pueden utilizar la macro ON_CONTROL para definir una entrada de mapa de mensaje con un código de notificación personalizada. Esta macro tiene la forma

ON_CONTROL (wNotificationCode, id, memberFxn)

Para uso avanzado ON_CONTROL_RANGE puede utilizarse para manejar una notificación de control específico de una gama de controles con el mismo controlador.

ClassWizard no admite la creación de un controlador de ON_CONTROL o ON_CONTROL_RANGE en la interfaz de usuario; manualmente debe entrar con el editor de texto. Una vez introducido, ClassWizard será analizar estas entradas y le permiten navegar al igual que otras entradas de mapa de mensajes.

Los controles comunes de Windows hacen uso de la más poderosa WM_NOTIFY para notificaciones de control complejo. Esta versión de MFC tiene soporte directo para este nuevo mensaje con las macros ON_NOTIFY y ON_NOTIFY_RANGE . Consulte la documentación del producto para obtener más información sobre estas macros.

&Notas técnicas por número |nbsp; Notas técnicas por categoría

Index