I want to place a GDI+ Bitmap
onto the clipboard. The obvious way would be to:
Bitmap.GetHBITMAP
to create an HBITMAP
SetClipboardData
to place the HBITMAP
onto the clipboard as a CF_BITMAP
So i try pseudo-code:
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();
}
Error checking has been omitted for expository purposes; but neither function fails:
GetHBITMAP
and its HRESULT
style errorSetClipboardData
return a null
But when i try to use the CF_BITMAP
on the clipboard, it can't be pasted into Paint:
So, what is the correct code to fill in the function:
void PlaceBitmapOnClipboard(Bitmap image)
{
//TODO: Ask Stackoverflow to figure this out
}
We need to call:
SetClipboardData(CF_BITMAP, hbitmap_ddb)
Where hbitmap_ddb
must be a compatible bitmap (DDB), not DIB which we get from Gdiplus::GetHBitmap
Or we call:
SetClipboardData(CF_DIB, hmemory)
Where hmemory
is not HBITMAP
. hmemory
is described in documentation as:
A memory object containing a
BITMAPINFO
structure followed by the bitmap bits.
Example using CF_BITMAP
Use CreateDIBitmap
to create a compatible bitmap based on our DIB bitmap. Then call SetClipboardData
with the new DDB bitmap.
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);
Example using CF_DIB
Use GlobalAlloc
to allocate memory, and copy BITMAPINFOHEADER
to that memory, followed by the bits. There is no need to worry about the color table, because Gdiplus::HBitmap
returns 32-bit bitmap (at least on modern displays as far as I know)
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);