Click here to Skip to main content
15,885,956 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 254.8K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// ==========================================================================
// 							   Class Implementation : 
//									COXMenuBar 
// ==========================================================================

// Version: 9.3

// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
                          
// //////////////////////////////////////////////////////////////////////////


#include "stdafx.h"

#include "OXMenuBar.h"
#include "OXSkins.h"
#include "OXBitmapMenuOrganizer.h"

#ifdef OX_CUSTOMIZE_COMMANDS
#include "OXDragDropCommands.h"
#include "..\include\oxmenubar.h"
#endif	//	OX_CUSTOMIZE_COMMANDS

#include "UTB64Bit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


#ifndef IDT_OXCHECKFORDRAGDROPEVENT
#define IDT_OXCHECKFORDRAGDROPEVENT				412
#endif	//	IDT_OXCHECKFORDRAGDROPEVENT
#ifndef ID_OXCHECKFORDRAGDROPEVENT_DELAY
#define ID_OXCHECKFORDRAGDROPEVENT_DELAY		500
#endif	//	ID_OXCHECKFORDRAGDROPEVENT_DELAY


#if _MFC_VER>=0x0420


/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// COXMenuBar
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(COXMenuBar,COXCoolToolBar)

HHOOK COXMenuBar::m_hMouseHook = NULL;

HWND COXMenuBar::m_hwndPrevMouseMoveWnd = NULL;

COXMenuBar::COXMenuBar()
{
	// only works when comctl32.dll v4.71>= is installed
	if(m_dwComCtlVersion<_IE40_COMCTL_VERSION)
	{
		TRACE(_T("In order to use Menu Bar in your application you have to have comctl32.dll v 4.71 or higher installed\n"));
		AfxThrowNotSupportedException();
	}

	// use entire row/column
	m_bTakeEntireRow=TRUE;

	m_hMenu=NULL;
	m_hMDIWindowMenu=NULL;

	m_nActiveMenuItem=-1;
	m_nActivateNextItem=-1;
	m_nForbiddenItem=-1;

	m_rectCloseBtn.SetRectEmpty();
	m_rectRestoreBtn.SetRectEmpty();
	m_rectMinimizeBtn.SetRectEmpty();
	m_pressedBtn=OX_MNU_NONE;

	m_cxLeftBorder=0;
	m_cyTopBorder=0;
	m_cxRightBorder=0;
	m_cyBottomBorder=0;

	m_bIsInSurfingMode=FALSE;

	m_bForceEntireRow=FALSE;

	m_bIsMenuMetricInitialized=FALSE;

	m_nCheckForDragDropEventTimerID=0;
	m_nWouldBeDraggedItem=-1;

	m_bStaySurfing=FALSE;
	m_pMenuSkin = NULL;
}


COXMenuBar::~COXMenuBar()
{
	for(int nIndex=PtrToInt(m_arrCreatedPopupMenus.GetSize()-1); nIndex>=0; nIndex--)
	{
		::DestroyMenu(m_arrCreatedPopupMenus[nIndex]);
	}
	m_arrCreatedPopupMenus.RemoveAll();

	if ( m_pMenuSkin != NULL )
		delete m_pMenuSkin;
}

BEGIN_MESSAGE_MAP(COXMenuBar, COXCoolToolBar)
	//{{AFX_MSG_MAP(COXMenuBar)
	ON_WM_NCLBUTTONDOWN()
	ON_WM_NCHITTEST()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_MOUSEMOVE()
	ON_WM_NCLBUTTONDBLCLK()
	ON_WM_KILLFOCUS()
	ON_WM_SETTINGCHANGE()
	ON_WM_TIMER()
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_NCMOUSEMOVE()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_IDLEUPDATECMDUI, OnIdleUpdateCmdUI)
	ON_UPDATE_COMMAND_UI_RANGE(0,0xffff,OnUpdateMenuItem)
	ON_NOTIFY_REFLECT_EX(TBN_DROPDOWN,OnMenuDropDown)
	ON_MESSAGE(WM_DISPLAYPOPUPMENU, OnDisplayPopupMenu)
	ON_COMMAND(ID_OXCUSTTB_DELETE,OnCustTBDelete)
	// reflect messages to make customization work
	ON_NOTIFY_REFLECT_EX(TBN_BEGINDRAG, OnTBNBeginDrag)
	// v9.3 update 01 modification (added) Manfred Drasch
	ON_MESSAGE(WM_DISPLAYPOPUPMENU_ALLITEMS, OnDisplayPopupMenuAllItems)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

BOOL COXMenuBar::Create(CWnd* pParentWnd, 
						DWORD dwStyle/*=WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_SIZE_DYNAMIC*/, 
						UINT nID/*=AFX_IDW_MENUBAR*/)
{
	ASSERT(pParentWnd!=NULL);
	ASSERT(::IsWindow(pParentWnd->m_hWnd));

	// CToolBar bug !!!!!
	// When menu bar is created again it uses data saved in m_sizeImage 
	// variable for initializing button sizes. CToolBar reset this value
	// as aresult of applying different operations. COXMenuBar doesn't use
	// images so m_sizeImage will be set to (0,0). The thing is CToolBar::CreateEx
	// doesn't like m_sizeImage being set to (0,0)!!!!
	// So we need to set this variable to some reasonable non-zero value.
	// We will use the same numbers as in CToolBar initialization part
	if(m_sizeImage.cx==0 || m_sizeImage.cy==0)
	{
		// not the first creation, reset variables

		// default image sizes
		m_sizeImage.cx = 16;
		m_sizeImage.cy = 15;

		// default button sizes
		m_sizeButton.cx = 23;
		m_sizeButton.cy = 22;
	}

	// try to create cool toolbar
	if(!COXCoolToolBar::Create(pParentWnd,dwStyle,nID))
	{
		return FALSE;
	}

	// make sure dropdown arrows are not appeared on the buttons
	SetDropDownArrow(FALSE);

	// set size of images to zero (cannot call SetSizes function
	// because it will assert if zero value is specified)
	SendMessage(TB_SETBITMAPSIZE,0,MAKELPARAM(0,0));

	// set window text
	CString sText;
	VERIFY(sText.LoadString(IDS_OX_MENUBARTITLE));//"Menu"
	SetWindowText(sText);

	// save pointer to parent window
	m_pFrameWnd=pParentWnd;

	return TRUE;
}

void COXMenuBar::OnFloatingDocking(BOOL bFloating) 
{
	// TODO: Add your message handler code here
	COXCoolToolBar::OnFloatingDocking(bFloating);
	
	if(bFloating)
	{
		// remove all items form mini dock frame window system menu
		CFrameWnd* pMiniDockFrame=(CFrameWnd*)GetDockingFrame();
		ASSERT(pMiniDockFrame!=NULL &&
			pMiniDockFrame->IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)));
		if(pMiniDockFrame!=NULL && pMiniDockFrame->
			IsKindOf(RUNTIME_CLASS(CMiniDockFrameWnd)))
		{
			CMenu* pPopup=pMiniDockFrame->GetSystemMenu(FALSE);
			while(pPopup->DeleteMenu(0,MF_BYPOSITION));
		}
	}
}

void COXMenuBar::OnChangeDockSide(DWORD dwDockSide)
{
	UNREFERENCED_PARAMETER(dwDockSide);
	if(!IsFloating() && GetParentFrame()!=NULL)
	{
		GetParentFrame()->RecalcLayout();
	}
}

// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXMenuBar::OnIdleUpdateCmdUI(WPARAM wParam, LPARAM lParam)
{
	// refresh icon if any is displayed
	UpdateIcon(TRUE);

	COXCoolToolBar::OnIdleUpdateCmdUI(wParam,lParam);

	return 0L;
}

// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXMenuBar::OnDisplayPopupMenu(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);

	MSG msg;
	// handle only the last one
	while(::PeekMessage(&msg,GetSafeHwnd(),
		WM_DISPLAYPOPUPMENU,WM_DISPLAYPOPUPMENU,PM_REMOVE))
	{
		wParam=msg.wParam;
	}

	ASSERT(wParam>=0 && wParam<=(WPARAM)::GetMenuItemCount(m_hMenu));

	DisplayPopupMenu(PtrToInt(wParam));

	return 0;
}
// v9.3 update 01 modification (handler added) Manfred Drasch 
// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXMenuBar::OnDisplayPopupMenuAllItems(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);

	MSG msg;
	// handle only the last one
	while(::PeekMessage(&msg,GetSafeHwnd(),
		WM_DISPLAYPOPUPMENU_ALLITEMS,WM_DISPLAYPOPUPMENU_ALLITEMS,PM_REMOVE))
	{
		wParam=msg.wParam;
	}

	ASSERT(wParam>=0 && wParam<=(WPARAM)::GetMenuItemCount(m_hMenu));

	// while deactivating popup menu the user could have set to
	// activate another menu item. In this case just post the 
	// corresponding message
	if(m_nActivateNextItemShowAll!=-1)
		DisplayPopupMenu(m_nActivateNextItemShowAll);

	return 0;
}

void COXMenuBar::OnUpdateMenuItem(CCmdUI* pCmd)
{
	// if there is nothing to update
	if(m_hMenu==NULL) 
		return;

	CMenu* pMenu=CMenu::FromHandle(m_hMenu);
	ASSERT(pMenu!=NULL);
	if(pMenu==NULL) 
		return;

	// enable menu items
	if(pCmd->m_nID-ID_CMDBASE<pMenu->GetMenuItemCount())
	{
		pCmd->Enable((pMenu->GetMenuState(pCmd->m_nID-ID_CMDBASE,
			MF_BYPOSITION)&(MF_DISABLED|MF_GRAYED))==0);
	}
}

BOOL COXMenuBar::OnMenuDropDown(NMHDR* pNotifyStruct, LRESULT* result)
{
	NMTOOLBAR* pNMTB=(NMTOOLBAR*)pNotifyStruct;

	*result=TBDDRET_DEFAULT;

	// don't call it twice for forbidden item
	if(m_nForbiddenItem!=pNMTB->iItem-ID_CMDBASE)
	{
		// analyze item
		CMenu* pMenu=CMenu::FromHandle(m_hMenu);
		ASSERT(pMenu!=NULL);
		UINT nCmdID=pMenu->GetMenuItemID(pNMTB->iItem-ID_CMDBASE);
		if(nCmdID==-1 || nCmdID==0xffff)
		{
			PostMessage(WM_DISPLAYPOPUPMENU,pNMTB->iItem-ID_CMDBASE);
		}
		else if(nCmdID>0)
		{
			if(!IsInAdvancedCustomizationMode())
			{
				// make sure the state of previously active button is restored
				RestoreMenuButton();

				// set current active item
				m_nActiveMenuItem=pNMTB->iItem-ID_CMDBASE;
				m_nActivateNextItem=-1;
				m_nForbiddenItem=m_nActiveMenuItem;

				// set button to pressed state
				CToolBarCtrl& tool=GetToolBarCtrl();
				tool.PressButton(m_nActiveMenuItem+ID_CMDBASE);

				ASSERT(m_pFrameWnd!=NULL);
				m_pFrameWnd->SendMessage(WM_COMMAND,nCmdID,(LPARAM)NULL);

				m_nForbiddenItem=-1;
				RestoreMenuButton();
			}
		}
	}
	else
	{
		m_nForbiddenItem=-1;
	}

	return FALSE;
}

#if _MSC_VER >= 1400
LRESULT COXMenuBar::OnNcHitTest(CPoint point)
#else
UINT COXMenuBar::OnNcHitTest(CPoint point)
#endif
{
	// TODO: Add your message handler code here and/or call default
	
	CRect rect;
	GetWindowRect(rect);
	CPoint ptTest=point;
	ptTest-=rect.TopLeft();

	// handle areas where icon and close, restore, minimize buttons
	// are located in a specific way
	if(GetIcon()!=NULL && (m_iconRect.PtInRect(ptTest) || 
		m_rectCloseBtn.PtInRect(ptTest) || m_rectRestoreBtn.PtInRect(ptTest) || 
		m_rectMinimizeBtn.PtInRect(ptTest)))
	{
		return HTCAPTION;
	}

	return CToolBar::OnNcHitTest(point);
}

