VS2010中GetMenu()和GetSubMenu(0)為NULL引發異常的解決方法 及添加方法


對於前面問題的分析:來源於http://blog.163.com/yuyang_tech/blog/static/216050083201211144120401/

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

今天學習VC++ 2010 MFC單文檔應用程序中動態添加菜單,下面是代碼部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
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"子項

效果如圖,因為還沒有為其添加處理函數,所以呈灰色:

 

給添加的子菜單項添加消息處理函數:

在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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM