La Red de Conocimientos Pedagógicos - Currículum vitae - Proceso de procesamiento de mensajes de WINDOWS

Proceso de procesamiento de mensajes de WINDOWS

1. Introducción

2. El concepto de mecanismo de mensajes de Windows

1. La diferencia entre los mecanismos de controlador de DOS y Windows

2. . Mensaje

3. Origen de los mensajes

4. Composición del sistema de mensajes de Windows

5. mensajes Puntos clave del mecanismo

1. Procedimiento de ventana

2 Tipo de mensaje

3 Colas de mensajes (Message Queues)

4 Cola mensajes y mensajes fuera de cola Mensaje

5 Funciones de mensajes de Windows

6 Interbloqueos de mensajes

7 BroadcastSystemMessage

Mecanismo de mensajes MFC<. /p >

1. En el marco de MFC, el proceso de recepción y procesamiento de mensajes de Windows

2. Método de procesamiento de mensajes interno de MFC

1.

En C++ En el artículo Arquitectura del programa, vimos que un programa se compone de varias capas y módulos. Entonces, ¿cómo se transfiere información entre estos módulos y entre su programa y Windows? En la plataforma Windows, ¿cómo se transfiere la información? ? El mecanismo de mensajes de Windows es responsable de esto, que es la parte central de Windows

Los mensajes incluyen datos e instrucciones

2.

1. La diferencia entre los mecanismos de controlador de DOS y Windows

1) DOS está controlado por procesos.

Los programas tradicionales de MS-DOS son principalmente secuenciales. Un enfoque de programación relacional y basado en procesos. Un proceso es una combinación de una secuencia predefinida de operaciones con un comienzo, un desarrollo y un final determinados. El programa controla directamente la secuencia de eventos y procedimientos del programa. Este tipo de método de programación está más orientado al programa que al usuario, tiene poca interactividad y la interfaz de usuario no es lo suficientemente amigable porque obliga a los usuarios a trabajar de acuerdo con un cierto modo inmutable. Su modelo básico se muestra en la Figura 1.1.

2) Windows se basa en eventos (mensajes)

La programación basada en eventos es un método de programación completamente nuevo. No está controlado por la secuencia de eventos, sino por la secuencia de. eventos La ocurrencia de tales eventos es aleatoria, incierta y no tiene un orden predeterminado. Esto permite a los usuarios del programa organizar el flujo del programa en varios órdenes razonables. Para aplicaciones que requieren la interacción del usuario, la programación basada en eventos tiene ventajas que no pueden ser reemplazadas por métodos basados ​​en procesos. Es un método de programación orientado al usuario. Además de completar las funciones requeridas durante el proceso de programación, también considera varias entradas posibles del usuario y diseña los procedimientos de procesamiento correspondientes. Es un método de programación "pasivo". Cuando el programa comienza a ejecutarse, está esperando que el usuario ingrese un evento, luego obtiene el evento y responde en consecuencia, y luego regresa después del procesamiento y está en estado de espera. para el evento. Su diagrama de bloques se muestra en la Figura 1.2:

2. Mensajes

El sistema Windows es un sistema operativo controlado por eventos. La ocurrencia de cada evento generará un mensaje, y lo sabemos. a través del mensaje. Qué sucedió, comprender el incidente y luego resolverlo. ¿Qué es la noticia? Es difícil dar una definición, así que vamos a explicarla desde diferentes aspectos:

1) La composición del mensaje: Un mensaje consta de un nombre de mensaje (UINT) y dos parámetros (WPARAM, LPARAM). Cuando el usuario realiza una entrada o cambia el estado de la ventana, el sistema enviará un mensaje a una ventana determinada. Por ejemplo, cuando se transfiere el menú, se enviará un mensaje WM_COMMAND. La palabra alta de WPARAM (HIWORD(wParam)) es el número de ID del comando, que es el ID del menú. Por supuesto, los usuarios también pueden definir sus propios nombres de mensajes o utilizar mensajes personalizados para enviar notificaciones y transferir datos.