void COXMenuBar::OnNcLButtonDown(UINT nHitTest, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	UNREFERENCED_PARAMETER(nHitTest);

	CRect rect;
	GetWindowRect(rect);
	CPoint ptTest=point;
	ptTest-=rect.TopLeft();

	ASSERT(GetIcon()!=NULL && (m_iconRect.PtInRect(ptTest) || 
		m_rectCloseBtn.PtInRect(ptTest) || m_rectRestoreBtn.PtInRect(ptTest) || 
		m_rectMinimizeBtn.PtInRect(ptTest)));

	if(GetIcon()==NULL)
		return;

	// handle mouse click over icon and close, restore, minimize buttons
	//

	m_pressedBtn=OX_MNU_NONE;

	MENUBARHITTEST hitTest=(MENUBARHITTEST)HitTest(ptTest);

	if(hitTest==OX_MNU_ICON)
	{
		PostMessage(WM_DISPLAYPOPUPMENU,::GetMenuItemCount(m_hMenu));
	}
	else if(hitTest==OX_MNU_CLOSEBTN || hitTest==OX_MNU_RESTOREBTN || hitTest==OX_MNU_MINIMIZEBTN)
	{
		SetCapture();
		m_pressedBtn=hitTest;
		RedrawToolBar(FALSE,TRUE);
	}
	else
	{
		COXCoolToolBar::OnNcLButtonDown(nHitTest,point);
	}
}

void COXMenuBar::OnNcLButtonDblClk(UINT nHitTest, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	// handle mouse double click over icon
	//
	if(GetIcon()!=NULL)
	{
		ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd);
	    BOOL bMaximize=FALSE;
		CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->
			MDIGetActive(&bMaximize);
		ASSERT(pChild!=NULL && bMaximize);
		if(pChild==NULL || !bMaximize)
		{
			COXCoolToolBar::OnNcLButtonDblClk(nHitTest, point);
			return;
		}

		int hitTest=HitTest(point,OX_MNU_SCREEN);
		if(hitTest==OX_MNU_ICON)
			pChild->PostMessage(WM_SYSCOMMAND,SC_CLOSE);
	}

	COXCoolToolBar::OnNcLButtonDblClk(nHitTest, point);
}


void COXMenuBar::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	if(IsFloating())
	{
		CToolBarCtrl& tool=GetToolBarCtrl();
		tool.PressButton(ID_CMDBASE,FALSE);
	}


	if (!IsFloatingEnabled())
	{
		if (HitTest(point, OX_MNU_CLIENT) != OX_MNU_NONE)
			COXCoolToolBar::OnLButtonDblClk(nFlags, point);
	}
	else
		COXCoolToolBar::OnLButtonDblClk(nFlags, point);

	return;
}


void COXMenuBar::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	if(IsFloating())
	{
		CToolBarCtrl& tool=GetToolBarCtrl();
		tool.PressButton(ID_CMDBASE,FALSE);
	}
	
	if (!IsFloatingEnabled())
	{
		if (HitTest(point, OX_MNU_CLIENT) != OX_MNU_NONE)
			COXCoolToolBar::OnLButtonDown(nFlags, point);
	}
	else
		COXCoolToolBar::OnLButtonDown(nFlags, point);


	if(GetDraggedButton()==-1  &&  IsInAdvancedCustomizationMode())
	{
		if(m_nCheckForDragDropEventTimerID==0)
		{
			m_nWouldBeDraggedItem=COXCoolToolBar::HitTest(&point);
			m_nCheckForDragDropEventTimerID=SetTimer(IDT_OXCHECKFORDRAGDROPEVENT,
				ID_OXCHECKFORDRAGDROPEVENT_DELAY,NULL);
			TRACE(_T("\nSetTimer IDT_OXCHECKFORDRAGDROPEVENT\n"));

			ASSERT(m_nCheckForDragDropEventTimerID!=0);
		}
		else
		{
			KillTimer(m_nCheckForDragDropEventTimerID);
			TRACE(_T("Kill timer m_nCheckForDragDropEventTimerID\n"));
			m_nCheckForDragDropEventTimerID=0;
		}
	}

	return;
}


void COXMenuBar::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	// handle mouse click close, restore, minimize buttons
	//
	if (GetIcon() == NULL || ::GetCapture() != GetSafeHwnd() || m_bDragging)
	{
		COXCoolToolBar::OnLButtonUp(nFlags,point);
		return;
	}

	::ReleaseCapture();

    BOOL bMaximize=FALSE;
	ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd);
	CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->MDIGetActive(&bMaximize);
	ASSERT(pChild!=NULL && bMaximize);
	if(pChild==NULL || !bMaximize)
	{
		COXCoolToolBar::OnLButtonUp(nFlags,point);
		return;
	}

	CRect rect;
	GetWindowRect(rect);
	CPoint ptTest=point;
	ClientToScreen(&ptTest);
	ptTest-=rect.TopLeft();

	MENUBARHITTEST hitTest=(MENUBARHITTEST)HitTest(ptTest);

	// send corresponding messages

	if(m_pressedBtn==hitTest)
	{
		if(m_pressedBtn==OX_MNU_CLOSEBTN)
			pChild->PostMessage(WM_SYSCOMMAND,SC_CLOSE);
		else if(m_pressedBtn==OX_MNU_RESTOREBTN)
			pChild->PostMessage(WM_SYSCOMMAND,SC_RESTORE);
		else if(m_pressedBtn==OX_MNU_MINIMIZEBTN)
			pChild->PostMessage(WM_SYSCOMMAND,SC_MINIMIZE);
	}

	m_pressedBtn=OX_MNU_NONE;

	RedrawToolBar(FALSE,TRUE);
}


void COXMenuBar::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	if(IsFloating())
	{
		CToolBarCtrl& tool=GetToolBarCtrl();
		tool.PressButton(ID_CMDBASE,FALSE);
	}
	
	COXCoolToolBar::OnRButtonDown(nFlags,point);
}


void COXMenuBar::OnRButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	
	if(IsFloating())
	{
		CToolBarCtrl& tool=GetToolBarCtrl();
		tool.PressButton(ID_CMDBASE,FALSE);
	}
	
	COXCoolToolBar::OnRButtonDblClk(nFlags,point);
}


void COXMenuBar::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	if (GetIcon())
	{
		CWindowDC dc(this);
		GetToolbarSkin()->DrawMenuButtons(&dc, this);
	}

	if(m_nCheckForDragDropEventTimerID!=0 && ::GetKeyState(VK_LBUTTON)>=0)
	{
		KillTimer(m_nCheckForDragDropEventTimerID);
		TRACE(_T("Kill timer m_nCheckForDragDropEventTimerID\n"));

		m_nCheckForDragDropEventTimerID=0;
	}

	if(GetIcon()==NULL || ::GetCapture()!=GetSafeHwnd())
	{
		COXCoolToolBar::OnMouseMove(nFlags, point);
		return;
	}

	CPoint ptTest=point;

	// handle mouse cursor movement over close, restore, minimize buttons
	//

	int hitTest=HitTest(ptTest,OX_MNU_CLIENT);
	hitTest=hitTest>=0 ? OX_MNU_NONE : hitTest;

	if(m_pressedBtn!=hitTest)
	{
		m_pressedBtn=(MENUBARHITTEST)hitTest;
		RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_FRAME);
	}

	COXCoolToolBar::OnMouseMove(nFlags, point);
}


void COXMenuBar::OnKillFocus(CWnd* pNewWnd) 
{
	COXCoolToolBar::OnKillFocus(pNewWnd);
	
	// TODO: Add your message handler code here

	// reset the surfing mode
	m_bIsInSurfingMode=FALSE;

}


// v9.3 - update 03 - 64-bit - using OXTPARAM here - see UTB64Bit.h
void COXMenuBar::OnTimer(OXTPARAM nIDEvent)
{
	if((int)nIDEvent==m_nCheckForDragDropEventTimerID)
	{
		KillTimer(m_nCheckForDragDropEventTimerID);
		TRACE(_T("Kill timer m_nCheckForDragDropEventTimerID\n"));

		m_nCheckForDragDropEventTimerID=0;

		if(::IsWindow(GetSafeHwnd()))		
		{
			// do drag and drop
			//
			if(::GetKeyState(VK_LBUTTON)<0 && IsInAdvancedCustomizationMode())
			{
				if(m_nWouldBeDraggedItem>=0 && 
					m_nWouldBeDraggedItem<GetToolBarCtrl().GetButtonCount())
				{
					ASSERT(GetParent()!=NULL);
					NMTOOLBAR nmtb;
					nmtb.hdr.hwndFrom=GetSafeHwnd();
					nmtb.hdr.idFrom=GetDlgCtrlID();
					nmtb.hdr.code=TBN_BEGINDRAG;
					nmtb.iItem=m_nWouldBeDraggedItem+ID_CMDBASE;
					GetParent()->
						SendMessage(WM_NOTIFY,(WPARAM)nmtb.hdr.idFrom,(LPARAM)&nmtb);
					m_nWouldBeDraggedItem=-1;
				}
			}
			//
			////////////////////////////////////
		}

		return;
	}

	COXCoolToolBar::OnTimer(nIDEvent);
}


void COXMenuBar::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
	UpdateMenuMetrics();

	COXCoolToolBar::OnSettingChange(uFlags, lpszSection);
}


BOOL COXMenuBar::OnTBNBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMTOOLBAR* pNMToolBar=(NMTOOLBAR*)pNMHDR;

	int nIndex=CommandToIndex(pNMToolBar->iItem);

#ifdef OX_CUSTOMIZE_COMMANDS
	if(IsInAdvancedCustomizationMode())
	{
		int nState=GetToolBarCtrl().GetState(GetItemID(nIndex));
		if((nState&TBSTATE_PRESSED)!=0)
		{
			GetToolBarCtrl().SetState(GetItemID(nIndex),nState&~TBSTATE_PRESSED);
		}

		CWnd* pParentWnd=GetParent();
		ASSERT(pParentWnd!=NULL);
		pNMToolBar->hdr.code=TBN_QUERYDELETE;
		if(pParentWnd->SendMessage(WM_NOTIFY,pNMToolBar->hdr.idFrom,
			(LPARAM)pNMToolBar))
		{
			SendCustomizeNotification(ID_OXCUSTMB_RESET_POPUP_MENU);

			BOOL bWasInAdvancedCustomizationMode=IsInAdvancedCustomizationMode();
			if(GetCustomizedButton()!=nIndex)
			{
				SetCustomizedButton(nIndex);
			}
			SetDraggedButton(nIndex);

			// mark the control as the one that launched drag'n'drop operation
			m_bDragDropOwner=TRUE;

// v9.3 update 02 - VS2008 - using GetHMenu
#if _MFC_VER >= 0x0800
			CMenu* pMenu=CMenu::FromHandle(GetHMenu());
#else 
			CMenu* pMenu=CMenu::FromHandle(GetMenu());
#endif
			ASSERT(pMenu!=NULL);
			CString sText;
			pMenu->GetMenuString(nIndex,sText,MF_BYPOSITION);
			HMENU hSubmenu=::GetSubMenu(pMenu->GetSafeHmenu(),nIndex);
			UINT nCmdID=pMenu->GetMenuItemID(nIndex);
			if(nCmdID==0xffff)
			{
				nCmdID=(UINT)-1;
			}
			COleDataSource* pDataSource=COXDragDropCommands::PrepareDragDropData(
				sText,-1/*image index*/,nCmdID/*command ID*/,0/*button style*/,hSubmenu);
			ASSERT(pDataSource!=NULL);
			m_bDragDropOperation=TRUE;
			DROPEFFECT dropEffect=
				COXDragDropCommands::DoDragDrop(pDataSource,GetDropSource());
			if(DROPEFFECT_MOVE==dropEffect || (DROPEFFECT_NONE==dropEffect &&
				::GetKeyState(VK_LBUTTON)>=0 && !m_bDragDropOperation))
			{
				int nDraggedButtonIndex=GetDraggedButton();
				OnRemoveDraggedButton(nDraggedButtonIndex);
			}
			SetDraggedButton(-1);

			//delete drag source (we are responsible to do that)
			delete pDataSource;

			// unmark as the control which launched drag'n'drop operation
			m_bDragDropOwner=FALSE;


			if(!bWasInAdvancedCustomizationMode)
			{
				SetCustomizedButton(-1);
			}
		}
	}
#else
	UNREFERENCED_PARAMETER(nIndex);
#endif	//	OX_CUSTOMIZE_COMMANDS

	*pResult=0;
	return FALSE;
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXMenuBar::OnDragOver(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);

	// toolbar must be in advanced customizable state
	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	pSHBDTAction->result=(LRESULT)DROPEFFECT_NONE;
