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

An alternative way to create the menu bar

0.00/5 (No votes)
22 Jul 2011 1  
An alternative way to create the menu bar

I don't like resources. I really don't. I can understand their usefulness for features such as string tables or embedded icons, but when it comes to the Windows Mobile menu bar definition, I just hate the whole thing. Take a good look at how the CrypSafe sample app's menu bar is defined:

ATL_IDW_MENU_BAR SHMENUBAR DISCARDABLE
BEGIN
IDR_MAINFRAME,
2,
I_IMAGENONE, ID_ACTION, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE,
ID_ACTION, 0, NOMENU,
I_IMAGENONE, ID_MENU, TBSTATE_ENABLED, TBSTYLE_DROPDOWN  TBSTYLE_AUTOSIZE,
ID_MENU, 0, 0,
END

Intuitive, right? Incidentally, this resource is defined in the .rc2 file and the ATL_IDW_MENU_BAR identifier is used as a default parameter of the CreateSimpleCEMenuBar method of the CFrameWindowImplBase class template. So what do you have to do in order to change the menu bar? Gasp!

There is a better way, fortunately. A way that you can encapsulate and that makes the whole process a bit more transparent.

You create a Windows Mobile menu bar by calling the SHCreateMenuBar API typically from your main window's WM_CREATE handler. As you can see, the function takes a single parameter, a pointer to a SHMENUBARINFO structure where you define the menu bar. There are two ways to create a menu bar: you either specify a menu bar resource ID or you provide your own HMENU by specifying the SHCMBF_HMENU flag. This is in fact a much more palatable alternative because you can declaratively create your menu bar in a single location of your application's code. Using my beloved WTL, here's how the code would look like on the main frame's OnCreate handler:

C++
if(m_mainMenu.CreateMenu())
{
  m_mainMenu.AppendMenu(MF_BYCOMMAND  MF_ENABLED  MF_STRING,
                        ID_BACK, _T("Back"));
  m_mainMenu.AppendMenu(MF_BYCOMMAND  MF_ENABLED  MF_STRING,
                        ID_MENU, _T("Menu"));

  SHMENUBARINFO mbi = { 0 };
  mbi.cbSize        = sizeof(mbi);
  mbi.hwndParent    = m_hWnd;
  mbi.dwFlags       = SHCMBF_HMENU;
  mbi.nToolBarId    = (UINT)(HMENU)m_mainMenu;
  mbi.hInstRes      = ModuleHelper::GetResourceInstance();
  mbi.nBmpId        = 0;
  mbi.cBmpImages    = 0;
  mbi.hwndMB        = NULL;

  BOOL bRet = ::SHCreateMenuBar(&mbi);
  if(bRet != FALSE)
  {
      m_hWndCECommandBar = mbi.hwndMB;
      SizeToMenuBar();
  }
}

The m_mainMenu variable is a CMenu, of course. The advantage of this approach is that you create the main menu bar in a very explicit way and if you later want to change it, you know where to find the code, and stop guessing what that crappy SHMENUBAR resource declaration means...

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