2) Quién recibirá el mensaje: Un mensaje debe ser recibido por una ventana.

En el proceso de ventana (WNDPROC), puede analizar los mensajes y procesar los mensajes que le interesen. Por ejemplo, si desea procesar selecciones de menú, puede definir el código para procesar WM_COMMAND. Si desea realizar salida gráfica en la ventana, debe procesar WM_PAINT.

3) A dónde van los mensajes no procesados: M$ escribe un procedimiento de ventana predeterminado para la ventana. Este procedimiento de ventana será responsable de procesar aquellos mensajes que usted no procese. Es precisamente gracias a este proceso de ventana predeterminado que podemos usar Windows Windows para el desarrollo sin tener que prestar demasiada atención al procesamiento de varios mensajes en la ventana. Por ejemplo, se enviarán muchos mensajes cuando se arrastre la ventana, pero podemos ignorarlos y dejar que el sistema los maneje por sí solo.

4) Identificador de ventana: cuando hablamos de mensajes, no podemos dejar de hablar de identificadores de ventana. El sistema utiliza identificadores de ventana para identificar de forma única una ventana en todo el sistema. Al enviar un mensaje, se debe tener un identificador de ventana. especificado para indicar de qué ventana proviene el mensaje. Ventana de recepción. Cada ventana tendrá su propio procedimiento de ventana, por lo que la entrada del usuario se procesará correctamente. Por ejemplo, si hay dos ventanas que utilizan un código de procedimiento de ventana, cuando hace clic con el mouse en la ventana uno, el mensaje se enviará a la ventana uno en lugar de a la ventana dos a través del identificador de la ventana uno.

3. Fuente de los mensajes

Los eventos impulsados ​​por eventos giran en torno a la generación y el procesamiento de mensajes. Un mensaje es un mensaje sobre un evento que ocurrió. El control por eventos se implementa mediante el mecanismo de bucle de mensajes. También se puede entender que un mensaje es una notificación que informa la ocurrencia de eventos relevantes.

Hay cuatro fuentes de mensajes para aplicaciones de Windows:

1) Mensajes de entrada: incluida la entrada del teclado y del mouse. Este tipo de mensaje se coloca primero en la cola de mensajes del sistema y luego Windows los envía a la cola de mensajes de la aplicación y la aplicación procesa el mensaje.

2) Mensaje de control: se utiliza para la comunicación bidireccional con objetos de control de Windows, como cuadros de lista, botones, casillas de verificación, etc. Este mensaje se emite cuando el usuario cambia la selección actual en un cuadro de lista o cambia el estado de una casilla de verificación. Este tipo de mensaje generalmente no pasa por la cola de mensajes de la aplicación, sino que se envía directamente al objeto de control.

3) Mensajes del sistema: Responde a eventos programados o interrupciones del reloj del sistema. Algunos mensajes del sistema, como los mensajes DDE (mensajes de intercambio dinámico de datos), pasan por la cola de mensajes del sistema de Windows, mientras que otros se envían directamente a la cola de mensajes de la aplicación sin pasar por la cola de mensajes del sistema, como la creación de mensajes de ventana.

4) Mensaje de usuario: lo define el propio programador y se emite activamente en la aplicación, y generalmente es procesado internamente por una determinada parte de la aplicación.

4. Composición del sistema de mensajes de Windows

El sistema de mensajes de Windows consta de las siguientes tres partes:

Cola de mensajes: Windows puede mantenerla para todas las aplicaciones. Una cola de mensajes, la aplicación debe obtener el mensaje de la cola de mensajes y luego enviarlo a un formulario.

Bucle de mensajes: a través de este mecanismo de bucle, la aplicación recupera un mensaje de la cola de mensajes, lo envía a la ventana apropiada y luego continúa recuperando el siguiente mensaje de la cola de mensajes y lo envía a la ventana apropiada. ventana. , proceda en secuencia.

Procedimiento de ventana: Cada ventana tiene un procedimiento de ventana para recibir mensajes pasados ​​por Windows a la ventana. La tarea del procedimiento de ventana es obtener el mensaje y responder al mismo. El procedimiento de ventana es una función de devolución de llamada que generalmente devuelve un valor a Windows después de procesar un mensaje.

