Microsoft KB Archive/145857

= How to Use Multiple Menus in MFC App That Uses GetDefaultMenu =

Article ID: 145857

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 1.5 Professional Edition

 Microsoft Visual C++ 1.51

 Microsoft Visual C++ 1.52 Professional Edition

 Microsoft Visual C++ 2.0 Professional Edition</li></ul>

 Microsoft Visual C++ 2.1</li></ul>

 Microsoft Visual C++ 2.2</li></ul>

 Microsoft Visual C++ 4.0 Standard Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q145857

<div class="summary_section">

SUMMARY
In an MFC application, you may occasionally find it useful to switch between menus within the same frame window, such as when using static splitter windows or objects in a view requiring a whole new menu. Because the framework provides automatic support for only one menu per document template (hence per frame), additional code must be added to switch automatically between multiple menu resources. MFC provides the undocumented virtual function CDocument::GetDefaultMenu to allow the document to determine which menu to display.

<div class="moreinformation_section">

MORE INFORMATION
When AppWizard generates an SDI or MDI application, it creates a menu resource by using IDR_MAINFRAME as its resource ID. This menu is displayed at all times for an SDI application and only when there are no active documents in an MDI application. For an MDI application, AppWizard also generates a menu resource for the one multidoc template it creates using IDR_xxxxTYPE as its resource ID. Additional menu resources can be used by creating them using the resource editor and associating them with another multidoc template (see CMultiDocTemplate). The framework will display the menu resource associated with each multidoc template automatically. This method limits you one menu per document template. To bypass this limitation, you can override CDocument::GetDefaultMenu and perform some calls to display the menu.

MFC uses CMDIChildWnd::m_hMenuShared and CFrameWnd::m_hMenuDefault data members to determine which menu to display. In an MDI application, the menu resource associated with each document template is loaded during the construction of the document templates and copied into CMDIChildWnd::m_hMenuShared. This menu is then used in CMDIChildWnd::OnUpdateFrameMenu to set the menu of the MDI Frame window when there is an active MDI child window. CMDIChildWnd::OnUpdateFrameMenu uses CFrameWnd::m_hMenuDefault, which is loaded during CFrameWnd construction using IDR_MAINFRAME when there are no active child windows. An SDI program calls CFrameWnd::OnUpdateFrameMenu, which uses CFrameWnd::m_hMenuDefault for its menu.

In both an SDI and MDI application, the menu you need to display is obtained from two other sources before using the m_hMenuShared or m_hMenuDefault menus. The framework first checks CFrameWnd::m_hMenuAlt. This is used in OLE supported programs with in-place activated objects that provide its own menus. The second source it checks is CDocument::GetDefaultMenu, which is also virtual. The default implementation of it is to return NULL. This function can be overridden to allow the program to select the menu to display.

Changing the menus manually is done by calling OnUpdateFrameMenu and DrawMenuBar. You must call CFrameWnd::OnUpdateFrameMenu(NULL) or CMDIFrameWnd::OnUpdateFrameMenu(NULL) in order to set the new menu into the window. Call DrawMenuBar to redraw the menu. Use the following code to implement for both MDI and SDI:

<ol> Create a new menu resource (IDR_MYMENU1) in the resource editor.</li>  Add an HMENU data member to CMyDocument and override GetDefaultMenu to return this data member: // .h file //   HMENU m_hMyMenu; //   virtual HMENU GetDefaultMenu; // get menu depending on state HMENU CMyDocument::GetDefaultMenu {     return m_hMyMenu;    // just use original default } Remember to initialize this member variable to NULL either in the constructor or CDocument::OnNewDocument. </li>  Change and redraw the menu at the desired times. For example, when switching between splitter panes, this is normally done in CView::OnActivateView. The following code shows how to implement it in that function. // example within CView member function ((CMyDocument*)GetDocument)->m_hMyMenu = ::LoadMenu(      AfxGetResourceHandle, MAKEINTRESOURCE(IDR_MYMENU1)); ((CFrameWnd*)AfxGetMainWnd)->OnUpdateFrameMenu(NULL); AfxGetMainWnd->DrawMenuBar; </li></ol>

Be sure to destroy the menu upon exiting the application, and avoid having too many menus loaded at once.

Menus can also be switched simply by changing the value of CMDIChildWnd::m_hMenuShared (MDI) or CFrameWnd::m_hMenuDefault (SDI). However, using GetDefaultMenu allows a safer method of changing the menus.

For more information about how to share menus between MDI child windows, please see the following article in the Microsoft Knowledge Base:

118435 Sharing Menus Between MDI Child Windows.

<div class="references_section">