Last Updated 2004/07/02
Programming Tips Visual C++ MFC MDI  索 引 
MDIメニュー消去
2004/07/02

MDI の CMainFrame メニューは SDI と同様に消すことができる.
しかし,アクティブビューに対応するフレームメニューは MDICLIENT に WM_MDISETMENU を送って設定しているため消すことができない.

CMenu *MDISetMenu() をオーバーライドしようにも virtual でないのでできない.

CMainFrame::m_hWndMDIClient をサブクラス化して WM_MDISETMENU をフックすればなんとかメニューを消すことができる.


■MainFrameBackWnd.h

/////////////////////////////////////////////////////////////////////////////
// CMainFrameBackWnd ウィンドウ(MDICLIENTのサブクラス)
class CMainFrameBackWnd : public CWnd
{
    // 生成されたメッセージ マップ関数
protected:
    //{{AFX_MSG(CMainFrameBackWnd)
    afx_msg void OnPaint();
    //}}AFX_MSG

    afx_msg LRESULT OnSetMenuNotify(WPARAM wParam, LPARAM lParam);
};



■MainFrm.h

/////////////////////////////////////////////////////////////////////////////
// CMainFrame
class CMainFrame : public CMDIFrameWnd
{
// アトリビュート
private:
    CMainFrameBackWnd m_backWnd;
};



■MainFrm.cpp

/////////////////////////////////////////////////////////////////////////////
// CMainFrame メッセージ ハンドラ

BOOL CMainFrame::CreateClient( LPCREATESTRUCT lpCreateStruct, CMenu* pWindowMenu )
{
    // まず MDICLIENT を作る
    BOOL ret = CMDIFrameWnd::CreateClient(lpCreateStruct, pWindowMenu);
    if( !ret ) {
        return FALSE;
    }

    // ここでサブクラス化
    if( m_hWndMDIClient ) {
        if( !m_backWnd.GetSafeHwnd() ) {
            m_backWnd.SubclassWindow(m_hWndMDIClient);
        }
    }
    return TRUE;
}


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{

    // 元のメニューを消す
    SetMenu(NULL);

    return 0;
}



■MainFrameBackWnd.cpp

BEGIN_MESSAGE_MAP(CMainFrameBackWnd, CWnd)
    //{{AFX_MSG_MAP(CMainFrameBackWnd)
    ON_WM_PAINT()
    //}}AFX_MSG_MAP

    // メッセージマップの追加
    ON_MESSAGE(WM_MDISETMENU, OnSetMenuNotify)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CMainFrameBackWnd メッセージ ハンドラ

LRESULT CMainFrameBackWnd::OnSetMenuNotify(WPARAM wParam, LPARAM lParam)
{
    // フレームのメニューを無視させる
    return CWnd::DefWindowProc(WM_MDISETMENU, (WPARAM)0, lParam);
}


ON_MESSAGE で取ってきたメッセージを
    return CWnd::DefWindowProc(WM_MDISETMENU, (WPARAM)0, lParam);
と呼び出しても問題はないかどうかは気になるところである.
(場合によるとしか言えない)

return 0;
とすると,lParam がポップアップメニュー用のハンドルらしいから,ポップアップメニューまで勝手に潰してしまうのは「フレームメニューを出さない」という観点からするとまずい気がする.
(ポップアップを使用しないのであれば return 0 で問題はないと推測する)


参照
MDIメニューの変更はどこでしているのか?
前後のTips
MDIメニュー消去

DSS ProgrammingTipsCGI Ver2.01