5. Respuesta del mensaje

Los mensajes se generan a partir de eventos del sistema (incluidos los eventos del temporizador) y Windows usa mensajes para cargar y cerrar (y otros procesos, como dibujar una ventana). , etc.) aplicación, un rendimiento típico es que durante la operación de apagado, Windows envía un mensaje de apagado a todas las aplicaciones en ejecución, diciéndoles que salgan de la memoria. En este momento, la aplicación responde al sistema operativo respondiendo al mensaje. por lo tanto, los mensajes son el medio para que las aplicaciones interactúen con WinOS.

Los pasos desde la generación del mensaje hasta la respuesta de la ventana: (como se muestra a continuación)

1> El sistema ha ocurrido o el usuario ha emitido un determinado evento.

2> Windows traduce este evento en un mensaje y luego lo coloca en la cola de mensajes.

3> La aplicación recibe este mensaje de la cola de mensajes y lo almacena en TMsg. Grabación.

4>La aplicación pasa el mensaje a un procedimiento de formulario apropiado.

El procedimiento del formulario responde a este mensaje y lo procesa. El mensaje se pasa a la función de formulario de este formulario.

3. Puntos clave del mecanismo de mensajes de Windows

1. Procedimiento de ventana

Cada ventana tendrá una función de devolución de llamada (WndProc) llamada procedimiento de ventana, que trae Hay cuatro parámetros, a saber: identificador de ventana (identificador de ventana), ID de mensaje (ID de mensaje) y dos parámetros de mensaje (wParam, lParam). Cuando la ventana recibe un mensaje, el sistema llamará a este procedimiento de ventana para procesar el mensaje. (Por eso se llama función de devolución de llamada)

2 tipos de mensajes

1) Mensajes definidos por el sistema

Mensajes definidos de antemano en el SDK, no definido por el usuario, su rango está entre [0×0000, 0×03ff], y se puede dividir en las siguientes tres categorías:

Mensaje de ventana (Mensaje de Windows)

Con la ventana Relacionado con operaciones internas, como crear ventanas, dibujar ventanas, destruir ventanas, etc. Puede ser una ventana general, un Diálogo, un control, etc.

Por ejemplo: WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL..

Mensaje de comando (Mensaje de comando)

Relacionado con el procesamiento de solicitudes de usuario, como hacer clic Se genera un mensaje de comando de menú cuando se selecciona un elemento, barra de herramientas o control.

WM_COMMAND, LOWORD(wParam) representa el ID de un elemento de menú, botón de barra de herramientas o control. Si es un control, HIWORD(wParam) representa el tipo de mensaje de control

Notificación de control (Mensaje de notificación)

Mensaje de notificación de control Este es el formato de mensaje más flexible. wParam, lParam Son: WM_NOTIFY, ID de control, puntero a NMHDR. NMHDR contiene el contenido de las notificaciones de control y puede ampliarse arbitrariamente.

2) Mensajes definidos por la aplicación

Los mensajes definidos por el usuario tienen las siguientes disposiciones para su alcance:

WM_USER: 0×0400 -0×7FFF (ex . WM_USER+10)

WM_APP(winver>4.0): 0×8000-0xBFFF (ex.WM_APP+4)

RegisterWindowMessage: 0xC000-0xFFFF

3 colas de mensajes

Hay dos tipos de colas de mensajes en Windows

1) Cola de mensajes del sistema (cola de mensajes del sistema)

Esta es una cola solo del sistema El controlador del dispositivo (ratón, teclado) convertirá la entrada de la operación en un mensaje y lo almacenará en la cola del sistema. Luego, el sistema colocará el mensaje en la cola de mensajes del hilo donde se encuentra la ventana de destino (específica del hilo). . cola de mensajes)

2) Cola de mensajes específica del hilo

Cada hilo de la GUI mantendrá dicha cola de mensajes. (Esta cola solo se crea cuando un subproceso llama a una función GDI y no se crea de forma predeterminada).

