• Viernes 8 de Noviembre de 2024, 13:55

Autor Tema:  API - WaitMessage  (Leído 3244 veces)

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
API - WaitMessage
« en: Martes 16 de Marzo de 2010, 01:06 »
0
¿Alguien sabría porqué el WaitMessage de la siguiente situación no funciona?:

Proyecto VB6

Declaro la función:

Private Declare Function WaitMessage Lib "user32" () As Long
Private Declare Function GetQueueStatus Lib "user32" (ByVal fuFlags As Long) As Long

Declaro todas las constantes asociadas a SendMessage y WaitMessage, y entre ellas:

Const QS_SENDMESSAGE = &H40

En el proc Private Sub Form_Load(), pongo:

  MsgBox Str(GetQueueStatus(QS_SENDMESSAGE))
  'Sigue = WaitMessage
  WaitMessage
  MsgBox "Ha pasado"

Y el resultado es que aparece el primer MsgBox con cero como contenido de la cola, y directamente, al aceptar ese MsgBox, sale el segundo diciendo que "ha pasado" por el WaitMessage sin que le mandara ningún mensaje, o sea, que se lo ha saltado.

La linea Sigue = WaitMessage puesta activa también produce lo mismo. La variable Sigue la he declarado como Long.

Entiendo que WaitMessage debería producir la suspensión de la ejecución hasta que le llegue un mensaje enviado p. ej. con SendMessage.

¿Alguien sabría qué puede pasar?

Gracias

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #1 en: Martes 16 de Marzo de 2010, 03:58 »
0
Tienes un pequeño error de concepto respecto de lo que supones que ocurre
Desde el momento que sale el msgbox, como es una ventana modal, cuando el usuario pulsa el botón para cerrar la ventana modal, acontece en ese momento un mensaje, por tanto ya hay mensajes en la cola y por tanto waitmessage, deja de ceder el control a otros hilos. ...Aparte de los mensajes de mover el ratón (mousemove)...

El problema lo tienes porque tu sólo chequeas si en la cola hay eventos de sendmessage sin procesar, te devuelve 0, es decir no hay mensajes de ese tipo en la cola, pero hay mensajes serán de otro tipo, pero los hay... coloca el mismo código  dentro de un evento click de un botón verás como 'z' devuelve diferentes valores del load del  formulario... que aparte tiene pendiente un show...

prueba con esto y lo verás tu mismo.
Código: Visual Basic
  1.  
  2. Private Sub Form_Load()
  3.     const TodosLosEventos = 191
  4.    
  5.     z = GetQueueStatus(TodosLosEventos)
  6.     sigue = WaitMessage
  7.     WaitMessage
  8.     MsgBox sigue & " Ha pasado " & z
  9. End Sub
  10.  
  11.  


WaitMessage lo puedes poner para recibir un tipo de datos boolean... si te resulta más cómodo.
«Ma non troppo»
----> ModoVacaciones = False<----

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #2 en: Miércoles 17 de Marzo de 2010, 00:49 »
0
Muchas gracias por la respuesta, Nebire.

La cuestión que he puesto es porque estoy buscando la forma de suspender la ejecución de código VB6 en medio de un procedimiento, hasta que se produzca un evento, y consumiendo los menores recursos posibles (procesador, memoria).

Se puede hacer a lo bestia con un bucle que no salga de él hasta que se produzca el evento, pero te comes el procesador aunque le pongas un DoEvents en medio.

Una de las formas alternativas que estoy mirando es esta; un "Esperar a que llegue el mensaje de que ha ocurrido el evento" mediante llamadas a la API, que no cosumen recursos; algo así como la espera de un MsgBox, que suspende la ejecución hasta que el usuario hace algo en el MsgBox, pero en este caso, el "seguir" lo produce un evento que ocurra en nuestro programa o en otro.

La verdad es que me está extrañando que esto no esté más resuelto, tanto a nivel VB6, como a nivel API, con funciones pensadas para ello, o sea un "WaitEvent".

A raiz de tu respuesta, que es cierto, aunque no le lleguen mensajes desde un SendMessage, sí hay mensajes en la cola de otras muchas cosas, se me han ocurrido algunas vías por donde tirar:

1) Filtrar los mensajes en la cola hasta detectar uno procedente de un SendMessage que sea el requerido, lo cual tiene su miga, y sobre todo, ya estamos metiendo bucles...

2) Se me ocurre investigar la función de la API SleepEx, que no me ha dado tiempo a mirarla bien, pero parece que aparte de despertar por tiempo, puede despertar por un par de condiciones que todavía no sé cómo sacarles partido para lo que quiero:


    A) An I/O completion callback function is called

    B) An asynchronous procedure call (APC) is queued to the thread


Si a alguien se le ocurre algo...

P.D.: Vuelvo a decir que me quedo sorprendido de que esto no esté resuelto... y reitero las gracias

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #3 en: Miércoles 17 de Marzo de 2010, 14:38 »
0
El problema que planteas está resuelto, otra cosa es que tu no veas claramente como se logra.

La respuesta son los eventos. Un evento es precisamente eso, compartimentar código de ejecución...
Y efectivamente se necesita una función callback para 'estudiar' los eventos y cuando suceda el deseado producir el evento.
Dado que tu quieres que no se precesen en resto de eventos mientras no llegue un evento de tipo determinado, debes cerrar en la función de callback el reenvío hacia adelante de todo los eventos.

Te pondré un sencillo ejemplo que puedas calcar y hacer los cambios que precises... si sigues interesado, dame un par de días, que encuentre una hora disponible para realizarlo...

p.d.: también puedes optar por la función SignalObjectAndWait y / ó WaitForSingleObject.
«Ma non troppo»
----> ModoVacaciones = False<----

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #4 en: Viernes 19 de Marzo de 2010, 14:59 »
0
Me acabo de dar cuenta releyendo tu mensaje, que me ofrecías más ayuda "si sigo interesado". SÍ, sigo MUY interesado y agradecido.

No me quedé parado por mi parte, lo que pasa es que entre que cada uno tiene su nivel..., y que la documentación y ejemplos sobre esto, yo al menos, no la encuentro fácil, pues voy despacio.

De momento, sigo pensando que la función SleepEx puede valer, al menos en parte. De hecho, la instrucción SleepEx(INFINITE, TRUE), creo que suspendería la ejecución adecuadamente en espera de "algo" en la linea de lo que yo planteo. Ahora hay que diseñar el "algo" convenientemente, y quizá con las funciones QueueUserAPC y APCProc Callback se consiga. En ello estoy, pero despacio y no sé si conseguiré finalizar el objetivo.

Si me ayudas, te lo agradecería.

Saludos

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #5 en: Sábado 20 de Marzo de 2010, 08:38 »
0
Hola otra vez. He estado dándole más vueltas y he abordado otro camino; el de los eventos y WaitForSingleObject. Creo que el esquema no anda muy descaminado, pero algo falla. Es el siguiente:

He hecho dos proyectos VB6 que he intentado adjuntar pero no me ha dejado la web del foro porque parece que no tengo privilegios para ello (además, me ha tocado escribir el mensaje otra vez porque el cabrito del sistema no lo ha mantenido al volver atrás como no me dejaba adjuntar, cosa que podía advertir desde el principio o estar capada la opción, lo digo por si el moderador y los webmaster...). Bueno, los he puesto en el siguiente enlace:

megaupload.com/?d=BN6313RD   (es que no me deja poner enlaces tampoco, por eso no lo pongo completo)

La idea es; un proyecto tiene basicamente un CreateEvent y un SetEvent. Con ello deberíamos tener evento por el sistema. Y el otro tiene el OpenEvent para escucharlo y el WaitForSingleObject para esperar a que suceda.

Parece que el el primero funciona, salvo quizá en algo relacionado con el nombre del evento, y sea por ello por lo que el otro no lo identifica. Y el segundo parece que no identifica el evento y el WaitForSingleObject no se espera, pasa de largo.

He puesto varios MsgBox para que cante datos de paso y el de después del WaitForSingleObject da error; un error 5 (ERROR_ACCESS_DENIED), he intentando meterle a capón el handler del evento con un inputbox, entonces el error es el 6 (ERROR_INVALID_HANDLE) (y eso que se lo meto a capón).

La conexión del CreateEvent con OpenEvent por el nombre dado al evento es el procedimiento sugerido en MSDN; "... The creating thread can also specify a name for the event object. Threads in other processes can open a handle to an existing event object by specifying its name in a call to the OpenEvent function ...".

Anda Nebire, por favor, a ver si puedes abrir camino.

Gracias

Nebire

  • Miembro HIPER activo
  • ****
  • Mensajes: 670
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #6 en: Jueves 25 de Marzo de 2010, 15:39 »
0
Bueno, tenía un hueco en dicho momento, pero llevo unos días bastante ocupado y todavía estaré bastante ocupado una semana más por lo menos, pero lo anoto y en cuanto encuentre un tiempo libre te lo hago.

