# -*- coding: utf-8 -*- r'''重写安装包的"装完收尾"逻辑。 问题:CurStepChanged(ssPostInstall) 在这个 Inno 版本里**没被触发** (日志显示回调进了,CurStep=1,但 `CurStep <> ssPostInstall` 判断为真;而 Ord(ssPostInstall) 又报类型不匹配)。 结果 --code 从来没执行过,配对码永远是空的。 解决:不再依赖 CurStepChanged。改用 Inno 的标准做法 —— 把收尾命令放进 [Run] 段,配对码用 {code:Function} 取。 [Run] 里可以写 {code:GetPairingCode},Inno 会调用同名 Pascal 函数取值。 再加 Check: 函数决定这一条要不要跑(码为空就跳过)。 这样装完必然执行,不依赖任何步骤枚举。 ''' from __future__ import annotations import ast import sys from pathlib import Path ISS = (Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote") / "installer" / "ykxmz.iss") # ---------- 新的 [Run] 段 ---------- NEW_RUN = '''[Run] ; 收尾分三步,顺序很重要: ; 1. 写配对码(一次性命令,秒退) ; 2. 设开机自启(一次性命令) ; 3. 静默启动(常驻进程) ; ; 为什么不放在 CurStepChanged 里: ; 实测这个 Inno 版本的 ssPostInstall 回调**不会触发** ; (日志里回调进了、CurStep=1,但 CurStep <> ssPostInstall 成立), ; 放在那里 --code 永远不执行、配对码永远为空。 ; [Run] 段是安装完成后必然执行的,靠得住。 ; ; {code:GetPairingCode} 是 Inno 的写法:调用同名 Pascal 函数取值。 ; Check 函数返回 False 时这一条跳过(比如用户没填配对码)。 ; 1. 写配对码 Filename: "{app}\\{#MyAppExeName}"; Parameters: "--code {code:GetPairingCode}"; \\ Flags: runhidden; Check: HasPairingCode ; 2. 开机自启 Filename: "{app}\\{#MyAppExeName}"; Parameters: "--autostart on"; \\ Flags: runhidden; Tasks: autostart ; 3. 静默启动 ; skipifsilent 是因为静默安装走下面那条 cmd 版本 ; (直接起会挂在安装器的进程树上,见那条注释) Filename: "{app}\\{#MyAppExeName}"; Parameters: "--silent"; \\ Description: "立即启动(后台运行,不显示窗口)"; \\ Flags: nowait postinstall skipifsilent; Check: not WizardSilent ; 静默安装时也要跑起来。 ; 必须用 cmd /c start 起:直接 Exec 出来的进程是安装器的子进程, ; 而 Start-Process -Wait / start /wait / MSI 封装器都会等**整个进程树**, ; --silent 是常驻守护进程永远不退出,于是"安装脚本永远跑不完" ; (实测卡满 600 秒超时)。cmd /c start 会把它挂到别处,父进程一退就断干净。 Filename: "cmd.exe"; Parameters: "/c start """" ""{app}\\{#MyAppExeName}"" --silent"; \\ Flags: runhidden nowait; Check: WizardSilent ; 让用户看一眼装完须知 Filename: "{app}\\docs\\AFTER-INSTALL.txt"; \\ Description: "打开「安装后须知」"; \\ Flags: postinstall shellexec unchecked skipifsilent ''' # ---------- 新的 [Code] 收尾函数 ---------- NEW_FUNCS = ''' { ===== 给 [Run] 段用的取值 / 判断函数 ===== } { 配对码。空串时 Inno 不会展开,所以配 HasPairingCode 一起用。 } function GetPairingCode(Param: String): String; begin Result := EffectiveCode(); Diag('GetPairingCode -> "' + Result + '"'); end; { 有配对码才跑那条 --code 命令 } function HasPairingCode(): Boolean; begin Result := EffectiveCode() <> ''; Diag('HasPairingCode -> ' + IntToStr(Ord(Result))); end; { 非静默时才跑"立即启动"那条 } function NotWizardSilent(): Boolean; begin Result := not WizardSilent; end; ''' def main() -> int: text = ISS.read_text(encoding="utf-8") # 1) 换掉 [Run] 段(从 [Run] 到 [UninstallDelete] 之前) start = text.find("[Run]") end = text.find("[UninstallDelete]") if start < 0 or end < 0 or end < start: print(" [失败] 找不到 [Run] / [UninstallDelete]") return 1 text = text[:start] + NEW_RUN + "\n" + text[end:] print(" 已替换 [Run] 段") # 2) 在 [Code] 末尾追加三个函数 if "function GetPairingCode" not in text: text = text.rstrip() + "\n" + NEW_FUNCS print(" 已追加 GetPairingCode / HasPairingCode / NotWizardSilent") ISS.write_text(text, encoding="utf-8", newline="\n") # 语法自检(Python 层只能查文件可读) print() print(" [Run] 段现在:") run_start = text.find("[Run]") run_end = text.find("[UninstallDelete]") for line in text[run_start:run_end].splitlines(): if line.strip() and not line.strip().startswith(";"): print(" " + line[:88]) return 0 if __name__ == "__main__": sys.exit(main())