Commit Graph
2 Commits
Author SHA1 Message Date
xmz7891 c7c0484a27 修安装包卸载卡死的真凶:attach_console 在无控制台时阻塞
排查过程(一步步排除,记录下来免得以后重踩):

  1. 现象:从控制面板卸载,进度条永远走不完。
  2. 先怀疑 input():安装器用 runhidden 调 --uninstall,没有 stdin,
     input() 会一直等。加了 isatty 保护 —— **没解决**。
  3. 再怀疑 Popen 没重定向 stdio:_schedule_self_delete 起的 cmd
     继承了父进程句柄,capture_output 会等管道 EOF。加了
     DEVNULL 重定向 —— **还是卡**。
  4. 又发现 _kill_running 用 taskkill /IM ykxmz.exe 把正在卸载的
     自己杀了(--uninstall 就跑在 ykxmz.exe 里),
     导致后面的"删自启/删数据"没执行。改成 /FI "PID ne self" ——
     自启能删了,**卸载仍然卡**。
  5. 最后看进程状态才定位:卡住的 ykxmz.exe 只有 **1 个线程、
     0.16 秒 CPU、19MB 内存** —— 明显停在启动早期,根本没干活。
     那就是 cli_uninstall 第一行的 attach_console():
     它对 --windowed 程序调 AllocConsole(),再 open("CONIN$")。
     在没有控制台的隐藏进程里,这一步**永久阻塞**。

修法:加 --quiet。安装包的卸载器用
      ykxmz.exe --uninstall --keep-dir --quiet
      --quiet 下完全不碰控制台(不 AllocConsole、不 input),
      结果写进 uninstall.log 供排查。
      实测:不带 --quiet 无限卡住;带了 **0.6 秒返回**。

顺带修的两处(也是实测发现的):
  * 安装器关不掉以管理员身份运行的旧实例 -> Inno 弹"无法关闭所有
    应用程序",静默下被压成"终止",**整个安装回滚**。
    改成 PrepareToInstall 里自己 taskkill /F。
  * 测试脚本把注册表路径写成 HKCU\...(少了冒号),
    PowerShell 静默返回空,"开机自启"永远误报失败。

最终实测(test_installer_cycle.py,20 项):
    静默安装   退出码 0,7.1 秒
    配对码     正确写入 C:\ProgramData\ykxmz\data\settings.json
    进程/端口  在跑,8765 监听
    开机自启   已设置
    静默卸载   1.2 秒
    卸载清理   安装目录 / 数据目录 / 注册表 / 进程 / 自启 全部干净
    20 项全通过

套件新增一个阶段:「安装包完整周期」。
2026-10-07 02:21:36 +08:00
xmz7891 df8056dd16 修四个安装/卸载卡死的 bug(都实测复现过)
1. 卸载里 input() 在无 stdin 时永久阻塞
   从控制面板卸载**永远卡住不结束**。安装包的 [UninstallRun]
   用 runhidden 调用,没有 stdin,input() 就一直等。
   改成只在 sys.stdin.isatty() 时才等回车。

2. Popen 没重定向子进程 stdio,导致 capture_output 等管道 EOF
   _schedule_self_delete 起的 cmd 继承了父进程的 stdout/stderr 句柄,
   任何用 capture_output 调 --uninstall 的地方都会一直等,
   表现为"程序卡死"(实测 90 秒不返回,改后 0.2 秒)。
   Popen 加 stdin/stdout/stderr=DEVNULL。
   顺带把延迟从 timeout 换成 ping —— timeout 在 DETACHED_PROCESS
   下没有控制台会立刻失败,等于没延迟直接删。

3. _kill_running 用 taskkill /IM ykxmz.exe 把**自己**杀了
   --uninstall 本身就跑在 ykxmz.exe 里,这条命令一发,
   后面的"删开机自启""删数据目录"全都没执行。
   现象:卸载看着完成了,HKCU 的自启注册表项还留着。
   改成 /FI "PID ne <self>" 排除自己。

4. 安装器关不掉以管理员身份运行的旧实例 -> 整个安装回滚
   Inno 自带机制只会"请求"对方退出,遇上常驻的服务进程关不掉,
   弹"无法自动关闭所有应用程序",静默模式下被压成"终止",
   安装直接回滚 —— 用户看到的是"装了没反应/还是旧版本"。
   改成 PrepareToInstall 里自己 taskkill /F,关掉 Inno 那套。

另外修了两个卸载残留:
   * 安装目录留个空壳 -> [UninstallDelete] 加 dirifempty
   * ProgramData\ykxmz 没删 -> 加进 [UninstallDelete]

还有一处 Inno 写法陷阱(踩了三次):
   注释里写 [区段名] 或 {常量} 会让编译直接失败,
   因为 [Code] 解析器连注释内容也处理。
   加了 _build/check_iss.py 专门扫这个,并进全量套件。

实测结果:
   静默安装  5 秒内退出,退出码 0,配对码正确写入,程序自动跑起来
   静默卸载  0.7 秒退出(原来无限卡住)
   全量回归  29 项全通过
   卸载逻辑  11 项全通过
2026-10-07 01:19:11 +08:00