#ifdef OX_CUSTOMIZE_COMMANDS
	// Can we use this object?
	if(pSHBDTAction->pDataObject->
		IsDataAvailable(COXDragDropCommands::m_cfCommandButton))
	{
		BOOL bQualified=!(m_bDragDropOwner && 
			(pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL);
		if(bQualified)
		{
			BOOL bAllowToDrop=TRUE;
			if(!(m_bDragDropOwner && 
				(pSHBDTAction->dwKeyState & MK_CONTROL)!=MK_CONTROL))
			{
				// Get the drag item info
				//
				HGLOBAL hgData=pSHBDTAction->pDataObject->
					GetGlobalData(COXDragDropCommands::m_cfCommandButton);
				ASSERT(hgData!=NULL);
				// lock it
				BYTE* lpItemData=(BYTE*)::GlobalLock(hgData);

				// get button command ID
				int nCommandID=*(int*)lpItemData;
				lpItemData+=sizeof(int);
				
				// get button text
				CString sText((LPTSTR)lpItemData);
				lpItemData+=(sText.GetLength()+1)*sizeof(TCHAR);

				// unlock it
				::GlobalUnlock(hgData);
				// free it
				::GlobalFree(hgData);

				if(nCommandID==0)
				{
					bAllowToDrop=FALSE;
				}

				if(sText.IsEmpty())
				{
					bAllowToDrop=FALSE;
				}

				if(GetCustomButtonIndex(nCommandID)!=-1)
				{
					bQualified=FALSE;
				}
			}

			if(!bAllowToDrop && !IsInAdvancedCustomizationMode())
			{
				bQualified=FALSE;
			}

			if(bQualified)
			{
				// analize the current cursor position
				//
				CPoint point=pSHBDTAction->point;

				int nButtonIndex=COXCoolToolBar::HitTest(&point);
				BOOL bIsOut=(nButtonIndex<0);
				nButtonIndex=(bIsOut ? -nButtonIndex : nButtonIndex);
				if(nButtonIndex>=GetToolBarCtrl().GetButtonCount() && 
					GetToolBarCtrl().GetButtonCount()>0)
				{
					nButtonIndex=-1;
					bQualified=FALSE;
				}
				else
				{
					if(nButtonIndex!=GetCustomizedButton())
					{
						SetCustomizedButton(nButtonIndex);
						if(!(m_bDragDropOwner && nButtonIndex==GetDraggedButton()))
						{
							DisplayPopupMenu(nButtonIndex);
						}
					}

					if(bAllowToDrop)
					{
						CWnd* pParentWnd=GetParent();
						ASSERT(pParentWnd!=NULL);
						NMTOOLBAR nmtb;
						nmtb.hdr.hwndFrom=GetSafeHwnd();
						nmtb.hdr.idFrom=GetDlgCtrlID();
						nmtb.hdr.code=TBN_QUERYINSERT;
						nmtb.iItem=nButtonIndex;
						if(!pParentWnd->
							SendMessage(WM_NOTIFY,nmtb.hdr.idFrom,(LPARAM)&nmtb))
						{
							bQualified=FALSE;
						}
						else
						{
							TBINSERTMARK tbim;
							tbim.iButton=nButtonIndex;
							tbim.dwFlags=0;
							CRect rectItem;
							GetItemRect(tbim.iButton,rectItem);
							if(point.x>=rectItem.left+rectItem.Width()/2 || point.x<0)
							{
								tbim.dwFlags=TBIMHT_AFTER;
							}
							SetInsertMark(&tbim);

							// Check if the control key was pressed          
							if((pSHBDTAction->dwKeyState & MK_CONTROL)==MK_CONTROL)
							{
								pSHBDTAction->result=(LRESULT)DROPEFFECT_COPY;
							}
							else
							{
								pSHBDTAction->result=(LRESULT)DROPEFFECT_MOVE; 
							}
						}
					}
				}
			}
		}
			
		if(!bQualified)
		{
			SetInsertMark(-1);
		}
	}
#endif	//	OX_CUSTOMIZE_COMMANDS

	return (LONG)TRUE;
}


// v9.3 - update 03 - 64-bit - return value was declared as LONG - changed to LRESULT
LRESULT COXMenuBar::OnDrop(WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(wParam);

	if(!IsCustomizable(TRUE))
		return (LONG)FALSE;

	// lParam is the pointer to SHBDROPTARGETACTION structure
	LPSHBDROPTARGETACTION pSHBDTAction=(LPSHBDROPTARGETACTION)lParam;
	ASSERT(pSHBDTAction!=NULL);

	ASSERT(pSHBDTAction->pWnd);
	ASSERT(pSHBDTAction->pWnd->GetSafeHwnd()==GetSafeHwnd());

	pSHBDTAction->result=(LRESULT)FALSE;

#ifdef OX_CUSTOMIZE_COMMANDS
	// if dragged item is to be copied or moved
	if((pSHBDTAction->dropEffect&DROPEFFECT_COPY)!=0 || 
		(pSHBDTAction->dropEffect&DROPEFFECT_MOVE)!=0)
	{
		// data must be in the specific format
		ASSERT(pSHBDTAction->pDataObject->
			IsDataAvailable(COXDragDropCommands::m_cfCommandButton));

		TBINSERTMARK tbim;
		GetInsertMark(&tbim);
		int nButtonIndex=tbim.iButton;
		// remove insert mark
		SetInsertMark(-1);
		if(nButtonIndex!=-1 || GetToolBarCtrl().GetButtonCount()==0)
		{
			int nDraggedButtonIndex=GetDraggedButton();

			if(m_bDragDropOwner && (pSHBDTAction->dropEffect&DROPEFFECT_COPY)==0)
			{
				ASSERT(GetToolBarCtrl().GetButtonCount()>0);

				ASSERT(nDraggedButtonIndex!=-1);
				if(nButtonIndex==nDraggedButtonIndex)
				{
					pSHBDTAction->result=(LRESULT)FALSE;
					return (LONG)TRUE;
				}
			}

			nButtonIndex=(tbim.dwFlags==0 ? nButtonIndex : nButtonIndex+1);
			int nButtonCount=GetToolBarCtrl().GetButtonCount();
			if(nButtonIndex==-1)
			{
				ASSERT(nButtonCount==0 && !m_bDragDropOwner);
				nButtonIndex=0;
			}
			else if(nButtonIndex>nButtonCount)
			{
				nButtonIndex=nButtonCount;
			}
			// v9.3 update 02 - using GetHMenu for VS2008
#if _MFC_VER >= 0x0800
			HMENU hMenu=GetHMenu();
#else
			HMENU hMenu=GetMenu();
#endif
			ASSERT(hMenu!=NULL);

			// Get the drag item info
			//
			HGLOBAL hgData=pSHBDTAction->pDataObject->
				GetGlobalData(COXDragDropCommands::m_cfCommandButton);
			ASSERT(hgData!=NULL);
			// lock it
			BYTE* lpItemData=(BYTE*)::GlobalLock(hgData);

			RetrieveDragDropMenuItem(lpItemData,hMenu,nButtonIndex);

			// unlock it
			::GlobalUnlock(hgData);
			// free it
			::GlobalFree(hgData);

			// update dragged item position
			if(nButtonIndex<nDraggedButtonIndex)
			{
				SetDraggedButton(nDraggedButtonIndex+1);
			}

			// drag'n'drop operation completed successfully
			pSHBDTAction->result=(LRESULT)TRUE;

			MarkAsChanged();
			DrawMenuBar();
		}
		else
		{
			pSHBDTAction->result=(LRESULT)FALSE;
		}
	}
#endif	//	OX_CUSTOMIZE_COMMANDS

	m_bDragDropOperation=FALSE;

	// we handled the message
	return (LONG)TRUE;
}


void COXMenuBar::RetrieveDragDropMenuItem(BYTE*& lpData, HMENU hMenu, int nButtonIndex)
{
	ASSERT(lpData!=NULL);
	ASSERT(hMenu!=NULL);
	ASSERT(::IsMenu(hMenu));

	while(TRUE)
	{
		// get button command ID
		int nCommandID=*(int*)lpData;
		lpData+=sizeof(int);
		
		// get button text
		CString sText((LPTSTR)lpData);
		lpData+=(sText.GetLength()+1)*sizeof(TCHAR);

		// get button image index
		int nImageIndex=*(int*)lpData;
		lpData+=sizeof(int);
		UNREFERENCED_PARAMETER(nImageIndex);

		// get button style
		BYTE fsStyle=*(BYTE*)lpData;
		lpData+=sizeof(BYTE);
		UNREFERENCED_PARAMETER(fsStyle);

		// get finish flag
		int nFinish=*(int*)lpData;
		lpData+=sizeof(int);

		// update menu
		if(nCommandID==-1)
		{
			HMENU hSubMenu=::CreatePopupMenu();
			ASSERT(hSubMenu!=NULL);
			m_arrCreatedPopupMenus.Add(hSubMenu);
			VERIFY(::InsertMenu(hMenu,nButtonIndex,
				MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT_PTR)hSubMenu,sText)!=0);
			if(nFinish!=0)
			{
				RetrieveDragDropMenuItem(lpData,hSubMenu,0);
			}
		}
		else
		{
			VERIFY(::InsertMenu(hMenu,nButtonIndex,
				MF_BYPOSITION|(nCommandID==0 ? MF_SEPARATOR : MF_STRING),
				(UINT)nCommandID,sText)!=0);
		}
		nButtonIndex++;

		if(nFinish==0 || nFinish==2)
		{
			break;
		}
	}
}


void COXMenuBar::OnRemoveDraggedButton(int nButtonIndex)
{
	// update menu buttons ID
	int nButtonCount=GetToolBarCtrl().GetButtonCount();
	for(int nIndex=nButtonIndex+1; nIndex<nButtonCount; nIndex++)
	{
		UINT nID=GetItemID(nIndex);
		if(nID!=0)
		{
			GetToolBarCtrl().SetCmdID(nIndex,nID-1);
		}
	}

	COXCoolToolBar::OnRemoveDraggedButton(nButtonIndex);

			// v9.3 update 02 - using GetHMenu for VS2008
#if _MFC_VER >= 0x0800
	HMENU hMenu=GetHMenu();
#else
	HMENU hMenu=GetMenu();
#endif	ASSERT(hMenu!=NULL);
	VERIFY(::DeleteMenu(hMenu,nButtonIndex,MF_BYPOSITION));
	MarkAsChanged();
}


void COXMenuBar::OnCustTBDelete()
{
	ASSERT(IsInAdvancedCustomizationMode());
	int nCustomizedButtonIndex=GetCustomizedButton();
	ASSERT(nCustomizedButtonIndex!=-1);

	if(SendCustomizeNotification(ID_OXCUSTTB_DELETE))
		return;

	OnRemoveDraggedButton(nCustomizedButtonIndex);
}


////////////////////////////////////////////////////////////////////


CSize COXMenuBar::CalcLayout(DWORD dwMode, int nLength)
{
	CSize sizeResult=COXCoolToolBar::CalcLayout(dwMode,nLength);

	RecalculateItemWidths();

	// adjust the size of menu bar if it should take the entire 
	// row/column
	if(m_bTakeEntireRow)
	{
		CSize size=GetEntireRow((dwMode & LM_HORZ));
		if((dwMode&LM_HORZDOCK) || (dwMode&LM_VERTDOCK) || m_bForceEntireRow)
		{
			if(dwMode & LM_HORZ)
				sizeResult.cx=size.cy-size.cx;
			else
				sizeResult.cy=size.cy-size.cx;
		}

	}

	return sizeResult;
}

