2010-05-31 27 views
8

Cuando enviamos un mensaje, "si la ventana especificada fue creada por el hilo de llamada, el procedimiento de ventana se llama inmediatamente como una subrutina". Pero "si la ventana especificada fue creada por un hilo diferente, el sistema cambia a ese hilo y llama al procedimiento de ventana apropiado. Los mensajes enviados entre hilos se procesan solo cuando el hilo receptor ejecuta el código de recuperación de mensaje" (tomado de MSDN documentación para SendMessage).¿Cómo se ejecuta SendMessage desde un hilo diferente?

Ahora, no entiendo cómo (o, más apropiadamente, cuando ) el procedimiento ventanas de destino se llama. Por supuesto, el hilo de destino no será reemplazado (el contador del programa no se cambia). Supongo que la llamada se producirá durante alguna función de espera (como GetMessage o PeekMessage), ¿es verdad? Ese proceso está documentado en detalle en alguna parte?


Actualización: la razón de que se explica por la bandera QS_SENDMESSAGE de GetQueueStatus() y MsgWaitForMultipleObjects():

QS_SENDMESSAGE 
A message sent by another thread or application is in the queue. 

Esto, junto con las observaciones adicionales en la documentación de MSDN, significa que un mensaje enviado por otro el hilo se publica realmente en la cola. Luego, tan pronto como se llamen a GetMessage o PeekMessage, se procesará antes de que se envíe cualquier otro mensaje publicado directamente al procedimiento de ventana.

Respuesta

5

Veo algo de confusión aquí.

De acuerdo con la documentación de MSDN, cuando se toca la cola de mensajes del hilo actual con la intención de procesamiento de mensajes (por ejemplo, si se llama a PeekMessage o GetMessage), todo espera Enviado (es decir, no en cola) mensajes de otros hilos son manejados - pasaron a la WndProc - y luego se comprueba la cola de mensajes, por lo que:

  • enviaron mensajes nunca se pasan por DispatchMessage y se manejan tan pronto como sea posible:
    • en el hilo actual, que simplemente pasan a WndProc
    • en otro hilo, que se manejan antes de cualquier procesamiento mensaje publicado
  • a ser capaz de manejar los mensajes enviados, el subproceso de destino todavía necesita una suministro de mensajes
  • PostThreadMessage hace exactamente lo que dice - mensajes un mensaje en una cola de hilos - tales mensajes no están dirigidos a cualquier ventana y debe manejarse explixitly
  • el sólo mensajes manejados por DispatchMessage son los creados por PostMessage o alguna instalación del sistema (contadores de tiempo, eventos, entrada de usuario, etc.)
  • para evitar los puntos muertos, utilice SendNotifyMessage, SendMessageTimeout o SendMessageCallback en lugar de llanura SendMessage entre diferentes hilos

Para obtener más información, estudie la sección Observaciones de la entrada MSDN PeekMessage.

+0

Gracias, esto definitivamente responde mi duda. Desafortunadamente en la documentación Get/PeekMessage de Windows CE 6 esa parte faltaba en la sección "Comentarios" (me pregunto si WinCE GWES tiene un comportamiento diferente y sutil que Win32 USER). – Wizard79

+4

La documentación de GetMessage dice que "despacha mensajes enviados entrantes hasta que un mensaje publicado esté disponible para su recuperación". Es por eso que SendMessage dice "los mensajes enviados entre hilos se procesan solo cuando el hilo receptor ejecuta el código de recuperación de mensajes". En consecuencia, enviar un mensaje a un hilo diferente requiere que el hilo objetivo tenga un bucle de mensaje. Enviar un mensaje en el mismo subproceso resulta en una llamada de procedimiento de ventana directa en el mismo subproceso. Enviar un mensaje a otro hilo da como resultado una llamada al procedimiento de ventana directa en el hilo * objetivo desde una llamada GetMessage *. – Triynko

+0

