简体   繁体   English

如何检测用户何时切换到登录屏幕?

[英]How to detect when the user switches to the Log On screen?

I need to know when the user switches to the logon screen (as triggered by ctrl-alt-del) in order to circumvent a pesky bug in WPF . 我需要知道用户何时切换到登录屏幕(由ctrl-alt-del触发) 以避免WPF中的麻烦错误 I want to work around this bug by reinitializing my GUI after returning from the logon screen. 我想通过从登录屏幕返回后重新初始化我的GUI来解决这个问题。 Currently it works, but I have to trigger it manually. 目前它可以工作,但我必须手动触发它。

I have found SystemEvents.SessionSwitch , but unfortunately this is only triggered when logging off. 我找到了SystemEvents.SessionSwitch ,但不幸的是,这仅在注销时触发。

How can I detect when the logon screen is displayed by forming ctrl-alt-del? 如何通过形成ctrl-alt-del来检测何时显示登录屏幕?

The tricky thing is that this is not a session change, but rather just a desktop change. 棘手的是,这不是会话更改,而是桌面更改。 In particular, Ctrl+Alt+Del switches to a secured desktop associated with Winlogon. 特别是,Ctrl + Alt + Del切换到与Winlogon关联的安全桌面。

I don't think you're really supposed to detect this kind of thing (that is, after all, the whole point of having a "secure desktop"), but you could probably do it using an Active Accessibility hook. 我不认为你真的应该检测到这种事情(毕竟,有一个“安全桌面”),但你可以使用Active Accessibility钩子做到这一点。 Call the SetWinEventHook function to install an event hook for the EVENT_SYSTEM_DESKTOPSWITCH event and see what notifications you receive. 调用SetWinEventHook函数EVENT_SYSTEM_DESKTOPSWITCH事件安装事件挂钩,并查看收到的通知。

To get it going, you'll need to do the following: 为了实现这一目标,您需要执行以下操作:

  • Ensure that you're pumping a message loop on your client thread in order to receive event notifications. 确保您在客户端线程上添加消息循环以接收事件通知。 This shouldn't be a problem for a standard WPF application. 这应该不是标准WPF应用程序的问题。
  • Make sure that you specify the WINEVENT_OUTOFCONTEXT flag, considering that you're working from managed code. 考虑到您使用的是托管代码,请确保指定WINEVENT_OUTOFCONTEXT标志。 You don't want the system to attempt to inject your DLL that contains the callback function into every process. 您不希望系统尝试将包含回调函数的DLL注入每个进程。 Instead, this will cause the callback function to be called asynchronously from a queue; 相反,这将导致从队列中异步调用回调函数; much safer from the land of managed code. 从托管代码的土地更安全。
  • A little bit of P/Invoke magic. 一点点P / Invoke魔法。 To get you started… 为了让你开始......

     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); 

The process which gets started to show the logon screen seems to be called LogonUI.exe . 开始显示登录屏幕的过程似乎被称为LogonUI.exe

Using the Windows Management Instrumentation (WMI) infrastructure you can listen for processes which start and shut down. 使用Windows Management Instrumentation(WMI)基础结构,您可以侦听启动和关闭的进程。 You will need to reference the System.Management assembly. 您需要引用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;

Handling these events, you can get information about the started or closed process. 处理这些事件,您可以获得有关已启动或已关闭流程的信息。 This way you can verify when LogonUI.exe was shut down, and subsequently trigger the required actions. 这样,您可以验证LogonUI.exe关闭,并随后触发所需的操作。

void OnStopEventArrived( object sender, EventArrivedEventArgs e )
{
    var o = (ManagementBaseObject)e.NewEvent[ "TargetInstance" ];
    string name = (string)o[ "Name" ];

    ...
}

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

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