Click here to Skip to main content
Click here to Skip to main content

An alternative way to create the menu bar

By , 22 Jul 2011
 

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:

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)

About the Author

Joao Paulo Figueira
Software Developer Primeworks
Portugal Portugal
Member
João is a partner at Primeworks, a company that develops remote database access software for Windows Mobile. He also works for Frotcom, a company that develops web-based fleet management solutions.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130513.1 | Last Updated 22 Jul 2011
Article Copyright 2011 by Joao Paulo Figueira
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid