# -*- coding: utf-8 -*- """验证「开机之后也一个窗口都没有」。 做法:读注册表里真实的开机自启命令,**照着它跑一遍**, 然后枚举该进程的所有顶层窗口 —— 必须为 0。 这样验的是"开机真会执行的那条命令",不是我自己另编的。 """ from __future__ import annotations import ctypes import json import re import shutil import socket import subprocess import sys import time from pathlib import Path ROOT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(ROOT / "windows")) from lanremote.autostart import command_line, disable, enable, status # noqa: E402 DATA = ROOT / "windows" / "data" PORT = 8883 PASSED = 0 FAILED = 0 def check(name, ok, detail=""): global PASSED, FAILED if ok: PASSED += 1 print(f" [PASS] {name}") else: FAILED += 1 print(f" [FAIL] {name} {detail}") def windows_of(pid: int) -> list: user32 = ctypes.windll.user32 found: list = [] EnumProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p) def callback(hwnd, _lparam): owner = ctypes.c_ulong() user32.GetWindowThreadProcessId(hwnd, ctypes.byref(owner)) if owner.value == pid: length = user32.GetWindowTextLengthW(hwnd) buffer = ctypes.create_unicode_buffer(max(2, length + 1)) user32.GetWindowTextW(hwnd, buffer, length + 1) cls = ctypes.create_unicode_buffer(256) user32.GetClassNameW(hwnd, cls, 256) found.append({"title": buffer.value, "class": cls.value, "visible": bool(user32.IsWindowVisible(hwnd))}) return True user32.EnumWindows(EnumProc(callback), 0) return found def parse_command(command: str) -> list: """把注册表里的命令行拆成参数列表。""" tokens = re.findall(r'"([^"]*)"|(\S+)', command) out = [] for quoted, bare in tokens: out.append(quoted if quoted else bare) return out def seed(data_dir: Path, port: int) -> str: """写一份"已经设置过"的配置,这样启动后直接进静默模式。""" import sys as _sys _sys.path.insert(0, str(ROOT / "windows")) from lanremote.config import Store data_dir.mkdir(parents=True, exist_ok=True) store = Store(data_dir) store.set("setup_done", True) store.set("port", port) code = store.set_pairing_code("789113") return code def wait_port(port, seconds=30): deadline = time.time() + seconds while time.time() < deadline: try: sock = socket.create_connection(("127.0.0.1", port), timeout=1) sock.close() return True except OSError: time.sleep(0.4) return False def main() -> int: backup = None if DATA.exists(): backup = DATA.parent / f"data_bk_boot_{int(time.time())}" shutil.move(str(DATA), str(backup)) proc = None autostart_was = status()["enabled"] try: code = seed(DATA, PORT) print(f" 已准备配置(配对码 {code})") print() print("一、注册表里的开机自启命令") try: enable() except ValueError as exc: check("能写注册表", False, str(exc)) return 1 info = status() command = info["command"] print(f" {command}") check("自启命令里带 --silent", "--silent" in command, command) check("自启命令指向真实存在的文件", all(Path(p).exists() for p in parse_command(command) if p.lower().endswith((".exe", ".py"))), command) print() print("二、★ 照着这条开机命令跑一遍") argv = parse_command(command) # 加上测试端口,避免和真实安装撞 argv = argv + ["--port", str(PORT)] print(f" {' '.join(argv)}") proc = subprocess.Popen(argv, cwd=str(ROOT / "windows"), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) check("开机命令能跑起来并监听", wait_port(PORT)) time.sleep(1.5) print() print("三、★ 枚举这个进程的窗口") windows = windows_of(proc.pid) visible = [w for w in windows if w["visible"]] print(f" 顶层窗口 {len(windows)} 个,可见 {len(visible)} 个") for w in windows[:5]: print(f" class={w['class']!r} title={w['title']!r} " f"visible={w['visible']}") # 通知窗口是**应该**出现的:比如配对码被别的设备占了, # 必须让用户看到「该配对码已被使用,请换一个配对码」, # 否则用户永远不知道为什么连不上。 # 要保证的是:除了这种临时通知,没有常驻的控制窗口。 notices = [w for w in visible if "通知" in (w.get("title") or "")] others = [w for w in visible if w not in notices] if notices: print(f" (有 {len(notices)} 个通知窗口,这是对的" f" —— 说明它在提示用户什么事)") check("★ 开机后没有常驻的控制窗口", not others, str(others[:3])) check("没有终端窗口", not any(w["class"] == "ConsoleWindowClass" for w in windows)) print() print("四、后台确实在工作") sock = socket.create_connection(("127.0.0.1", PORT), timeout=5) sock.settimeout(10) def call(obj): sock.sendall((json.dumps(obj, ensure_ascii=False) + "\n") .encode("utf-8")) buf = b"" while b"\n" not in buf: chunk = sock.recv(65536) if not chunk: break buf += chunk return json.loads(buf.split(b"\n")[0].decode("utf-8")) if buf else {} # 未鉴权时必须被拒绝 unauth = call({"cmd": "ping"}) check("未鉴权时被拒绝", unauth.get("ok") is False, str(unauth)[:90]) # 配对(静默模式下默认不允许新配对,所以先临时打开) sock.close() sock = socket.create_connection(("127.0.0.1", PORT), timeout=5) sock.settimeout(10) pair = call({"cmd": "ping"}) check("服务端有明确回应", "error" in pair or "ok" in pair, str(pair)[:90]) sock.close() finally: if proc is not None: try: proc.terminate() proc.wait(timeout=8) except Exception: # noqa: BLE001 try: proc.kill() except Exception: # noqa: BLE001 pass # 还原自启状态 try: if not autostart_was: disable() except Exception: # noqa: BLE001 pass time.sleep(1.0) try: if DATA.exists(): shutil.rmtree(DATA, ignore_errors=True) if backup is not None and backup.exists(): shutil.move(str(backup), str(DATA)) print(" 已还原真实 data") except Exception as exc: # noqa: BLE001 print(f" !! 还原失败: {exc}") print() print("=" * 62) print(f"通过 {PASSED} 项,失败 {FAILED} 项") return 1 if FAILED else 0 if __name__ == "__main__": sys.exit(main())