【win备份还原工具开发日记】08:VM 引导修复、孤儿快照回收与智能分流键盘自动化

举报
任正非 发表于 2026/10/10 06:08:14 2026/10/10
【摘要】 开发残留清理与测试盘重建(0021)删设备必须先停 VM:--device-del 在运行态报 "cannot be added or removed while the virtual machine is running";实际设备名就是 boot order 里的 hdd1/hdd2,之前报 "device does not exist" 是 VM 没停导致的误导性报错。快照引用会锁住...

开发残留清理与测试盘重建(0021)

  1. 删设备必须先停 VM:--device-del 在运行态报 "cannot be added or removed while the virtual machine is running";实际设备名就是 boot order 里的 hdd1/hdd2,之前报 "device does not exist" 是 VM 没停导致的误导性报错。

  2. 快照引用会锁住删除:--destroy-image 报 "This disk is in use by the following snapshots" → 必须 --destroy-image-force(顺带清快照对镜像的引用)。

  3. nul 保留设备名文件:Remove-Item -Recurse -Force 和 rd /s /q 都因目录里有名为 nul 的 0 字节文件而失败(报"目录不是空的")→ 用 \\?\ 前缀走 [System.IO.Directory]::Delete 才删得掉;来源是历史脚本 copy ... nul 忘了加 >。

  4. prlctl exec 是管理员以外上下文:vssadmin/DISM 在线命令在 exec 下无权限(输出版权信息即未执行)→ 必须 schtasks /create /ru SYSTEM /rl HIGHEST 提权跑,用完删任务。

孤儿快照层 .hds 回收:.pvm 208G→62G(0021)

  1. 现象:快照树已空(GUI 和 prlctl snapshot-list 都空),但 harddisk.hdd/ 下仍残留 12 个 .hds 层 ≈206GB;原因是历史 11 个快照在 VM 运行态删除,只删了树节点、差异层没合并回收。

  2. 解法(官方工具,别手删文件):先 prl_disk_tool merge --hdd <路径> 合并 12 层→单层,再 compact --hdd 回收空洞;必须先 merge 再 compact,直接 compact 会因"无空洞"无效(merge 后才标出可回收 83GB)。

  3. 语法坑:merge 用 --hdd <路径>,不带 -i(带 -i 报 "The 'i' option cannot be used for the 'merge' operation")。

VM 引导修复:新建 VM 挂旧盘(0158)

  1. 现象:VM 挂起恢复后 Boot Manager 只剩「UEFI Shell」,Parallels 弹「没有安装操作系统」;prl_disk_tool check 100% 通过,磁盘数据完好。

  2. 根因:坏的是 VM NVRAM 里的 EFI 引导变量(Boot0000/BootOrder),挂起/恢复过程中丢失;重置 NVRAM、关 Secure Boot 都无效。

  3. 死路:固件菜单要键盘导航,但 cu 按键传不进 Parallels VM 窗口;prlctl send-key-event --scancode 在「无操作系统」模态弹窗出现期间被 Parallels 拦截(弹窗存在时键完全无效)。

  4. 解法(已成功):prlctl create "Win11-repair" --no-hdd 新建 VM 拿干净 NVRAM → --device-add hdd --image <旧盘> 引用旧盘(不复制、不占空间)→ 干净固件直接扫到 ESP 引导文件就进 Windows,无需 PE 修复。

  5. 遗留:新旧 VM UUID 不同,Windows 激活可能失效;旧 VM 已停(磁盘被新 VM 引用不能同时启动)。

WinRE 自动进入踩坑(0505)

  1. WinRE 状态 Disabled 不等于镜像丢失:dir /s /b Winre.wim 在 C: 找不到 → 其实在 R: 恢复分区的 Recovery\WindowsRE\Winre.wim,直接 reagentc /enable 就注册启用,无需 copype 重建。

  2. winpeshl.ini 指向的每个程序必须在注入列表里:inject_winre_payload() 复制列表漏了 RecoveryLauncher.cmd → WinRE 启动找不到入口 → 走默认恢复界面超时回 Windows(表现为 prepare 成功、bootsequence 被消费,但 Recovery.log 空、WIM 没生成)。

  3. Recovery.exe 会变成旧版:build-win.sh 只复制 BackupRestore.exe 没复制成 Recovery.exe,而 winpeshl.ini 按 Recovery.exe 启动 → 部署时必须两个名字一起 copy。

  4. 还原不能在目标盘上运行程序:程序目录在 C: 而还原目标也是 C: 时,代码主动拒绝(运行中的程序会把自己删掉)——须把整个程序目录挪到非目标盘再跑。

  5. 本平台坑集合:.cmd/.bat 从 macOS 复制必须转 CRLF;schtasks /delete /f 和 del 被安全策略判定不可逆而拦截(改用 /create /f 覆盖、> 覆盖写)。

  6. WinRE 与 PE 不能共用 winpeshl.ini(v1.6.0 修复):产品包拆成 winre-winpeshl.ini(只允许 Recovery.exe recover-env)与 winpe-winpeshl.ini(只允许 Recovery.exe --pe-desktop),缺任一必需文件即失败且不提交 WIM。

智能分流与 PE 桌面(1408)

  1. 判断口径:备份比 source_drive、还原比 target_drive,与 %SystemDrive% 比——不是「含 Windows 的卷」(双系统场景会错);相等弹 PE/RE/取消三按钮,不等走后台在线 DISM(不重启)。

  2. 自绘模态对话框:项目无 manifest、comctl32 v6 的 TaskDialogIndirect 不可依赖,弹窗得自绘。

  3. Hwnd 不能跨线程 move(*mut c_void 不是 Send)→ 先转 usize,线程里再 as Hwnd。

  4. PE 桌面 6 按钮:备份/还原/安装第二系统/命令提示符/返回 Windows/打开完整程序;「重启」合并进「返回 Windows」。

  5. 「打开完整程序」坑:should_launch_gui() 检查 exe 文件名 == "BackupRestore",PE 里是 Recovery.exe,无参数启动走 CLI 不进 GUI → 必须带 --tab。

  6. 状态栏会被 tab 控件覆盖(y=440 与备份 tab 的镜像路径/压缩率重叠)→ 关键错误/状态提示不能只写状态栏,必须弹窗。

GUI 键盘导航与 prlctl 键盘通道(1408)

  1. 鼠标注入死路:cu 点击 Parallels 窗口、VM 内 mouse_event/SendInput 都不进 Parallels 订阅管道(人手鼠标走 IOHID 专线所以有效)→ 自动化只能靠键盘。

  2. prlctl send-key-event 宿主导入可用:-k <十进制键码> -e press|release 走官方输入管道,不依赖 CGEvent、不依赖 VM 内进程;组合键依次 press 修饰→press 主键→release 主键→release 修饰。

  3. GUI 键盘化:三个消息循环全改 IsDialogMessageW 路由(Tab/方向键/回车/Esc);主窗口加 WM_KEYDOWN 快捷键(Ctrl+B/R/P/O、F5、Ctrl+Enter,走 PostMessage WM_COMMAND 与真点击同路径)。

  4. F5 坑:IsDialogMessage 会吞掉 F5 → 要在它之前拦截;且 Parallels -k 对 F 键映射错误,F 键得用 scancode(-s 63)。

  5. Ctrl 检测用 GetAsyncKeyState:GetKeyState 读消息队列有延迟,prlctl 注入偶发不生效;GetKeyState(...) as i16 & 0x8000 直接 & 0x8000 会因 i16 溢出编译错。

  6. reagentc /boottore 在 Parallels UEFI 下无效:prepare 链执行成功(报"操作成功")但重启后不进 WinRE——Parallels 固件不消费一次性 WinRE 启动。真实硬件应有效;VM 内验证 WinRE 只能看到「prepare→任务创建→重启」。

  7. 在线备份 exit=87:execute_online 拼 cmd 字符串时索引名 2026-09-13 20:43 带空格、/Name: 没加引号 → cmd 拆参报 87;凡是拼字符串执行的路径、名称必须自己加引号(run_logged 用参数数组则安全)。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。