VS2010中GetMenu()和GetSubMenu(0)为NULL引发异常的解决方法 及添加方法

时间:2022-08-29 21:57:21

对于前面问题的分析:来源于http://blog.163.com/yuyang_tech/blog/static/216050083201211144120401/

解决方法1: //来源:http://www.cnblogs.com/yuzhoufeng/archive/2011/12/11/2284200.html

今天学习VC++ 2010 MFC单文档应用程序中动态添加菜单,下面是代码部分:

12345678910111213 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){......CMenu m_Menu;m_Menu.CreatePopupMenu();ASSERT(m_Menu.GetSafeHmenu());GetMenu()->AppendMenuW(MF_POPUP,(UINT)m_Menu.m_hMenu,_T("文件"));m_Menu.AppendMenuW(MF_STRING,111,_T("新建"));m_Menu.AppendMenuW(MF_STRING,112,_T("打开"));m_Menu.Detach();return 0;}

  但是GetMenu()返回始终未NULL,无法获取菜单指针,网上查了下,说VS2010建的SDI/MDI与之前的不一样,是类似BCG的一些东西,所以用之前的方法GetMenu()得到CMenu是NULL或者无效。

【解决方案】:

  在CMainFrame类中找到CMFCMenuBar m_wndMenuBar;这个成员变量,将跟它相关的代码注释掉的话,然后运行,OK。

 

解决方法2: //来源:http://blog.csdn.net/grasshopperwarbler/article/details/6337754

这里说的是SDI的情况,如果在vs2010里面按着默认选项创建一个单文档工程(Single Document).

问题分析:

出错的代码如下 :
GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND|MF_CHECKED);
加在CMainFrame::Oncreate()里面,整个程序就会崩溃,出现的异常类似如此:Unhandled exception at 0x58aba12c (mfc100ud.dll) in menu1.exe: 0xC0000005: Access violation reading location 0x00000004.

出错的原因是,在执行这段代码的时候,Menu并没有生成。因为采用断点来检测的话,此时的GetMenu返回值不是一个正常的地址。为什么会这样呢?

后来才发现visual studio2010里默认采用的是Menu格式在OnCreate()末端并未生成。vs2010默认采用的是增加了扩展功能的Menu,所以调用GetMenu()会得到空指针。

解决方法:

最原始的解决方法是采用回原来的Menu格式。就在新建工程的一个对话框中选择回原始的菜单模式即可如下图:

VS2010中GetMenu()和GetSubMenu(0)为NULL引发异常的解决方法  及添加方法

不过经过更改后编译会出现两个错误,是关于:

ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)

两句代码是关于打印功能的。如果不涉及这方面的功能,可以直接把这两句话注释掉。然后在CMainFrame::OnCreate()末尾加上GetMenu()->GetSubMenu(0)->CheckMenuItem(ID_FILE_NEW,MF_BYCOMMAND|MF_CHECKED);
程序就可以顺利通过了。

对于该问题在vs2010上面的解决方法出自http://blog.csdn.net/mjk1133/article/details/6681051

在VC6.0和VS2010里面动态添加菜单项是不一样的,查看MSDN文档可知,VS2010采用的是MFC9.0版,其中有很多新增的项具体信息请查看http://msdn.microsoft.com/en-us/library/ws8s10w4.aspx,本文就根据自己的测试详细的比较一下二者的区别:

1.在VC6.0里面动态添加一个子菜单项

在CMainFrame::OnCtreate()中添加代码,另外要在Resource.h里面添加#define ID_MENU_ADDMENUITEM    32773

CMainFrame::OnCtreate(){

//下面是添加的代码

CMenu *pMenu=AfxGetMainWnd()->GetMenu(); 
CMenu *pmSub=pMenu->GetSubMenu(1); 
pmSub->AppendMenu(MF_STRING,ID_MENU_ADDMENUITEM,L"Add Menu &Item"); 

}//效果是在“Edit”菜单最下面添加了一个"Add Menu Item"子项 

2.在VS2010里面添加一个子菜单项:

要对CMainFrame类的OnShowPopupMenu()进行重载,另外要在Resource.h里面添加#define IDS_EDIT_MYITEM_1    32773

BOOL CMainFrame::OnShowPopupMenu(CMFCPopupMenu* pMenuPopup) 

    // TODO: Add your specialized code here and/or call the base class

    int iIndex = -1; 
    if (!CMFCToolBar::IsCustomizeMode()&&(iIndex=pMenuPopup->GetMenuBar()->CommandToIndex(ID_EDIT_PASTE))>=0) 
    { 
        pMenuPopup->InsertSeparator(iIndex+1); 
        pMenuPopup->InsertItem(CMFCToolBarMenuButton(IDS_EDIT_MYITEM_1,NULL,-1,_T("&MyItem 1")),iIndex+2); 
    }   //使用CommandToIndex()来获得菜单项的索引,然后根据索引来确定子菜单项的添加位置 
    return CFrameWndEx::OnShowPopupMenu(pMenuPopup); 
}//效果是在“Edit”菜单最下面添加了一个分割线和一个"MyItem 1"子项

效果如图,因为还没有为其添加处理函数,所以呈灰色:

 VS2010中GetMenu()和GetSubMenu(0)为NULL引发异常的解决方法  及添加方法

给添加的子菜单项添加消息处理函数:

在MainFrame.h里面添加消息处理函数声明:

   class CMainFrame : public CFrameWnd{

//…

protected:

  afx_msg void OnEditMyItem1 ();

}

然后在MainFrame.cpp消息映射里面添加消息映射项:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) 
     //…

    ON_COMMAND(IDS_EDIT_MYITEM_1, OnEditMyItem1) 
END_MESSAGE_MAP()

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

CMFCMenuBar的继承关系:

CObject

    CCmdTarget

           CWnd

                   CBasePane

                          CPane

                                 CMFCBaseToolBar

                                         CMFCToolBar

                                                   CMFCMenuBar

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++