November 1997

Bitmaps on demand

by Kent Reisdorph

Did you ever wonder how you could get your hands on certain bitmaps found in Windows? Maybe your application has owner-drawn controls. Or, perhaps you’re writing a custom component and you need it to look as much as possible like a standard Windows control. The minimize button, maximize button, close button, scroll bar arrows, menu check marks--they all have to come from somewhere. But how do you get hold of them? In this article, we’ll show you their hiding places.

LoadBitmap

The secret lies in the Windows API function LoadBitmap(), which you can use to load a bitmap contained in your application as a resource. Typically, you create a resource with a resource editor, bind it to the executable file when you build your application, and then load and display it at runtime.

But LoadBitmap() can also extract the stock Windows bitmaps. The Win32 online help contains a complete list of bitmaps that you can obtain using LoadBitmap(), along with their constants. To obtain the flying Windows logo, for example, you could use code like the following:

#include 
HBITMAP hBitmap = 
  LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE)); 
This code loads the bitmap identified by OBM_CLOSE (the close-box bitmap). Figure A shows a program that displays all the bitmaps available to you, along with their constant names. Note that some bitmap names begin with OBM_OLD. These bitmaps don’t display, because the constants are leftover from prior versions of Windows. If you want to use the resource names, then you must include the WINSRESRC.H file in which the constant names are defined.

Figure A:Our example program shows all the stock Windows bitmaps. Figure A

So now what?

OK, so our example doesn’t tell you much about what to do with the bitmap once you’ve pried it out of Windows. A typical VCL use of one of these bitmaps might look like this:
Graphics::TBitmap* bm = new Graphics::TBitmap;
bm-&gtHandle = 
  LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE));
if (bm-&gtHandle) 
  Canvas-&gtDraw(0, 0, bm);
delete bm;
This code loads the close-box bitmap from Windows and displays it in the upper-left corner of the form. Once you give the bitmap handle to VCL, you no longer have to worry about it--the TBitmap class will take care of freeing the resource. Listing A contains the paint routine we used to produce the program shown in Figure A. A quick look at this listing will show you how to load and display bitmaps in VCL.

That’s it!

Does this technique sound simple? Well, so it is. When you need your owner-drawn controls to look just like the Windows controls, you know where to get the bitmaps. The pre-defined Windows bitmaps are there for the taking--why bother creating your own? Listing A: OnPaint handler
void __fastcall TForm1::FormPaint(TObject *Sender)
{
  TStringList* Names = new TStringList;
  Names-&gtAdd(“Undocumented”);
  Names-&gtAdd(“Undocumented”);
  Names-&gtAdd(“N/A”);
  Names-&gtAdd(“OBM_LFARROWI”);
  Names-&gtAdd(“OBM_RGARROWI”);
  Names-&gtAdd(“OBM_DNARROWI”);
  Names-&gtAdd(“OBM_UPARROWI”);
  Names-&gtAdd(“OBM_COMBO”);
  Names-&gtAdd(“OBM_MNARROW”);
  Names-&gtAdd(“OBM_LFARROWD”);
  Names-&gtAdd(“OBM_RGARROWD”);
  Names-&gtAdd(“OBM_DNARROWD”);
  Names-&gtAdd(“OBM_UPARROWD”);
  Names-&gtAdd(“OBM_RESTORED”);
  Names-&gtAdd(“OBM_ZOOMD”);
  Names-&gtAdd(“OBM_REDUCED”);
  Names-&gtAdd(“OBM_RESTORE”);
  Names-&gtAdd(“OBM_ZOOM”);
  Names-&gtAdd(“OBM_REDUCE”);
  Names-&gtAdd(“OBM_RGARROW”);
  Names-&gtAdd(“OBM_LFARROW”);
  Names-&gtAdd(“OBM_DNARROW”);
  Names-&gtAdd(“OBM_UPARROW”);
  Names-&gtAdd(“OBM_CLOSE”);
  Names-&gtAdd(“OBM_OLD_RESTORE”);
  Names-&gtAdd(“OBM_OLD_ZOOM”);
  Names-&gtAdd(“OBM_OLD_REDUCE”);
  Names-&gtAdd(“OBM_BTNCORNERS”);
  Names-&gtAdd(“OBM_CHECKBOXES”);
  Names-&gtAdd(“OBM_CHECK”);
  Names-&gtAdd(“OBM_BTSIZE”);
  Names-&gtAdd(“OBM_OLD_LFARROW”);
  Names-&gtAdd(“OBM_OLD_RGARROW”);
  Names-&gtAdd(“OBM_OLD_DNARROW”);
  Names-&gtAdd(“OBM_OLD_UPARROW”);
  Names-&gtAdd(“OBM_SIZE”);
  Names-&gtAdd(“OBM_OLD_CLOSE”);
  Graphics::TBitmap* bm = new Graphics::TBitmap;
  int y = 20;
  int x = 20;
  int Offset;
  Canvas-&gtBrush-&gtStyle = bsClear;
  for (int i = 1;i < 38;i++) {
    bm-&gtHandle = 
      LoadBitmap(NULL, MAKEINTRESOURCE(i + 32730));
    if (bm-&gtHandle) {
      Canvas-&gtFont-&gtColor = clBlack;
      Canvas-&gtDraw(x + 130, y, bm);
      Offset = (y + (bm-&gtHeight / 2)) - 6;
    }
    else {
      Canvas-&gtFont-&gtColor = clGray;
      Offset = y + 5;
    }
    Canvas-&gtTextOut(x, Offset, Names-&gtStrings[i - 1]);
    if (bm-&gtHeight > 21) y += bm-&gtHeight + 5;
    else y+= 21;
    if (i > 18 && x == 20) {
      y = 20;
      x = 220;
    }
  }
  delete bm;
  delete Names;
}