To make a long history short, imagine my main menu is a CMFCMenuBar which menu is defined by:
IDR_MAINFRAME MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "New", ID_FILE_NEW
MENUITEM "Open", ID_FILE_OPEN
MENUITEM "Save", ID_FILE_SAVE
POPUP "Save As"
BEGIN
MENUITEM "Format XXX", ID_FILE_SAVEAS_XXX
MENUITEM SEPARATOR
MENUITEM "Format YYY", ID_FILE_SAVEAS_YYY
MENUITEM SEPARATOR
MENUITEM "Format ZZZ", ID_FILE_SAVEAS_ZZZ
MENUITEM "Format WWW", ID_FILE_SAVEAS_WWW
END
MENUITEM "Close", ID_FILE_CLOSE
END
POPUP "&Object"
BEGIN
POPUP "Create object"
BEGIN
MENUITEM "Create object...", ID_CREATE_OBJECT
MENUITEM "Create object as...", ID_CREATE_OBJECTAS
END
POPUP "Save object"
BEGIN
MENUITEM "Save object...", ID_SAVE_AS_XXX
MENUITEM "Save object copy", ID_SAVE_OBJECT_COPY
END
END
MENUITEM "Delete", ID_DELETE_OBJECT
END
END
As POPUP menus have no ID (all them have a value of -1), to know on what menu I am doing the initialization, I followed the approach on https://stackoverflow.com/a/3910405/383779 and implemented functions like
bool CMainFrame::IsFileMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_FILE_NEW);
}
bool CMainFrame::IsObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(2) == ID_DELETE_OBJECT);
}
The Menu initialization is like:
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
for(int i = 0; i < pPopupMenu->GetMenuItemCount();i++)
{
MENUITEMINFO MenuItemInfo;
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO); // must fill up this field
MenuItemInfo.fMask = MIIM_SUBMENU;
if (!pPopupMenu->GetMenuItemInfo(i, &MenuItemInfo, TRUE))
continue;
CMenu* SubMenu = pPopupMenu->GetSubMenu(i);
if (SubMenu != NULL)
{
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO);
MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE;
for(int j=0; j<SubMenu->GetMenuItemCount() ;j++ )
{
SubMenu->GetMenuItemInfo(j, &MenuItemInfo, TRUE);
if (MenuItemInfo.wID == ID_CREATE_OBJECTAS)
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopup->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName() );
found= true;
break;
}
}
if(found)
break;
}
}
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
Notice the ID_FILE_SAVEAS_XXX
MENUITEM identifer is repeated! As I don't'want to delete the "Save Object" POPUP when the the license supporting "SaveAsFile" is absent, so it is an absolute need to identify what menu is now being processed.
Now the user has created a toolbar by using the MFC Customize dialog, then he dragged the "Create Object" POPUP to the new toolbar. When he clicks this new button of the toolbar, he sees the "Create object" and "Create object as" option, but not the custom objects have not been appended because to the IsObjectMenu()
condition was not satisfied. The behaviour was completely different when he came from the main menu; the appending has been done!
How can I make the code in a way that the Appending of custom objects is done when the user clicks the button of the toolbar?
I am not proud of my own code, but I solved it by separating the code of "Object" from "Create Object" menu.
bool CMainFrame::IsCreateObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_CREATE_OBJECT);
}
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
// Do things
}
if(IsCreateObjectMenu())
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopupMenu->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName());
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}