Open
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
8497846 to
c42d3aa
Compare
**根本原因** 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>
- 完整翻译所有章节为简体中文 - 添加测试命令详细说明 - 补充 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
用 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>
adc937e to
a04785a
Compare
…lidation - Remove RegistryCache from RegistryService; delegate caching to MenuManagerService - Replace MenuManagerService raw Map with RegistryCache instance (2min TTL) - Invalidate all cache layers on batch enable/disable operations - Remove unused affectedScenes collection in batch methods
Replace two separate inline type assertions with a single MainWindow interface.
- Test resolveClassicName fallback when indirect MUIVerb fails - Test Level 2.5 DLL name length boundary (>64 chars skipped) - Test Level 2.5 ProductName fallback when FileDescription is null
Replace the legacy CmHelper (C# runtime compilation) section with the current koffi FFI + PowerShell FileVersionInfo approach.
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.
问题
HKCR\DesktopBackground\shellex\ContextMenuHandlers\DesktopSlideshow在应用中显示"在我的电池需要替换时发出警告",与菜单项实际含义完全无关。根本原因:Level 3 DLL 字符串暴力扫描(范围 1-500)命中了 DLL 中与菜单无关的早期资源字符串。
变更内容
PowerShellBridge.ts
ReadDllStrings),CmHelper C# 源码同步精简(移除LoadLibraryEx/FreeLibrary/LoadStringP/Invoke)FileDescription/ProductName/InternalName/OriginalFilename四个 VersionInfo 字段(foreach 取第一个合法值)buildGetItemsScript新增CmShellAdd-Type +Resolve-MenuName函数,经典菜单项名称读取优先级改为 MUIVerb → (Default) → 子键名,支持@dll,-id格式间接字符串解析RegistryService.ts
RegistryCache缓存层,getMenuItems优先读缓存,enable/disable 操作后自动失效对应场景缓存@开头的未解析字符串,自动替换为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)验证方式
npm startDesktopSlideshow条目名称合理(键名或 VersionInfo 字段),不再显示"在我的电池需要替换时发出警告"测试结果
🤖 Generated with Claude Code