CSize COXMenuBar::GetEntireRow(BOOL bHorz) const
{
	CWnd* pWndFrame=m_pDockSite;
	if(pWndFrame==NULL)
		pWndFrame=GetParentFrame();
	if(pWndFrame==NULL)
		pWndFrame=m_pFrameWnd;
	if(pWndFrame==NULL)
		pWndFrame=GetParent();
	ASSERT(pWndFrame!=NULL);


	CSize sizeResult(0,0);
	CRect rect;
	pWndFrame->GetClientRect(rect);
	if(bHorz)
	{
		sizeResult.cx=-afxData.cxBorder2;
		sizeResult.cy=rect.Width()+afxData.cxBorder2;
	}
	else
	{
		sizeResult.cx=-afxData.cyBorder2;
		sizeResult.cy=rect.Height()+afxData.cyBorder2;
	}

	if(pWndFrame->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
	{
		// find corresponding dock bar 

		CRect rectDockBar;
		CWnd* pDockBar;

		if(bHorz)
		{
			pDockBar=((CFrameWnd*)pWndFrame)->
				GetControlBar(AFX_IDW_DOCKBAR_TOP);
			if(pDockBar!=NULL)
				pDockBar=((CFrameWnd*)pWndFrame)->
					GetControlBar(AFX_IDW_DOCKBAR_BOTTOM);
		}
		else
		{
			pDockBar=((CFrameWnd*)pWndFrame)->
				GetControlBar(AFX_IDW_DOCKBAR_LEFT);
			if(pDockBar!=NULL)
				pDockBar=((CFrameWnd*)pWndFrame)->
					GetControlBar(AFX_IDW_DOCKBAR_RIGHT);
		}

		if(pDockBar!=NULL)
		{
			pDockBar->GetWindowRect(rectDockBar);
			pDockBar->ScreenToClient(rectDockBar);
			if(bHorz)
			{
				sizeResult.cx=-afxData.cxBorder2;
				sizeResult.cy=rectDockBar.right+afxData.cyBorder2;
			}
			else
			{
				sizeResult.cx=-afxData.cxBorder2;
					sizeResult.cy=rectDockBar.bottom+afxData.cyBorder2;
			}
		}
	}

	return sizeResult;
}


BOOL COXMenuBar::IsCustomizable(BOOL bAdvanced/*=TRUE*/) const
{ 
	return (bAdvanced ? TRUE : FALSE);
}


// global handle of the window that had focus before the menu bar
// was set in the surfing mode
HWND g_hWndHadFocus=NULL;

BOOL COXMenuBar::SetSurfingMode(BOOL bIsInSurfingMode/*=TRUE*/, int nItem/*=0*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));
	ASSERT(nItem==-1 || (nItem>=0 && nItem<=GetToolBarCtrl().GetButtonCount()));
	if(nItem==GetToolBarCtrl().GetButtonCount())
	{
		nItem=-1;
	}

	if(bIsInSurfingMode==m_bIsInSurfingMode)
	{
		ASSERT(!m_bIsInSurfingMode || !IsInDisplayingMode());
		ASSERT((m_bIsInSurfingMode && ::GetFocus()==m_hWnd) || 
			(!m_bIsInSurfingMode && ::GetFocus()!=m_hWnd));
		// just reset the hot item
		if(m_bIsInSurfingMode)
		{
			SendMessage(TB_SETHOTITEM,nItem);
		}
		return TRUE;
	}

	// double check
	if(bIsInSurfingMode && IsInDisplayingMode())
	{
		TRACE(_T("COXMenuBar::SetSurfingMode: Cannot be set in the surfing mode while displaying popup menus\n"));
		return FALSE;
	}

	if(bIsInSurfingMode)
	{
		// save thae handle of the window that had focus
		g_hWndHadFocus=::GetFocus();
		SetFocus();
		// reset hot item
		SendMessage(TB_SETHOTITEM,nItem);

		if(!m_bStaySurfing)
		{
			// send WM_ENTERMENULOOP and WM_INITMENU messages. 
			m_pFrameWnd->SendMessage(WM_ENTERMENULOOP,(WPARAM)FALSE);
			m_pFrameWnd->SendMessage(WM_INITMENU,(WPARAM)m_hMenu);
			// send WM_MENUSELECT message
			m_pFrameWnd->SendMessage(WM_MENUSELECT,
				MAKEWPARAM(nItem,MF_POPUP|MF_HILITE),(LPARAM)m_hMenu);
		}
	}
	else		
	{
		g_hWndHadFocus=::IsWindow(g_hWndHadFocus) ? g_hWndHadFocus : NULL;
		// reset focus window
		::SetFocus(g_hWndHadFocus);
		g_hWndHadFocus=NULL;
		// reset hot item
		SendMessage(TB_SETHOTITEM,(WPARAM)-1);
	}

	m_bIsInSurfingMode=bIsInSurfingMode;

	return TRUE;
}

void COXMenuBar::BookSpace(CRect& rectBookedSpace, DWORD dwMode) 
{
	// book some space for close, restore, minimize buttons
	if(dwMode&LM_HORZ)
		rectBookedSpace.right=CalcButtonRects();
	else
		rectBookedSpace.bottom=CalcButtonRects();
}

void COXMenuBar::DrawInBookedSpace(CDC& dc, CRect& rectToDrawIn)
{
	if(GetIcon()!=NULL)
	{
		ASSERT(m_pFrameWnd!=NULL);
		if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
		{
			// recalculate close, restore, minimize buttons rectangles
			CalcButtonRects();

			// and draw them
			DrawButtons(dc);

			// update the rectangle that can be used by parent window to draw 
			// additional elements
			if(m_dwStyle&CBRS_ORIENT_HORZ)
				rectToDrawIn.right=(!m_rectMinimizeBtn.IsRectEmpty() ? 
					m_rectMinimizeBtn.left : (!m_rectRestoreBtn.IsRectEmpty() ? 
					m_rectRestoreBtn.left : m_rectCloseBtn.left))-6;
			else
				rectToDrawIn.bottom=(!m_rectMinimizeBtn.IsRectEmpty() ? 
					m_rectMinimizeBtn.top : (!m_rectRestoreBtn.IsRectEmpty() ? 
					m_rectRestoreBtn.top : m_rectCloseBtn.top))-6;
		}
	}
}

BOOL COXMenuBar::SetMenu(HMENU hMenu)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	if(m_hMenu==hMenu)
		return TRUE;

	SaveCustomizedMenu();

	m_hMenu=hMenu;

	if(IsCustomizable(TRUE))
	{
		CDocTemplate* pDocTemplate=NULL;
		if(!m_mapCustomizableMenus.Lookup(m_hMenu,pDocTemplate))
		{
			CDocument* pDocument=NULL;
			CWnd* pWnd=AfxGetMainWnd();
			CFrameWnd* pFrameWnd=DYNAMIC_DOWNCAST(CFrameWnd,pWnd);
			if(pFrameWnd!=NULL)
			{
				if(pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
				{
					CMDIChildWnd* pChildWnd=((CMDIFrameWnd*)pFrameWnd)->MDIGetActive();
					if(pChildWnd==NULL)
					{
						pDocument=NULL;
					}
					else
					{
						pDocument=pChildWnd->GetActiveDocument();
					}
				}
				else
				{
					pDocument=pFrameWnd->GetActiveDocument();
				}
			}
			pDocTemplate=(pDocument==NULL ? NULL : pDocument->GetDocTemplate());

			BOOL bAlreadyExist=FALSE;
			POSITION pos=m_mapCustomizableMenus.GetStartPosition();
			while(pos!=NULL)
			{
				CDocTemplate* pTestDocTemplate=NULL;
				HMENU hTestMenu=NULL;
				m_mapCustomizableMenus.GetNextAssoc(pos,hTestMenu,pTestDocTemplate);
				ASSERT(hTestMenu!=NULL);
				if(pTestDocTemplate==pDocTemplate)
				{
					bAlreadyExist=TRUE;
					break;
				}
			}

			if(!bAlreadyExist)
			{
				m_mapCustomizableMenus.SetAt(m_hMenu,pDocTemplate);
#ifndef _UNICODE
				VERIFY(LoadMenuState(m_hMenu,(pDocument==NULL ? NULL :
					pDocument->GetRuntimeClass()->m_lpszClassName)));
#else
				if(pDocument!=NULL)
				{
					LPCSTR lpszUniqueName=
						pDocument->GetRuntimeClass()->m_lpszClassName;
					// v9.3 update 01 - incorrect string length calculation - noted by Karl Edwall
					//int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1;
					int nLength = lstrlenA(lpszUniqueName) + 1;
					LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength];
					memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR));
					_mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength);
					VERIFY(LoadMenuState(m_hMenu,lpszUnicodeUniqueName));
					delete[] lpszUnicodeUniqueName;
				}
				else
				{
					VERIFY(LoadMenuState(m_hMenu,NULL));
				}
#endif
			}
		}
	}

	// repopulate menubar
	return RecreateMenuBar();
}

BOOL COXMenuBar::RecreateMenuBar(BOOL bRedraw/*=TRUE*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	// preserve old settings
	int nOldDraggedButton=GetDraggedButton();
	int nOldCustomizedButton=GetCustomizedButton();


	// delete existing buttons
	CToolBarCtrl& tool=GetToolBarCtrl();
	// don't redraw the menubar contents yet
	m_bNoInternalRedraw=TRUE;
	while(tool.DeleteButton(0));
	m_bNoInternalRedraw=FALSE;
	// clean up accelerator table
	m_accelTable.RemoveAll();


	// work out currently active MDIChild window icon (only for MDI applications)
	UpdateIcon(FALSE);

	BOOL bResult=TRUE;

	if(m_hMenu!=NULL)
	{

		// create one button for every menu item
		//

		CMenu menu;
		if(!menu.Attach(m_hMenu))
		{
			return FALSE;
		}

		// number of menu items 
		int nItems=menu.GetMenuItemCount();
		CString sMenuItem;
		TBBUTTON* pButtons=new TBBUTTON[nItems]; 

		// add buttons and set text to them
		for(int nIndex=0; nIndex<nItems; nIndex++)
		{
			// item name
			menu.GetMenuString(nIndex,sMenuItem,MF_BYPOSITION);
			// in AddStrings() parameter must ends with "\0\0"
			TCHAR* szMenuItemWithDoubleZero=new TCHAR[sMenuItem.GetLength()+2];
			::lstrcpyn(szMenuItemWithDoubleZero,sMenuItem,sMenuItem.GetLength()+1);
			szMenuItemWithDoubleZero[sMenuItem.GetLength()+1]=_T('\0');

			// work out accelerator
			int nPos=sMenuItem.Find(_T("&"));
			if(nPos!=-1)
			{
				CString sAccelSymbol=sMenuItem.Mid(nPos+1,1);
				sAccelSymbol.MakeUpper();
				m_accelTable.SetAt((TCHAR)*((LPCTSTR)sAccelSymbol),nIndex);
			}

			// setup button structure
			pButtons[nIndex].iBitmap=-1;
			pButtons[nIndex].idCommand=nIndex+ID_CMDBASE;
			pButtons[nIndex].fsState=TBSTATE_ENABLED;
			pButtons[nIndex].fsStyle=
				TBSTYLE_BUTTON|TBSTYLE_DROPDOWN|TBSTYLE_AUTOSIZE;
			pButtons[nIndex].dwData=nIndex;
			pButtons[nIndex].iString=tool.AddStrings(szMenuItemWithDoubleZero);

			delete[] szMenuItemWithDoubleZero;
		}

		bResult=tool.AddButtons(nItems,pButtons);
		delete[] pButtons;
		//////////////////////////////////////////////////////////////////////

		VERIFY(menu.Detach()!=NULL);
	}

	// reset old settings
	if(nOldDraggedButton>=0 && 
		nOldDraggedButton<GetToolBarCtrl().GetButtonCount())
	{
		SetDraggedButton(nOldDraggedButton);
	}
	if(nOldCustomizedButton>=0 && 
		nOldCustomizedButton<GetToolBarCtrl().GetButtonCount())
	{
		m_nCustomizedButtonIndex=nOldCustomizedButton;
	}


	if(!m_bIsMenuMetricInitialized)
	{
		UpdateMenuMetrics(FALSE);
		m_bIsMenuMetricInitialized=TRUE;
	}

	ASSERT(m_pFrameWnd!=NULL);
	if(m_hMenu==NULL)
	{
		if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
			((CFrameWnd*)m_pFrameWnd)->ShowControlBar(this,FALSE,FALSE);
		else
			ShowWindow(SW_HIDE);
	}
	else 
	{
		if(bRedraw)
		{
			// redraw the toolbar if specified
			RedrawToolBar(TRUE,TRUE);
			m_bDelayedButtonLayout=TRUE;
		}
		if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)))
		{
			((CFrameWnd*)m_pFrameWnd)->ShowControlBar(this,TRUE,FALSE);
		}
		else
		{
			CRect rect;
			m_pFrameWnd->GetClientRect(rect);
			CSize szToolbar=CalcFixedLayout(TRUE,TRUE);
			rect.top-=2;
			rect.bottom=rect.top+szToolbar.cy;
			MoveWindow(rect);
			ShowWindow(SW_SHOWNA);
		}
	}

	return bResult;
}

void COXMenuBar::UpdateIcon(BOOL bRedraw/*=TRUE*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	// refresh the icon
	HICON hIcon=NULL;
	if(m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
	{
	    BOOL bMaximize=FALSE;
		CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->
			MDIGetActive(&bMaximize);
		if(pChild!=NULL && bMaximize)
		{
			hIcon=(HICON)(INT_PTR)::GetClassLongPtr(pChild->m_hWnd,GCL_HICONSM);
			if(hIcon==NULL)
				hIcon=(HICON)(INT_PTR)::GetClassLongPtr(pChild->m_hWnd,GCL_HICON);
			if(hIcon==NULL)
			{
				// v9.3 - update 03 - 64-bit - using OXPDWORD - see UTB64Bit.h
				if(!::SendMessageTimeout(pChild->m_hWnd,
					WM_GETICON,ICON_SMALL,0,SMTO_ABORTIFHUNG,1000,
					(OXPDWORD)&hIcon) || hIcon==NULL)
				{
					::SendMessageTimeout(pChild->m_hWnd,
						WM_GETICON,ICON_BIG,0,SMTO_ABORTIFHUNG,1000,
						(OXPDWORD)&hIcon);
				}

				if(hIcon==NULL)
					hIcon=::LoadIcon(NULL,IDI_WINLOGO);
			}
		}
	}

	if(hIcon!=GetIcon())
		SetIcon(hIcon,bRedraw);
}

void COXMenuBar::DisplayPopupMenu(int nMenuItem)
{
    m_nActivateNextItemShowAll = nMenuItem;

    ASSERT(m_hMenu!=NULL);
    ASSERT((nMenuItem>=0 && nMenuItem<::GetMenuItemCount(m_hMenu)) ||
        (GetIcon()!=NULL && nMenuItem==::GetMenuItemCount(m_hMenu)));

    if (IsInAdvancedCustomizationMode())
        SaveCustomizedMenu();

    if(m_hMenu==NULL || nMenuItem<0 || nMenuItem>::GetMenuItemCount(m_hMenu) ||
        (GetIcon()==NULL && nMenuItem==::GetMenuItemCount(m_hMenu)) ||
        (::GetMenuItemID(m_hMenu,nMenuItem)!=-1 && 
        ::GetMenuItemID(m_hMenu,nMenuItem)!=0xffff))
    {
        // make sure the state of previously active button is restored
        if (m_hMenu && IsInSurfingMode())
        {
            CMenu* pMenu=CMenu::FromHandle(m_hMenu);
            ASSERT(pMenu);
            CMenu* pSubMenu=pMenu->GetSubMenu(nMenuItem);
            ASSERT(pSubMenu==NULL);
            UINT nID=pMenu->GetMenuItemID(nMenuItem);
            CWnd* pMainWnd=AfxGetMainWnd();
            pMainWnd->SendMessage(WM_COMMAND,nID);
        }
        RestoreMenuButton();
        return;
    }

    BOOL bWasInDisplayingMode=IsInDisplayingMode();

    // reset the surfing mode
    BOOL bWasInSurfingMode=IsInSurfingMode();
    SetSurfingMode(FALSE);

    // if system menu should be displayed
    BOOL bSysMenu=(nMenuItem==::GetMenuItemCount(m_hMenu));

    CMenu* pPopup=NULL;
    if(bSysMenu)
    {
        if(IsInAdvancedCustomizationMode())
            return;

        // work out system menu
        ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd);
        BOOL bMaximize=FALSE;
        CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->
            MDIGetActive(&bMaximize);
        ASSERT(pChild!=NULL && bMaximize);
        if(pChild==NULL || !bMaximize)
            return;

        pPopup=pChild->GetSystemMenu(FALSE);
    }
    else
    {
        // work out popup menu
        CMenu* pMenu=CMenu::FromHandle(m_hMenu);
        ASSERT(pMenu!=NULL);
        if(pMenu!=NULL && (pMenu->GetMenuState(nMenuItem,MF_BYPOSITION)&
            (MF_DISABLED|MF_GRAYED))==0)
        {
            pPopup=pMenu->GetSubMenu(nMenuItem);
        }
    }

    if(pPopup==NULL && !IsInAdvancedCustomizationMode()) 
    {
        // make sure the state of previously active button is restored
        RestoreMenuButton();
        return;
    }

    ASSERT(m_pFrameWnd!=NULL);

    if(!bWasInSurfingMode)
    {
        // send WM_ENTERMENULOOP and WM_INITMENU messages. 
        if(!bWasInDisplayingMode)
        {
            m_pFrameWnd->SendMessage(WM_ENTERMENULOOP,(WPARAM)FALSE);
            m_pFrameWnd->SendMessage(WM_INITMENU,(WPARAM)m_hMenu);
        }
        // send WM_MENUSELECT message
        m_pFrameWnd->SendMessage(WM_MENUSELECT,MAKEWPARAM((bSysMenu ? 0 : nMenuItem),
            ((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))),(LPARAM)m_hMenu);
    }

    UINT nFlags=TPM_LEFTBUTTON;

    CRect rect;
    GetItemRect(nMenuItem,&rect);
    // translate the current toolbar item rectangle into screen coordinates
    // so that we'll know where to pop up the menu
    ClientToScreen(&rect);    

    // Attach the COXBitmapMenu object if not done already
    COXBitmapMenu* pBitmapMenu = DYNAMIC_DOWNCAST(COXBitmapMenu, pPopup);
    BOOL bConvert = FALSE;
    COXBitmapMenuOrganizer* pOrganizer = COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
        
    if (pOrganizer != NULL)
    {
        if (pBitmapMenu == NULL)
        {
            pBitmapMenu    = new COXBitmapMenu();
            TRACE(_T("\nCreated menu at %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__);
            pBitmapMenu->Attach(pPopup->Detach());
            pPopup = (CMenu *) pBitmapMenu;
            pOrganizer->m_BitmapMenuList.AddTail(pBitmapMenu);    
            bConvert = TRUE;
        }
        
        pOrganizer->ConvertBitmapMenu(pBitmapMenu, bConvert);
    }

    

    // Determine top left point of the popup menu
    CPoint ptPos;
    UINT nDummy;
    COXBitmapMenu::DeterminePosition(pPopup, rect, m_dwStyle, ptPos, nFlags, nDummy);

    // make sure the state of previously active button is restored
    RestoreMenuButton();    

    // set current active item
    m_nActiveMenuItem=nMenuItem;
    m_nActivateNextItem=-1;

    // set button to pressed state
    CToolBarCtrl& tool=GetToolBarCtrl();
    if(!IsInAdvancedCustomizationMode())
    {
        tool.PressButton(m_nActiveMenuItem+ID_CMDBASE);
    }

    // display popup menu
    CWnd* pWndOwner=AfxGetMainWnd();
    if(pPopup!=NULL)
    {
        if(IsInAdvancedCustomizationMode())
        {
            OXCUSTOMIZEPOPUPMENUINFO cpmi;
            cpmi.hMenu=pPopup->GetSafeHmenu();
            cpmi.nFlags=nFlags;
            cpmi.ptStart = ptPos;
            SendCustomizeNotification(ID_OXCUSTMB_CUSTOMIZE_POPUP_MENU,(LPARAM)&cpmi);
            m_nForbiddenItem=-1;
            RestoreMenuButton();
        }
        else
        {
            if (pBitmapMenu != NULL)
                pBitmapMenu->TrackPopupMenu(this, pWndOwner);
            else
                pPopup->TrackPopupMenu(nFlags, ptPos.x, ptPos.y, pWndOwner, rect);


			// v9.3 update 01 modification Manfred Drasch - to avoid attempted popup display on app close
            CPoint cursorPos;
            GetCursorPos(&cursorPos);
            ScreenToClient(&cursorPos);
#if _MFC_VER>0x0421
            int hitPos=tool.HitTest(&cursorPos);
#else
            int hitPos=tool.SendMessage(TB_HITTEST,0,(LPARAM)&cursorPos);
#endif

            // are we over a menu or arrow menupoint?
            if((m_nActivateNextItem!=-1) && (m_nActivateNextItem != nMenuItem) && (hitPos!=m_nActivateNextItem))
            {
                CRect Rect;

                BOOL fHit = FALSE;
                int nCount = ::GetMenuItemCount(m_hMenu);
                for (int nLoop = 0; nLoop <= nCount; nLoop++)
                {
                    GetItemRect(nLoop, &Rect);
                    if (Rect.PtInRect(cursorPos))
                    {
                        fHit = TRUE;
                        break;
                    }
                }
                if (!fHit)
                    m_nActivateNextItem = -1;
            }
			// *** end mods Manfred Drasch


            // while deactivating popup menu the user could have set to
            // activate another menu item. In this case just post the 
            // corresponding message
            if(m_nActivateNextItem!=-1)
            {
                PostMessage(WM_DISPLAYPOPUPMENU,m_nActivateNextItem);
            }
            else
            {
                // Check whether we are still on the original button
// v9.3 update 01 *** modification (code removed) Manfred Drasch 
//                CPoint cursorPos;
//                GetCursorPos(&cursorPos);
//                ScreenToClient(&cursorPos);
//#if _MFC_VER>0x0421
//                int hitPos=tool.HitTest(&cursorPos);
//#else
//                int hitPos=tool.SendMessage(TB_HITTEST,0,(LPARAM)&cursorPos);
//#endif
// *** end mods manfred 
                if(hitPos==m_nActiveMenuItem)
                {
                    // Don't allow it to drop down again
                    m_nForbiddenItem=m_nActiveMenuItem; 
                }
                RestoreMenuButton();
            }
        }
    }
}

void COXMenuBar::RestoreMenuButton()
{
	// set button to unpressed state
	if(m_nActiveMenuItem!=-1)
	{
		CToolBarCtrl& tool=GetToolBarCtrl();
		tool.PressButton(m_nActiveMenuItem+ID_CMDBASE,FALSE);
		int nSavedActiveMenuItem=m_nActiveMenuItem;
		m_nActiveMenuItem=-1;
		if(m_nActivateNextItem==-1 && !m_bStaySurfing)
		{
			// send WM_EXITMENULOOP message
			m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE);
		}
		if(m_bStaySurfing)
		{
			SetSurfingMode(TRUE,nSavedActiveMenuItem);
			// reset forbidden item
			m_nForbiddenItem=-1;
		}
		m_bStaySurfing=FALSE;
	}
}


int COXMenuBar::CalcButtonRects()
{
	m_rectCloseBtn.SetRectEmpty();
	m_rectRestoreBtn.SetRectEmpty();
	m_rectMinimizeBtn.SetRectEmpty();

	// total width of buttons
	int nButtonsWidth=0;

	if(GetIcon()!=NULL)
	{
		ASSERT(m_pFrameWnd!=NULL);
		ASSERT(::IsWindow(m_pFrameWnd->m_hWnd));
		ASSERT_KINDOF(CMDIFrameWnd,m_pFrameWnd);

	    BOOL bMaximize=FALSE;
		CMDIChildWnd* pChild=((CMDIFrameWnd*)m_pFrameWnd)->
			MDIGetActive(&bMaximize);
		if(pChild==NULL || !bMaximize)
			return nButtonsWidth;

		nButtonsWidth=2;

		DWORD dwStyle=pChild->GetStyle();

		// buttons metrics
		int cxIcon=18;
		int cyIcon=18;

		BOOL bHorz=(m_dwStyle&CBRS_ORIENT_HORZ); 

		CRect rectToDrawIn;
		GetWindowRect(rectToDrawIn);
		rectToDrawIn-=rectToDrawIn.TopLeft();

		// center the button images depending on orientation
		int nOffset=0;
		if(bHorz)
		{
			if(rectToDrawIn.Height()<cyIcon)
			{
				cyIcon=rectToDrawIn.Height();
				cxIcon=cyIcon;
			}
			else
				nOffset=(rectToDrawIn.Height()-cyIcon)/2+
					(rectToDrawIn.Height()-cyIcon)%2;
		}
		else
		{
			if(rectToDrawIn.Width()<cxIcon)
			{
				cxIcon=rectToDrawIn.Width();
				cyIcon=cxIcon;
			}
			else
				nOffset=(rectToDrawIn.Width()-cxIcon)/2+
					(rectToDrawIn.Width()-cxIcon)%2;
		}

		// flags that specify if corresponding buttons are displayed
		BOOL bCloseBox=TRUE;
		BOOL bMaxBox=bCloseBox & 
			((dwStyle&WS_MAXIMIZEBOX)!=0 || (dwStyle&WS_MINIMIZEBOX)!=0);

		// Calculate caption buttons. 
		CRect rect;
		if(bHorz)
			rect=CRect(rectToDrawIn.right-cxIcon-nButtonsWidth,nOffset, 
				rectToDrawIn.right-nButtonsWidth,nOffset+cyIcon);
		else
			rect=CRect(nOffset,rectToDrawIn.bottom-cxIcon-nButtonsWidth,
				nOffset+cxIcon,rectToDrawIn.bottom-nButtonsWidth);
	
		if(bCloseBox)
		{
			// Close box has a 2 pixel border on all sides but left/top, 
			// which is zero
			if(bHorz)
				rect.DeflateRect(0,2,2,2);
			else
				rect.DeflateRect(2,0,2,2);
			m_rectCloseBtn=rect;
			nButtonsWidth+=bHorz ? cxIcon : cyIcon;
		}

		// Max/restore button is like close box; just shift rectangle left
		if(bMaxBox) 
		{
			ASSERT(bCloseBox);

			rect-=bHorz ? CPoint(cxIcon,0) : CPoint(0,cyIcon);
			m_rectRestoreBtn=rect;
			nButtonsWidth+=bHorz ? cxIcon : cyIcon;
		}

		// Minimize button has 2 pixel border on all sides but right.
		if(bMaxBox) 
		{
			ASSERT(bCloseBox);

			rect-=bHorz ? CPoint(cxIcon-2,0) : CPoint(0,cyIcon-2);
			m_rectMinimizeBtn=rect;
			nButtonsWidth+=bHorz ? cxIcon : cyIcon;
		}

		nButtonsWidth+=ID_BUTTONSGAP;
	}

	return nButtonsWidth;
}


void COXMenuBar::DrawButtons(CDC& dc)
{
	GetToolbarSkin()->DrawMenuButtons(&dc, this);
}

int COXMenuBar::HitTest(const CPoint& ptTest, 
						HITTESTORIGIN Origin/*=OX_MNU_ZEROBASED*/) const
{
	CPoint point=ptTest;

	CRect rect;

	// update the test point depending on origin
	switch(Origin)
	{
	case OX_MNU_ZEROBASED:
		break;
	case OX_MNU_CLIENT:
		GetWindowRect(rect);
		ScreenToClient(rect);
		point-=rect.TopLeft();
		break;
	case OX_MNU_SCREEN:
		GetWindowRect(rect);
		point-=rect.TopLeft();
		break;
	}

	int hitTest;
	if(m_iconRect.PtInRect(point))
		hitTest=OX_MNU_ICON;
	else if(m_rectCloseBtn.PtInRect(point))
		hitTest=OX_MNU_CLOSEBTN;
	else if(m_rectRestoreBtn.PtInRect(point))
		hitTest=OX_MNU_RESTOREBTN;
	else if(m_rectMinimizeBtn.PtInRect(point))
		hitTest=OX_MNU_MINIMIZEBTN;
	else
	{
		// find corresponding menu item
		//

		hitTest=OX_MNU_NONE;

		CRect rectClient;
		GetClientRect(rectClient);
		if(rectClient.PtInRect(point))
		{
			GetWindowRect(rect);
			ScreenToClient(rect);
			point+=rect.TopLeft();

			CToolBarCtrl& tool=GetToolBarCtrl();
			for(int nIndex=0; nIndex<tool.GetButtonCount(); nIndex++)
			{
				tool.GetItemRect(nIndex,rect);
				if(rect.PtInRect(point))
				{
					hitTest=nIndex;
					break;
				}
			}
		}
	}

	return hitTest;
}


BOOL COXMenuBar::HandleMenuKey(UINT nChar)
{
	// handle keyboard messages
	//

	if(AfxGetMainWnd()->SendMessage(WM_KEYDOWN,nChar,1))
		return TRUE;
	
	ASSERT(::IsWindow(m_hWnd));

	BOOL bHandled=FALSE;

	if(nChar==0)
	{
		// ALT key was pressed
		ASSERT(!IsInDisplayingMode());
		int nHotItem=PtrToInt(SendMessage(TB_GETHOTITEM));
		nHotItem=nHotItem==-1 ? 0 : nHotItem;
		// set the menu  bar in surfing mode when user presses ALT key
		SetSurfingMode(!IsInSurfingMode(),nHotItem);
		if(!IsInSurfingMode())
		{
			// send WM_EXITMENULOOP message
			m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE);
		}
		bHandled=TRUE;
	}
	else if(nChar==VK_ESCAPE && IsInSurfingMode())
	{
		// Esc key was pressed in surfing mode
		int nHotItem=PtrToInt(SendMessage(TB_GETHOTITEM));
		nHotItem=nHotItem==-1 ? 0 : nHotItem;
		SetSurfingMode(FALSE,nHotItem);
		// send WM_EXITMENULOOP message
		m_pFrameWnd->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE);
		bHandled=TRUE;
	}
	else
	{
		int nItemCount=GetToolBarCtrl().GetButtonCount();
		if(nItemCount==0)
			return FALSE;

		// handle keys  depending on their values, menu bar
		// orientation sand the mode it is currently in
		switch(nChar)
		{
		case VK_LEFT:
			if(m_dwStyle & CBRS_ORIENT_HORZ)
			{
				if(IsInSurfingMode())
				{
					// in surfing mode just navigate through menu items
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					// retrieve the item that preceedes the current hot one
					nItem=GetPrevMenuItem(nItem);
					// set it to hot state
					SendMessage(TB_SETHOTITEM,
						(nItem>=0 && nItem<nItemCount) ? nItem : -1);

					// if system menu should be displayed
					BOOL bSysMenu=(nItem==::GetMenuItemCount(m_hMenu));
					// send WM_MENUSELECT message
					m_pFrameWnd->SendMessage(WM_MENUSELECT,
						MAKEWPARAM((bSysMenu ? 0 : nItem),
						((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))),
						(LPARAM)m_hMenu);

					bHandled=TRUE;
				}
				else if(IsInDisplayingMode())
				{
					// in displaying mode we activate the preceeding menu item
					int nItem=GetPrevMenuItem(m_nActiveMenuItem);
					if(nItem!=m_nActiveMenuItem)
					{
						if((::GetMenuItemID(m_hMenu,nItem)==-1 || 
							::GetMenuItemID(m_hMenu,nItem)==0xffff))
						{
							m_nActivateNextItem=nItem;

							// emulate mouse click 
							//
							CRect rect;
							if(GetIcon()!=NULL && nItem==nItemCount)
							{
								GetToolBarCtrl().GetItemRect(0,rect);
								
								// v9.3 update 01 Modification Manfred Drasch
								// the sysmenu was not shown
								//	rect.DeflateRect(1,1);
								//	rect.OffsetRect(-::GetSystemMetrics(SM_CXSMICON),0);
								ClientToScreen(rect);
								// end modification Manfred Drasch
							}
							else
							{
								GetToolBarCtrl().GetItemRect(nItem,rect);
							}
							CPoint point(rect.left+rect.Width()/2,
								rect.top+rect.Height()/2);
							PostMessage(WM_LBUTTONDOWN,MK_LBUTTON,
								MAKELPARAM(point.x,point.y));
							PostMessage(WM_LBUTTONUP,MK_LBUTTON,
								MAKELPARAM(point.x,point.y));
							//////////////////////////////
						}
						bHandled=TRUE;
					}
				}
			}
			else
			{
				if(IsInSurfingMode())
				{
					// in surfing mode activate the currently hot item
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=nItem==-1 ? nItemCount : nItem;
					DisplayPopupMenu(nItem);
					bHandled=TRUE;
				}
			}
			break;
		
		case VK_RIGHT:
			if(m_dwStyle & CBRS_ORIENT_HORZ)
			{
				if(IsInSurfingMode())
				{
					// in surfing mode just navigate through menu items
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					// retrieve the item that followss the current hot one
					nItem=GetNextMenuItem(nItem);
					// set it to hot state
					SendMessage(TB_SETHOTITEM,
						(nItem>=0 && nItem<nItemCount) ? nItem : -1);

					// if system menu should be displayed
					BOOL bSysMenu=(nItem==::GetMenuItemCount(m_hMenu));
					// send WM_MENUSELECT message
					m_pFrameWnd->SendMessage(WM_MENUSELECT,
						MAKEWPARAM((bSysMenu ? 0 : nItem),
						((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))),
						(LPARAM)m_hMenu);

					bHandled=TRUE;
				}
				else if(IsInDisplayingMode())
				{
					// in displaying mode we activate the following menu item
					int nItem=GetNextMenuItem(m_nActiveMenuItem);
					if(nItem!=m_nActiveMenuItem)
					{
						if((::GetMenuItemID(m_hMenu,nItem)==-1 || 
							::GetMenuItemID(m_hMenu,nItem)==0xffff))
						{
							m_nActivateNextItem=nItem;

							// emulate mouse click 
							//
							CRect rect;
							if(GetIcon()!=NULL && nItem==nItemCount)
							{
								GetToolBarCtrl().GetItemRect(0,rect);
								// v9.3 update 01 modification Manfred Drasch
								// the sysmenu was not shown
								// rect.DeflateRect(1,1);
								// rect.OffsetRect(-::GetSystemMetrics(SM_CXSMICON),0);
								ClientToScreen(rect);
								// end modification Manfred Drasch
							}
							else
							{
								GetToolBarCtrl().GetItemRect(nItem,rect);
							}
							CPoint point(rect.left+rect.Width()/2,
								rect.top+rect.Height()/2);
							PostMessage(WM_LBUTTONDOWN,MK_LBUTTON,
								MAKELPARAM(point.x,point.y));
							PostMessage(WM_LBUTTONUP,MK_LBUTTON,
								MAKELPARAM(point.x,point.y));
							////////////////////////////
						}
						bHandled=TRUE;
					}
				}
			}
			else
			{
				if(IsInSurfingMode())
				{
					// in surfing mode activate the currently hot item
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=nItem==-1 ? nItemCount : nItem;
					DisplayPopupMenu(nItem);
					bHandled=TRUE;
				}
			}
			break;

		case VK_UP:
			if(m_dwStyle & CBRS_ORIENT_VERT)
			{
				if(IsInSurfingMode())
				{
					// in surfing mode just navigate through menu items
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=GetPrevMenuItem(nItem);
					SendMessage(TB_SETHOTITEM,
						(nItem>=0 && nItem<nItemCount) ? nItem : -1);

					// if system menu should be displayed
					BOOL bSysMenu=(nItem==::GetMenuItemCount(m_hMenu));
					// send WM_MENUSELECT message
					m_pFrameWnd->SendMessage(WM_MENUSELECT,
						MAKEWPARAM((bSysMenu ? 0 : nItem),
						((bSysMenu ? MF_SYSMENU : MF_POPUP|MF_HILITE))),
						(LPARAM)m_hMenu);

					bHandled=TRUE;
				}
			}
			else
			{
				if(IsInSurfingMode())
				{
					// in surfing mode activate the currently hot item
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=nItem==-1 ? nItemCount : nItem;
					DisplayPopupMenu(nItem);
					bHandled=TRUE;
				}
			}
			break;

		case VK_DOWN:
			if(m_dwStyle & CBRS_ORIENT_VERT)
			{
				if(IsInSurfingMode())
				{
					// in surfing mode just navigate through menu items
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=GetNextMenuItem(nItem);
					SendMessage(TB_SETHOTITEM,
						(nItem>=0 && nItem<nItemCount) ? nItem : -1);
					bHandled=TRUE;
				}
			}
			else
			{
				if(IsInSurfingMode())
				{
					// in surfing mode activate the currently hot item
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
					nItem=nItem==-1 ? nItemCount : nItem;
					DisplayPopupMenu(nItem);
					bHandled=TRUE;
				}
			}
			break;

		case VK_RETURN:
			if(IsInSurfingMode())
			{
				// in surfing mode activate the currently hot item
					int nItem=PtrToInt(SendMessage(TB_GETHOTITEM));
				nItem=nItem==-1 ? nItemCount : nItem;
				DisplayPopupMenu(nItem);
				bHandled=TRUE;
			}
			break;
		
		case VK_ESCAPE:
			if(IsInDisplayingMode())
			{
				// set the flag that specifies that menu bar should state 
				// in surfing mode after Esc key was pressed when
				// top level popup menu was active
				m_bStaySurfing=TRUE;

				bHandled=FALSE;
			}
			break;
		
		default:
			if(!IsInDisplayingMode() && ::GetAsyncKeyState(VK_CONTROL)>=0)
			{
				// try to find the matching key in accelerator table
				int nMenuItem=-1;
				TCHAR sHotKey=(TCHAR)nChar;


				// the key strokes passed in to the OnKeyDown handlers are always as
                // capital letters, there is no need to convert characters to capitals again
                // this will only cause problems with extended keyboard keys (ie num-pad)
                //_tcsupr(&sHotKey);

				if(m_accelTable.Lookup(sHotKey,nMenuItem))
				{
					ASSERT(nMenuItem>=0 && 
						nMenuItem<GetToolBarCtrl().GetButtonCount());
					// if found, activate it
					DisplayPopupMenu(nMenuItem);
					bHandled=TRUE;
				}
			}
		}
	}

	return bHandled;
}


