Phi
Phi

Reputation: 497

Check if Windows is currently locked

I'm on Windows 10 Pro x64 ver 1703 build 15063.726, trying to write a program rebooter service. It runs under my user on admin permissions, every 10 minutes via a scheduled task.

If the server is unavailable or borked:

The only complication is detecting if the computer is locked. I've tried several methods:

  1. OpenInputDesktop()

Returns NULL only if the user has started to input their password since the computer was locked. Besides that returns a valid handle. Presumably the input desktop isn't deselected until the user attempts to login and their input switches.

  1. OpenInputDesktop() vs GetThreadDesktop()

(Passing in GetCurrentThreadID() of course)

Handles still match, probably due to same reason 1 fails.

  1. Process check for LockApp.exe/LockAppHost.exe

Seems to relate to user inputting their password as well... or because my server rebooter app is 32-bit, having problems reading the 64-bit process LockApp.exe.

  1. GetForegroundWindow() returns null when locked

While mentioned as dubious, I tried this too. False negative, said it wasn't locked

  1. Switching desktop manually and seeing if it worked

Described with code example here, this one was also a bust and gave a false negative.

Is there any way left? I'd really rather not have a service just for registering locking/unlocking running constantly.

Or should one of these ways worked already, and my Windows is bugged?

Cheers

Upvotes: 12

Views: 8007

Answers (4)

Vedat Ermiş
Vedat Ermiş

Reputation: 51

using Microsoft.Win32;

SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;

        private async void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
        {
            if (e.Reason == SessionSwitchReason.SessionLock)
            {
                //Do someting
            }
        }

Upvotes: 3

Martlark
Martlark

Reputation: 14581

I found that the mouse pointer is always at x=0, y=0 when locked.

Upvotes: 1

Phi
Phi

Reputation: 497

Searching for LogonUI running in process list seems to be the way to go.

pslist is 32-bit but in the background, spawns a 64-bit process to list the 64-bit counterparts, so there's no dependency on the C# app being x86 or x64 (or LockApp for that matter).

It's not great, but it works.

Process p = new Process
{
    StartInfo = new ProcessStartInfo
    {
        FileName = @"[path to SysSuite]\pslist.exe",
        Arguments = " -nobanner logonui",
        UseShellExecute = false,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};

p.Start();
p.WaitForExit();
string s = p.StandardOutput.ReadToEnd();
if (!s.Contains("process logonui was not found on "))
{
    Debug.WriteLine("Windows is locked.");
    return true;
}

It's really dumb that Windows has no built-in way for such a basic feature, though.

EDIT: Nope, this way doesn't work either. While LogonUI does run upon lock, and sticks around for a while, I've had it also vanish if the computer isn't interacted with for a couple hours or so. Notably, overnight, my computer gets clogged with dialogs that only spawn that frequently if logged in.

I'm now using SystemEvents.SessionSwitch and a single process as Hans suggested. I was kinda hoping for a current reading thing for future reference, but at this point it's mostly curiosity.

Upvotes: 1

Keith
Keith

Reputation: 211

I'm not sure how to do it in C#, but with PowerShell, I checked if the LockApp.exe threads are Suspended to see if the desktop is unlocked or locked, like so:

$lockapp = Get-Process lockapp

for ($i = 0; $i -lt 60; $i++)
{
    $process=[System.Diagnostics.Process]::GetProcessById($lockapp.Id)
    $threads=$process.Threads
    if ($threads[0].WaitReason -eq "Suspended") { "It's unlocked" } else { "It's locked" }
    Sleep 1
}

This script loops for 60 seconds and writes out the locked/unlocked state.

Upvotes: 8

Related Questions