Status bars are great for displaying text, but what if you want to put a bitmap in your status bar, as Microsoft Mail does? Using the Win32 API, you can add a bitmap by taking advantage of the control's support for owner drawing. Owner drawing lets you display a bitmap instead of text (or use a different font) in a section of a status bar. In the code you just saw, you send the SB_SETTEXT message with the SBT_OWNERDRAW drawing style specified to tell the system that a part of your status bar should be owner-drawn. The lParam parameter is a 32-bit, application-defined value that the application can use when drawing that part of the status bar (that is, you can pass a bitmap handle in this parameter if you like). At this point, you treat the control like any other owner-drawn control: you handle the WM_DRAWITEM message and then use the information in the DRAWITEMSTRUCT structure that is passed along. The following code demonstrates how I did this in the STATUS sample:
case WM_DRAWITEM:
if ((int)wParam == ID_STATUSBAR)
{
LPDRAWITEMSTRUCT lpDis;
HDC hdcMem;
HBITMAP hbmOld;
BITMAP bm;
// Save the drawing information. This information is specific
// to the part of the status bar to be drawn.
lpDis = (LPDRAWITEMSTRUCT)lParam;
// Create a compatible device context (DC) for the bit block
// transfer (bitblt).
hdcMem = CreateCompatibleDC (lpDis->hDC);
// Select the bitmap into the DC.
hbmOld = SelectObject (hdcMem, hBmp);
// Get the information about the bitmap's size.
GetObject (hBmp, sizeof (bm), &bm);
// Use BitBlt to transfer the bitmap to the part.
BitBlt (lpDis->hDC, lpDis->rcItem.left,
lpDis->rcItem.top,
bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
// Reselect the original object into the DC.
SelectObject (hdcMem, hbmOld);
// Delete the compatible DC.
DeleteDC (hdcMem);
}
break;
Some clever readers will notice that I call the BitBlt function to transfer a bitmap but that this bitmap is not drawn transparently. I cheated a bit by drawing the background as the standard gray used in most status bars. If someone were to change the color of the status bar, this little cheat would show.
The code in my MFC version of this sample looks strikingly familiar; however, I ran into a big gotcha when I ported this portion of the code. In short, the MFC class that is provided demands that you override the DrawItem method of the CStatusBarCtrl class in order to use the owner-drawn capabilities of the status bar. Initially, I just handled the WM_DRAWITEM message in the view, and the bitmap and the status bar drew correctly. But I kept getting these pesky ASSERT messages. When I tracked down the problem, I was annoyed, to say the least. To remedy the situation, I used ClassWizard to create a class based on CStatusBarCtrl and handled the DrawItem method myself. The MFC sample uses the following code to draw its bitmap on the status bar:
// CStatus message handlers
void CStatus::DrawItem (LPDRAWITEMSTRUCT lpDrawItemStruct)
{
static HBITMAP m_Bmp;
if (m_Bmp == NULL)
// Load the bitmap for the owner-drawn part of the status bar.
m_Bmp = ::LoadBitmap (AfxGetResourceHandle (),
MAKEINTRESOURCE (ID_BITMAP));
// Create a compatible DC for the bit block transfer.
HDC hdcMem = ::CreateCompatibleDC (lpDrawItemStruct->hDC);
// Select the bitmap into the DC.
HBITMAP hbmOld = (HBITMAP) ::SelectObject (hdcMem,
(HBITMAP)m_Bmp);
BITMAP bm;
// Get the information about the bitmap's size.
::GetObject ((HBITMAP)m_Bmp, sizeof (bm), &bm);
// Use BitBlt to transfer the bitmap.
::BitBlt (lpDrawItemStruct->hDC,
lpDrawItemStruct->rcItem.left,
lpDrawItemStruct->rcItem.top,
bm.bmWidth,
bm.bmHeight,
hdcMem, 0, 0,
SRCCOPY);
// Reselect the original bitmap.
::SelectObject (hdcMem, hbmOld);
// Delete the compatible DC.
::DeleteDC (hdcMem);
}