int COXMenuBar::GetPrevMenuItem(int nItem, 
								BOOL bEnsureVisible/*=TRUE*/)
{
	int nItemCount=GetToolBarCtrl().GetButtonCount();

	nItem=nItem==-1 ? ((GetIcon()!=NULL) ? nItemCount : 0) : nItem;
	if(GetIcon()!=NULL)
		nItem=nItem==0 ? nItemCount : nItem-1;
	else
		nItem=nItem==0 ? nItemCount-1 : nItem-1;

	if(bEnsureVisible && nItem!=nItemCount)
	{
		// make sure the button rectangle is within menubar client area
		//
		CRect rectClient;
		GetClientRect(rectClient);
		CRect rectItem;
		GetItemRect(nItem, rectItem);
		if(rectItem.left>rectClient.right)
			nItem=GetIcon()!=NULL ? nItemCount : 0;
	}

	return nItem;
}

int COXMenuBar::GetNextMenuItem(int nItem, 
								BOOL bEnsureVisible/*=TRUE*/)
{
	int nItemCount=GetToolBarCtrl().GetButtonCount();

	nItem=nItem==-1 ? ((GetIcon()!=NULL) ? nItemCount : 0) : nItem;
	if(GetIcon()!=NULL)
		nItem=nItem==nItemCount ? 0 : nItem+1;
	else
		nItem=nItem==nItemCount-1 ? 0 : nItem+1;

	if(bEnsureVisible && nItem!=nItemCount)
	{
		// make sure the button rectangle is within menubar client area
		//
		CRect rectClient;
		GetClientRect(rectClient);
		CRect rectItem;
		GetItemRect(nItem,rectItem);
		if(rectItem.left>rectClient.right)
			nItem=GetIcon()!=NULL ? nItemCount : 0;
	}

	return nItem;
}


