Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WinAPI: Correctly copying a HBITMAP to the clipboard

Tags:

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?

like image 832
JD80121 Avatar asked May 28 '16 19:05

JD80121


1 Answers

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!

like image 87
JD80121 Avatar answered Sep 28 '22 01:09

JD80121