Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En esta nota se describe la instalación del mapa de mensajes de MFC.
El problema
Microsoft Windows implementa funciones virtuales en clases de ventana que usan su instalación de mensajería. Debido al gran número de mensajes implicados, proporcionar una función virtual independiente para cada mensaje de Windows crearía una tabla virtual prohibitivamente grande.
Dado que el número de mensajes de Windows definidos por el sistema cambia a lo largo del tiempo y, dado que las aplicaciones pueden definir sus propios mensajes de Windows, los mapas de mensajes proporcionan un nivel de direccionamiento indirecto que impide que los cambios de interfaz rompan el código existente.
Información general
MFC proporciona una alternativa a la instrucción switch que se usó en programas tradicionales basados en Windows para controlar los mensajes enviados a una ventana. Se puede definir una asignación de mensajes a métodos para que cuando una ventana reciba un mensaje, se llama automáticamente al método adecuado. Esta instalación de mapa de mensajes está diseñada para parecerse a funciones virtuales, pero tiene ventajas adicionales no posibles con las funciones virtuales de C++.
Definición de un mapa de mensajes
La macro DECLARE_MESSAGE_MAP declara tres miembros para una clase.
Matriz privada de entradas de AFX_MSGMAP_ENTRY llamadas _messageEntries.
Estructura de AFX_MSGMAP protegida denominada messageMap que apunta a la matriz _messageEntries .
Función virtual protegida denominada
GetMessageMapque devuelve la dirección de messageMap.
Esta macro debe colocarse en la declaración de cualquier clase mediante asignaciones de mensajes. Por convención, se encuentra al final de la declaración de clase. Por ejemplo:
class CMyWnd : public CMyParentWndClass
{
// my stuff...
protected:
//{{AFX_MSG(CMyWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Este es el formato generado por AppWizard y ClassWizard cuando crean nuevas clases. Los corchetes //{{ y //}} son necesarios para ClassWizard.
La tabla del mapa de mensajes se define mediante un conjunto de macros que se expanden a entradas de mapa de mensajes. Una tabla comienza con una llamada a macro de BEGIN_MESSAGE_MAP , que define la clase que controla este mapa de mensajes y la clase primaria a la que se pasan los mensajes no controladas. La tabla termina con la llamada de macro END_MESSAGE_MAP .
Entre estas dos llamadas a macros es una entrada para que este mapa de mensajes controle cada mensaje. Cada mensaje estándar de Windows tiene una macro del formulario ON_WM_MESSAGE_NAME que genera una entrada para ese mensaje.
Se ha definido una firma de función estándar para desempaquetar los parámetros de cada mensaje de Windows y proporcionar seguridad de tipos. Estas firmas se pueden encontrar en el archivo Afxwin.h en la declaración de CWnd. Cada uno se marca con la palabra clave afx_msg para facilitar la identificación.
Nota:
ClassWizard requiere que use la palabra clave afx_msg en las declaraciones del controlador de mapa de mensajes.
Estas firmas de función se derivaron mediante una convención simple. El nombre de la función siempre comienza con "On". Esto va seguido del nombre del mensaje de Windows con la "WM_" quitada y la primera letra de cada palabra en mayúsculas. El orden de los parámetros es wParam seguido de LOWORD(lParam) a continuación HIWORD(lParam). No se pasan parámetros sin usar. Los identificadores que se encapsulan en las clases MFC se convierten en punteros a los objetos MFC adecuados. En el ejemplo siguiente se muestra cómo controlar el mensaje de WM_PAINT y hacer que se llame a la CMyWnd::OnPaint función :
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
La tabla de mapa de mensajes debe definirse fuera del ámbito de cualquier definición de función o clase. No debe colocarse en un bloque "C" extern.
Nota:
ClassWizard modificará las entradas del mapa de mensajes que se producen entre el corchete de comentarios //{{ y //}}}.
Mensajes de Windows definidos por el usuario
Los mensajes definidos por el usuario se pueden incluir en un mapa de mensajes mediante la macro ON_MESSAGE . Esta macro acepta un número de mensaje y un método del formulario:
// 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()
En este ejemplo, se establece un controlador para un mensaje personalizado que tiene un identificador de mensaje de Windows derivado de la base de WM_USER estándar para los mensajes definidos por el usuario. En el ejemplo siguiente se muestra cómo llamar a este controlador:
CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);
El intervalo de mensajes definidos por el usuario que usan este enfoque debe estar en el intervalo WM_USER para 0x7fff.
Nota:
ClassWizard no admite la entrada de ON_MESSAGE rutinas de controlador desde la interfaz de usuario classWizard. Debe escribirlos manualmente desde el editor de Visual C++. ClassWizard analizará estas entradas y le permitirá examinarlas igual que cualquier otra entrada de mapa de mensajes.
Mensajes registrados de Windows
La función RegisterWindowMessage se usa para definir un nuevo mensaje de ventana que se garantiza que sea único en todo el sistema. La macro ON_REGISTERED_MESSAGE se usa para controlar estos mensajes. Esta macro acepta un nombre de una variable NEAR de UINT que contiene el identificador de mensaje de Windows registrado. Por ejemplo
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 de identificador de mensaje de Windows registrada (WM_FIND en este ejemplo) debe ser una variable NEAR debido a la forma en que se implementa ON_REGISTERED_MESSAGE.
El intervalo de mensajes definidos por el usuario que usan este enfoque estará en el intervalo 0xC000 para 0xFFFF.
Nota:
ClassWizard no admite la entrada de ON_REGISTERED_MESSAGE rutinas de controlador desde la interfaz de usuario classWizard. Debe escribirlos manualmente desde el editor de texto. ClassWizard analizará estas entradas y le permitirá examinarlas igual que cualquier otra entrada de mapa de mensajes.
Mensajes de comando
Los mensajes de comandos de menús y aceleradores se controlan en asignaciones de mensajes con la macro ON_COMMAND. Esta macro acepta un identificador de comando y un método . Solo el mensaje de WM_COMMAND específico que tiene un wParam igual al identificador de comando especificado se controla mediante el método especificado en la entrada de mapa de mensajes. Las funciones miembro del controlador de comandos no toman parámetros ni devuelven void. La macro tiene el formato siguiente:
ON_COMMAND(id, memberFxn)
Los mensajes de actualización de comandos se enrutan a través del mismo mecanismo, pero usan la macro ON_UPDATE_COMMAND_UI en su lugar. Las funciones miembro del controlador de actualizaciones de comandos toman un único parámetro, un puntero a un objeto CCmdUI y devuelven void. La macro tiene el formulario
ON_UPDATE_COMMAND_UI(id, memberFxn)
Los usuarios avanzados pueden usar la macro ON_COMMAND_EX, que es una forma extendida de controladores de mensajes de comando. La macro proporciona un superconjunto de la funcionalidad de ON_COMMAND. Las funciones miembro del controlador de comandos extendidas toman un único parámetro, un UINT que contiene el identificador de comando y devuelven un BOOL. El valor devuelto debe ser TRUE para indicar que se ha controlado el comando. De lo contrario, el enrutamiento continuará con otros objetos de destino de comando.
Ejemplos de estas formas:
Dentro de Resource.h (normalmente generado por Visual C++)
#define ID_MYCMD 100 #define ID_COMPLEX 101Dentro de la declaración de clase
afx_msg void OnMyCommand(); afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI); afx_msg BOOL OnComplexCommand(UINT nID);Dentro de la definición del mapa de mensajes
ON_COMMAND(ID_MYCMD, OnMyCommand) ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand) ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)En el archivo de implementación
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; }
Los usuarios avanzados pueden controlar un intervalo de comandos mediante un único controlador de comandos: ON_COMMAND_RANGE o ON_COMMAND_RANGE_EX. Consulte la documentación del producto para obtener más información sobre estas macros.
Nota:
ClassWizard admite la creación de controladores de ON_COMMAND y ON_UPDATE_COMMAND_UI, pero no admite la creación de controladores de ON_COMMAND_EX o ON_COMMAND_RANGE. Sin embargo, el Asistente para clases analizará y le permitirá examinar las cuatro variantes del controlador de comandos.
Mensajes de notificación de control
Los mensajes que se envían desde controles secundarios a una ventana tienen un bit adicional de información en su entrada de mapa de mensajes: el identificador del control. Solo se llama al controlador de mensajes especificado en una entrada de mapa de mensajes si se cumplen las condiciones siguientes:
El código de notificación de control (palabra alta de lParam), como BN_CLICKED, coincide con el código de notificación especificado en la entrada de mapa de mensajes.
El identificador de control (wParam) coincide con el identificador de control especificado en la entrada de mapa de mensajes.
Los mensajes de notificación de control personalizados pueden usar la macro ON_CONTROL para definir una entrada de mapa de mensajes con un código de notificación personalizado. Esta macro tiene el formulario
ON_CONTROL(wNotificationCode, id, memberFxn)
Para el uso avanzado ON_CONTROL_RANGE se puede usar para controlar una notificación de control específica desde un intervalo de controles con el mismo controlador.
Nota:
ClassWizard no admite la creación de un controlador de ON_CONTROL o ON_CONTROL_RANGE en la interfaz de usuario. Debe escribirlos manualmente con el editor de texto. ClassWizard analizará estas entradas y le permitirá examinarlas igual que cualquier otra entrada de mapa de mensajes.
Los controles comunes de Windows usan la WM_NOTIFY más eficaz para las notificaciones de control complejas. Esta versión de MFC admite directamente este nuevo mensaje mediante las macros ON_NOTIFY y ON_NOTIFY_RANGE. Consulte la documentación del producto para obtener más información sobre estas macros.