Windows下需先调用OpenClipboard和IsClipboardFormatAvailable(CF_HDROP)判断剪切板是否含文件路径,再用GetClipboardData获取HDROP句柄,通过DragQueryFile逐个提取宽字符路径,最后用WideCharToMultiByte转UTF-8并以二进制模式写入文件。

Windows 平台下,C++ 无法直接跨进程读取剪切板中的文件路径列表(即“CF_HDROP”格式),必须调用 Win32 API 并正确处理 HDROP 句柄;Linux/macOS 没有等效剪切板文件路径概念,该需求仅在 Windows 有效。
如何判断剪切板当前是否包含文件路径(CF_HDROP)
不是所有复制操作都会写入文件路径——只有在资源管理器中选中文件 → Ctrl+C,或拖拽文件到桌面/窗口释放时才可能触发。需先检查剪切板格式是否为 CF_HDROP:
- 调用
OpenClipboard(nullptr)获取剪切板所有权 - 用
IsClipboardFormatAvailable(CF_HDROP)判断是否存在文件列表 - 若返回
false,说明当前剪切板是文本、图片或其他内容,CF_HDROP不可用 - 注意:不能跳过此步直接
GetClipboardData(CF_HDROP),否则返回nullptr且后续DragQueryFile会崩溃
如何安全提取 CF_HDROP 中的每个文件路径
CF_HDROP 数据本质是一个 HDROP 句柄,指向内存中结构体(含文件数、偏移表、路径字符串块)。必须用 DragQueryFile 逐个读取,不能用 GlobalLock + 字符串解析:
- 调用
GetClipboardData(CF_HDROP)得到HDROP句柄 - 第一次调用
DragQueryFile(hdrop, 0xFFFFFFFF, nullptr, 0)获取文件总数 - 对每个索引
i,调用DragQueryFile(hdrop, i, buffer, sizeof(buffer))写入路径(UTF-16) - 缓冲区必须足够大(建议
WCHAR[MAX_PATH * 4]),因长路径或含多个文件时总长度不可预估 - 返回值是实际写入字符数,不包括结尾
L'\0',但DragQueryFile会自动补上
如何将路径写入 UTF-8 编码的 txt 文件(避免中文乱码)
剪切板路径是宽字符(WCHAR*),直接用 fopen("out.txt", "w") 写入会导致中文全变成问号或乱码。必须转为 UTF-8:
立即学习“C++免费学习笔记(深入)”;
- 用
WideCharToMultiByte(CP_UTF8, ...)转换单个路径字符串 - 打开文件时用
_wfopen(L"out.txt", L"w, ccs=UTF-8")(注意:这会写 BOM,且部分编辑器不兼容) - 更稳妥做法:用
fopen("out.txt", "wb")以二进制模式打开,手动写入 UTF-8 字节流 - 每行路径后追加
"\r\n"(Windows 换行),不要用\n单独写,否则记事本打开显示为一行 - 示例关键片段:
FILE* f = fopen("paths.txt", "wb"); for (int i = 0; i < count; ++i) { WCHAR path[MAX_PATH * 4] = {}; int len = DragQueryFile(hdrop, i, path, _countof(path)); if (len > 0) { int utf8_len = WideCharToMultiByte(CP_UTF8, 0, path, -1, nullptr, 0, nullptr, nullptr); char* utf8_buf = new char[utf8_len]; WideCharToMultiByte(CP_UTF8, 0, path, -1, utf8_buf, utf8_len, nullptr, nullptr); fwrite(utf8_buf, 1, utf8_len - 1, f); // -1 排除末尾 '\0' fwrite("\r\n", 1, 2, f); delete[] utf8_buf; } } fclose(f);
真正容易被忽略的是:剪切板句柄 HDROP 属于全局内存对象,你不能 GlobalFree 它,也不需要释放;但必须在 CloseClipboard() 前完成所有 DragQueryFile 调用——一旦关闭剪切板,HDROP 句柄立即失效。



















