0
votes

Has anybody encountered this issue?

I am using MFC on an MDI application. I switch between menus using SetMenu() but has the side effect of system menus (Maximize, Minimize, Close buttons) disappearing when I maximize the child windows.

CMenu* pMenu = GetMenu();
if (pMenu == NULL) return;
pMenu->Detach();

// Reset application menu
CMenu newMenu;
newMenu.LoadMenu(menuID);
SetMenu(&newMenu);

If I don't call SetMenu(), the issue does not happen.

2

2 Answers

2
votes
CMenu newMenu;
newMenu.LoadMenu(menuID);
SetMenu(&newMenu);

newMenu is a temporary object. It will be destroyed as soon as the function exits. The result is undefined behavior.

CMenu* pMenu = GetMenu();
if (pMenu == NULL) return;
pMenu->Detach();

I am not sure what this code will accomplish. Note that CWnd::SetMenu will replace the old menu. It will not destroy the old menu handle, but MFC will handle the clean up at the end (Detach will not destroy the handle if that was the goal)


Declare menu objects as class member:

class CMainFrame : public CMDIFrameWnd
{
    CMenu m_menu1, m_menu2;
    ...
};

Load the menu once:

CMainFrame::CMainFrame()
{
    m_menu1.LoadMenu(IDR_MENU1);
    m_menu2.LoadMenu(IDR_MENU2);
    ...
}

Change menu:

void CMainFrame::OnChangeMenu()
{
    if(want_menu1)
    {
        SetMenu(&m_menu1);
    }
    else if (want_menu2)
    {
        SetMenu(&m_menu2);
    }
}
1
votes

I would recommend something different: Just use the menu management functionality as originally intended by MFC. For a typical MDI MFC application, you don't really need to do anything with menus (and I mean these calls to SetMenu()). Only define them, and MFC will do the rest for you.

More specifically, a Wizard-generated MDI application contains the following menus:

  • IDR_MAINFRAME, which will be displayed when there exists no MDI child window (open document). Typically contains the File, View and Help submenus.
  • IDR_DocType, one for each document-type you have defined. This is displayed when a MDI child window displaying a document of this type is the active one. Typically contains the File, Edit, View, Window and Help submenus.

Please note that:

  • You only have to define/edit these menus, eg add more commands or even more submenus. You don't need to switch menus, the framework will do this for you.
  • The framework will NOT merge submenus or menu items, it will instead just select IDR_MAINFRAME or one of the IDR_DocType ones, depending on the MDI child window currently active.
  • Consequently, some of the submenus or items may be duplicates (albeit not necessarily exact copies), some others not. For example, the View submenu for IDR_MAINFRAME typically contains two menu items, Toolbar (or Toolbars) and Status Bar (toggling display of the toolbar and status bar), while the doctype-specific ones typically contain the above, plus some additional ones, determining how to display the document; eg if the document is an image, you would normally add some display choices like 1:1, Fit To Width, Fit To Height and Best Fit (in a radio-button setting), shown above the Toolbar and Status Bar ones, separated with a separator menu-item.

I have developed many such applications, and never had to use SetMenu(). I would suggest that you first restore the IDR_MAINFRAME and IDR_DocType menus to their original state, and then put in any additional/custom ones. If you have destroyed or changed significantly the menus originally generated by the Wizard, you can create a new MFC project/solution with the same settings as yours, and copy-paste the menus in the resource file.