目前我正在使用以下代码来测试 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;
这个屏幕的名称是什么?我如何检测这种类型的窗口?它看起来与登录窗口的类型相同。
答案 0 :(得分:5)
当您按 CTRL + ALT + DEL 时,Windows会切换到另一个特殊的虚拟桌面 a 托管负责用户登录/注销/锁定等操作的winlogon
进程。通过将WinAPI函数SetWinEventHook
与EVENT_SYSTEM_DESKTOPSWITCH
参数一起使用,您可以设置一个在发生这样的桌面切换时调用的回调函数:
//Store the callback in a variable so that it is not GC'd private static
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");
不幸的是,另一起案件有点复杂。我只是设法检测到用户从锁定屏幕返回的信息,而不是他们是否输入它(正如你所说,这与你无关,但无论如何我想提及它。)
检测会话是否被锁定可以通过监听来完成
我们HiddenForm
中的SystemEvents.SessionSwitch
事件。如果这是锁定事件,则SessionSwitchEventArgs.Reason
属性设置为SessionSwitchReason.SessionLock
,如果用户解锁,则设置为SessionSwitchReason.SessionUnlock
。当我们切换回默认桌面时,我们只能判断桌面交换机是否未进入锁屏桌面,因为交换桌面事件回调在会话锁定之前被称为而之后> em>会话解锁。这导致示例控制台应用程序的以下代码:
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中的功能
答案 1 :(得分:0)
不确定这是否有帮助。这不会检查屏幕是否存在,而不是事件已被触发,为此您可能需要启用这些事件的记录,您可以通过打开组策略编辑器来执行此操作:
gpedit.msc
→计算机配置→ Windows设置→安全设置→高级审核策略配置 →系统审核策略→本地组策略对象→登录/注销→审核其他登录/注销事件
启用后,您可以侦听事件标识4800
以进行锁定,并4801
进行解锁。