PowerToys C 公共基础设施解析通用工具类、Helpers 与 Toast 通知 API【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys本文基于仓库开发文档 doc/devdocs/common/common.md 撰写系统讲解 Microsoft PowerToys 为各 PowerToy 模块提供的 C 公共层DPI 感知、显示器信息、任务栏定位、设置对象序列化、异步消息队列与双向管道 IPC 等工具类以及 UWP 风格的 Toast 通知 API。读完本文你将了解每个公共组件的职责与当前在src/common中的真实落位并掌握如何在模块中接入 Toast 通知含按钮回调/后台激活机制的完整流程以及文档中历史路径与现有代码结构的对应关系。1. 文档定位PowerToys 的 C 公共层是什么doc/devdocs/common/common.md 是面向 PowerToys 贡献者的开发文档描述src/common下可被各 PowerToy 模块C 宿主、Runner 设置窗口等复用的类与结构。文档本身标注了 This document is outdated and will soon be renewed即它记录的是历史路径下的 API 快照在梳理时已确认仓库经过目录重组原文所列文件大多已迁移到src/common下的功能子目录中。本文按原文档骨架Classes and structures → Helpers → Toast Notifications展开并在每一节给出经核实的当前文件路径与源码级细节。2. 通用类与结构体Classes and structures原文档以条目形式列出了 8 组公共组件下表演述时均保留原条目并补充了当前仓库中的实际位置与实现要点。原文档条目原文路径当前仓库路径已核实class Animationsrc/common/animation.h该文件在当前src/common中已不存在属于历史遗留条目class AsyncMessageQueuesrc/common/async_message_queue.hsrc/common/interop/async_message_queue.hclass TwoWayPipeMessageIPCsrc/common/two_way_pipe_message_ipc.hsrc/common/interop/two_way_pipe_message_ipc.hclass DPIAwaresrc/common/dpi_aware.hsrc/common/Display/dpi_aware.hstruct MonitorInfosrc/common/monitors.hsrc/common/Display/monitors.hclass Settings / PowerToyValues / CustomActionObjectsrc/common/settings_objects.hsrc/common/SettingsAPI/settings_objects.hclass Tasklistsrc/common/tasklist_positions.hsrc/common/interop/tasklist_positions.hstruct WindowsColorssrc/common/windows_colors.hsrc/common/Themes/windows_colors.h下面按组件深入说明。2.1 AsyncMessageQueueHeader-only 异步消息队列原描述Header-only asynchronous message queue. Used byTwoWayPipeMessageIPC。 当前实现位于 src/common/interop/async_message_queue.h是一个单文件头文件类核心成员与行为如下源码见 该文件std::queuestd::wstring message_queue消息队列元素为宽字符串std::mutex queue_mutexstd::condition_variable message_ready线程安全的入队/出队同步bool interrupted中断标记。队列被中断时pop_message()返回空字符串供消费线程优雅退出类禁用了拷贝构造与拷贝赋值AsyncMessageQueue(const AsyncMessageQueue);被声明而未定义保证队列实例唯一的消费者语义。接口极简生产者调用queue_message(std::wstring)入队并notify_one()消费者调用pop_message()阻塞取消息。这种条件变量等待 空队列轮询保护的写法避免了虚假唤醒导致的忙等是典型的阻塞队列模式。2.2 TwoWayPipeMessageIPCRunner 与设置窗口的双向管道通信原描述Header-only asynchronous IPC messaging class. Used by the runner to communicate with the settings window。 当前类定义位于 src/common/interop/two_way_pipe_message_ipc.h采用 PIMPL 模式class TwoWayPipeMessageIPCImpl;前向声明 裸指针成员对外接口为typedef std::functionvoid(const std::wstring) callback_function; TwoWayPipeMessageIPC(std::wstring _input_pipe_name, std::wstring _output_pipe_name, callback_function p_func); void send(std::wstring msg); // 向管道另一端发送消息 void start(HANDLE _restricted_pipe_token); void end();值得注意的两处源码细节安全姿态头文件明确约束出站客户端绝不能授予服务器可模拟身份的令牌并内联定义了ClientOpenFlags FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATIONsrc/common/interop/two_way_pipe_message_ipc.h即客户端以SECURITY_IDENTIFICATION级别打开命名管道降低被利用做身份模拟的风险。fail-closed 调用方校验新增了重载start(HANDLE, const interop_auth::CallerPolicy)注释说明其用于 Runner 的特权服务端管道——每个连接的客户端在派发前都要经过认证认证策略失败即关闭。TwoWayPipeMessageIPC依赖上节的AsyncMessageQueue作为接收缓冲实现文件在 src/common/interop/two_way_pipe_message_ipc.cpp。该组件有专门的故障注入测试钩子TWO_WAY_PIPE_MESSAGE_IPC_TESTS宏下的FailThreadStartAfter、SetWaitNamedPipeEnteredEvent等见 头文件测试用例位于 src/common/UnitTests-CommonUtils/TwoWayPipeMessageIPC.Tests.cpp覆盖线程启动失败、监听替换等竞态场景——从源码结构看这是该组件在 Runner 关键路径上稳定性的重要保障。2.3 DPIAware跨 DPI 缩放的坐标换算原描述Helper class for creating DPI-aware applications。 当前位于 src/common/Display/dpi_aware.h以namespace DPIAware提供一组查询与换算函数源码DEFAULT_DPI 96默认 DPI 常量换算的基准按监视器/窗口/点/光标查询 DPIGetScreenDPIForMonitor、GetScreenDPIForWindow、GetScreenDPIForPoint、GetScreenDPIForCursor逻辑↔物理坐标双向换算Convertwidth/height 或 RECT 重载、ConvertByCursorPosition、InverseConvert。悬浮窗、覆盖层类模块如 MeasureTool、FancyZones 一类需要精确落位的 UI通常依赖这组函数在多显示器、多缩放比环境下保持尺寸正确EnableDPIAwarenessForThisProcess()与GetAwarenessLevel(...)后者把系统返回的DPI_AWARENESS_CONTEXT归一为UNAWARE / SYSTEM_AWARE / PER_MONITOR_AWARE / PER_MONITOR_AWARE_V2 / UNAWARE_GDISCALED五个枚举级别。2.4 MonitorInfo 与 Box物理显示器信息原描述Class for obtaining information about physical displays connected to the machine。 当前位于 src/common/Display/monitors.h。该文件包含两个关键类型struct Box源码对RECT的轻量封装提供left()/right()/top()/bottom()/width()/height()以及top_left()、middle()、bottom_right()等九个锚点、inside(POINT)命中判断并实现了三路比较运算符C20便于排序。源码注释中还留有一行// TODO: merge with FZ::Rect说明它与 FancyZones 的FZ::Rect存在功能重叠从源码结构看后续可能合并class MonitorInfo以HMONITORMONITORINFOEX为核心源码定义Size结构同时携带逻辑分辨率width_logical/height_logical与物理尺寸width_physical/height_physical、width_mm/height_mm是 FancyZones、ZoomIt 等显示器相关模块获取屏幕拓扑的基础。2.5 Settings / PowerToyValues / CustomActionObject设置页的数据契约原描述Classes used to define settings screens for the PowerToys modules。 当前位于 src/common/SettingsAPI/settings_objects.h。这一组类定义了 C PowerToy 模块与 WinUI 设置界面之间交换 JSON 的契约class Settings源码以模块 HINSTANCE 和 PowerToy 名称构造随后通过链式add_*方法声明设置项。每种控件都有一对重载——一个接收资源 IDUINT description_resource_id从模块资源 DLL 取本地化文本一个直接接收std::wstring_view文本add_bool_toggle开关add_int_spinner整数步进器带min/max/step取值范围add_string/add_multiline_string单行/多行文本add_color_picker颜色选择add_hotkey快捷键接收HotkeyObjectadd_choice_group/add_dropdown单选组与下拉框选项为key, text对向量add_custom_action自定义按钮动作add_header_szLarge大标题分组。 最终由serialize()/serialize_to_buffer()把内部json::JsonObject m_json导出为字符串内部字段m_curr_priority用于保持添加顺序稳定class PowerToyValues源码反方向的数据读取器。可通过PowerToyValues::from_json_string(json, powertoy_key)从 JSON 字符串解析或PowerToyValues::load_from_settings_file(powertoy_key)直接从设置文件加载模板方法add_propertyT(name, value)把设置项绑定为强类型属性供模块读取当前配置。2.6 Tasklist任务栏按钮定位原描述Class that can detect the position of the windows buttons on the taskbar. It also detects which window will react to pressing WinKey number。 当前位于 src/common/interop/tasklist_positions.h核心为struct TasklistButton { wchar_t name[256]; // 按钮名称 int x, y, width, height; // 屏幕坐标与尺寸 int keynum; // 对应 WinN 的序号 }; extern C { HWND GetTaskbarHwndForCursorMonitor(HMONITOR monitor); // 取光标所在显示器的任务栏 HWND bool update_buttons(std::vectorTasklistButton buttons); __declspec(dllexport) TasklistButton* get_buttons(HMONITOR monitor, int* size); }从源码结构看这类枚举任务栏子窗口 → 记录每个按钮的屏幕矩形与 WinN 序号的能力是 MouseJump鼠标定位跳转类功能的定位数据源get_buttons被__declspec(dllexport)导出说明它同时服务于以 DLL 形式被外部托管代码加载的场景。2.7 WindowsColors跟随 Windows 配色方案原描述Class for detecting the current Windows color scheme。 当前位于 src/common/Themes/windows_colors.h是一个静态方法 少量成员的状态结构源码调色取值get_accent_color()、get_accent_light_1_color()、get_accent_dark_1_color()、get_button_face_color()、get_highlight_color()、get_background_color()等返回winrt::Windows::UI::Color模式判断is_dark_mode()bool update()刷新一次颜色返回值表示是否有值变化便于模块仅在配色实际改变时重绘成员accent_color_menu、start_color_menu、desktop_fill_color、light_mode缓存最近一次取到的颜色。3. 辅助函数Helpers原文档还列出了三组 helpers当前仓库中的对应情况如下Common helpers原src/common/common.h/.cppVarious helper functions该文件已不在src/common顶层。从各模块的pch.h仍广泛包含common.h的路径如 src/modules/fancyzones/FancyZonesModuleInterface/pch.h、src/modules/CropAndLock/CropAndLockModuleInterface/pch.h可以推断通用头文件被拆分/重组到了src/common/utils/等子目录Settings helpers原src/common/settings_helpers.h现位于 src/common/SettingsAPI/settings_helpers.h与上节settings_objects同目录提供设置 JSON 的读写辅助Start visible helper原src/common/start_visible.h/.cpp包含检测开始菜单是否可见的函数该文件在当前src/common中未找到属于已被移除或迁移的历史条目引用它的场景如按 Start 键定位可能已由其他实现替代。4. Toast Notifications API从文档示例到当前实现这是原文档最详实的部分。文档给出的原始 API 为void show_toast(std::wstring_view message); // #1 简单通知无回调无按钮 void show_toast_background_activated( // #2 带多按钮 后台激活 std::wstring_view message, std::wstring_view background_handler_id, std::vectorstd::wstring_view button_labels);其中#1用于发送无回调的纯文本通知#2支持显示多个按钮并绑定后台激活处理器文档也预告了未来可能增加show_toast_xml之类的富定制接口。4.1 当前 API更丰富的结构化接口当前实现位于 src/common/notifications/notifications.hAPI 已演进为结构化参数形式源码void show_toast(std::wstring plaintext_message, std::wstring title, toast_params params {}); void show_toast_with_activations(std::wstring plaintext_message, std::wstring title, std::wstring_view background_handler_id, std::vectoraction_t actions, toast_params params {}, std::wstring launch_uri L); void update_toast_progress_bar(std::wstring_view tag, progress_bar_params params); void remove_toasts_by_tag(std::wstring_view tag); void remove_all_scheduled_toasts();相比文档快照新增了若干能力notifications.haction_t std::variantlink_button, background_activated_button, snooze_button按钮从纯文本标签数组升级为三种类型——协议链接按钮可放入右键上下文菜单、后台激活按钮、以及系统级稍后提醒snooze按钮可带最多 5 个时长选项toast_params支持tag配合remove_toasts_by_tag按标签撤销、resend_if_scheduled、progress_bar进度条参数update_toast_progress_bar/remove_toasts_by_tag/remove_all_scheduled_toasts对已发送通知进行更新与清理override_application_id/run_desktop_app_activator_loopAppUserModelID 覆写与桌面版激活循环见 4.3。一个真实的调用示例来自 Runner 的更新通知 src/runner/UpdateUtils.cpp以及 src/runner/main.cpp 中的notifications::show_toast(GET_RESOURCE_STRING(...).c_str(), LPowerToys)。4.2 实现要点XML 组装与 Toast 分组notifications.cpp 中的show_toast_with_activations展示了完整生成链路源码按 Windows toast XML schema 拼接toastvisualbinding templateToastGenerictitle 与 message 分别绑定text id1/2源码注释强调这些 XML 标签字符串不得本地化可选附加launch属性与activationTypeprotocol用于点击后通过 URI 启动应用遍历actions用std::visit 重载 lambda 为三类按钮生成对应action元素。后台激活按钮的 arguments 会写入button_idihandlerhandler_id即原文档按钮按下后回调拿到 button_id的机制在 XML 层的落点进度条用progress title{progressTitle} value{progressValue} .../占位随后以NotificationData的 StringMap 注入真实数值progress被std::clamp到[0,1]并自动生成百分比字符串所有通知统一归入DEFAULT_TOAST_GROUP LPowerToysToastTag分组带tag长度 64时可去重若resend_if_scheduled为 false 且计划队列中已存在同 tag 通知则直接跳过通过ToastNotificationManager::CreateToastNotifier(APPLICATION_ID)的Show(notification)发出异常被静默吞掉——从源码结构看这是为了保证通知失败不影响主流程。4.3 后台激活文档的注册模式与当前实现原文档给出的接入范式在handler_functions.cpp实现处理函数并经handlers_map注册在当前仓库中依然成立且与实现一一对应。文档示例保留原文骨架仅把 handler 签名对齐当前实现// 某个模块的 .cpp #include common/notifications.h void some_func() { // ... notifications::show_toast_background_activated( LToast message!, // 通知文本 Lawesome_toast, // 激活处理器 id { LPress me!, LAlso could press me! }); // 按钮 }// handler_functions.cpp void awesome_toast_handler(const size_t button_id) { switch (button_id) { case 0: /* Press me! */ break; case 1: /* Also could press me! */ break; } } namespace { const std::unordered_mapstd::wstring_view, handler_function_t handlers_map { { Lawesome_toast, awesome_toast_handler } }; }当前实现的三块拼图处理器注册表src/common/notifications/BackgroundActivator/handler_functions.cpp。注意当前签名已从文档中的void(IBackgroundTaskInstance, const size_t)简化为void(const size_t button_id)handler_function_t定义在 handler_functions.h。dispatch_to_background_handler(argument)用WwwFormUrlDecoder解析button_id与handler两个参数在handlers_map中查不到时直接返回COM 激活对象notifications.cpp 中的NotificationActivator实现了INotificationActivationCallbackDECLSPEC_UUID(DD5CACDA-7C2E-4997-A62A-04A597B58F76)其Activate()会动态LoadLibraryW(LPowerToys.BackgroundActivatorDLL.dll)并取dispatch_to_background_handler入口完成派发run_desktop_app_activator_loop()则通过CoRegisterClassObject注册该 COM 对象并运行消息循环。Runner 主入口在 src/runner/main.cpp 调用了这一循环进程边界后台激活意味着处理器可能在独立进程BackgroundActivatorDLL中执行无法与 PT 进程直接共享内存数据。此外由于 PT 曾是 Desktop Bridge 应用前台激活按后台激活同等处理因此没有为前台单独设计 API——这是原文档 Note 中说明的设计动机理解它对正确使用该 API 很重要例如不要试图在 handler 中依赖宿主进程的堆数据。4.4 相关测试IPC 相关行为有单元覆盖src/common/UnitTests-CommonUtils/TwoWayPipeMessageIPC.Tests.cpp设置对象的序列化行为有 src/common/UnitTests-CommonLib/Settings.Tests.cpp。从源码结构看Toast API 本身依赖 WinRT 通知子系统未在当前仓库内发现独立的单元测试工程验证主要依赖 Runner 内的实际调用路径如 4.1 节所列的UpdateUtils.cpp用例。5. 使用指引在模块中如何引用这些公共组件结合上述落位开发新 PowerToy 模块时的实践路径是通知包含common/notifications.h并在模块代码中调用notifications::show_toast(...)若需要按钮回调在BackgroundActivator的handlers_map中登记处理函数显示器/DPI包含common/Display/monitors.h与common/Display/dpi_aware.h项目 src/common/Display/Display.vcxproj主题色包含common/Themes/windows_colors.h项目 src/common/Themes/Themes.vcxproj设置模块侧用PowerToysSettings::Settings声明控件并serialize()运行时用PowerToyValues::load_from_settings_file(...)读取均见 src/common/SettingsAPI/settings_objects.hRunner↔设置窗口的消息通道使用TwoWayPipeMessageIPC注意新代码应评估是否需要带CallerPolicy的认证重载。6. 小结doc/devdocs/common/common.md 勾勒出 PowerToys C 公共层的三块内容工具类DPI、显示器、任务栏、主题色、设置对象、helpers以及一套以 XML 组装 后台激活回调解耦为核心的 Toast 通知 API。需要提醒的是该文档自述已过时文中/src/common/*.h顶层路径大多已迁移为src/common/{Display,Interop/interop,SettingsAPI,Themes,notifications}/下的子目录文件Animation、start_visible等条目对应的文件在当前仓库中已不可见。以本文给出的当前路径为准查阅源码能更准确地对接这些公共能力。【免费下载链接】PowerToysMicrosoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考