fix(windows): 驱动安装假成功——InstallShield 壳提前退出骗过 -Wait,改 pnputil 实时校验
用户实测:一键安装日志显示 12 秒"装完"但打印机仍离线。根因:HiTi 的 Setup64.exe 是自解压壳(InstallShield 类),Start-Process -Wait 等的是壳进程, 内层安装向导未真正完成即返回;且旧的注册表标记机制把这次假安装记成了"已装"。 修复: - 安装流程尾部增加 pnputil /enum-drivers 校验(匹配 cs2xxhcd/htitahcd/hiti), 未发现驱动即报"校验未通过"(引导重试或手动运行 Setup64),不再盲写标记 - queryInstalled 改为 pnputil 实时校验驱动商店(唯一真源,废弃注册表标记—— 假安装误写后向导会错误地不再显示安装按钮) - 成功日志改为提示"拔插 USB 重新枚举设备后再检测"
This commit is contained in:
1 parent
7e65d22f09
commit
9ece6cc294
1 file changed
+25
-18
@@ -6,13 +6,11 @@ import '../utils/command_runner.dart';
|
||||
///
|
||||
/// - macOS:CUPS 过滤器 pkg(dmg 内置),已装判断 = /Library/Printers/HiTi 存在,
|
||||
/// 安装 = 挂载 dmg → osascript 提权 installer → 卸载卷
|
||||
/// - Windows:HiTi 官方驱动 exe(assets/drivers/*.exe 内置),UAC 提权运行;
|
||||
/// 已装判断 = 我们自己的注册表标记(HKCU\Software\zax\desktop-plugin,
|
||||
/// 系统级驱动安装状态无统一可查标志,安装成功后写标记最可靠)
|
||||
/// - Windows:HiTi 官方驱动整目录 zip 内置,已装判断 = pnputil 枚举驱动商店
|
||||
/// (实时校验,安装器壳提前退出不会误判),安装 = 解压 → UAC 提权 Setup64 →
|
||||
/// pnputil 校验通过才算成功
|
||||
class DriverInstall {
|
||||
static const installedMarker = '/Library/Printers/HiTi';
|
||||
static const _winMarkKey = r'HKCU\Software\zax\desktop-plugin';
|
||||
static const _winMarkValue = 'HiTiDriverInstalled';
|
||||
|
||||
static bool get isSupported => Platform.isMacOS || Platform.isWindows;
|
||||
|
||||
@@ -22,15 +20,14 @@ class DriverInstall {
|
||||
return false; // Windows 走异步 queryInstalled(注册表查询需要子进程)
|
||||
}
|
||||
|
||||
/// Windows:异步查询安装标记。
|
||||
/// Windows:pnputil 实时校验驱动商店(安装器是自解压壳、可能假成功,
|
||||
/// 注册表标记会被失败的安装误写,故以系统驱动商店为唯一真源)。
|
||||
static Future<bool> queryInstalled() async {
|
||||
if (!Platform.isWindows) return isInstalled();
|
||||
final out = await runCommand(
|
||||
'reg',
|
||||
['query', _winMarkKey, '/v', _winMarkValue],
|
||||
tolerateExit: true,
|
||||
);
|
||||
return out.contains('0x1');
|
||||
final drivers = await runCommand('pnputil', ['/enum-drivers'],
|
||||
tolerateExit: true, timeoutMs: 60000);
|
||||
final lower = drivers.toLowerCase();
|
||||
return lower.contains('cs2xxhcd') || lower.contains('htitahcd') || lower.contains('hiti');
|
||||
}
|
||||
|
||||
/// 内置驱动安装包的文件系统路径;未打包携带返回 null。
|
||||
@@ -135,10 +132,11 @@ class DriverInstall {
|
||||
throw StateError('驱动包内未找到安装程序(Setup64.exe)');
|
||||
}
|
||||
log('开始安装 HiTi 打印机驱动(请在 UAC 弹窗中确认,安装向导可能需要点几次"下一步")…');
|
||||
// -Verb RunAs 触发 UAC;-Wait 等安装程序退出(用户取消 UAC 时 PowerShell 报错)
|
||||
// 注意:HiTi 的 Setup64 是自解压壳(InstallShield 类),-Wait 等的是壳进程,
|
||||
// 内层安装向导可能仍在运行——安装是否成功必须以后续的驱动校验为准
|
||||
final script = 'Start-Process -FilePath "$setup" -Verb RunAs -Wait';
|
||||
await runCommand('powershell', ['-Command', script], timeoutMs: 600000);
|
||||
log('驱动安装程序已退出');
|
||||
log('安装程序已退出,正在校验驱动是否装入系统…');
|
||||
} finally {
|
||||
// 3. 清理临时目录(失败不影响安装结果)
|
||||
try {
|
||||
@@ -146,10 +144,19 @@ class DriverInstall {
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// 4. 写安装标记(我们自己的注册表键;0x1 = 已装)
|
||||
await runCommand('reg',
|
||||
['add', _winMarkKey, '/v', _winMarkValue, '/t', 'REG_DWORD', '/d', '1', '/f']);
|
||||
log('已记录驱动安装状态');
|
||||
// 4. 校验:驱动是否真的进了驱动商店(pnputil 枚举,匹配 htitahcd/CS2xx)
|
||||
await Future<void>.delayed(const Duration(seconds: 3)); // 给安装收尾一点时间
|
||||
final drivers = await runCommand('pnputil', ['/enum-drivers'],
|
||||
tolerateExit: true, timeoutMs: 60000);
|
||||
final lower = drivers.toLowerCase();
|
||||
final installed = lower.contains('cs2xxhcd') || lower.contains('htitahcd') || lower.contains('hiti');
|
||||
if (!installed) {
|
||||
throw StateError(
|
||||
'驱动校验未通过:系统中未发现 HiTi 驱动(安装器可能未真正完成,请重试,'
|
||||
'或手动运行驱动包 CS2xx 目录内的 Setup64.exe 完成安装)');
|
||||
}
|
||||
log('校验通过:HiTi 驱动已装入系统');
|
||||
log('驱动安装完成——请拔掉打印机 USB 重新插上(驱动绑定需要设备重新枚举),然后重新检测');
|
||||
}
|
||||
|
||||
static String? _findFileDeep(String root, String lowerName) {
|
||||
|
||||
Reference in new issue
Block a user