´

C# - Recibir notificaciones cuando hayan cambios de sesión parte 3 - 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 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:

  1. 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.
  2. Crear un Hook para el WndProc nativo, el cual es por default inaccesible desde WPF
  3. (No)Registrar la ventana para recibir notificaciones
  4. 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

SNAGHTML5bb704d

 

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

 

SNAGHTML5bc02db

 

Perfecto!! Guiño eso fue todo.

Posted: 10/6/2011 17:20 por Juan Carlos Ruiz Pacheco | con no comments |
Comparte este post: