Shell 扩展名称解析重构 + 国际化 + 主题系统 + Dialog 弹窗#11
Merged
Merged
Conversation
- 完整翻译所有章节为简体中文 - 添加测试命令详细说明 - 补充 TypeScript 严格模式配置 feat: 添加 PowerShell 脚本工具 - cleanup.ps1: 清理脚本 - task.ps1: 任务管理脚本
- Simplify Windows Terminal command for new tab in task.ps1 - Clean up and standardize permissions in settings.json
**根本原因** buildGetShellExtItemsScript 的 Level 3 DLL 字符串扫描(范围 1-500) 会命中与菜单项无关的资源字符串,导致 DesktopSlideshow 等条目显示 "在我的电池需要替换时发出警告"等错误名称。 **变更内容** - PowerShellBridge: 移除 Level 3 DLL 字符串暴力扫描(ReadDllStrings), CmHelper C# 源码同步精简(移除 LoadLibraryEx / FreeLibrary / LoadString P/Invoke) - PowerShellBridge: Level 2 扩展为遍历 FileDescription / ProductName / InternalName / OriginalFilename 四个 VersionInfo 字段 - PowerShellBridge: 原 Level 4(CLSID Default 值)晋升为 Level 3 兜底 - PowerShellBridge: buildGetItemsScript 新增 CmShell Add-Type + Resolve-MenuName, 经典菜单项名称读取优先级改为 MUIVerb → (Default) → 子键名, 支持 @dll,-id 格式的间接字符串解析 - RegistryService: 新增缓存支持(RegistryCache),getMenuItems 优先读缓存, enable/disable 操作后自动失效对应场景缓存 - RegistryService: 名称兜底层 —— 若 PS 返回以 @ 开头的未解析字符串, 自动替换为 subKeyName **单元测试** - PowerShellBridge.test.ts: 新增 12 个用例,覆盖 MUIVerb、CmShell、 Level 3 移除、InternalName/OriginalFilename、CLSID Default 升级等 - RegistryService.test.ts: 新增 5 个用例,覆盖 @ 前缀名称净化场景 (含 DesktopSlideshow 问题复现验证) - MenuManagerService.test.ts: 修复预存 mock 缺失(invalidateCache、log.debug) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- buildGetShellExtItemsScript 从四级降为三级策略 Level 1: LocalizedString(@ 格式或直接值,过滤泛型 COM 类型描述) Level 2: CLSID 默认值 Level 3: 处理程序键名(最终兜底) - Format-DisplayName 移除大小写规范化和热键清理(热键已迁至 TS 层) - buildGetItemsScript 新增 LocalizedDisplayName 第三优先级 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
加载期间快速切换场景时,后续请求不再被丢弃,而是记录为 pendingScene,前一次加载完成后立即执行最新的待切换场景。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
原问题:/&\w/g 先执行,(&V) 中的 &V 被移除,剩余空括号 (), 后续 /\(&\w\)/g 无法匹配,导致"使用 Visual Studio 打开()"。 修复: 1. 调整顺序:/\(&\w\)/g 先于 /&\w/g 执行,整体匹配移除 (&V) 2. 新增 /\(\s*\)/g 空括号兜底,防止顺序问题遗留 3. 补充测试:覆盖 VS Code 打开、个性化、QQ 音乐三个典型场景 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PowerShellBridge: Resolve-ExtName 在 LocalizedString 与 CLSID Default 之间插入 Level 1.5 MUIVerb,修复 gvim 等扩展名称退化问题;同时读取 InprocServer32 DLL 路径并展开环境变量后输出 dllPath 字段 - RegistryService: PsMenuItemRaw 新增 dllPath 字段,getMenuItems 映射时透传 - shared/types: MenuItemEntry 新增 dllPath?: string | null - mainPage: ShellExt 详情面板拆为"COM 标识符"+ 可选"提供程序 DLL"两行 - 补充 PowerShellBridge/RegistryService 单元测试(共 9 个新用例) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
**核心 bug 修复**
当 handler 键名为 CLSID 格式而 Default 值为非 CLSID 字符串时(如
{90AA3A4E...} 的 Default = "Taskband Pin"),旧代码将 Default 值误用
作 $clsid 传入 Resolve-ExtName,导致 CLSID 正则匹配失败,名称退化为键名。
修复:引入 $actualClsid(键名优先为 CLSID)和 $directName(非 CLSID
Default 值)分离变量,$actualClsid 用于注册表查找和 command 字段输出,
$directName 作为 Resolve-ExtName Level 0 直接名称。
**移除 friendlyNames 硬编码映射表**
原映射表包含中文硬编码字符串('发送到'、'复制到文件夹'等),在 Level 0
优先级最高,屏蔽了 SHLoadIndirectString 的本地化机制,导致非中文系统
显示错误名称。移除后,Level 1 LocalizedString → SHLoadIndirectString
自动按系统语言返回正确本地化名称。
**新增 ms-resource: URI 支持**
- CmHelper.ResolveIndirect 扩展入口过滤,允许 ms-resource: 前缀通过
- LocalizedString、MUIVerb、directName 的 StartsWith 检查同步扩展
- Windows 11 MSIX 封装扩展的裸 ms-resource:// URI 不再作为原始字符串
返回,而是先尝试 SHLoadIndirectString 解析,失败则静默降级
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Level 0 重构:directName 仅处理间接格式(@dll,-id / ms-resource:), 普通字符串降级至 Level 3,避免英文技术名抢占本地化结果 - Level 1.7:预建 CommandStore 反向索引,通过 ExplorerCommandHandler CLSID 反查 MUIVerb,支持 Taskband Pin 等 ImplementsVerbs 扩展 - Level 2.5:读取 InprocServer32 DLL 的 FileDescription/ProductName, 过滤泛型描述(shell extension、context menu 等)后作为兜底名称, 解决 YunShellExt 等第三方扩展无法显示中文产品名的问题 - Level 3:directName 普通字符串兜底,位于所有 CLSID 查询链之后 - 更新测试:调整两个已废弃测试名/断言,新增 Level 2.5 专项测试(共 28 个) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n names Add Test-IsGenericName function to centralize filtering of generic COM/shell descriptions. The function checks for patterns like "context menu", "class" suffix, and placeholders. Update all name resolution levels (1.5 MUIVerb, 2 CLSID Default, 2.5 DLL metadata) to use this common filter. Add corresponding test cases to verify the filtering behavior.
feat(utils): add shared escapeHtml utility function fix(backup): validate backup existence before deletion fix(ipc): handle closed window case in backup handlers perf(menu): implement scene preloading and request queuing test(history): add operation history service tests docs: add shell extension name resolution guide
Electron 不支持原生弹窗 API,新增 dialog.ts 工具模块封装 showPrompt / showConfirm / showAlert,使用 <dialog> 元素实现 自定义弹窗,backupPage 中所有弹窗调用已全部替换。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Resolve trivial conflict in script/task.ps1 (identical content). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
用 koffi FFI 直接调用 Windows API 替代内嵌 C# 编译 + 200 行 PS 解析脚本,消除三语言嵌套。核心变更: - 新增 Win32Shell.ts: koffi 封装 SHLoadIndirectString + GetFileVersionInfo - 新增 ShellExtNameResolver.ts: TypeScript 名称解析引擎(Level 0→3 回退链 + Test-IsGenericName Group A-D 过滤规则 + CommandStoreIndex) - 删除 buildCmHelperBlock(): 不再运行时编译 C# 源码 - 简化 PS 脚本: Classic Shell / ShellExt 均只返回原始注册表值 - 注册表缓存 + 依赖注入: resolver 通过构造函数注入,方便测试 mock Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- resolveIndirect 输出缓冲区类型从 'char16 *' 改为 'void *', 修复 koffi 无法正确传递 Buffer 地址导致 SHLoadIndirectString 失败 - getFileVersionInfo 新增 GetUserDefaultUILanguage 获取系统 UI 语言, Translation 表匹配项插入队首(修复始终返回英文名的问题) - readUInt16 指针运算改用 bigint 直接偏移(修复 64 位地址精度丢失) - ShellExtNameResolver 各 Level 增加 debug 日志,便于追踪解析路径 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- resolveIndirect 输出缓冲区从 Buffer.alloc 改为 koffi.alloc('char16')
+ koffi.decode,修复 Node.js Buffer 与 koffi 类型系统不兼容导致
SHLoadIndirectString 运行时失败
- Win32Shell 暴露 uiLanguage 属性(GetUserDefaultUILanguage)
- 新增 35 个标准 shell 动词翻译表(open→打开, edit→编辑, runas→以
管理员身份运行 等),作为 Classic/ShellExt 两路径的最后回退
- ShellExtNameResolver 构造函数接受 language 参数
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
实测 koffi.alloc('char16') + decode('str16') 在 Windows 上导致
进程崩溃 (exit 139 segfault)。根因是 koffi 2.16.1 的 str16 decode
对 char16 数组指针存在兼容性问题。
正确方案: Buffer.alloc(2048) + 'void *' 参数 + buf.toString('utf16le')
同时加固:
- Win32Shell 构造函数 try-catch koffi 初始化失败时降级 (koffiAvailable=false)
- RegistryService 逐条 try-catch 保护 resolver 调用,单条失败使用 cleanName
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
原 PS 脚本在构建 CommandStore 索引时同步解析了 @dll,-id 格式的 MUIVerb (通过 CmHelper.ResolveIndirect)。迁移到 TS 后存储了原始值 但 Level 1.7 查找时直接返回了 @shell32.dll,-37423 原始字符串。 修复后先调用 resolveIndirect 解析,如失败则让后续 Level 继续尝试。 案例: {a2a9545d-...} StartMenuPin 的 CommandStore MUIVerb 是 @shell32.dll,-37423 → resolveIndirect → "固定到"开始"屏幕" Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
核心问题: Level 1 LocalizedString 的 plain text 值(如 "Start Menu Pin")
是开发者硬编码的英文名,应在 CommandStore(Windows 本地化机制)之后查询。
新优先级:
Phase A: 间接格式 (@/ms-resource:) → resolveIndirect → 系统语言名称
Phase B: CommandStore 反向索引 → Windows 本地化名称
Phase C: Plain text 回退 → 开发者原始名称
...
Fallback
案例: {a2a9545d-...} StartMenuPin
旧: Level 1 plain → "Start Menu Pin" (英文) → 立即返回 ❌
新: Level 1 indirect (无) → Phase A skip
→ CommandStore → @shell32.dll,-xxxxx → resolveIndirect → 中文名 ✓
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 新增 IPC sys:diagnose 通道: 测试 SHLoadIndirectString + GetFileVersionInfo - Win32Shell 构造函数打印确认日志 (Initialized OK 或 FAILED) - settingsPage 新增隐藏诊断面板,点击按钮显示 koffi 状态 - CommandStoreIndex 新增 size getter 用于在 Electron 运行时验证 koffi FFI 是否正常工作。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- cmdStoreSize 从构造时快照改为 getter 函数,诊断面板显示实时值 - getMenuItems 输出 [ResolveTrace] 日志,记录每条 ShellExt 的 最终名称 + 所有原始注册表字段(便于追踪解析路径) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
koffi 运行时 out 参数返回 number 而非 [number,number] 元组, const [size] = ... 解构失败导致 Level 2.5 在所有 DLL 上报错: "TypeError: number X is not iterable" 修复: 所有 koffi out 参数调用改用 Array.isArray 兼容处理 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- fvResult size 可能是 BigInt,需 Number() 转后才能传入后续函数 - transLen/descLen/prodLen 同样做 Number() 转换 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Level 2 返回前调用 translateStandardVerb 尝试翻译已知英文名 - 新增 11 个常见 CLSID Default 英文名 → 中文翻译 包括: Start Menu Pin, Taskband Pin, Open With Context Menu Handler, Doubao Context Menu, Shell extensions for sharing 等 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PS 枚举 handler 时通过 [FileVersionInfo]::GetVersionInfo() 采集 dllFileDescription 字段,天然支持 UI 语言,零额外 PS 进程 - 删除 Win32Shell.getFileVersionInfo() 及所有 version.dll koffi FFI 代码(历经3次修复仍不稳定:解构失败/Expected N arguments) - Win32Shell 精简为仅 resolveIndirect + uiLanguage - ShellExtNameResolver Level 2.5 改用 dllFileDescription 字段 - 回退上一提交的硬编码 CLSID 翻译表(对照翻译不可扩展) - 保留标准谓词翻译表(open→打开等真正的 shell 动词) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PS 脚本额外采集 dllProductName(用户可见产品名,优于组件描述) - Level 2.5: FileDescription → ProductName 顺序尝试 - 新增 isUselessPlain 检查:DLL 描述等于 fallback 时跳过 (如 YunShellExt.dll FileDescription="YunShellExt" 被跳过) - ResolveTrace 增加 dllProd 字段 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CLSID → ProgID → HKCR\{ProgID}\(Default) → 应用程序名
优先级: CommandStore(1.7) 之后, Plain text(Phase C) 之前
案例: YunShellExt CLSID → ProgID "BaiduNetdisk.YunShellExt"
→ HKCR\BaiduNetdisk.YunShellExt\(Default) = "百度网盘"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- 新增 Shell Ext 完整解析链 (Phase A/B/C 三阶段 + 所有 Level) - 新增 DLL FileDescription/ProductName 采集说明 (PS FileVersionInfo) - 新增 Level 1.6 ProgID 解析链 - 新增 CommandStore 索引、标准动词翻译表、泛型名过滤 (Group A-D) - Win32Shell 移除已删除的 getFileVersionInfo,仅保留 resolveIndirect - 新增诊断与调试章节 (IPC diagnose + ResolveTrace 日志) - 更新数据结构 (PsRawClassicItem / PsRawShellExtItem 完整字段) - 更新代表案例表、性能优化、错误处理 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
所有 PowerShell 脚本前统一插入: [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 解决 PS 默认 UTF-16 LE 或系统代码页 (GBK) 输出与 Node.js execFile UTF-8 解码不匹配导致中文显示为乱码的问题。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
常规 sibling key 查找要求 cleanName 作为 shell verb 键名存在,
但 CLSID 格式的 cleanName (如 {a2a9545d-...}) 不会作为键名。
新增回退: 反向扫描 $shellPath 下所有 verb,查找其
CommandStateHandler 或 DelegateExecute 值等于当前 CLSID 的键,
读取其 MUIVerb。
案例: {a2a9545d-...} → pintostartscreen verb
CommandStateHandler = {a2a9545d-...}
MUIVerb = @shell32.dll,-XXXXX → resolveIndirect → 中文名
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- PS 脚本读取 CLSID\Shell\*\MUIVerb(COM 对象自身注册的 verb) - 反向扫描增加 ExplorerCommandHandler 匹配 (部分 verb 使用此值而非 CommandStateHandler 指向 CLSID) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tzzs
added a commit
that referenced
this pull request
May 10, 2026
* refactor(scripts): update worktree creation and permissions settings - Simplify Windows Terminal command for new tab in task.ps1 - Clean up and standardize permissions in settings.json * ci: 接入 release-please-action 自动化发布流程 - 新增 release-please-config.json:配置 node 发布类型、CHANGELOG 分段 - 新增 .release-please-manifest.json:版本基线 1.0.0 - 新增 .github/workflows/release-please.yml: * release-please job:push 到 master 时自动创建/更新 Release PR * build-and-upload job:Release PR 合并后构建 Windows 安装包并上传到 GitHub Release - 移除 ci.yml 中的 release-check job(已由 build-and-upload 替代) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Shell 扩展名称解析重构 + 国际化 + 主题系统 + Dialog 弹窗 (#11) * docs: 将 AGENTS.md 翻译为中文 - 完整翻译所有章节为简体中文 - 添加测试命令详细说明 - 补充 TypeScript 严格模式配置 feat: 添加 PowerShell 脚本工具 - cleanup.ps1: 清理脚本 - task.ps1: 任务管理脚本 * refactor(scripts): update worktree creation and permissions settings - Simplify Windows Terminal command for new tab in task.ps1 - Clean up and standardize permissions in settings.json * chore: update claude settings with additional file permissions * fix(registry): 修复 Shell 扩展名称错误解析,新增 MUIVerb 支持 **根本原因** buildGetShellExtItemsScript 的 Level 3 DLL 字符串扫描(范围 1-500) 会命中与菜单项无关的资源字符串,导致 DesktopSlideshow 等条目显示 "在我的电池需要替换时发出警告"等错误名称。 **变更内容** - PowerShellBridge: 移除 Level 3 DLL 字符串暴力扫描(ReadDllStrings), CmHelper C# 源码同步精简(移除 LoadLibraryEx / FreeLibrary / LoadString P/Invoke) - PowerShellBridge: Level 2 扩展为遍历 FileDescription / ProductName / InternalName / OriginalFilename 四个 VersionInfo 字段 - PowerShellBridge: 原 Level 4(CLSID Default 值)晋升为 Level 3 兜底 - PowerShellBridge: buildGetItemsScript 新增 CmShell Add-Type + Resolve-MenuName, 经典菜单项名称读取优先级改为 MUIVerb → (Default) → 子键名, 支持 @dll,-id 格式的间接字符串解析 - RegistryService: 新增缓存支持(RegistryCache),getMenuItems 优先读缓存, enable/disable 操作后自动失效对应场景缓存 - RegistryService: 名称兜底层 —— 若 PS 返回以 @ 开头的未解析字符串, 自动替换为 subKeyName **单元测试** - PowerShellBridge.test.ts: 新增 12 个用例,覆盖 MUIVerb、CmShell、 Level 3 移除、InternalName/OriginalFilename、CLSID Default 升级等 - RegistryService.test.ts: 新增 5 个用例,覆盖 @ 前缀名称净化场景 (含 DesktopSlideshow 问题复现验证) - MenuManagerService.test.ts: 修复预存 mock 缺失(invalidateCache、log.debug) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(ps): 简化 Shell 扩展名称解析,移除 DLL VersionInfo 层 - buildGetShellExtItemsScript 从四级降为三级策略 Level 1: LocalizedString(@ 格式或直接值,过滤泛型 COM 类型描述) Level 2: CLSID 默认值 Level 3: 处理程序键名(最终兜底) - Format-DisplayName 移除大小写规范化和热键清理(热键已迁至 TS 层) - buildGetItemsScript 新增 LocalizedDisplayName 第三优先级 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(main-page): 修复场景切换竞态条件,新增 pendingScene 队列 加载期间快速切换场景时,后续请求不再被丢弃,而是记录为 pendingScene,前一次加载完成后立即执行最新的待切换场景。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(registry): 修复 cleanDisplayName 正则顺序,修复括号加速键残留括号问题 原问题:/&\w/g 先执行,(&V) 中的 &V 被移除,剩余空括号 (), 后续 /\(&\w\)/g 无法匹配,导致"使用 Visual Studio 打开()"。 修复: 1. 调整顺序:/\(&\w\)/g 先于 /&\w/g 执行,整体匹配移除 (&V) 2. 新增 /\(\s*\)/g 空括号兜底,防止顺序问题遗留 3. 补充测试:覆盖 VS Code 打开、个性化、QQ 音乐三个典型场景 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(shellex): 新增 MUIVerb 解析层与 InprocServer32 DLL 路径展示 - PowerShellBridge: Resolve-ExtName 在 LocalizedString 与 CLSID Default 之间插入 Level 1.5 MUIVerb,修复 gvim 等扩展名称退化问题;同时读取 InprocServer32 DLL 路径并展开环境变量后输出 dllPath 字段 - RegistryService: PsMenuItemRaw 新增 dllPath 字段,getMenuItems 映射时透传 - shared/types: MenuItemEntry 新增 dllPath?: string | null - mainPage: ShellExt 详情面板拆为"COM 标识符"+ 可选"提供程序 DLL"两行 - 补充 PowerShellBridge/RegistryService 单元测试(共 9 个新用例) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(shellex): 修复 CLSID 键名条目名称退化问题,移除硬编码映射表,支持 ms-resource: **核心 bug 修复** 当 handler 键名为 CLSID 格式而 Default 值为非 CLSID 字符串时(如 {90AA3A4E...} 的 Default = "Taskband Pin"),旧代码将 Default 值误用 作 $clsid 传入 Resolve-ExtName,导致 CLSID 正则匹配失败,名称退化为键名。 修复:引入 $actualClsid(键名优先为 CLSID)和 $directName(非 CLSID Default 值)分离变量,$actualClsid 用于注册表查找和 command 字段输出, $directName 作为 Resolve-ExtName Level 0 直接名称。 **移除 friendlyNames 硬编码映射表** 原映射表包含中文硬编码字符串('发送到'、'复制到文件夹'等),在 Level 0 优先级最高,屏蔽了 SHLoadIndirectString 的本地化机制,导致非中文系统 显示错误名称。移除后,Level 1 LocalizedString → SHLoadIndirectString 自动按系统语言返回正确本地化名称。 **新增 ms-resource: URI 支持** - CmHelper.ResolveIndirect 扩展入口过滤,允许 ms-resource: 前缀通过 - LocalizedString、MUIVerb、directName 的 StartsWith 检查同步扩展 - Windows 11 MSIX 封装扩展的裸 ms-resource:// URI 不再作为原始字符串 返回,而是先尝试 SHLoadIndirectString 解析,失败则静默降级 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(shellex): 新增 Resolve-ExtName Level 1.7/2.5/3 名称解析层 - Level 0 重构:directName 仅处理间接格式(@dll,-id / ms-resource:), 普通字符串降级至 Level 3,避免英文技术名抢占本地化结果 - Level 1.7:预建 CommandStore 反向索引,通过 ExplorerCommandHandler CLSID 反查 MUIVerb,支持 Taskband Pin 等 ImplementsVerbs 扩展 - Level 2.5:读取 InprocServer32 DLL 的 FileDescription/ProductName, 过滤泛型描述(shell extension、context menu 等)后作为兜底名称, 解决 YunShellExt 等第三方扩展无法显示中文产品名的问题 - Level 3:directName 普通字符串兜底,位于所有 CLSID 查询链之后 - 更新测试:调整两个已废弃测试名/断言,新增 Level 2.5 专项测试(共 28 个) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(PowerShellBridge): add generic name filtering for shell extension names Add Test-IsGenericName function to centralize filtering of generic COM/shell descriptions. The function checks for patterns like "context menu", "class" suffix, and placeholders. Update all name resolution levels (1.5 MUIVerb, 2 CLSID Default, 2.5 DLL metadata) to use this common filter. Add corresponding test cases to verify the filtering behavior. * refactor(registry): improve menu item resolution and caching feat(utils): add shared escapeHtml utility function fix(backup): validate backup existence before deletion fix(ipc): handle closed window case in backup handlers perf(menu): implement scene preloading and request queuing test(history): add operation history service tests docs: add shell extension name resolution guide * refactor(renderer): 用 HTML5 <dialog> 替代原生 prompt/confirm/alert Electron 不支持原生弹窗 API,新增 dialog.ts 工具模块封装 showPrompt / showConfirm / showAlert,使用 <dialog> 元素实现 自定义弹窗,backupPage 中所有弹窗调用已全部替换。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(shellex): 将 Shell 扩展名称解析从 PS/C# 迁移到 TypeScript/koffi 用 koffi FFI 直接调用 Windows API 替代内嵌 C# 编译 + 200 行 PS 解析脚本,消除三语言嵌套。核心变更: - 新增 Win32Shell.ts: koffi 封装 SHLoadIndirectString + GetFileVersionInfo - 新增 ShellExtNameResolver.ts: TypeScript 名称解析引擎(Level 0→3 回退链 + Test-IsGenericName Group A-D 过滤规则 + CommandStoreIndex) - 删除 buildCmHelperBlock(): 不再运行时编译 C# 源码 - 简化 PS 脚本: Classic Shell / ShellExt 均只返回原始注册表值 - 注册表缓存 + 依赖注入: resolver 通过构造函数注入,方便测试 mock Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): 修复 resolveIndirect FFI 类型错误与 DLL 语言优先排序 - resolveIndirect 输出缓冲区类型从 'char16 *' 改为 'void *', 修复 koffi 无法正确传递 Buffer 地址导致 SHLoadIndirectString 失败 - getFileVersionInfo 新增 GetUserDefaultUILanguage 获取系统 UI 语言, Translation 表匹配项插入队首(修复始终返回英文名的问题) - readUInt16 指针运算改用 bigint 直接偏移(修复 64 位地址精度丢失) - ShellExtNameResolver 各 Level 增加 debug 日志,便于追踪解析路径 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): resolveIndirect 改用 koffi.alloc + 新增标准谓词翻译表 - resolveIndirect 输出缓冲区从 Buffer.alloc 改为 koffi.alloc('char16') + koffi.decode,修复 Node.js Buffer 与 koffi 类型系统不兼容导致 SHLoadIndirectString 运行时失败 - Win32Shell 暴露 uiLanguage 属性(GetUserDefaultUILanguage) - 新增 35 个标准 shell 动词翻译表(open→打开, edit→编辑, runas→以 管理员身份运行 等),作为 Classic/ShellExt 两路径的最后回退 - ShellExtNameResolver 构造函数接受 language 参数 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): 回退 koffi.alloc → Buffer.alloc,修复 decode('str16') segfault 实测 koffi.alloc('char16') + decode('str16') 在 Windows 上导致 进程崩溃 (exit 139 segfault)。根因是 koffi 2.16.1 的 str16 decode 对 char16 数组指针存在兼容性问题。 正确方案: Buffer.alloc(2048) + 'void *' 参数 + buf.toString('utf16le') 同时加固: - Win32Shell 构造函数 try-catch koffi 初始化失败时降级 (koffiAvailable=false) - RegistryService 逐条 try-catch 保护 resolver 调用,单条失败使用 cleanName Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): CommandStore Level 1.7 间接 MUIVerb 未解析导致英文名 原 PS 脚本在构建 CommandStore 索引时同步解析了 @dll,-id 格式的 MUIVerb (通过 CmHelper.ResolveIndirect)。迁移到 TS 后存储了原始值 但 Level 1.7 查找时直接返回了 @shell32.dll,-37423 原始字符串。 修复后先调用 resolveIndirect 解析,如失败则让后续 Level 继续尝试。 案例: {a2a9545d-...} StartMenuPin 的 CommandStore MUIVerb 是 @shell32.dll,-37423 → resolveIndirect → "固定到"开始"屏幕" Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): 调整解析优先级 — CommandStore 优先于 plain text 核心问题: Level 1 LocalizedString 的 plain text 值(如 "Start Menu Pin") 是开发者硬编码的英文名,应在 CommandStore(Windows 本地化机制)之后查询。 新优先级: Phase A: 间接格式 (@/ms-resource:) → resolveIndirect → 系统语言名称 Phase B: CommandStore 反向索引 → Windows 本地化名称 Phase C: Plain text 回退 → 开发者原始名称 ... Fallback 案例: {a2a9545d-...} StartMenuPin 旧: Level 1 plain → "Start Menu Pin" (英文) → 立即返回 ❌ 新: Level 1 indirect (无) → Phase A skip → CommandStore → @shell32.dll,-xxxxx → resolveIndirect → 中文名 ✓ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(diagnose): 添加 koffi FFI 运行时诊断通道 - 新增 IPC sys:diagnose 通道: 测试 SHLoadIndirectString + GetFileVersionInfo - Win32Shell 构造函数打印确认日志 (Initialized OK 或 FAILED) - settingsPage 新增隐藏诊断面板,点击按钮显示 koffi 状态 - CommandStoreIndex 新增 size getter 用于在 Electron 运行时验证 koffi FFI 是否正常工作。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(diagnose): cmdStoreSize 改为实时查询 + 新增逐条解析追踪日志 - cmdStoreSize 从构造时快照改为 getter 函数,诊断面板显示实时值 - getMenuItems 输出 [ResolveTrace] 日志,记录每条 ShellExt 的 最终名称 + 所有原始注册表字段(便于追踪解析路径) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): 修复 getFileVersionInfo koffi out 参数解构崩溃 koffi 运行时 out 参数返回 number 而非 [number,number] 元组, const [size] = ... 解构失败导致 Level 2.5 在所有 DLL 上报错: "TypeError: number X is not iterable" 修复: 所有 koffi out 参数调用改用 Array.isArray 兼容处理 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): koffi out 参数 Number 强转 + "Expected N arguments" 修复 - fvResult size 可能是 BigInt,需 Number() 转后才能传入后续函数 - transLen/descLen/prodLen 同样做 Number() 转换 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): Level 2 CLSID Default 英文名查翻译表 + 扩充常见英文名 - Level 2 返回前调用 translateStandardVerb 尝试翻译已知英文名 - 新增 11 个常见 CLSID Default 英文名 → 中文翻译 包括: Start Menu Pin, Taskband Pin, Open With Context Menu Handler, Doubao Context Menu, Shell extensions for sharing 等 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor(shellex): DLL FileDescription 从 koffi FFI 改为 PS 内联采集 - PS 枚举 handler 时通过 [FileVersionInfo]::GetVersionInfo() 采集 dllFileDescription 字段,天然支持 UI 语言,零额外 PS 进程 - 删除 Win32Shell.getFileVersionInfo() 及所有 version.dll koffi FFI 代码(历经3次修复仍不稳定:解构失败/Expected N arguments) - Win32Shell 精简为仅 resolveIndirect + uiLanguage - ShellExtNameResolver Level 2.5 改用 dllFileDescription 字段 - 回退上一提交的硬编码 CLSID 翻译表(对照翻译不可扩展) - 保留标准谓词翻译表(open→打开等真正的 shell 动词) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): Level 2.5 增加 ProductName 回退 + 过滤等于 fallback 的描述 - PS 脚本额外采集 dllProductName(用户可见产品名,优于组件描述) - Level 2.5: FileDescription → ProductName 顺序尝试 - 新增 isUselessPlain 检查:DLL 描述等于 fallback 时跳过 (如 YunShellExt.dll FileDescription="YunShellExt" 被跳过) - ResolveTrace 增加 dllProd 字段 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * feat(shellex): 新增 Level 1.6 ProgID 解析链 CLSID → ProgID → HKCR\{ProgID}\(Default) → 应用程序名 优先级: CommandStore(1.7) 之后, Plain text(Phase C) 之前 案例: YunShellExt CLSID → ProgID "BaiduNetdisk.YunShellExt" → HKCR\BaiduNetdisk.YunShellExt\(Default) = "百度网盘" Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs: 全面更新 context-menu-parsing-logic.md 与当前实现对齐 - 新增 Shell Ext 完整解析链 (Phase A/B/C 三阶段 + 所有 Level) - 新增 DLL FileDescription/ProductName 采集说明 (PS FileVersionInfo) - 新增 Level 1.6 ProgID 解析链 - 新增 CommandStore 索引、标准动词翻译表、泛型名过滤 (Group A-D) - Win32Shell 移除已删除的 getFileVersionInfo,仅保留 resolveIndirect - 新增诊断与调试章节 (IPC diagnose + ResolveTrace 日志) - 更新数据结构 (PsRawClassicItem / PsRawShellExtItem 完整字段) - 更新代表案例表、性能优化、错误处理 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(ps): PS 输出强制 UTF-8 编码,修复中文乱码 所有 PowerShell 脚本前统一插入: [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 解决 PS 默认 UTF-16 LE 或系统代码页 (GBK) 输出与 Node.js execFile UTF-8 解码不匹配导致中文显示为乱码的问题。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): Level 1.3 反向扫描 CommandStateHandler/DelegateExecute 常规 sibling key 查找要求 cleanName 作为 shell verb 键名存在, 但 CLSID 格式的 cleanName (如 {a2a9545d-...}) 不会作为键名。 新增回退: 反向扫描 $shellPath 下所有 verb,查找其 CommandStateHandler 或 DelegateExecute 值等于当前 CLSID 的键, 读取其 MUIVerb。 案例: {a2a9545d-...} → pintostartscreen verb CommandStateHandler = {a2a9545d-...} MUIVerb = @shell32.dll,-XXXXX → resolveIndirect → 中文名 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(shellex): 新增 CLSID\Shell 子键 MUIVerb + 反向扫描增加 ExplorerCommandHandler - PS 脚本读取 CLSID\Shell\*\MUIVerb(COM 对象自身注册的 verb) - 反向扫描增加 ExplorerCommandHandler 匹配 (部分 verb 使用此值而非 CommandStateHandler 指向 CLSID) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
<dialog>替代 Electron 不支持的 prompt/confirm/alertTest plan
🤖 Generated with Claude Code