【发布时间】:2019-08-05 13:42:27
【问题描述】:
在我的应用程序中,我需要知道用户何时切换虚拟桌面,例如通过按 Ctrl+Win+→。
我认为通过 Hooking 来做到这一点是个好主意。我列出了我编写的一个示例类来测试我的想法。我想当虚拟桌面发生变化时,我会得到一个回调。但是,无论我如何更改虚拟桌面,都没有回调。
我还编写了一个测试应用程序,用于创建、打开、切换和关闭桌面。它工作正常,但我下面的代码没有检测到任何桌面开关。
public class SwitchDesktopMonitor
{
private delegate void CreateHookDelegate();
private delegate void SetWinEventHookCallback(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, uint objectId, int childId, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, SetWinEventHookCallback lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
private IntPtr _setWinEventHook;
private readonly SetWinEventHookCallback _hookingCallback;
private readonly Window _window;
public SwitchDesktopMonitor(Window window)
{
_window = window;
_hookingCallback = (hWinEventHook, eventType, hWnd, objectId, childId, dwEventThread, dwmsEventTime) =>
{
Console.WriteLine("-> _hookingCallback - hWinEventHook = {0}, eventType = {1}, hWnd = {2}, objectId = {3}, childId = {4}, dwEventThread = {5}, dwmsEventTime = {6}",
hWinEventHook, eventType, hWnd, objectId, childId, dwEventThread, dwmsEventTime);
};
}
public void Start()
{
Console.WriteLine("{0}.Start", this);
if (_window == null || _window.Dispatcher == null)
{
return;
}
if (_window.Dispatcher.CheckAccess())
{
CreateHook();
}
else
{
_window.Dispatcher.Invoke(new CreateHookDelegate(CreateHook));
}
}
public void Stop()
{
Console.WriteLine("{0}.Stop", this);
if (_setWinEventHook != null)
{
Console.WriteLine("\tUnhookWinEvent = {0}", UnhookWinEvent(_setWinEventHook));
}
}
private void CreateHook()
{
var windowHandle = new WindowInteropHelper(_window).Handle;
uint processId;
uint threadId = GetWindowThreadProcessId(windowHandle, out processId);
Console.WriteLine("\twindowHandle = {0}, processId = {1}, threadId = {2}", windowHandle, processId, threadId);
_setWinEventHook = SetWinEventHook(0x0020, 0x0020, IntPtr.Zero, _hookingCallback, processId, threadId, 0x0000);
Console.WriteLine("\t_setWinEventHook = {0}", _setWinEventHook);
}
}
我不必这样做。我很感激或其他方法。唯一重要的是我需要检测 Windows 桌面开关。
【问题讨论】:
-
我知道 IVirtualDesktopManager 接口,但它不会触发事件。它提供了一个功能来检查我的应用程序是否在当前桌面上,但我需要使用轮询来获取最新状态,对吗?我可以在不使用 COM API 的情况下使用 GetThreadDesktop 完成相同的任务。