Windows 10的虚拟桌面

  • 简介
  • 使用虚拟桌面的快捷键
  • IVirtualDesktopManager接口
  • Windows Desktop API
  • 总结
  • 注脚

简介

Windows 10发布后,Windows系统外壳终于内置了虚拟桌面功能。虽然该功能有些跟随Mac多重桌面的嫌疑,但它的确极大方便了桌面组织。

首先,本文将介绍一些使用虚拟桌面的快捷键。然后,讨论使用IVirtualDesktopManager接口,在C#里实现追随虚拟桌面的代码。最后,谈谈Windows 10虚拟桌面和Windows Desktop API的区别。

使用虚拟桌面的快捷键

新建桌面:Ctrl+Win + D
删除桌面:Ctrl+Win + F4
上个桌面:Ctrl+Win + <-
下个桌面:Ctrl+Win + ->

如果记不清快捷键也没关系,可以用Win+Tab还呼出桌面管理视图。或者,用鼠标点击任务栏上的“任务视图”图标:

出现桌面管理视图后,用鼠标新建,删除,切换,以及移动窗口到其他桌面。

IVirtualDesktopManager接口

Windows SDK Support Team博客中,有一篇Chris Lewis1的文章《Virtual Desktop Switching in Windows 10》。它介绍了如何在C#里利用Windows Shell的VirtualDeskTopManager2,以及它的COM接口IVirtualDeskTopManager3来将当前窗口移动到活跃桌面的方法。这里给出简单的c#实现。

