Introduction
Recently, I had cause to save a DIB to the clipboard. I tried numerous methods over a four-week period, but none of
them worked (many thanks to Chris Losinger and Christian Graus for their willingness to try and provide me with
guidance, an answer, or both). This article describes how I finally attained my goal, but also falls neatly into the
category It Ain't Pretty But It Works.
Trials and Tribulations
Since the reason I need to do this is fairly well out of the scope of this article, suffice it to say that my
starting point was a BITMAPINFOHEADER
struct and a pointer to an array of bits which represented the actual bitmap
data. The bitmap was of the 24-bit variety.
At first, I wandered around trying to create a bitmap handle with the info I had. I was sure I was doing it right,
but with failure after failure where moving that bitmap to the clipboard was concerned, I (naturally) assumed I must
have really mucked it up, so I went looking for help, and ended up using Chris Maunder's CDIBSectionLite class.
Chris's class contains all the code necessary to turn my captured bitmap into a DIBSection, but it lacked the code
to move the DIB to the clipboard. This turned out to be a great place to start. However, no matter what I tried, I
couldn't get the bitmap to the clipboard.
How It all Came Together
After doinking around for a week trying to coerce the desired functionality out of my code (and CDIBSectionLite), I
called the Microsoft Software Developer Hotline (using one of two available free incidents on my MSDN subscription).
The guy at MS steered me to a sample that evidently comes with the compiler called wincap32. This sample
program will capture the contents of the selected window and convert it to a DIB, and store it on the clipboard.
Perfect.
After changing a one or two #include statements, and changing the name of a file, I compiled my code, ran the
resulting program, and bingo - DIB on the clipboard!
What I did
The first thing I did was to add this function to the CDIBSectionLite
class (remember, it ain't pretty, but it
works:
HANDLE CDIBSectionLite::PutOnClipboard()
{
HANDLE hResult = NULL;
if (::OpenClipboard(NULL))
{
::EmptyClipboard();
::GdiFlush();
HDIB hDib = NULL;
HBITMAP hBitmap = NULL;
HPALETTE ghPal = NULL;
if (m_hBitmap)
{
hDib = BitmapToDIB(m_hBitmap, ghPal);
if (hDib)
{
hResult = ::SetClipboardData(CF_DIB, hDib);
if (hResult == NULL)
{
_ShowLastError();
}
}
else
{
MessageBeep(0);
}
}
::CloseClipboard();
}
return hResult;
}
From the Microsoft sample application, I copied the following files into my project directory:
DIBUTIL.C
DIBUTIL.H
DIBAPI.H
I then renamed the DIBUTIL.C file to DIBUTIL.CPP. After that, I had to make the following changes in that file so
that it would compile. The sample app compiled as is, but because I included stdafx.h, the compiler puked on some type
mismatches, hence the following changes:
Line 30: #include <windows.h>
to: #include "stdafx.h"
Line 381: lpbi = GlobalLock(hDIB);
to: lpbi = (LPSTR)GlobalLock(hDIB);
Line 524: lpDIBHdr = GlobalLock(hDIB);
to: lpDIBHdr = (LPSTR)GlobalLock(hDIB);
Line 608: hPal = GetStockObject(DEFAULT_PALETTE);
to: hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
Finally, I was using the whole shebang as follows:
HBITMAP hBitmap;
BITMAPINFO bmi;
memset(&bmi, 0, sizeof(BITMAPINFO));
bmi.bmiHeader = cb.bih;
CDIBSectionLite dib;
dib.SetBitmap(&bmi, cb.pBuffer);
dib.PutOnClipboard();
In The End
It works. I'm not really interested in culling out just the stuff I need from the files I harvested from the
Microsoft sample app, so I intend on just leaving it all in there. This is an exercise I am leaving to the reader.
The zip file accompanying this article contains both the modified CDIBSectionLite
class with the modified sample app
files, as well as the entire sample app source in it's native form. One thing to note is that if compiled as is, the
sample app project creates (or is supplied with) a DLL called DIBAPI.DLL. This DLL contains the code that I linked
directly into my program (I didn't want it in DLL form).
Due to the size of the bitmaps I'm capturing, I didn't equip CDIBSectionLite
with the ability to save the bitmap on
the clipboard as anything other than a DIB. However, keep in mind that it is possible to save multiple items on the
clipboard at one time, so you could simultaneously (using the sample app code) place a bitmap on the clipboard in DIB
format, device dependent format, and metafile format if that's what trips your trigger. Any app that pastes from the
clipboard will/should pull out the format that best fits it's requirements.