The Rebar Control: Using a Coolbar in Your Application

Nancy Winnick Cluts
Developer Technology Engineer
Microsoft Corporation

October 1996
Updated June 24, 1997

Click to open or copy the files in the REBAR sample application for this technical article.

Contents

What Is a Coolbar?
Creating a Coolbar
Messages and Notifications
Summary

Abstract

One of the controls created for Internet Explorer 3.0 is the Rebar control. It is most commonly known, however, as the coolbar. A coolbar contains child windows such as toolbars, combo boxes, and bitmaps, and manages the size and position of the child windows it contains. Once you create the child windows and assign them to the coolbar, the child windows are displayed in it. This article demonstrates how to create and use a coolbar. The sample that accompanies this article, creatively named "Rebar," was written using Microsoft® Visual C++® version 4.2, the Win32® Software Development Kit (SDK), and the ActiveX™ SDK for Internet Explorer 3.x. If you are going to use the coolbar in an application targeted to Internet Explorer 4.0, use the Internet Client SDK (INet SDK) instead of the ActiveX SDK.

What Is a Coolbar?

If you use Internet Explorer 3.0, you've seen the coolbar at the top of the screen, and probably thought that it was just a funky toolbar. Take a look:

Figure 1. The Coolbar for Internet Explorer 3.0

Figure 1 shows a coolbar containing several child windows: a toolbar, a list of Internet links, a drop-down combo box listing the URL history, and an animation control. Note that the toolbar control is transparent to the background bitmap of the coolbar. This works because the toolbar and the coolbar both speak the same “transparency” language. Currently, the toolbar is the only control that supports this type of transparency.

In order to create a coolbar like the one in Figure 1, you need to:

  1. Create the coolbar.

  2. Create your child windows.

  3. Insert each child window into the coolbar.

Each area that contains a child window is referred to as a band. Coolbars can contain one or more bands. Each band can have any combination of the following: a gripper bar, a bitmap, a text label, and a child window. However, each band cannot contain more than one of these items. For example, you cannot have two grippers or two child windows within one band.

All bands, except those that have the RBBS_FIXEDSIZE style, can be resized via the gripper bar. You can also single-click the gripper bar to minimize or maximize the band. The coolbar manages the size and position of the child window assigned to that band.

Creating a Coolbar

Creating a coolbar is similar to creating any other type of common control: You initialize the common control library and use the CreateWindowEx function.

Using InitCommonControlsEx

The first thing your application must do is register the coolbar window class via the InitCommonControlsEx function. This function is different from InitCommonControls (which took no parameters) in that it is passed a structure, INITCOMMONCONTROLSEX, that describes what you want initialized. You need to fill in the dwSize member of this structure to successfully initialize the common control classes. This member allows the system to determine which version of the common controls you are using. INITCOMMONCONTROLSEX also contains the dwICC member, which specifies the common control you would like initialized. This member can be any combination of the following:

Table 1. Common Control Class Constants

Value Meaning
ICC_ANIMATE_CLASS Load animate control class.
ICC_BAR_CLASSES Load toolbar, status bar, track bar, and tooltips control classes.
ICC_COOL_CLASSES Load the coolbar class.
ICC_DATE_CLASSES Load date and time picker control class.
ICC_HOTKEY_CLASS Load hot-key control class.
ICC_LISTVIEW_CLASSES Load list view and header control classes.
ICC_PROGRESS_CLASS Load progress bar control class.
ICC_TAB_CLASSES Load tab and tooltips control classes.
ICC_TREEVIEW_CLASSES Load tree view and tooltips control classes.
ICC_UPDOWN_CLASS Load up-down control class.
ICC_USEREX_CLASSES Load ComboBoxEx class.
ICC_WIN95_CLASSES Load the animate control, header, hot-key, list view, progress bar, status bar, tab, tooltips, toolbar, track bar, tree view, and up-down control classes.

The code to initialize the common control class for a coolbar is as follows:

INITCOMMONCONTROLSEX icex;

icex.dwSize = sizeof(INITCOMMONCONTROLSEX);

// Load the coolbar. 
icex.dwICC = ICC_COOL_CLASSES;   

InitCommonControlsEx(&icex);

Setting Up the Coolbar

Once the class has been registered, the application calls CreateWindowEx, specifying REBARCLASSNAME as the class name to create the coolbar (remember, the “real” name of the coolbar is Rebar). If you are going to add an image list to your coolbar, your application must send the RB_SETBARINFO message. This message passes a pointer to a structure, REBARINFO, in its lParam. The structure information below is based on information in the ActiveX SDK:

typedef struct tagREBARINFO{
   UINT        cbSize;
   UINT        fMask;
   HIMAGELIST  himl;
} REBARINFO, FAR *LPREBARINFO;

where:

Coolbar styles

Special styles are associated with coolbar windows. These are listed in Table 2. Specify these styles in the same way that you specify other window styles in your call to CreateWindowEx.

Table 2. The REBARINFO Styles

Value Meaning
RBS_TOOLTIPS Tooltips are supported. This style allows you to use the same tooltip in all of the inner bands. There is no hot region in the coolbar that will otherwise cause the tooltip created by this style bit to be shown.
RBS_VARHEIGHT The coolbar displays bands at the minimum required height when possible. Without this style, the coolbar displays all bands at the same height. The control uses the height of the tallest visible band to determine the height of other bands.
RBS_BANDBORDERS A border is placed around each band in the coolbar.
RBS_FIXEDORDER This style prevents the user from reordering the coolbar bands.

Like the INITCOMMONCONTROLSEX structure, the REBARINFO structure also contains a sizing member, cbSize, that your application must fill in before sending a message that uses the structure. The code below does the following:

  1. Creates an image list to associate with the coolbar and adds an image to it.

  2. Creates a coolbar that supports variable band height and has a background bitmap associated with it.

  3. Associates the image list with the coolbar.
    // Create the image list.
    hIml = ImageList_Create (
       MIN_COMBOCX, // width
       MIN_COMBOCY, // height 
       0,              // creation flags
       NUM_LINKS + 1,           // number of images
       0);             // amount this list can grow
    
    // Load the bitmap and add it to the image list.
    hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (IDB_SMEAR));
    idxFirstImage = ImageList_Add (hIml,  // handle to image list
       hBmp,        // handle of bitmap to add
       NULL);       // handle of bitmap mask
    
    // Create the COOLBAR control.
    hWndRebar = CreateWindowEx( 
       0L,
       REBARCLASSNAME,
       NULL,
       WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPCHILDREN |
          WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN |
          RBS_VARHEIGHT | RBS_BANDBORDERS,
          0, 0, 400, 275,
       hWndParent,
       (HMENU)ID_REBAR,
       hInst,
       NULL );
    
    if (!hWndRebar)
       return 0;
    
    // Set the image list for the coolbar.
    rbi.cbSize = sizeof(rbi);
    rbi.fMask = RBIM_IMAGELIST;
    rbi.himl = hIml;
    SendMessage(hWndRebar, RB_SETBARINFO, 0L, (LPARAM)&rbi);
    

Using an Extended Combo Box

Now that the coolbar has been created, we’d like to add some bands to it. Within each band, there will be one child control. In our example, we have two bands: one containing an extended drop-down combo box and the other containing a transparent toolbar. Let’s first talk about the extended combo box that I decided to add.

Combo boxes have been extended to support images and indentation. In the Rebar sample, I include an image for each item in my drop-down list of links to the Internet. You create an extended combo box by specifying “ComboBoxEx32" (in versions of Internet Explorer later than 3.x, use WC_COMBOEX) as the class in your call to CreateWindowEx. To use an image list, send the CBEM_SETIMAGELIST message with the handle to the image list after creating the combo box. Inserting items into the combo box is easy; you simply send the CBEM_INSERTITEM message with a pointer to a COMBOBOXEXITEM. This structure contains a field, fMask, that specifies which items in the structure are valid. Valid masks specify characteristics such as indented (CBEIF_INDENT), textual (CBEIF_TEXT), image (CBEIF_IMAGE), and extra data (CBEIF_LPARAM). Setting the iItem member of this structure to –1 indicates that you want the item inserted at the end of the list.