首先,在Visual Studio中新建一个WinForm项目,选用DotNet Framework4.0或以上都可以。
然后,在Form1.cs文件中,Form1类的后面,贴入如下COM调用声明:

    public partial class Form1 : Form{//...}[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")][System.Security.SuppressUnmanagedCodeSecurity]public interface IVirtualDesktopManager{bool IsWindowOnCurrentVirtualDesktop([In] IntPtr TopLevelWindow);Guid GetWindowDesktopId([In] IntPtr TopLevelWindow);void MoveWindowToDesktop([In] IntPtr TopLevelWindow, ref Guid CurrentDesktop);}[ComImport, Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")]public class CVirtualDesktopManager{}

接口和COM class的GUID可以在Shobjidl.h头文件中找到。
使用IVirtualDesktopManager接口,我们可以

  1. 判断是否当前窗口位于活动桌面上,
  2. 获取某个顶级窗口所在桌面的桌面标志,
  3. 将某个顶级窗口移动到目标桌面上。

在Form1的构造函数下,我们启用一个定时器。定时器每一秒将检查是否当前窗口位于活动桌面下。
如果用户切换到另外一个虚拟桌面,我们将尝试获取该活动虚拟桌面的标志,并将当前窗口移动到活动桌面下。

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;namespace WindowsFormsApp1
{public partial class Form1 : Form{public Form1(){InitializeComponent();this.timer.Tick += delegate{if (!virtualDesktopManager.IsWindowOnCurrentVirtualDesktop(this.Handle)) // 如果当前窗口不在活动桌面(Active Desktop)下{Guid activeVirtualDesktop;using (var form = new Form() { Size = new Size(50, 50), Location = new Point(-100, -100) }){form.Show(null); // 创建一个‘隐藏窗口’,该窗口将默认显示在活动桌面下。activeVirtualDesktop = virtualDesktopManager.GetWindowDesktopId(form.Handle); // 获取该‘隐藏窗口’的桌面标志this.Text = activeVirtualDesktop.ToString();}if (activeVirtualDesktop != Guid.Empty){virtualDesktopManager.MoveWindowToDesktop(this.Handle, ref activeVirtualDesktop); // 将当前窗口移动到活动桌面下。}}};try{virtualDesktopManager = new CVirtualDesktopManager() as IVirtualDesktopManager;this.timer.Start(); // 如果virtualDesktopManager顺利创建,开始定时器}catch{ }}readonly IVirtualDesktopManager virtualDesktopManager;readonly Timer timer = new Timer() { Interval = 1000 };}[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")][System.Security.SuppressUnmanagedCodeSecurity]public interface IVirtualDesktopManager{bool IsWindowOnCurrentVirtualDesktop([In] IntPtr TopLevelWindow);Guid GetWindowDesktopId([In] IntPtr TopLevelWindow);void MoveWindowToDesktop([In] IntPtr TopLevelWindow, ref Guid CurrentDesktop);}[ComImport, Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")]public class CVirtualDesktopManager{}
}

编译成功后,运行。用快捷键或“任务视图图标”创建新的虚拟桌面。约一秒内,测试窗口将自动移到当下的虚拟桌面中。

Windows Desktop API

在回答“曹同学”的帖子4《c#的windows服务程序中调用dll(c++编写),在dll中调用了一个exe外部文件》中,我简单地介绍了Windows系统的Session,WindowStation和Desktop的关系。

但是,我的回答中有错误的地方。实际上Windows 10里的快速虚拟桌面,不等于传统Win32 API里的Desktop。Windows 10里的快速虚拟桌面,不是用User32里的CreateDesktop API5实现的。要实现传统意义上的User32 Desktop创建和切换,有兴趣的朋友,可以下载和运行Mark Russinovich的Desktop.exe工具6

这里我给出了检查当前程序的会话ID,当前WindowStation和当前Win32桌面名字的C#实现:

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;static class Program
{static void Main(){var hWINSTA = GetProcessWindowStation();var stationName = GetUserObjectName(hWINSTA); // WinSta0var hDESK = GetThreadDesktop(GetCurrentThreadId());var desktopName = GetUserObjectName(hDESK); // Defaultvar currentTime = DateTime.Now.ToString("s");var sessionId = Process.GetCurrentProcess().SessionId;var detail = $"[{currentTime}] 会话:{sessionId}, 当前用户:{Environment.UserName}, Station:{stationName}, 桌面:{desktopName}";Console.WriteLine(detail);if (File.Exists(@"c:\temp\log.txt")){File.AppendAllLines(@"c:\temp\log.txt", new[] { detail }); // 写文件里。当该程序在Windows服务中调用时,方便检查。}}static string GetUserObjectName(IntPtr hObject){const int UOI_NAME = 2;var bufferLength = 128;var buffer = new byte[bufferLength];if (!GetUserObjectInformationW(hObject, UOI_NAME, buffer, bufferLength, ref bufferLength)){throw new Win32Exception();}return Encoding.Unicode.GetString(buffer, 0, bufferLength).TrimEnd('\0');}[DllImport("User32", SetLastError = true)]extern static bool GetUserObjectInformationW(IntPtr hObj, int nIndex, byte[] pvInfo, int nLength, ref int lpnLengthNeeded);[DllImport("User32", SetLastError = true)]extern static IntPtr GetProcessWindowStation();[DllImport("User32", SetLastError = true)]extern static IntPtr GetThreadDesktop(int dwThreadId);[DllImport("Kernel32", SetLastError = true)]extern static int GetCurrentThreadId();
}

当该程序在Windows 10的虚拟桌面下运行时,将汇报当前桌面名字为’Default’。
如果用Russinovich的Desktop.exe工具,切换Win32桌面,那么该程序将汇报桌面名字为’SysInternals Desktop 1‘等等。

Win32的Desktop的隔离性比Windows 10的虚拟桌面强。Win32的Desktop界定了Windows消息,菜单,和钩子的范围7。也就是说,SendMessage和PostMessage不能跨越Win32 Desktop。Windows相关的钩子,也只能在当前Win32 Desktop内有效。

我大胆猜测这也是Windows 10的虚拟桌面不采用Win32 Desktop实现的原因。

总结

本文简单介绍了Windows 10的新功能“虚拟桌面”。并解释了它没有采用传统的Win32 Desktop实现。它的实现是基于Windows Shell新增的IVirtualDeskTopManager接口。

注脚


  1. https://blogs.msdn.microsoft.com/winsdk/2015/09/10/virtual-desktop-switching-in-windows-10/ ↩︎

  2. https://docs.microsoft.com/en-us/windows/win32/shell/virtualdesktopmanager ↩︎

  3. https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ivirtualdesktopmanager ↩︎

  4. https://bbs.csdn.net/topics/395462438 ↩︎

  5. https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-createdesktopa ↩︎

  6. https://docs.microsoft.com/en-us/sysinternals/downloads/desktops ↩︎

  7. https://docs.microsoft.com/en-us/windows/win32/winstation/desktops ↩︎

Windows 10的虚拟桌面相关推荐

  1. 怎样取消Windows 10的虚拟桌面切换动画和窗口动画

    怎样取消Windows 10的虚拟桌面切换动画和窗口动画 对于晕3D的人来说这是真的要命. 步骤: 在"这台电脑"上点击右键(如bai何在Win10桌面上显示"du这台电 ...

  2. windows虚拟桌面_在Windows中使用虚拟桌面的最佳免费程序

    windows虚拟桌面 If you often open a lot of applications at once, a virtual desktop program can help you ...

  3. NVIDIA GRID 和 NICE DCV 技术用于实现 Linux 和 Windows® 图形加速虚拟桌面

    NVIDIA GRID 和 NICE DCV 技术用于实现 Linux 和 Windows® 图形加速虚拟桌面. NICE DCV: 满足 LINUX 和 WINDOWS 的远程 3D 通过 NICE ...

  4. 桌面图标设计里的计算机是灰色的,小技巧教您如何将Windows 10上的桌面图标设置中的回收站为灰色!...

    如果Windows 10的``桌面图标设置''窗口中的``回收站''选项显示为灰色,则可以查看本逐步指南以解决问题.这将帮助您取回"桌面图标设置"面板中的"回收站&quo ...

  5. 如何使用python获取Windows 10精美的桌面壁纸

    Windows 10界面UI相较于Windows 7做了很多优化,个人最喜欢的就是隔几天自动更新一次的锁屏壁纸.每一张看起来都是大师所做,非常精美.看到打动自已的壁纸,往往想要收藏起来,自定义成桌面壁 ...

  6. Windows 10打开远程桌面的方法

    今天使用windows 10,想要用远程桌面连接,可是怎么都找不到,哎,win10相比于win7和XP系统,感觉还是有点使用不习惯.不过后来还是找到了两个方法,在此记录下来,分享给需要的朋友. 1. ...

  7. Windows 10 开机进入桌面没有任何图标,闪屏系统自动重启explorer.exe,调不出任务管理器

    环境: 电脑:联想台式电脑 操作系统:Windows 10 专业版 64位 问题描述: 开机进入桌面没有图标,闪屏系统自动重启explorer.exe,点击开始没反应,调不出任务管理器,进入安全模式也 ...

  8. Windows 10 企业版远程桌面连接CredSSP 加密数据库修正问题解决

    Win10企业版远程桌面连接报错如下: 解决方案 1.新建文件复制下面内容命名.bat右键使用管理员身份运行 @echo offpushd "%~dp0"dir /b C:\Win ...

  9. Windows 10修改远程桌面的端口以及防火墙设置

    Windows系统自带了远程桌面连接[Win+R 运行,输入mstsc 打开],也非常好用,系统自带远程服务默认端口是[3389],但可能会担心他人恶意连接不安全或遇到端口被占用的问题(如想内网映射到 ...

最新文章

  1. Windows下curl使用
  2. 2017云计算及工业物联网论坛即将于广州开幕
  3. 2021年河北高考成绩位次怎么查询,2021年河北高考一分一段表查询排名方法 成绩排名位次什么时候公布...
  4. php数据库表怎么删除,php删除数据库表的方法
  5. boost::filesystem模块实现打印window属性的测试程序
  6. PHP数组推入弹出的函数:头进头出array_unshift/array_shift 尾进尾出array_push/array_pop
  7. css固定gridview的表头
  8. Cmake:linux中cmake添加动态库
  9. 【BZOJ 1566】 1566: [NOI2009]管道取珠 (DP)
  10. java中线程的6种状态
  11. axure实现搜索功能_vue实现模糊搜索功能
  12. 【转】C++中#include包含头文件带 .h 和不带 .h 的区别
  13. 大佬!莫言获颁第13个荣誉博士学位
  14. java地球_java – 应用地球纹理地图的球体
  15. 转:程序员最值得关注的10个C开源项目
  16. tapestry mysql_tapestry与mybatis模块的结合
  17. 初中语文古诗词作者生平归纳
  18. Debian11 更换软件源
  19. ROS TF2 中的 四元数 基础部分
  20. 由FREENOS看去

热门文章

  1. 辨别亦真亦假的Svchost.exe
  2. CVPR‘21 | 真·内卷!involution:超越convolution和self-attention的神经网络新算子
  3. aero peek_如何在Windows中禁用Aero Peek
  4. 怎么把计算机里隐藏的文件显示,怎么把隐藏的文件夹显示出来 多种方法介绍【图文教程】...
  5. 2022汽车驾驶员(初级)考试模拟100题及模拟考试
  6. vTPM环境部署(ubuntu)
  7. c 当前程序的语言,c语言实现获取macos当前的系统语言
  8. 文件管理系统FastDFS详解
  9. 苹果iPad2充不上电的问题
  10. 联想小新笔记本充不上电——客服提供的处理办法(已解决)