Ahora, en lo que respecta a la prioridad de los mensajes enviados y publicados, está muy claro. Si el bucle de mensaje de destino está esperando a que se publiquen los mensajes (es decir, está bloqueando dentro de una llamada de GetMessage), un mensaje enviado se procesará primero si llega antes de un mensaje publicado. Si el bucle de mensaje de destino está procesando un mensaje (es decir, llamando a Translate o DispatchMessage), un mensaje enviado se procesará antes de un mensaje publicado, incluso si llega más tarde, siempre que llegue antes de que el bucle de mensaje de destino termine de procesarse cualquier mensaje que esté en medio del procesamiento. – Triynko

1

Respuesta corta: Cuando el hilo objetivo llama a GetMessage (o PeekMessage) seguido de DispatchMessage, se recibe y se maneja el SendMessage del otro hilo.

No estoy seguro si la SendMessage recibida reemplaza a otros mensajes en la cola o no. De cualquier manera, un SendMessage de un hilo a otro es como decir: "Publique este mensaje en la cola de mensajes del otro hilo. Regrese cuando el hilo haya terminado de procesarlo".

Un ahora para una respuesta que no pidió:

En general, cuando programo interacciones entre el hilo de interfaz de usuario principal y un subproceso de trabajo, trato de evitar el uso de SendMessage. Si no tiene cuidado, puede entrar en una situación donde ambos hilos están en punto muerto el uno al otro. (Piense en el caso donde el hilo principal llama a WaitForSingleObject para esperar a que se complete el hilo de trabajo, pero el hilo de trabajo está bloqueado en SendMessage de nuevo al hilo de UI).

+0

OK, entonces hacer un SendMessage desde un hilo diferente (de hecho, incluso un proceso diferente en mi caso) es como usar un "PostMessage de bloqueo"? Mi problema es que tengo que crear un bucle de mensaje secundario utilizando MsgWaitForMultipleObjectsEx y PeekMessage (en Windows CE). – Wizard79

+0

No estoy seguro de lo que realmente está tratando de hacer, pero si es para comunicaciones entre procesos, entonces probablemente debería usar COM. – selbie

+0

Tengo que solucionar algunas limitaciones del sistema en el que estoy trabajando, tengo que emular un escenario síncrono bloqueando la espera de un mensaje (que, por supuesto, es asincrónico). Mientras tanto, debo responder a los mensajes enviados por el shell. Por alguna razón, en algunas circunstancias, nuestro shell personalizado se cuelga hasta que recibí ese mensaje, y no puedo entender por qué ... Sin embargo, su respuesta en SendMessage es satisfactoria para la duda que tenía. – Wizard79

1

Cada ventana está asociada a un hilo. Puede usar GetWindowThreadProcessId para recuperar el hilo de cada ventana. Si envía un mensaje a una ventana del otro hilo con respecto al PostThreadMessage, el mensaje se colocará en la cola de mensajes del hilo. El hilo debe tener un bucle de mensaje de obtención (con GetMessage por ejemplo) para obtener los mensajes y enviarlos allí al procedimiento de ventana de la ventana.

Si llama al SendMessage en lugar de PostThreadMessage llama directamente al Procedimiento de Windows sin colocarlo en la cola de mensajes. Algunos mensajes no en cola se envían también de inmediato al procedimiento de la ventana de destino, omitiendo la cola de mensajes del sistema y la cola de mensajes de la secuencia. (ver http://msdn.microsoft.com/en-us/library/ms644927(VS.85).aspx#nonqueued_messages).La razón principal para usar SendMessage en lugar de PostThreadMessage si desea dar cierta información de otra ventana (control) como leer un texto de otro control durante el procesamiento de otro mensaje. Debe hacer esto solo si realmente lo necesita. Por lo tanto, si usa SendMessage para enviar un mensaje a una ventana de otro hilo, su tema actual debe estar bloqueado por algún tiempo.

Puede ser una buena idea usar PostThreadMessage o SendMessageCallback en lugar de SendMessage si es posible.

+0

Gracias por la respuesta, pero la pregunta en realidad fue acerca de lo que ocurre internamente cuando se invoca SendMessage en un hilo diferente, más precisamente cómo se llama al procedimiento de ventana de destino. – Wizard79

Cuestiones relacionadas