Luego, los mensajes en la cola de mensajes del hilo se enviarán al procedimiento de ventana correspondiente (WndProc) para su procesamiento.

Nota: WM_PAINT y WM_TIMER en la cola de mensajes del hilo solo se procesarán cuando no haya otros mensajes en Los mensajes de la cola WM_PAINT también se fusionan para mejorar la eficiencia. Todos los demás mensajes se procesan según el método primero en entrar, primero en salir (FIFO).

4 Mensajes en cola y mensajes no en cola

1) Mensajes en cola

El mensaje se guardará primero En la cola de mensajes, el bucle de mensajes buscará los mensajes de esta cola y distribuirlos a cada ventana para su procesamiento

como mensajes del mouse y del teclado.

2) Mensajes no en cola

Los mensajes omitirán la cola de mensajes del sistema y la cola de mensajes del hilo y se enviarán directamente al proceso de ventana para su procesamiento.

Por ejemplo: WM_ACTIVATE , WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED

Nota: El mensaje enviado por postMessage es un mensaje en cola, que publicará el mensaje en la cola de mensajes. El mensaje enviado por SendMessage es un mensaje que no está en cola, que es directamente; enviado al procedimiento de ventana para su procesamiento

5 funciones de mensajes de Windows

1) PostMessage (PostThreadMessage), SendMessage

PostMessage: coloque el mensaje en la cola de mensajes del hilo donde se encuentra la ventana especificada y regresar inmediatamente. PostThreadMessage: regresa inmediatamente después de colocar el mensaje en la cola de mensajes del hilo especificado.

SendMessage: envía el mensaje directamente al procedimiento de ventana para su procesamiento y regresa solo después de que se completa el procesamiento.

2) GetMessage, PeekMessage

PeekMessage regresará inmediatamente y el mensaje se puede retener

GetMessage eliminará el mensaje si regresa cuando hay un mensaje

3 ) TranslateMessage, TranslateAccelerator

TranslateMessage: convierte un mensaje de clave virtual en un mensaje de carácter (mensaje de carácter) y lo coloca en la cola de mensajes del hilo actual y el mensaje loop lo sacará para procesarlo la próxima vez.

TranslateAccelerator: asigna teclas de acceso directo a los comandos de menú correspondientes. Convertirá WM_KEYDOWN o WM_SYSKEYDOWN en el mensaje WM_COMMAND o WM_SYSCOMMAND correspondiente en la tabla de teclas de acceso directo, y luego enviará el WM_COMMAND o WM_SYSCOMMAND convertido directamente al procedimiento de ventana para su procesamiento, y regresará después del procesamiento.

6 interbloqueos de mensajes

Supongamos que hay hilos A y B, ahora existen los siguientes pasos

1) Hilo A Enviar mensaje al hilo B, A Esperar el mensaje se procesará en el hilo B y luego regresará

2) El hilo B recibe el mensaje del hilo A y lo procesa. Durante el procesamiento, B también envíaMessgae al hilo A y luego espera el retorno del hilo. A. .

Porque en este momento, el subproceso A está esperando regresar del subproceso B y no puede procesar el mensaje enviado por el subproceso B, lo que hace que los subprocesos A y B se esperen entre sí, formando un punto muerto. Varios subprocesos también pueden formar un punto muerto circular.

Puedes utilizar SendNotifyMessage o SendMessageTimeout para evitar un punto muerto.

7 BroadcastSystemMessage

Los mensajes con los que generalmente entramos en contacto se envían a la ventana. De hecho, el receptor del mensaje puede ser diverso, y pueden ser aplicaciones. controladores instalables, controladores de red, controladores de dispositivos a nivel de sistema, etc.

BroadcastSystemMessage es una API que puede enviar mensajes a los componentes del sistema anteriores.

Entonces, ¿cómo se transmiten estos mensajes? Tomemos MFC como ejemplo para observar el proceso de transmisión de mensajes.

4. Mecanismo de mensajes MFC

