You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows平台C++中如何复制GetClipboardData返回的剪贴板句柄内容?

解决剪贴板内容保存与恢复的问题

核心问题在于你保存的是剪贴板返回的原句柄,而EmptyClipboard()会让剪贴板回收这些句柄,导致后续无法使用。正确的做法是提前复制句柄指向的实际内容到自己管理的内存中,而不是保存原句柄。

实现步骤

  1. 打开剪贴板并枚举所有存在的格式:不要硬编码格式列表,用EnumClipboardFormats遍历当前剪贴板支持的所有格式,更可靠。
  2. 复制每个格式的内容到自有内存:对每个格式,通过GlobalLock获取内容指针,GlobalSize获取内容长度,然后分配符合剪贴板要求的内存(需带GMEM_MOVEABLE标记),将内容复制进去。
  3. 设置新剪贴板内容并执行操作:清空剪贴板,设置新内容,完成操作后再恢复原内容。
  4. 恢复原剪贴板内容:再次清空剪贴板,将之前保存的每个格式和对应内存句柄交还给剪贴板。

示例代码

#include <vector>
#include <windows.h>

// 保存剪贴板格式与对应内容的结构体
typedef struct {
    UINT format;
    HANDLE data;
} ClipboardItem;

int main() {
    std::vector<ClipboardItem> savedClipboard;
    HANDLE newClipData = WhatIWantOnClipboard(); // 生成新剪贴板内容的自定义函数
    UINT newFormat = CF_TEXT; // 根据实际需求替换格式

    // 1. 打开剪贴板并保存原内容
    if (OpenClipboard(NULL)) {
        UINT format = EnumClipboardFormats(0);
        while (format != 0) {
            HANDLE hClipData = GetClipboardData(format);
            if (hClipData != NULL) {
                LPVOID pSrc = GlobalLock(hClipData);
                SIZE_T dataSize = GlobalSize(hClipData);
                // 分配可被剪贴板接管的内存
                HANDLE hDest = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dataSize);
                if (hDest != NULL) {
                    LPVOID pDest = GlobalLock(hDest);
                    memcpy(pDest, pSrc, dataSize);
                    GlobalUnlock(hDest);
                    savedClipboard.push_back({format, hDest});
                }
                GlobalUnlock(hClipData);
            }
            format = EnumClipboardFormats(format);
        }

        // 2. 设置新剪贴板内容
        EmptyClipboard();
        SetClipboardData(newFormat, newClipData);
        CloseClipboard(); // 释放剪贴板,允许其他程序访问

        // 执行需要使用新剪贴板的操作
        DoSomethingWithClipboard();

        // 3. 恢复原剪贴板内容
        if (OpenClipboard(NULL)) {
            EmptyClipboard();
            for (auto& item : savedClipboard) {
                SetClipboardData(item.format, item.data);
                // 注意:SetClipboardData后,剪贴板接管内存所有权,无需手动释放
            }
            CloseClipboard();
        }
    }

    return 0;
}

关键说明

  • 原句柄失效原因:GetClipboardData返回的句柄由剪贴板管理,调用EmptyClipboard()时,剪贴板会立即释放这些句柄,后续再使用会触发"访问拒绝"错误。
  • 内存分配要求:必须用GlobalAlloc并指定GMEM_MOVEABLE,因为剪贴板需要可移动的内存块来管理。SetClipboardData后,内存所有权转移给剪贴板,不要自行释放。
  • 特殊格式处理:对于私有格式或CF_OWNERDISPLAY这类特殊格式,可能需要额外处理,但绝大多数标准格式(如文本、图片)都适用此方法。

内容的提问来源于stack exchange,提问作者mRedgate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:13:09