Max Max - 1 month ago 23
C++ Question

WM_MENUSELECT not handled in CFrameWndEx windows

I'm trying to handle the WM_MENUSELECT message in a VS2008 (and VS2010) SDI project based on a CFrameWndEx main frame window.

I create a simple project from the VS2008 wizard (single document, "MFC standard", "use classic menu" options) which results in something like (after added the WM_MENUSELECT message):

class CMainFrame : public CFrameWnd
{
///...
public:
afx_msg void OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu);
};


and

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_MENUSELECT()
END_MESSAGE_MAP()

///...
void CMainFrame::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
{
CFrameWnd::OnMenuSelect(nItemID, nFlags, hSysMenu);
}


This works, when putting a breakpoint in CMainFrame::OnMenuSelect it is triggered when the menu is used (in that case everytime)

Replacing CFrameWnd by CFrameWndEx (or by creating a new project with the wizard with the options single document, "MFC standard", "use a menubar and toolbar" options)

class CMainFrame : public CFrameWndEx
{
///....
public:
afx_msg void OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu);
};


and

IMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
ON_WM_CREATE()
ON_WM_MENUSELECT()
END_MESSAGE_MAP()

///....
void CMainFrame::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
{
CFrameWndEx::OnMenuSelect(nItemID, nFlags, hSysMenu);
}


The message will never be triggered.

I've even stripped down the project using CFrameWndEx to the strict minimum and I still cannot get the message.

Any idea why ? tips, hints are always welcome.
Thanks.
Max.

Answer

Aaah, the good old times of single-stepping into the source code of MFC! It's always been the key ;-)

CMFCPopupMenu::SetSendMenuSelectMsg() is your new friend.

Just add this line in your CMainFrame::OnCreate() :

CMFCPopupMenu::SetSendMenuSelectMsg(TRUE);

The bottom line is that MFC menus and toolbars aren't the usual wrappers around standard Windows objects. They implement things differently, using a different model.

Now, for the sake of backward compatibility, you can ask those classes to act as their predecessors and send a WM_MENUSELECT, which they don't by default.

Note: There are probably new mechanisms or best practices to manipulate these objects. It's probably worth investigating them rather than forcing a compatibility setting.