将其他进程的窗口移动到另一个虚拟桌面

Cai*_*Cai 5 c# c++ virtual-desktop windows-10

所以我在Windows 10下实现了类似win-tab的界面.我试图将其他进程的窗口移动到另一个虚拟桌面.使用此问题的 API,我已经可以将自己的应用程序移动到任何桌面.但是当我在调用MoveWindowToDesktop(IntPtr TopLevelWindow,Guid CurrentDesktop)时移动其他窗口时,我得到了E_ACCESSDENIED作为返回码.在这个Github项目中,有人设法将DLL挂钩到其他进程,因此用户可以成功触发此函数.

我怎样才能做到这一点?

ray*_*nnz 0

这可以使用 com 来实现VirtualDesktopManagerInternal

该对象及其依赖对象具有不同的 CLSID,具体取决于 Windows 的构建版本。

这里的示例代码被高度精简,只够在 Windows build 22000 上运行(在我的例子中,在 Windows 11 上测试它工作正常)。

您可以在这里看到一个非常详细的 .NET 库,它可以处理具有虚拟桌面的所有 Windows 版本: github VirtualDesktop

无论如何,这是在 Windows 11 上经过测试并运行的最少代码。

COM 导入部分:

static Guid CLSID_VirtualDesktopManagerInternal = new Guid("c5e0cdca-7b6e-41b2-9fc4-d93975cc467b");
static Guid CLSID_IVirtualDesktopManagerInternal = new Guid("b2f925b9-5a0f-4d2e-9f4d-2b1507593c10"); //windows version 22000
static Guid CLSID_ImmersiveShell = new Guid("C2F03A33-21F5-47FA-B4BB-156362A2F239");

[ComImport]
[Guid("372e1d3b-38d3-42e4-a15b-8ab2b178f513")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IApplicationView { }
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
internal interface IServiceProvider10 { [return: MarshalAs(UnmanagedType.IUnknown)] object QueryService(ref Guid service, ref Guid riid); }
[ComImport]
[Guid("92ca9dcd-5622-4bba-a805-5e9f541bd8c9")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IObjectArray { uint GetCount(); [return: MarshalAs(UnmanagedType.Interface)] object GetAt(uint iIndex, in Guid riid); }
[ComImport]
[Guid("536d3495-b208-4cc9-ae26-de8111275bf8")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IVirtualDesktop { Guid GetID(); }
[ComImport]
[Guid("1841c6d7-4f9d-42c0-af41-8747538f10e5")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IApplicationViewCollection { IObjectArray GetViews(); IObjectArray GetViewsByZOrder(); IObjectArray GetViewsByAppUserModelId(string id); IApplicationView GetViewForHwnd(IntPtr hwnd); }
//windows 22000
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("b2f925b9-5a0f-4d2e-9f4d-2b1507593c10")]
[System.Security.SuppressUnmanagedCodeSecurity]
public interface IVirtualDesktopManagerInternal { int GetCount(IntPtr hWndOrMon); void MoveViewToDesktop(IApplicationView pView, IVirtualDesktop desktop); bool CanViewMoveDesktops(IApplicationView pView); IVirtualDesktop GetCurrentDesktop(IntPtr hWndOrMon); IObjectArray GetDesktops(IntPtr hWndOrMon); IVirtualDesktop GetAdjacentDesktop(IVirtualDesktop pDesktopReference, int uDirection); void SwitchDesktop(IntPtr hWndOrMon, IVirtualDesktop desktop); IVirtualDesktop CreateDesktop(IntPtr hWndOrMon); void MoveDesktop(IVirtualDesktop desktop, IntPtr hWndOrMon, int nIndex); void RemoveDesktop(IVirtualDesktop pRemove, IVirtualDesktop pFallbackDesktop); IVirtualDesktop FindDesktop(in Guid desktopId); }
Run Code Online (Sandbox Code Playgroud)

要放入您的方法中的代码:

IServiceProvider10 shell = (IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_ImmersiveShell));
IVirtualDesktopManagerInternal managerInternal = (IVirtualDesktopManagerInternal)shell.QueryService(CLSID_VirtualDesktopManagerInternal, CLSID_IVirtualDesktopManagerInternal);
int numberOfDesktops = managerInternal.GetCount(IntPtr.Zero);
IApplicationViewCollection applicationViewCollection = (IApplicationViewCollection)shell.QueryService(CLSID_IApplicationViewCollection, CLSID_IApplicationViewCollection);
            
//window you want to move
IntPtr hwnd = PutHwndOfTheWindowYouWantToMoveHere;
IApplicationView applicationView = applicationViewCollection.GetViewForHwnd(hwnd);

//virtual desktop you want to move to, in this example the desktop at index 0
uint virtualDesktopIndex = 0; //index of the virtual desktop you want ot move the window into
IObjectArray allDesktops = managerInternal.GetDesktops(IntPtr.Zero);
IVirtualDesktop firstVVD = (IVirtualDesktop)allDesktops.GetAt(virtualDesktopIndex, typeof(IVirtualDesktop).GUID);

//the move function
managerInternal.MoveViewToDesktop(applicationView, firstVVD);
Run Code Online (Sandbox Code Playgroud)