// Global array of cool links.
COOLLINKS rgLinks[] = 
{
   {TEXT("Microsoft"),TEXT("http://www.microsoft.com/default.htm"), IDB_MSFT},
   {TEXT("Microsoft Developer Network Online"), TEXT("http://www.microsoft.com/msdn/default.htm"), IDB_FDO},
   {TEXT("Site Builder"), TEXT("http://www.microsoft.com/workshop/default.htm"), IDB_SB},
   {TEXT("Win32 Development"),TEXT("http://www.microsoft.com/win32dev/default.htm"), IDB_WIN32},
   {TEXT("Interactive Media"), TEXT("http://www.microsoft.com/imedia/default.htm"), IDB_IM},
   {TEXT("Microsoft Developer Network"),TEXT("http://www.microsoft.com/msdn/default.htm"), IDB_MSDN},
   {TEXT("Internet Explorer"),TEXT("http://www.microsoft.com/ie30/default.htm"), IDB_IE}
};

int idx, idxImage;
REBARBANDINFO rbBand;
COMBOBOXEXITEM cbI;
HBITMAP  hBmp;

// Create the combo box.
hWndCombo = CreateWindowEx ( 
   0,                                   // extended styles
   "ComboBoxEx32",                      // extended combo box – will 
   TEXT(""),                            // default text
   WS_VISIBLE | WS_CHILD | WS_TABSTOP |
      WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NORESIZE |
      CBS_AUTOHSCROLL | CBS_DROPDOWNLIST,
   0,0,                                 // x, y
   MIN_COMBOCX,                         // width
   MIN_COMBOCY * NUM_LINKS,             // height
   hWndParent,                          // parent window
   (HMENU)ID_COMBO,                     // ID
   hInst,                               // current instance
   NULL );                              // no class data

if (hWndCombo == NULL)
   return 0;

// Set the image list for the combo box.
SendMessage( hWndCombo, CBEM_SETIMAGELIST, 0L, (LPARAM)hIml);

// Add strings to the combo box.    
for (idx=0; idx < NUM_LINKS; idx++)
{
   // Load the bitmap and add it to the image list.
   hBmp = LoadBitmap (hInst, MAKEINTRESOURCE (rgLinks[idx].iBmp));
   idxImage = ImageList_Add (hIml,  // handle to image list
      hBmp,        // handle of bitmap to add
      NULL);       // handle of bitmap mask

   rgLinks[idx].idx = idxImage;

   // Each item has text, an lParam with extra data, and an image.
   cbI.mask = CBEIF_TEXT | CBEIF_LPARAM | CBEIF_IMAGE;    
   cbI.pszText = rgLinks[idx].szName;         // Name of the link.
   cbI.cchTextMax = sizeof(rgLinks[idx].szName);    
   cbI.lParam = (LPARAM)rgLinks[idx].szURL;   // Pass the URL as extra data.
   cbI.iItem = -1;          // Add the item to the end of the list.
   cbI.iImage = idxImage;   // Image to display.

   // Add the item to the combo box drop-down list.
   SendMessage(hWndCombo, CBEM_INSERTITEM, 0L,(LPARAM)&cbI);
}

Adding Bands to the Coolbar

Once you create the child windows, your application must fill in a structure called the REBARBANDINFO that describes the characteristics of each band you want to insert. As before, the structure information below is based on information in the ActiveX SDK.

typedef struct tagREBARBANDINFO
{
    UINT        cbSize;
    UINT        fMask;
    UINT        fStyle;
    COLORREF    clrFore;
    COLORREF    clrBack;
    LPSTR       lpText;
    UINT        cch;
    int         iImage;
    HWND        hwndChild;
    UINT        cxMinChild;
    UINT        cyMinChild;
    UINT        cx;
    HBITMAP     hbmBack;
    UINT        wID;
}   REBARBANDINFO, FAR *LPREBARBANDINFO;

where:

After filling in the REBARBANDINFO structure, an application sends the RB_INSERTBAND message to add the band to the coolbar, specifying the pointer to the REBARBANDINFO structure in the lParam and the zero-based index where the band is to be inserted in the wParam. If you want to add the band to the end of the bar, specify –1 in the wParam. If you have already added a band and want to change the characteristics of the band later (for example, you would like to change the text), use the RB_SETBANDINFO message. Similarly, if you want to retrieve information about a band, use the RB_GETBANDINFO message.

The code below sets the information in the REBARBANDINFO structure and inserts the window into the band via the RB_INSERTBAND message. This band contains an image, idxFirstImage, specified by the iImage member.

// Initialize REBARBANDINFO.
rbBand.cbSize = sizeof(REBARBANDINFO);
rbBand.fMask = RBBIM_COLORS |     // clrFore and clrBack are valid
   RBBIM_CHILD |                  // hwndChild is valid
   RBBIM_CHILDSIZE |              // cxMinChild and cyMinChild are valid
   RBBIM_STYLE |                  // fStyle is valid
   RBBIM_ID |                     // wID is valid
   RBBIM_TEXT |                   // lpText is valid
   RBBIM_IMAGE |                  // iImage is valid
   RBBIM_BACKGROUND;              // hbmBack is valid
rbBand.clrFore = GetSysColor(COLOR_BTNTEXT);
rbBand.clrBack = GetSysColor(COLOR_BTNFACE);
rbBand.fStyle = RBBS_NOVERT |     // Do not display in vertical orientation.
   RBBS_CHILDEDGE |
   RBBS_FIXEDBMP;
rbBand.hbmBack = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BACK));
rbBand.lpText = TEXT("Cool sites:");
rbBand.hwndChild = hWndCombo;
rbBand.cxMinChild = MIN_COMBOCX;
rbBand.cyMinChild = MIN_CY;
rbBand.iImage = idxFirstImage;

// Add the combo box band to the end.
SendMessage(hWndRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);

I added the toolbar next to the coolbar. Being artistically challenged, I simply took the standard file buttons and resized them larger for the toolbar. The toolbar supports tooltips and appears “flat” (rather than having raised buttons). An important style to include is the CCS_NORESIZE style, which prevents the toolbar from being resized to the default width and height during creation. Instead, the toolbar uses the width and height specified in the call to CreateWindowEx. If you don’t use this style, the toolbar will be automatically resized to the width of the client window and possibly overdraw your other bands.

HWND CreateTheToolBar (HWND hWndParent)
{
   REBARBANDINFO rbBand;

   hWndToolBar = CreateToolbarEx(hWndParent,
        WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | WS_CLIPCHILDREN |
           WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | WS_VISIBLE,
        ID_TOOLBAR, 
      NUM_TBBITMAPS, 
      (HINSTANCE)hInst, 
      IDB_TOOLBAR, 
        (LPCTBBUTTON)&tbButtons,
        NUM_TBBUTTONS,
      BMP_CX,BMP_CY,                  // width & height of buttons
      BMP_CX,BMP_CY,                  // width & height of bitmaps
      sizeof(TBBUTTON));

   if (hWndToolBar == NULL )
   {
      MessageBox (NULL, TEXT("Toolbar not created!"), NULL, MB_OK );
      return (HWND)NULL;
   }

   // Initialize REBARBANDINFO for all coolbar bands.
   rbBand.cbSize = sizeof(REBARBANDINFO);
   rbBand.fMask = RBBIM_COLORS |  // clrFore and clrBack are valid
      RBBIM_CHILD |                     // hwndChild is valid
      RBBIM_CHILDSIZE |                 // cxMinChild and cyMinChild are valid
      RBBIM_STYLE |                     // fStyle is valid
      RBBIM_ID |                              // wID is valid
      RBBIM_BACKGROUND;                 // hbmBack is valid
   rbBand.clrFore = GetSysColor(COLOR_BTNTEXT);
   rbBand.clrBack = GetSysColor(COLOR_BTNFACE);
   rbBand.fStyle = RBBS_NOVERT |  // Do not display in vertical orientation.
      RBBS_CHILDEDGE |
      RBBS_FIXEDBMP;
   rbBand.hbmBack = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BACK));
   rbBand.hwndChild = hWndToolBar;
   rbBand.wID = ID_TOOLBAR;
   rbBand.cxMinChild = MIN_TBCX;
   rbBand.cyMinChild = MIN_CY;

   // Insert band into coolbar.
   SendMessage(hWndRebar, RB_INSERTBAND, (UINT) -1, 
       (LPARAM)(LPREBARBANDINFO)&rbBand);

   return (hWndToolBar);
}

