1

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.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
GameDevAlien
  • 195
  • 1
  • 17
  • 1
    https://stackoverflow.com/questions/31801402/api-for-windows-10-virtual-desktops – Daniel A. White Aug 05 '19 at 13:44
  • 1
    I know the IVirtualDesktopManager interface, but it does not fire events. It offers a function to check if my application is on the current Desktop, but I would need to use polling to get the latest state, right? I can do the same task with GetThreadDesktop without using the COM API. – GameDevAlien Aug 05 '19 at 13:48
  • https://github.com/Grabacr07/VirtualDesktop – Daniel A. White Aug 05 '19 at 13:58

1 Answers1

1

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.

NineBerry
  • 26,306
  • 3
  • 62
  • 93
  • I am currently working through Grabacr07's source code and I will test the `VirtualDesktopNotificationService` in detail. I will let you know when I am done and mark your reply as answer if it works. Thank you very much for the clarification about the Desktop Switch Hook! – GameDevAlien Aug 06 '19 at 13:48