调用getclipboarddata前必须先openclipboard,否则返回null;需按cf_unicodetext、cf_dibv5等优先级枚举格式,正确解析dib数据并及时closeclipboard。

Windows平台用GetClipboardData获取文本和位图需先打开剪贴板
直接调用GetClipboardData会失败,必须先用OpenClipboard获取所有权,否则返回NULL。常见错误是忘记检查返回值或未及时关闭——这会导致其他程序无法访问剪贴板(表现为复制粘贴卡死)。
实操要点:
-
OpenClipboard传入NULL(当前线程窗口句柄可为NULL,但多线程下建议传真实HWND) - 成功后按需调用
GetClipboardData(CF_TEXT)、GetClipboardData(CF_UNICODETEXT)或GetClipboardData(CF_BITMAP) - 对
CF_UNICODETEXT,返回的是HGLOBAL,需用GlobalLock转为wchar_t*,用完GlobalUnlock - 对
CF_BITMAP,返回HBITMAP,可用GetObject获取尺寸,再用GetDIBits导出像素数据 - 务必在最后调用
CloseClipboard,哪怕中间出错也要保证执行
监听剪贴板变化不能靠轮询,要用AddClipboardFormatListener
轮询GetClipboardSequenceNumber效率低、耗CPU,且无法区分是本进程还是其他进程修改了剪贴板。Windows Vista+ 推荐用AddClipboardFormatListener注册窗口消息监听。
关键约束:
- 目标窗口必须是**有消息循环的UI线程窗口**(控制台程序需创建隐藏窗口或改用Win32 GUI项目)
- 监听后系统会向该窗口发送
WM_CLIPBOARDUPDATE消息,无需SetTimer - 收到消息后,仍需调用
OpenClipboard→GetClipboardData→CloseClipboard流程取内容 - 进程退出前必须调用
RemoveClipboardFormatListener,否则可能引发GDI泄漏
读取图片时CF_BITMAP不够用,要处理CF_DIB和CF_DIBV5
现代应用(如微信、Chrome)复制图片时通常不放CF_BITMAP,而是放CF_DIB(设备无关位图)或CF_DIBV5(带Alpha通道)。只检查CF_BITMAP会漏掉绝大多数图片。
正确做法:
- 用
EnumClipboardFormats遍历所有可用格式,优先匹配CF_DIBV5,其次CF_DIB,最后才看CF_BITMAP -
CF_DIB数据开头是BITMAPINFO结构,后面紧跟像素数据;CF_DIBV5用BITMAPV5HEADER,支持sRGB、Alpha等扩展字段 - 解析时注意
BITMAPINFOHEADER.biHeight为负值表示倒序BGR排列(Top-down DIB),需按实际排布读取 - 若需保存为PNG/JPEG,得用
Gdiplus::Bitmap或第三方库(如stb_image_write)转换,不能直接写二进制
跨进程监听需处理剪贴板所有权冲突和格式兼容性
多个监听程序同时运行时,WM_CLIPBOARDUPDATE会发给所有注册窗口,但OpenClipboard只能由一个线程成功——后调用者会阻塞或失败。这不是bug,是Windows设计使然。
规避方案:
- 监听到更新后,用
GetClipboardOwner判断是否是本进程触发的变更(返回NULL或非本窗体句柄则跳过处理) - 文本优先尝试
CF_UNICODETEXT(UTF-16),fallback到CF_TEXT(ANSI,依赖当前代码页) - 避免在
WM_CLIPBOARDUPDATE处理中做耗时操作(如图像编码、网络上传),应投递到工作线程 - 某些UWP应用(如截图工具)使用
CF_HTML或自定义格式,需额外解析HTML片段提取文本/图片URL
真正难的不是读取,而是在不干扰用户日常复制粘贴的前提下稳定捕获内容——格式判断、内存管理、线程安全、权限边界,每个环节都容易静默失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











