关于 DesktopManager Windows Verification
DesktopManager 是面向 Windows 桌面操作的工具集,提供 .NET 库、PowerShell 模块、CLI、MCP 服务和托盘应用。其 MCP 服务面向 Agent 自动化,采用先检查、再通过显式会话执行更改的安全模式。
主要功能
- 01查询和调整显示器与窗口布局
- 02管理壁纸、亮度和桌面配置文件
- 03查看音频、电源、会话与无线设备
- 04管理已保存的 Wi-Fi 配置文件
- 05通过共享核心提供多种操作界面
- 06MCP 自动化默认先检查
适用场景
- 01检查显示器和窗口状态
- 02保存并恢复工作站配置
- 03通过脚本或 CLI 管理桌面设置
- 04让 Agent 检查并执行桌面操作
MCP 相关
MCP 服务通过 stdio 为 Agent 提供桌面检查与自动化能力。其安全模式要求先检查,并通过显式服务器会话执行更改。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
DesktopManager - C# 库和 PowerShell 模块
DesktopManager 是一款 Windows 桌面自动化工具包,提供 .NET 库、PowerShell 模块、CLI、MCP 服务和托盘应用。
.NET 库还提供 PortableDesktopService,可在 Windows、macOS、GNOME 和 KDE Plasma 上管理当前用户的壁纸、发现显示器并诊断会话。每个适配器都会报告其功能;窗口自动化、托盘应用、CLI 和现有 PowerShell 命令仍仅支持 Windows。
使用方法和平台限制请参阅便携式桌面集成。
你也可以从 PowerShell Gallery 下载
如果你想联系我,可以通过 Twitter 或 LinkedIn 联系。
项目简介
DesktopManager 通过五种方式提供统一的 Windows 自动化核心:
- C# 库,适用于 .NET 应用程序和服务
- PowerShell 模块,适用于脚本和操作员工作流
- CLI 可执行文件,适用于终端和 JSON 自动化
- MCP 服务,适用于优先检查的 Agent 自动化
- Windows 托盘应用,适用于日常快捷键和显示器操作
它具有以下功能:
- 获取显示器信息
- 获取显示设备信息
- 获取壁纸信息
- 设置壁纸
- 获取/设置桌面背景色
- 获取/设置显示器位置
- 获取/设置窗口位置
- 获取/设置窗口状态(最小化、最大化、还原)
- 从所有显示器、单台显示器或自定义区域捕获桌面屏幕截图
- 管理显示器亮度
- 启动/停止/切换壁纸幻灯片
- 跟踪壁纸历史记录
- 调整显示器分辨率和方向
- 在虚拟桌面上移动显示器
- 保存和还原窗口布局
- 将窗口贴靠到其他显示器或在显示器之间移动
- 订阅分辨率、方向或显示变化
- 通过定期输入操作,防止非活动窗口进入休眠
- 管理窗口的保持活动会话
- 在显示器、音频、个性化设置和任务栏之间保存和还原统一的工作站配置文件
- 枚举 Core Audio 播放/采集终结点、更改音量和静音状态、设置默认角色,并监视终结点变化
- 检查电源和交互式会话状态;锁定、注销、睡眠、休眠或保持有时限的防休眠租约
- 捕获和还原个性化设置快照,并配置任务栏的可见性、位置和自动隐藏
- 通过受支持的 Windows 无线电 API 枚举、监视并显式启用或禁用 Wi-Fi、Bluetooth、移动宽带和 FM 无线电
- 列出已保存的 Windows Wi-Fi 配置文件,并连接到指定的已保存配置文件,无需扫描附近网络或公开凭据
- 检查窗口所属的虚拟桌面,并通过公开的 Windows 虚拟桌面 API 将窗口移动到已知桌面
- 通过有文档说明的 Windows 原生 API 检查和管理即插即用设备及驱动程序存储包
壁纸使用者
PowerBGInfo 等应用程序可以直接从库中读取显示器几何信息、 显示缩放比例和已登录会话用户:
using DesktopManager;
var monitors = new Monitors();
foreach (var display in monitors.GetMonitorSnapshots()) {
Console.WriteLine($"{display.Index}: {display.DeviceName}, " +
$"{display.Width} x {display.Height}, scale {display.Scale}");
}
var user = new DesktopSessionService().GetSessionUser();
Console.WriteLine(user?.AccountName ?? "Unknown");
即使调用方未启用 DPI 感知,快照也包含物理像素边界和每台显示器的 DPI。 调用线程的 DPI 上下文会被还原。索引描述当前显示拓扑;扩展坞连接或重新连接后,请重新读取。 会话主机上缺失的壁纸设备路径会予以保留。
Monitors.SetLogonWallpaperWithResult(imagePath) 可通过 Windows Runtime 为当前帐户设置锁屏壁纸,适用于 .NET Framework、现代 .NET 和 netstandard 使用者。结果会报告是否成功、使用的机制以及任何故障。回退到计算机策略需要显式设置 allowPolicyFallback: true 并提升权限。现有的 SetLogonWallpaper 方法仍会自动回退到策略。示例、操作系统要求、策略限制和会话部署行为请参阅 壁纸使用者 API。
桌面状态与控制
当你想在可重复使用的设置之间切换时,工作站配置文件是高级入口。它会捕获已连接显示器的模式和位置、显示器壁纸以及受支持的亮度/HDR 状态、活动音频终结点状态和默认角色、个性化设置及任务栏。应用配置文件时,会根据稳定标识匹配显示器,将显示更改集中执行,并在必需步骤失败时回滚所选部分。系统范围的个性化策略也会被捕获,但只有在明确请求时才会恢复。
Save-DesktopWorkstationProfile -Name 'office'
Get-DesktopAudioEndpoint -DataFlow Render -ActiveOnly
Get-DesktopPowerStatus
Get-DesktopSession
Get-DesktopRadio
Get-DesktopWifiProfile
Connect-DesktopWifiProfile -Name 'Corporate WiFi'
Get-DesktopDevice -Present -Problem
Get-DesktopDriverPackage
Restore-DesktopWorkstationProfile -Name 'office' -Confirm
相同的功能也可通过 CLI 使用:
desktopmanager workstation save --name office
desktopmanager audio list --flow render --active
desktopmanager system power
desktopmanager system session
desktopmanager radio list
desktopmanager wifi profiles
desktopmanager wifi connect --profile "Corporate WiFi"
desktopmanager device list --present --problem
desktopmanager driver list
desktopmanager workstation apply --name office
无线电控制有两个刻意分开的 API。RadioService 和常规的 radio list / radio set 命令使用受支持的 Windows.Devices.Radios 契约来控制单个无线电。全局飞行模式使用未公开的 Windows Shell COM 契约,因此它归属 ExperimentalAirplaneModeService,并且在 CLI 中需要 --experimental,在 PowerShell 中需要 -Experimental,在 MCP 中需要 --allow-experimental。
Wi-Fi 配置文件连接与无线电控制相互独立。WifiProfileService、Get-DesktopWifiProfile 和 desktopmanager wifi profiles 仅枚举 Windows 中已存储的配置文件。连接指定的配置文件时使用 Native Wi-Fi 配置文件 API 和 ACM 完成通知;它不会扫描附近的网络、返回 BSSID、公开配置文件 XML 或凭据,也不会查询涉及位置的当前连接详情。Windows 仍要求获得位置许可,才能扫描附近网络并使用相关的 Wi-Fi 信息 API。请参阅 Wi-Fi 访问和位置的 API 行为变更。
VirtualDesktopService 仅公开 Windows 的公共操作:检查顶层窗口是否位于当前桌面、获取其桌面 ID,以及将其移动到已知桌面 ID。桌面枚举、创建、重命名、切换和移除不会被作为受支持的 API 提供。
面向操作人员的较新 CLI 和 MCP 接口的补充文档:
- Docs/DesktopManager.Cli.md
- Docs/DesktopManager.Mcp.md
- Docs/DesktopManager.Architecture.md
- Docs/DesktopManager.DesktopState.md
- Docs/DesktopManager.DeviceManagement.md
- Docs/DesktopManager.AutomationBasics.md
- Docs/DesktopManager.Plugin.md
- .agents/skills/desktopmanager-operator/SKILL.md
- .agents/skills/desktopmanager-build/SKILL.md
应使用哪个接口?
| 接口 | 最适用于 | 典型入口 |
|---|---|---|
| C# 库 | 将 DesktopManager 嵌入你自己的 .NET 应用或服务 | DesktopManager.dll |
| PowerShell 模块 | 脚本、操作人员、管理工作流、可重复的任务自动化 | Install-Module DesktopManager |
| CLI 可执行文件 | 手动使用、Shell 自动化、JSON 输出和托管 MCP | desktopmanager.exe |
| MCP 服务 | 通过 stdio 实现由 Agent 驱动的自动化,并采用先检查再操作的安全模型 | desktopmanager mcp serve |
| Windows 托盘应用 | 日常热键、显示器绑定、HDR 控制、托盘运行时和按用户启动 | DesktopManager.App.exe |
整体架构
DesktopManager 现在采用一个共享核心,并在其上提供多个面向操作人员的界面。
flowchart LR
A["Your .NET app"] --> B["DesktopManager library"]
C["PowerShell module"] --> B
D["desktopmanager.exe CLI"] --> B
E["MCP server"] --> D
J["DesktopManager.App tray app"] --> B
B --> F["Windows desktop APIs"]
F --> G["Monitors / wallpapers / brightness"]
F --> H["Windows / controls / input"]
F --> I["Layouts / snapshots / targets"]
如需查看更完整的组件和请求流图,请参阅 Docs/DesktopManager.Architecture.md。
可以从以下角度理解其实际用法:
- 将 DesktopManager 集成到自己的应用程序中时,使用库
- 需要可脚本化的管理/操作自动化时,使用 PowerShell
- 需要面向用户或支持 JSON 的命令界面时,使用 CLI
- 需要 Agent 先检查、再通过显式服务器会话执行变更时,使用 MCP
常用入口
| 目标 | 推荐入口 |
|---|---|
| 在自己的代码中添加 DesktopManager 功能 | 引用 DesktopManager NuGet 包 |
| 从终端手动执行桌面操作 | desktopmanager.exe |
| 每天从系统托盘运行 DesktopManager | DesktopManager.App.exe 或 DesktopManager MSI |
| 在 PowerShell 脚本中使用 | DesktopManager PowerShell 模块 |
| 连接 Agent/工具层 | desktopmanager mcp serve |
| 了解整体连接方式 | Docs/DesktopManager.Architecture.md |
请求流概览
flowchart LR
A["User, script, or agent"] --> B{"Surface"}
B -->|".NET"| C["DesktopManager library"]
B -->|"PowerShell"| D["Cmdlets"]
B -->|"CLI"| E["desktopmanager.exe"]
B -->|"MCP"| F["desktopmanager mcp serve"]
B -->|"Tray app"| J["DesktopManager.App.exe"]
D --> C
E --> G["DesktopOperations"]
F --> G
J --> C
G --> C
C --> H["Win32, UI Automation, monitor, screenshot, and input services"]
重点在于,CLI、MCP 和 PowerShell 会复用相同的共享 C# 行为,以保持一致,而不是在每个界面中分别实现桌面逻辑。
可用的 PowerShell Cmdlet
| Cmdlet | 描述 |
|---|---|
| Get-DesktopMonitor | 获取显示器信息,并提供筛选选项 |
| Get-DesktopWallpaper | 获取各显示器当前壁纸路径 |
| Set-DesktopWallpaper | 从路径、URL 或流应用壁纸 |
| Get-DesktopWallpaperHistory | 列出已存储的壁纸历史记录 |
| Set-DesktopWallpaperHistory | 更新或清除壁纸历史记录文件 |
| Get-DesktopSlideshow | 检查幻灯片放映图片、状态、选项和切换间隔 |
| Set-DesktopSlideshowOptions | 更新幻灯片放映的随机播放行为和切换间隔 |
| Start-DesktopSlideshow | 在各显示器上开始播放壁纸幻灯片 |
| Stop-DesktopSlideshow | 停止当前正在运行的幻灯片放映 |
| Step-DesktopSlideshow | 将幻灯片放映向前或向后切换 |
| Get-DesktopBackgroundColor | 读取当前桌面背景颜色 |
| Set-DesktopBackgroundColor | 更改桌面背景颜色 |
| Get-DesktopBrightness | 读取显示器亮度级别 |
| Set-DesktopBrightness | 设置显示器亮度级别 |
| Set-DesktopPosition | 移动显示器的左上角坐标,且不更改分辨率 |
| Set-DesktopResolution | 更改显示器分辨率或方向 |
| Set-DefaultAudioDevice | 设置默认音频播放设备 |
| Get-DesktopAudioEndpoint | 列出 Core Audio 渲染和采集端点及其音量、静音状态和默认角色 |
| Set-DesktopAudioEndpoint | 设置端点音量、静音状态或选定的默认角色 |
| Register-DesktopAudioEvent | 订阅端点、状态、属性和默认角色的更改 |
| Save-DesktopWorkstationProfile | 将显示器、音频、个性化设置和任务栏捕获为一个命名配置文件 |
| Get-DesktopWorkstationProfile | 列出或加载命名工作站配置文件 |
| Restore-DesktopWorkstationProfile | 应用命名工作站配置文件,并提供匹配和回滚选项 |
| Remove-DesktopWorkstationProfile | 删除命名工作站配置文件 |
| Get-DesktopPowerStatus | 读取交流电源和电池状态 |
| Get-DesktopSession | 读取当前交互式会话的身份、连接、锁定和空闲状态 |
| Register-DesktopSessionEvent | 订阅重要的会话更改 |
| Lock-DesktopSession | 锁定当前 Windows 会话 |
| Exit-DesktopSession | 注销当前 Windows 会话,并支持确认 |
| Start-DesktopKeepAwake | 获取有时限的系统/显示器防休眠租约 |
| Suspend-DesktopSystem | 请求睡眠或休眠,并支持确认 |
| Get-DesktopPersonalization | 捕获当前状态,或列出/加载已保存的个性化设置快照 |
| Save-DesktopPersonalization | 保存命名个性化设置快照 |
| Set-DesktopPersonalization | 应用明确指定的个性化设置 |
| Restore-DesktopPersonalization | 恢复命名个性化设置快照 |
| Remove-DesktopPersonalization | 删除命名个性化设置快照 |
| Get-DesktopTaskbar | 列出任务栏及其显示器映射、可见性、边缘和边界 |
| Set-DesktopTaskbarAutoHide | 设置明确的任务栏自动隐藏状态 |
| Get-DesktopRadio | 通过受支持的 Windows 无线电 API 列出无线电设备 |
| Set-DesktopRadio | 明确启用或禁用匹配的受支持无线电设备 |
| Register-DesktopRadioEvent | 订阅受支持的无线电状态更改 |
| Get-DesktopWifiProfile | 列出已保存的 Windows Wi-Fi 配置文件,不扫描附近网络 |
| Connect-DesktopWifiProfile | 连接到指定的已保存 Windows Wi-Fi 配置文件 |
| Get-DesktopAirplaneMode | 在明确确认后读取实验性的全局飞行模式状态 |
| Set-DesktopAirplaneMode | 在明确确认后应用并验证实验性的全局飞行模式 |
| Get-DesktopVirtualDesktop | 检查顶层窗口受支持的虚拟桌面状态 |
| Move-DesktopWindowToVirtualDesktop | 将顶层窗口移动到已知的虚拟桌面 ID |
| Get-LogonWallpaper | 获取锁屏壁纸路径 |
| Set-LogonWallpaper | 设置锁屏壁纸 |
| Set-TaskbarPosition | 移动或隐藏任务栏 |
| Invoke-DesktopMouseMove | 移动鼠标光标 |
| Invoke-DesktopMouseClick | 模拟鼠标单击 |
| Invoke-DesktopMouseScroll | 滚动鼠标滚轮 |
| Invoke-DesktopScreenshot | 捕获显示器或区域的屏幕截图 |
| Get-DesktopWindow | 枚举可见窗口 |
| Get-DesktopWindowGeometry | 返回匹配窗口的外部窗口和客户区几何信息 |
| Get-DesktopWindowControl | 枚举 Win32 或 UIA 窗口控件 |
| Get-DesktopWindowControlDiagnostic | 说明 Win32 与 UIA 控件的发现方式和可操作性 |
| Get-DesktopWindowProcessInfo | 返回匹配窗口的进程详情 |
| Get-DesktopWindowTarget | 列出已保存的窗口相对目标,或根据实时窗口解析目标 |
| Get-DesktopControlTarget | 列出已保存的控件目标,或根据实时窗口解析目标 |
| Get-DesktopHostedSessionDiagnostic | 读取最新的托管会话输入诊断文件,或读取指定文件 |
| Invoke-DesktopControlClick | 使用共享控件操作路由单击匹配的控件 |
| Invoke-DesktopWindowClick | 单击窗口相对位置或已保存的窗口目标 |
| Invoke-DesktopWindowDrag | 在窗口相对位置或已保存目标之间拖动 |
| Invoke-DesktopWindowScroll | 在窗口相对位置或已保存目标处滚动 |
| Send-DesktopControlKey | 向匹配的控件发送按键,而无需重新实现按键路由 |
| Set-DesktopControlTarget | 保存可重复使用的控件选择器配置文件 |
| Set-DesktopControlText | 直接向特定控件写入文本 |
| Set-DesktopWindow | 移动、调整大小或控制窗口 |
| Set-DesktopWindowSnap | 将窗口贴靠到常用位置 |
| Set-DesktopWindowTarget | 保存可重复使用的窗口相对位置目标 |
| Set-DesktopWindowText | 将文本粘贴或输入到窗口中 |
| Wait-DesktopWindow | 等待窗口出现 |
| Wait-DesktopWindowControl | 等待控件出现 |
| Test-DesktopWindow | 验证窗口是否存在或是否与活动窗口匹配 |
| Test-DesktopWindowControl | 验证控件是否存在 |
| Start-DesktopWindowKeepAlive | 定期发送输入以保持窗口唤醒 |
| Stop-DesktopWindowKeepAlive | 停止发送保活输入 |
| Get-DesktopWindowKeepAlive | 列出已启用保活的窗口 |
| Save-DesktopWindowLayout | 将当前窗口布局保存到文件 |
| Restore-DesktopWindowLayout | 恢复已保存的窗口布局 |
| Register-DesktopMonitorEvent | 订阅显示配置更改 |
| Register-DesktopOrientationEvent | 订阅方向更改 |
| Register-DesktopResolutionEvent | 订阅分辨率更改 |
Cmdlet 到 C# 方法映射
下表展示了每个 PowerShell cmdlet 背后最相关的 API 方法。
| Cmdlet | Main C# methods |
|---|---|
| Get-DesktopMonitor | Monitors.GetMonitors |
| Get-DesktopWallpaper | Monitors.GetWallpaper or Monitor.GetWallpaper |
| Set-DesktopWallpaper | Monitors.SetWallpaper, Monitors.SetWallpaperFromUrl |
| Get-DesktopWallpaperHistory | WallpaperHistory.GetHistory |
| Set-DesktopWallpaperHistory | WallpaperHistory.SetHistory |
| Get-DesktopSlideshow | Monitors.GetWallpaperSlideshow |
| Set-DesktopSlideshowOptions | Monitors.SetWallpaperSlideshowOptions |
| Start-DesktopSlideshow | Monitors.StartWallpaperSlideshow |
| Stop-DesktopSlideshow | Monitors.StopWallpaperSlideshow |
| Step-DesktopSlideshow | Monitors.AdvanceWallpaperSlide |
| Get-DesktopBackgroundColor | Monitors.GetBackgroundColor |
| Set-DesktopBackgroundColor | Monitors.SetBackgroundColor |
| Get-DesktopBrightness | Monitors.GetMonitorBrightness |
| Set-DesktopBrightness | Monitors.SetMonitorBrightness |
| Set-DesktopPosition | Monitor.SetMonitorPosition or Monitors.SetMonitorPosition |
| Set-DesktopResolution | Monitors.SetMonitorResolution, Monitors.SetMonitorOrientation |
| Set-DefaultAudioDevice | AudioService.SetDefaultAudioDevice |
| Get-LogonWallpaper | Monitors.GetLogonWallpaper |
| Set-LogonWallpaper | Monitors.SetLogonWallpaper |
| Set-TaskbarPosition | TaskbarService.SetTaskbarPosition / SetTaskbarVisibility |
| Invoke-DesktopMouseMove | WindowManager.MoveMouse |
| Invoke-DesktopMouseClick | WindowManager.ClickMouse |
| Invoke-DesktopMouseScroll | WindowManager.ScrollMouse |
| Invoke-DesktopScreenshot | ScreenshotService.CaptureScreen, ScreenshotService.CaptureRegion |
| Get-DesktopWindow | WindowManager.GetWindows / GetWindowsForProcess |
| Get-DesktopWindowGeometry | DesktopAutomationService.GetWindowGeometry |
| Get-DesktopWindowControl | DesktopAutomationService.GetControls |
| Get-DesktopWindowControlDiagnostic | DesktopAutomationService.GetControlDiagnostics / GetControlTargetDiagnostics |
| Get-DesktopWindowProcessInfo | WindowManager.GetWindowProcessInfo |
| Get-DesktopWindowTarget | DesktopAutomationService.ListWindowTargets, GetWindowTarget, ResolveWindowTargets |
| Get-DesktopControlTarget | DesktopAutomationService.ListControlTargets, GetControlTarget, ResolveControlTargets |
| Invoke-DesktopControlClick | DesktopAutomationService.ClickControls / ClickControlTarget |
| Invoke-DesktopWindowClick | DesktopAutomationService.ClickWindowPoint / ClickWindowTarget |
| Invoke-DesktopWindowDrag | DesktopAutomationService.DragWindowPoints / DragWindowTargets |
| Invoke-DesktopWindowScroll | DesktopAutomationService.ScrollWindowPoint / ScrollWindowTarget |
| Send-DesktopControlKey | DesktopAutomationService.SendControlKeys / SendControlTargetKeys |
| Set-DesktopControlTarget | DesktopAutomationService.SaveControlTarget |
| Set-DesktopControlText | DesktopAutomationService.SetControlText |
| Set-DesktopWindow | WindowManager.SetWindowPosition, MoveWindowToMonitor, etc. |
| Set-DesktopWindowSnap | WindowManager.SnapWindow |
| Set-DesktopWindowTarget | DesktopAutomationService.SaveWindowTarget |
| Set-DesktopWindowText | WindowManager.TypeText, WindowManager.PasteText, WindowInputService |
| Wait-DesktopWindow | DesktopAutomationService.WaitForWindows |
| Wait-DesktopWindowControl | DesktopAutomationService.WaitForControls |
| Test-DesktopWindow | DesktopAutomationService.WindowExists / ActiveWindowMatches |
| Test-DesktopWindowControl | DesktopAutomationService.ControlExists |
| Start-DesktopWindowKeepAlive | WindowKeepAlive.Start |
| Stop-DesktopWindowKeepAlive | WindowKeepAlive.Stop or StopAll |
| Get-DesktopWindowKeepAlive | WindowKeepAlive.ActiveHandles |
| Save-DesktopWindowLayout | WindowManager.SaveLayout |
| Restore-DesktopWindowLayout | WindowManager.LoadLayout |
| Register-DesktopMonitorEvent | MonitorWatcher.DisplaySettingsChanged |
| Register-DesktopOrientationEvent | MonitorWatcher.OrientationChanged |
| Register-DesktopResolutionEvent | MonitorWatcher.ResolutionChanged |
安装
若要在 PowerShell 中使用,可从 PowerShell Gallery 安装
Install-Module DesktopManager -Force -Verbose
日常使用 Windows 托盘应用时,请在有可用版本时使用 DesktopManager MSI 发布工件。安装程序会创建“开始”菜单快捷方式,应用的“启动”开关会将当前用户设置为最小化到托盘启动。
从源代码构建应用和 MSI 时,请使用 PowerForge:
.\Build\Build-DesktopManagerApp.ps1
.\Build\Build-DesktopManagerApp-MSI.ps1
msiexec.exe /i .\Artefacts\PowerForge\Msi\DesktopManager.App\win-x64\net10.0-windows10.0.19041.0\PortableCompat\output\DesktopManager.msi
已验证的修改示例
如果你希望确认的不只是“调用没有抛出异常”,请优先同时使用 -Verify 和 -PassThru,这样 cmdlet 会返回观察到的后置条件。
# Verify a window move against the observed geometry
Set-DesktopWindow -Name "*Visual Studio Code*" -Left 0 -Top 0 -Width 1600 -Height 1200 -Verify -PassThru
# Verify exact text after a control text update
Set-DesktopControlText -Control $ctrl -Text "Hello world" -Verify -PassThru
# Verify the observed check state
Set-DesktopControlCheck -Control $checkbox -Check $true -Verify -PassThru
# Return a structured record after a control click
Invoke-DesktopControlClick -Control $button -PassThru
# Return a structured record after sending keys
Send-DesktopControlKey -Control $editor -Keys @([DesktopManager.VirtualKey]::VK_RETURN) -PassThru
验证行为会根据操作类型而有所不同:
- 对于窗口修改,如果后置条件有意义,则会验证几何信息、状态、置顶、关闭或前台条件
Set-DesktopControlText -Verify会在控件可重新查询时验证观察到的文本/值Set-DesktopControlCheck -Verify会验证观察到的勾选状态- 控件点击/按键操作会返回准确的存在状态和前台证据;如果精确的语义验证会造成误导,则不会进行此类验证
测试说明
为避免本地开发期间打开窗口或更改桌面,UI 影响类测试默认选择性启用。使用以下环境变量控制行为:
RUN_UI_TESTS=true(或DESKTOPMANAGER_RUN_UI_TESTS=true)会启用顶层 UI 测试套件。RUN_OWNED_WINDOW_UI_TESTS=true(或DESKTOPMANAGER_RUN_OWNED_WINDOW_UI_TESTS=true)会启用使用仓库创建的测试窗口的自有窗口 UI 测试。RUN_DESTRUCTIVE_UI_TESTS=true(或DESKTOPMANAGER_RUN_DESTRUCTIVE_UI_TESTS=true)会启用针对仓库创建的测试窗口进行移动、调整大小、隐藏、贴靠和透明度更改等自有窗口修改测试。RUN_FOREGROUND_UI_TESTS=true(或DESKTOPMANAGER_RUN_FOREGROUND_UI_TESTS=true)会启用会主动抢占前台焦点的测试,即使这些测试只针对仓库创建的测试窗口。RUN_SYSTEM_UI_TESTS=true(或DESKTOPMANAGER_RUN_SYSTEM_UI_TESTS=true)会启用系统范围的桌面更改,例如壁纸、亮度、分辨率及其他可能影响当前会话的显示器级修改。RUN_EXTERNAL_UI_TESTS=true(或DESKTOPMANAGER_RUN_EXTERNAL_UI_TESTS=true)会启用实时外部应用 UI 测试和 MCP 端到端测试框架,这些测试会启动真实的桌面应用。RUN_EXPERIMENTAL_UI_TESTS=true(或DESKTOPMANAGER_RUN_EXPERIMENTAL_UI_TESTS=true)会启用实验性实时 UI 测试框架,适用于手动验证,但不属于稳定回归测试套件。SKIP_UI_TESTS=true(或DESKTOPMANAGER_SKIP_UI_TESTS=true)会强制跳过 UI 测试,即使其他位置已启用这些测试。
自有 WinForms 测试装置会在不激活窗口的情况下显示。显式激活窗口或依赖前台焦点的测试还需要启用前台门控。使用桌面期间,请保持 RUN_FOREGROUND_UI_TESTS 和 DESKTOPMANAGER_RUN_FOREGROUND_UI_TESTS 禁用;仅在专门的交互式运行期间启用该部分测试。
这些门控会按预期组合使用:
| 门控 | 允许的操作 | 典型影响 |
|---|---|---|
RUN_UI_TESTS | 仅启用顶层 UI 测试套件 | 低 |
RUN_OWNED_WINDOW_UI_TESTS | 仓库自有的 WinForms/WPF 测试框架窗口 | 低到中 |
RUN_DESTRUCTIVE_UI_TESTS | 修改自有测试框架窗口 | 中到高 |
RUN_FOREGROUND_UI_TESTS | 主动获取前台焦点的测试 | 中到高 |
RUN_SYSTEM_UI_TESTS | 系统范围的桌面更改 | 高 |
RUN_EXTERNAL_UI_TESTS | 启动真实的桌面应用 | 中到高 |
RUN_EXPERIMENTAL_UI_TESTS | 实验性实时测试框架 | 不定 |
# Run owned-window UI tests
$env:RUN_UI_TESTS = "true"
$env:RUN_OWNED_WINDOW_UI_TESTS = "true"
# Run repo-owned window mutation tests
$env:RUN_DESTRUCTIVE_UI_TESTS = "true"
# Run tests that intentionally steal foreground focus
$env:RUN_FOREGROUND_UI_TESTS = "true"
# Run system-wide desktop mutations
$env:RUN_SYSTEM_UI_TESTS = "true"
# Run live external-application harnesses
$env:RUN_EXTERNAL_UI_TESTS = "true"
# Run experimental live UI harnesses
$env:RUN_EXPERIMENTAL_UI_TESTS = "true"
# Force skip
$env:SKIP_UI_TESTS = "true"
# Run the repo-owned window mutation slice
dotnet test Sources/DesktopManager.Tests/DesktopManager.Tests.csproj -f net8.0-windows10.0.19041.0 --no-build --filter "WindowPositionTests|WindowStateHelpersTests|WindowVisibilityTests|WindowTransparencyTests|WindowStyleModificationTests|WindowLayoutTests"
# Run the foreground-window slice
dotnet test Sources/DesktopManager.Tests/DesktopManager.Tests.csproj -f net8.0-windows10.0.19041.0 --no-build --filter "DesktopAutomationAssertionTests|WindowManagerFilterTests|WindowTopMostActivationTests"
# Run the live MCP desktop pack backed by the repo-owned DesktopManager.TestApp harness
dotnet test Sources/DesktopManager.Tests/DesktopManager.Tests.csproj -f net8.0-windows10.0.19041.0 --no-build --filter "McpServer_TestApp"
如果托管会话或实验性实时测试框架因焦点或可发现性始终不稳定而跳过测试,现在会生成结构化诊断信息和工件,而不再静默失败。有关托管会话工件流程和门控指南,请参阅 Docs/Build.Runbook.md。
用法
C# 示例
DesktopManager.Example 项目包含更多示例。默认模式为只读;运行修改演示需要显式指定 --run-mutations 选项。
var monitors = new Monitors();
foreach (var monitor in monitors.GetMonitors(connectedOnly: true)) {
MonitorPosition bounds = monitor.GetMonitorPosition();
Console.WriteLine($"{monitor.Index}: {monitor.DeviceName} at {bounds.Left},{bounds.Top} " +
$"({bounds.Right - bounds.Left}x{bounds.Bottom - bounds.Top})");
}
// Moving a monitor changes only its top-left coordinate. Change resolution separately.
// monitors.SetMonitorPosition(selected.DeviceId, left: -1920, top: 0);
C# 示例 - 获取/设置窗口位置
var manager = new WindowManager();
WindowInfo? window = manager.GetWindows(processName: "notepad").FirstOrDefault();
if (window != null) {
manager.SetWindowPosition(window, left: 100, top: 100, width: 1000, height: 700);
manager.ActivateWindow(window);
}
平台说明
获取窗口样式时,库会使用一个辅助方法:在 32 位进程中调用
GetWindowLong,在 64 位进程中调用 GetWindowLongPtr。该
方法返回 IntPtr,因此调用方应将该值转换为
相应的数值类型。
PowerShell 示例 - 获取显示器信息
Get-DesktopMonitor | Format-Table
Get-DesktopWallpaper -Index 0
Set-DesktopWallpaper -Index 1 -WallpaperPath "C:\Wallpapers\Landscape.jpg" -Position Fit
Set-DesktopWallpaper -Index 0 -WallpaperPath "C:\Wallpapers\Portrait.jpg"
Set-DesktopBackgroundColor -Color 0x0000FF
Get-DesktopBackgroundColor
PowerShell 示例 - 壁纸幻灯片
Start-DesktopSlideshow -ImagePath 'C:\Wallpapers\img1.jpg','C:\Wallpapers\img2.jpg' -Shuffle -SlideshowTick 300000
Get-DesktopSlideshow
Set-DesktopSlideshowOptions -NoShuffle -SlideshowTick 600000
Step-DesktopSlideshow -Direction Forward
Stop-DesktopSlideshow
$Desktop1 = Get-DesktopMonitor
$Desktop1 | Format-Table
$Desktop2 = Get-DesktopMonitor -ConnectedOnly
$Desktop2 | Format-Table
$Desktop3 = Get-DesktopMonitor -PrimaryOnly
$Desktop3 | Format-Table
$Desktop4 = Get-DesktopMonitor -Index 1
$Desktop4 | Format-Table
$Desktop5 = Get-DesktopMonitor -DeviceName "\\.\DISPLAY2"
$Desktop5 | Format-Table
PowerShell 示例 - 设置显示器位置
$Desktop2 = Get-DesktopMonitor -ConnectedOnly
$Desktop2 | Format-Table
Set-DesktopPosition -Index 0 -Left -3840 -Top 0 -WhatIf
Set-DesktopPosition -Index 1 -Left 0 -Top 0 -WhatIf
PowerShell 示例 - 获取/设置窗口位置
Get-DesktopWindow | Format-Table *
$np = Start-Process notepad -PassThru
Get-DesktopWindow -ProcessId $np.Id
$np | Stop-Process
Set-DesktopWindow -Name '*Zadanie - Notepad' -Height 800 -Width 1200 -Left 100
Set-DesktopWindow -Name '*Zadanie - Notepad' -State Maximize
Set-DesktopWindowText -Name '*Notepad*' -Text 'Hello world'
# Send Ctrl+S to Notepad
$notepad = Get-DesktopWindow -Name '*Notepad*'
Invoke-DesktopKeyPress -Window $notepad -Keys @(
[DesktopManager.VirtualKey]::VK_CONTROL,
[DesktopManager.VirtualKey]::VK_S
)
# See Examples/KeyboardActions.ps1
PowerShell 示例 - 激活窗口并将其设为最顶层
Set-DesktopWindow -Name '*Notepad*' -TopMost -Activate
C# 示例 - 激活窗口并将其设为最顶层
var manager = new WindowManager();
var window = manager.GetWindows().First();
manager.SetWindowTopMost(window, true);
manager.ActivateWindow(window);
#### Example in PowerShell - Monitoring Display Changes
Use `Register-DesktopMonitorEvent` to react when monitors are plugged in or the display configuration changes.
```powershell
Register-DesktopMonitorEvent -Duration (New-TimeSpan -Seconds 30) -Action { Write-Host 'Display settings changed' }
使用 Register-DesktopOrientationEvent 或 Register-DesktopResolutionEvent,分别处理方向或分辨率变化。
Register-DesktopResolutionEvent -Duration (New-TimeSpan -Seconds 30) -Action { Write-Host 'Resolution changed' }
Register-DesktopOrientationEvent -Duration (New-TimeSpan -Seconds 30) -Action { Write-Host 'Orientation changed' }
C# 示例 - 监控显示器变化
应用程序可以订阅 MonitorWatcher.DisplaySettingsChanged 事件。
MonitorWatcherExample.Run(TimeSpan.FromSeconds(30));
PowerShell 示例 - 保存和还原窗口布局
如需可选的虚拟桌面分配、固定项、资源管理器文件夹以及显式的逐桌面壁纸还原,请参阅工作区恢复。
Save-DesktopWindowLayout -Path './layout.json'
# ... move windows around ...
Restore-DesktopWindowLayout -Path './layout.json' -Validate
C# 示例 - 保存和还原窗口布局
var manager = new WindowManager();
manager.SaveLayout("layout.json");
// ... move windows around ...
manager.LoadLayout("layout.json", validate: true);
布局还原时,每个实时窗口最多使用一次,并跳过目标不明确或缺失的情况。保存的布局包含进程名和原生类名,因此可以匹配已重启的应用程序,而无需仅依赖其标题。旧版文件仍使用精确的进程 ID/标题匹配;已禁用仅按标题和仅按进程的回退匹配。使用 PlanLayout 检查匹配结果,并使用 ApplyLayout 获取每个窗口的处理结果:
var layout = JsonSerializer.Deserialize<WindowLayout>(File.ReadAllText("layout.json"))!;
WindowLayoutPlan plan = manager.PlanLayout(layout);
foreach (WindowLayoutMatch match in plan.Windows) {
Console.WriteLine($"{match.SavedWindow.Title}: {match.Status} ({match.CandidateCount} candidates)");
}
IReadOnlyList<WindowLayoutApplyResult> results = manager.ApplyLayout(layout);
PowerShell 示例 - 窗口保持活动状态 Cmdlet
# Keep Notepad alive for one minute
Start-DesktopWindowKeepAlive -Name '*Notepad*' -Interval 00:01:00
# List active sessions
Get-DesktopWindowKeepAlive
# Stop the session
Stop-DesktopWindowKeepAlive -Name '*Notepad*'
# Keep Notepad and Calculator alive
Start-DesktopWindowKeepAlive -Name '*Notepad*'
Start-DesktopWindowKeepAlive -Name '*Calculator*' -Interval 00:00:30
Start-Sleep -Seconds 5
Get-DesktopWindowKeepAlive | Format-Table Title, Handle
Stop-DesktopWindowKeepAlive -All
# Monitor RDP windows
Start-DesktopWindowKeepAlive -Name '*RDP*' -Interval 00:00:30
1..3 | ForEach-Object {
Start-Sleep -Seconds 10
Get-DesktopWindowKeepAlive | ForEach-Object { "Active: $($_.Title)" }
}
Stop-DesktopWindowKeepAlive -Name '*RDP*'
C# 示例 - 窗口保持活动状态
var manager = new WindowManager();
var notepad = manager.GetWindows("*Notepad*").FirstOrDefault();
if (notepad != null) {
WindowKeepAlive.Instance.Start(notepad, TimeSpan.FromMinutes(1));
}
foreach (var window in new WindowManager().GetWindows("*Chrome*")) {
WindowKeepAlive.Instance.Start(window, TimeSpan.FromSeconds(30));
}
foreach (var handle in WindowKeepAlive.Instance.ActiveHandles) {
Console.WriteLine($"Keeping {handle} alive");
}
WindowKeepAlive.Instance.StopAll();
C# API 亮点
DesktopManager 作为 .NET 库发布,目标框架为 net472、netstandard2.0、net8.0-windows10.0.19041.0 和 net10.0-windows10.0.19041.0。主要入口点包括:
Monitors,用于显示器枚举、壁纸管理、亮度、分辨率、方向和幻灯片控制。WindowManager,用于窗口枚举、定位、调整大小和布局持久化。MonitorWatcher,用于在显示设置变化时接收事件。ScreenshotService,用于截取桌面或自定义区域。WorkstationProfileService和WorkstationProfileStore,用于管理完整的具名工作站状态。AudioService和AudioEndpointWatcher,用于 Core Audio 终结点、默认角色、音量、静音和变更。SystemPowerService、DesktopSessionService和DesktopSessionWatcher,用于电源和会话状态/操作。PersonalizationService、PersonalizationStateStore和TaskbarService,用于可还原的用户设置和任务栏。RadioService,用于受支持的单个无线电操作;ExperimentalAirplaneModeService用于需单独确认的未公开全局开关。WifiProfileService,用于已保存配置文件的清单,以及精确连接到指定配置文件,而不扫描附近网络。VirtualDesktopService,用于受支持的窗口到桌面操作。
输入、等待与提供程序运行状况
TypeText 和 PasteText 会在可编辑控件的当前选区插入内容。它们不会为了修复意外结果而替换控件的整个值。后台文本发送优先使用目标中已聚焦的编辑器;如果没有编辑器处于聚焦状态,且存在多个符合条件的编辑器,则会拒绝操作。需要替换内容时,请使用 WindowControlService.SetText。粘贴、原生点击和字符消息都只会发送一次。仅当 SendInput 确认未发送任何输入时,才会应用 InputRetryCount。NativeOperationOutcomeUnknownException 表示目标可能已经发生变化;在决定是否重试前,请先检查其状态。即使发送失败,也会恢复请求的焦点和剪贴板文本。
所有库目标的异步等待都支持取消。超时时间为零时,将无限期等待,直到出现匹配项或收到取消请求:
using var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(10));
WindowInfo window = await manager.WaitWindowAsync("*Notepad*", cancellationToken: cancellation.Token);
UI Automation 会为每个目标进程使用单独的 STA 工作线程,最多 16 个工作线程,每个工作线程最多排队 64 项操作。每个工作线程最多允许 64 个活动事件订阅,并预留清理容量,因此操作队列已满时也不会丢失清理操作。只要还有可用容量,一个提供程序发生阻塞不会影响其他进程。进行中的原生调用无法安全取消或重放,并会在返回前占用其工作线程。DesktopAutomationDiagnostics.GetUiAutomationHealth() 无需联系提供程序即可报告待处理工作和阻塞调用。工作线程的关闭有时间上限;达到工作线程或队列上限时,新工作将失败。
窗口捕获来源信息
CaptureWindow 保留其桌面回退行为。CaptureWindowDetailed 默认严格捕获窗口,并记录后端、实际屏幕边界、暗像素观测结果和回退原因。暗色图像可能是正常情况;严格模式会保留这些像素。桌面回退图像可能包含遮挡应用程序的像素。
using WindowCaptureResult capture = ScreenshotService.CaptureWindowDetailed(window.Handle);
Console.WriteLine($"{capture.Backend}: {capture.ScreenBounds}");
capture.Bitmap.Save("window.png");
传入 new WindowCaptureOptions { AllowDesktopFallback = true },即可选择启用可见桌面回退。DesktopAutomationService 捕获对象以及 CLI/MCP 截图结果也会公开捕获后端和回退原因。稀疏暗图像采样和视觉差异采样会直接读取已锁定的像素,避免创建完整的图像托管副本;模板匹配仍会保留其密集像素缓冲区。
需要重启的显示请求
当 Windows 接受了需要系统重启的显示请求时,SetMonitorDisplayModeDetailed 会返回 RestartRequired。现有的 void SetMonitorDisplayMode 方法在出现此结果时会抛出 DisplayRestartRequiredException。对于此请求,工作站配置文件结果会报告 Succeeded = false 和 RestartRequired = true。PowerShell 和托盘应用会显示警告;CLI JSON 和 MCP 结果会保留重启要求。没有任何 API 会自动重启 Windows。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。