Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting if the screensaver is active and/or the user has locked the screen in Windows

Tags:

c#

windows

I'm writing an app that at times will send notifications to the user in the form of toaster messages.

If the user is not there, he can't see the notification. So what I wanna do is be able to check if the user has locked the screen or if the screensaver happens to be activated.

Any notification that is triggered while the user cannot see it will be delayed and shown when the user logs back in and resumes his session.

I'm on Windows 7 myself, but I'd prefer a solution that works universally for Windows XP and up.

like image 431
Pieter Avatar asked Oct 17 '10 12:10

Pieter


People also ask

How do I know if my screensaver is running?

When the screen saver runs, it typically runs a file with a . scr file extension. If we want to know whether or not the screen saver is running all we have to do is check and see if there are any processes running that have an executable name ending in . scr.

Is screensaver a Lock screen?

The reason it's called a lock screen is because it's normally password-protected, so the overlaid image is 'locked' in place until you enter the password. Your computer continues to run normally with a lockscreen. A screen saver is a moving image intended to prevent burn-in on old CRT monitors.

How do you make your screensaver your Lock screen?

Go to Settings > Personalization > Lock screen, and select Screen saver settings. In the Screen Saver Settings window, choose a screen saver from the drop-down list.

What is a locking screensaver?

This helps prevent others from viewing or using your device when you're not around. Set up your computer and mobile devices to automatically go to screensaver after a certain amount of inactivity. In addition, manually lock when leaving your device unattended.


2 Answers

There is no documented way to find out if the workstation is currently locked. You can however get a notification when it un/locks. Subscribe the SystemEvents.SessionSwitch event, you'll get SessionSwitchReason.SessionLock and Unlock.

The sceen saver is troublesome too. Your main window gets the WM_SYSCOMMAND message, SC_SCREENSAVE when the screen saver turns on. You can pinvoke SystemParametersInfo to check if it running. You'll find sample code for this in my answer in this thread.

There is no good way to find out if the user fell asleep.

like image 86
Hans Passant Avatar answered Oct 06 '22 00:10

Hans Passant


I have recently checked this code again from a previous blog post to ensure it works on versions of Windows XP to 7, x86 and x64 and cleaned it up a bit.

Here is the latest minimalist code that checks if the workstation is locked and if the screensaver is running wrapped in two easy to use static methods:

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;
    }
  }
}

UPDATE: Code updated based on suggestions in the comments.

When the workstation is locked then the OpenInputDesktop method does not return a handle so we can fall-back on OpenDesktop for a handle to make sure it's locked by trying to switch. If it's not locked then your default desktop will not be activated since OpenInputDesktop will return a valid handle for the desktop you are viewing.

like image 36
BrutalDev Avatar answered Oct 05 '22 22:10

BrutalDev