我喜欢Windows现在有内置的虚拟桌面,但我有一些function,我想添加/修改。 (强制在所有桌面上显示一个窗口,使用热键启动任务视图,拥有每个监视器桌面等)
我已经search了应用程序和开发人员参考,以帮助我自定义我的桌面,但没有运气。
有什么想法,我应该开始?
在Windows XP中的符号链接
如何在进程死于Windows之前做些事情
如何获得初始分配调用VirtualAlloc中保留的区域大小
我不希望控制台出现在我运行c + +程序
将选定的列表框(绑定)项目保存到c#中的数组
如何开始编写DDK代码?
如何在Ruby on Windows上获取文件创build时间?
如何在Windows 8中安装瓢虫的android?
如何在C ++的窗口中获得用户的最大进程数
Windows 10崩溃Whodunit
对虚拟桌面功能的编程访问非常有限,微软只公开了IVirtualDesktopManager COM接口。 还不足以完成任何有用的事情。 我已经写了一些基于NickoTin完成的逆向工程工作的C#代码。 在他的博客文章中我读不了任何俄文,但他的C ++代码是相当准确的。
我需要强调的是,这个代码不是你想要在产品中承诺的东西。 微软总是觉得可以随时更改无证apis,只要他们觉得。 而且存在运行时风险,当用户修改虚拟桌面时,这些代码并不一定会交互良好。 请务必记住,虚拟桌面可以随时出现和消失,与您的代码完全不同步。
创建一个新的C#类库项目。 我将首先发布ComInterop.cs,它包含匹配NickoTin的C ++声明的COM接口声明:
using System; using System.Runtime.InteropServices; namespace Windows10Interop { internal static class Guids { public static readonly Guid CLSID_ImmersiveShell = new Guid(0xC2F03A33,0x21F5,0x47FA,0xB4,0xBB,0x15,0x63,0x62,0xA2,0xF2,0x39); public static readonly Guid CLSID_VirtualDesktopManagerInternal = new Guid(0xC5E0CDCA,0x7B6E,0x41B2,0x9F,0xC4,0xD9,0x39,0x75,0xCC,0x46,0x7B); public static readonly Guid CLSID_VirtualDesktopManager = new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A"); public static readonly Guid IID_IVirtualDesktopManagerInternal = new Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5"); public static readonly Guid IID_IVirtualDesktop = new Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4"); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnkNown)] [Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")] internal interface IVirtualDesktop { void notimpl1(); // void IsViewVisible(IApplicationView view,out int visible); Guid GetId(); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnkNown)] [Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5")] internal interface IVirtualDesktopManagerInternal { int GetCount(); void notimpl1(); // void MoveViewToDesktop(IApplicationView view,IVirtualDesktop desktop); void notimpl2(); // void CanViewMoveDesktops(IApplicationView view,out int itcan); 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")] internal interface IVirtualDesktopManager { int IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow); Guid GetwindowDesktopId(IntPtr topLevelWindow); void MoveWindowToDesktop(IntPtr topLevelWindow,ref Guid desktopId); } [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnkNown)] [Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")] internal 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("6D5140C1-7436-11CE-8034-00AA006009FA")] internal interface IServiceProvider10 { [return: MarshalAs(UnmanagedType.IUnkNown)] object QueryService(ref Guid service,ref Guid riid); } }
接下来是Desktop.cs,它包含您可以在代码中使用的友好的C#类:
using System; using System.Runtime.InteropServices; namespace Windows10Interop { public class Desktop { public static int Count { // Returns the number of desktops get { return DesktopManager.Manager.GetCount(); } } public static Desktop Current { // Returns current desktop get { return new Desktop(DesktopManager.Manager.GetCurrentDesktop()); } } public static Desktop FromIndex(int index) { // Create desktop object from index 0..Count-1 return new Desktop(DesktopManager.GetDesktop(index)); } public static Desktop FromWindow(IntPtr hWnd) { // Creates desktop object on which window <hWnd> is displayed Guid id = DesktopManager.WManager.GetwindowDesktopId(hWnd); return new Desktop(DesktopManager.Manager.FindDesktop(ref id)); } public static Desktop Create() { // Create a new desktop return new Desktop(DesktopManager.Manager.CreateDesktop()); } public void Remove(Desktop fallback = null) { // Destroy desktop and switch to <fallback> var back = fallback == null ? DesktopManager.GetDesktop(0) : fallback.itf; DesktopManager.Manager.RemoveDesktop(itf,back); } public bool IsVisible { // Returns <true> if this desktop is the current displayed one get { return object.ReferenceEquals(itf,DesktopManager.Manager.GetCurrentDesktop()); } } public void MakeVisible() { // Make this desktop visible DesktopManager.Manager.SwitchDesktop(itf); } public Desktop Left { // Returns desktop at the left of this one,null if none get { IVirtualDesktop desktop; int hr = DesktopManager.Manager.GetAdjacentDesktop(itf,3,out desktop); if (hr == 0) return new Desktop(desktop); else return null; } } public Desktop Right { // Returns desktop at the right of this one,4,out desktop); if (hr == 0) return new Desktop(desktop); else return null; } } public void MoveWindow(IntPtr handle) { // Move window <handle> to this desktop DesktopManager.WManager.MoveWindowToDesktop(handle,itf.GetId()); } public bool HasWindow(IntPtr handle) { // Returns true if window <handle> is on this desktop return itf.GetId() == DesktopManager.WManager.GetwindowDesktopId(handle); } public override int GetHashCode() { return itf.GetHashCode(); } public override bool Equals(object obj) { var desk = obj as Desktop; return desk != null && object.ReferenceEquals(this.itf,desk.itf); } private IVirtualDesktop itf; private Desktop(IVirtualDesktop itf) { this.itf = itf; } } internal static class DesktopManager { static DesktopManager() { var shell = (IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell)); Manager = (IVirtualDesktopManagerInternal)shell.QueryService(Guids.CLSID_VirtualDesktopManagerInternal,Guids.IID_IVirtualDesktopManagerInternal); WManager = (IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager)); } internal static IVirtualDesktop GetDesktop(int index) { int count = Manager.GetCount(); if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index"); IObjectArray desktops; Manager.GetDesktops(out desktops); object objdesk; desktops.GetAt(index,Guids.IID_IVirtualDesktop,out objdesk); Marshal.ReleaseComObject(desktops); return (IVirtualDesktop)objdesk; } internal static IVirtualDesktopManagerInternal Manager; internal static IVirtualDesktopManager WManager; } }
最后,我用一个测试Winforms项目来测试代码。 只需在表单上放置4个按钮并将其命名为buttonLeft / Right / Create / Destroy:
using Windows10Interop; using System.Diagnostics; ... public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void buttonRight_Click(object sender,EventArgs e) { var curr = Desktop.FromWindow(this.Handle); Debug.Assert(curr.Equals(Desktop.Current)); var right = curr.Right; if (right == null) right = Desktop.FromIndex(0); if (right != null) { right.MoveWindow(this.Handle); right.MakeVisible(); this.BringToFront(); Debug.Assert(right.IsVisible); } } private void buttonLeft_Click(object sender,EventArgs e) { var curr = Desktop.FromWindow(this.Handle); Debug.Assert(curr.Equals(Desktop.Current)); var left = curr.Left; if (left == null) left = Desktop.FromIndex(Desktop.Count - 1); if (left != null) { left.MoveWindow(this.Handle); left.MakeVisible(); this.BringToFront(); Debug.Assert(left.IsVisible); } } private void buttonCreate_Click(object sender,EventArgs e) { var desk = Desktop.Create(); desk.MoveWindow(this.Handle); desk.MakeVisible(); Debug.Assert(desk.IsVisible); Debug.Assert(desk.Equals(Desktop.Current)); } private void buttonDestroy_Click(object sender,EventArgs e) { var curr = Desktop.FromWindow(this.Handle); var next = curr.Left; if (next == null) next = curr.Right; if (next != null && next != curr) { next.MoveWindow(this.Handle); curr.Remove(next); Debug.Assert(next.IsVisible); } } }
我在测试时注意到的唯一真正的怪癖是,当您首先切换桌面时,将窗口从一个桌面移动到另一个桌面可以将其移动到Z顺序的底部,然后移动窗口。 没有这样的问题,如果你反其道而行之。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。