mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 13:40:45 +00:00
修四个安装/卸载卡死的 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 项全通过
This commit is contained in:
+25
-5
@@ -79,6 +79,10 @@ def parse_args(argv=None):
|
||||
help="查看中转连接状态")
|
||||
parser.add_argument("--uninstall", action="store_true",
|
||||
help="卸载:停进程、删开机自启、删数据目录")
|
||||
parser.add_argument("--keep-dir", action="store_true",
|
||||
help="配合 --uninstall:不安排自删程序目录。"
|
||||
"安装包的卸载器调用时用这个 —— "
|
||||
"Inno 自己会删 {app},两边一起删会抢文件")
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -98,17 +102,33 @@ def cli_autostart(action: str) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
def cli_uninstall() -> int:
|
||||
"""卸载。会开一个控制台让用户看到过程。"""
|
||||
def cli_uninstall(keep_dir: bool = False) -> int:
|
||||
"""卸载。有控制台就开一个让用户看到过程。
|
||||
|
||||
keep_dir=True 时不安排自删程序目录(安装包卸载器调用时用)。
|
||||
|
||||
⚠ 别无条件调 input()。
|
||||
安装包的 [UninstallRun] 是用 runhidden + waituntilterminated 调的,
|
||||
那种情况下**没有 stdin**,input() 会永远阻塞 ——
|
||||
表现就是"从控制面板卸载永远卡住不结束"。
|
||||
(2026-10 实测:卸载器无限等待,根因就是这一行。)
|
||||
所以只在真的有交互式终端时才等回车。
|
||||
"""
|
||||
attach_console()
|
||||
from lanremote.uninstall import run as do_uninstall
|
||||
try:
|
||||
print(do_uninstall())
|
||||
print(do_uninstall(keep_dir=keep_dir))
|
||||
except Exception as exc: # noqa: BLE001
|
||||
print(f"卸载出错:{exc}")
|
||||
return 1
|
||||
print()
|
||||
input("按回车关闭…")
|
||||
|
||||
# 只有真有人在看的时候才等回车
|
||||
if sys.stdin is not None and sys.stdin.isatty():
|
||||
try:
|
||||
input("按回车关闭…")
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
pass
|
||||
return 0
|
||||
|
||||
|
||||
@@ -661,7 +681,7 @@ def main(argv=None) -> int:
|
||||
if args.relay_status:
|
||||
return cli_relay_status()
|
||||
if args.uninstall:
|
||||
return cli_uninstall()
|
||||
return cli_uninstall(keep_dir=bool(args.keep_dir))
|
||||
|
||||
store = Store(data_dir())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user