From 75ee3560a4551107c60946e17b709192d51607f7 Mon Sep 17 00:00:00 2001 From: DARKGuy Date: Wed, 27 Oct 2021 12:28:45 -0600 Subject: [PATCH] Win10LTSC to Win11 compatible! Refactor VirtualDesktopAPI code with some interfaces to withstand COM GUID changes. Fix window redraw bug. --- src/Core/API/Interfaces.cs | 25 ++ src/Core/API/VirtualDesktopAPI-Win10.cs | 309 +++++++++++++++++++ src/Core/API/VirtualDesktopAPI-Win10LTSC.cs | 309 +++++++++++++++++++ src/Core/API/VirtualDesktopAPI-Win11.cs | 322 ++++++++++++++++++++ src/Core/API/VirtualDesktopAPI.cs | 314 ++----------------- src/Core/WindowManager.cs | 3 +- src/Core/WindowsVersion.cs | 29 ++ src/GUI/MainForm.cs | 18 +- src/GUI/VirtualDesktop.cs | 6 +- src/Program.cs | 1 + 10 files changed, 1040 insertions(+), 296 deletions(-) create mode 100644 src/Core/API/Interfaces.cs create mode 100644 src/Core/API/VirtualDesktopAPI-Win10.cs create mode 100644 src/Core/API/VirtualDesktopAPI-Win10LTSC.cs create mode 100644 src/Core/API/VirtualDesktopAPI-Win11.cs create mode 100644 src/Core/WindowsVersion.cs diff --git a/src/Core/API/Interfaces.cs b/src/Core/API/Interfaces.cs new file mode 100644 index 0000000..126c1fe --- /dev/null +++ b/src/Core/API/Interfaces.cs @@ -0,0 +1,25 @@ +using System; + +namespace Switchie +{ + + public interface IIVirtualDesktop { } + + public interface IWindowsVirtualDesktopManager + { + void PinApplication(IntPtr hWnd); + int FromDesktop(IWindowsVirtualDesktop desktop); + IWindowsVirtualDesktop FromWindow(IntPtr hWnd); + } + + public interface IWindowsVirtualDesktop + { + int Count { get; } + void MakeVisible(); + void MoveWindow(IntPtr hWnd); + IIVirtualDesktop ivd { get; set; } + IWindowsVirtualDesktop Current { get; } + IWindowsVirtualDesktop FromIndex(int index); + } + +} \ No newline at end of file diff --git a/src/Core/API/VirtualDesktopAPI-Win10.cs b/src/Core/API/VirtualDesktopAPI-Win10.cs new file mode 100644 index 0000000..37ba6f9 --- /dev/null +++ b/src/Core/API/VirtualDesktopAPI-Win10.cs @@ -0,0 +1,309 @@ +// Adapted from https://github.com/MScholtes/VirtualDesktop with a few modifications +using System; +using System.Runtime.InteropServices; + +namespace Switchie.VirtualDesktopAPI.Win10 +{ + + public class WindowsVirtualDesktopAPI + { + public static readonly Guid CLSID_IMMERSIVESHELL = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGERINTERNAL = new Guid("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGER = new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); + public static readonly Guid CLSID_VIRTUALDESKTOPPINNEDAPPS = new Guid("B5A399E7-1C87-46B8-88E9-FC5747B171BD"); + + [StructLayout(LayoutKind.Sequential)] + public struct SIZE + { + public int X; + public int Y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + public enum APPLICATION_VIEW_CLOAK_TYPE : int + { + AVCT_NONE = 0, + AVCT_DEFAULT = 1, + AVCT_VIRTUAL_DESKTOP = 2 + } + + public enum APPLICATION_VIEW_COMPATIBILITY_POLICY : int + { + AVCP_NONE = 0, + AVCP_SMALL_SCREEN = 1, + AVCP_TABLET_SMALL_SCREEN = 2, + AVCP_VERY_SMALL_SCREEN = 3, + AVCP_HIGH_SCALE_FACTOR = 4 + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] + public interface IObjectArray + { + void GetCount(out int count); + void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out object obj); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("4CE81583-1E4C-4632-A621-07A53543148F")] + public interface IVirtualDesktopPinnedApps + { + bool IsAppIdPinned(string appId); + void PinAppID(string appId); + void UnpinAppID(string appId); + bool IsViewPinned(IApplicationView applicationView); + void PinView(IApplicationView applicationView); + void UnpinView(IApplicationView applicationView); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] + public interface IServiceProvider10 + { + [return: MarshalAs(UnmanagedType.IUnknown)] + object QueryService(ref Guid service, ref Guid riid); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)] + [Guid("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] + public interface IApplicationView + { + int SetFocus(); + int SwitchTo(); + int TryInvokeBack(IntPtr /* IAsyncCallback* */ callback); + int GetThumbnailWindow(out IntPtr hwnd); + int GetMonitor(out IntPtr /* IImmersiveMonitor */ immersiveMonitor); + int GetVisibility(out int visibility); + int SetCloak(APPLICATION_VIEW_CLOAK_TYPE cloakType, int unknown); + int GetPosition(ref Guid guid /* GUID for IApplicationViewPosition */, out IntPtr /* IApplicationViewPosition** */ position); + int SetPosition(ref IntPtr /* IApplicationViewPosition* */ position); + int InsertAfterWindow(IntPtr hwnd); + int GetExtendedFramePosition(out RECT rect); + int GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string id); + int SetAppUserModelId(string id); + int IsEqualByAppUserModelId(string id, out int result); + int GetViewState(out uint state); + int SetViewState(uint state); + int GetNeediness(out int neediness); + int GetLastActivationTimestamp(out ulong timestamp); + int SetLastActivationTimestamp(ulong timestamp); + int GetVirtualDesktopId(out Guid guid); + int SetVirtualDesktopId(ref Guid guid); + int GetShowInSwitchers(out int flag); + int SetShowInSwitchers(int flag); + int GetScaleFactor(out int factor); + int CanReceiveInput(out bool canReceiveInput); + int GetCompatibilityPolicyType(out APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int SetCompatibilityPolicyType(APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int GetSizeConstraints(IntPtr /* IImmersiveMonitor* */ monitor, out SIZE size1, out SIZE size2); + int GetSizeConstraintsForDpi(uint uint1, out SIZE size1, out SIZE size2); + int SetSizeConstraintsForDpi(ref uint uint1, ref SIZE size1, ref SIZE size2); + int OnMinSizePreferencesUpdated(IntPtr hwnd); + int ApplyOperation(IntPtr /* IApplicationViewOperation* */ operation); + int IsTray(out bool isTray); + int IsInHighZOrderBand(out bool isInHighZOrderBand); + int IsSplashScreenPresented(out bool isSplashScreenPresented); + int Flash(); + int GetRootSwitchableOwner(out IApplicationView rootSwitchableOwner); + int EnumerateOwnershipTree(out IObjectArray ownershipTree); + int GetEnterpriseId([MarshalAs(UnmanagedType.LPWStr)] out string enterpriseId); + int IsMirrored(out bool isMirrored); + int Unknown1(out int unknown); + int Unknown2(out int unknown); + int Unknown3(out int unknown); + int Unknown4(out int unknown); + int Unknown5(out int unknown); + int Unknown6(int unknown); + int Unknown7(); + int Unknown8(out int unknown); + int Unknown9(int unknown); + int Unknown10(int unknownX, int unknownY); + int Unknown11(int unknown); + int Unknown12(out SIZE size1); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")] + public interface IApplicationViewCollection + { + int GetViews(out IObjectArray array); + int GetViewsByZOrder(out IObjectArray array); + int GetViewsByAppUserModelId(string id, out IObjectArray array); + int GetViewForHwnd(IntPtr hwnd, out IApplicationView view); + int GetViewForApplication(object application, out IApplicationView view); + int GetViewForAppUserModelId(string id, out IApplicationView view); + int GetViewInFocus(out IntPtr view); + int Unknown1(out IntPtr view); + void RefreshCollection(); + int RegisterForApplicationViewChanges(object listener, out int cookie); + int UnregisterForApplicationViewChanges(int cookie); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("F31574D6-B682-4CDC-BD56-1827860ABEC6")] + public interface IVirtualDesktopManagerInternal + { + int GetCount(); + void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop); + bool CanViewMoveDesktops(IApplicationView view); + IVirtualDesktop GetCurrentDesktop(); + void GetDesktops(out IObjectArray desktops); + [PreserveSig] + int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop); + void SwitchDesktop(IVirtualDesktop desktop); + IVirtualDesktop CreateDesktop(); + void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback); + IVirtualDesktop FindDesktop(ref Guid desktopid); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")] + public interface IVirtualDesktopManager + { + bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); + Guid GetWindowDesktopId(IntPtr topLevelWindow); + void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] + public interface IVirtualDesktop : IIVirtualDesktop + { + bool IsViewVisible(IApplicationView view); + Guid GetId(); + } + } + + public class WindowsVirtualDesktop : IWindowsVirtualDesktop + { + private static WindowsVirtualDesktopManager _windowsVirtualDesktopManager = new WindowsVirtualDesktopManager(); + [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + + public IIVirtualDesktop ivd { get; set; } + public WindowsVirtualDesktop() { } + public WindowsVirtualDesktop(IIVirtualDesktop desktop) { this.ivd = desktop; } + public void MakeVisible() => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.SwitchDesktop((WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + public IWindowsVirtualDesktop FromIndex(int index) => new WindowsVirtualDesktop(_windowsVirtualDesktopManager.GetDesktop(index)); + + public int Count + { + get => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCount(); + } + + public IWindowsVirtualDesktop Current + { + get => new WindowsVirtualDesktop((IIVirtualDesktop)_windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCurrentDesktop()); + } + + public void MoveWindow(IntPtr hWnd) + { + int processId; + if (hWnd == IntPtr.Zero) throw new ArgumentNullException(); + GetWindowThreadProcessId(hWnd, out processId); + WindowsVirtualDesktopAPI.IApplicationView view; + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(hWnd, out view); + try + { + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + catch + { + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view); + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + } + } + + public class WindowsVirtualDesktopManager : IWindowsVirtualDesktopManager + { + public WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps VirtualDesktopPinnedApps; + public WindowsVirtualDesktopAPI.IVirtualDesktopManager VirtualDesktopManagerPrivate; + public WindowsVirtualDesktopAPI.IApplicationViewCollection ApplicationViewCollection; + public WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal VirtualDesktopManagerInternal; + public int FromDesktop(IWindowsVirtualDesktop desktop) => desktop != null ? GetDesktopIndex((WindowsVirtualDesktopAPI.IVirtualDesktop)desktop.ivd) : -1; + public bool IsWindowPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsViewPinned(GetApplicationView(hWnd)); + public bool IsApplicationPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsAppIdPinned(GetAppId(hWnd)); + + private WindowsVirtualDesktopAPI.IApplicationView GetApplicationView(IntPtr hWnd) + { + ApplicationViewCollection.GetViewForHwnd(hWnd, out WindowsVirtualDesktopAPI.IApplicationView view); + return view; + } + + private string GetAppId(IntPtr hWnd) + { + GetApplicationView(hWnd).GetAppUserModelId(out string appId); + return appId; + } + + public WindowsVirtualDesktopManager() + { + var shell = (WindowsVirtualDesktopAPI.IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_IMMERSIVESHELL)); + VirtualDesktopManagerPrivate = (WindowsVirtualDesktopAPI.IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGER)); + ApplicationViewCollection = (WindowsVirtualDesktopAPI.IApplicationViewCollection)shell.QueryService(typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID, typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID); + VirtualDesktopManagerInternal = (WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGERINTERNAL, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal).GUID); + VirtualDesktopPinnedApps = (WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPPINNEDAPPS, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps).GUID); + } + + public WindowsVirtualDesktopAPI.IVirtualDesktop GetDesktop(int index) + { + int count = VirtualDesktopManagerInternal.GetCount(); + if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); + WindowsVirtualDesktopAPI.IObjectArray desktops; + VirtualDesktopManagerInternal.GetDesktops(out desktops); + object objdesktop; + desktops.GetAt(index, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out objdesktop); + Marshal.ReleaseComObject(desktops); + return (WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop; + } + + public int GetDesktopIndex(WindowsVirtualDesktopAPI.IVirtualDesktop desktop) + { + int index = -1; + Guid IdSearch = desktop.GetId(); + VirtualDesktopManagerInternal.GetDesktops(out WindowsVirtualDesktopAPI.IObjectArray desktops); + for (int i = 0; i < VirtualDesktopManagerInternal.GetCount(); i++) + { + desktops.GetAt(i, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out object objdesktop); + if (IdSearch.CompareTo(((WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop).GetId()) == 0) + { + index = i; + break; + } + } + Marshal.ReleaseComObject(desktops); + return index; + } + + public IWindowsVirtualDesktop FromWindow(IntPtr hWnd) + { + Guid id = VirtualDesktopManagerPrivate.GetWindowDesktopId(hWnd); + if (id != Guid.Empty) return new WindowsVirtualDesktop(VirtualDesktopManagerInternal.FindDesktop(ref id)); + return null; + } + + public void PinApplication(IntPtr hWnd) + { + string appId = GetAppId(hWnd); + if (!VirtualDesktopPinnedApps.IsAppIdPinned(appId)) + VirtualDesktopPinnedApps.PinAppID(appId); + } + } + +} \ No newline at end of file diff --git a/src/Core/API/VirtualDesktopAPI-Win10LTSC.cs b/src/Core/API/VirtualDesktopAPI-Win10LTSC.cs new file mode 100644 index 0000000..0754648 --- /dev/null +++ b/src/Core/API/VirtualDesktopAPI-Win10LTSC.cs @@ -0,0 +1,309 @@ +// Adapted from https://github.com/MScholtes/VirtualDesktop with a few modifications +using System; +using System.Runtime.InteropServices; + +namespace Switchie.VirtualDesktopAPI.Win10LTSC +{ + + public class WindowsVirtualDesktopAPI + { + public static readonly Guid CLSID_IMMERSIVESHELL = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGERINTERNAL = new Guid("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGER = new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); + public static readonly Guid CLSID_VIRTUALDESKTOPPINNEDAPPS = new Guid("B5A399E7-1C87-46B8-88E9-FC5747B171BD"); + + [StructLayout(LayoutKind.Sequential)] + public struct SIZE + { + public int X; + public int Y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + public enum APPLICATION_VIEW_CLOAK_TYPE : int + { + AVCT_NONE = 0, + AVCT_DEFAULT = 1, + AVCT_VIRTUAL_DESKTOP = 2 + } + + public enum APPLICATION_VIEW_COMPATIBILITY_POLICY : int + { + AVCP_NONE = 0, + AVCP_SMALL_SCREEN = 1, + AVCP_TABLET_SMALL_SCREEN = 2, + AVCP_VERY_SMALL_SCREEN = 3, + AVCP_HIGH_SCALE_FACTOR = 4 + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] + public interface IObjectArray + { + void GetCount(out int count); + void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out object obj); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("4CE81583-1E4C-4632-A621-07A53543148F")] + public interface IVirtualDesktopPinnedApps + { + bool IsAppIdPinned(string appId); + void PinAppID(string appId); + void UnpinAppID(string appId); + bool IsViewPinned(IApplicationView applicationView); + void PinView(IApplicationView applicationView); + void UnpinView(IApplicationView applicationView); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] + public interface IServiceProvider10 + { + [return: MarshalAs(UnmanagedType.IUnknown)] + object QueryService(ref Guid service, ref Guid riid); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)] + [Guid("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] + public interface IApplicationView + { + int SetFocus(); + int SwitchTo(); + int TryInvokeBack(IntPtr /* IAsyncCallback* */ callback); + int GetThumbnailWindow(out IntPtr hwnd); + int GetMonitor(out IntPtr /* IImmersiveMonitor */ immersiveMonitor); + int GetVisibility(out int visibility); + int SetCloak(APPLICATION_VIEW_CLOAK_TYPE cloakType, int unknown); + int GetPosition(ref Guid guid /* GUID for IApplicationViewPosition */, out IntPtr /* IApplicationViewPosition** */ position); + int SetPosition(ref IntPtr /* IApplicationViewPosition* */ position); + int InsertAfterWindow(IntPtr hwnd); + int GetExtendedFramePosition(out RECT rect); + int GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string id); + int SetAppUserModelId(string id); + int IsEqualByAppUserModelId(string id, out int result); + int GetViewState(out uint state); + int SetViewState(uint state); + int GetNeediness(out int neediness); + int GetLastActivationTimestamp(out ulong timestamp); + int SetLastActivationTimestamp(ulong timestamp); + int GetVirtualDesktopId(out Guid guid); + int SetVirtualDesktopId(ref Guid guid); + int GetShowInSwitchers(out int flag); + int SetShowInSwitchers(int flag); + int GetScaleFactor(out int factor); + int CanReceiveInput(out bool canReceiveInput); + int GetCompatibilityPolicyType(out APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int SetCompatibilityPolicyType(APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int GetSizeConstraints(IntPtr /* IImmersiveMonitor* */ monitor, out SIZE size1, out SIZE size2); + int GetSizeConstraintsForDpi(uint uint1, out SIZE size1, out SIZE size2); + int SetSizeConstraintsForDpi(ref uint uint1, ref SIZE size1, ref SIZE size2); + int OnMinSizePreferencesUpdated(IntPtr hwnd); + int ApplyOperation(IntPtr /* IApplicationViewOperation* */ operation); + int IsTray(out bool isTray); + int IsInHighZOrderBand(out bool isInHighZOrderBand); + int IsSplashScreenPresented(out bool isSplashScreenPresented); + int Flash(); + int GetRootSwitchableOwner(out IApplicationView rootSwitchableOwner); + int EnumerateOwnershipTree(out IObjectArray ownershipTree); + int GetEnterpriseId([MarshalAs(UnmanagedType.LPWStr)] out string enterpriseId); + int IsMirrored(out bool isMirrored); + int Unknown1(out int unknown); + int Unknown2(out int unknown); + int Unknown3(out int unknown); + int Unknown4(out int unknown); + int Unknown5(out int unknown); + int Unknown6(int unknown); + int Unknown7(); + int Unknown8(out int unknown); + int Unknown9(int unknown); + int Unknown10(int unknownX, int unknownY); + int Unknown11(int unknown); + int Unknown12(out SIZE size1); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")] + public interface IApplicationViewCollection + { + int GetViews(out IObjectArray array); + int GetViewsByZOrder(out IObjectArray array); + int GetViewsByAppUserModelId(string id, out IObjectArray array); + int GetViewForHwnd(IntPtr hwnd, out IApplicationView view); + int GetViewForApplication(object application, out IApplicationView view); + int GetViewForAppUserModelId(string id, out IApplicationView view); + int GetViewInFocus(out IntPtr view); + int Unknown1(out IntPtr view); + void RefreshCollection(); + int RegisterForApplicationViewChanges(object listener, out int cookie); + int UnregisterForApplicationViewChanges(int cookie); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("F31574D6-B682-4CDC-BD56-1827860ABEC6")] + public interface IVirtualDesktopManagerInternal + { + int GetCount(); + void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop); + bool CanViewMoveDesktops(IApplicationView view); + IVirtualDesktop GetCurrentDesktop(); + void GetDesktops(out IObjectArray desktops); + [PreserveSig] + int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop); + void SwitchDesktop(IVirtualDesktop desktop); + IVirtualDesktop CreateDesktop(); + void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback); + IVirtualDesktop FindDesktop(ref Guid desktopid); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")] + public interface IVirtualDesktopManager + { + bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); + Guid GetWindowDesktopId(IntPtr topLevelWindow); + void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] + public interface IVirtualDesktop : IIVirtualDesktop + { + bool IsViewVisible(IApplicationView view); + Guid GetId(); + } + } + + public class WindowsVirtualDesktop : IWindowsVirtualDesktop + { + private static WindowsVirtualDesktopManager _windowsVirtualDesktopManager = new WindowsVirtualDesktopManager(); + [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + + public IIVirtualDesktop ivd { get; set; } + public WindowsVirtualDesktop() { } + public WindowsVirtualDesktop(IIVirtualDesktop desktop) { this.ivd = desktop; } + public void MakeVisible() => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.SwitchDesktop((WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + public IWindowsVirtualDesktop FromIndex(int index) => new WindowsVirtualDesktop(_windowsVirtualDesktopManager.GetDesktop(index)); + + public int Count + { + get => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCount(); + } + + public IWindowsVirtualDesktop Current + { + get => new WindowsVirtualDesktop((IIVirtualDesktop)_windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCurrentDesktop()); + } + + public void MoveWindow(IntPtr hWnd) + { + int processId; + if (hWnd == IntPtr.Zero) throw new ArgumentNullException(); + GetWindowThreadProcessId(hWnd, out processId); + WindowsVirtualDesktopAPI.IApplicationView view; + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(hWnd, out view); + try + { + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + catch + { + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view); + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + } + } + + public class WindowsVirtualDesktopManager : IWindowsVirtualDesktopManager + { + public WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps VirtualDesktopPinnedApps; + public WindowsVirtualDesktopAPI.IVirtualDesktopManager VirtualDesktopManagerPrivate; + public WindowsVirtualDesktopAPI.IApplicationViewCollection ApplicationViewCollection; + public WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal VirtualDesktopManagerInternal; + public int FromDesktop(IWindowsVirtualDesktop desktop) => desktop != null ? GetDesktopIndex((WindowsVirtualDesktopAPI.IVirtualDesktop)desktop.ivd) : -1; + public bool IsWindowPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsViewPinned(GetApplicationView(hWnd)); + public bool IsApplicationPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsAppIdPinned(GetAppId(hWnd)); + + private WindowsVirtualDesktopAPI.IApplicationView GetApplicationView(IntPtr hWnd) + { + ApplicationViewCollection.GetViewForHwnd(hWnd, out WindowsVirtualDesktopAPI.IApplicationView view); + return view; + } + + private string GetAppId(IntPtr hWnd) + { + GetApplicationView(hWnd).GetAppUserModelId(out string appId); + return appId; + } + + public WindowsVirtualDesktopManager() + { + var shell = (WindowsVirtualDesktopAPI.IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_IMMERSIVESHELL)); + VirtualDesktopManagerPrivate = (WindowsVirtualDesktopAPI.IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGER)); + ApplicationViewCollection = (WindowsVirtualDesktopAPI.IApplicationViewCollection)shell.QueryService(typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID, typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID); + VirtualDesktopManagerInternal = (WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGERINTERNAL, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal).GUID); + VirtualDesktopPinnedApps = (WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPPINNEDAPPS, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps).GUID); + } + + public WindowsVirtualDesktopAPI.IVirtualDesktop GetDesktop(int index) + { + int count = VirtualDesktopManagerInternal.GetCount(); + if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); + WindowsVirtualDesktopAPI.IObjectArray desktops; + VirtualDesktopManagerInternal.GetDesktops(out desktops); + object objdesktop; + desktops.GetAt(index, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out objdesktop); + Marshal.ReleaseComObject(desktops); + return (WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop; + } + + public int GetDesktopIndex(WindowsVirtualDesktopAPI.IVirtualDesktop desktop) + { + int index = -1; + Guid IdSearch = desktop.GetId(); + VirtualDesktopManagerInternal.GetDesktops(out WindowsVirtualDesktopAPI.IObjectArray desktops); + for (int i = 0; i < VirtualDesktopManagerInternal.GetCount(); i++) + { + desktops.GetAt(i, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out object objdesktop); + if (IdSearch.CompareTo(((WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop).GetId()) == 0) + { + index = i; + break; + } + } + Marshal.ReleaseComObject(desktops); + return index; + } + + public IWindowsVirtualDesktop FromWindow(IntPtr hWnd) + { + Guid id = VirtualDesktopManagerPrivate.GetWindowDesktopId(hWnd); + if (id != Guid.Empty) return new WindowsVirtualDesktop(VirtualDesktopManagerInternal.FindDesktop(ref id)); + return null; + } + + public void PinApplication(IntPtr hWnd) + { + string appId = GetAppId(hWnd); + if (!VirtualDesktopPinnedApps.IsAppIdPinned(appId)) + VirtualDesktopPinnedApps.PinAppID(appId); + } + } + +} \ No newline at end of file diff --git a/src/Core/API/VirtualDesktopAPI-Win11.cs b/src/Core/API/VirtualDesktopAPI-Win11.cs new file mode 100644 index 0000000..8abe134 --- /dev/null +++ b/src/Core/API/VirtualDesktopAPI-Win11.cs @@ -0,0 +1,322 @@ +// Adapted from https://github.com/MScholtes/VirtualDesktop with a few modifications +using System; +using System.Runtime.InteropServices; + +namespace Switchie.VirtualDesktopAPI.Win11 +{ + + public class WindowsVirtualDesktopAPI + { + public static readonly Guid CLSID_IMMERSIVESHELL = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGERINTERNAL = new Guid("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B"); + public static readonly Guid CLSID_VIRTUALDESKTOPMANAGER = new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); + public static readonly Guid CLSID_VIRTUALDESKTOPPINNEDAPPS = new Guid("B5A399E7-1C87-46B8-88E9-FC5747B171BD"); + + [StructLayout(LayoutKind.Sequential)] + public struct SIZE + { + public int X; + public int Y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RECT + { + public int Left; + public int Top; + public int Right; + public int Bottom; + } + + public enum APPLICATION_VIEW_CLOAK_TYPE : int + { + AVCT_NONE = 0, + AVCT_DEFAULT = 1, + AVCT_VIRTUAL_DESKTOP = 2 + } + + public enum APPLICATION_VIEW_COMPATIBILITY_POLICY : int + { + AVCP_NONE = 0, + AVCP_SMALL_SCREEN = 1, + AVCP_TABLET_SMALL_SCREEN = 2, + AVCP_VERY_SMALL_SCREEN = 3, + AVCP_HIGH_SCALE_FACTOR = 4 + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] + public interface IObjectArray + { + void GetCount(out int count); + void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out object obj); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("4CE81583-1E4C-4632-A621-07A53543148F")] + public interface IVirtualDesktopPinnedApps + { + bool IsAppIdPinned(string appId); + void PinAppID(string appId); + void UnpinAppID(string appId); + bool IsViewPinned(IApplicationView applicationView); + void PinView(IApplicationView applicationView); + void UnpinView(IApplicationView applicationView); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] + public interface IServiceProvider10 + { + [return: MarshalAs(UnmanagedType.IUnknown)] + object QueryService(ref Guid service, ref Guid riid); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)] + [Guid("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] + public interface IApplicationView + { + int SetFocus(); + int SwitchTo(); + int TryInvokeBack(IntPtr /* IAsyncCallback* */ callback); + int GetThumbnailWindow(out IntPtr hwnd); + int GetMonitor(out IntPtr /* IImmersiveMonitor */ immersiveMonitor); + int GetVisibility(out int visibility); + int SetCloak(APPLICATION_VIEW_CLOAK_TYPE cloakType, int unknown); + int GetPosition(ref Guid guid /* GUID for IApplicationViewPosition */, out IntPtr /* IApplicationViewPosition** */ position); + int SetPosition(ref IntPtr /* IApplicationViewPosition* */ position); + int InsertAfterWindow(IntPtr hwnd); + int GetExtendedFramePosition(out RECT rect); + int GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string id); + int SetAppUserModelId(string id); + int IsEqualByAppUserModelId(string id, out int result); + int GetViewState(out uint state); + int SetViewState(uint state); + int GetNeediness(out int neediness); + int GetLastActivationTimestamp(out ulong timestamp); + int SetLastActivationTimestamp(ulong timestamp); + int GetVirtualDesktopId(out Guid guid); + int SetVirtualDesktopId(ref Guid guid); + int GetShowInSwitchers(out int flag); + int SetShowInSwitchers(int flag); + int GetScaleFactor(out int factor); + int CanReceiveInput(out bool canReceiveInput); + int GetCompatibilityPolicyType(out APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int SetCompatibilityPolicyType(APPLICATION_VIEW_COMPATIBILITY_POLICY flags); + int GetSizeConstraints(IntPtr /* IImmersiveMonitor* */ monitor, out SIZE size1, out SIZE size2); + int GetSizeConstraintsForDpi(uint uint1, out SIZE size1, out SIZE size2); + int SetSizeConstraintsForDpi(ref uint uint1, ref SIZE size1, ref SIZE size2); + int OnMinSizePreferencesUpdated(IntPtr hwnd); + int ApplyOperation(IntPtr /* IApplicationViewOperation* */ operation); + int IsTray(out bool isTray); + int IsInHighZOrderBand(out bool isInHighZOrderBand); + int IsSplashScreenPresented(out bool isSplashScreenPresented); + int Flash(); + int GetRootSwitchableOwner(out IApplicationView rootSwitchableOwner); + int EnumerateOwnershipTree(out IObjectArray ownershipTree); + int GetEnterpriseId([MarshalAs(UnmanagedType.LPWStr)] out string enterpriseId); + int IsMirrored(out bool isMirrored); + int Unknown1(out int unknown); + int Unknown2(out int unknown); + int Unknown3(out int unknown); + int Unknown4(out int unknown); + int Unknown5(out int unknown); + int Unknown6(int unknown); + int Unknown7(); + int Unknown8(out int unknown); + int Unknown9(int unknown); + int Unknown10(int unknownX, int unknownY); + int Unknown11(int unknown); + int Unknown12(out SIZE size1); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")] + public interface IApplicationViewCollection + { + int GetViews(out IObjectArray array); + int GetViewsByZOrder(out IObjectArray array); + int GetViewsByAppUserModelId(string id, out IObjectArray array); + int GetViewForHwnd(IntPtr hwnd, out IApplicationView view); + int GetViewForApplication(object application, out IApplicationView view); + int GetViewForAppUserModelId(string id, out IApplicationView view); + int GetViewInFocus(out IntPtr view); + int Unknown1(out IntPtr view); + void RefreshCollection(); + int RegisterForApplicationViewChanges(object listener, out int cookie); + int UnregisterForApplicationViewChanges(int cookie); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("B2F925B9-5A0F-4D2E-9F4D-2B1507593C10")] + public interface IVirtualDesktopManagerInternal + { + int GetCount(IntPtr hWndOrMon); + void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop); + bool CanViewMoveDesktops(IApplicationView view); + IVirtualDesktop GetCurrentDesktop(IntPtr hWndOrMon); + void GetDesktops(IntPtr hWndOrMon, out IObjectArray desktops); + [PreserveSig] + int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop); + void SwitchDesktop(IntPtr hWndOrMon, IVirtualDesktop desktop); + IVirtualDesktop CreateDesktop(IntPtr hWndOrMon); + void MoveDesktop(IVirtualDesktop desktop, IntPtr hWndOrMon, int nIndex); + void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback); + IVirtualDesktop FindDesktop(ref Guid desktopid); + void GetDesktopSwitchIncludeExcludeViews(IVirtualDesktop desktop, out IObjectArray unknown1, out IObjectArray unknown2); + void SetDesktopName(IVirtualDesktop desktop, [MarshalAs(UnmanagedType.HString)] string name); + void SetDesktopWallpaper(IVirtualDesktop desktop, [MarshalAs(UnmanagedType.HString)] string path); + void UpdateWallpaperPathForAllDesktops([MarshalAs(UnmanagedType.HString)] string path); + void CopyDesktopState(IApplicationView pView0, IApplicationView pView1); + int GetDesktopIsPerMonitor(); + void SetDesktopIsPerMonitor(bool state); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")] + public interface IVirtualDesktopManager + { + bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); + Guid GetWindowDesktopId(IntPtr topLevelWindow); + void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId); + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("536D3495-B208-4CC9-AE26-DE8111275BF8")] + public interface IVirtualDesktop : IIVirtualDesktop + { + bool IsViewVisible(IApplicationView view); + Guid GetId(); + IntPtr Unknown1(); + [return: MarshalAs(UnmanagedType.HString)] + string GetName(); + [return: MarshalAs(UnmanagedType.HString)] + string GetWallpaperPath(); + } + } + + public class WindowsVirtualDesktop : IWindowsVirtualDesktop + { + private static WindowsVirtualDesktopManager _windowsVirtualDesktopManager = new WindowsVirtualDesktopManager(); + [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + + public IIVirtualDesktop ivd { get; set; } + public WindowsVirtualDesktop() { } + public WindowsVirtualDesktop(IIVirtualDesktop desktop) { this.ivd = desktop; } + public void MakeVisible() => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.SwitchDesktop(IntPtr.Zero, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + public IWindowsVirtualDesktop FromIndex(int index) => new WindowsVirtualDesktop(_windowsVirtualDesktopManager.GetDesktop(index)); + + public int Count + { + get => _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCount(IntPtr.Zero); + } + + public IWindowsVirtualDesktop Current + { + get => new WindowsVirtualDesktop((IIVirtualDesktop)_windowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCurrentDesktop(IntPtr.Zero)); + } + + public void MoveWindow(IntPtr hWnd) + { + int processId; + if (hWnd == IntPtr.Zero) throw new ArgumentNullException(); + GetWindowThreadProcessId(hWnd, out processId); + WindowsVirtualDesktopAPI.IApplicationView view; + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(hWnd, out view); + try + { + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + catch + { + _windowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view); + _windowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, (WindowsVirtualDesktopAPI.IVirtualDesktop)ivd); + } + } + } + + public class WindowsVirtualDesktopManager : IWindowsVirtualDesktopManager + { + public WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps VirtualDesktopPinnedApps; + public WindowsVirtualDesktopAPI.IVirtualDesktopManager VirtualDesktopManagerPrivate; + public WindowsVirtualDesktopAPI.IApplicationViewCollection ApplicationViewCollection; + public WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal VirtualDesktopManagerInternal; + public int FromDesktop(IWindowsVirtualDesktop desktop) => desktop != null ? GetDesktopIndex((WindowsVirtualDesktopAPI.IVirtualDesktop)desktop.ivd) : -1; + public bool IsWindowPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsViewPinned(GetApplicationView(hWnd)); + public bool IsApplicationPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsAppIdPinned(GetAppId(hWnd)); + + private WindowsVirtualDesktopAPI.IApplicationView GetApplicationView(IntPtr hWnd) + { + ApplicationViewCollection.GetViewForHwnd(hWnd, out WindowsVirtualDesktopAPI.IApplicationView view); + return view; + } + + private string GetAppId(IntPtr hWnd) + { + GetApplicationView(hWnd).GetAppUserModelId(out string appId); + return appId; + } + + public WindowsVirtualDesktopManager() + { + var shell = (WindowsVirtualDesktopAPI.IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_IMMERSIVESHELL)); + VirtualDesktopManagerPrivate = (WindowsVirtualDesktopAPI.IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGER)); + ApplicationViewCollection = (WindowsVirtualDesktopAPI.IApplicationViewCollection)shell.QueryService(typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID, typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID); + VirtualDesktopManagerInternal = (WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGERINTERNAL, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal).GUID); + VirtualDesktopPinnedApps = (WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPPINNEDAPPS, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps).GUID); + } + + public WindowsVirtualDesktopAPI.IVirtualDesktop GetDesktop(int index) + { + int count = VirtualDesktopManagerInternal.GetCount(IntPtr.Zero); + if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); + WindowsVirtualDesktopAPI.IObjectArray desktops; + VirtualDesktopManagerInternal.GetDesktops(IntPtr.Zero, out desktops); + object objdesktop; + desktops.GetAt(index, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out objdesktop); + Marshal.ReleaseComObject(desktops); + return (WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop; + } + + public int GetDesktopIndex(WindowsVirtualDesktopAPI.IVirtualDesktop desktop) + { + int index = -1; + Guid IdSearch = desktop.GetId(); + VirtualDesktopManagerInternal.GetDesktops(IntPtr.Zero, out WindowsVirtualDesktopAPI.IObjectArray desktops); + for (int i = 0; i < VirtualDesktopManagerInternal.GetCount(IntPtr.Zero); i++) + { + desktops.GetAt(i, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out object objdesktop); + if (IdSearch.CompareTo(((WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop).GetId()) == 0) + { + index = i; + break; + } + } + Marshal.ReleaseComObject(desktops); + return index; + } + + public IWindowsVirtualDesktop FromWindow(IntPtr hWnd) + { + Guid id = VirtualDesktopManagerPrivate.GetWindowDesktopId(hWnd); + if (id != Guid.Empty) return new WindowsVirtualDesktop(VirtualDesktopManagerInternal.FindDesktop(ref id)); + return null; + } + + public void PinApplication(IntPtr hWnd) + { + string appId = GetAppId(hWnd); + if (!VirtualDesktopPinnedApps.IsAppIdPinned(appId)) + VirtualDesktopPinnedApps.PinAppID(appId); + } + } + +} \ No newline at end of file diff --git a/src/Core/API/VirtualDesktopAPI.cs b/src/Core/API/VirtualDesktopAPI.cs index 6eae713..b85b64d 100644 --- a/src/Core/API/VirtualDesktopAPI.cs +++ b/src/Core/API/VirtualDesktopAPI.cs @@ -1,308 +1,44 @@ -// Adapted from https://github.com/MScholtes/VirtualDesktop with a few modifications -// TODO: Needs to be adapted to the latest versions on his repo targeting Win10/Win11 - using System; -using System.Runtime.InteropServices; - namespace Switchie { - public static class WindowsVirtualDesktopAPI - { - public static readonly Guid CLSID_IMMERSIVESHELL = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239"); - public static readonly Guid CLSID_VIRTUALDESKTOPMANAGERINTERNAL = new Guid("C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B"); - public static readonly Guid CLSID_VIRTUALDESKTOPMANAGER = new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); - public static readonly Guid CLSID_VIRTUALDESKTOPPINNEDAPPS = new Guid("B5A399E7-1C87-46B8-88E9-FC5747B171BD"); - - [StructLayout(LayoutKind.Sequential)] - public struct SIZE - { - public int X; - public int Y; - } - - [StructLayout(LayoutKind.Sequential)] - public struct RECT - { - public int Left; - public int Top; - public int Right; - public int Bottom; - } - - public enum APPLICATION_VIEW_CLOAK_TYPE : int - { - AVCT_NONE = 0, - AVCT_DEFAULT = 1, - AVCT_VIRTUAL_DESKTOP = 2 - } - - public enum APPLICATION_VIEW_COMPATIBILITY_POLICY : int - { - AVCP_NONE = 0, - AVCP_SMALL_SCREEN = 1, - AVCP_TABLET_SMALL_SCREEN = 2, - AVCP_VERY_SMALL_SCREEN = 3, - AVCP_HIGH_SCALE_FACTOR = 4 - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] - public interface IObjectArray - { - void GetCount(out int count); - void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)] out object obj); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("4CE81583-1E4C-4632-A621-07A53543148F")] - public interface IVirtualDesktopPinnedApps - { - bool IsAppIdPinned(string appId); - void PinAppID(string appId); - void UnpinAppID(string appId); - bool IsViewPinned(IApplicationView applicationView); - void PinView(IApplicationView applicationView); - void UnpinView(IApplicationView applicationView); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("6D5140C1-7436-11CE-8034-00AA006009FA")] - public interface IServiceProvider10 - { - [return: MarshalAs(UnmanagedType.IUnknown)] - object QueryService(ref Guid service, ref Guid riid); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIInspectable)] - [Guid("372E1D3B-38D3-42E4-A15B-8AB2B178F513")] - public interface IApplicationView - { - int SetFocus(); - int SwitchTo(); - int TryInvokeBack(IntPtr /* IAsyncCallback* */ callback); - int GetThumbnailWindow(out IntPtr hwnd); - int GetMonitor(out IntPtr /* IImmersiveMonitor */ immersiveMonitor); - int GetVisibility(out int visibility); - int SetCloak(APPLICATION_VIEW_CLOAK_TYPE cloakType, int unknown); - int GetPosition(ref Guid guid /* GUID for IApplicationViewPosition */, out IntPtr /* IApplicationViewPosition** */ position); - int SetPosition(ref IntPtr /* IApplicationViewPosition* */ position); - int InsertAfterWindow(IntPtr hwnd); - int GetExtendedFramePosition(out RECT rect); - int GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string id); - int SetAppUserModelId(string id); - int IsEqualByAppUserModelId(string id, out int result); - int GetViewState(out uint state); - int SetViewState(uint state); - int GetNeediness(out int neediness); - int GetLastActivationTimestamp(out ulong timestamp); - int SetLastActivationTimestamp(ulong timestamp); - int GetVirtualDesktopId(out Guid guid); - int SetVirtualDesktopId(ref Guid guid); - int GetShowInSwitchers(out int flag); - int SetShowInSwitchers(int flag); - int GetScaleFactor(out int factor); - int CanReceiveInput(out bool canReceiveInput); - int GetCompatibilityPolicyType(out APPLICATION_VIEW_COMPATIBILITY_POLICY flags); - int SetCompatibilityPolicyType(APPLICATION_VIEW_COMPATIBILITY_POLICY flags); - int GetSizeConstraints(IntPtr /* IImmersiveMonitor* */ monitor, out SIZE size1, out SIZE size2); - int GetSizeConstraintsForDpi(uint uint1, out SIZE size1, out SIZE size2); - int SetSizeConstraintsForDpi(ref uint uint1, ref SIZE size1, ref SIZE size2); - int OnMinSizePreferencesUpdated(IntPtr hwnd); - int ApplyOperation(IntPtr /* IApplicationViewOperation* */ operation); - int IsTray(out bool isTray); - int IsInHighZOrderBand(out bool isInHighZOrderBand); - int IsSplashScreenPresented(out bool isSplashScreenPresented); - int Flash(); - int GetRootSwitchableOwner(out IApplicationView rootSwitchableOwner); - int EnumerateOwnershipTree(out IObjectArray ownershipTree); - int GetEnterpriseId([MarshalAs(UnmanagedType.LPWStr)] out string enterpriseId); - int IsMirrored(out bool isMirrored); - int Unknown1(out int unknown); - int Unknown2(out int unknown); - int Unknown3(out int unknown); - int Unknown4(out int unknown); - int Unknown5(out int unknown); - int Unknown6(int unknown); - int Unknown7(); - int Unknown8(out int unknown); - int Unknown9(int unknown); - int Unknown10(int unknownX, int unknownY); - int Unknown11(int unknown); - int Unknown12(out SIZE size1); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("1841C6D7-4F9D-42C0-AF41-8747538F10E5")] - public interface IApplicationViewCollection - { - int GetViews(out IObjectArray array); - int GetViewsByZOrder(out IObjectArray array); - int GetViewsByAppUserModelId(string id, out IObjectArray array); - int GetViewForHwnd(IntPtr hwnd, out IApplicationView view); - int GetViewForApplication(object application, out IApplicationView view); - int GetViewForAppUserModelId(string id, out IApplicationView view); - int GetViewInFocus(out IntPtr view); - int Unknown1(out IntPtr view); - void RefreshCollection(); - int RegisterForApplicationViewChanges(object listener, out int cookie); - int UnregisterForApplicationViewChanges(int cookie); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("F31574D6-B682-4CDC-BD56-1827860ABEC6")] - public interface IVirtualDesktopManagerInternal - { - int GetCount(); - void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop); - bool CanViewMoveDesktops(IApplicationView view); - IVirtualDesktop GetCurrentDesktop(); - void GetDesktops(out IObjectArray desktops); - [PreserveSig] - int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop); - void SwitchDesktop(IVirtualDesktop desktop); - IVirtualDesktop CreateDesktop(); - void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback); - IVirtualDesktop FindDesktop(ref Guid desktopid); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("A5CD92FF-29BE-454C-8D04-D82879FB3F1B")] - public interface IVirtualDesktopManager - { - bool IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); - Guid GetWindowDesktopId(IntPtr topLevelWindow); - void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId); - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] - public interface IVirtualDesktop - { - bool IsViewVisible(IApplicationView view); - Guid GetId(); - } - } - public class WindowsVirtualDesktop { - [DllImport("user32.dll")] private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); - - public WindowsVirtualDesktopAPI.IVirtualDesktop ivd; - public WindowsVirtualDesktop(WindowsVirtualDesktopAPI.IVirtualDesktop desktop) { this.ivd = desktop; } - public void MakeVisible() => WindowsVirtualDesktopManager.VirtualDesktopManagerInternal.SwitchDesktop(ivd); - public static WindowsVirtualDesktop FromIndex(int index) => new WindowsVirtualDesktop(WindowsVirtualDesktopManager.GetDesktop(index)); - - public static int Count - { - get => WindowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCount(); - } - - public static WindowsVirtualDesktop Current - { - get => new WindowsVirtualDesktop(WindowsVirtualDesktopManager.VirtualDesktopManagerInternal.GetCurrentDesktop()); - } - - public void MoveWindow(IntPtr hWnd) + private static IWindowsVirtualDesktop _instance; + public static IWindowsVirtualDesktop GetInstance() { - int processId; - if (hWnd == IntPtr.Zero) throw new ArgumentNullException(); - GetWindowThreadProcessId(hWnd, out processId); - WindowsVirtualDesktopAPI.IApplicationView view; - WindowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(hWnd, out view); - try + if (WindowsVirtualDesktop._instance == null) { - WindowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, ivd); - } - catch - { - WindowsVirtualDesktopManager.ApplicationViewCollection.GetViewForHwnd(System.Diagnostics.Process.GetProcessById(processId).MainWindowHandle, out view); - WindowsVirtualDesktopManager.VirtualDesktopManagerInternal.MoveViewToDesktop(view, ivd); + if (Program.WindowsVersion.IsWin11()) + _instance = new Switchie.VirtualDesktopAPI.Win11.WindowsVirtualDesktop(); + else if (Program.WindowsVersion.IsWin10()) + _instance = new Switchie.VirtualDesktopAPI.Win10.WindowsVirtualDesktop(); + else if (Program.WindowsVersion.IsWin10LTSC()) + _instance = new Switchie.VirtualDesktopAPI.Win10LTSC.WindowsVirtualDesktop(); + else + throw new PlatformNotSupportedException(); } + return WindowsVirtualDesktop._instance; } } - public static class WindowsVirtualDesktopManager + public class WindowsVirtualDesktopManager { - public static WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps VirtualDesktopPinnedApps; - public static WindowsVirtualDesktopAPI.IVirtualDesktopManager VirtualDesktopManagerPrivate; - public static WindowsVirtualDesktopAPI.IApplicationViewCollection ApplicationViewCollection; - public static WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal VirtualDesktopManagerInternal; - public static int FromDesktop(WindowsVirtualDesktop desktop) => desktop != null ? GetDesktopIndex(desktop.ivd) : -1; - public static bool IsWindowPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsViewPinned(hWnd.GetApplicationView()); - public static bool IsApplicationPinned(IntPtr hWnd) => VirtualDesktopPinnedApps.IsAppIdPinned(GetAppId(hWnd)); - - private static WindowsVirtualDesktopAPI.IApplicationView GetApplicationView(this IntPtr hWnd) + private static IWindowsVirtualDesktopManager _instance; + public static IWindowsVirtualDesktopManager GetInstance() { - ApplicationViewCollection.GetViewForHwnd(hWnd, out WindowsVirtualDesktopAPI.IApplicationView view); - return view; - } - - private static string GetAppId(IntPtr hWnd) - { - hWnd.GetApplicationView().GetAppUserModelId(out string appId); - return appId; - } - - static WindowsVirtualDesktopManager() - { - var shell = (WindowsVirtualDesktopAPI.IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_IMMERSIVESHELL)); - VirtualDesktopManagerPrivate = (WindowsVirtualDesktopAPI.IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGER)); - ApplicationViewCollection = (WindowsVirtualDesktopAPI.IApplicationViewCollection)shell.QueryService(typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID, typeof(WindowsVirtualDesktopAPI.IApplicationViewCollection).GUID); - VirtualDesktopManagerInternal = (WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPMANAGERINTERNAL, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopManagerInternal).GUID); - VirtualDesktopPinnedApps = (WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps)shell.QueryService(WindowsVirtualDesktopAPI.CLSID_VIRTUALDESKTOPPINNEDAPPS, typeof(WindowsVirtualDesktopAPI.IVirtualDesktopPinnedApps).GUID); - } - - public static WindowsVirtualDesktopAPI.IVirtualDesktop GetDesktop(int index) - { - int count = VirtualDesktopManagerInternal.GetCount(); - if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); - WindowsVirtualDesktopAPI.IObjectArray desktops; - VirtualDesktopManagerInternal.GetDesktops(out desktops); - object objdesktop; - desktops.GetAt(index, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out objdesktop); - Marshal.ReleaseComObject(desktops); - return (WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop; - } - - public static int GetDesktopIndex(WindowsVirtualDesktopAPI.IVirtualDesktop desktop) - { - int index = -1; - Guid IdSearch = desktop.GetId(); - VirtualDesktopManagerInternal.GetDesktops(out WindowsVirtualDesktopAPI.IObjectArray desktops); - for (int i = 0; i < VirtualDesktopManagerInternal.GetCount(); i++) + if (WindowsVirtualDesktopManager._instance == null) { - desktops.GetAt(i, typeof(WindowsVirtualDesktopAPI.IVirtualDesktop).GUID, out object objdesktop); - if (IdSearch.CompareTo(((WindowsVirtualDesktopAPI.IVirtualDesktop)objdesktop).GetId()) == 0) - { - index = i; - break; - } + if (Program.WindowsVersion.IsWin11()) + _instance = new Switchie.VirtualDesktopAPI.Win11.WindowsVirtualDesktopManager(); + else if (Program.WindowsVersion.IsWin10()) + _instance = new Switchie.VirtualDesktopAPI.Win10.WindowsVirtualDesktopManager(); + else if (Program.WindowsVersion.IsWin10LTSC()) + _instance = new Switchie.VirtualDesktopAPI.Win10LTSC.WindowsVirtualDesktopManager(); + else + throw new PlatformNotSupportedException(); } - Marshal.ReleaseComObject(desktops); - return index; - } - - public static WindowsVirtualDesktop FromWindow(IntPtr hWnd) - { - Guid id = VirtualDesktopManagerPrivate.GetWindowDesktopId(hWnd); - if (id != Guid.Empty) return new WindowsVirtualDesktop(VirtualDesktopManagerInternal.FindDesktop(ref id)); - return null; - } - - public static void PinApplication(IntPtr hWnd) - { - string appId = GetAppId(hWnd); - if (!VirtualDesktopPinnedApps.IsAppIdPinned(appId)) - VirtualDesktopPinnedApps.PinAppID(appId); + return WindowsVirtualDesktopManager._instance; } } diff --git a/src/Core/WindowManager.cs b/src/Core/WindowManager.cs index f9dd999..5ecd784 100644 --- a/src/Core/WindowManager.cs +++ b/src/Core/WindowManager.cs @@ -35,8 +35,9 @@ public static List GetOpenWindows() WinAPI.RECT rct = new WinAPI.RECT(); WinAPI.GetWindowRect(hWnd, ref rct); + int index = 0; WinAPI.GetWindowThreadProcessId(hWnd, out uint pid); - int index = WindowsVirtualDesktopManager.FromDesktop(WindowsVirtualDesktopManager.FromWindow((IntPtr)hWnd)); + try { index = WindowsVirtualDesktopManager.GetInstance().FromDesktop(WindowsVirtualDesktopManager.GetInstance().FromWindow((IntPtr)hWnd)); } catch { } int hIcon = WinAPI.SendMessage(hWnd, WinAPI.WM_GETICON, WinAPI.ICON_SMALL2, 0); if (hIcon == 0) { hIcon = WinAPI.GetClassLongPtr(hWnd, WinAPI.GCL_HICON); } diff --git a/src/Core/WindowsVersion.cs b/src/Core/WindowsVersion.cs new file mode 100644 index 0000000..89b80a5 --- /dev/null +++ b/src/Core/WindowsVersion.cs @@ -0,0 +1,29 @@ +namespace Switchie +{ + + public class WindowsVersion + { + public int Major { get; set; } + public int Minor { get; set; } + public int Build { get; set; } + public string Name { get; set; } + + public WindowsVersion() + { + Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + Major = int.Parse(registryKey.GetValue("CurrentMajorVersionNumber").ToString()); + Minor = int.Parse(registryKey.GetValue("CurrentMinorVersionNumber").ToString()); + Build = int.Parse(registryKey.GetValue("CurrentBuildNumber").ToString()); + Name = registryKey.GetValue("DisplayVersion", string.Empty).ToString().ToUpperInvariant().Trim(); + } + + // Windows version detection could improve, but I think this works, tested on: + // Microsoft Windows [Version 10.0.22000.282] (Windows 11) + // Microsoft Windows [Version 10.0.19043.1288] (Windows 10) + // Microsoft Windows [Version 10.0.17763.2237] (Windows 10 LTSC) + public bool IsWin11() => Major == 10 && Minor == 0 && Build >= 22000 && Name == "21H2"; + public bool IsWin10() => Major == 10 && Minor == 0 && Build > 17763 && Build < 22000; + public bool IsWin10LTSC() => Major == 10 && Minor == 0 && Build <= 17763; + } + +} \ No newline at end of file diff --git a/src/GUI/MainForm.cs b/src/GUI/MainForm.cs index b92eebf..b93fb2d 100644 --- a/src/GUI/MainForm.cs +++ b/src/GUI/MainForm.cs @@ -46,7 +46,7 @@ public MainForm() Name = "frmMain"; TopMost = true; Icon = new System.Drawing.Icon(new MemoryStream(Helpers.GetResourceFromAssembly(typeof(Program), "Switchie.Resources.icon.ico"))); - Enumerable.Range(0, WindowsVirtualDesktop.Count).ToList().ForEach(x => + Enumerable.Range(0, WindowsVirtualDesktop.GetInstance().Count).ToList().ForEach(x => { VirtualDesktop desktop = new VirtualDesktop(x, this, new Point(_virtualDesktops.Sum(y => y.Size.Width), 0)); MouseUp += desktop.OnMouseUp; @@ -70,7 +70,7 @@ public MainForm() private void OnShown(object sender, EventArgs e) { - WindowsVirtualDesktopManager.PinApplication(Handle); + WindowsVirtualDesktopManager.GetInstance().PinApplication(Handle); new TaskFactory().StartNew(async () => { while (!Program.ApplicationClosing.IsCancellationRequested) @@ -82,7 +82,7 @@ private void OnShown(object sender, EventArgs e) if (_forceAlwaysOnTop) WindowManager.SetAlwaysOnTop(Handle, _forceAlwaysOnTop); Windows = new ConcurrentBag(WindowManager.GetOpenWindows()); - var hash = $"{Windows.Sum(x => Math.Abs(x.Dimensions.X))}{Windows.Sum(x => Math.Abs(x.Dimensions.Y))}{Windows.Sum(x => x.Dimensions.Width)}{Windows.Sum(x => x.Dimensions.Height)}{Windows.Sum(x => x.IsActive ? 1 : 0)}{Windows.Sum(x => x.VirtualDesktopIndex)}"; + var hash = $"{Windows.Sum(x => Math.Abs(x.Dimensions.X))}{Windows.Sum(x => Math.Abs(x.Dimensions.Y))}{Windows.Sum(x => x.Dimensions.Width)}{Windows.Sum(x => x.Dimensions.Height)}{string.Join("", Windows.Select(x => x.IsActive ? 1 : 0))}{string.Join("", Windows.Select(x => x.VirtualDesktopIndex))}"; if (hash != _windowsHash) { _windowsHash = hash; @@ -94,6 +94,18 @@ private void OnShown(object sender, EventArgs e) await Task.Delay(1); } }); + new TaskFactory().StartNew(async () => + { + while (!Program.ApplicationClosing.IsCancellationRequested) + { + Invoke(new Action(() => + { + try { Invalidate(); } + catch { } + })); + await Task.Delay(100); + } + }); } private void OnMouseUp(object sender, MouseEventArgs e) diff --git a/src/GUI/VirtualDesktop.cs b/src/GUI/VirtualDesktop.cs index 2e4fcbe..bcd1d12 100644 --- a/src/GUI/VirtualDesktop.cs +++ b/src/GUI/VirtualDesktop.cs @@ -12,7 +12,7 @@ public class VirtualDesktop public Size Size { get; set; } public Point Location { get; set; } public int VirtualDesktopIndex { get; set; } - public bool IsCurrentActiveDesktop { get => WindowsVirtualDesktopManager.FromDesktop(WindowsVirtualDesktop.Current) == VirtualDesktopIndex; } + public bool IsCurrentActiveDesktop { get => WindowsVirtualDesktopManager.GetInstance().FromDesktop(WindowsVirtualDesktop.GetInstance().Current) == VirtualDesktopIndex; } private DragDropData _dragDropData; private Rectangle dragBoxFromMouseDown; @@ -64,7 +64,7 @@ public void OnMouseUp(object sender, MouseEventArgs e) if (!IsInsideBounds(e.X, e.Y)) return; if ((e.Button & MouseButtons.Left) == MouseButtons.Left) { - WindowsVirtualDesktop.FromIndex(VirtualDesktopIndex).MakeVisible(); + WindowsVirtualDesktop.GetInstance().FromIndex(VirtualDesktopIndex).MakeVisible(); Form.Invalidate(); } } @@ -106,7 +106,7 @@ public void OnDragDrop(object sender, DragEventArgs e) var ddd = (DragDropData)e.Data.GetData(typeof(DragDropData)); if (e.Effect == DragDropEffects.Move) { - WindowsVirtualDesktop.FromIndex(VirtualDesktopIndex).MoveWindow(ddd.DraggedWindow.Handle); + WindowsVirtualDesktop.GetInstance().FromIndex(VirtualDesktopIndex).MoveWindow(ddd.DraggedWindow.Handle); Form.Invalidate(); } } diff --git a/src/Program.cs b/src/Program.cs index 5446709..40889c7 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -7,6 +7,7 @@ namespace Switchie static class Program { public static CancellationToken ApplicationClosing = new CancellationToken(); + public static WindowsVersion WindowsVersion = new WindowsVersion(); [STAThread] static void Main()