2010-10-17 42 views
7

Estoy escribiendo una aplicación que a veces va a enviar notificaciones al usuario en forma de toaster messages.Detectar si el salvapantallas está activo y/o el usuario ha bloqueado la pantalla en Windows

Si el usuario no está allí, no puede ver la notificación. Entonces, lo que quiero hacer es poder verificar si el usuario ha bloqueado la pantalla o si el protector de pantalla está activado.

Toda notificación que se activa cuando el usuario no puede ver que será retrasado y se muestra cuando el usuario inicia sesión de nuevo y vuelve a su sesión.

estoy en Windows 7 a mí mismo, pero yo preferiría una solución que funciona universalmente para Windows XP y para arriba.

+0

Has publicado un enlace no válido –

+0

Aha, deshabilitaron el hotlinking. ¿Esto funciona? http://images.google.com/imgres?imgurl=http://blog.fatbusinessman.com/blog-post-images/msn-pics-in-popups.png&imgrefurl=http://blog.fatbusinessman.com/ archives/2005/04/07/msn-messenger-7-review/& usg = __ Ed4o5d78BK01ZJ3K6penXkWgsJc = & h = 287 & w = 341 & sz = 21 & hl = es & start = 0 & zoom = 1 & tbnid = _fUzeg729w42dM: & tbnh = 157 & tbnw = 187 & prev =/imágenes% 3Fq% 3Dmsn% 2Bmessenger % 2Baster% 26hl% 3Den% 26biw% 3D1600% 26bih% 3D775% 26tbs% 3Disch: 1 & itbs = 1 & iact = rc & dur = 529 & ei = jQS7TJnID9ug4QasnODRDQ & oei = jQS7TJnID9ug4QasnODRDQ & esq = 1 & page = 1 & ndsp = 33 & ved = 1t: 429, r: 11, s: 0 & tx = 146 & ty = 89 – Pieter

Respuesta

22

No hay una forma documentada de averiguar si la estación de trabajo está actualmente bloqueada. Sin embargo, puede recibir una notificación cuando se desbloquea. Suscríbete al evento SystemEvents.SessionSwitch, obtendrás SessionSwitchReason.SessionLock y Unlock.

El protector de pantalla también es problemático. Su ventana principal recibe el mensaje WM_SYSCOMMAND, SC_SCREENSAVE cuando se activa el protector de pantalla. Puede pinvoke SystemParametersInfo para verificar si se está ejecutando. Encontrará un código de muestra para esto en mi respuesta en this thread.

No hay una buena forma de averiguar si el usuario se durmió.

+3

+1 para "No hay una buena manera de averiguar si el usuario se quedó dormido". :) – zeFree

1

Hay muchas razones por las que el usuario no puede ver las notificaciones también para la reproducción de vídeo en pantalla completa o ejemplo que el usuario no está allí.

sugiero que en vez de comprobar si la notificación se puede mostrar comprobar si el usuario está ahí, se puede hacer eso mediante el control del teclado y el ratón.

+0

Eso podría funcionar, pero solo mientras el usuario no juegue juegos de pantalla completa. – Pieter

+0

@Pieter debe verificar que la pantalla no esté en modo exclusivo de pantalla completa –

3

Utilice SystemParametersInfo para detectar si el protector de pantalla está en ejecución: el tipo de llamada es SPI_GETSCREENSAVERRUNNING. Esto es compatible con Win2000 y versiones posteriores.

hay código de @dan_g en StackOverflow here para comprobar si WKSTA está bloqueado.

8

Recientemente he comprobado este código nuevamente desde previous blog post para asegurarme de que funciona en las versiones de Windows XP a 7, x86 y x64 y lo limpié un poco.

Aquí es el último código minimalista que comprueba si la estación de trabajo está bloqueada y si el salvapantallas está corriendo envuelto en dos fáciles de usar métodos estáticos:

using System; 
using System.Runtime.InteropServices; 

namespace BrutalDev.Helpers 
{ 
    public static class NativeMethods 
    { 
    // Used to check if the screen saver is running 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool SystemParametersInfo(uint uAction, 
                uint uParam, 
                ref bool lpvParam, 
                int fWinIni); 

