GameDevAlien
GameDevAlien

Reputation: 187

How to detect switched Desktops?

In my application I need to know when the user switches the virtual Desktop, e.g. by pressing Ctrl+Win+.

I though it'd be a great idea to do this via Hooking. I have listed an example class I wrote to test my idea. I thought when the virtual Desktop changes, I would get a callback. However, there is no callback no matter how I change the virtual Desktop.

I also wrote a test application that creates, opens, switches and closes Desktops. It works fine, but my code below detects none of the Desktop switches.

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

I don't have to do this way. I am thankful or other approaches. The only important thing is that I need to detect Windows Desktop switches.

Upvotes: 1

Views: 2114

Answers (1)

NineBerry
NineBerry

Reputation: 28499

You install a hook for the event EVENT_SYSTEM_DESKTOPSWITCH (0x0020). However, the term desktop here does not refer to "virtual desktops" as a feature in Windows 10 to switch between different sets of windows, but to desktops as a system concept in Windows to separate different operating environments (Normal, Logon, Screensaver).

So, you cannot detect a switching of virtual desktops this way.

Instead, use the way as shown in this open source library https://github.com/Grabacr07/VirtualDesktop which uses a currently undocumented VirtualDesktopNotificationService COM service in the Windows Shell to be notified when the current virtual desktop changes.

Upvotes: 2

Related Questions