我需要知道用户何时切换到登录屏幕(由 ctrl-alt-del 触发)以规避 WPF 中的一个讨厌的错误。我想通过在从登录屏幕返回后重新初始化我的 GUI 来解决这个错误。目前它可以工作,但我必须手动触发它。
我找到了 SystemEvents.SessionSwitch,但不幸的是,这仅在注销时触发。
如何通过形成 ctrl-alt-del 来检测登录屏幕何时显示?
我需要知道用户何时切换到登录屏幕(由 ctrl-alt-del 触发)以规避 WPF 中的一个讨厌的错误。我想通过在从登录屏幕返回后重新初始化我的 GUI 来解决这个错误。目前它可以工作,但我必须手动触发它。
我找到了 SystemEvents.SessionSwitch,但不幸的是,这仅在注销时触发。
如何通过形成 ctrl-alt-del 来检测登录屏幕何时显示?
棘手的是,这不是会话更改,而只是桌面更改。特别是,Ctrl+Alt+Del 切换到与 Winlogon 关联的安全桌面。
我不认为你真的应该检测到这种事情(也就是说,毕竟,拥有“安全桌面”的全部意义),但你可能可以使用 Active Accessibility 钩子来做到这一点。调用该SetWinEventHook
函数为事件安装事件挂钩EVENT_SYSTEM_DESKTOPSWITCH
并查看您收到的通知。
为此,您需要执行以下操作:
WINEVENT_OUTOFCONTEXT
考虑到您正在使用托管代码,请确保指定标志。您不希望系统尝试将包含回调函数的 DLL 注入每个进程。相反,这将导致回调函数从队列中异步调用;从托管代码的土地上安全得多。一点点 P/Invoke 魔法。为了让你开始……
const uint WINEVENT_OUTOFCONTEXT = 0x0;
const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin,
uint eventMax,
IntPtr hmodWinEventProc,
WinEventDelegate lpfnWinEventProc,
uint idProcess,
uint idThread,
uint dwFlags);
delegate void WinEventDelegate(IntPtr hWinEventHook,
uint event,
IntPtr hwnd,
int idObject,
int idChild,
uint dwEventThread,
uint dwmsEventTime);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
似乎调用了开始显示登录屏幕的过程LogonUI.exe
。
使用Windows Management Instrumentation (WMI) 基础结构,您可以侦听启动和关闭的进程。您将需要引用System.Management
程序集。
var interval = new TimeSpan( 0, 0, 1 );
const string isWin32Process = "TargetInstance isa \"Win32_Process\"";
// Listen for started processes.
WqlEventQuery startQuery
= new WqlEventQuery( "__InstanceCreationEvent", interval, isWin32Process );
_startWatcher = new ManagementEventWatcher( startQuery );
_startWatcher.Start();
_startWatcher.EventArrived += OnStartEventArrived;
// Listen for closed processes.
WqlEventQuery stopQuery
= new WqlEventQuery( "__InstanceDeletionEvent", interval, isWin32Process );
_stopWatcher = new ManagementEventWatcher( stopQuery );
_stopWatcher.Start();
_stopWatcher.EventArrived += OnStopEventArrived;
处理这些事件,您可以获得有关已启动或已关闭进程的信息。通过这种方式,您可以验证何时LogonUI.exe
关闭,并随后触发所需的操作。
void OnStopEventArrived( object sender, EventArrivedEventArgs e )
{
var o = (ManagementBaseObject)e.NewEvent[ "TargetInstance" ];
string name = (string)o[ "Name" ];
...
}