Files

青简 Windows 安装包

用 Inno Setup 打的安装包,把 TSF DLL(64 位与 32 位各一份)、Server、设置程序与随包数据一起装进 C:\Program Files\Qingjian,注册文本服务,并设登录自启。对应 macOS 的 pkg。

安装布局

C:\Program Files\Qingjian\
    qingjian_tsf-<版本>.dll       TSF 文本服务(64 位;被加载进每个应用进程;按版本起名,见「升级」)
    qingjian_tsf-<版本>-x86.dll   同上的 32 位版(企业微信 / WPS / 32 位 QQ 这类 32 位应用只能加载它)
    qingjian-server.exe       输入内核 Server(跑在应用进程外)
    qingjian-settings.exe     设置程序(apps\settings,三平台共用,不依赖 Windows App Runtime)
    qingjian-settings-legacy.exe  旧版设置程序(WinUI,开始菜单「青简旧版设置」,留一个版本作回退)
    Microsoft.UI.Xaml.dll …   旧版设置程序自带的 Windows App Runtime(自包含部署,见下节;约 56 MB / 185 个文件)
    qingjian.ico              开始菜单 / 启动项快捷方式的图标(exe 里也嵌了一份)
    data\generated\           dict.qj / lm.qj / glossary-{en,ja,zh,es,vi}.qj / english.tsv / dicts\*.qj
    data\generated\codes\     随包辅码码表 stroke.qj + LICENSE-CNS11643.txt(tools\dict-convert 的 pack codes 生成)
    assets\                   emoji\ levels\ sample\

Server 与设置程序按 exe 相对定位随包资源(qingjian_platform::resources):装机时资源与 exe 同级, 开发时是仓库 ime\(exe 在 target\{debug,release}\ 下往上三层)。相对写法两套布局一致,只有根不同。

用户数据仍在 %APPDATA%\Qingjian(config.toml、密钥 .env、学习数据、统计),三个进程的日志在 %LOCALAPPDATA%\Qingjian\logs(server. / tsf. / settings. 前缀,按天,留 7 天); 卸载不动这些。输入法图标由 regsvr32 写到 %ProgramData%\Qingjian\qingjian.ico(DLL 里 include_bytes 内嵌单色深浅两版,按注册时任务栏深浅挑一版;之后 Server 启动与系统切深浅色时改写,任务栏在下次切换输入法时换过来。安装包给这个目录放开了普通用户写权限)。

安装程序做的几件事

  1. 结束旧进程:PrepareToInstall 里 taskkill Server 与两个设置程序(只有这几个 exe 要覆盖)。
  2. 应用容器权限:icacls 给安装目录加 ALL APPLICATION PACKAGES(SID *S-1-15-2-1)读+执行。 不加的话 UWP/AppContainer 应用(任务栏搜索、设置)读不到 DLL,切不到青简。
  3. 注册文本服务:64 位 DLL 用 regsvr32、32 位 DLL 用 SysWOW64\regsvr32,各注册一次(各自写进自己视图的 HKCR,CTF\TIP 两边共用;要管理员——安装程序本就提权)。
  4. 清旧 DLL:装完删历次版本留下的 qingjian_tsf*.dll,仍被应用占用的登记成重启后删(RestartReplace)。
  5. 登录自启:「启动」文件夹放 Server 快捷方式(Explorer 走 ShellExecute 拉起才拿到 uiAccess;计划任务拿不到)。
  6. 立即启动:完成页以当前非提升用户 ShellExecute 起一次 Server,装完就能用,不必先注销。

卸载反向:杀 Server / 设置程序 → 反注册当前版本 DLL → 删文件(占用中的 DLL 重启后删,[UninstallDelete] 兜住旧版本的)。

升级:DLL 被占用怎么办

qingjian_tsf.dll 被加载进每一个有文本框的应用进程,文件锁着覆盖不了;Inno 缺省的 CloseApplications 用 Restart Manager 找出所有占用者要求关闭——对输入法 DLL 就是「关掉一切」,所以关掉它(CloseApplications=no),改成:

  • DLL 按版本起名并排装(DestName: qingjian_tsf-<版本>.dll),新文件从不与旧文件撞名;
  • 只 regsvr32 新文件(InprocServer32 指向它)。不要对旧 DLL regsvr32 /u:那会把整个 CLSID / profile 注销掉;
  • 已开着的应用继续用进程里的旧 DLL 直到重启,Server 两个版本都服务(OpenSession 带协议版本,对不上只记警告);
  • 装完删旧 DLL,删不掉的登记成重启后删。

旧版设置程序自带 Windows App Runtime

旧版设置界面用 Windows Reactor(WinUI 3)写,而它的框架依赖引导只有 Windows 11 走得通:要 Windows 11 才有的 AppModel API 把框架包加进进程包图,Windows 10 上没有那两个函数(定位见 docs\notes\windows-win10.md)。 所以旧版设置程序用自包含部署——apps\windows\settings\build.rs 让 windows-reactor-setup 把 Windows App Runtime 铺到 target\release\,打包时按 settings-runtime.txt 挑进 target\installer\settings-runtime,本目录的 qingjian.iss 再整个目录装到 {app} 下、与 qingjian-settings-legacy.exe 同级。下个版本删掉旧版设置程序时,这一节、settings-runtime.txt 与运行时文件一起删。

  • 这些文件是运行时必需:少一件(或层级装错)设置窗口就起不来,build.ps1 发现缺文件会直接失败。
  • 升级 windows-reactor / windows-reactor-setup 时,照新版 crate 的 assets/runtime.txt 核对 settings-runtime.txt。
  • Server 与 TSF DLL 不依赖它;装机体积的大头仍是随包数据。
  • windows-reactor-setup 在 cargo build 时用系统 curl.exe 从 NuGet 下运行时包(无校验,失败只打印),缓存在 %LOCALAPPDATA%\windows-reactor-setup;CI 的 runner 每次都会重下一遍。下载失败的后果由 build.ps1 的缺项检查兜住。

打包(在编译机上)

# 需要 MSVC 工具链 + Inno Setup。数据取自仓库 data\generated 与 assets,打包前先确保 .qj 是最新的。
powershell -ExecutionPolicy Bypass -File apps\windows\installer\build.ps1

脚本 release 构建三个产物、从 apps\windows\server\Cargo.toml 读版本、找 ISCC.exe、编 qingjian.iss, 成品在 target\installer\qingjian-<版本>-windows-x86_64-setup.exe。改了数据 / 脚本但二进制没变时加 -SkipBuild;-Sign 用自签证书签产物 (uiAccess 要求 Server 签名 + 装 Program Files)。

也可手动:iscc /DAppVersion=0.1.0 apps\windows\installer\qingjian.iss。

注意

  • Inno 版本:开发机与 CI 统一用 Inno Setup 7.1.0(CI 从 jrsoftware/issrc 的 GitHub Release 钉死下载)。它自带简体中文翻译; 6.x 的安装包不带 Languages\ChineseSimplified.isl,Chocolatey 也只有 6.x,别用。ArchitecturesAllowed=x64compatible 需 6.3+。
  • 签名:发版证书就绪后在这里加 SignTool(对应 mac 的 Developer ID);开发期用 -Sign 的自签证书。
  • 没证书的包(CI 内测版):先设 $env:QINGJIAN_UIACCESS = '0' 再打,Server 不嵌 uiAccess——没签名的 exe 带 uiAccess=true 会起不来。 代价是候选窗在 UWP 宿主里可能被盖住。release.yml 的 windows job 就是这么打的。