void COXMenuBar::UpdateMenuMetrics(BOOL bRedraw/*=TRUE*/)
{
	ASSERT(::IsWindow(GetSafeHwnd()));

	if((HFONT)m_fontMenu!=NULL)
		m_fontMenu.DeleteObject();
	// Menu font, height and color
	//////////////////////////////////////////////////////////////////
	// v9.3 update 02 - the NONCLIENTMETRICS struct is an int larger 
	// on Vista vs XP (iPaddedBorderWidth added). Code compiled for 
	// WINVER 0x0600 will fail the call to SystemParametersInfo on XP.
	// Code compiled for XP should still run on Vista.

	int ncmSize = sizeof( NONCLIENTMETRICS );

#	if WINVER >= 0x0600
	// compiled for Vista - check for OS version
	OSVERSIONINFO vi={ sizeof(OSVERSIONINFO) };
	ASSERT(GetVersionEx(&vi));
	if(vi.dwMajorVersion < 6) {
		// running on lesser version - adjust size of NONCLIENTMETRICS struct
		ncmSize -= sizeof( int );
	}
#	endif

	NONCLIENTMETRICS ncm={ ncmSize };
	VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncmSize, &ncm, 0));
	// end NONCLIENTMETRICS mods v9.3 update 02
	/////////////////////////////////////////////////

	VERIFY(m_fontMenu.CreateFontIndirect(&ncm.lfMenuFont));
	SetFont(&m_fontMenu,TRUE);

	if(GetToolBarCtrl().GetButtonCount()>0)
	{
		GetToolBarCtrl().AutoSize();
		CRect rect;
		GetToolBarCtrl().GetItemRect(0,&rect);
#if _MFC_VER<=0x0421
		SetHeight(rect.Height()+6);
#else
		SetHeight(rect.Height()+3);
#endif
		GetToolBarCtrl().SetButtonSize(rect.Size());
	}

	SetDefaultTextColor(::GetSysColor(COLOR_MENUTEXT));

	if(bRedraw)
	{
		// redraw the toolbar if specified
		RedrawToolBar();
	}
}


