mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
修安装包卸载卡死的真凶: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 项全通过
套件新增一个阶段:「安装包完整周期」。
This commit is contained in:
+23
-1
@@ -320,11 +320,33 @@ begin
|
||||
Sleep(1200);
|
||||
end;
|
||||
|
||||
{ 卸载前先停掉正在跑的进程,不然文件删不干净。
|
||||
|
||||
三个参数缺一不可,每个都对应一个实测踩过的卡死/残留问题:
|
||||
|
||||
* 必须在这里做,**不能**改到 UninstallRun 区段去
|
||||
—— UninstallRun 是在文件都删完之后才跑的,
|
||||
那时候"停进程"已经没意义了(文件早没了)。
|
||||
|
||||
* 必须带 --keep-dir
|
||||
—— InitializeUninstall 在卸载器开始删文件**之前**执行。
|
||||
不带的话被控端会安排一个后台 rmdir 删安装目录,
|
||||
而卸载器紧接着也在删同一个目录 —— 两边抢文件**永久卡住**。
|
||||
|
||||
* 必须带 --quiet
|
||||
—— 卸载器是 runhidden 调的,进程没有控制台。
|
||||
被控端里的 attach_console() 会 AllocConsole + open("CONIN$"),
|
||||
在无控制台的隐藏进程里**永久阻塞**;input() 也因为没 stdin 卡住。
|
||||
实测卡住的进程只有 1 个线程、0.16 秒 CPU,就是停在这一步。
|
||||
--quiet 让它彻底不碰控制台,结果写进 uninstall.log。
|
||||
实测:不带 --quiet 无限卡住,带了 0.6 秒返回。
|
||||
}
|
||||
function InitializeUninstall(): Boolean;
|
||||
var
|
||||
ResultCode: Integer;
|
||||
begin
|
||||
Result := True;
|
||||
Exec(ExpandConstant('{app}\{#MyAppExeName}'), '--uninstall --keep-dir',
|
||||
Exec(ExpandConstant('{app}\{#MyAppExeName}'),
|
||||
'--uninstall --keep-dir --quiet',
|
||||
ExpandConstant('{app}'), SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user