如何安全、正确地创建 Windows 剪贴板的备份?
我正在尝试创建 Windows 剪贴板的备份。基本上我正在做的是使用 EnumClipboardFormats()
获取当前剪贴板上存在的所有格式,然后对于每种格式,我调用 GetClipboardData(format)
代码>.
备份数据的一部分显然涉及复制数据。我通过对返回的数据调用 GlobalLock()
(其中“锁定全局内存对象并返回指向该对象内存块的第一个字节的指针。”)来实现这一点。通过 GetClipboardData()
,然后通过调用 GlobalSize()
获取数据的大小,最后执行 memcpy()
来复制数据。当我完成后,我当然会调用 GlobalUnlock()
。
嗯,这在大多数情况下都有效。如果剪贴板包含格式为 CF_BITMAP 或 CF_METAFILEPICT 的数据,我的程序会在 GlobalLock()
处崩溃。阅读这篇旧新事物博客文章 (https://devblogs.microsoft. com/oldnewthing/20071026-00/?p=24683)我找到了崩溃发生的原因:显然并非剪贴板上的所有数据都是使用 GlobalAlloc()
分配的(例如 CF_BITMAP 数据),因此对该数据调用 GlobalLock()
会导致崩溃。
我遇到了这篇 MSDN 文章,它给出了剪贴板格式列表以及系统如何释放它们。因此,我所做的是将系统未通过 GlobalFree() 函数释放的所有剪贴板格式 (CF_*) 硬编码到我的程序中,并且我根本不备份这些格式;我跳过它们。
事实上,这个解决方法看起来效果很好。即使剪贴板上有位图或“特殊”数据(例如从 Excel 复制到剪贴板的行),我的剪贴板备份功能也运行良好,并且没有遇到任何崩溃。另外,即使剪贴板上有位图,并且我在备份期间跳过了某些格式(例如 CF_BITMAP),在恢复剪贴板备份后,我仍然可以按 Ctrl+V 从剪贴板粘贴最初复制的位图,因为位图也由剪贴板上的其他格式表示,这不会导致我的程序崩溃(CF_DIB)。
然而,这充其量只是一种解决方法。我担心的是,其中一次某些奇怪的格式(可能是私有格式,即 CF_PRIVATEFIRST 和 CF_PRIVATELAST 之间的格式,或者可能是其他类型)将出现在剪贴板上,并且我的程序在调用 GlobalLock() 后将再次崩溃。但是,由于似乎没有太多文档解释备份剪贴板的最佳方法,并且很明显 GlobalLock()
不能对所有数据类型正常工作(不幸的是),我不知道如何处理这些情况。是否可以安全地假设所有其他格式(除了前面 URL 中列出的未由 GlobalFree()
释放的格式)之外的所有其他格式都可以使用 GlobalLock()< 进行“抓取” /代码>?
有什么想法吗?
I'm trying to create a backup of the Windows clipboard. Basically what I'm doing is using EnumClipboardFormats()
to get all of the formats that exist on the clipboard currently, and then for each format, I'm calling GetClipboardData(format)
.
Part of backing up the data obviously involves duplicating it. I do that by calling GlobalLock()
(which "Locks a global memory object and returns a pointer to the first byte of the object's memory block.") on the data returned by GetClipboardData()
, then I fetch the size of the data by calling GlobalSize()
, and then finally I do a memcpy()
to duplicate the data. I then of course call GlobalUnlock()
when I'm done.
Well, this works... most of the time. My program crashes at the GlobalLock()
if the clipboard contains data with the format CF_BITMAP or CF_METAFILEPICT. After reading this Old New Thing blog post (https://devblogs.microsoft.com/oldnewthing/20071026-00/?p=24683) I found out why the crash occurs: apparently not all data on the clipboard is allocated using GlobalAlloc()
(such as CF_BITMAP data), and so calling GlobalLock()
on that data causes a crash.
I came across this MSDN article and it gives a list of clipboard formats and how they are freed by the system. So what I did was hard-code into my program all of the clipboard formats (CF_*) that are not freed by the GlobalFree()
function by the system, and I simply don't back up those formats; I skip them.
This workaround seems to work well, actually. Even if a bitmap is on the clipboard, or "special" data (such as rows copied from Excel to the clipboard), my clipboard backup function works well and I haven't experienced any crashes. Also, even if there's a bitmap on the clipboard and I skip some formats during the backup (like CF_BITMAP), I can still Ctrl+V paste the originally-copied bitmap from the clipboard after restoring my clipboard backup, as the bitmap is represented by other formats on the clipboard as well that don't cause my program to crash (CF_DIB).
However, it's a workaround at best. My fear is that one of these times some weird format (perhaps a private one, i.e one between CF_PRIVATEFIRST and CF_PRIVATELAST, or maybe some other type) will be on the clipboard and my program, after calling GlobalLock()
, will crash again. But since there doesn't seem to be much documentation explaining the best way to back up the clipboard, and it's clear that GlobalLock()
does not work properly for all datatypes (unfortunately), I'm not sure how to handle these situations. Is it safe to assume that all other formats -- besides the formats listed in the previous URL that aren't freed by GlobalFree()
-- can be "grabbed" using GlobalLock()
?
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是愚蠢的,因为您无法 100% 备份/恢复剪贴板。许多应用程序使用延迟渲染,并且数据实际上并不在剪贴板上。当您请求粘贴时,他们会收到通知并生成数据。对于来自 Excel 等应用程序的大量数据,这将需要几分钟和数百 MB 的时间。从 Excel 复制时,查看剪贴板上列出的格式数量。会有两打以上,包括Bitmap、Metafile、HTML。如果您在 Excel 中选择 255x25000 单元格并复制它,您认为会发生什么?该位图有多大?提示:在尝试此操作之前,请保存所有打开的文档,因为您可能需要重新启动。
This is folly, as you cannot 100% backup/restore the clipboard. Lots of apps used delayed rendering, and the data is not actually on the clipboard. When you request to paste, they get notified and produce the data. This would take several minutes and hundreds of MB for large amounts of data from apps like Excel. Take a look at the number of formats listed on the clipboard when you copy from Excel. There will be more than two dozen, including Bitmap, Metafile, HTML. What do you think will happen if you select 255x25000 cells in Excel and copy that? How large would that bitmap be? Tip: save any open documents before attempting this, as you're likely going to have to reboot.