En la función principal de una aplicación de Windows, primero debe registrar la clase de ventana y luego crear y mostrar la ventana. Después de crear la ventana, el programa ingresa al bucle de mensajes. En el bucle de mensajes, el programa obtiene mensajes continuamente y los envía a la función de ventana correspondiente para su procesamiento.

Podemos ver que en el marco MFC, los archivos de encabezado de las clases que pueden realizar el procesamiento de mensajes contendrán la macro DECLARE_MESSAGE_MAP(), que realiza principalmente el mapeo de mensajes y el procesamiento de mensajes. La declaración de la función del controlador. /p>

. Los archivos de implementación de clases que pueden realizar procesamiento de mensajes generalmente contienen la siguiente estructura.

BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass) //{{AFX_MSG_MAP(CInheritClass)

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

Aquí implementamos principalmente las funciones de mapeo y procesamiento de mensajes.

Todas las clases que pueden realizar el procesamiento de mensajes se basan en la clase CCmdTarget, lo que significa que la clase CCmdTarget es la clase principal de todas las clases que pueden realizar el procesamiento de mensajes. La clase CCmdTarget es la base y el núcleo del procesamiento de mensajes de comando de MFC.

Al mismo tiempo, MFC define las siguientes dos estructuras principales:

AFX_MSGMAP_ENTRY

struct AFX_MSGMAP_ENTRY

{//""" //

};

y AFX_MSGMAP

estructura AFX_MSGMAP

{//""``//

};

La estructura AFX_MSGMAP_ENTRY contiene toda la información relevante de un mensaje, y AFX_MSGMAP tiene dos funciones principales: una: se utiliza para obtener la dirección de entrada de mapeo del mensaje de la clase base. Dos: obtenga su propia dirección de entrada de mapeo de mensajes.

De hecho, MFC llena todos los mensajes en la estructura AFX_MSGMAP_ENTRY uno por uno, formando una matriz que almacena todos los mensajes y sus parámetros de mensaje relacionados. Al mismo tiempo, la primera dirección de la matriz se puede obtener a través de AFX_MSGMAP, y también se puede obtener la dirección de entrada de mapeo de mensajes de la clase base. Este es un ejemplo de cómo llamar a la respuesta del mensaje de su clase base cuando no responde. al mensaje.

Ahora analicemos cómo MFC permite que el procedimiento de ventana procese mensajes. De hecho, todas las clases de ventana de MFC interceptan mensajes a través de la función de enlace _AfxCbtFilterHook y configuran el procedimiento de ventana en la función de enlace _AfxCbtFilterHook. El procedimiento de ventana original se almacena en la variable miembro m_pfnSuper

1. En el marco de MFC, el proceso de recepción y procesamiento de mensajes de Windows:

2. /p>

MFC recibe un mensaje publicado:

La única diferencia significativa entre MFC procesar un mensaje publicado y enviar un mensaje es que el mensaje publicado pasa algún tiempo en la cola de mensajes de la aplicación.

Permanece en la cola hasta que el mensaje lo muestra. Aquí se explica cómo aceptar un mensaje enviado. La bomba de mensajes en la aplicación MFC está en la función miembro Run() de CWinApp. Cuando la aplicación comienza a ejecutarse, se llama a Run(). Run() divide el tiempo en dos partes. Una parte se usa para realizar procesamiento en segundo plano, como cancelar el objeto CWnd temporal; la otra parte se usa para verificar la cola de mensajes. Cuando llega un mensaje nuevo, Run() lo extrae, es decir, utiliza GetMessage() para eliminar el mensaje de la cola, ejecuta las dos funciones de traducción de mensajes PreTranslateMessage() y ::TranslateMessage() y luego llama a DispatchMessage( ) función. El proceso de ventana al que está destinado el mensaje. Como se muestra a continuación.

Usamos una función de instancia A para enviar un mensaje a la función B para observar el proceso de procesamiento de mensajes interno de MFC.

1. Primero, la función A debe obtener el puntero del objeto de clase CWnd del mensaje y luego llamar a la función miembro SendMessage() de CWnd.

