5

I have some difficulties trying to copy a HBITMAP to the clipboard. My HBITMAP is created from a COLORREF array and I am able to display it correctly. Here is how it is created:

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;

In order to copy my bitmap to the clipboard, I use this small piece of code:

OpenClipboard(hWnd);
EmptyClipboard();

SetClipboardData(CF_BITMAP, hBitmap);

CloseClipboard();

When I execute my app, I am able to copy the bitmap and paste it somewhere, for example in MS Paint. But if I try to copy it a second time, the clipboard content can't be pasted anymore unless the first piece of code above is executed again.

In the MSDN documentation, it is said that

If SetClipboardData succeeds, the system owns the object identified by the hMem parameter.

I don't understand exactly what this means, but I guess it is the source of my problem. I found an example of a function which does what I want here, but it does not seem to use the same kind of variables. Another example, using strings this time, can be found here.

I am not too sure how to translate this last example to my case. Could you point me in the right direction?

Community
  • 1
  • 1
JD80121
  • 477
  • 3
  • 12
  • `COLORREF` is for RGB and RGBA images, but this looks like a 32-bit grayscale image. It's long since I've done this however and I couldn't see any obvious caveat in the documentation. – Cheers and hth. - Alf May 28 '16 at 19:47
  • @RemyLebeau Interestingly, the results of the OP's tests in http://stackoverflow.com/questions/32086618/who-releases-handle-in-setclipboarddatacf-bitmap-hbitmap apparently showed that the system does not in fact take ownership of the bitmap. – Jonathan Potter May 28 '16 at 20:09
  • 1
    See the notes about `CF_BITMAP` in the [Clipboard Formats](https://msdn.microsoft.com/en-us/library/windows/desktop/ms649013.aspx) documentation. `CF_BITMAP` is a DDB and can't be stored as-is, it gets converted and stored as a DIB instead. – Remy Lebeau May 28 '16 at 20:17

2 Answers2

2

A comment that was deleted helped me find the answer. I actually have to copy my HBITMAP to another HBITMAP before calling SetClipboardData. This way, the copied bitmap can be sent to the clipboard, and the original bitmap is kept for later.

To copy the bitmap, I used the code that can be found in Copying a Bitmap to another Bitmap. In my code, it looks like this:

// 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();

I can now copy the displayed bitmap as many times as I want!

JD80121
  • 477
  • 3
  • 12
1
// 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();
Dana Yan
  • 406
  • 4
  • 8