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

后端 未结 2 1174
隐瞒了意图╮
隐瞒了意图╮ 2020-12-15 12:48

Currently I\'m using the below code to test if the CTRL+ALT+DEL screen is visible and it is working as expected. The problem is that polling

相关标签:
2条回答
  • 2020-12-15 13:21

    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

    After it has been enabled, you could listen for the event id 4800 for locking and 4801 for unlocking.

    0 讨论(0)
  • 2020-12-15 13:24

    When you press CTRL+ALT+DEL, Windows switches to a another special virtual desktopa that hosts the winlogon process that is responsible for user login/logoff/lock etc. actions. 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:

    //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:

    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. 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:

    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. The SessionSwitchEventArgs.Reason property is set to SessionSwitchReason.SessionLock if this is a lock event, and to SessionSwitchReason.SessionUnlock if the user unlocks. 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

    0 讨论(0)
提交回复
热议问题