Mientras intenta ver si logras resolverlo por tu ingenio.
Eso si, cuando hablo de eventos, no necesariamente estoy hablando de los eventos de la API, los de vb valen también.

Te pongo un resumen de como es el procedimiento (con el poco tiempo que ahora mismo tengo), aunque se pueda implementar con las variaciones que cada uno considere.

Primero debemos decidir, si la aplicación ha de tener capacidad de decidir si 'autoesperar' cuando solicita una petición o si esta actúa como un servicio y por tanto siempre espera hasta que otra aplicación la active o la pare.

Sea como fuere hay que establecer un pequeño protocolo para que una aplicación comunique a la otra, lo mejor para ello es disponer de unos datos que ambas aplicaciones sepan entender. Para esto lo mejor es inyectar (encapsular) todo el protocolo en una clase de la que ambas aplicaciones tienen una instancia.

Esta clase portaría toda la funcionalidad y tendría al menos 2 eventos. Y tendría 2 campos que por comodidad podríamos llamar cliente y servidor, cliente sería un puntero a la aplicación que tiene que esperar y servidor sería un puntero a la aplicación que en un momento dado debe enviar el mensaje esperado. El tipo de mensaje esperado debería ser un mensaje de usuario (WM_USER), y el código recibido es lo que la clase trata en profundidad, por ejemplo un valor x enviado al servidor pone al cliente en modo de espera y estará así hasta que el servidor le envíe un valor de mensaje Y, esto se le comunica al servidor mediante el evento a tal fin, una vez que el servidor devuelva por referencia si acepta o no la petición delcliente, la clase pondría al cliente en espera... como ya se indicó esto sería usando una función de callback, cuando se reciben mensajes se comparan con el estado establecido en la clase (esperando=true ?), si es true, se comprueba si es wm_user y si lo es si tiene el 'valor esperado', si es así cambiamo estado (esperando=false), ahora todos los mensajespasan, antes todos rebotaban (exit sub). En esta parte, pued eusarse alguna función de Wait de la API, si cumple nuestros propósitos o bien dejarlo tal como lo hemos descrito, no se notará mucha diferencia de rendimiento,  ya que las funciones wait hacen esto mismo, interponer una función callback y filtrar.

Los filtros a este nivel son ra´pidos porque los mensajes no seprocesan, sólo se filtran, es el procesarlos (todos) lo que produce  una caída de rendimiento si luego van a ser descartados.

Las funciones wait, no obstante están un 'nivel' más arriba pues, es decir estarían colocados antes que cualquiera de nuestras funciones callback, en una posible cascada, de hecho están en el nivel donde se decide que mensajes se envían o no a una aplicación.
«Ma non troppo»
----> ModoVacaciones = False<----

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #7 en: Jueves 25 de Marzo de 2010, 23:36 »
0
Voy a ver si lo consigo a partir de tus explicaciones. Así en una primera leida, me creo que no lo conseguiré, pero lo voy a intentar... y si lo consigo, por supuesto lo pongo aquí.

Creo que este problema que planteo es bastante "de propósito general", uséase, con amplia aplicación y con gente por ahí pidiendo ayuda en una solución, según he visto buscando en Google, pero no he visto soluciones. Es por todo ello por lo que decía que me sorprende que las soluciones no estén más al alcance general; bien por soluciones directas implementadas en VB o en API, o por soluciones más desarrolladas que estén publicadas por ahí en foros p. ej.

En el caso inmediato que yo lo quiero aplicar, el código "esperante" iría en un VB para aplicaciones (los de Office p. ej.) y el desencadenante, en un proyecto VB6.

Gracias, Nebire, y si algún otro espontáneo quiere colaborar... gracias tb

epko

  • Nuevo Miembro
  • *
  • Mensajes: 6
    • Ver Perfil
Re: API - WaitMessage
« Respuesta #8 en: Sábado 2 de Octubre de 2010, 17:50 »
0
He estado fuera de juego 6 meses. Escribo para decir que a mí me resulta difícil implementar la solución que describe Nebire, no obstante, acabo de ver que otro forero dió solución por la vía de los mensajes entre aplicaciones, lo podeis ver en canalvisualbasic.net/foro/visual-basic-6-0/api-waitmessage-14635/
a quien se lo he agradecido mucho. Hay un pequeño error y es que en el código común de los dos proyectos, hay que meter tb la llamada a API de la función PostMessage, o al menos ponerla en el proyecto que envía el mensaje.

Si alguien consigue solución mediante eventos, creo que estaría muy bien como un recurso más.