Skip to content

fix(windows): NSIS 安装包注册 TSF DLL + local-asr RAM 真正归还#279

Merged
appergb merged 3 commits into
mainfrom
fix/local-asr-release-flow
May 6, 2026
Merged

fix(windows): NSIS 安装包注册 TSF DLL + local-asr RAM 真正归还#279
appergb merged 3 commits into
mainfrom
fix/local-asr-release-flow

Conversation

@appergb
Copy link
Copy Markdown
Collaborator

@appergb appergb commented May 6, 2026

User description

Summary

1.2.20 发版候选,包含两个修复:

1. 修 Windows TSF 输入法显示「不可用」(NEW)

  • 现象:1.2.15 起 NSIS / updater 走的版本,Settings 页"Windows 输入法后端"显示「不可用」。
  • 根因:NSIS 包既不打包 OpenLessIme.dll(wxs.componentRefs 是 MSI-only),也没 hook 跑 regsvr32 → 用 setup.exe 安装的、走 updater 升级的存量用户全部命中。MSI 才有 RegisterOpenLessIme* CustomAction。
  • 修复
    • installer.nsh PostInstall/PreUninstall hook 跑 regsvr32
    • bundle.resources 把 dll 拷到 `$INSTDIR\tsf-ime\OpenLessIme.dll`(避开 wxs 已用的 `windows-ime\x64\` 路径以免 MSI 冲突)
    • `bundle.windows.nsis.installMode = "perMachine"` 让 NSIS 以管理员身份运行(写 HKLM 必需)
    • CI 用真 dll 覆盖仓库占位;mac/Linux build 用 `--config '{"bundle":{"resources":{}}}'` 跳过 Windows-only resources

2. 切走 / 删模型 / 手动释放时真正归还本地 ASR RAM

463a6d9 commit message。

Trade-off

  • NSIS perMachine 升级会触发 UAC,老 currentUser 用户首次升级多一次提示
  • MSI 包里 dll 有两份(wxs File + bundle.resources),磁盘冗余几百 KB,无功能影响

Test plan

  • CI Windows pass:MSI / NSIS bundle 都成功,updater artifact 齐
  • CI macOS pass:DMG 干净(无 0 字节占位 dll 进入 .app)
  • CI Linux pass:deb / rpm / AppImage 不带 dll 占位
  • 真机 Windows:NSIS setup.exe 安装 → Settings 页"Windows 输入法后端"显示"已安装"
  • 真机 Windows:NSIS 卸载后注册表 `HKLM\Software\Classes\CLSID\{6B9F3F4F-...}` 已清理
  • 真机 Windows:本地 ASR 切走/删模型后 RAM 实际归还

影响范围

  • 不是这次发版的回归 — TSF 不可用问题自 1.2.15 起一直存在,1.2.16~1.2.19 都受影响
  • 升 1.2.20 后所有 Windows 用户首次升级一次 UAC,之后 Pill 显示"已安装"

PR Type

Bug fix, Enhancement


Description

  • Register TSF DLLs in NSIS

  • Package payloads under tsf-ime

  • Copy real DLLs during release

  • Skip placeholder DLLs on mac/Linux


Diagram Walkthrough

flowchart LR
  A["Release CI builds DLLs"] --> B["Copy DLLs into payload paths"]
  B --> C["Tauri bundle resources"]
  C --> D["NSIS installer hooks"]
  D --> E["Register TSF in HKLM"]
  C --> F["mac/Linux builds skip resources"]
Loading

File Walkthrough

Relevant files
Configuration changes
build-mac.sh
Override Tauri resources for mac builds                                   

openless-all/app/scripts/build-mac.sh

  • Adds --config '{"bundle":{"resources":{}}}' to tauri build.
  • Prevents 0-byte Windows DLL placeholders from entering .app.
  • Preserves updater artifact config when signing is enabled.
+3/-1     
release-tauri.yml
Copy built DLLs into bundle payloads                                         

.github/workflows/release-tauri.yml

  • Copies compiled Windows DLLs into
    src-tauri/openless-ime-payload/{x64,x86}.
  • Ensures bundle resources contain real DLLs instead of placeholders.
  • Overrides bundle.resources to {} for Linux packaging.
+15/-2   
tauri.conf.json
Add TSF payload resources and NSIS hooks                                 

openless-all/app/src-tauri/tauri.conf.json

  • Maps payload DLLs into tsf-ime/x64 and tsf-ime/x86.
  • Sets NSIS install mode to perMachine for HKLM access.
  • Registers installer.nsh as the NSIS installer hook.
+8/-0     
Bug fix
installer.nsh
Register OpenLess TSF DLLs during install                               

openless-all/app/src-tauri/installer.nsh

  • Adds NSIS post-install regsvr32 calls for x64 and x86 DLLs.
  • Adds pre-uninstall unregistration for both DLL variants.
  • Documents WOW64 redirection and non-blocking failure handling.
+52/-0   

## 现象
1.2.15 起在 Settings 页"Windows 输入法后端"出现 Pill「不可用」。`get_windows_ime_status()`
查 HKLM 注册表四件套(COM CLSID + TSF LanguageProfile + 三个 Category),缺一即报 NotInstalled。

## 根因
- MSI 通过 wix/openless-ime.wxs 的 RegisterOpenLessIme* CustomAction 跑 regsvr32 → 注册齐全。
- NSIS 包既没把 OpenLessIme.dll 打进去(wxs.componentRefs 是 MSI-only),也没 hook 跑
  regsvr32 → 用 setup.exe 安装的用户、走 updater 自动升级的存量用户全部命中"不可用"。
- 由于 updater latest-windows-x86_64.json 是 NSIS pass 写的,老 MSI 用户每次更新后也
  会被替换为没 TSF 的 NSIS 版本。

## 修复
- 加 src-tauri/installer.nsh:NSIS_HOOK_POSTINSTALL/PREUNINSTALL 跑 regsvr32 注册/反注册。
- bundle.resources map 把 OpenLessIme.dll 拷贝到 $INSTDIR\tsf-ime\OpenLessIme.dll
  (target 路径避开 wxs File 已声明的 windows-ime\x64\,避免 MSI component 路径冲突)。
- bundle.windows.nsis.installMode = "perMachine",让 NSIS 以管理员身份运行(写 HKLM 必需)。
- CI 在 build native dll 后把真 dll 复制到 src-tauri/openless-ime-payload/x64/OpenLessIme.dll;
  仓库 commit 0 字节占位文件,让本地 mac 端 tauri build 也能 resolve resources 路径。
- build-mac.sh 与 Linux build 步骤加 --config '{"bundle":{"resources":{}}}' 跳过 Windows-only
  的 dll 占位,避免污染 mac .app / Linux .deb/.rpm/.AppImage。

## Trade-off
- NSIS perMachine 升级需要 UAC,老 currentUser 用户首次升级时多一次 UAC 提示。
- MSI 包里 dll 会有两份(wxs File + bundle.resources),磁盘冗余 ~几百 KB,无功能影响。
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5aec74653b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"icons/icon.ico"
],
"resources": {
"openless-ime-payload/x64/OpenLessIme.dll": "tsf-ime/OpenLessIme.dll"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Register the 32-bit TSF DLL for NSIS installs

For NSIS/updater installs this resource map only packages the x64 DLL, and the new hook only runs regsvr32 against that one file. However inspect_windows_ime_registration() explicitly requires both the 64-bit COM key and the WOW64 32-bit COM key (KEY_WOW64_32KEY) before reporting the backend as installed, matching the MSI flow that registers both OpenLessImeDllX64 and OpenLessImeDllX86. As a result, users installed via NSIS will still see the Windows IME backend as broken/not available with “OpenLess 32-bit COM registration is missing,” so the intended fix does not take effect for the updater path.

Useful? React with 👍 / 👎.

Codex review 发现:windows_ime_profile.rs::inspect_windows_ime_registration() 同时
用 KEY_WOW64_64KEY 和 KEY_WOW64_32KEY 两次检查 HKLM\Software\Classes\CLSID\{...}\
InprocServer32,少了任一边就返回 RegistrationBroken("OpenLess 32-bit COM
registration is missing")。MSI 流程通过 wxs 同时跑了 64-bit 和 SysWOW64\regsvr32
注册两份;之前的 NSIS hook 只注册了 x64,所以 NSIS / updater 用户依然在 Settings
页看到「不可用」。

修复:
- bundle.resources 拆出 x64 / x86 两份 dll target;x64 → tsf-ime\x64,x86 → tsf-ime\x86
- installer.nsh PostInstall/PreUninstall 增加 x86 分支,
  x86 用 $WINDIR\SysWOW64\regsvr32.exe(写 KEY_WOW64_32KEY 必需)
- CI Build Windows IME native DLLs 步骤把复制 dll 移到循环里,x64 + x86 都覆盖
  仓库占位
- 仓库新增 0 字节 x86 占位 dll,让本地 mac/linux 构建也能 resolve resources
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 6, 2026

P1 review 已采纳:commit c52658b 把 x86 dll 也加入 bundle.resources + installer.nsh 用 SysWOW64\regsvr32 注册,让 inspect_windows_ime_registration() 两次 WOW64 校验都能通过。

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

PR Reviewer Guide 🔍

(Review updated until commit 81fa80d)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Persistent review updated to latest commit c52658b

NSIS installer 是 32-bit 进程,进程内的 $SYSDIR / $WINDIR\System32 都因
WOW64 文件系统重定向变成 $WINDIR\SysWOW64,跑的是 32-bit regsvr32 → x64 dll
被注册到 HKLM\Software\Wow6432Node\Classes\CLSID(KEY_WOW64_32KEY 视图)。
但 windows_ime_profile.rs 用 KEY_WOW64_64KEY 校验时只看 HKLM\Software\Classes
\CLSID,永远查不到 → 仍判 RegistrationBroken("OpenLess COM registration is
missing")。

修复:x64 改用 $WINDIR\Sysnative\regsvr32.exe — 这是 32-bit 进程访问真
64-bit System32 的专用 alias,写入会落在 KEY_WOW64_64KEY 视图。x86 保持
SysWOW64 不变(确实需要 32-bit regsvr32 写 Wow6432Node)。
@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 6, 2026

再修一刀(commit 81fa80d):NSIS installer 是 32-bit 进程,$SYSDIR 因 WOW64 重定向变成 SysWOW64,跑的是 32-bit regsvr32 → x64 dll 会被注册到 HKLM\Software\Wow6432Node 而非 64-bit 视图。改用 $WINDIR\Sysnative\regsvr32.exe(32-bit 进程访问真 64-bit System32 的专用 alias),让 KEY_WOW64_64KEY 校验也能通过。x86 保持 SysWOW64。

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Persistent review updated to latest commit 81fa80d

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 81fa80da69

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


!macro NSIS_HOOK_POSTINSTALL
DetailPrint "Registering OpenLess TSF IME (x64) ..."
nsExec::ExecToLog '"$WINDIR\Sysnative\regsvr32.exe" /s "$INSTDIR\tsf-ime\x64\OpenLessIme.dll"'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Point regsvr32 at the resources directory

For NSIS installs, Tauri places bundle.resources under $INSTDIR\resources\... (the Windows installer docs' hook example accesses bundled resources from $INSTDIR\resources\), not directly under $INSTDIR. With the new map target tsf-ime/x64/OpenLessIme.dll, this hook looks for a file that is actually installed as $INSTDIR\resources\tsf-ime\x64\OpenLessIme.dll (and the x86 line has the same issue), so both regsvr32 calls fail and are ignored; NSIS/updater users still end up without the TSF COM registration the change is trying to add.

Useful? React with 👍 / 👎.

@appergb
Copy link
Copy Markdown
Collaborator Author

appergb commented May 6, 2026

@codex 这次的 P1 我判定为误报,不修代码。证据:

  1. Tauri NSIS template (v2.10.1) 源码明确

    • crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi:616SetOutPath $INSTDIR
    • installer.nsi:632 渲染成 File /a "/oname={{this.[1]}}"this.[1] 直接是 map 的 target,没有 resources\ 前缀
    • mod.rs:783 target_path 来自用户配置原样,不加前缀
  2. 文档里的 $INSTDIR\resources\ 例子是 array form["./resources/vc_redist.x64.msi"]),那种情况下 target = source 原始路径,所以装到 $INSTDIR\resources\...。我用的是 map form,target 直接控制安装位置:

    "resources": {
      "openless-ime-payload/x64/OpenLessIme.dll": "tsf-ime/x64/OpenLessIme.dll"
    }
  3. Tauri 2 schema 描述也确认:array form preserves directory structure,map form 是用户精确控制。

所以 dll 实际安装到 $INSTDIR\tsf-ime\x64\OpenLessIme.dll / $INSTDIR\tsf-ime\x86\OpenLessIme.dll,与 hook 中 regsvr32 的路径一致。

@chatgpt-codex-connector
Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@appergb appergb merged commit b84b0bd into main May 6, 2026
2 checks passed
appergb added a commit that referenced this pull request May 6, 2026
chore(release-prep): 清理 #268/#279 双 NSIS 方案残留
H-Chris233 pushed a commit to H-Chris233/openless that referenced this pull request May 6, 2026
main 上 Open-Less#268 (millionart/codex/register-windows-ime-nsis-installer) 与 Open-Less#279
(本人) 都修了 NSIS 注册 TSF DLL,merge Open-Less#279 时未手动解决冲突,导致:

1. tauri.conf.json 出现两个 windows.nsis block(line 92-95 和 105-108),
   serde_json 用最后写入的覆盖前面,结果 Open-Less#268 的 nsis/openless-ime-hooks.nsh
   被丢弃,实际生效的是 Open-Less#279 的 installer.nsh。
2. Open-Less#279 的 bundle.resources 把 dll 多打一份到 $INSTDIR\tsf-ime\,与 Open-Less#268
   PREINSTALL File 直接装到 $INSTDIR\windows-ime\ 并存。
3. installer.nsh 与 openless-ime-payload/ 残留为死代码。

Open-Less#268 方案更稳:x64 注册带 Sysnative + DisableX64FSRedirection 双保险,有
POSTUNINSTALL 清理 hook,有测试覆盖(4a7a1b6b/test、933e014a/test),且
不污染 MSI(不用 bundle.resources,避免 dll 重复)。

清理:
- 删除 tauri.conf.json 重复 nsis block,保留 nsis/openless-ime-hooks.nsh
- 删除 bundle.resources(Open-Less#268 不需要)
- 删除死文件 installer.nsh
- 删除死目录 openless-ime-payload/

release-tauri.yml 里"复制 dll 到 openless-ime-payload"步骤、build-mac.sh
与 Linux build 的 --config '{"bundle":{"resources":{}}}' override 暂留 —
没有 bundle.resources 后这些是 noop,不会破坏 build;当前 token 没有
workflow scope,等下一次有需求再清。
appergb pushed a commit that referenced this pull request May 6, 2026
主要修复
─────────
- fix(windows): NSIS 安装包注册 OpenLess TSF DLL(含 32-bit COM 注册到
  Wow6432Node + Sysnative 绕过 32-bit installer 的 WOW64 重定向);
  改 perMachine 安装让 regsvr32 能写 HKLM。修「Windows 输入法后端:不可用」
  自 1.2.15 起的长期 bug。
- fix(local-asr): 切走/删模型/手动释放时引擎真正归还 1+ GB RAM;下载稳定性
  4 次指数退避 + Range 分块 + 取消正确传播;点击下载即崩(tokio::spawn →
  tauri::async_runtime)。
- fix(tauri): Rust crate tauri 锁 ~2.10,避开 npm 端 @tauri-apps/api
  尚未发布 2.11 导致的跨 minor 版本检查 fail。
- fix(capsule): AudioBars 用 cubic-bezier 缓动 + 0.18s transition,圆点→
  长条形变在 60Hz audio level 高频更新下平滑混合,不再阶梯式跳变。
- fix(recorder): liveness watchdog + 全局超时;watchdog 从首次回调开始计时
  避免慢启动误报(issue #238)。
- fix(windows): hotkey trigger leak、capsule 视觉异常、音量计稳定(多 PR)。
- fix(credentials): 凭据状态按 active provider 判断。

新功能
─────────
- feat(asr): 本地 Qwen3-ASR-Flash 全链路 — 模型注册表、HF/HF-Mirror 4 并发
  分块下载、Settings → 模型设置页、Coordinator 第三分支接入。
- feat(i18n): 日本語 / 한국어 完整翻译(217 string × 2 语种)+ 5 locale
  在语言名后加 Beta 标识。
- feat(translation): 输出语言扩展为日 / 韩,与翻译链路解耦。
- feat(recording): 录音时静音系统输出,多会话共享 mute guard。
- feat(i18n): 繁體中文 UI 完整 + 简繁脚本随 UI 切换同步。
- feat(settings): 合并设置内外两个「关于」(QQ 群 / 反馈 / 源码 / 隐私
  全部并入弹窗的关于)+ 一键导出错误日志(plugin-dialog 选保存位置,
  跨 macOS / Windows)。

工程
─────────
- chore(ci): release-tauri.yml + ci.yml checkout 拉 submodule,修 mac 端
  qwen-asr build 缺源文件。
- chore(release-prep): 清理 #268/#279 双 NSIS 方案残留。
- chore(deps): 引入 tauri-plugin-dialog ~2 给前端 save dialog 用。
@appergb appergb deleted the fix/local-asr-release-flow branch May 6, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant