Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Fun with Common Controls Bitmaps and Toolbars

0.00/5 (No votes)
29 May 2004 6  
A WTL mix-in class for creating toolbar controls using common controls bitmaps instead of local resources.

Sample screenshot

Introduction

I've been lurking around The Code Project for years now, but this is my first contribution. It's a mix-in class to help a CFrameWindowImpl derived class build a toolbar using the standard WIN32 common controls bitmaps. This class can be used to avoid weighing that lean-and-mean WTL app down with bitmap resources for such commonplace toolbar buttons as print, save, etc. While this may seem like an awful lot of trouble for nothing, I'm a WTL newbie and I wanted to see if I could make my WTL app a little bit leaner. Also, for a variety of other reasons, I like using system resources and controls instead of custom objects. For instance, if a resource is updated when a new version of Windows comes out, an application that inherits from the system automatically inherits the new look, whereas an application that defines its own resource must often be rebuilt just to avoid looking dated.

Background

The common controls bitmap constants and the indices to the individual images within those bitmaps are documented in the Platform SDK in various locations depending on the SDK version. Two locations I know of are:

  1. User Interface Services/Shell and Common Controls/Common Controls/Toolbar Controls/Toolbar Control Reference/Toolbar Standard Button Image Index Values
  2. User Interface Services/Windows Controls/Individual Control Information/Toolbar Controls/Toolbar Controls Reference/Constants/Toolbar Standard Button Image Index Values

In some cases, these constants are incorrectly documented. They're defined in the Platform SDK's <commctrl.h> file, which is also where the TBBUTTON structure type is defined:

typedef struct _TBBUTTON {
    int iBitmap;
    int idCommand;
    BYTE fsState;
    BYTE fsStyle;
#ifdef _WIN64
    BYTE bReserved[6];          // padding for alignment

#elif defined(_WIN32)
    BYTE bReserved[2];          // padding for alignment

#endif
    DWORD_PTR dwData;
    INT_PTR iString;
} TBBUTTON, NEAR* PTBBUTTON, *LPTBBUTTON;

It includes some undocumented padding which varies in size depending on the target platform. To simplify TBBUTTON array initialization statements, I define the TBBPADDING macro in SysToolbarCtrl.h, and macros for buttons corresponding to the toolbar icons.

In order to make the demo a little more interesting than a simple frame window with a do-nothing toolbar, I've stolen (well, OK, "borrowed" may be a gentler way of putting it) some other peoples' ideas:

  • Leon Finker's IShellBrowser article
  • Ed Gadziemski's Pixview sample application, which sadly doesn't seem to be available on Code Project anymore. I used his CPix class, which uses IPicture to load and render image files. I guess there are plenty of other examples of how to use IPicture.

Using the code

There are four simple steps to using this code:

  1. This probably doesn't need to be said, but I'll say it anyway: include the header file SysToolbarCtrl.h in your mainframe class precompiler directives:
    #include "SysToolbarCtrl.h"
  2. Include CFrameWindowImpl and CSysToolbarCtrl in your mainframe's inheritance list:
    class CMainFrame : public CFrameWindowImpl<CMainFrame>,
            public CSysToolbarCtrl<CMainFrame>,
            ...
  3. Instead of calling CreateSimpleToolBarCtrl in your mainframe class' OnCreate method (or whatever technique you normally use to create your toolbar), declare and initialize a TBBUTTON array, then call CreateSysToolbarCtrl as follows:
    // init toolbar button array, including separators, if any.
    
    TBBUTTON tbb[] =
    {
        // File|New
    
        STBB_STD_FILENEW,
        // File|Save
    
        STBB_STD_FILESAVE,
        // separator
    
        STBB_SEPARATOR,
        // View|Parent folder
    
        STBB_VIEW_PARENTFOLDER(ID_VIEW_PARENTFOLDER),
        // separator
    
        STBB_SEPARATOR,
        // Help|About
    
        STBB(STD_HELP, ID_APP_ABOUT, IDB_STD_SMALL_COLOR)
    };
    
        // create the toolbar control
    
        HWND hWndToolBar = CreateSysToolbarCtrl(m_hWnd, tbb,
            sizeof(tbb)/sizeof(TBBUTTON), &m_CmdBar);

    The code uses some macros I defined to specify the toolbar buttons. The macros come in three basic forms, which all use STBB (System Tool Bar Button) as a prefix:

    • STBB_IMG_ID, where IMG_ID is the button's image identifier as defined in <commctrl.h>. This form assigns a default command ID to the button using the command IDs defined in <atlres.h>;
    • STBB_IMG_ID(CMD_ID), where IMG_ID is as described above, and CMD_ID is the command ID that should be associated with the toolbar button. This is used when there is no standard command ID in the <atlres.h> file that corresponds to the button image, as in the case of VIEW_PARENTFOLDER;
    • STBB(IMG_ID, CMD_ID, BITMAP_ID), where IMG_ID and CMD_ID are as described previously, and BITMAP_ID is the bitmap ID defined in <commctrl.h> that contains the button image identified by IMG_ID. This is the one to use when you want to override the default command ID for a particular toolbar button, as I do in the demo for Help|About.

    Use your favorite resource editor to define your menus as you normally would. You can include the command IDs defined by your resource editor in the system toolbar. If <atlres.h> pre-defines any command IDs you could use in your menus, those can be used as well. Needless to say, the specified command ID should have an associated handler somewhere in the application's message map, and may have a corresponding menu item as well. In the demo, I've only provided a handler for two of the buttons (View|Parent folder, and Help|About) but it should be enough to give you a general idea of how it all works.

    You can also include a pointer to a CCommandBarCtrl as a parameter, and CreateSysToolbarCtrl will put the bitmaps on the appropriate menu items. If you aren't using a command bar, passing NULL (the default value) will cause CreateSysToolbarCtrl to ignore this parameter.

  4. Last, but not least, don't forget to remove any references to the toolbar bitmap you no longer want, from your resource script (*.rc file). You might want to do this manually using a bare-bones text editor instead of Visual C++. Simply commenting out the unwanted line should work:
    ///////////////////////////////////////////////////////////////////////
    
    //
    
    // Bitmap
    
    //
    
    
    // IDR_MAINFRAME           BITMAP  MOVEABLE PURE   "res\\Toolbar.bmp"

    Now if you try to open the toolbar in the Visual C++ IDE, it will squawk at you and ask you if you want to create a bitmap for the toolbar. JUST SAY NO!

Points of Interest

  • The STD_HELP image is the arrow-question-mark traditionally used for context help. Where's the classic yellow question mark?
  • There is no image for VIEW_VIEWMENU on any system I've looked at, yet it's in <commctrl.h>. What gives?
  • For the enterprising reader, there are other system bitmaps available to make hot/cold image toolbars. Of course, the code would have to be modified somewhat, and that's beyond the scope of this article.
  • Yes, I know, I might be cheating when my IShellBrowser implementation gets a selected item's PIDL from the IShellView window. That's because I don't know the "right" way to do it.
  • I found a way to synch a tree control with the shell folder view, but it's an undocumented hack and I didn't include it in this article. It's really just a brute-force method, but if anybody's interested, email me and I'll send you the code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here