BOOL COXMenuBar::SaveBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, 
							  BOOL bProperties)
{
	UNREFERENCED_PARAMETER(lpszSubKey);
	UNREFERENCED_PARAMETER(lpszValueName);
	UNREFERENCED_PARAMETER(bProperties);

#ifndef _MAC
	if(IsCustomizable(TRUE))
	{
		POSITION pos=m_mapChangedMenus.GetStartPosition();
		while(pos!=NULL)
		{
			HMENU hMenu=NULL;
			int nIndex=-1;
			m_mapChangedMenus.GetNextAssoc(pos,hMenu,nIndex);
			ASSERT(hMenu!=NULL);
			CDocTemplate* pDocTemplate=NULL;
			VERIFY(m_mapCustomizableMenus.Lookup(hMenu,pDocTemplate));
			CDocument* pDocument=NULL;
			if(pDocTemplate!=NULL)
			{
				POSITION pos=pDocTemplate->GetFirstDocPosition();
				ASSERT(pos!=NULL);
				pDocument=pDocTemplate->GetNextDoc(pos);
				ASSERT(pDocument!=NULL);
			}
#ifndef _UNICODE
			VERIFY(SaveMenuState(hMenu,(pDocument==NULL ? NULL :
				pDocument->GetRuntimeClass()->m_lpszClassName)));
#else
			if(pDocument!=NULL)
			{
				LPCSTR lpszUniqueName=pDocument->GetRuntimeClass()->m_lpszClassName;
				// v9.3 update 01 - incorrect string length calculation - noted by Karl Edwall
				//int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1;
				int nLength = lstrlenA(lpszUniqueName) + 1;				LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength];
				memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR));
				_mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength);
				VERIFY(SaveMenuState(hMenu,lpszUnicodeUniqueName));
				delete[] lpszUnicodeUniqueName;
			}
			else
			{
				VERIFY(SaveMenuState(hMenu,NULL));
			}
#endif
			m_mapChangedMenus.RemoveKey(hMenu);
		}
	}
	return TRUE;
#else
	return FALSE;
#endif
}

// Load from registry state of menus
BOOL COXMenuBar::LoadBarState(LPCTSTR lpszSubKey, LPCTSTR lpszValueName, 
							  BOOL bProperties)
{
	UNREFERENCED_PARAMETER(lpszSubKey);
	UNREFERENCED_PARAMETER(lpszValueName);
	UNREFERENCED_PARAMETER(bProperties);

#ifndef _MAC
	return TRUE;
#else
	return FALSE;
#endif
}


BOOL COXMenuBar::SaveMenuState(HMENU hMenu, LPCTSTR lpszSubKey)
{
#ifndef _MAC
	ASSERT(hMenu!=NULL);
	ASSERT(::IsMenu(hMenu)!=NULL);

	if(!IsCustomizable(TRUE))
		return FALSE;

	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
		// v9.3 update 01 - TD removed garbage here
		// sProfileName=_T("Menu_Default~!@#$#$%^");
		sProfileName=_T("Menu_Default_");
	else
		sProfileName=_T("Menu_")+sProfileName;
	CString sValueName=_T("MenuItems");
	
	CMemFile memFile;
	CArchive ar(&memFile,CArchive::store);
	VERIFY(SaveMenuContents(hMenu,ar));
	ar.Close();
	int nBufferLength=(int)memFile.GetLength();
	ASSERT(nBufferLength>0);
	BYTE* pBuffer=memFile.Detach();

	pApp->WriteProfileBinary(sProfileName,sValueName,pBuffer,nBufferLength);
	::free((void*)pBuffer);

	sValueName=_T("MenuDataSize");
	pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength);

	if(m_pFrameWnd!=NULL)
	{
		// notify parent that the state of menu is being saved. Parent window 
		// might save any additional info
		m_pFrameWnd->SendMessage(WM_OX_SAVEMENUSTATE,(WPARAM)hMenu,
			(LPARAM)(LPCTSTR)sProfileName);
	}

	return TRUE;
#else
	return FALSE;
#endif
}


BOOL COXMenuBar::LoadMenuState(HMENU hMenu, LPCTSTR lpszSubKey)
{
#ifndef _MAC
	ASSERT(hMenu!=NULL);
	ASSERT(::IsMenu(hMenu)!=NULL);

	if(!IsCustomizable(TRUE))
		return FALSE;

	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
		// v9.3 update 01 - TD removed garbage here
		// sProfileName=_T("Menu_Default~!@#$#$%^");
		sProfileName=_T("Menu_Default");
	else
		sProfileName=_T("Menu_")+sProfileName;
	CString sValueName=_T("MenuDataSize");
	int nSavedBufferLength=
		pApp->GetProfileInt(sProfileName,sValueName,-1);
	sValueName=_T("MenuItems");
	if(nSavedBufferLength!=-1)
	{
		ASSERT(nSavedBufferLength>0);
		UINT nBufferLength=0;
		BYTE* pBuffer=NULL;
		if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength))
		{
			m_hMDIWindowMenu=NULL;

			ASSERT(nBufferLength>0);
			ASSERT(pBuffer!=NULL);
			CMemFile memFile(pBuffer,nBufferLength);
			CArchive ar(&memFile,CArchive::load);
			VERIFY(LoadMenuContents(hMenu,ar));
			ar.Close();
			memFile.Detach();
			delete[] pBuffer;
		}
	}

	if(m_pFrameWnd!=NULL)
	{
		// notify parent that the state of menu is being restored from registry. 
		// Parent window might apply any saved info
		m_pFrameWnd->SendMessage(WM_OX_LOADMENUSTATE,(WPARAM)hMenu,
			(LPARAM)(LPCTSTR)sProfileName);
	}

	return TRUE;
#else
	return FALSE;
#endif
}


BOOL COXMenuBar::SaveMenuContents(HMENU hMenu, CArchive& ar)
{
	ASSERT(hMenu!=NULL);
	ASSERT(::IsMenu(hMenu)!=NULL);

	int nItemCount=::GetMenuItemCount(hMenu);
	ar<<nItemCount;
	for(int nIndex=0; nIndex<nItemCount; nIndex++)
	{
		MENUITEMINFO menuItemInfo;
		::memset(&menuItemInfo, 0, sizeof(MENUITEMINFO));
		menuItemInfo.cbSize = sizeof(MENUITEMINFO);
		menuItemInfo.fMask=MIIM_ID|MIIM_SUBMENU|MIIM_TYPE;
		menuItemInfo.cch=1024;
		TCHAR tszBuffer[1024];
		menuItemInfo.dwTypeData = tszBuffer;
		VERIFY(::GetMenuItemInfo(hMenu,nIndex,TRUE,&menuItemInfo));

		CString strText(tszBuffer, menuItemInfo.cch);
		
		ASSERT(!strText.IsEmpty() || (menuItemInfo.fType&MFT_SEPARATOR)!=0);
		ar<<menuItemInfo.fType;
		ar<<(BOOL)(menuItemInfo.hSubMenu!=NULL);
		ar<<(menuItemInfo.hSubMenu!=NULL ? (UINT)-1 : menuItemInfo.wID);
		ar<<strText;

		if (menuItemInfo.hSubMenu != NULL)
		{
			VERIFY(SaveMenuContents(menuItemInfo.hSubMenu,ar));
		}
	}
	return TRUE;
}


