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...
CodeProject