To support tooltips in your toolbar, remember to provide the tooltip text when the text is needed. This comes in the form of a WM_NOTIFY message and TTN_NEEDTEXT notification:

case WM_NOTIFY:
   switch (((LPNMHDR)lParam)->code) 
   {
      case TTN_NEEDTEXT:
      {
         LPTOOLTIPTEXT lpToolTipText;
         char szBuf[MAX_PATH];

         // Display the tooltip text.
         lpToolTipText = (LPTOOLTIPTEXT)lParam;
         LoadString (hInst, 
            lpToolTipText->hdr.idFrom,   // string ID == cmd ID
            szBuf,
            sizeof (szBuf));
            lpToolTipText->lpszText = szBuf;
         break;
      }
   }
   break;

If you build and run the sample, you will see my coolbar replete with background bitmap, combo box images, and toolbar.

Figure 2. The Rebar sample main window

Getting Information About a Band

An item in the Options menu in the Rebar sample gives you the ability to get information about the first band in the coolbar. This information is retrieved via the RB_GETBANDCOUNT, RB_GETROWCOUNT, and RB_GETROWHEIGHT messages and is displayed in a dialog box.

BOOL APIENTRY BarInfo(
   HWND hDlg,
   UINT message,
   UINT wParam,
   LONG lParam)
{
   static UINT uHeight, uRowCount, uBandCount;
   static REBARINFO rbi;

   switch (message)
   {
      case WM_INITDIALOG:
         // Get the number of bands.
         uBandCount = SendMessage(hWndRebar, RB_GETBANDCOUNT, 0, 0);
         SetDlgItemInt(hDlg, IDC_NUMBANDS, uBandCount, FALSE);
         // Get the number of rows.
         uRowCount = SendMessage(hWndRebar, RB_GETROWCOUNT, 0, 0);
         SetDlgItemInt(hDlg, IDC_NUMROWS, uRowCount, FALSE);
         // Get the row height for the first row.
         uHeight = SendMessage(hWndRebar, RB_GETROWHEIGHT, 0, 0);
         SetDlgItemInt(hDlg, IDC_ROWHEIGHT, uHeight, FALSE);
         return (TRUE);

      case WM_COMMAND:              
         if (LOWORD(wParam) == IDOK)
         {
            EndDialog(hDlg, TRUE);
            return (TRUE);
         }
         break;
   }
   return (FALSE);   
}

Cleaning Up

Once your application is ready to exit, you must be sure to destroy your coolbar along with any of the child windows that you may have created and inserted into the coolbar. You also must destroy any image lists that you may have created. I know that this probably sounds rudimentary to many of you, but I’m a mom, so I am accustomed to reminding others to clean up after themselves.

case WM_DESTROY:                  
   if (hWndRebar) 
      DestroyWindow(hWndRebar);

   if (hWndToolBar)
      DestroyWindow(hWndToolBar);

   if (hWndCombo)
   {
      ImageList_Destroy(hIml);                     
      DestroyWindow(hWndCombo);
   }

   PostQuitMessage(0);
   break;

Linking to the Internet

If you build and run the Rebar sample I've provided, you will notice that the items in the combo box are links to the World Wide Web. If you click one of the items in the list, your Internet browser (we hope that it will be Internet Explorer) will be invoked with the URL of the link chosen. I handle this in the window procedure for the combo box in the event of a CBN_SELCHANGE notification—it’s simply a matter of calling ShellExecute. The system will look for the browser you have associated with .HTM files and run that browser.

LRESULT CALLBACK ComboWndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
   int iSelect;

   if ((uMessage == WM_COMMAND) && (HIWORD(wParam)==CBN_SELCHANGE))
   {
      // Get the currently selected item.
       iSelect = SendMessage(hWndCombo, CB_GETCURSEL, 0, 0);

      ShellExecute( NULL, TEXT("open"), rgLinks[iSelect].szURL,
         NULL, NULL, SW_SHOWNORMAL );
   }

   return (CallWindowProc(lpfnDefCombo, hWnd, uMessage, wParam, lParam));
}

Messages and Notifications

This section lists the messages and notifications supported by coolbar controls, based on information in the ActiveX SDK for Internet Explorer 3.x.

Coolbar Control Messages

Table 3 lists the messages that can be sent to coolbar controls.

Note   Whenever you pass the address of a REBARINFO or REBARBANDINFO structure in one of the messages in the table above, you must first set the cbSize member of this structure using the sizeof function; otherwise, the call will fail.

Table 3. Coolbar Control Messages

Message Description wParam lParam Returns
RB_DELETEBAND Removes a band from the coolbar. UINT – the zero-based index of the band to delete 0 (not used) 0 if successful; non-zero otherwise
RB_GETBANDCOUNT Returns the number of bands in the coolbar. 0 (not used) 0 (not used) UINT – Number of bands in the coolbar
RB_GETBANDINFO Retrieves information on the specified band. UINT – the band to check LPREBARBANDINFO – pointer to a structure containing band information 0 if successful; non-zero otherwise
RB_GETBARINFO Retrieves information about the coolbar control and the image list that it may use. 0 (not used) LPREBARINFO – pointer to a structure containing coolbar information 0 if successful; non-zero otherwise
RB_GETROWCOUNT Retrieves the number of rows in the coolbar. 0 (not used) 0 (not used) UINT – the number of rows
RB_GETROWHEIGHT Returns the height of the specified row in the coolbar. UINT – the zero-based row to check 0 (not used) UINT – the height, in pixels, of the row
RB_INSERTBAND Inserts a band into a coolbar. UINT – the zero-based index of the place to insert the band; –1 signifies that the band will be added to the end LPREBARINFO - pointer to a structure containing information about the band 0 if successful; non-zero otherwise
RB_SETBANDINFO Sets the information about an existing band in the coolbar. UINT – the zero-based index to the band LPREBARBANDIFO – pointer to a structure containing new information about the band 0 if successful; non-zero otherwise
RB_SETBARINFO Sets information about the coolbar. 0 LPREBARINFO – pointer to a structure containing new coolbar information 0 if successful; non-zero otherwise
RB_SETPARENT Sets the window that will receive coolbar notification messages. Note that this message does not actually set the parent of the coolbar control. When you call GetParent, you will still get the handle to the original parent window that was specified when the coolbar control was created. HWND – handle to the new parent window 0 HWND – handle to the previous parent window; NULL if there is no previous parent

Coolbar Notification Messages

Coolbars have one notification message that is unique to them: RBN_HEIGHTCHANGE. This notification is sent to the coolbar when the height of the coolbar has changed (in the form of a WM_NOTIFY message). The lParam associated with this notification contains the address of an NMHDR structure.

Summary

Now you, too, can have that funky-looking bar at the top of your application! Just follow my instructions and you shouldn’t have any problems. Go ahead: Cut and paste the code, if you want. That’s why I write this stuff.