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:
procedure PostMessageToWindowClass(WClass: PAnsiCHAR; Msg: UINT; _WParam: WPARAM; _LParam: LPARAM); stdcall; type // Estructura para definir el mensaje TWMParam = record WClass: ShortString; // Nombre de la clase Msg: UINT; // El mensaje _WParam: WPARAM; _LParam: LPARAM; end; PWMParam = ^TWMParam; // Función de control de la enumeración reentrante function EnumWindowsProc(Handle: Thandle; Param: PWMParam): BOOL; stdcall; var Buffer: ShortString; begin Result:= true; GetClassName(Handle, @Buffer[0], 255); if lstrcmpiA(@Buffer[0], @Param.WClass[0]) = 0 then PostMessage(Handle, Param.Msg, Param._WParam, Param._LParam) else EnumChildWindows(Handle, @EnumWindowsProc, LPARAM(Param)); end; var Param: TWMParam; begin // Preparando el mensaje y enumerando las ventanas lstrcpynA(@Param.WClass[0], WClass, 255); Param.Msg:= Msg; Param._WParam:= _WParam; Param._LParam:= _LParam; EnumWindows(@EnumWindowsProc, LPARAM(@Param)); 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:
PostMessageToWindowClass('ClsCapWin', WM_CAP_DRIVER_DISCONNECT, 0, 0);
Saludos.