Jump to content


Photo

[MULTILENGUAJE] Enviar un Mensaje a todas las ventanas de una clase


  • Please log in to reply
4 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 24 May 2019 - 02:59 PM

En alguna ocasión se requiere enviar un mensaje a muchas ventanas a la vez, En este caso se puede usar el Handle HWND_BROADCAST lo que provoca el envío a todas las ventanas top-level. Pero puede ser que nuestro interés se centre sólo en una determinada clase de ventana y que no necesariamente sea top-level lo que nos plantea un problema que vengo a solucionar con este truco. La idea viene de la necesidad creada aquí, en la que doy una solución muy particular que generalizo en este truco.

En esta ocasión voy a mostrar como enviar un mensaje a todas las ventanas de una clase enumerando todas las ventanas top-level y sus hijas de forma reentrante.
 
Para ello tenemos dos API:
EnumWindows y EnumChildWindows, ambas pasan el flujo del programa a otra función de enumeración del tipo WNDENUMPROC que recorre las ventanas hasta que se devuelva false o hasta que se enumeren tosas. Nosotros vamos a usar esta función para comparar las ventanas con la clase dada y tras encontrarla enviar el mensaje deseado a dicha ventana. Luego seguiremos enumerando hasta el final para no dejarnos ninguna.
 
Para completar lo necesario, debemos tener una estructura cuyo puntero usaremos como parámetro para pasar el nombre de la clase, el tipo de mensaje y sus parámetros. Veamos el código:
 


delphi
  1. procedure PostMessageToWindowClass(WClass: PAnsiCHAR; Msg: UINT; _WParam: WPARAM; _LParam: LPARAM); stdcall;
  2. type
  3. // Estructura para definir el mensaje
  4. TWMParam = record
  5. WClass: ShortString; // Nombre de la clase
  6. Msg: UINT; // El mensaje
  7. _WParam: WPARAM;
  8. _LParam: LPARAM;
  9. end;
  10. PWMParam = ^TWMParam;
  11.  
  12. // Función de control de la enumeración reentrante
  13. function EnumWindowsProc(Handle: Thandle; Param: PWMParam): BOOL; stdcall;
  14. var
  15. Buffer: ShortString;
  16. begin
  17. Result:= true;
  18. GetClassName(Handle, @Buffer[0], 255);
  19. if lstrcmpiA(@Buffer[0], @Param.WClass[0]) = 0 then
  20. PostMessage(Handle, Param.Msg, Param._WParam, Param._LParam)
  21. else
  22. EnumChildWindows(Handle, @EnumWindowsProc, LPARAM(Param));
  23. end;
  24. var
  25. Param: TWMParam;
  26. begin
  27. // Preparando el mensaje y enumerando las ventanas
  28. lstrcpynA(@Param.WClass[0], WClass, 255);
  29. Param.Msg:= Msg;
  30. Param._WParam:= _WParam;
  31. Param._LParam:= _LParam;
  32. EnumWindows(@EnumWindowsProc, LPARAM(@Param));
  33. end;

Como podéis comprobar el tratamiento de las cadenas lo realizo a bajo nivel para que el código sea independiente de las utilidades de cadenas de delphi. El mensaje se envía con PostMessage para evitar el bloqueo en caso de no respuesta.
 
Un ejemplo de uso:


delphi
  1. PostMessageToWindowClass('ClsCapWin', WM_CAP_DRIVER_DISCONNECT, 0, 0);

Saludos.


  • 1

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 24 May 2019 - 03:10 PM

Muy interesante truco amigo, como siempre por supuesto :)

 

Solo una pregunta, ¿estos procesos no pasan lista con el Firewall y/o el Windows Defender?

 

Saludos (y)


  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 24 May 2019 - 03:44 PM

Solo una pregunta, ¿estos procesos no pasan lista con el Firewall y/o el Windows Defender?


El Firewall controla la red (WinSock entre máquinas) no los mensajes windows entre ventanas (que siempre es en la misma máquina) de forma que el envío de un mensaje con SendMessage o PostMessage que controla directamente el S.O. nunca es sospechoso y guarda las reglas de seguridad que el propio S.O. impone. El problema es si se trata de enviar mensajes entre estaciones de ventanas distintas, en cuyo caso el propio S.O. las aísla de forma que nunca llegan.

 

Saludos.


  • 1

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 24 May 2019 - 04:28 PM

El Firewall controla la red (WinSock entre máquinas) no los mensajes windows entre ventanas (que siempre es en la misma máquina) de forma que el envío de un mensaje con SendMessage o PostMessage que controla directamente el S.O. nunca es sospechoso y guarda las reglas de seguridad que el propio S.O. impone. El problema es si se trata de enviar mensajes entre estaciones de ventanas distintas, en cuyo caso el propio S.O. las aísla de forma que nunca llegan.

 

Saludos.

 

Entendido, pues ya está. Lo dicho muy interesante (y)

 

Saludos


  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 25 May 2019 - 08:17 AM

Para no dejar cojo este truco, voy a publicar una implementación en C:


cpp
  1. // Estructura para definir el mensaje
  2. struct TWMParam
  3. {
  4. char WClass[255]; // Nombre de la clase
  5. UINT Msg; // El mensaje
  6. WPARAM WParam;
  7. LPARAM LParam;
  8. };
  9.  
  10. // Función de control de la enumeración reentrante
  11. BOOL __stdcall EnumWindowsProc(HWND Handle, TWMParam *Param)
  12. {
  13. char Buffer[255];
  14. GetClassName(Handle, Buffer, 255);
  15. if(!lstrcmpiA(Buffer, Param->WClass))
  16. PostMessage(Handle, Param->Msg, Param->WParam, Param->LParam);
  17. else
  18. EnumChildWindows(Handle, (WNDENUMPROC)EnumWindowsProc, (LPARAM)Param); // Enumeramos las ventanas Child
  19. return true;
  20. }
  21.  
  22. void PostMessageToWindowClass(CHAR *WClass, UINT Msg, WPARAM WParam, LPARAM LParam)
  23. {
  24. TWMParam Param;
  25.  
  26. // Preparando el mensaje y enumerando las ventanas
  27. lstrcpynA(Param.WClass, WClass, 255);
  28. Param.Msg = Msg;
  29. Param.WParam = WParam;
  30. Param.LParam = LParam;
  31. EnumWindows((WNDENUMPROC)EnumWindowsProc, LPARAM(&Param));
  32. } 

El uso y funcionamiento es equiparable a la versión delphi

 

 

Saludos. 


  • 1




IP.Board spam blocked by CleanTalk.