BOOL COXMenuBar::LoadMenuContents(HMENU hMenu, CArchive& ar)
{
	ASSERT(hMenu!=NULL);
	ASSERT(::IsMenu(hMenu)!=NULL);

	// remove all items from menu
	while(::DeleteMenu(hMenu,0,MF_BYPOSITION));

	DWORD dwItemCount=0;
	ar>>dwItemCount;
	for(int nIndex=0; nIndex<(int)dwItemCount; nIndex++)
	{
		MENUITEMINFO menuItemInfo={ sizeof(MENUITEMINFO) };
		menuItemInfo.fMask=MIIM_ID|MIIM_SUBMENU|MIIM_TYPE;
		ar>>menuItemInfo.fType;
		BOOL bPopupMenu=FALSE;
		ar>>bPopupMenu;
		ar>>menuItemInfo.wID;

		CString sText;
		ar>>sText;
		menuItemInfo.hSubMenu=NULL;
		if(bPopupMenu)
		{
			menuItemInfo.wID=(UINT)-1;
			// create new popup menu
			menuItemInfo.hSubMenu=::CreatePopupMenu();
			ASSERT(menuItemInfo.hSubMenu!=NULL);
			m_arrCreatedPopupMenus.Add(menuItemInfo.hSubMenu);
			VERIFY(LoadMenuContents(menuItemInfo.hSubMenu,ar));
		}

		// if this item is first MDIChild then we have to remove the separator 
		// that we put before
		if(menuItemInfo.wID==AFX_IDM_FIRST_MDICHILD)
		{
			CWnd* pWnd=AfxGetMainWnd();
			CMDIFrameWnd* pMDIFrameWnd=DYNAMIC_DOWNCAST(CMDIFrameWnd,pWnd);
			if(pMDIFrameWnd!=NULL)
			{
				// check if the previous item is separator
				MENUITEMINFO menuItemInfo={ sizeof(MENUITEMINFO) };
				menuItemInfo.fMask=MIIM_TYPE;
				VERIFY(::GetMenuItemInfo(hMenu,::GetMenuItemCount(hMenu)-1,
					TRUE,&menuItemInfo));
				if((menuItemInfo.fType&MFT_SEPARATOR)!=0)
				{
					VERIFY(::DeleteMenu(hMenu,::GetMenuItemCount(hMenu)-1,
						MF_BYPOSITION));
				}

				m_hMDIWindowMenu=hMenu;
			}
		}

		// don't add MDIChild windows menu items 
		if(bPopupMenu || menuItemInfo.wID<AFX_IDM_FIRST_MDICHILD)
		{
			menuItemInfo.cch=sText.GetLength();
			menuItemInfo.dwTypeData=(LPTSTR)sText.GetBuffer(menuItemInfo.cch);
			VERIFY(::InsertMenuItem(hMenu,::GetMenuItemCount(hMenu),TRUE,
				&menuItemInfo));
			sText.ReleaseBuffer();
		}
	}

	return TRUE;
}


BOOL COXMenuBar::DisplayCustomizeButtonContextMenu(int nButtonIndex, CPoint point)
{
	ASSERT(::IsWindow(GetSafeHwnd()));
	ASSERT(nButtonIndex>=0 && nButtonIndex<GetToolBarCtrl().GetButtonCount());
	UNUSED(nButtonIndex);

	CMenu menu;
	if(!menu.CreatePopupMenu())
		return FALSE;
	// populate menu
	CString sItem;
	sItem.LoadString(IDS_OX_CUSTTB_DELETE);
	VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTTB_DELETE,sItem));
	VERIFY(menu.AppendMenu(MF_SEPARATOR));
	sItem.LoadString(IDS_OX_CUSTTB_APPEARANCE);
	VERIFY(menu.AppendMenu(MF_STRING,ID_OXCUSTTB_APPEARANCE,sItem));

	menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
		point.x,point.y,this);

	return TRUE;
}


COXMenuBar* COXMenuBar::FindMenuBar(CWnd* pStartWnd/*=NULL*/)
{
	if(pStartWnd==NULL)
		pStartWnd=AfxGetMainWnd();
	if(pStartWnd==NULL)
		return NULL;

	if(pStartWnd->IsKindOf(RUNTIME_CLASS(COXMenuBar)))
		return DYNAMIC_DOWNCAST(COXMenuBar,pStartWnd);

	CWnd* pWnd=pStartWnd->GetWindow(GW_CHILD);
	while(pWnd!=NULL)
	{
		COXMenuBar* pMenuBar=COXMenuBar::FindMenuBar(pWnd);
		if(pMenuBar!=NULL)
			return pMenuBar;

		pWnd=pWnd->GetWindow(GW_HWNDNEXT);
	}

	return NULL;
}

BOOL COXMenuBar::SaveCustomizedMenu()
{
	if(!IsCustomizable(TRUE))
		return TRUE;

	BOOL bRes = TRUE;
	int nIndex=-1;
	if(m_mapChangedMenus.Lookup(m_hMenu,nIndex))
	{
		CDocTemplate* pDocTemplate=NULL;
		VERIFY(m_mapCustomizableMenus.Lookup(m_hMenu,pDocTemplate));
		CDocument* pDocument=NULL;
		if(pDocTemplate!=NULL)
		{
			POSITION pos=pDocTemplate->GetFirstDocPosition();
			ASSERT(pos!=NULL);
			pDocument=pDocTemplate->GetNextDoc(pos);
			ASSERT(pDocument!=NULL);
		}
#ifndef _UNICODE
		bRes = SaveMenuState(m_hMenu,(pDocument==NULL ? NULL :
			pDocument->GetRuntimeClass()->m_lpszClassName));
#else
		if(pDocument!=NULL)
		{
			LPCSTR lpszUniqueName=pDocument->GetRuntimeClass()->m_lpszClassName;
			// v9.3 update 01 - incorrect string length calculation - noted by Karl Edwall
			//int nLength=sizeof(lpszUniqueName)/sizeof(lpszUniqueName[0])+1;
			int nLength = lstrlenA(lpszUniqueName) + 1;
			LPTSTR lpszUnicodeUniqueName=new TCHAR[nLength];
			memset(lpszUnicodeUniqueName,0,nLength*sizeof(TCHAR));
			_mbstowcsz(lpszUnicodeUniqueName,lpszUniqueName,nLength);
			bRes = SaveMenuState(m_hMenu,lpszUnicodeUniqueName);
			delete[] lpszUnicodeUniqueName;
		}
		else
		{
			VERIFY(SaveMenuState(m_hMenu,NULL));
		}
#endif
		m_mapChangedMenus.RemoveKey(m_hMenu);
	}

	return bRes;
}

///////////////////////////////////////////////////////////////////////////


#endif	//	_MFC_VER>=0x0420

CString COXMenuBar::GetItemText(int iIndex)
{
	CMenu menu;
	menu.Attach(m_hMenu);

	CString strText;
	menu.GetMenuString(iIndex, strText, MF_BYPOSITION);
	menu.Detach();
	return strText;
}

int COXMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (COXCoolToolBar::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	// Hook the mouse
	if (m_hMouseHook == NULL)
		m_hMouseHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 0, AfxGetApp()->m_nThreadID);

	return 0;
}

void COXMenuBar::OnDestroy() 
{
	// Unhook the mouse
	if (m_hMouseHook)
	{
		::UnhookWindowsHookEx(m_hMouseHook);
		m_hMouseHook = NULL;
	}

	COXCoolToolBar::OnDestroy();
}

// Update the buttons of the mini frame window when the mouse leaves
LRESULT CALLBACK COXMenuBar::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if (nCode < 0)
		return ::CallNextHookEx(m_hMouseHook, nCode, wParam, lParam);

	if (nCode == HC_ACTION && (wParam == WM_MOUSEMOVE || wParam == WM_NCMOUSEMOVE))
	{

		MOUSEHOOKSTRUCT* pMH = (MOUSEHOOKSTRUCT*) lParam;

		// If the previous message was for COXSizableMiniDockFrameWnd and the current is not
		// we need to update the caption buttons
		COXMenuBar* pPrev = DYNAMIC_DOWNCAST(COXMenuBar,
			CWnd::FromHandlePermanent(m_hwndPrevMouseMoveWnd));
		COXMenuBar* pCurrent = DYNAMIC_DOWNCAST(COXMenuBar,
			CWnd::FromHandlePermanent(pMH->hwnd));

		if (pPrev != NULL && pCurrent != pPrev)
		{
			if (pPrev->m_pFrameWnd->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd)))
			{
				// The mouse just left the mini frame window
				CWindowDC dc(pPrev);
				pPrev->GetToolbarSkin()->DrawMenuButtons(&dc, pPrev);
			}
		}
		m_hwndPrevMouseMoveWnd = pMH->hwnd;
	}

	return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam);
}

void COXMenuBar::OnNcMouseMove(UINT nHitTest, CPoint point) 
{
	CWindowDC dc(this);
	GetToolbarSkin()->DrawMenuButtons(&dc, this);
	
	COXCoolToolBar::OnNcMouseMove(nHitTest, point);
}

COXMenuSkin* COXMenuBar::GetMenuSkin()
{
	// Check if the app is derived from COXSkinnedApp
	COXSkinnedApp* pSkinnedApp = DYNAMIC_DOWNCAST(COXSkinnedApp, AfxGetApp());
	if (pSkinnedApp != NULL && pSkinnedApp->GetCurrentSkin() != NULL)
		return pSkinnedApp->GetCurrentSkin()->GetMenuSkin();
	else
	{
		// Create a classic skin for this class if not created already
		if (m_pMenuSkin == NULL)
			m_pMenuSkin = new COXMenuSkinClassic();

		return m_pMenuSkin;
	}
}

void COXMenuBar::RecalculateItemWidths()
{
	// Go though all the buttons and determine their widths
	CToolBarCtrl& ctrl = GetToolBarCtrl();
	int iCount = ctrl.GetButtonCount();
	int iMaxTextLength = 0;
	int i = 0;
	for (i = 0; i < iCount; i++)
	{
		CString strText = GetItemText(i);
		if (strText.IsEmpty())
			continue;

		// Determine the length of the text
		CDC* pDC = GetDC();
		CRect rectText(0, 0, 0, 0);
		CFont* pOldFont = pDC->SelectObject(GetFont());
		pDC->DrawText(strText, rectText, DT_CALCRECT);
		pDC->SelectObject(pOldFont);
		ReleaseDC(pDC);

		if (rectText.right + 8 > iMaxTextLength)
			iMaxTextLength = rectText.right + 8;

		if (m_dwStyle & CBRS_ORIENT_HORZ)
		{
			// Horizontal
			TBBUTTONINFO tbi;
			tbi.cbSize = sizeof(TBBUTTONINFO);
			tbi.dwMask = TBIF_SIZE;
			tbi.cx = (BYTE) (rectText.right + GetMenuSkin()->GetDimentionConstants().m_nGapMenuItems);

			ctrl.SetButtonInfo(GetItemID(i), &tbi);
		}
	}

	// If we have a vertical menubar make the items as wide as the widest item
	if ((m_dwStyle & CBRS_ORIENT_HORZ) == 0)
	{
		for (i = 0; i < iCount; i++)
		{
			TBBUTTONINFO tbi;
			tbi.cbSize = sizeof(TBBUTTONINFO);
			tbi.dwMask = TBIF_SIZE;
			tbi.cx = (WORD) iMaxTextLength;

			ctrl.SetButtonInfo(GetItemID(i), &tbi);
		}
	}
}

void COXShadowedItemWnd::OnPaint() 
{
	COXBitmapMenu::GetMenuSkin()->OnPaintShadowedItemWnd(this);
}

void COXMenuBar::GetItemRect(int nIndex, LPRECT lpRect)
{
	// Handle the system menu case, otherwise call the default implementation
	bool bSysMenu = (nIndex == (int) ::GetMenuItemCount(m_hMenu));
	if (bSysMenu)
	{
		CRect rectWindow;
		GetWindowRect(rectWindow);
		ScreenToClient(&rectWindow);

		CRect rectClient;
		GetClientRect(rectClient);
		
		lpRect->left = m_iconRect.left;
		lpRect->top = m_iconRect.top;
		lpRect->right = m_iconRect.right;
		lpRect->bottom = m_iconRect.bottom;

		// Offset the rectangle
		lpRect->left += rectWindow.left - rectClient.left;
		lpRect->right += rectWindow.left - rectClient.left;
		lpRect->top += rectWindow.top - rectClient.top;
		lpRect->bottom += rectWindow.top - rectClient.top;
	}
	else
		COXCoolToolBar::GetItemRect(nIndex, lpRect);
}

CSize COXMenuBar::CalcSize(TBBUTTON *pData, int nCount)
{
	CSize size = COXCoolToolBar::CalcSize(pData, nCount);

	// If the menu bar if horizontally docked make it as wide as the frame, so that it would
	// wrap and become multiline
	if (!IsFloating())
	{
		CFrameWnd* pDockingFrame = GetDockingFrame();
		CRect rectClient;
		pDockingFrame->GetClientRect(rectClient);
		
		int iFrameWidth;
		if (m_rectCloseBtn.IsRectEmpty())
			iFrameWidth = rectClient.right;
		else
			iFrameWidth = rectClient.right - m_rectCloseBtn.Width() - m_rectMinimizeBtn.Width()
				- m_rectRestoreBtn.Width() - m_iconRect.Width() - 14;

		if (iFrameWidth < size.cx)
			size.cx = iFrameWidth;
	}

	return size;
}

void COXMenuBar::OnSize(UINT nType, int cx, int cy) 
{
	COXCoolToolBar::OnSize(nType, cx, cy);
	
	if (!IsFloating() && IsWindowVisible())
	{
		m_bDelayedButtonLayout = TRUE;
		Layout();
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions