¿Qué es una bomba de mensajes?


104

En este hilo (publicado hace aproximadamente un año) hay una discusión de los problemas que pueden surgir al ejecutar Word en una sesión no interactiva. El consejo (bastante fuerte) que se da allí es que no lo haga. En una publicación se dice "Todas las API de Office asumen que está ejecutando Office en una sesión interactiva en un escritorio, con un monitor, teclado y mouse y, lo más importante, una bomba de mensajes". No estoy seguro de qué es eso. (He estado programando en C # durante solo un año; mi otra experiencia de programación ha sido principalmente con ColdFusion).

Actualizar:

Mi programa ejecuta una gran cantidad de archivos RTF para extraer dos piezas de información que se utilizan para construir un número de informe médico. En lugar de intentar averiguar cómo funcionan las instrucciones de formato en RTF, decidí simplemente abrirlas en Word y extraer el texto de allí (sin iniciar realmente la GUI). De vez en cuando, el programa fallaba en medio del procesamiento de un archivo y dejaba un hilo de Word abierto adjunto a ese documento (todavía tengo que averiguar cómo cerrarlo). Cuando volví a ejecutar el programa, obviamente recibí una notificación de que había un hilo usando ese archivo, y ¿quería abrir una copia de solo lectura? Cuando dije que Sí, la GUI de Word apareció repentinamente de la nada y comenzó a procesar los archivos. Me preguntaba por qué sucedió eso;


3
¿Por qué está etiquetado como win32? - El sistema de mensajes estaba en Windows V1 (que, según recuerdo, era de 8 bits)
Hogan

Respuestas:


187

Un bucle de mensaje es un pequeño fragmento de código que existe en cualquier programa nativo de Windows. Más o menos se parece a esto:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ 
   TranslateMessage(&msg); 
   DispatchMessage(&msg); 
} 

La API GetMessage () Win32 recupera un mensaje de Windows. Su programa normalmente pasa el 99,9% de su tiempo allí, esperando que Windows le diga que ha ocurrido algo interesante. TranslateMessage () es una función auxiliar que traduce los mensajes del teclado. DispatchMessage () asegura que se llame al procedimiento de ventana con el mensaje.

Cada programa .NET habilitado para GUI tiene un bucle de mensaje, es iniciado por Application.Run ().

La relevancia de un bucle de mensajes para Office está relacionada con COM. Los programas de Office son programas compatibles con COM, así es como funcionan las clases Microsoft.Office.Interop. COM se encarga del subproceso en nombre de una coclase COM, se asegura de que las llamadas realizadas en una interfaz COM siempre se realicen desde el subproceso correcto. La mayoría de las clases COM tienen una clave de registro en el registro que declara su ThreadingModel; las más comunes (incluida Office) usan "Apartamento". Lo que significa que la única forma segura de llamar a un método de interfaz es haciendo la llamada desde el mismo hilo que creó el objeto de clase. O para decirlo de otra manera: la mayoría de las clases COM no son seguras para subprocesos.

Cada subproceso habilitado para COM pertenece a un apartamento COM. Hay dos tipos, apartamentos de un solo subproceso (STA) y un apartamento de subprocesos múltiples (MTA). Se debe crear una clase COM de subproceso de apartamento en un subproceso de STA. Puede ver esto en los programas .NET, el punto de entrada del subproceso de la interfaz de usuario de un programa de Windows Forms o WPF tiene el atributo [STAThread]. El modelo de apartamento para otros subprocesos se establece mediante el método Thread.SetApartmentState ().

Gran parte de la plomería de Windows no funcionará correctamente si el hilo de la interfaz de usuario no es STA. En particular, arrastrar y soltar, el portapapeles, cuadros de diálogo de Windows como OpenFileDialog, controles como WebBrowser, aplicaciones de automatización de la interfaz de usuario como lectores de pantalla. Y muchos servidores COM, como Office.

Un requisito estricto para un subproceso STA es que nunca debe bloquearse y debe bombear un bucle de mensaje. El bucle de mensajes es importante porque eso es lo que COM usa para ordenar una llamada de método de interfaz de un hilo a otro. Aunque .NET facilita la clasificación de llamadas (Control.BeginInvoke o Dispatcher.BeginInvoke por ejemplo), en realidad es algo muy complicado de hacer. El hilo que ejecuta la llamada debe estar en un estado conocido. No puede simplemente interrumpir arbitrariamente un hilo y forzarlo a realizar una llamada a un método, eso causaría horribles problemas de reentrada. Un hilo debe estar "inactivo", no ocupado ejecutando ningún código que esté mutando el estado del programa.

Quizás pueda ver a dónde conduce eso: sí, cuando un programa está ejecutando el bucle de mensajes, está inactivo. La clasificación real tiene lugar a través de una ventana oculta que crea COM, utiliza PostMessage para que el procedimiento de ventana de esa ventana ejecute código. En el hilo de STA. El bucle de mensajes asegura que este código se ejecute.


Respuesta muy bonita y detallada. Solo para agregar, también hay una STA especial llamada STA principal, que es la primera STA creada. Lo que idealmente debería ser el creado por su hilo de interfaz de usuario. El STA principal es donde se crean los componentes con modelo de subprocesamiento = ninguno. Si su STA principal no es el creado por su subproceso de interfaz de usuario, podría encontrarse con problemas interesantes al usar controles Activex más antiguos que no tienen ningún modelo de subprocesamiento.
quixver

12

La "bomba de mensajes" es una parte central de cualquier programa de Windows que es responsable de enviar mensajes de ventanas a las distintas partes de la aplicación. Este es el núcleo de la programación de la interfaz de usuario de Win32. Debido a su ubicuidad, muchas aplicaciones usan la bomba de mensajes para pasar mensajes entre diferentes módulos, razón por la cual las aplicaciones de Office fallarán si se ejecutan sin ninguna interfaz de usuario.

Wikipedia tiene una descripción básica .


Creo que es imposible escribir una aplicación de Windows sin un bucle de mensajes, por lo que todas las aplicaciones usan la bomba de mensajes.
Hogan

2
También puede escribir aplicaciones GUI simples sin una; por ejemplo, puede abrir cuadros de mensajes sin que su propia aplicación tenga un bucle de mensajes en su aplicación.

Si crea un cuadro de diálogo a través de DialogBox o DialogBox indirecto, no necesita un bucle de mensaje, solo necesita proporcionar una función (dlgproc) a la que Windows llamará. (y un cuadro de mensaje es solo un diálogo simple)
quixver

6

John está hablando de cómo el sistema Windows (y otros sistemas basados ​​en ventanas - X Window , Mac OS original ...) implementan interfaces de usuario asíncronas usando eventos a través de un sistema de mensajes.

Detrás de escena para cada aplicación, hay un sistema de mensajería donde cada ventana puede enviar eventos a otras ventanas u oyentes de eventos; esto se implementa agregando un mensaje a la cola de mensajes. Hay un bucle principal que siempre se ejecuta mirando esta cola de mensajes y luego enviando los mensajes (o eventos) a los oyentes.

El bucle de mensajes del artículo de Wikipedia en Microsoft Windows muestra un código de ejemplo de un programa básico de Windows y, como puede ver, en el nivel más básico, un programa de Windows es simplemente la "bomba de mensajes".

Entonces, para juntarlo todo. La razón por la que un programa de Windows diseñado para admitir una IU no puede actuar como un servicio es porque necesita que el bucle de mensajes se ejecute todo el tiempo para habilitar la compatibilidad con la IU. Si lo implementa como un servicio como se describe, no podrá procesar el manejo de eventos asincrónico interno.


6

En COM , una bomba de mensajes serializa y deserializa los mensajes enviados entre apartamentos. Un apartamento es un mini proceso en el que se pueden ejecutar componentes COM. Los apartamentos vienen en modos de un solo hilo y de hilo libre. Los apartamentos de un solo subproceso son principalmente un sistema heredado para aplicaciones de componentes COM que no admiten subprocesos múltiples. Por lo general, se usaban con Visual BASIC (ya que no admitía código multiproceso) y aplicaciones heredadas.

Supongo que el requisito de bombeo de mensajes para Word proviene de la API COM o de partes de la aplicación que no son seguras para subprocesos. Tenga en cuenta que los modelos de recolección de basura y subprocesos de .NET no funcionan bien con COM de fábrica. COM tiene un mecanismo de recolección de basura muy simplista y un modelo de subprocesamiento que requiere que haga las cosas de la manera COM. El uso de los PIA de Office estándar aún requiere que cierre explícitamente las referencias de objetos COM, por lo que debe realizar un seguimiento de cada identificador COM creado. Los PIA también crearán cosas detrás de escena si no tienes cuidado.

La integración .NET-COM es un tema en sí mismo, e incluso hay libros escritos sobre el tema. Incluso el uso de COM API para Office desde una aplicación de escritorio interactiva requiere que se salte el aro y se asegure de que las referencias se publiquen explícitamente.

Se puede suponer que Office no es seguro para subprocesos, por lo que necesitará una instancia separada de Word, Excel u otras aplicaciones de Office para cada subproceso. Tendría que incurrir en la sobrecarga inicial o mantener un grupo de subprocesos. Un grupo de subprocesos tendría que probarse meticulosamente para asegurarse de que todas las referencias COM se publicaron correctamente. Incluso iniciar y cerrar instancias requiere que se asegure de que todas las referencias se publican correctamente. Si no coloca los puntos en sus i y no cruza las t aquí, se producirá una gran cantidad de objetos COM inactivos e incluso la filtración de instancias completas de Word.


1
Hay algunas inexactitudes en su respuesta. Hay 3 tipos de apartamentos: STA (de un solo hilo), MTA (de varios hilos) y NTA (de hilo neutro). Free subproceso se utiliza para describir un componente que agrega el marshaller de subproceso libre, no existe tal cosa como un apartamento de subproceso libre. COM utiliza mensajes para comunicarse con las STA. Para los componentes que viven en un MTA (o que agregan el contador de referencias de subprocesos libres) no se requieren bucles de mensajes. AFAIK - lpc se usa para ordenar los datos de un hilo de llamada a un hilo del grupo de hilos de RPC que luego invoca el método.
quixver


0

Creo que esta discusión de Channel 9 tiene una buena explicación sucinta:

Este proceso de comunicación de ventana es posible gracias a la llamada Bomba de mensajes de Windows. Piense en Message Pump como una entidad que permite la cooperación entre las ventanas de la aplicación y el escritorio.


2
wow ... esa es una cita horrible y engañosa. (¿Una "entidad"? Err .. no.)
Hogan

4
entidad - objeto: algo que existe o se percibe como un único objeto separado encarta.msn.com/dictionary_1861608661/entity.html
Matthew Whited
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.