June 24, 2018
Hot Topics:

Create Flexible Custom Menus in Windows CE

  • November 13, 2002
  • By Nancy Nicolaisen
  • Send Email »
  • More Articles »

The Dropdown Button

The Dropdown button is definitely more work than anything we've seen so far. Is has one great redeeming advantage, though. Visually, the dropdown button has the impact and space requirements of a button with a drop arrow icon next to it. When the user taps it, it displays a dropdown menu. For this reason it's an important design option if you have floating menus or sub menus in the original Win 32 resource file.

If you can keep popup submenus and floating menus "logically intact", then you won't have nearly as much work to do in porting the message handling behind the menu items.

There are three things we have to do to support the drop button. First, we add the button to the command bar, which is the same as for other types, except that we specify the TBSTYLE_DROPDOWN in the TBBUTTON structure.

// Command band button initialization structure

TBBUTTON tbDropButton[] = {
  {0,             // Bitmap Index
   IDM_ONE,          //Command
   0,                // UserData
   0},               // String

HWND    AddDropDownButton( HWND hWnd )
    //we have to destroy the old one before expanding
    CommandBar_Destroy( hwndCB ); 
    hwndCB = CommandBar_Create(hInst, hWnd, 1);     
    // Insert the menu band
    CommandBar_InsertMenubar(hwndCB, hInst, IDM_MENU, 0);
    //add bitmaps for buttons
    CommandBar_AddBitmap(hwndCB, hInst, IDB_ONE_TWO, 2, 0, 0);
    //Add the buttons
    CommandBar_AddButtons(hwndCB, 1, tbDropButton);
    // Add exit button to command band control.
    CommandBar_AddAdornments (hwndCB, 0, 0);
    CommandBar_Show(hwndCB, TRUE);
    return hwndCB;


Unlike other button types, however, the dropdown doesn't do much to manage it's own appearance. When the user taps a dropdown button, the button will change its appearance to look "pressed", and send the application a WM_NOTIFY message. Since many control elements can generate these messages, we must check to make sure it's from our drop down button.

Here's how to do this. The lParam of the WM_NOTIFY message is a pointer to a generic notification message header. To determine if the notification is coming from the button, we cast the lParam to a pointer of LPNMHDR type, and then use the pointer to get the value of the lpnmHeader->code. The code tells us what kind notification structure is being provided. In this case, we check for a toolbar notification from a dropdown button. If that's what we got, then we call our handler.

   case WM_NOTIFY:
   // Notify messages have a generic header.
   //check it to see what sent the notify message
     lpnmHeader = (LPNMHDR)lParam;
     if (lpnmHeader->code == TBN_DROPDOWN) 
         //if the notify message came from our button, 
         //recast lParam to a toolbar notify pointer
         //and call the handler for the drop button
         return HandleDropButton( hWnd, (LPNMHDR)lParam,

Here's where the rubber meets the road, so to speak. We have to display the dropdown menu directly underneath the dropdown button, making sure we don't cover up the button itself.

long HandleDropButton( HWND hWnd, 
                       LPNMHDR lpnmHeader, 
                       LPNMTOOLBAR lpnmDropButton )
    RECT rect;
    TPMPARAMS tpm;
    HMENU hMenu;

    if (lpnmDropButton->iItem == IDM_ONE)

      // Get the rectangle of the drop-down button.
      SendMessage (lpnmHeader->hwndFrom, TB_GETRECT,
         lpnmDropButton->iItem, (LPARAM)&rect);

      // Convert rect into screen coordinates.  The rect is
      // considered here to be an array of 2 POINT structures.
      MapWindowPoints (lpnmHeader->hwndFrom, HWND_DESKTOP,
           (LPPOINT)&rect, 2);

      // Prevent the menu from covering the button.
      tpm.cbSize = sizeof (tpm);
      CopyRect (&tpm.rcExclude, &rect);

      hMenu = LoadMenu (hInst, TEXT("DROPMENU"));
      hMenu = GetSubMenu ( hMenu, 0);
      TrackPopupMenuEx (hMenu, TPM_LEFTALIGN | TPM_VERTICAL,
            rect.left, rect.bottom, hWnd, &tpm);
  return 0;

We get the button's screen rectangle with a call to SendMessage(). The parameters, in the order shown, are the handle to the button window, which we get from the notify message header, the Windows message constant TB_GETRECT, the control ID of the toolbar button, and the address of a RECT structure which will contain the rectangle coordinates when the function returns.

   // Get the rectangle of the drop-down button.
   SendMessage (lpnmHeader->hwndFrom, TB_GETRECT,
      lpnmDropButton->iItem, (LPARAM)&rect);

The rectangle of the button is reported in parent window coordinates, but we need screen coordinates to draw the menu properly. MapWindowPoints() translates the button rectangle to the screen coordinate systems. Notice that we treat the RECT structure as an array of two POINT structures in this call.

   // Convert rect into screen coordinates.  The rect is
   // considered here to be an array of 2 POINT structures.
   MapWindowPoints (lpnmHeader->hwndFrom, HWND_DESKTOP,
        (LPPOINT)&rect, 2);

We get a bit of help in putting up the menu. We initialize a popup menu tracking structure with the screen coordinates of the button's rectangle so that it can be excluded when the menu is painted, load the menu resource and get a handle to it. TrackPopupMenuEx() does the rest.

   // Prevent the menu from covering the button.
   tpm.cbSize = sizeof (tpm);
   CopyRect (&tpm.rcExclude, &rect);

   hMenu = LoadMenu (hInst, TEXT("DROPMENU"));
   hMenu = GetSubMenu ( hMenu, 0);
   TrackPopupMenuEx (hMenu, TPM_LEFTALIGN | TPM_VERTICAL,
         rect.left, rect.bottom, hWnd, &tpm);

I'd like you to notice two things particularly. First, LoadMenu() uses the text macro to create the literal string with the menu name. File names, resources names, path names and control text are always Unicode under Win CE. Second, notice that the alignment, positioning and upper left hand corner of the popup are set in the second, third and fourth parameters of TrackPopupMenuEx().

This brings us to the point where we can articulate the rules for menu porting decisions:

Win 32 Menu Porting Checklist:

  • Examine menu resources and eliminate menu items that are superfluous under Windows CE. If there are four or fewer dropdowns, you may be able to port with no changes.
  • If there are popup submenus or floating menus, consider converting to command bar style menus.
  • If you choose command bar menus, sub divide menu functionality across several command bar menus, creating them as needed.
  • Eliminate menu items that duplicate the command bar adornments.

Looking Ahead

Now that we've examined the issues around porting menus, we are ready to dive into the more application specific and functional area of dialog boxes. Dialog boxes present several kinds of porting challenges. First, of course, is the issue of size. More subtly, though, we begin to see the influence of CE's minimalist nature. In contrast to menus, which we move to CE simply by doing more or less the same thing but in a smaller space, porting complex dialogs requires fundamental functional shifts. In the next several installments, we'll see how to quickly move dialog based applications to CE. Then we'll turn our attention to modifying dialog based applications, incrementally moving ported code toward the spirit of the CE environment.

What Is Unicode and Why Do We Need It?

Conceptually, all computer character sets map arbitrary integer values to specific characters. Some familiar standard mappings of the past include the EBCIDIC and ASCII character sets. These two sets are incompatible with one another and neither fully supports special characters or the diacritical marks necessary to render languages other than English. In order to make textual data portable and accessible, we need a universal character encoding system: one that accommodates all languages and is consistent across platforms Enter Unicode.

Unicode is a sort of "lingua franca" for text display. By definition, it is a character representation standard that uniquely encodes all characters of all languages on all platforms. From a programmer's point of view, the key thing to remember about Unicode is that characters are encoded in multiple bytes. We have to treat Unicode data in the way we treat numeric data types:

  • Don't count on a particular size in bytes for a datum
  • Don't assume anything about the ordering of bytes
  • To get the address of Unicode data, use the address operator

The assignment of Unicode character values is administered and maintained by the Unicode Standards Organization. You can read about the organization and its membership at www.unicode.org. Most industry leaders are members of the organization, giving the Unicode standard a broad base of support among both hardware and software vendors.

About the Author

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, entry time data validation.

In addition to writing for Developer.com, she has written several books including Making Win 32 Applications Mobile. She has also written numerous articles on programming technology for national publications including Dr. Dobbs, BYTE Magazine, Microsoft Systems Journal, PC Magazine; Computer Shopper, Windows Sources and Databased Advisor.

# # #

Page 2 of 2

Comment and Contribute


(Maximum characters: 1200). You have characters left.



Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

By submitting your information, you agree that developer.com may send you developer offers via email, phone and text message, as well as email offers about other products and services that developer believes may be of interest to you. developer will process your information in accordance with the Quinstreet Privacy Policy.


We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.
Thanks for your registration, follow us on our social networks to keep up-to-date