简体   繁体   English

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

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

Currently I'm using the below code to test if the CTRL + ALT + DEL screen is visible and it is working as expected.目前我正在使用下面的代码来测试CTRL + ALT + DEL屏幕是否可见并且它是否按预期工作。 The problem is that polling this info consumes CPU and I'm looking for an event based option.问题是轮询此信息会消耗 CPU,我正在寻找基于事件的选项。 Does anyone know another way to detect if this screen is visible?有谁知道另一种检测此屏幕是否可见的方法?

I only need to know when this screen is closed.我只需要知道此屏幕何时关闭。 I don't really care when it opens.我真的不在乎它什么时候打开。 Just that it had been open and is now closed.只是它一直开放,现在关闭。

To be honest, I found this code and I'm not exactly sure how it is specific, if at all, to the screen I'm referring to.老实说,我找到了这段代码,但我不确定它是如何具体到我所指的屏幕的,如果有的话。 It appears to look for any process creation and deletion events.它似乎在寻找任何进程创建和删除事件。 What this means is that this screen must be opening a new process.这意味着此屏幕必须打开一个新进程。 Knowing that process name would be helpful too.知道进程名称也会有帮助。

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;

What is the name of this screen?这个屏幕叫什么名字? And how do I detect this type of window?我如何检测这种类型的窗口? It seems like the same type as the login window.它似乎与登录窗口的类型相同。

在此处输入图片说明

When you press CTRL + ALT + DEL , Windows switches to a another special virtual desktop a that hosts the winlogon process that is responsible for user login/logoff/lock etc. actions.当您按CTRL + ALT + DEL 时,Windows 会切换到另一个特殊的虚拟桌面a ,该桌面托管负责用户登录/注销/锁定等操作的winlogon进程。 By using the WinAPI function SetWinEventHook with the EVENT_SYSTEM_DESKTOPSWITCH argument you can set up a callback function that is called whenever such a desktop switch occurs:通过使用带有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");
}

Note: If you want to use this in a console application, you have to add a message loop by adding a hidden Form :注意:如果你想在控制台应用程序中使用它,你必须通过添加一个隐藏的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;

Further : The desktop switch also occurs when the user pressed Win + L or a UAC window pops up.进一步:当用户按下Win + L或弹出 UAC 窗口时,也会发生桌面切换。 Thus, we need a way to detect these other cases.因此,我们需要一种方法来检测这些其他情况。 The UAC case is rather trivial, it is enough to check if the process consent.exe is running during the callback function: UAC案例比较简单,在回调函数中检查consent.exe进程是否在运行就足够了:

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

The other case, unfortunately, is a bit more complicated.不幸的是,另一种情况要复杂一些。 I have only managed to detect wheter a user returns from a lock screen, but not whether they enter it (as you said, this is not relevant for you, but I wanted to mention it anyway).我只设法检测到用户是否从锁定屏幕返回,而不是他们是否进入(如您所说,这与您无关,但无论如何我想提一下)。

Detecting whether the session is locked can be done by listening for the SystemEvents.SessionSwitch event in our HiddenForm .检测会话是否被锁定,可以通过监听来完成SystemEvents.SessionSwitch在我们的活动HiddenForm The SessionSwitchEventArgs.Reason property is set to SessionSwitchReason.SessionLock if this is a lock event, and to SessionSwitchReason.SessionUnlock if the user unlocks.SessionSwitchEventArgs.Reason属性设置为SessionSwitchReason.SessionLock如果这是一个锁事件,并SessionSwitchReason.SessionUnlock如果用户解锁。 We only can tell whether a desktop switch was not to the lock screen desktop when we are switching back to the default desktop since the switch desktop event callbacks are called before a session lock and after a session unlock.我们只能在切换回默认桌面时判断桌面切换是否不是锁定屏幕桌面,因为切换桌面事件回调是会话锁定之前和会话解锁之后调用的。 This leads to the following code for a sample console application:这导致示例控制台应用程序的以下代码:

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 This type of virtual desktop has nothing to do with the newly introduced "virtual desktop" feature in Windows 10 a此类虚拟桌面与 Windows 10 中新引入的“虚拟桌面”功能无关

Not sure if this might help.不确定这是否有帮助。 This won't check if the screen is there bur rather if the events have been triggered, to do that you might need to enable the logging of these events, you can do it by opening the group policy editor:这不会检查屏幕是否存在,而是是否已触发事件,为此您可能需要启用这些事件的日志记录,您可以通过打开组策略编辑器来完成:

gpedit.mscComputer ConfigurationWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationSystem Audit PoliciesLocal Group Policy ObjectLogon/LogoffAudit Other Login/Logoff Events gpedit.msc计算机配置Windows 设置安全设置高级审核策略配置系统审核策略本地组策略对象登录/注销审核其他登录/注销事件

After it has been enabled, you could listen for the event id 4800 for locking and 4801 for unlocking.启用后,您可以监听事件 id 4800用于锁定和4801用于解锁。

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

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