繁体   English   中英

检查 CTRL+ALT+DEL 屏幕是否可见的替代方法

[英]Alternative way to check if CTRL+ALT+DEL screen is visible

目前我正在使用下面的代码来测试CTRL + ALT + DEL屏幕是否可见并且它是否按预期工作。 问题是轮询此信息会消耗 CPU,我正在寻找基于事件的选项。 有谁知道另一种检测此屏幕是否可见的方法?

我只需要知道此屏幕何时关闭。 我真的不在乎它什么时候打开。 只是它一直开放,现在关闭。

老实说,我找到了这段代码,但我不确定它是如何具体到我所指的屏幕的,如果有的话。 它似乎在寻找任何进程创建和删除事件。 这意味着此屏幕必须打开一个新进程。 知道进程名称也会有帮助。

var interval = new TimeSpan(0, 0, 3);
const string isWin32Process = "TargetInstance isa \"Win32_Process\"";

// Listen for started processes.
WqlEventQuery startQuery = new WqlEventQuery("__InstanceCreationEvent", interval, isWin32Process);
var _startWatcher = new ManagementEventWatcher(startQuery);
_startWatcher.Start();
_startWatcher.EventArrived += OnStartEventArrived;

// Listen for closed processes.
WqlEventQuery stopQuery = new WqlEventQuery("__InstanceDeletionEvent", interval, isWin32Process);
var _stopWatcher = new ManagementEventWatcher(stopQuery);
_stopWatcher.Start();
_stopWatcher.EventArrived += OnStopEventArrived;

这个屏幕叫什么名字? 我如何检测这种类型的窗口? 它似乎与登录窗口的类型相同。

在此处输入图片说明

当您按CTRL + ALT + DEL 时,Windows 会切换到另一个特殊的虚拟桌面a ,该桌面托管负责用户登录/注销/锁定等操作的winlogon进程。 通过使用带有EVENT_SYSTEM_DESKTOPSWITCH参数的 WinAPI 函数SetWinEventHook ,您可以设置一个回调函数,该函数在发生此类桌面切换时调用:

//Store the callback in a variable so that it is not GC'd
private static readonly WinEventDelegate callback = EventCallback;
static void StartListeningForDesktopSwitch()
{
    SetWinEventHook(EVENT_SYSTEM_DESKTOPSWITCH, EVENT_SYSTEM_DESKTOPSWITCH,
        IntPtr.Zero, callback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNTHREAD);
}

static void EventCallback(IntPtr hWinEventHook, uint eventType,
       IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
    Console.WriteLine("Desktop switched");
}

注意:如果你想在控制台应用程序中使用它,你必须通过添加一个隐藏的Form来添加一个消息循环:

static void Main(string[] args)
{        
    StartListeningForDesktopSwitch(); 

    // Run message loop
    Application.Run(new HiddenForm());
}

private class HiddenForm : Form
{
    public HiddenForm()
    {
        this.FormBorderStyle = FormBorderStyle.None;
        this.WindowState = FormWindowState.Minimized;
        this.ShowInTaskbar = false;
    }
}

delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
    IntPtr hwnd, int idObject, int idChild, uint dwEventThread,
    uint dwmsEventTime);

[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
    hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
    uint idThread, uint dwFlags);

const uint WINEVENT_OUTOFCONTEXT = 0x0000;
const uint WINEVENT_SKIPOWNTHREAD = 0x0001;
const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;

进一步:当用户按下Win + L或弹出 UAC 窗口时,也会发生桌面切换。 因此,我们需要一种方法来检测这些其他情况。 UAC案例比较简单,在回调函数中检查consent.exe进程是否在运行就足够了:

var processes = Process.GetProcessesByName("consent");
if (processes.Length == 0)
    Console.WriteLine("This is not a UAC prompt");

不幸的是,另一种情况要复杂一些。 我只设法检测到用户是否从锁定屏幕返回,而不是他们是否进入(如您所说,这与您无关,但无论如何我想提一下)。

检测会话是否被锁定,可以通过监听来完成SystemEvents.SessionSwitch在我们的活动HiddenForm SessionSwitchEventArgs.Reason属性设置为SessionSwitchReason.SessionLock如果这是一个锁事件,并SessionSwitchReason.SessionUnlock如果用户解锁。 我们只能在切换回默认桌面时判断桌面切换是否不是锁定屏幕桌面,因为切换桌面事件回调是会话锁定之前和会话解锁之后调用的。 这导致示例控制台应用程序的以下代码:

private static readonly WinEventDelegate callback = EventCallback;
static void Main(string[] args)
{
    SetWinEventHook(EVENT_SYSTEM_DESKTOPSWITCH,
        EVENT_SYSTEM_DESKTOPSWITCH, IntPtr.Zero, callback, 0, 0,
        WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNTHREAD);

    Application.Run(new HiddenForm());
}

private class HiddenForm : Form
{
    public HiddenForm()
    {
        this.FormBorderStyle = FormBorderStyle.None;
        this.WindowState = FormWindowState.Minimized;
        this.ShowInTaskbar = false;
        SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
    }

    private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
    {
        if (e.Reason == SessionSwitchReason.SessionUnlock)
            wasUnlocked = true;
    }
}

static bool wasUnlocked = false;
static bool wasOpened = false;

static void EventCallback(IntPtr hWinEventHook, uint eventType,
    IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
    // Check if UAC dialog is being shown
    var processes = Process.GetProcessesByName("consent");
    if (processes.Length == 0)
    {
        if (wasOpened)
        {
            if (!wasUnlocked)
                Console.WriteLine("Exited from CTRL+ALT+DEL");
            wasUnlocked = false;
            wasOpened = false;
        }
        else
            wasOpened = true;
    }
}

delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
    IntPtr hwnd, int idObject, int idChild, uint dwEventThread,
    uint dwmsEventTime);

[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
    hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
    uint idThread, uint dwFlags);

const uint WINEVENT_OUTOFCONTEXT = 0x0000;
const uint WINEVENT_SKIPOWNTHREAD = 0x0001;
const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;

a此类虚拟桌面与 Windows 10 中新引入的“虚拟桌面”功能无关

不确定这是否有帮助。 这不会检查屏幕是否存在,而是是否已触发事件,为此您可能需要启用这些事件的日志记录,您可以通过打开组策略编辑器来完成:

gpedit.msc计算机配置Windows 设置安全设置高级审核策略配置系统审核策略本地组策略对象登录/注销审核其他登录/注销事件

启用后,您可以监听事件 id 4800用于锁定和4801用于解锁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM