【问题标题】:WinAPI: Correctly copying a HBITMAP to the clipboardWinAPI:正确地将 HBITMAP 复制到剪贴板
【发布时间】:2016-09-26 22:50:03
【问题描述】:

尝试将HBITMAP 复制到剪贴板时遇到了一些困难。我的HBITMAP 是从COLORREF 数组创建的,我能够正确显示它。以下是它的创建方式:

COLORREF* colors = new COLORREF[imageSize[0] * imageSize[1]];

for (int i = 0; i < imageSize[1]; i++) {
    for (int j = 0; j < imageSize[0]; j++) {
        colors[imageSize[0] * i + j] = RGB(/* ... */);
    }
}

// Create bitmap
HBITMAP hBitmap = CreateBitmap(imageSize[0], imageSize[1], 1, 32, (void*)colors);

delete[] colors;

为了将我的位图复制到剪贴板,我使用了这段小代码:

OpenClipboard(hWnd);
EmptyClipboard();

SetClipboardData(CF_BITMAP, hBitmap);

CloseClipboard();

当我执行我的应用程序时,我可以复制位图并将其粘贴到某处,例如在 MS Paint 中。但是如果我再次尝试复制它,剪贴板内容将无法再粘贴,除非再次执行上面的第一段代码。

MSDN documentation中,据说

如果SetClipboardData成功,则系统拥有hMem参数标识的对象。

我不明白这到底是什么意思,但我想这是我问题的根源。我找到了一个函数示例,它可以执行我想要的here,但它似乎没有使用相同类型的变量。另一个例子,这次使用字符串,可以找到here

我不太确定如何将最后一个示例转换为我的案例。你能指出我正确的方向吗?

【问题讨论】:

  • COLORREF 用于 RGB 和 RGBA 图像,但这看起来像 32 位灰度图像。然而,我已经很久没有这样做了,我在文档中看不到任何明显的警告。
  • @RemyLebeau 有趣的是,stackoverflow.com/questions/32086618/… 中 OP 的测试结果显然表明系统实际上并不拥有位图的所有权。
  • 查看Clipboard Formats 文档中关于CF_BITMAP 的说明。 CF_BITMAP 是一个 DDB,不能按原样存储,它会被转换并存储为 DIB。

标签: c++ winapi bitmap


【解决方案1】:

一条被删除的评论帮助我找到了答案。在调用SetClipboardData 之前,我实际上必须将我的HBITMAP 复制到另一个HBITMAP。这样,复制的位图可以发送到剪贴板,而原始位图则保留以备后用。

为了复制位图,我使用了Copying a Bitmap to another Bitmap 中的代码。在我的代码中,它看起来像这样:

// Create a new bitmap
HBITMAP hBitmap_copy = CreateBitmap(imageSize[0], imageSize[1], 1, 32, NULL);

// Copy the source bitmap to the new one    
HDC srcDC = CreateCompatibleDC(GetDC(NULL));
HDC newDC = CreateCompatibleDC(GetDC(NULL));

HBITMAP srcBitmap = (HBITMAP)SelectObject(srcDC, hBitmap);
HBITMAP newBitmap = (HBITMAP)SelectObject(newDC, hBitmap_copy);

BitBlt(newDC, 0, 0, imageSize[0], imageSize[1], srcDC, 0, 0, SRCCOPY);

SelectObject(srcDC, srcBitmap);
SelectObject(newDC, newBitmap);

DeleteDC(srcDC);
DeleteDC(newDC);

// hBitmap_copy can now be copied to the clipboard
OpenClipboard(hWnd);
EmptyClipboard();   

SetClipboardData(CF_BITMAP, hBitmap_copy);

CloseClipboard();

我现在可以根据需要多次复制显示的位图!

【讨论】:

    【解决方案2】:
    // You can't pass hBitmap to SetClipboardData directly
    OpenClipboard(NULL)
    HBITMAP hBitmap = getBit(); // From somewhere
    
    DIBSECTION ds;
    ::GetObject(hBitmap, sizeof(DIBSECTION), &ds);
    //make sure compression is BI_RGB
    ds.dsBmih.biCompression = BI_RGB;
    HDC hdc = ::GetDC(NULL);
    HBITMAP hbitmap_ddb = ::CreateDIBitmap(
        hdc, &ds.dsBmih, CBM_INIT, ds.dsBm.bmBits, (BITMAPINFO*)&ds.dsBmih, DIB_RGB_COLORS);
    ::ReleaseDC(NULL, hdc);
    
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hbitmap_ddb);
    CloseClipboard();
    

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-15
      • 1970-01-01
      • 2020-02-06
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多