June 2011 - Artículos
Tomado de
El bucle de mensajes - message loop - WndProc
-------------------
Debido a que este es un tema recurrente en este blog, he decidido extraer este pequeño aporte hecho en otro artículo para poder referenciarlo puntualmente cuando se requiera.
Las ventanas – y los demás controles – funcionan gracias a un bucle de mensajes, todo lo que manejamos nosotros como eventos : click del mouse, mover, cerrar, cambiar tamaño, maximizar etc, realmente es controlado por un bucle en donde se envían diferentes mensajes a la ventana, esta a su vez tiene un procedimiento que recibe estos mensajes y con base a los mensajes recibidos puede hacer una u otra cosa según se programe.
Si, para algunos esto ya debe estar sonando a cuento, pero las cosas son así por debajo de lo que usamos tradicionalmente. El tema del artículo no es explicar como funciona un ciclo de mensajes así que por el momento lo dejaremos hasta allí y quien quiera profundizar puede consultar esta fuente en internet
http://www.winprog.org/tutorial/message_loop.html
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - Como obtener un manejador (handle) para una ventana de WPF
-------------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos el menejador ( handle ) de la ventana el cual no es expuesto por WPF.
Para obtenerlo debemos hacer uso de una clase utilitaria llamada WindowInteropHelper la cual tiene un elemento muy importante, la propiedad Handle que no es ni más menos que el manejador a la ventana de WPF. Su uso es muy sencillo:
[csharp]
Window miVentana = this;
WindowInteropHelper interopHelper = new WindowInteropHelper(miVentana);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
El código esta así por claridad, dentro del código de una ventana de WPF a la que querramos obtenerle el manejador basta con hacer:
[csharp]
WindowInteropHelper interopHelper = new WindowInteropHelper(this);
IntPtr manejadorVentana = interopHelper.Handle;
[/csharp]
Ya teniendo el manejador de la ventana podemos acceder a muchas otras funcionalidades fuertemente atadas con el SO como por ejemplo las expuestas en Win32Api o equivalente en otras plataformas
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - usar el WndProc en una Ventana WPF
----------------------------------
WPF es una parte del .Net Framework muy robusta pensada para ser multiplataforma, pero a veces necesitamos que nuestra aplicación interactue con aspectos más relacionados con el sistema operativo donde se ejecuta. En estos casos requerimos interceptar mensajes en el WndProc.
Para lograr acceder al WndProc debemos obtener un manejador (handle) para la ventana WPF y seguidamente utilizar la clase utilitaria HwndSource para crear el Hook, allí creamos un delegado el cual hara las veces de WndProc de nuestra ventana.
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Crear un hook al WndProc
HwndSource sourceWindow = HwndSource.FromHwnd(interopHelper.Handle);
sourceWindow.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//Hacer algo...
return IntPtr.Zero;
}[/csharp]
Y eso es todo ;)
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# - Recibir notificaciones cuando hayan cambios de sesión parte 3 - WPF
------------------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
En artículos anteriores enseñe como crear una librería para interceptar las notificaciones generadas en el sistema cuando se hacen cambios de sesión y como utilizar esa librería en Windows Forms. En este artículo enseñare como hacer uso de ese componente en una aplicación para Windows Presentation Foundation - WPF.
LETS CODE!
Para Windows forms esta tarea es bastante sencilla e intuitiva, pero este no es el caso de WPF dadas las propias características de esta tecnología.
He creado una aplicacion WPF sencilla con un ListBox que se irá llenando a medida que lleguen notificaciones de cambios en las sesiones.
Para comenzar recibiendo notificaciones lo primero que se supone debemos hacer es registrar nuestra Ventana ya que eso dice en la documentación de msdn:
WTSRegisterSessionNotificationSession change notifications are sent in the form of a WM_WTSSESSION_CHANGE message. These notifications are sent only to the windows that have registered for them using this function.
Para el caso de WPF esto no es necesario ya que al parecer PresentationCore ya lo hace por nosotros.
Ya que por defecto ya estamos recibiendo las notificaciones de cambios en las sesiones, lo que debemos hacer es interceptar estos mensajes en el WndProc de manera muy similar a como lo hicimos con Windows Forms en el artículo anterior. Fácil, solo que... una ventana de WPF no expone el WndProc pequeño problema. :(
En resumen lo que debemos tener en cuenta para poder interceptar los mensajes desde WPF es:
- Obtener el manejador de la ventana, ya que lo necesitamos para el siguiente punto , y de paso también por default es inaccesible para WPF.
- Crear un Hook para el WndProc nativo, el cual es por default inaccesible desde WPF
- (No)Registrar la ventana para recibir notificaciones
- Modificar el comportamiento del WndProc
Obtener el manejador de la ventana
Como ya lo comente necesitamos el manejador para posteriormente crear un Hook al WndProc, en este mini artículo explico C# - Como obtener un manejador (handle) para una ventana de WPF , pero en resumen el código esta acá:
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
}[/csharp]
Crear un Hook para el nativo
Aunque ya estamos recibiendo las notificaciones lo cierto es que no estamos haciendo nada con ellas, para interceptarlas y comenzar a hacer algo es necesario usar el WndProc de la ventana WPF y capturar el mensaje de notificación que se envía desde el sistema de ventanas.
Como ya lo escribí arriba, el WndProc no esta disponible para una ventana WCF, para utilizarlo debemos obtener el manejador de la ventana, cosa que ya hicimos y crear un Hook al WndProc, en este artículo explico C# - Como usar el WndProc en una Ventana WPF , pero en resumen el código esta acá:
[csharp]
WindowInteropHelper interopHelper;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Crear un hook al WndProc
HwndSource sourceWindow = HwndSource.FromHwnd(interopHelper.Handle);
sourceWindow.AddHook(WndProc);
}[/csharp]
Donde el parámetro WndProc es realmente un delegado a un método llamado intencionalmente así, como lo veremos más adelante.
Una vez creado el hook, debemos interceptar los mensajes del WndProc, revisamos la variable wParam del mensaje ya que esta nos da detalles adicionales acerca del evento que se ha generado. Para efectos de este ejemplo simplemente convierto ese valor a su equivalente en los enum de la librería creada en el articulo previo, y adiciono esa cadena al listbox para que básicamente nos vaya mostrando los mensajes que van llegando.
[csharp]
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == W32HandleSessionChanges.WM_WTSSESSION_CHANGE)
{
var name = Enum.GetName(typeof(SessionNotificationMsg), (SessionNotificationMsg)wParam);
this.listBoxOne.Items.Add(name);
handled = true;
return (IntPtr)1;
}
return IntPtr.Zero;
}[/csharp]
NOTA IMPORTANTE
WPF por defecto nos permite recibir notificaciones de la sesión actual, si queremos recibir notificaciones de todas las sesiones debemos des registrar la ventana y luego registrarla nuevamente con el parámetro NOTIFY_FOR_ALL_SESSIONS, así:
[csharp]
//Conseguir el Handle de la ventana
interopHelper = new WindowInteropHelper(this);
//Des Registramos
W32HandleSessionChanges.WTSUnRegisterSessionNotification(interopHelper.Handle);
//Registramos la forma para recibir notificaciones
W32HandleSessionChanges.WTSRegisterSessionNotification(interopHelper.Handle, NotifyType.NOTIFY_FOR_ALL_SESSIONS);
[/csharp]
El resultado
Ejecutamos el programa

