JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Subclasificación de ventanas en .NET

¿Qué es la subclasificación?

El sistema operativo Windows efectúa la comunicación entre los diversos objetos de la interfaz de usuario utilizando mensajes. Todo lo que ocurre en la interfaz requiere mensajes para ocurrir. Por ejemplo, cuando pulsas con el ratón sobre una ventana se envía un mensaje para indicar en dónde has pulsado y cómo. Si haces clic en el aspa de cerrar una ventana Windows envía un mensaje a ésta para que se cierre. Etc, etc...

Otra cuestión a tener en cuenta en este contexto es que, en contra de lo que pueda parecer, muchos objetos aparte de las propias ventanas son también ventanas. Por ejemplo, un cuadro de texto, un botón o una rejilla son ventanas (sólo que de otros tipos) y por consiguiente reciben mensajes del sistema operativo para indicarles cómo deben comportarse.

Cuando un proceso intercepta y (opcionalmente) modifica los mensajes que se envían a una ventana se dice que la ventana ha sido subclasificada.

Pero, ¿para qué puede nos puede valer esto?. En realidad para multitud de cosas.

Lo más obvio es poder engañar a un control o ventana para que se comporte como nosotros queremos en lugar de cómo le dicen que debe hacerlo. Por ejemplo podemos capturar el mensaje que le indica a una ventana que se debe maximizar, modificarlo y así impedir que lo haga. De acuerdo, hay formas más fáciles de hacer esto, pero nos da una idea ¿verdad?. Luego veremos un caso más útil.

Otra utilidad es la que nos permite responder a acciones que normalmente no podríamos detectar porque no se exponen mediante evento alguno en nuestro lenguaje de programación favorito. Por ejemplo, cuando se introduce un CD en la unidad lectora de nuestro ordenador se notifica a las ventanas con un mensaje que podemos capturar. Esta es la única forma que tendremos de hacerlo.

¿Cómo se lleva a cabo la subclasificasificación en .NET y Windows Forms?

Antes de .NET la subclasificación era bastanbte tediosa de implementar, sobre todo si en lugar de C/C++ usábamos Visual Basic.
Por fortuna en .NET es un proceso muy fácil de realizar. Todos los controles de Windows Forms que derivan de la clase base Control (incluyendo el objeto Form que representa a las ventanas de una aplicación) poseen un método llamado WndProc que es el que se encarga de gestionar los mensajes que recibe el control (o, dicho con más propiedad, la ventana). Para interceptar estos mensajes sólo tenemos que sobreescribir esta función por una propia que la sustituya. En ésta podremos obtener toda la inforamción sobre cada mensaje a través del parámetro del tipo System.Windows.Forms.Message que se le pasa automáticamente como argumento. Con esta información y sabiendo qué mensajes podemos interceptar así como su significado es muy fácil conseguir infinidad de efectos.

Por ejemplo, en el archivo que puedes descargar desde aquí (23 KB), he escrito un sencillo ejemplo que efectúa dos tareas subclasificando una ventana. Primeramente engaña a la ventana para que cuando se pulse sobre su área cliente (sobre cualquier sitio en el que no haya un control colocado), ésta piense que se ha pulsando en realidad sobre la barra de títulos. Con esto lo que conseguimos es que la ventana se mueva arrastrándola por su área cliente.
Por otra parte, como ejemplo adicional, he dejado la propiedad FormBorderStyle con el valor Sizable, es decir, que se puede cambiar su tamaño arrastrando los bordes. Sin embargo he capturado el correspondiente mensaje para impedir que se pueda modificar las dimensiones de la ventana.

Todo el código necesario para conseguirlo es el siguiente:

private const int WM_NCHITTEST = 0x84;
private const int HTCAPTION = 2;
private const int HTCLIENT = 1;
private const int WM_SYSCOMMAND = 0x112;
private const int SC_SIZE = 0xF000;

protected override void WndProc(ref System.Windows.Forms.Message m)
{

if (m.Msg == WM_SYSCOMMAND && (((int) m.WParam) & 0xFFF0) == SC_SIZE)

{

m.Result =

new System.IntPtr(0);
return;

}

base.WndProc(ref m);

if (m.Msg == WM_NCHITTEST && m.Result.ToInt32() == HTCLIENT)

{

m.Result = new IntPtr(HTCAPTION);

}

}

No lo explico con detalle. Te dejo como ejercicio interpretarlo ;-).
En el ZIP adjunto encontrarás algunas explicaciones como comentarios al código.

Te recomiendo que leas el artículo de MSDN "Windows procedures" para aprender sobre la gestión de mensajes en ventanas. En MSDN encontrarás también información sobre todos los mensajes de Windows, su significado y cómo se gestionan. Busca las constantes del código anterior para comprenderlo bien.

José Manuel Alarcón
Banner

Comentarios (1) -

Agregar comentario