PowerToys Runner 深入解析:PowerToys.exe 如何加载、管理与驱动全部模块
PowerToys Runner 是整个 PowerToys 产品的主可执行文件(PowerToys.exe),负责加载并管理所有 PowerToys 模块。本文基于仓库中的 runner 开发文档 与 src/runner/ 下的真实源码,完整拆解 Runner 的架构职责、启动流程、托盘图标实现、与 Settings UI 的命名管道 IPC 通信机制、集中式键盘钩子的性能优化,以及模块 DLL 的加载与热键注册链路。读完后,你将掌握 PowerToys 从进程启动、模块加载、托盘交互到跨进程设置分发的完整工作机制,并能定位每个关键行为的源码位置。
Runner 是做什么的
Runner 的职责可以归纳为五项(见 runner 文档):
- 管理系统托盘图标;
- 加载并管理各模块的接口对象;
- 处理模块的启用/禁用(enable/disable);
- 处理全局热键(global hotkeys);
- 管理更新(updates)与设置(settings)。
从 main.cpp 的 runner() 函数(L181-L365)可以看到其运行时形态:Runner 以 Windows 消息循环(message loop)的方式持续运行,托盘图标窗口就是这个消息循环的宿主窗口;同时它还启动了 Quick Access 宿主、后台更新检查线程(PeriodicUpdateWorker)、AI 能力检测(调用 ImageResizer 的 --detect-ai 参数)等旁路线程。
Runner 的关键组成(Key Components)包括:
- 主 C++ 文件管理托盘图标与模块集合;
- 维护一份模块 DLL 路径列表(即
knownModules数组); - 对 WinUI 3 应用做特殊处理——这些模块的 DLL 被拆分放在独立的
WinUI3Apps子目录中; - 对依赖 DLL 做“拍平”(flattening)处理,保证各模块依赖的版本一致;
- 整个生命周期运行在 Windows 消息循环中;
- 创建一个具有特定类名的窗口,并把自己注册为需要窗口句柄的组件(如集中式热键)的消息接收方。
启动流程:从 WinMain 到消息循环
文档描述的 10 步启动流程,在当前源码中可以逐步对应上。入口是 main.cpp 中的 WinMain(L448):
- 初始化日志。
Logger::init把 Runner 日志写入PTSettingsHelper::get_root_save_folder_location()下(日志路径由LogSettings::runnerLogPath决定),日志级别由get_log_settings_file_location()指向的配置驱动。 - 创建单实例互斥量。
create_msi_mutex()基于POWERTOYS_MSI_MUTEX_NAME创建应用互斥量(main.cpp L164-L167)。如果互斥量拿不到,说明已有 Runner 在运行,此时调用open_menu_from_another_instance():它用FindWindowW(L"PToyTrayIconWindow", nullptr)找到已存在的托盘窗口,向其PostMessageW(hwnd, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, ...)转发“打开设置”的请求后直接退出(L169-L179)。 - 初始化通用工具代码,包括 COM 安全描述符初始化、
winrt::init_apartment()与 DPI 感知设置(DPIAware::EnableDPIAwarenessForThisProcess())。 - 解析命令行参数。当前源码中实际支持以下参数:
--open-settings:启动后打开设置窗口;--open-settings=<窗口名>:打开指定模块的设置页(如Overview),窗口名通过ESettingsWindowNames_from_string解析;--dont-elevate:请求非提权运行;若当前已提权且设置中也未要求提权,则调用schedule_restart_as_non_elevated()以普通权限重启自身;--restartedElevated:标记“提权重启已完成”,用于打破提权重启死循环(对应源码注释中提到的 issue #19307)。 此外还有特殊启动模式:powertoys://协议 URI(处理 Toast 通知的激活动作,如open_settings/、open_overview/、update_now/)、Toast 通知 COM 服务模式、以及ReportSuccessfulUpdate模式,均由should_run_in_special_mode()判定(L367-L396)。
- 启动托盘图标:
start_tray_icon(isProcessElevated, settings.showThemeAdaptiveTrayIcon)。 - 初始化低级键盘钩子:
CentralizedKeyboardHook::Start()(见后文“集中式键盘钩子”一节)。 - 从 DLL 加载模块接口:遍历
knownModules列表逐一load_powertoy()。 - 启动已启用的模块:
start_enabled_powertoys()根据%LOCALAPPDATA%\Microsoft\PowerToys\settings.json中enabled字段的标记,调用各模块的enable()。 - 进入 Windows 消息循环:
result = run_message_loop()。 - 退出时停止模块并清理资源:消息循环结束后,
WinMain依次执行释放互斥量、检查并执行计划中的重启(restart_if_scheduled())、stop_tray_icon()清理。
值得注意的是,runner() 中在加载模块前还会先做两件事:chdir_current_executable()(把工作目录切到可执行文件所在目录,保证模块相对路径可解析)以及加载并应用通用设置 load_general_settings() + apply_general_settings()。
knownModules:一份硬编码的模块清单
与文档描述的“扫描模块目录”不同,当前实现采用的是显式清单方式:knownModules 数组列出了全部 30 余个模块 DLL 的相对路径(main.cpp L256-L292),例如:
std::vector<std::wstring_view> knownModules = {
L"PowerToys.FancyZonesModuleInterface.dll",
L"PowerToys.powerpreview.dll",
L"WinUI3Apps/PowerToys.ImageResizerExt.dll", // WinUI 3 模块放在独立子目录
L"PowerToys.KeyboardManager.dll",
L"PowerToys.Launcher.dll",
L"WinUI3Apps/PowerToys.PowerRenameExt.dll",
/* ... 其余模块 ... */
};
这里印证了文档提到的“WinUI 3 应用被分离到不同文件夹”:以 WinUI3Apps/ 前缀开头的条目(ImageResizer、PowerRename、ShortcutGuide、MouseJump、FileLocksmith、RegistryPreview、MeasureTool、NewPlus、Hosts、Peek、EnvironmentVariables)全部位于 WinUI3Apps 子目录。加载失败时,Debug 构建只记录警告(方便开发迭代),Release 构建则弹出错误对话框(L301-L318)。
模块加载完成后,start_enabled_powertoys() 负责按 settings.json 的启用状态启动它们;文档提到的“检查 GPO 策略决定哪些模块可以启动”对应于模块接口上的 gpo_policy_enabled_configuration() 虚函数(见 powertoy_module_interface.h L156-L159),由 GPO 强制禁用的模块即使本地开启也不会启动。
模块接口:powertoy_create 与 RAII 包装
Runner 与模块之间的契约定义在 powertoy_module_interface.h 的 PowertoyModuleIface 类中。头文件注释完整描述了 Runner 对每个模块 DLL 的生命周期约定:
- 加载 DLL 并调用其导出的
powertoy_create()工厂函数; - 对返回对象调用
get_key()(非本地化 ID)、enable()(初始化)、get_hotkeys()(注册热键); - 运行期间可能调用
disable()/enable()/is_enabled()、get_config()/set_config()、call_custom_action()、on_hotkey(); - 终止时调用
destroy()释放全部内存,然后卸载 DLL; - 即使模块处于禁用状态,Runner 也会调用
on_hotkey()(由各模块自行决定是否响应)。
DLL 必须以如下方式导出工厂函数:
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
Runner 侧的加载实现在 powertoy_module.cpp L14-L30:
PowertoyModule load_powertoy(const std::wstring_view filename)
{
auto handle = winrt::check_pointer(LoadLibraryW(filename.data()));
auto create = reinterpret_cast<powertoy_create_func>(GetProcAddress(handle, "powertoy_create"));
if (!create)
{
FreeLibrary(handle);
winrt::throw_last_error();
}
auto pt_module = create();
if (!pt_module)
{
FreeLibrary(handle);
winrt::throw_hresult(winrt::hresult(E_POINTER));
}
return PowertoyModule(pt_module, handle);
}
而 PowertoyModule 类(powertoy_module.h L32-L59)是一个 RAII 风格的持有者:它用两个自定义删除器(PowertoyModuleDeleter 调用 pt_module->destroy(),PowertoyModuleDLLDeleter 调用 FreeLibrary(handle))分别管理接口指针与 DLL 句柄,保证对象析构时模块内存与 DLL 一定被正确释放。所有模块实例存放在 modules() 返回的 std::map<std::wstring, PowertoyModule> 单例中(powertoy_module.cpp L8-L12),以模块的 get_key() 为键。
模块构造函数中还会顺带完成热键注册:先清除旧的冲突记录,再执行 update_hotkeys()(遍历 get_hotkeys() 返回的每个 isShown 热键,写入冲突检测器 HotkeyConflictManager,并向 CentralizedKeyboardHook::SetHotkeyAction 注册回调 modulePtr->on_hotkey(i))和 UpdateHotkeyEx()(处理 GetHotkeyEx() 单热键扩展,以及 Shortcut Guide 遗留的“长按 Windows 键”行为,见 powertoy_module.cpp L55-L119)。
系统托盘图标实现
托盘图标是 Runner 最先启动的组件之一。核心实现在 tray_icon.h / tray_icon.cpp:
- 窗口类名固定为
PToyTrayIconWindow,这是一个跨进程约定的常量,注释明确要求它与 Settings UI 侧(Settings.UI/Views/ShellPage.xaml.cs)的ptTrayIconWindowClass保持一致(tray_icon.h L28-L29); start_tray_icon()负责初始化;tray_icon_window_proc()处理窗口消息;- 通过
WM_COMMAND与托盘图标通知消息处理菜单选项; - 区分左键单击/双击;
- 监听任务栏重建(TaskbarCreated)以在需要时重新注册图标;
- 使用
Shell_NotifyIcon(文档中的shell_notify_icon)注册到系统托盘。
start_tray_icon:从注册窗口类到 NIM_ADD
start_tray_icon()(tray_icon.cpp L409-L479)的执行序列:
- 读取
UpdateState,判断是否有可用更新(readyToDownload/readyToInstall),决定使用带更新标记的图标; - 选择图标:主题自适应模式下按系统主题从
svgs/目录加载PowerToysWhite.ico/PowerToysDark.ico(对应 svgs 资源目录),否则从资源加载APPICON; - 注册窗口类并创建
WS_OVERLAPPEDWINDOW | WS_POPUP风格的隐藏窗口,把tray_icon_window_proc设为回调; - 调用
CentralizedHotkeys::RegisterWindow(hwnd)与CentralizedKeyboardHook::RegisterWindow(hwnd),让托盘窗口成为全局热键与键盘钩子的宿主句柄; - 填充
NOTIFYICONDATAW结构(uID = 1,uCallbackMessage = wm_icon_notify,即WM_APP),写入含版本号(以及“以管理员运行”提示)的 tooltip,并调用Shell_NotifyIcon(NIM_ADD, ...)完成注册; - 通过
ThemeListener注册系统主题变化回调,并注册 Bug 报告状态回调(用dispatch_run_on_main_ui_thread把回调切回主 UI 线程)。
一个值得注意的工程细节:Shell_NotifyIcon 在 explorer.exe 尚未就绪时会失败,且此时永远收不到 TaskbarCreated 消息,因此窗口过程额外处理 WM_WINDOWPOSCHANGING 消息(explorer 启动序列中必然收到),借此机会补做 NIM_ADD(tray_icon.cpp L213-L223);同时 WM_CREATE 中通过 RegisterWindowMessageW(L"TaskbarCreated") 订阅任务栏重建消息,收到后重新 NIM_ADD(L356-L359)。
tray_icon_window_proc:消息分发与单击/双击判定
tray_icon_window_proc()(tray_icon.cpp L161-L363)是托盘交互的总入口,主要分支包括:
WM_HOTKEY:利用托盘窗口避免为热键另建窗口,直接把修饰键掩码与虚拟键码交给CentralizedHotkeys::PopulateHotkey分发给对应模块;WM_CLOSE/WM_DESTROY:WM_CLOSE触发DestroyWindow;WM_DESTROY中删除托盘图标(Shell_NotifyIcon(NIM_DELETE, ...))、关闭 Settings 子进程(close_settings_window())并PostQuitMessage(0)结束消息循环。源码中还专门优化了“系统关机”场景:当g_system_session_ending为真时跳过跨进程清理,避免在 Windows 的 quiesce 时间预算内等待 Settings 进程而被判定为挂起;WM_COMMAND:交给handle_tray_command()(L92-L140),按菜单 ID 分发:ID_SETTINGS_MENU_COMMAND打开指定设置页、ID_CLOSE_MENU_COMMAND关闭窗口、ID_ABOUT_MENU_COMMAND显示关于框(含产品版本号)、ID_REPORT_BUG_COMMAND启动 Bug 报告工具、ID_DOCUMENTATION_MENU_COMMAND打开文档链接、ID_QUICK_ACCESS_MENU_COMMAND打开 Quick Access 弹出窗口、ID_UPDATE_MENU_COMMAND跳到 Overview 页;wm_icon_notify(WM_APP)自定义消息:托盘图标交互的实际载荷,按lparam区分:- 右键/上下文菜单:动态构建菜单(含“Update available”项的插入/移除、Quick Access 项随设置的显隐、Bug 报告项的置灰),用
TrackPopupMenu展示; WM_LBUTTONUP:启动一个延时GetDoubleClickTime()毫秒的定时器线程,若期间未发生双击则按单击处理——若开启了 Quick Access 则打开快速访问浮窗,否则打开设置窗口(click_timer_elapsed(),L142-L159);WM_LBUTTONDBLCLK:标记double_clicked = true抵消单击定时器,并直接打开设置窗口;
- 右键/上下文菜单:动态构建菜单(含“Update available”项的插入/移除、Quick Access 项随设置的显隐、Bug 报告项的置灰),用
wm_run_on_main_ui_thread:执行dispatch_run_on_main_ui_thread()投递来的回调(供 IPC 等后台线程把 JSON 消息切回主线程)。
托盘菜单:RC 资源 + 本地化字符串
与文档描述一致,菜单结构定义在资源脚本 runner.base.rc 中(ID_TRAY_MENU MENU,含 "Settings" 等 MENUITEM),菜单命令 ID 由头文件定义,本地化文本存放在 Resources.resx(IDS_SETTINGS_MENU_TEXT、IDS_CLOSE_MENU_TEXT 等资源字符串在 tray_icon_window_proc 中按需加载并写回菜单项)。菜单还会在每次弹出时根据 Quick Access 开关状态动态更新“Settings”菜单项的文案。
与 Settings UI 的 IPC 通信机制
Runner 与设置窗口是两个独立进程,二者通过 Windows 命名管道(Named Pipes)传输 JSON 消息:
- Runner 侧使用
TwoWayPipeMessageIPC(双向管道)建立连接; - Settings UI 启动时初始化自己的管道连接,文档中给出的 C# 侧初始化代码为:
ipcmanager = new TwoWayPipeMessageIPCManaged(cmdArgs[(int)Arguments.SettingsPipeName],
cmdArgs[(int)Arguments.PTPipeName],
(string message) => {
if (IPCMessageReceivedCallback != null && message.Length > 0) {
IPCMessageReceivedCallback(message);
}
});
Runner 侧:管道命名、进程创建与客户端鉴权
run_settings_window()(settings_window.cpp L435)负责拉起 WinUI3Apps\PowerToys.Settings.exe 子进程。管道命名采用“固定前缀 + 随机 UUID”的方式保证每次会话唯一(L454-L476):
std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_");
std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_");
// UuidCreate 成功后追加 uuid 字符串
子进程参数依次为:两个管道名、Runner 的 PID、主题(dark/system 归一化)、是否提权、当前用户是否管理员、是否显示 OOBE/Scoobe 窗口、是否携带指定设置窗口名。
管道建立后,当前源码在 current_settings_ipc->start() 之前还有一道管道客户端鉴权(interop_auth::CallerPolicy,L590-L602):只接受位于 Runner 自身 WinUI3Apps 目录下、版本与 Runner 一致、且带 Microsoft 签名的 PowerToys.Settings.exe(Debug 构建下签名检查被编译排除),拒绝的客户端会记录日志。这为文档描述的 JSON 管道通信补充了一层安全边界。
Runner 收到消息后并不直接在管道线程处理,而是 receive_json_send_to_main_thread() → dispatch_run_on_main_ui_thread() 切回主 UI 线程执行 dispatch_received_json(),这正是文档中 dispatch_run_on_main_ui_thread 的作用——Settings 窗口是从专用线程通信的,JSON 消息必须安全地转移到主线程。
Runner 侧处理的 JSON 消息类型
dispatch_received_json()(settings_window.cpp L194-L357)按顶层键名分发,覆盖以下消息:
| 消息键 | 行为 |
|---|---|
general |
apply_general_settings() 应用通用设置 |
module_status |
单个模块的启用/禁用更新,格式 {"module_status": {"ModuleName": true/false}} |
powertoys |
对每个模块调用 set_config(),若 properties.hotkey_changed 为真则同步重建热键;随后把全量设置回写给 Settings |
refresh |
立即回写 get_all_settings() |
action |
分发自定义动作:restart_elevation(切换提权并重启)、restart_maintain_elevation(保持提权重启,跳过落盘设置)、check_for_updates(后台检查更新)、request_update_state_date(返回上次检查日期) |
bugreport / bug_report_status |
启动 Bug 报告 / 回报运行状态 |
killrunner |
对托盘窗口发送 WM_CLOSE 关闭 Runner |
language |
将语言 JSON 落盘到 language.json |
check_hotkey_conflict / get_all_hotkey_conflicts |
热键冲突查询,返回 has_conflict 与冲突详情 |
回写给 Settings 的完整设置由 get_all_settings() 组装:general 段加每个模块 get_config() 返回的 JSON(L41-L65)。
Runner 主动打开/指示设置窗口
当托盘图标被点击或菜单选项被选中时,Runner 通过 IPC 向 Settings 发送 JSON 指令(open_settings_window(),L699-L727):
- 快速访问浮窗(左键单击,Settings 已运行时):
current_settings_ipc->send(L"{\"ShowYourself\":\"flyout\"}"); - 主仪表盘(菜单项或双击):
current_settings_ipc->send(L"{\"ShowYourself\":\"Dashboard\"}"); - 打开特定模块页:
{"ShowYourself":"<窗口名>"},窗口名来自ESettingsWindowNames_to_string枚举(覆盖 Overview、FancyZones、KBM、PowerRename、Peek 等全部模块页,L757-L836)。
如果 Settings 进程尚未启动,则在线程中执行 run_settings_window() 拉起它;若正在启动中(g_isLaunchInProgress)则直接返回,避免重复创建。
Settings UI 侧的消息处理链
Settings UI 侧的处理流程(与文档一致):
- 来自 Runner 的消息经 IPC 回调接收;
- 消息被解析为 JSON 对象;
- 注册在
ShellPage.ShellHandler.IPCResponseHandleList中的处理器逐个处理消息; ShellPage的ReceiveMessage方法解释命令:"ShowYourself": "flyout"显示浮窗;"ShowYourself": "Dashboard"或其他页名则打开对应页面(Settings UI 侧实现位于 Settings.UI/Views/ShellPage.xaml.cs)。
浮窗还支持携带坐标,让浮窗出现在托盘图标附近:
{
"ShowYourself": "flyout",
"x_position": 1234,
"y_position": 567
}
浮窗窗口随后通过原生 Windows API 激活并置于前台以保证可见。
集中式键盘钩子
全局快捷键统一由 centralized_kb_hook.cpp 中的 CentralizedKeyboardHook 处理——为多个模块集中处理热键,避免每个模块各自挂钩子带来的性能问题。核心钩子回调 KeyboardHookProc(L88)包含文档所列的多个提前退出(early exit)优化:
- 忽略 PowerToys 自身产生的按键:
KBDLLHOOKSTRUCT.dwExtraInfo等于PowertoyModuleIface::CENTRALIZED_KEYBOARD_HOOK_DONT_TRIGGER_FLAG(0x110)时直接CallNextHookEx放行——该标志专门用于 AdvancedPaste 这类会产生新输入的动作,防止自身输出被再次捕获; - 忽略没有按键真正按下的事件:用
vkCodePressed原子变量跟踪“当前是否已有按键被按住”,只有第一个物理按键按下时才会为“长按触发”类行为(pressedKeyDescriptors,如 Shortcut Guide 的长按 Win 键)启动计时器; - 利用按键元数据避免重复处理修改态输入:
vkCodePressed记录了上一次按下的虚拟键码,用于识别重复键与多键同时按下的情况,且刻意选择虚拟键码作为 multiset 排序键,因为“按键命中查找”发生在时间最敏感的钩子路径上。
文档特别强调的性能约束在这里体现得很直白:该回调在每一次击键时都会运行,任何耗时逻辑(如启动长按计时器)都被推到 SetTimer 回调(PressedKeyTimerProc,触发前还会用 GetAsyncKeyState 复核按键仍被物理按住,防止“幽灵触发”)中异步执行,钩子内部持锁时间被压缩到最短。
热键的注册与注销逻辑在 centralized_hotkeys.cpp,Runner 通过托盘窗口的 WM_HOTKEY 消息把命中分发给 CentralizedHotkeys::PopulateHotkey。设置中修改热键后,send_json_config_to_module() 会调用 remove_hotkey_records() + update_hotkeys() + UpdateHotkeyEx() 完成整套热键的重建(settings_window.cpp L151-L165),并由 hotkey_conflict_detector.cpp 维护跨模块冲突检测。
如何找到并“发消息给”托盘窗口
文档指出,托盘窗口类同时是 Runner 的进程间控制句柄。因为窗口类名 PToyTrayIconWindow 是跨进程公开约定,任何组件(包括 Runner 自身的第二实例、Settings UI 的 killrunner 消息处理)都可以:
// 找到 PToyTrayIconWindow 类的窗口并发送消息
HWND hwnd = FindWindowW(L"PToyTrayIconWindow", nullptr);
PostMessageW(hwnd, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, 0); // 请求打开设置
SendMessageW(hwnd, WM_CLOSE, 0, 0); // 请求关闭 Runner
源码中有三处实际用例:单实例转发 open_menu_from_another_instance()(main.cpp L169-L179)、IPC killrunner 消息处理(settings_window.cpp L270-L277)、以及 stop_tray_icon() 内部的 SendMessage(tray_icon_hwnd, WM_CLOSE, 0, 0)(tray_icon.cpp L556-L564)。
关键文件速查
以下为 runner 文档 列出的关键文件与当前仓库路径对照:
| 文件 | 职责 |
|---|---|
| main.cpp | 可执行文件入口:初始化顺序、模块清单与加载、消息循环;单例初始化也在此完成 |
| powertoy_module.h / powertoy_module.cpp | 模块的初始化与管理;PowertoyModule 是对 PowertoyModuleIface 指针的 RAII 持有,接口由 powertoy_create() 创建 |
| tray_icon.cpp | 托盘图标与菜单命令管理;dispatch_run_on_main_ui_thread 用于把 Settings 传来的 JSON 消息切回主线程 |
| settings_window.cpp | 启动设置窗口进程并维持命名管道 JSON 通信,分发设置/动作/冲突查询等消息 |
| general_settings.cpp | 通用设置的加载、保存与应用 |
| auto_start_helper.cpp | 注册/注销用户登录时自启动 |
| unhandled_exception_handler.cpp | 在构建中获取堆栈跟踪的辅助代码(init_global_error_handlers 仅在 Debug 构建被引用) |
| trace.cpp | 遥测(ETW/EventLaunch 等事件) |
| svgs/ | 托盘图标等资源文件 |
| bug_report.cpp | 启动 Bug 报告工具 |
| centralized_hotkeys.cpp | 全局热键的注册与注销 |
| centralized_kb_hook.cpp | 集中式低级键盘钩子与所有模块快捷键的匹配/分发 |
| restart_elevated.cpp | 以不同提权级别重启当前进程 |
| RestartManagement.cpp | 基于 Restart Manager 的进程重启实现 |
| settings_telemetry.cpp | 周期性触发各模块设置遥测的投递,管理时序与错误处理 |
| UpdateUtils.cpp | 自动更新检查、通知与安装流程 |
小结:Runner 在 PowerToys 架构中的位置
把上述源码证据串起来,Runner 的角色可以概括为“模块宿主 + 托盘前端 + 设置总机”三层:
- 模块宿主:通过
knownModules清单加载模块 DLL,以powertoy_create()+ RAII 包装完成模块生命周期管理,用settings.json与 GPO 策略共同决定谁被enable(); - 托盘前端:
PToyTrayIconWindow类窗口承载托盘图标、菜单、单击/双击交互与全局热键分发,同时充当跨进程消息的“收件地址”; - 设置总机:以带 UUID 的命名管道承载 Runner ↔ Settings UI 的双向 JSON 协议(
ShowYourself、powertoys配置、action、热键冲突查询、killrunner等),并用管道客户端鉴权约束对端身份。
理解这套机制后,无论是排查“模块没启动”“热键不生效”“托盘图标消失”,还是开发新模块(可参考 tools/project_template/ModuleTemplate 的模块模板与 powertoy_module_interface.h 的接口约定),都能沿着本文的调用链快速定位到对应源码。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00