结论
宿主与客机之间双向复制粘贴文件不通,不是虚拟化配置错误,也不是客户端不支持 —— 根因在客机内的 SPICE 代理(vdagent-win)剪贴板格式表只认文本与图像,没有 Windows 的「文件」剪贴板格式(CF_HDROP)。表现特征是不对称的:文本正常、文件双向静默失败(无任何弹窗)。该能力上游只在未发布的主线分支补过,正式发行版没有,项目也已停止维护。官方给的文件互传机制是走 webdav 共享盘中转(需多处改造)。本项目不采用该机制,改用客机内置的 qemu-guest-agent 走命令行搬文件,已落地为管理命令的 ls / cp / paste 三个子命令并验收通过。
现象
- 宿主(桌面环境)与客机(Windows 10)之间,双向 Ctrl+C / Ctrl+V 文件都不能完成粘贴,无任何弹窗提示;多次尝试表现不一但都不成功。
- 纯文本复制粘贴正常(两个方向都正常)。
- 把文件拖拽进/出虚拟机窗口,同样不行。
排查过程(实测)
| 步骤 | 动作 | 实测结果 |
|---|---|---|
| 1 | 核对客机内代理是否装好并在运行 | 代理进程在用户桌面会话中运行,版本为最后一个正式发行版 |
| 2 | 开启 SPICE 调试,抓客户端协议日志 | 代理已连接;其上报的能力集合为 {鼠标状态、显示器配置、回复、显示配置、按需剪贴板、稀疏显示器、行尾 CRLF、剪贴板体积上限} —— 没有「剪贴板选择(selection)」能力,也没有任何文件传输能力 |
| 3 | 看客户端是否忽略了剪贴板内容 | 日志出现 Ignoring clipboard grab(对非标准剪贴板选择通道的丢弃);确认客户端侧剪贴板共享本身是开着的 |
| 4 | 取出客机内代理程序二进制,检索其能力 | 含完整的 Win32 剪贴板 API 与文件传输(file-xfer)实现,但缺文件路径解析相关调用(处理「剪贴板里的文件」必须用到它) |
| 5 | 对照上游源码的剪贴板格式表 | 决定性证据,见下节 |
| 6 | 改走 qemu-guest-agent 命令行搬文件 | 双向均可搬,逐字节校验一致(见证据表) |
| 7 | 溯源官方给出的文件互传机制 | 剪贴板传文件依赖 webdav 共享盘,见「处置与判据」 |
根因
客机侧 SPICE 代理(vdagent-win)最后一个正式发行版的剪贴板格式表只有两项:
| Windows 剪贴板格式 | 映射的协议格式 | 含义 |
|---|---|---|
CF_UNICODETEXT | VD_AGENT_CLIPBOARD_UTF8_TEXT | 文本 |
CF_DIB | VD_AGENT_CLIPBOARD_IMAGE_PNG / ..._BMP | 图像 |
恰好没有 CF_HDROP —— 那是 Windows 剪贴板里表示「文件」的格式。上游主线分支在 2020-07 的一次提交中补上了这一行({CF_HDROP, {VD_AGENT_CLIPBOARD_FILE_LIST, 0}}),但从未进入任何正式发行版,官方下载目录里最新版就是客机所装的那个版本;该上游项目已停止维护。
由此产生两个方向都静默失败:
- 宿主 → 客机:宿主复制文件后,客户端把「来的是文件」这一事实告知客机,客机代理按格式表逐个匹配,一个都不认识,直接丢弃(其内部日志串即
No supported clipboard types in client grab)。 - 客机 → 宿主:在客机里复制文件 = 剪贴板格式
CF_HDROP,代理认不出,不产生任何通知,宿主端完全无感知。
同时,客机复制的文本命中表内第一项,所以文本双向正常 —— 这正是「文本行、文件不行」这条不对称现象的来源。
实测证据
| 判据 | 实测 |
|---|---|
| 代理是否连上 | 协议日志 agent connected: yes |
| 客机上报的能力集合 | 含「按需剪贴板」,不含剪贴板选择、不含文件传输 |
| 客机代理的剪贴板格式表 | 仅 CF_UNICODETEXT + CF_DIB 两行 |
| 上游主线同表 | 比发行版多一行 CF_HDROP |
| 官方下载目录 | 最新即客机所装版本,无更新的正式版 |
| 客户端侧行为 | 日志 Ignoring clipboard grab |
| 文本剪贴板 | 双向正常 |
| 改走命令行搬文件 | 单个文件 132638 字节,两端 sha256 完全一致 |
与本次改动无关的判据
排查期间恰好动过若干其它配置,逐一排除如下:
| 被怀疑的原因 | 实测结论 |
|---|---|
| 宿主桌面是 Wayland,剪贴板内容到不了 X11 剪贴板 | 否:宿主会话是 X11,X 侧剪贴板工具可直接读写生效 |
| 剪贴板代理没装 / 没在跑 | 否:代理进程在用户桌面会话中运行 |
| SPICE 通道没建立 | 否:协议日志显示代理已连接,且文本通道正常 |
| 虚拟化软件版本旧,缺代理侧修复 | 否:本机版本已高于任何外部报告提及的修复版本 |
| 域配置屏蔽了剪贴板 / 文件传输 | 否:相关设备段都在 |
| 客户端不支持剪贴板或文件传输 | 否:客户端内置完整剪贴板处理与文件传输对话框 |
处置与判据
① 最省事(已采纳并落地):用客机内置的 qemu-guest-agent 走命令行搬文件 —— 不改虚拟化配置、不装软件、不重启。已做成管理命令的三个子命令:
| 子命令 | 作用 |
|---|---|
ls [虚拟机] | 列出客机桌面上的文件 |
cp | copy | get | pull [虚拟机] [文件名] | 客机桌面 → 域目录 |
paste | send | push [虚拟机] [文件名] | 域目录 → 客机桌面 |
约定:省略虚拟机名时取列表中第一个;省略文件名时默认全部;文件名支持通配符(需加引号,否则会被本地 shell 先按当前目录展开)。判据:双向搬文件逐字节校验一致;命令 ls 可列出客机桌面文件名与大小。
② 机制性修法(未采纳):走官方机制 —— 域里加一条 webdav 通道,客机内装 webdav 客户端与服务端组件,并把客机内代理升级到含 CF_HDROP 的版本,客户端再指定一个共享目录。这套改造能让宿主 → 客机方向的复制粘贴文件可用。未采纳的理由:改造面大、要重启域,与「配置式优雅」的偏好不符;且对反向(客机 → 宿主)同样无效。
③ 官方未实现的部分(属新需求,本档不做):客机 → 宿主方向的「复制粘贴文件」,上游源码中明确标注 not supported yet,任何配置都绕不过;该方向只能靠共享盘或上面 ① 的命令行搬文件。
边界
- 本档只覆盖「宿主 ↔ 客机双向复制粘贴文件」这一问题;不覆盖拖拽(另一套机制),也不覆盖共享盘方案的实施细节。
- 文本 / 图像剪贴板本来就是正常的,不在本档范围。
- 「能力集合」「剪贴板格式表」「客户端忽略日志」均为实测或源码级证据;「上游何时补上该能力」按提交时间给出,属可复核事实。
- 处置 ① 落地形态与判据已实测通过;② 与 ③ 为对照方案,未在本机实施。