
The used colors are just for highlighting the power of the menu, they can be changed.
Introduction
Principal class is CColorMenu:
#define FADE_NONE 0x00 #define FADE_HORZ 0x01 #define FADE_VERT 0x02 #define FADE2D_NONE 0x00 #define FADE2D_HORZ 0x10 #define FADE2D_VERT 0x20 #define MENU_NONE 0x00 #define MENU_SIMPLE 0x01 #define MENU_POPUP 0x02
Members
COLORREF m_Bk2DPop; COLORREF m_Txt2DPop; COLORREF m_Bk2DMen; COLORREF m_Txt2DMen;
COLORREF m_Bk3DPop; COLORREF m_Txt3DPop; COLORREF m_Bk3DMen; COLORREF m_Txt3DMen;
COLORREF m_Fade2DPop; COLORREF m_Fade3DPop;
COLORREF m_Fade2DMen; COLORREF m_Fade3DMen;
protected:
COLORREF m_ColCheck; COLORREF m_ColSepar;
COLORREF m_BkGray; COLORREF m_TxtGray;
UINT m_FadeTypeMen;
UINT m_FadeTypePop;
int m_Val3D; int m_HeightSep; int m_HeightCel; int m_WidthCel; VTYPE_ITEMCONT* m_itemsStr; VTYPE_MENUCOLOR* m_HandlesMenu;
Steps
-
"Recent Files"

If you have "Recent Files" you must use LoadStdProfileSettingsEx instead of LoadStdProfileSettings, on the derived class from CWinApp.
A new class is used in LoadStdProfileSettingsEx: CRecentFileListEx derived from CRecentFileList.
BOOL CSampleMenuApp::InitInstance()
{
LoadStdProfileSettingsEx(_AFX_MRU_COUNT);
return TRUE;
};
If you don't have "Recent Files" or _AFX_MRU_COUNT = 0, you can eliminate CRecentFileListEx class and void LoadStdProfileSettingsEx(UINT nMaxMRU); function.
All this are used for handling items which are added at run time on "Recent Files" section menu.
-
"Active Windows"

If you use "Active Windows" it is a little bit hard to handle items which are inserted at run time with message WM_MDISETMENU.
On each child frame, you must implement virtual void OnUpdateFrameMenu(BOOL bActive, CWnd* pActivateWnd, HMENU hMenuAlt); as follows:
void CChildFrame::OnUpdateFrameMenu(BOOL bActivate,
CWnd* pActivateWnd, HMENU hMenuAlt)
{
CMDIChildWnd::OnUpdateFrameMenu(bActivate, pActivateWnd, hMenuAlt);
((CMainFrame*)GetParentFrame())->RefreshInternalMenu();
}
This is a virtual function from CMDIChildWnd which updates the frame menu, and you must inform the ColorMenu that "Active Windows" menu was changed with RefreshInternalMenu function.
On CMainFrame, you must define RefreshInternalMenu() as following:
void CMainFrame::RefreshInternalMenu()
{
m_IdTimer = SetTimer(INTERNAL_UPDATE_TIMER, 50, NULL);
}
and on timer function you must do this:
void CMainFrame::OnTimer(UINT nIDEvent)
{
if(nIDEvent == INTERNAL_UPDATE_TIMER)
{
KillTimer(m_IdTimer);
m_IdTimer = NULL;
HMENU hMenuWindow = GetWindowMenuPopup(GetMenuOfView());
CColorMenu* pMenu = m_menuChildFrame.FindSubMenu(hMenuWindow);
if(pMenu)
pMenu->RefreshMenusForMDIs();
}
CMDIFrameWnd::OnTimer(nIDEvent);
}
All this must be done with a timer because UpdateFrameMenu is made as "delayed refresh". If you will not use the timer, you will "not see the new updated menu", you will see menu unchanged.
-
"Final step"
On CMainFrame, you must define all menus: one for CMainFrame and the rest for child frames (if you have more than one).
class CMainFrame : public CMDIFrameWnd
{
HMENU GetMenuOfView(){return m_menuChildFrame.GetSafeHmenu();}
CColorMenu m_menuMainFrame;
CColorMenu m_menuChildFrame;
}
So, if you have more child frames with different menus, you must define more CColorMenu m_menuChildFrame;
On CMainFrame::OnCreate you must just load menus, set the needed icons and replace the default menu as follows:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_menuMainFrame.LoadMenu(IDR_MAINFRAME);
m_menuChildFrame.LoadMenu(IDR_SAMPLETYPE);
m_menuMainFrame.SetIconToHandle(ID_FILE_NEW, IDI_ICON_NEW);
HMENU OldMenuDefault = m_hMenuDefault;
SetMenu(&m_menuMainFrame);
m_hMenuDefault = m_menuMainFrame.GetSafeHmenu();
::DestroyMenu(OldMenuDefault);
}
After that you must implement CMainFrame::OnMeasureItem as follows:
void CMainFrame::OnMeasureItem(int nIDCtl,
LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if(lpMeasureItemStruct->CtlType == ODT_MENU)
{
if(m_menuMainFrame.IsMenu((HMENU)lpMeasureItemStruct->itemID))
{
m_menuMainFrame.MeasureItem(lpMeasureItemStruct);
return;
}
if(m_menuChildFrame.IsMenu((HMENU)lpMeasureItemStruct->itemID))
{
m_menuChildFrame.MeasureItem(lpMeasureItemStruct);
return;
}
}
CMDIFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
};
And destroy the menus... on CMainFrame::OnDestroy().
void CMainFrame::OnDestroy()
{
SetMenu(NULL);
::DestroyMenu(m_hMenuDefault);
m_hMenuDefault = NULL;
m_menuMainFrame.DestroyMenu();
m_menuChildFrame.DestroyMenu();
CMDIFrameWnd::OnDestroy();
}
And last, on each child frame, on CChildFrame::OnCreate, replace the default menu.
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
return -1;
CMainFrame* pFram = (CMainFrame*)GetParentFrame();
HMENU OldMenuDefault = m_hMenuDefault;
m_hMenuDefault = pFram->GetMenuOfView();
m_hMenuShared = m_hMenuDefault;
::DestroyMenu(OldMenuDefault);
}
And on destroy, prevent not to destroy the default menu.
void CChildFrame::OnDestroy()
{
m_hMenuShared = NULL;
m_hMenuDefault = NULL;
CMDIChildWnd::OnDestroy();
}
Have luck!