MRU list in a submenu: the MFC bug and how to correct it

We should be able to use the MRU list in a submenu just by moving the menu item with the id ID_FILE_MRU_FILE1 from the "File" menu to the submenu we wanted. However, a bug in the CWinApp class causes that if the MRU first item is the first item in the submenu, the MRU list appears in the parent menu, instead of the submenu. This article describes the bug and how to correct it.

First, lets understand how the MFC framework displays the MRU menu (or submenu). The CWinApp class has a member m_pRecentFileList of type CRecentFileList*. The class CRecentFileList encapsulates the funcionality of a MRU list, and knows how to display itself. To display the MRU list, the CWinApp class calls CRecentFileList::UpdateMenu(pCmdUI). The parameter is a pointer to a CCmdUI object, that indicates to the UpdateMenu function the first item of the MRU list, which should be the item with the id ID_FILE_MRU_FILE1. If the CRecentFileList::UpdateMenu function were called always with the right pCmdUI, then there would be no problems (this function works Ok). Now, when and where is this function called? Well, only in one place, the CWinApp::OnUpdateRecentFileMenu function, the code of which is provided below:


void CWinApp::OnUpdateRecentFileMenu(CCmdUI* pCmdUI)
{
	ASSERT_VALID(this);
	if (m_pRecentFileList == NULL) // no MRU files
		pCmdUI->Enable(FALSE);
	else
		m_pRecentFileList->UpdateMenu(pCmdUI);
}

This function is the ON_UPDATE_COMMAND_UI handler for the menu item with the id ID_FILE_MRU_FILE1. Apparently, everything is right, the framework should be responsible of calling this function only when the m_nId member of the object pointed by the pCmdUI parameter is ID_FILE_MRU_FILE1 (as declared and implemented in the CWinApp's message map). The writer of this function however, forgot that the framework calls the OnUpdate function for the first menu item in a submenu also to update the submenu itself (which does not have an id). If that is the case, pCmdUI->m_pSubMenu points to the submenu, otherwise it is NULL (see technical note 21 for more information on command and message routing). Thus, the CWinApp::OnUpdateRecentFileMenu function should have been:


void CWinApp::OnUpdateRecentFileMenu(CCmdUI* pCmdUI)
{
	ASSERT_VALID(this);
	if (pCmdUI->m_pSubMenu!=NULL) // updating a submenu?
		return;

	if (m_pRecentFileList == NULL) // no MRU files
		pCmdUI->Enable(FALSE);
	else
		m_pRecentFileList->UpdateMenu(pCmdUI);
}

Now for the correction of the bug. We should obviously process the update command message ourselves, so using the ClassWizard, add an UPDATE_COMMAND_UI handler for the ID_FILE_MRU_FILE1 command to your CWinApp descendant class (I would call it OnUpdateRecentFileMenu also). In principle, we could write the handler as I said the original MFC function should have been written, but as we have it already as it is, we can save some code:


void CMyApp::OnUpdateRecentFileMenu(CCmdUI* pCmdUI)
{
	if (pCmdUI->m_pSubMenu!=NULL) // updating a submenu?
	{
		// update your submenu here, if you need to
		
		return;
	}
	
	CWinApp::OnUpdateRecentFileMenu(pCmdUI);
	return;
}

Well, that's it. I hope Microsoft will fix this bug somewhere in the near future. In the mean time, we can deal with it as described above.


Last updated: 21 November 1998



Comments

  • Still is a bug

    Posted by Andy on 01/04/2014 11:18am

    It's 2014 and this was never fixed in any service packs :)

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • VMware vCloud® Government Service provided by Carpathia® is an enterprise-class hybrid cloud service that delivers the tried and tested VMware capabilities widely used by government organizations today, with the added security and compliance assurance of FedRAMP authorization. The hybrid cloud is becoming more and more prevalent – in fact, nearly three-fourths of large enterprises expect to have hybrid deployments by 2015, according to a recent Gartner analyst report. Learn about the benefits of …

Most Popular Programming Stories

More for Developers

RSS Feeds