Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / MFC

An alternative way to create the menu bar

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
22 Jul 2011CPOL1 min read 15.3K   5   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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Frotcom International
Portugal Portugal
I work on R&D for Frotcom International, a company that develops web-based fleet management solutions.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 863682323-Dec-13 5:07
Member 863682323-Dec-13 5:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.