mirror of
https://gitee.com/xmz7891/ykxmz.git
synced 2026-10-18 14:50:45 +00:00
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 项全通过
97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
||
r'''验证卸载卡死的假设:--uninstall 里的自删逻辑和 Inno 卸载器抢目录。
|
||
|
||
步骤:
|
||
1. 彻底清干净
|
||
2. 静默安装
|
||
3. 单独跑 ykxmz.exe --uninstall,**计时**(不经过 Inno 卸载器)
|
||
如果它自己很快返回,说明卡的是 Inno 那一步(抢目录)
|
||
4. 看它有没有把安装目录删掉
|
||
'''
|
||
from __future__ import annotations
|
||
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
|
||
SETUP = ROOT / "dist" / "ykxmz-setup-1.7.1.exe"
|
||
INSTALL_DIR = Path(r"C:\Program Files\ykxmz")
|
||
CODE = "739251"
|
||
|
||
|
||
def ps(command: str, timeout: int = 300) -> tuple:
|
||
r = subprocess.run(
|
||
["powershell", "-NoProfile", "-ExecutionPolicy", "Bypass",
|
||
"-Command", command],
|
||
capture_output=True, text=True, timeout=timeout,
|
||
encoding="utf-8", errors="replace")
|
||
return r.returncode, (r.stdout or "").strip()
|
||
|
||
|
||
def main() -> int:
|
||
print(" 一、彻底清理")
|
||
ps("Get-Process ykxmz,unins000,_unins.tmp -ErrorAction SilentlyContinue | "
|
||
"Stop-Process -Force -ErrorAction SilentlyContinue; "
|
||
"Start-Sleep -Seconds 2; "
|
||
"Remove-Item 'C:\\Program Files\\ykxmz' -Recurse -Force "
|
||
"-ErrorAction SilentlyContinue; "
|
||
"Remove-Item 'C:\\ProgramData\\ykxmz' -Recurse -Force "
|
||
"-ErrorAction SilentlyContinue; "
|
||
"Remove-Item 'HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
|
||
"\\{8F3C1D42-7A5E-4B91-9C6D-2E8F4A1B7C30}_is1' -Recurse -Force "
|
||
"-ErrorAction SilentlyContinue; Write-Output ok")
|
||
ps("Get-Process ykxmz -ErrorAction SilentlyContinue | "
|
||
"Stop-Process -Force -ErrorAction SilentlyContinue")
|
||
time.sleep(3)
|
||
|
||
print(" 二、静默安装")
|
||
start = time.perf_counter()
|
||
ps("Start-Process -FilePath '%s' -ArgumentList "
|
||
"'/VERYSILENT /SUPPRESSMSGBOXES /NORESTART "
|
||
"/DIR=\"C:\\Program Files\\ykxmz\" /CODE=%s' -Wait" % (SETUP, CODE),
|
||
timeout=600)
|
||
print(" 安装耗时 %.1f 秒" % (time.perf_counter() - start))
|
||
time.sleep(5)
|
||
exe = INSTALL_DIR / "ykxmz.exe"
|
||
print(" ykxmz.exe 在: %s" % exe.is_file())
|
||
|
||
print()
|
||
print(" 三、单独跑 --uninstall 并计时(不经过 Inno 卸载器)")
|
||
print(" 这一步是关键:如果它很快返回,卡的就是 Inno 那边")
|
||
start = time.perf_counter()
|
||
try:
|
||
r = subprocess.run(
|
||
[str(exe), "--uninstall"],
|
||
capture_output=True, text=True, timeout=90,
|
||
encoding="utf-8", errors="replace")
|
||
elapsed = time.perf_counter() - start
|
||
print(" ✓ %.1f 秒返回,exit=%s" % (elapsed, r.returncode))
|
||
for line in (r.stdout or "").strip().splitlines():
|
||
print(" " + line.strip())
|
||
except subprocess.TimeoutExpired:
|
||
print(" ✗ 90 秒没返回 —— **它自己就会卡**")
|
||
print(" 假设不成立,问题在 --uninstall 本身")
|
||
|
||
print()
|
||
print(" 四、看安装目录现在什么样")
|
||
if INSTALL_DIR.is_dir():
|
||
files = list(INSTALL_DIR.iterdir())
|
||
print(" 目录还在,%d 个条目:" % len(files))
|
||
for f in files[:10]:
|
||
print(" %s" % f.name)
|
||
else:
|
||
print(" 目录已被自删逻辑删掉")
|
||
|
||
print()
|
||
print(" 五、进程状态")
|
||
rc, out = ps("(Get-Process ykxmz,unins000,_unins.tmp "
|
||
"-ErrorAction SilentlyContinue | Measure-Object).Count")
|
||
print(" 残留进程: %s" % (out.strip().splitlines()[-1] if out else "?"))
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|