LRESULT Res=pWnd->SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);

El puntero pWnd apunta al objeto de clase CWnd de destino. La variable Msg es el mensaje, y las variables wParam y lParam contienen los parámetros del mensaje, como dónde se hizo clic con el mouse o qué elemento del menú se seleccionó. El resultado del mensaje devuelto por la ventana de destino se coloca en la variable Res.

Para enviar un mensaje a una ventana que no tiene un objeto de función CWnd, puede llamar directamente a la API de Windows utilizando el siguiente identificador de ventana de destino:

LRESULT Res=::SendMessage (HWND hWnd, UINT Msg , WPARAM wParam, LPARAM lParam);

El hWnd aquí es el identificador de la ventana de destino.

Si se trata de una transmisión asíncrona, también puede utilizar PostMessage(). El mensaje es el mismo que el anterior, pero el valor de retorno Res es diferente. Res no es un valor devuelto por el formulario de destino, sino un. Valor booleano utilizado para representar el mensaje.

2. En circunstancias normales, una vez enviado el mensaje, el fondo de la aplicación lo enviará automáticamente, pero en circunstancias especiales, deberá eliminar un mensaje usted mismo, por ejemplo, si desea recibirlo. la aplicación Detener la aplicación ante algún tipo de mensaje. Hay dos formas de eliminar un mensaje de la cola de mensajes de la aplicación, pero ninguno de estos métodos implica MFC.

El primer método: echar un vistazo a la cola de mensajes para ver si hay un mensaje allí sin interferir con nada.

BOOL res=::PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg );

El segundo método: en realidad espera hasta que llega un nuevo mensaje en la cola, el mensaje se elimina y se devuelve.

BOOL res=::GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);

En estos dos métodos, la variable hWnd especifica la ventana para interceptar el mensaje, Si esta variable se establece en NULL, se interceptarán todos los mensajes de la ventana. Las variables wMsgFilterMin y wMsgFilterMax corresponden a la variable Msg en SendMessage() y especifican el rango del mensaje que se va a ver. Si se utiliza "0,0", todos los mensajes serán interceptados.

Si utiliza WM_KEYFIRST, WM_KEYLAST o WM_MOUSEFIRST, WM_MOUSELAST, todos los mensajes del teclado o del mouse serán interceptados. La variable wRemoveMsg especifica si PeekMessage() realmente debería eliminar el mensaje de la cola. (GetMessage() siempre elimina el mensaje). Esta variable puede tomar dos valores:

PM_REMOVE, PeekMessage() eliminará el mensaje.

PM_NOREMOVE, PeekMessage() dejará el mensaje en la cola y devolverá una copia del mismo.

Por supuesto, si deja el mensaje en la cola de mensajes y luego llama a PeekMessage() nuevamente para ver el mismo tipo de mensaje, se devolverá exactamente el mismo mensaje.

La variable lpMsg es un puntero a la estructura MSG que contiene el mensaje recuperado.

typedef struct tagMSG {

HWND hwnd; // el mensaje del identificador de ventana está destinado a

mensaje UINT;

WPARAM wParam;

LPARAM lParam;

DWORD time; // la hora en que se puso el mensaje en la cola

POINT pt // la ubicación del cursor del mouse cuando

// el mensaje se puso en la cola

} MSG;

3. El mensaje se colocará en la cola de mensajes. La función miembro de CwinApp, Run, divide el tiempo en dos partes cuando la aplicación se está ejecutando. Una parte realiza el procesamiento en segundo plano y la otra parte verifica la cola de mensajes. Cuando se encuentra un nuevo mensaje, Run llama a GetMessage () para recuperar el mensaje de la cola. . para recuperar el mensaje.

3. Ejecute las dos funciones de traducción de mensajes PreTranslateMessage() y ::TranslateMessage() para la traducción. Encuentre principalmente la ubicación del objeto de función, el identificador de acción del mensaje y las operaciones de ejecución relacionadas con el mensaje.

4. Utilice la función DispatchMessage() para llamar al proceso de función B esperado del mensaje y ejecutarlo.