检查 Windows 是否处于锁定状态

11
我正在使用Windows 10 Pro x64版本1703构建15063.726,尝试编写一个程序重启服务。它在我的用户下以管理员权限运行,每10分钟通过计划任务运行。
如果服务器不可用或出现故障:
- 如果我的计算机被锁定,重启器将杀死并重新启动服务器程序。 - 如果我的计算机没有被锁定,重启器会显示一个对话框以确认重启。我可能正在对服务器程序进行调试工作,不希望重启破坏任何调试工作。
唯一的复杂之处在于检测计算机是否被锁定。我已经尝试了几种方法:
1. OpenInputDesktop() 只有当用户自从计算机锁定以来开始输入密码时,才返回NULL。除此之外,返回有效句柄。假设输入桌面直到用户尝试登录并切换他们的输入之前都不会被取消选择。 2. OpenInputDesktop()与GetThreadDesktop() (当然传入GetCurrentThreadID()) 句柄仍然匹配,可能是由于同样的原因1失败。 3. 进程检查LockApp.exe / LockAppHost.exe 似乎也与用户输入密码有关...或者因为我的服务器重启应用程序是32位的,无法读取64位进程LockApp.exe。 4. GetForegroundWindow()在锁定时返回null

虽然被质疑, 我也尝试了这个方法。显示未锁定,但实际上是错误的负面结果。

  1. 手动切换桌面并查看是否有效

使用代码示例描述在这里,这个方法也是失败的并且给出了错误的负面结果。

还有其他的方法吗?我真的不想一直运行一个服务来注册锁定/解锁状态。

或者说这些方法中应该已经有一个可以工作了,我的Windows系统有问题吗?

谢谢


4
目前没有已知的方法可以发现这一点。但是你可以观察桌面会话切换,在 C# 中使用 SystemEvents.SessionSwitch 事件。 - Hans Passant
在我看来,你真正想要的是一个 Windows 服务,而不是桌面应用程序。 - spender
使用具有用户界面的服务一直是一种痛苦,而且这个应用程序将以可移植的方式部署,因此我非常不愿意走服务的路线。 - Phi
你尝试过这个吗: https://dev59.com/g3VD5IYBdhLWcg3wO5AD - Sy Le
@SyLe 我尝试了所有的方法,除了 https://dev59.com/g3VD5IYBdhLWcg3wO5AD#52102 这个。其他方法都适用于服务 - 它们会说某些东西是从锁定 <-> 解锁状态中更改了,但不会告诉你当前它是什么状态。 - Phi
4个回答

7

我不确定如何在C#中实现,但是使用PowerShell,我可以检查LockApp.exe线程是否处于挂起状态来判断桌面是解锁还是锁定的,代码如下:

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

这个脚本循环运行60秒,并输出锁定/解锁状态。


有趣,但当用户没有尝试输入其登录信息或与登录界面交互时,它会被挂起吗?它是否依赖于锁屏设置?LockApp的安全设置是什么?非管理员C#任务能读取它吗?这肯定比我的解决方案更好,我的解决方案是通过计划任务杀死LockApp.exe,应用程序将检查LockApp是否在运行,以确定是否锁定。 - Phi
1
无论是显示锁屏图像还是用户尝试输入密码,似乎在锁定状态下并没有被挂起。LockApp.exe 以用户帐户运行,因此我认为作为用户运行的应用程序应该能够读取其进程详细信息。 - Keith

2
using Microsoft.Win32;

SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;

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

1
在进程列表中搜索正在运行的LogonUI似乎是可行的方法。 pslist是32位的,但在后台生成一个64位进程来列出64位对应项,因此C#应用程序不依赖于x86或x64(或LockApp)。
这并不完美,但它能够起到作用。
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;
}

真的很愚蠢,Windows没有内置这样一个基本功能的方法。

编辑:不行,这种方式也不起作用。虽然LogonUI会在锁定时运行,并保持一段时间,但如果计算机长时间未被操作,它也会消失。值得注意的是,在过夜期间,我的计算机会因为只有登录后才会频繁出现的对话框而变得混乱。

我现在正在使用SystemEvents.SessionSwitch和单个进程,就像Hans建议的那样。我有点希望能有一个当前读数的东西以供将来参考,但现在这主要是出于好奇心。


1
我发现当锁定时,鼠标指针始终在x = 0,y = 0。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接