必须用CF_HDROP格式读取剪切板文件路径:先OpenClipboard→IsClipboardFormatAvailable→GetClipboardData→DragQueryFile获取数量及各路径,再以UTF-8/BOM写入文件,全程需检查返回值并配对GlobalLock/Unlock。

Windows 下用 C++ 读取剪切板里的文件路径(CF_HDROP)
Windows 剪切板中「复制文件」操作实际存的是 CF_HDROP 格式,不是纯文本——直接调用 GetClipboardData(CF_TEXT) 拿不到路径,会返回空或乱码。
必须先打开剪切板、检查格式支持、再用 GlobalLock 解析 HGLOBAL 内的文件列表结构。关键点是:DragQueryFile 要传 0xFFFFFFFF 获取文件数,再逐个读路径。
- 务必在
OpenClipboard(NULL)后立刻检查返回值,失败常见于其他程序正占用剪切板(比如资源管理器刚复制完还没释放) -
GlobalLock返回指针后,不能直接当字符串用——它开头是DROPFILES结构体,真实路径从偏移处开始,且以双 null 结尾 - 路径是宽字符(
wchar_t*),写入 txt 时建议用std::wofstream并设置 UTF-8 或 UTF-16 BOM,否则中文路径会变问号
用 GetClipboardData(CF_HDROP) 拿到句柄后怎么解析
拿到 HGLOBAL 句柄只是第一步,它里面是二进制布局:先是 DROPFILES 结构(含偏移、是否 Unicode 标志),后面紧跟一串 null 分隔的路径,末尾两个 \0。
别手撸偏移计算——直接用 Windows API DragQueryFile 最稳,它自动处理 Unicode 判断和边界。
立即学习“C++免费学习笔记(深入)”;
- 调用
DragQueryFile(hdrop, 0xFFFFFFFF, NULL, 0)得文件总数 - 对每个索引
i,先用DragQueryFile(hdrop, i, NULL, 0)获取长度,再分配缓冲区调用第二次取内容 - 如果
DragQueryFile返回 0,说明该索引无效(比如越界或剪切板已变),别硬读
保存为 txt 文件时中文路径乱码的根源
乱码不是读取错了,是写文件时编码不匹配:std::ofstream 默认窄字符流,遇到 wchar_t* 会截断或转码失败;即使强制用 std::wofstream,若没指定 locale 或 BOM,记事本默认用系统 ANSI 打开仍显示乱码。
- 推荐方案:用
std::wofstream+imbue(std::locale(""))(依赖系统 locale),或更可靠地手动写 UTF-8 BOM + UTF-8 编码字节 - 简单起见,可先用
WideCharToMultiByte(CP_UTF8, ...)转成std::string,再用普通std::ofstream写,并在开头写入"\xEF\xBB\xBF"(UTF-8 BOM) - 注意:路径末尾可能带反斜杠(如目录复制),
DragQueryFile不会自动补,但不影响写入 txt
完整流程里最容易被跳过的安全检查
不是所有剪切板内容都含文件——用户可能刚复制了一段文字,或剪切板被清空,或权限受限(比如沙盒进程)。忽略这些会导致崩溃或静默失败。
-
IsClipboardFormatAvailable(CF_HDROP)必须在GetClipboardData前调用,否则GetClipboardData(CF_HDROP)可能返回NULL -
GlobalLock成功后,必须用GlobalUnlock配对,否则内存泄漏(虽然进程退出会回收,但调试时容易误判) - 写文件前检查目标路径是否可写(比如
C:\需管理员权限),避免只提示“写入失败”却不告诉用户原因
真正卡住人的往往不是 API 调用顺序,而是某次 OpenClipboard 失败后没重试,或者把 HGLOBAL 当字符串指针直接 wcscpy——那块内存开头根本不是路径。



















