簡體   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