Windows剪贴板纯文本读写必须使用Win32 API,首选CF_UNICODETEXT格式;需严格配对OpenClipboard/CloseClipboard、GlobalLock/GlobalUnlock,且全程在同一线程执行。
OpenClipboard + GetClipboardData 读取纯文本Windows 剪贴板文本读取必须走 Win32 API,不能直接访问内存。核心流程是打开剪贴板、请求 CF_TEXT 或更推荐的 CF_UNICODETEXT 格式数据、再用 GlobalLock 取出内容。
常见错误是没检查 IsClipboardFormatAvailable 就直接调 GetClipboardData,结果返回 NULL;或者忘了 GlobalUnlock 和 CloseClipboard,导致后续操作失败(比如其他程序无法写入)。
CF_UNICODETEXT 是首选:支持中文、emoji、全角符号,CF_TEXT 只能处理 ANSI 编码(基本废了)HGLOBAL 指针需用 GlobalLock 转成 LPCWSTR,且不能直接当 C++ 字符串用——它不带长度信息,得用 wcslen 或按 null 终止判断OpenClipboard → 读取 → CloseClipboard 全流程,跨线程调用会失败if (OpenClipboard(NULL)) {
if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData) {
LPCWSTR lpcwstr = static_cast(GlobalLock(hData));
if (lpcwstr) {
std::wstring text(lpcwstr); // 自动截断到第一个 \0
GlobalUnlock(hData);
}
}
}
CloseClipboard();
} SetClipboardData 写入 Unicode 文本写入比读取更易出错:必须先 OpenClipboard,再 GlobalAlloc 分配可移动内存(GMEM_MOVEABLE),GlobalLock 后 memcpy 内容,GlobalUnlock,最后 SetClipboardData。漏掉任意一步都会导致写入失败或剪贴板卡死。
关键点在于分配的内存大小:要包含末尾的 \0,且单位是字节(wchar_t 是 2 字节),所以长度是 (text.length() + 1) * sizeof(wchar_t)。
GMEM_FIXED:系统要求剪贴板数据必须是可移动(GMEM_MOVEABLE)内存块SetClipboardData 接管内存所有权,你不能再 GlobalFree 它,否则系统崩溃CloseClipboard,或调用前已有程序占着剪贴板没释放std::wstring text = L"你好,clipboard!";
if (OpenClipboard(NULL)) {
EmptyClipboard();
size_t size = (text.length() + 1) * sizeof(wchar_t);
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, size);
if (hMem) {
LPWSTR lpMem = static_cast(GlobalLock(hMem));
if (lpMem) {
memcpy(lpMem, text.c_str(), size);
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem); // 系统接管 hMem
}
}
CloseClipboard();
} CF_OEMTEXT 和 CF_LOCALE 基本不用CF_OEMTEXT 对应 DOS 时代 OEM 字符集(如 GBK 的变体),现在 Windows 默认用 Unicode,该格式只在极老终端程序里出现;CF_LOCALE 是辅助信息,存区域设置 ID,单独存在无意义,且现代应用完全不依赖它做编码推断。
真正需要多格式支持时(比如粘贴进 Word 要保留粗体),得用 CF_HTML 或 CF_RTF,但它们结构复杂,需手动构造 MIME 头或 RTF 控制字——对纯文本场景属于过度设计。
CF_UNICODETEXT 就够了CF_TEXT 反而引入乱码风险:系统不会自动转码,只会原样返回 ANSI 字节流CF_UNICODETEXT 是唯一稳定选项OpenClipboard 返回 false 或 GetClipboardData 返回 NULL这不是代码写错了,而是系统级阻塞。最常见三种情况:剪贴板正被另一进程独占(如微信、钉钉后台监听)、当前线程没消息循环(GUI 程序必须有 GetMessage 循环)、或调用发生在 DLL 的 DllMain / 静态构造函数中(Windows 明确禁止)。
printf("open: %d\n", OpenClipboard(NULL)); 快速确认是否被占用OpenClipboard 和 GetClipboardData
真正麻烦的不是 API 调用本身,而是状态管理:开没开、锁没锁、关没关、内存谁释放——每一步都得严格配对。稍有遗漏,剪贴板就进入不可用状态,连 Ctrl+V 都失灵。