winapi - 如何将 GDI+ 位图放入剪贴板?

标签 winapi gdi+ clipboard

我想放置一个 GDI+ Bitmap到剪贴板。显而易见的方法是:

所以我尝试伪代码:

void PlaceBitmapOnClipboard(Bitmap image)
{
   //Convert GDI+ Bitmap to GDI Bitmap
   HBITMAP bmp;
   image.GetHBITMAP(0, @bmp);

   OpenClipboard(this.Handle);
      EmptyClipboard();
      SetClipboardData(CF_BITMAP, bmp);
   CloseClipboard();
}

出于说明目的,省略了错误检查;但两个函数都失败了:

  • 不是 GetHBITMAP 及其 HRESULT 样式错误
  • SetClipboardData 也不返回 null

但是当我尝试使用剪贴板上的CF_BITMAP时,它无法粘贴到Paint中:

enter image description here

那么,填写该函数的正确代码是什么:

void PlaceBitmapOnClipboard(Bitmap image)
{
   //TODO: Ask Stackoverflow to figure this out

}

最佳答案

我们需要调用:
SetClipboardData(CF_BITMAP, hbitmap_ddb)

其中 hbitmap_ddb 必须是兼容位图 (DDB),而不是我们从 Gdiplus::GetHBitmap 获取的 DIB


或者我们调用:
SetClipboardData(CF_DIB, hmemory)

其中 hmemory 不是 HBITMAPdocumentation 中描述了 hmemory如:

A memory object containing a BITMAPINFO structure followed by the bitmap bits.


使用CF_BITMAP的示例

使用CreateDIBitmap根据我们的DIB位图创建兼容的位图。然后使用新的 DDB 位图调用 SetClipboardData

Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
    return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(0, &hbitmap);
if(status != Gdiplus::Ok)
    return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
DIBSECTION ds;
if(sizeof ds == GetObject(hbitmap, sizeof ds, &ds))
{
    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);
    if(OpenClipboard(hwnd))
    {
        EmptyClipboard();
        SetClipboardData(CF_BITMAP, hbitmap_ddb);
        CloseClipboard();
    }
    DeleteObject(hbitmap_ddb);
}
DeleteObject(hbitmap);

使用CF_DIB的示例

使用GlobalAlloc分配内存,并将BITMAPINFOHEADER复制到该内存,后跟位。无需担心颜色表,因为 Gdiplus::HBitmap 返回 32 位位图(至少在我所知的现代显示器上)

Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
    return;

HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(NULL, &hbitmap);
if(status != Gdiplus::Ok)
    return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);

BITMAPINFOHEADER bi =
{ sizeof bi, bm.bmWidth, bm.bmHeight, 1, bm.bmBitsPixel, BI_RGB };

std::vector<BYTE> vec(bm.bmWidthBytes * bm.bmHeight);
auto hdc = GetDC(NULL);
GetDIBits(hdc, hbitmap, 0, bi.biHeight, vec.data(), (BITMAPINFO*)&bi, 0);
ReleaseDC(NULL, hdc);

auto hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof bi + vec.size());
auto buffer = (BYTE*)GlobalLock(hmem);
memcpy(buffer, &bi, sizeof bi);
memcpy(buffer + sizeof bi, vec.data(), vec.size());
GlobalUnlock(hmem);

if(OpenClipboard(hwnd))
{
    EmptyClipboard();
    SetClipboardData(CF_DIB, hmem);
    CloseClipboard();
}
DeleteObject(hbitmap);

关于winapi - 如何将 GDI+ 位图放入剪贴板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35154938/

相关文章:

c# - GDI+ 绘制矩形很慢

c++ - 将窗口内容显示为位图

windows - 在 Windows 剪贴板复制缓冲区中包含格式信息,以便粘贴到 Excel 中

c++ - 如何创建实心箭头 CustomLineCap?

ios - UIPasteboard无法多次复制带有过期时间的文本

C# - 剪贴板 Hook 检查正在复制的数据是真的图像还是文本?

c# - 如何确定修改文件的最后一个进程?

c++ - 在 64 位机器中无法使用 getsystemdirectory() 获取正确的路径

c++ - 在 OPENFILENAMEW 结构中填充 lpstrFile 时不推荐从字符串常量到 LPWSTR 的转换

c++ - 捕获 Visual Studio 响应文件?