    // Used to check if the workstation is locked 
    [DllImport("user32", SetLastError = true)] 
    private static extern IntPtr OpenDesktop(string lpszDesktop, 
              uint dwFlags, 
              bool fInherit, 
              uint dwDesiredAccess); 

    [DllImport("user32", SetLastError = true)] 
    private static extern IntPtr OpenInputDesktop(uint dwFlags, 
                bool fInherit, 
                uint dwDesiredAccess); 

    [DllImport("user32", SetLastError = true)] 
    private static extern IntPtr CloseDesktop(IntPtr hDesktop); 

    [DllImport("user32", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool SwitchDesktop(IntPtr hDesktop); 

    // Check if the workstation has been locked. 
    public static bool IsWorkstationLocked() 
    { 
     const int DESKTOP_SWITCHDESKTOP = 256; 
     IntPtr hwnd = OpenInputDesktop(0, false, DESKTOP_SWITCHDESKTOP); 

     if (hwnd == IntPtr.Zero) 
     { 
     // Could not get the input desktop, might be locked already? 
     hwnd = OpenDesktop("Default", 0, false, DESKTOP_SWITCHDESKTOP); 
     } 

     // Can we switch the desktop? 
     if (hwnd != IntPtr.Zero) 
     { 
     if (SwitchDesktop(hwnd)) 
     { 
      // Workstation is NOT LOCKED. 
      CloseDesktop(hwnd); 
     } 
     else 
     { 
      CloseDesktop(hwnd); 
      // Workstation is LOCKED. 
      return true; 
     } 
     } 

     return false; 
    } 

    // Check if the screensaver is busy running. 
    public static bool IsScreensaverRunning() 
    { 
     const int SPI_GETSCREENSAVERRUNNING = 114; 
     bool isRunning = false; 

     if (!SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref isRunning, 0)) 
     { 
     // Could not detect screen saver status... 
     return false; 
     } 

     if (isRunning) 
     { 
     // Screen saver is ON. 
     return true; 
     } 

     // Screen saver is OFF. 
     return false; 
    } 
    } 
} 

ACTUALIZACIÓN: Código actualizado en base a sugerencias de la comentarios

Cuando la estación de trabajo está bloqueada entonces el método OpenInputDesktop no devuelve un mango, de manera que podamos caer de nuevo en -OpenDesktop para un mango para asegurarse de que está bloqueado por intentar cambiar. Si no está bloqueado, su escritorio predeterminado no se activará porque OpenInputDesktop devolverá un identificador válido para el escritorio que está viendo.

+2

A menos que me falta algo, este código me volvería loco si ejecutara un temporizador en una aplicación que uso. Bastante seguro de que siempre forzará que el escritorio predeterminado esté activo, cuando no esté bloqueado. Utilicé varios escritorios y realicé el trabajo real en todos ellos. No lo uso, pero MS tiene una aplicación desktops.exe que le permite crear varios escritorios y cambiarlos también, sin estar seguro de si mucha gente lo usa, de ser así, este código no es bueno para la producción. Creo que hay una manera de obtener el escritorio de entrada actual, eso podría ser una mejor verificación. – eselk

+1

Consulte MSDN para OpenInputDesktop y GetUserObjectInformation, para obtener el nombre del escritorio activo en su lugar. – eselk

+0

@eselk: Gracias por los comentarios válidos. Si tiene diferentes escritorios nombrados (muy raros), entonces tiene razón, esto lo cambiará al predeterminado en un ciclo de temporizador. Usaré su sugerencia para usar OpenInputDesktop en su lugar, por lo que el modificador está en silencio. GetUserObjectInformation no sería útil, ya que no necesito el nombre del escritorio si utilizo OpenInputDesktop, solo el controlador está bien para hacer el cambio. Realizará las ediciones básicas del código cuando tenga la oportunidad de probarlo :) – BrutalDev

0
SystemEvents.SessionSwitch += new SessionSwitchEventHandler((sender, e) => 
     { 
      switch (e.Reason) 
      { 
       //If Reason is Lock, Turn off the monitor. 
       case SessionSwitchReason.SessionLock: 
        //SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF); 
        MessageBox.Show("locked"); 
        break; 

       case SessionSwitchReason.SessionUnlock: 
        MessageBox.Show("unlocked"); 
        break; 
      } 
     }); 

Esto indicará cuándo la sesión está bloqueada y desbloqueada.

Cuestiones relacionadas