Bloquemos nuestra sesión de Windows, volvemos a ingresar y…

Perfecto!!
eso fue todo.
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# – Recibir notificaciones cuando hayan cambios de sesión parte 2 – Windows Forms
----------------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
En mi artículo anterior enseñe como crear una librería para interceptar las notificaciones generadas en el sistema cuando se hacen cambios de sesión, en este artículo enseñare como hacer uso de ese componente en una aplicación para Windows Forms.
LETS CODE!
Divide y vencerás!, mi principio favorito. Seguiremos estos tres pasos:
- Registrar la ventana para recibir notificaciones
- Modificar el comportamiento del WndProc
- Des registrar la ventana para dejar de recibir notificaciones
He creado una aplicacion Windows Forms sencilla con un ListBox que se irá llenando a medida que lleguen notificaciones de cambios en las sesiones.
Registrar la ventana para recibir notificaciones
Para comenzar recibiendo notificaciones lo primero que debemos hacer es registrar nuestra Ventana, la Form, utilizando la API, para ello utilizamos la libreria que cree en C# - Recibir notificaciones cuando hayan cambios de sesión parte 1 simplemente usamos el evento load del form.
[csharp]
private void Form1_Load(object sender, EventArgs e)
{
//Registramos la forma para recibir notificaciones
W32HandleSessionChanges.WTSRegisterSessionNotification(this.Handle, NotifyType.NOTIFY_FOR_ALL_SESSIONS);
}
[/csharp]
Con esto nuestra ventana ya comienza a recibir notificaciones de cambios en las sesiones.
Modificar el comportamiento del WndProc
Aunque ya estamos recibiendo las notificaciones lo cierto es que no estamos haciendo nada con ellas, para interceptarlas y comenzar a hacer algo es necesario hacerle override al WndProc del form y capturar el mensaje de notificación que se envía desde el sistema de ventanas.
Una vez interceptado debemos revisar la propiedad wParam del mensaje ya que esta nos da detalles adicionales acerca del evento que se ha generado. Para efectos de este ejemplo simplemente convierto ese valor a su equivalente en los enum de la librería creada en el articulo previo, y adiciono esa cadena al listbox para que básicamente nos vaya mostrando los mensajes que van llegando.
En este caso paso como parámetro NOTIFY_FOR_ALL_SESSIONS para recibir notificaciones de cambios en todas las sesiones no solo en la actual
[csharp]
protected override void WndProc(ref Message m)
{
//Verificamos cuando el mensaje recibido sea el de cambios en la sesión
if (m.Msg == W32HandleSessionChanges.WM_WTSSESSION_CHANGE)
{
//convertimos el valor de wParam a su equivalente en nombre del enum
var name = Enum.GetName(typeof(SessionNotificationMsg), (SessionNotificationMsg)m.WParam);
this.listBox1.Items.Add(name);
}
base.WndProc(ref m);
}
[/csharp]
Des registrar la ventana para dejar de recibir notificaciones
Esta es la parte más fácil, antes de cerrar la ventana la des registramos:
[csharp]
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
//Des Registramos la forma para no recibir notificaciones
W32HandleSessionChanges.WTSUnRegisterSessionNotification(this.Handle);
}
[/csharp]
El resultado
Ejecutamos el programa

Bloquemos nuestra sesión de Windows, volvemos a ingresar y…

Perfecto!! 
En un próximo articulo veremos como hacer lo mismo con WPF.
Esta es una copia cruzada de mi blog original.
Puedes leer el articulo original con código coloreado y demás utilidades en
C# – Recibir notificaciones cuando hayan cambios de sesión parte 1
--------------
Artículos de este tema:
*Realmente son 6 articulos si contamos los mini post a los que se hace referencia
A veces necesitamos que nuestro software audite ciertos eventos generados por el equipo, como por ejemplo cuando se abren o cierran sesiones. Esto es importante por ejemplo para disparar procesos pesados cuando el computador no este en uso o para realizar procesos de auditoria.
Como es de suponerse el .Net Framework no trae nada que nos apoye en esa tarea ya que esta profundamente relacionada con el sistema operativo y ya que el CLR es multiplataforma este tipo de cosas no vienen soportadas. Se debe hacer uso de la Api de Windows.
En este artículo crearé una librería sencilla que permite ser notificado cuando suceden estos eventos bien sea en la sesión actual o a través de las diferentes sesiones iniciadas en el sistema.
NUESTRO KIT DE HERRAMIENTAS
Las cosas que necesitamos de la Api de Windows para realizar esta labor se describen a continuación
Funciones
Constantes para llamar a WTSRegisterSessionNotification
- NOTIFY_FOR_THIS_SESSION : Notifica eventos de la sesión actual
- NOTIFY_FOR_ALL_SESSIONS : Notifica eventos de todas las sesiones del sistema
Constantes relacionadas con las notificaciones
- WM_WTSSESSION_CHANGE : Mensaje generado cuando suceden los eventos de cambios en la sesión
- Parámetros:
- WTS_CONSOLE_CONNECT: Una sesión se ha conectado por terminal de consola.
- WTS_CONSOLE_DISCONNECT: Una sesión se ha desconectado por terminal de consola.
- WTS_REMOTE_CONNECT: Una sesión se ha conectado por una terminal remota.
- WTS_REMOTE_DISCONNECT: Una sesión de terminal remota se ha desconectado.
- WTS_SESSION_LOGON: Un usuario se ha logueado en la sesión.
- WTS_SESSION_LOGOFF: Un usuario se ha deslogueado de la sesión
- WTS_SESSION_LOCK: Una sesión se ha bloqueado.
- WTS_SESSION_UNLOCK: Una sesión se ha desbloqueado.
- WTS_SESSION_REMOTE_CONTROL: Una sesión ha cambiado su estado de control remoto. Par determinar el estado se debe hacer uso de GetSystemMetrics y revisar la métrica SM_REMOTECONTROL.
LETS CODE!
Preparando las funcionalidades de la Win32 API
Creamos una clase para centralizar los llamados a la API, allí con ayuda de DllImport importamos las funciones que requerimos y definimos todas las constantes necesarias, de preferencia agrupadas en enums:
Enums necesarias
[csharp]
/// Notificaciones a recibir
public enum NotifyType
{
/// Notificacion para la sesion actual
NOTIFY_FOR_THIS_SESSION = 0,
/// Notificacion para todas las sesiones del sistema
NOTIFY_FOR_ALL_SESSIONS = 1
}
/// Tipo de notificacion recibida
public enum SessionNotificationMsg
{
/// Una sesión se ha conectado por terminal de consola.
WTS_CONSOLE_CONNECT = 0x1,
/// Una sesión se ha desconectado por terminal de consola.
WTS_CONSOLE_DISCONNECT = 0x2,
/// Una sesión se ha conectado por una terminal remota.
WTS_REMOTE_CONNECT = 0x3,
/// Una sesión de terminal remota se ha desconectado.
WTS_REMOTE_DISCONNECT = 0x4,
/// Un usuario se ha logueado en la sesión.
WTS_SESSION_LOGON = 0x5,
/// Un usuario se ha deslogueado de la sesión.
WTS_SESSION_LOGOFF = 0x6,
/// Una sesión se ha bloqueado.
WTS_SESSION_LOCK = 0x7,
/// Una sesión se ha desbloqueado.
WTS_SESSION_UNLOCK = 0x8,
/// Una sesión ha cambiado su estado de control remoto. Par determinar el estado se debe hacer uso de GetSystemMetrics y revisar la métrica SM_REMOTECONTROL.
WTS_SESSION_REMOTE_CONTROL = 0x9
}
[/csharp]
Ahora la clase para manejar la W32API
[csharp]
using System;
using System.Runtime.InteropServices;
public static class W32HandleSessionChanges
{
///
/// Registra una ventana para recibir notificaciones de cambios en las sesiones
///
/// Manejador de la ventana
/// Modificadores
/// NOTIFY_FOR_THIS_SESSION, NOTIFY_FOR_ALL_SESSIONS
///
///
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSRegisterSessionNotification(IntPtr hWnd, NotifyType dwFlags);
///
/// Des Registra una ventana que recibe notificaciones de cambios en las sesiones
///
/// Manejador de la ventana
///
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
/// Mensaje recibido cuando hay cambios en las sesiones
public const int WM_WTSSESSION_CHANGE = 0x2b1;
}
[/csharp]
Para usarla basta con hacer uso del método W32HandleSessionChanges.WTSRegisterSessionNotification, el parámetro hWnd es el manejador de la ventana donde queremos recibir la notificaciones, esto nos permite registrar la ventana actual para recibir este tipo de mensajes, asi que una vez hecho esto se deben interceptar los mensajes para hacer lo que necesitemos. Una vez se valla a cerrar nuestro programa siempre es coveniente llamar a WTSUnRegisterSessionNotification
La librería que he creado se puede usar en diferentes tipos de aplicación para comenzar a recibir notificaciones, en próximos artículos les mostrare como utilizarla en Windows Forms y en WPF.