Click here to Skip to main content
15,884,388 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.7K   23.6K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
// ==========================================================================
//				Class Implementation : COXBitmapMenuOrganizer
// ==========================================================================

// 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 "OXBitmapMenuOrganizer.h"

#include "afxpriv.h"
#include "afxole.h"

#ifndef __OXMFCIMPL_H__
#if _MFC_VER >= 0x0700
#if _MFC_VER >= 1400
#include <afxtempl.h>
#endif
#include <..\src\mfc\afximpl.h>
#else
#include <..\src\afximpl.h>
#endif
#define __OXMFCIMPL_H__
#endif


#ifndef __OX_OLEIMPL2_H__
#ifdef MAP_LOGHIM_TO_PIX
#undef MAP_LOGHIM_TO_PIX
#endif
#ifdef MAP_PIX_TO_LOGHIM
#undef MAP_PIX_TO_LOGHIM
#endif

#if _MFC_VER < 0x0700
	#include <..\src\oleimpl2.h>
#else
	#include <..\src\mfc\oleimpl2.h>
#endif

#define __OX_OLEIMPL2_H__
#endif

#include "UTB64Bit.h"

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

#ifndef TB_GETIMAGELIST
#define TB_GETIMAGELIST			(WM_USER + 49)
#endif // TB_GETIMAGELIST

#ifndef TB_GETHOTIMAGELIST
#define TB_GETHOTIMAGELIST		(WM_USER + 53)
#endif // TB_GETHOTIMAGELIST

/////////////////////////////////////////////////////////////////////////////
// Definition of static members

// --- A map of all the frame windows that have been subclassed and that are associated with
//     a menu organizer object.  This object will handle the windows messages first
CMap<HWND, HWND, COXBitmapMenuOrganizer*, COXBitmapMenuOrganizer*> 
COXBitmapMenuOrganizer::m_allMenuOrganizers;

// handle of the old mouse hook procedure
HHOOK COXBitmapMenuOrganizer::g_pfnOldMouseHookProc=NULL;
// handle of the old keyboard hook procedure
HHOOK COXBitmapMenuOrganizer::g_pfnOldKeyboardHookProc=NULL;
///////////////////////////////////////////



// Member functions ---------------------------------------------------------
// public:

COXBitmapMenuOrganizer::COXBitmapMenuOrganizer()
	:
	m_pFrameWnd(NULL),
	m_hWnd(NULL),
	m_pfnSuper(NULL),
	m_bInCutomizationMode(FALSE),
	m_hWndCustomizeOrganizer(NULL),
	m_bShowOnlyRecentlyUsed(TRUE),
	m_bForceToDisplayHiddenItems(FALSE),
	m_bMainMenuIsActive(FALSE),
	m_nActivePopupMenuCount(0),
	m_pDeferedBM(NULL)
{
	Init();
}

BOOL COXBitmapMenuOrganizer::Init(UINT cx, UINT cy, UINT nCheckID, UINT nBulletID)
{
	CDC memDC;
	VERIFY(memDC.CreateCompatibleDC(NULL));

	CRect rcCheckMark;
	ASSERT((!cx && !cy) || (cx && cy));
	if(!cx && !cy)
	{
		rcCheckMark=CRect(0,0,
			::GetSystemMetrics(SM_CXMENUCHECK),::GetSystemMetrics(SM_CYMENUCHECK));
		// Convert from device to logical points
		memDC.DPtoLP(&rcCheckMark);	
	}
	else
	{
		rcCheckMark=CRect(0, 0, cx, cy);
	}
	
	if(m_DefaultImgList.m_hImageList!=NULL)
	{
		m_DefaultImgList.DeleteImageList();
	}
	// The default image list will contain a checkmark and a bulletmark
	VERIFY(m_DefaultImgList.Create(rcCheckMark.right,rcCheckMark.bottom,TRUE,2,0)); 

	CBitmap bmTemp;
	VERIFY(bmTemp.CreateCompatibleBitmap(&memDC,rcCheckMark.right,rcCheckMark.bottom));
	
	// Create a checkmark bitmap
	
	ASSERT((nCheckID==NULL && nBulletID==NULL) || (nCheckID!=NULL && nCheckID!=NULL));

	CBitmap* pbmTempOld;
	if(!nCheckID)
	{
		pbmTempOld=memDC.SelectObject(&bmTemp);
		memDC.DrawFrameControl(&rcCheckMark, DFC_MENU, DFCS_MENUCHECK);
		memDC.SelectObject(pbmTempOld);
		m_DefaultImgList.Add(&bmTemp, RGB(255,255,255));
	}
	else
	{
		CBitmap bmp;
		VERIFY(bmp.LoadBitmap(nCheckID));
		m_DefaultImgList.Add(&bmp,  RGB(255,255,255));
	}

	// Create a bulletmark bitmap
	if(!nBulletID)
	{
		pbmTempOld=memDC.SelectObject(&bmTemp);
		memDC.DrawFrameControl(&rcCheckMark, DFC_MENU, DFCS_MENUBULLET);
		memDC.SelectObject(pbmTempOld);
		m_DefaultImgList.Add(&bmTemp, RGB(255,255,255));
	}
	else
	{
		CBitmap bmp;
		VERIFY(bmp.LoadBitmap(nBulletID));
		m_DefaultImgList.Add(&bmp,  RGB(255,255,255));
	}

	// Clean up
	memDC.DeleteDC();

	return TRUE;
}

void COXBitmapMenuOrganizer::Empty(BOOL bCopyText/*=TRUE*/)
{
	CString sKey;
	CImageList* pImageList;
	POSITION pos=m_mapStringToImageList.GetStartPosition();
	// Remove all the elements from m_mapStringToImageList and deletes them
	while(pos!=NULL)
	{
		m_mapStringToImageList.GetNextAssoc(pos,sKey,pImageList);
		if(pImageList!=&m_DefaultImgList)
		{
			delete pImageList;
			pImageList = NULL;
		}
	}
	m_mapStringToImageList.RemoveAll();

	DWORD wKey;
	COXImageInfo* pImageInfo;
	pos=m_mapCommandToImageInfo.GetStartPosition();
	// Remove all the elements from m_mapCommandToImageInfo
	while(pos != NULL)
	{
		m_mapCommandToImageInfo.GetNextAssoc(pos,wKey,pImageInfo);
		delete pImageInfo;
		pImageInfo = NULL;
	}
	m_mapCommandToImageInfo.RemoveAll();

	// Deletes all the instantiated COXBitmapMenus
	while(!m_BitmapMenuList.IsEmpty())
	{

		COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.RemoveHead();
		//TRACE(_T("\nEmpty: Found bitmapmenu %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__);
		RestoreBitmapMenu(pBitmapMenu,bCopyText);

		//delete pBitmapMenu;
	}
}

COXBitmapMenuOrganizer::~COXBitmapMenuOrganizer()
{
	Empty(FALSE);

	// delete deferred from RestoreBitmapMenu - 9.3 patch
	if(m_pDeferedBM != NULL) {
		delete m_pDeferedBM;
	}

	// ... Detach a possible attached frame window
	DetachFrameWnd();

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

	ASSERT(g_pfnOldMouseHookProc==NULL);
	ASSERT(g_pfnOldKeyboardHookProc==NULL);

}

BOOL COXBitmapMenuOrganizer::AttachFrameWnd(CFrameWnd* pFrameWnd)
{
	if((m_pFrameWnd==NULL) && (pFrameWnd != NULL))
	{
		m_pFrameWnd=pFrameWnd;
		VERIFY(SubclassFrameWindow(pFrameWnd));
		return TRUE;
	}
	else
	{
		TRACE0("COXBitmapMenuOrganizer::AttachFrameWnd : Failed because already attached or frame wnd is NULL\n");
		return FALSE;
	}
}

CFrameWnd* COXBitmapMenuOrganizer::DetachFrameWnd()
{
	CFrameWnd* pFrameWnd=m_pFrameWnd;
	if(pFrameWnd != NULL)
	{
		UnsubclassFrameWindow();
	}
	m_pFrameWnd=NULL;
	Empty();
	return pFrameWnd;
}

BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, LPCTSTR pszBitmapID, 
										  int nBitmapIndex, int nCx)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	CString sUResourse=GetUniqueResourceString(pszBitmapID);
	CImageList* pImageList;
	//Doesn't add if already the resource is asociated with a ImageList
	if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
	{
		pImageList=new CImageList;
		m_mapStringToImageList[sUResourse]=pImageList;
	}
	else
	{
		VERIFY(pImageList->DeleteImageList());
	}
	pImageList->Create(pszBitmapID,nCx,0,RGB(192,192,192)); 
	ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		pImageInfo=new COXImageInfo(pImageList,nBitmapIndex);
		m_mapCommandToImageInfo[nCommandID]=pImageInfo;
	}
	else
	{
		pImageInfo->SetImageList(pImageList);
	}
	return TRUE;
}


BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, HICON hIcon, 
										  int nCx, int nCy)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	CString sUResourse=GetUniqueResourceString((UINT_PTR)hIcon);
	CImageList* pImageList;
	//Doesn't add if already the resource is asociated with a ImageList
	if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
	{
		pImageList=new CImageList;
		m_mapStringToImageList[sUResourse]=pImageList;
	}
	else
	{
		VERIFY(pImageList->DeleteImageList());
	}
	VERIFY(pImageList->Create(nCx,nCy,ILC_COLOR24|ILC_MASK,0,0)); 
	VERIFY(pImageList->Add(hIcon)!=-1);
	ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		pImageInfo=new COXImageInfo(pImageList,0);
		m_mapCommandToImageInfo[nCommandID]=pImageInfo;
	}
	else
	{
		pImageInfo->SetImageList(pImageList);
	}

	return TRUE;
}


BOOL COXBitmapMenuOrganizer::SetMenuImage(UINT nCommandID, CBitmap* pbmImage, 
										  COLORREF crMask, int nCx, int nCy)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::SetMenuImage : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	CString sUResourse=GetUniqueResourceString((UINT_PTR)pbmImage);
	CImageList* pImageList;
	//Doesn't add if already the resource is asociated with a ImageList
	if(!m_mapStringToImageList.Lookup(sUResourse,pImageList))
	{
		pImageList=new CImageList;
		m_mapStringToImageList[sUResourse]=pImageList;
	}
	else
	{
		VERIFY(pImageList->DeleteImageList());
	}
	VERIFY(pImageList->Create(nCx,nCy,ILC_COLOR24|ILC_MASK,0,0)); 
	VERIFY(pImageList->Add(pbmImage,crMask)!=-1);
	ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		pImageInfo=new COXImageInfo(pImageList,0);
		m_mapCommandToImageInfo[nCommandID]=pImageInfo;
	}
	else
	{
		pImageInfo->SetImageList(pImageList);
	}

	return TRUE;
}


BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, LPCTSTR pszBitmapID, 
											 int nBitmapIndex, int nCx)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
		return FALSE;
	}

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
		return FALSE;
	}
	ASSERT(pImageInfo!=NULL);
	CImageList* pExistingImageList=pImageInfo->GetImageList();
	ASSERT(pExistingImageList!=NULL);

	CImageList imageList;
	if(!imageList.Create(pszBitmapID,nCx,0,RGB(192,192,192)))
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to load the bitmap\n"));
		return FALSE;
	}
	ASSERT((HIMAGELIST)imageList!=NULL);

	HICON hIcon=imageList.ExtractIcon(nBitmapIndex);
	ASSERT(hIcon!=NULL);

	int nIndex=pExistingImageList->Add(hIcon);
	VERIFY(::DestroyIcon(hIcon));
	if(nIndex==-1)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
		return FALSE;
	}

	pImageInfo->SetHotIndex(nIndex);

	return TRUE;
}


BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, HICON hIcon)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
		return FALSE;
	}

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
		return FALSE;
	}
	ASSERT(pImageInfo!=NULL);
	CImageList* pExistingImageList=pImageInfo->GetImageList();
	ASSERT(pExistingImageList!=NULL);

	ASSERT(hIcon!=NULL);

	int nIndex=pExistingImageList->Add(hIcon);
	if(nIndex==-1)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
		return FALSE;
	}

	pImageInfo->SetHotIndex(nIndex);

	return TRUE;
}


BOOL COXBitmapMenuOrganizer::SetMenuHotImage(UINT nCommandID, CBitmap* pbmImage, 
											 COLORREF crMask)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : Must attach a frame window before calling this function\n"));
		return FALSE;
	}

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : normal image must be set for the item before calling this function\n"));
		return FALSE;
	}
	ASSERT(pImageInfo!=NULL);
	CImageList* pExistingImageList=pImageInfo->GetImageList();
	ASSERT(pExistingImageList!=NULL);

	ASSERT(pbmImage!=NULL);

	int nIndex=pExistingImageList->Add(pbmImage,crMask);
	if(nIndex==-1)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotImage : failed to add bitmap to menu item's image list\n"));
		return FALSE;
	}

	pImageInfo->SetHotIndex(nIndex);

	return TRUE;
}



BOOL COXBitmapMenuOrganizer::SetMenuBitmap(UINT nCommandID, LPCTSTR pszBitmapID)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::SetMenuBitmap : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	CBitmap Bitmap;
	//to get the width of the bitmap
	if(!Bitmap.LoadBitmap(pszBitmapID)) 
		return FALSE;
	BITMAP BitmapInfo;
	Bitmap.GetBitmap(&BitmapInfo);
	Bitmap.DeleteObject();
	return SetMenuImage(nCommandID, pszBitmapID, 0, BitmapInfo.bmWidth);
}

BOOL COXBitmapMenuOrganizer::SetMenuBitmap(UINT nCommandID, UINT nBitmapID)
{
	return SetMenuBitmap(nCommandID,MAKEINTRESOURCE(nBitmapID));
}

BOOL COXBitmapMenuOrganizer::SetMenuHotBitmap(UINT nCommandID, LPCTSTR pszBitmapID)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::SetMenuBitmap : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	CBitmap Bitmap;
	//to get the width of the bitmap
	if(!Bitmap.LoadBitmap(pszBitmapID)) 
		return FALSE;
	BITMAP BitmapInfo;
	Bitmap.GetBitmap(&BitmapInfo);
	Bitmap.DeleteObject();
	return SetMenuHotImage(nCommandID, pszBitmapID, 0, BitmapInfo.bmWidth);
}

BOOL COXBitmapMenuOrganizer::SetMenuHotBitmap(UINT nCommandID, UINT nBitmapID)
{
	return SetMenuHotBitmap(nCommandID,MAKEINTRESOURCE(nBitmapID));
}

BOOL COXBitmapMenuOrganizer::SetMenuIcon(UINT nCommandID, LPCTSTR pszIconID)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuIcon : Must attach a frame window before calling this function\n"));
		return FALSE;
	}

	HICON hIcon;
	//Loads Icon
	hIcon=AfxGetApp()->LoadIcon(pszIconID);
	if(hIcon==NULL)
		return FALSE;
		
	CImageList* pImageList;
	CString sUResource=GetUniqueResourceString(pszIconID,FALSE);
	//if the Icon resource is not already added
	if(!m_mapStringToImageList.Lookup(sUResource,pImageList))
	{
		pImageList=new CImageList;
		//To differentiate between Icon and bitmap add "Icon" at the end
		m_mapStringToImageList[sUResource]=pImageList;
	}
	else
	{
		VERIFY(pImageList->DeleteImageList());
	}
	VERIFY(pImageList->Create(GetSystemMetrics(SM_CXICON),
		GetSystemMetrics(SM_CYICON),FALSE,1,0)); 
	VERIFY(pImageList->Add(hIcon)!=-1);
	ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		pImageInfo=new COXImageInfo(pImageList,0);
		m_mapCommandToImageInfo[nCommandID]=pImageInfo;
	}
	else
	{
		pImageInfo->SetImageList(pImageList);
	}

	return TRUE;
}
	
BOOL COXBitmapMenuOrganizer::SetMenuIcon(UINT nCommandID, UINT nIconID)
{
	return SetMenuIcon(nCommandID,MAKEINTRESOURCE(nIconID));
}

BOOL COXBitmapMenuOrganizer::SetMenuHotIcon(UINT nCommandID, LPCTSTR pszIconID)
{
	if(m_pFrameWnd==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : Must attach a frame window before calling this function\n"));
		return FALSE;
	}

	COXImageInfo* pImageInfo=NULL;
	if(!m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo))
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : normal image must be set for the item before calling this function\n"));
		return FALSE;
	}
	ASSERT(pImageInfo!=NULL);
	CImageList* pExistingImageList=pImageInfo->GetImageList();
	ASSERT(pExistingImageList!=NULL);

	HICON hIcon;
	//Loads Icon
	hIcon=AfxGetApp()->LoadIcon(pszIconID);
	if(hIcon==NULL)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : failed to load the icon\n"));
		return FALSE;
	}
		
	int nIndex=pExistingImageList->Add(hIcon);
	if(nIndex==-1)
	{
		TRACE(_T("COXBitmapMenuOrganizer::SetMenuHotIcon : failed to add the icon to menu item's image list\n"));
		return FALSE;
	}

	pImageInfo->SetHotIndex(nIndex);

	return TRUE;
}
	

BOOL COXBitmapMenuOrganizer::SetMenuHotIcon(UINT nCommandID, UINT nIconID)
{
	return SetMenuHotIcon(nCommandID,MAKEINTRESOURCE(nIconID));
}


COXImageInfo* COXBitmapMenuOrganizer::GetMenuItemImageInfo(UINT nCommandID) const
{
	COXImageInfo* pImageInfo=NULL;
	m_mapCommandToImageInfo.Lookup(nCommandID,pImageInfo);
	return pImageInfo;
}


BOOL COXBitmapMenuOrganizer::AutoSetMenuImage()
{
	if(m_pFrameWnd==NULL)
	{
		TRACE0("COXBitmapMenuOrganizer::AutoSetMenuImage : Must attach a frame window before calling this function\n");
		return FALSE;
	}

	// Empty previous settings
	Empty();

	CToolBar* pToolBar=NULL;
	UINT nID=0;
	UINT nStyle=0;
	int iImage=0;
	int iHotImage=0;

	int nListIndex=0;
	CString sListIndex;
	// Iterate all the control bars and use only the toolbars
	POSITION pos=m_pFrameWnd->m_listControlBars.GetHeadPosition();
	while (pos != NULL)
	{
		pToolBar=DYNAMIC_DOWNCAST(CToolBar, 
			(CControlBar*)m_pFrameWnd->m_listControlBars.GetNext(pos));
		//If its a CToolBar
		if(pToolBar!=NULL)
		{
			// Get the original imagelist of the toolbar
			HIMAGELIST hOrigImageList=
				(HIMAGELIST)pToolBar->SendMessage(TB_GETIMAGELIST);
			if(hOrigImageList!=NULL)
			{
				CImageList origImageList;
				CImageList* pOrigImageList=
					CImageList::FromHandlePermanent(hOrigImageList);
				if(pOrigImageList==NULL)
				{
					VERIFY(origImageList.Attach(hOrigImageList));
					pOrigImageList=&origImageList;
				}
				ASSERT(pOrigImageList!=NULL);

				int nOrigImageCount=pOrigImageList->GetImageCount();
				ASSERT(0<nOrigImageCount);

				// Get the hot imagelist of the toolbar
				HIMAGELIST hHotImageList=
					(HIMAGELIST)pToolBar->SendMessage(TB_GETHOTIMAGELIST);
				CImageList hotImageList;
				CImageList* pHotImageList=NULL;
				int nHotImageCount=0;
				if(hHotImageList!=NULL)
				{
					pHotImageList=CImageList::FromHandlePermanent(hHotImageList);
					if(pHotImageList==NULL)
					{
						VERIFY(hotImageList.Attach(hHotImageList));
						pHotImageList=&hotImageList;
					}
					ASSERT(pHotImageList!=NULL);
					nHotImageCount=pHotImageList->GetImageCount();
					ASSERT(nHotImageCount==nOrigImageCount);
				}

				CImageList* pNewImageList=new CImageList;
				CRect buttonRect;
				pToolBar->GetItemRect(0, buttonRect);

				int nButtonIndex=0;
#if _MFC_VER > 0x0421
				VERIFY(pNewImageList->Create(pOrigImageList));
#else
				IMAGEINFO imageInfo;
				VERIFY(pOrigImageList->GetImageInfo(0,&imageInfo));
				VERIFY(pNewImageList->Create(imageInfo.rcImage.right-imageInfo.rcImage.left,
					imageInfo.rcImage.bottom-imageInfo.rcImage.top,
					ILC_COLOR24|ILC_MASK,0,0));
				for(nButtonIndex=0; nButtonIndex<nOrigImageCount; nButtonIndex++)
				{
					HICON hIcon=pOrigImageList->ExtractIcon(nButtonIndex);
					ASSERT(hIcon!=NULL);
					VERIFY(pNewImageList->Add(hIcon)!=-1);
					VERIFY(::DestroyIcon(hIcon));
				}
#endif
				for(nButtonIndex=0; nButtonIndex<nHotImageCount; nButtonIndex++)
				{
					HICON hIcon=pHotImageList->ExtractIcon(nButtonIndex);
					ASSERT(hIcon!=NULL);
					VERIFY(pNewImageList->Add(hIcon)!=-1);
					VERIFY(::DestroyIcon(hIcon));
				}

				ASSERT(pNewImageList->GetImageCount()==nHotImageCount+nOrigImageCount);

				// Close everything
				if((HIMAGELIST)hotImageList!=NULL)
					hotImageList.Detach();
				if((HIMAGELIST)origImageList!=NULL)
					origImageList.Detach();

				nListIndex++;
				sListIndex.Format(_T("%i"), nListIndex);
				m_mapStringToImageList[sListIndex]=pNewImageList;

				int nButtonCount=pToolBar->GetToolBarCtrl().GetButtonCount();
				// Iterate all buttons on the toolbar
				for(nButtonIndex=0; nButtonIndex < nButtonCount; nButtonIndex++)
				{
					nID=0;
					nStyle=0;
					iImage=0;
					iHotImage=-1;
					pToolBar->GetButtonInfo(nButtonIndex, nID, nStyle, iImage);
					if(nHotImageCount>0)
					{
						iHotImage=iImage+nOrigImageCount;
					}
					//If the Item is not a button
					if(nStyle&TBBS_SEPARATOR)
						continue;

					//Sets the mapping
					COXImageInfo* pImageInfo=NULL;
					if(!m_mapCommandToImageInfo.Lookup(nID,pImageInfo))
					{
						pImageInfo=new COXImageInfo(
							pNewImageList,iImage,FALSE,iHotImage);
						// ... Set new value
						m_mapCommandToImageInfo[nID]=pImageInfo;
					}
					else
					{
						ASSERT(pImageInfo!=NULL);
						pImageInfo->SetImageList(pNewImageList);
						pImageInfo->SetIndex(iImage);
						pImageInfo->SetHotIndex(iHotImage);
						pImageInfo->SetDefaultImgList(FALSE);
					}
				}
			}
		}
	}

	return TRUE;
}

void COXBitmapMenuOrganizer::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, 
											 BOOL bSysMenu)
{
	ASSERT(pPopupMenu->GetSafeHmenu()!=NULL);	

	// Replace the attached CMenu by a new COXBitmapMenu object
	// if necessary (if not done yet)
	CMenu* pMenu=pPopupMenu;

	COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu, pMenu);
	//If a COXBitmapMenu is not already attached to the SubMenu
	BOOL bNewBitmapMenu=FALSE;
	if(pBitmapMenu==NULL)
	{
		pBitmapMenu=new COXBitmapMenu();
		
		// Detaches the CMenu
		HMENU hMenu=pMenu->Detach();
		
		//Attaches the COXBitmapMenu object to the menu handle
		pBitmapMenu->Attach(hMenu);
		m_BitmapMenuList.AddTail(pBitmapMenu);
		pPopupMenu=pBitmapMenu;

		bNewBitmapMenu=TRUE;
	}

#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
	BOOL bUpdateCmdUI=TRUE;
	if(m_pFrameWnd->m_pNotifyHook!=NULL)
	{
		if(m_pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
		{
			bUpdateCmdUI=FALSE;
		}
	}
	if(bUpdateCmdUI)
	{
#endif	//	_AFX_NO_OLE_SUPPORT
#endif	//	_MFC_VER>0x0421

		// Before we begin iterating the menuitems to make them ownerdrawn, be sure
		// the CmdUI mechanism doesn't want to add or change some menuitems 
		// (E.g. MRU list)
		pBitmapMenu->OnUpdateCmdUI(CWnd::FromHandle(m_hWnd), nIndex, bSysMenu);

#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
	}
#endif	//	_AFX_NO_OLE_SUPPORT
#endif	//	_MFC_VER>0x0421

	
	ConvertBitmapMenu(pBitmapMenu,bNewBitmapMenu);

	pBitmapMenu->
		SetCutomizationMode(IsInCustomizationMode(),m_hWndCustomizeOrganizer);
}


LRESULT COXBitmapMenuOrganizer::OnMenuChar(UINT nChar, UINT /* nFlags */, 
										   CMenu* pMenu)
{
	//to check wether its a COXBitmapMenu
	COXBitmapMenu* pBitmapMenu=DYNAMIC_DOWNCAST(COXBitmapMenu, pMenu);
	int nLoWord =0;
	int nHiWord =0;
	//if its a COXBitmapMenu
	if(pBitmapMenu != NULL)
	{
		int nIndex=0;
		//sets the index of the menu item for the corresponding char
		if(pBitmapMenu->m_KeyAccessMap.Lookup((TCHAR)nChar,nIndex))
		{
			nHiWord=2;
			nLoWord=nIndex;
		}
	}
	return MAKELRESULT(nLoWord,nHiWord);
}

// Measure item implementation relies on unique control/menu IDs
BOOL COXBitmapMenuOrganizer::OnMeasureItem(int /*nIDCtl*/, 
										   LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	// ... Handle the cases we can handle
	BOOL bHandled=TRUE;
	CWnd* pWnd=CWnd::FromHandle(m_hWnd);
	ASSERT(pWnd != NULL);
	if(lpMeasureItemStruct->CtlType==ODT_MENU)
	{
		ASSERT(lpMeasureItemStruct->CtlID==0);
		CMenu* pMenu;

		_AFX_THREAD_STATE* pThreadState=AfxGetThreadState();
		if(pThreadState->m_hTrackingWindow==m_hWnd)
		{
			// start from popup
			pMenu=CMenu::FromHandle(pThreadState->m_hTrackingMenu);
		}
		else
		{
			// start from menubar
			pMenu=pWnd->GetMenu();
		}

		pMenu=OwnFindPopupMenuFromID(pMenu, lpMeasureItemStruct->itemID);
		if(pMenu==NULL)
		{
			if(m_arrPopupMenusTrace.GetSize()>0 && m_nActivePopupMenuCount>0)
			{
				OXPOPUPMENUTRACE popupMenu=
					m_arrPopupMenusTrace[m_nActivePopupMenuCount-1];
				pMenu=CMenu::FromHandlePermanent(popupMenu.m_hPopupMenu);
			}
		}
		if(pMenu!=NULL)
		{
			pMenu->MeasureItem(lpMeasureItemStruct);
		}
		else
		{
			TRACE0("COXBitmapMenuOrganizer::OnMeasureItem: Unknown Menu : passing to Default()\n");
			bHandled=FALSE;
		}
	}
	else
	{
		CWnd* pChild=pWnd->GetDescendantWindow(lpMeasureItemStruct->CtlID, TRUE);
		if(pChild != NULL && pChild->SendChildNotifyLastMsg())
			return bHandled;     // eaten by child
	}
	return bHandled;
}

CString COXBitmapMenuOrganizer::GetUniqueResourceString(UINT_PTR uResourceID,
														BOOL bBitmapIcon)
{
	CString sRet;
	CString sNum;
	sNum.Format(_T("%u"), uResourceID);
	sNum.ReleaseBuffer();
	sRet=CString((TCHAR)CHAR_MAX)+sNum+ 
		CString(bBitmapIcon ? (TCHAR)CHAR_MAX : (TCHAR)CHAR_MIN);
	return sRet;
}

CString COXBitmapMenuOrganizer::GetUniqueResourceString(LPCTSTR pszResource,
														BOOL bBitmapIcon)
{
	if(HIWORD((DWORD_PTR)pszResource)==0)
	{
		return GetUniqueResourceString(LOWORD((DWORD_PTR)pszResource),bBitmapIcon);
	}
	else
		return CString(pszResource)+
			CString(bBitmapIcon ? (TCHAR)CHAR_MAX : (TCHAR)CHAR_MIN);
}

BOOL COXBitmapMenuOrganizer::SubclassFrameWindow(CFrameWnd* pFrameWnd)
	// --- In  : pFrameWnd : The frame  window 
	// --- Out : 
	// --- Returns : Whether it was successful or not
	// --- Effect : This function subclasses the frame window 
{
	ASSERT(pFrameWnd != NULL);
	ASSERT(pFrameWnd->GetSafeHwnd() != NULL);
	ASSERT_VALID(pFrameWnd);

	if(m_pfnSuper != NULL)
	{
		// Already subclasses, check that hWnd and window proc is correct
		if((m_hWnd != pFrameWnd->GetSafeHwnd()) || 
		     ((WNDPROC)::GetWindowLongPtr(pFrameWnd->GetSafeHwnd(),GWL_WNDPROC)!= 
			 GlobalMenuOrganizerProc))
		{
			TRACE0("COXBitmapMenuOrganizer::SubclassFrameWindow : Failed because already subclassed by other window proc\n");
			return FALSE;
		}
		return TRUE;
	}

	ASSERT(m_hWnd==NULL);
	ASSERT(m_pfnSuper==NULL);
#ifdef _DEBUG
	COXBitmapMenuOrganizer* pDummyLayoutManager=NULL;
	// ... Should not yet be in list of subclassed frame windows
	ASSERT(!m_allMenuOrganizers.Lookup(m_hWnd, pDummyLayoutManager));
#endif // _DEBUG

	// ... Subclass window (Windows way, not MFC : because may already be subclessed by MFC)
	m_hWnd=pFrameWnd->GetSafeHwnd();
	m_pfnSuper=(WNDPROC)::GetWindowLongPtr(pFrameWnd->GetSafeHwnd(), GWL_WNDPROC);
	::SetWindowLongPtr(m_hWnd, GWL_WNDPROC, (LONG_PTR)GlobalMenuOrganizerProc);

	// ... Store in the global map
	m_allMenuOrganizers.SetAt(m_hWnd, this);

	ASSERT_VALID(this);
	return (m_hWnd != NULL);;
}

void COXBitmapMenuOrganizer::UnsubclassFrameWindow()
	// --- In  : 
	// --- Out : 
	// --- Returns : 
	// --- Effect : This function unsubclasses the window 
	//				It removes this object from the map
	//				When it is the last in the list it restores the original
	//				windows procedure
{
	ASSERT_VALID(this);

	if(m_hWnd != NULL)
	{
		// Put back original window procedure
		ASSERT(m_pfnSuper != NULL);
		ASSERT(m_pfnSuper != GlobalMenuOrganizerProc);
		// ... GlobalLayoutManagerProc is not used anymore : set WNDPROC back to original value
		::SetWindowLongPtr(m_hWnd, GWL_WNDPROC, (LONG_PTR)m_pfnSuper);
		// ... Remove use from global map
		m_allMenuOrganizers.RemoveKey(m_hWnd);
		m_hWnd=NULL;
		m_pfnSuper=NULL;
	}

	ASSERT(m_hWnd==NULL);
	ASSERT(m_pfnSuper==NULL);

	ASSERT_VALID(this);
}

LRESULT CALLBACK COXBitmapMenuOrganizer::GlobalMenuOrganizerProc(HWND hWnd, 
																 UINT uMsg, 
																 WPARAM wParam, 
																 LPARAM lParam)
	// --- In  : hWnd : 
	//			 uMsg : 
	//			 wParam : 
	//			 lParam :
	// --- Out : 
	// --- Returns : The result of the message
	// --- Effect : This is the global windows procedure of all the menu organizers
	//              objects that have subclasses a window
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif

	COXBitmapMenuOrganizer* pBitmapMenuOrganizer=NULL;

	VERIFY(m_allMenuOrganizers.Lookup(hWnd, pBitmapMenuOrganizer));
	ASSERT_VALID(pBitmapMenuOrganizer);
	return pBitmapMenuOrganizer->MenuOrganizerProc(hWnd, uMsg, wParam, lParam);
}


LRESULT COXBitmapMenuOrganizer::MenuOrganizerProc(HWND hWnd, UINT uMsg, 
												  WPARAM wParam, LPARAM lParam)
	// --- In  : hWnd : 
	//			 uMsg : 
	//			 wParam : 
	//			 lParam :
	// --- Out : 
	// --- Returns: The result of the message
	// --- Effect : This is the member function called by the windows procedure of the 
	//				COXBitmapMenuOrganizer object
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif

	ASSERT_VALID(this);
	ASSERT(hWnd==m_hWnd);

	// Handling before base class
	BOOL bHandled=FALSE;
	LRESULT result=0;

	// Let the original message procedure handle it first of all
	ASSERT(m_pfnSuper != NULL);
	ASSERT(m_pfnSuper != GlobalMenuOrganizerProc);
	if(uMsg!=WM_MEASUREITEM)
	{
		result=CallWindowProc(m_pfnSuper,hWnd, uMsg, wParam, lParam);
	}

	if(!::IsWindow(hWnd))
	{
		return result;
	}

	switch (uMsg)
	{
	case WM_MENUCHAR:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MENUCHAR\n"));
		{
			CMenu* pMenu=CMenu::FromHandle((HMENU)lParam);
			int nChar=towlower(LOWORD(wParam));
			int nFlags=HIWORD(wParam);
			result=OnMenuChar(nChar, nFlags, pMenu);
			bHandled=TRUE;
			break;
		}
	
	case WM_INITMENUPOPUP:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_INITMENUPOPUP\n"));
		{
			CMenu* pPopupMenu=CMenu::FromHandle((HMENU)wParam);
			UINT nIndex=(UINT) LOWORD(lParam); 
			BOOL bSysMenu=(BOOL) HIWORD(lParam);

			UpdateActivePopupMenuCount();
			int nTraceSize=PtrToInt(m_arrPopupMenusTrace.GetSize());
			if(nTraceSize>m_nActivePopupMenuCount)
			{
				for(int nMenuIndex=nTraceSize-1; 
					nMenuIndex>=m_nActivePopupMenuCount; 
					nMenuIndex--)
				{
					// update map of all popup menu windows
					if(nMenuIndex==m_nActivePopupMenuCount)
					{
						// reuse window object
						HWND hPopupMenuWnd=NULL;
						if(m_mapPopupMenuWindows.Lookup(
							m_arrPopupMenusTrace[nMenuIndex].m_hPopupMenu,
							hPopupMenuWnd))
						{
							m_mapPopupMenuWindows.SetAt((HMENU)wParam,hPopupMenuWnd);
						}
					}
					m_mapPopupMenuWindows.RemoveKey(
						m_arrPopupMenusTrace[nMenuIndex].m_hPopupMenu);

					m_arrPopupMenusTrace.RemoveAt(nMenuIndex);
				}
			}
			m_nActivePopupMenuCount++;

			// Don't make system menu's owner-drawn.  We can't retrieve them
			// in OnMeasureitem.
			if(bSysMenu)
			{
				TRACE(_T("\nCOXBitmapMenuOrganizer::MenuOrganizerProc: System Menu skipping Ownerdraw\n"));
				bHandled=FALSE;
				break;
			}

			OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

			OXPOPUPMENUTRACE pmt;
			pmt.m_hPopupMenu=(HMENU)wParam;
			m_arrPopupMenusTrace.Add(pmt);
			////////////////////////////////

			// the default msg proc further only deals with CmdUI and that is already
			// done in OnUpdateCmdUI, so halt further processing
			bHandled=TRUE;
			break;
		}

	case WM_MEASUREITEM:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MEASUREITEM\n"));
		{
			int nIDCtl=(int)wParam;
			LPMEASUREITEMSTRUCT lpMeasureItemStruct=
				(LPMEASUREITEMSTRUCT)(LPTSTR)lParam;
			result=OnMeasureItem(nIDCtl,lpMeasureItemStruct);
			bHandled=TRUE;
			break;
		}

	case WM_COMMAND:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_COMMAND\n"));
		{
			if(HIWORD(wParam)==0)
			{
				int nCmdID=LOWORD(wParam);

				if(nCmdID==ID_OX_SHOWALLITEMS)
				{
					// v9.3 update 01 modification Manfred Drasch
					POSITION pos=m_BitmapMenuList.GetHeadPosition();
					while(pos!=NULL)
					{
						COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
						RestoreBitmapMenu(pBitmapMenu,TRUE);
					}
					// end modification Manfred Drasch

					m_bForceToDisplayHiddenItems=TRUE;

					// current menu
					UpdateActivePopupMenuCount();

					// v9.3 update 01 modification Manfred Drasch
					if (m_nActivePopupMenuCount == 0)
						break;
					// end modification Manfred Drasch

					ASSERT(m_nActivePopupMenuCount>0);
					OXPOPUPMENUTRACE pmt=
						m_arrPopupMenusTrace[m_nActivePopupMenuCount-1];

					// handle these event differently for menu bar and standard menu
					// in the case the top level popup menu is being displayed.
					// In the case GetMenu() returns NULL we assume that we deal 
					// with menu bar
					BOOL bMenuBar=(m_pFrameWnd->GetMenu()==NULL);
					BOOL bSpecialCase=(bMenuBar && m_nActivePopupMenuCount==1);

					if(bSpecialCase)
					{
						m_pFrameWnd->LockWindowUpdate();
					}

					HWND hWndSendRepopulateMsg=NULL;
					if(!bSpecialCase)
					{
						if(m_nActivePopupMenuCount>1)
						{
							VERIFY(m_mapPopupMenuWindows.Lookup(
								m_arrPopupMenusTrace[m_nActivePopupMenuCount-2].
								m_hPopupMenu,hWndSendRepopulateMsg));
						}
						else
						{
							hWndSendRepopulateMsg=m_pFrameWnd->GetSafeHwnd();
						}
						ASSERT(hWndSendRepopulateMsg!=NULL);
					}

					// hide current menu
					HWND hWnd=NULL;
					VERIFY(m_mapPopupMenuWindows.Lookup(pmt.m_hPopupMenu,hWnd));
					ASSERT(hWnd!=NULL);
					if(bSpecialCase || bMenuBar)
					{
						TRACE(_T("MenuOrganizerProc ::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);"));
						::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
					}
					else
					{
						TRACE(_T("MenuOrganizerProc ::PostMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);"));
						::PostMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
					}

					if(bSpecialCase)
					{
						m_pFrameWnd->UnlockWindowUpdate();
					}
						
					// repopulate menus
					// v9.3 update 01 modification Manfred Drasch - POSITION pos declared above
					// POSITION pos=m_BitmapMenuList.GetHeadPosition();
					pos=m_BitmapMenuList.GetHeadPosition();
					while(pos!=NULL)
					{
						COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
						ASSERT(pBitmapMenu!=NULL);
						HWND hWnd=NULL;
						if(!::IsMenu(pBitmapMenu->m_hMenu) || 
							!m_mapPopupMenuWindows.Lookup(
							pBitmapMenu->GetSafeHmenu(),hWnd) || !::IsWindow(hWnd) ||
							pBitmapMenu->GetSafeHmenu()==pmt.m_hPopupMenu)
						{
							// restore the menu
							RestoreBitmapMenu(pBitmapMenu,TRUE);
						}
					}

					if(!bSpecialCase)
					{
						if(bMenuBar)
						{
							// display the menu again
							::SendMessage(hWndSendRepopulateMsg,
								WM_KEYDOWN,VK_RETURN,0x001c0001);
						}
						else
						{
							// display the menu again
							::PostMessage(hWndSendRepopulateMsg,
								WM_KEYDOWN,VK_RETURN,0x001c0001);
						}
					}
				}
				else if(nCmdID>0 && IsShowOnlyRecentlyUsedItems() && 
					m_arrPopupMenusTrace.GetSize()>0)
				{
					BOOL bMarkMenuAsChanged=FALSE;
					if(!IsRecentlyUsed(nCmdID))
					{
						AddToRecentlyUsed(nCmdID);
						bMarkMenuAsChanged=TRUE;
					}
					for(int nIndex=1; 
						nIndex<m_arrPopupMenusTrace.GetSize(); nIndex++)
					{
						HMENU hPopupMenu=m_arrPopupMenusTrace[nIndex].m_hPopupMenu;
						if(!IsSubmenuRecentlyUsed(hPopupMenu))
						{
							AddSubmenuToRecentlyUsed(hPopupMenu);
							bMarkMenuAsChanged=TRUE;
						}
					}

					if(bMarkMenuAsChanged && IsAttached())
					{
						m_pFrameWnd->SendMessage(WM_OX_MENUCHANGED);
					}
				}

				bHandled=TRUE;
			}
			break;
		}

	case WM_ENTERMENULOOP:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_ENTERMENULOOP\n"));
		{
			if(wParam==0)
			{
				m_bMainMenuIsActive=TRUE;
			}
			
			bHandled=TRUE;

			break;
		}

	case WM_EXITMENULOOP:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_EXITMENULOOP\n"));
		{
			if(wParam==0)
			{
				if(m_bForceToDisplayHiddenItems)
				{
					// repopulate menus
					m_bForceToDisplayHiddenItems=FALSE;
					if(IsShowOnlyRecentlyUsedItems())
					{
						POSITION pos=m_BitmapMenuList.GetHeadPosition();
						while(pos!=NULL)
						{
							COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
							RestoreBitmapMenu(pBitmapMenu,TRUE);
							
							TRACE(_T("\n %x menu should be removed by RestoreBitmapMenu"), pBitmapMenu);
							//delete pBitmapMenu;
						}
					}
				}

				m_bMainMenuIsActive=FALSE;

				m_nActivePopupMenuCount=0;
			}

			// unhook mouse messages
			if(g_pfnOldMouseHookProc!=NULL)
			{
				VERIFY(::UnhookWindowsHookEx(g_pfnOldMouseHookProc));
				g_pfnOldMouseHookProc=NULL;
			}

			// unhook keyboard messages
			if(g_pfnOldKeyboardHookProc!=NULL)
			{
				VERIFY(::UnhookWindowsHookEx(g_pfnOldKeyboardHookProc));
				g_pfnOldKeyboardHookProc=NULL;
			}
			
			bHandled=TRUE;

			break;
		}

	case WM_MENUSELECT:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_MENUSELECT\n"));
		{
			if(lParam!=NULL && m_arrPopupMenusTrace.GetSize()>0)
			{
				OXPOPUPMENUTRACE& pmt=
					m_arrPopupMenusTrace[m_arrPopupMenusTrace.GetSize()-1];
				if(pmt.m_hPopupMenu==(HMENU)lParam)
				{
					// save Top/Left coordinates of the menu window
					CWnd* pPopupWnd=CWnd::GetDesktopWindow()->GetTopWindow();
					ASSERT(pPopupWnd!=NULL);
					CRect rectPopupWnd;
					pPopupWnd->GetWindowRect(rectPopupWnd);
					pmt.m_ptTopLeft=rectPopupWnd.TopLeft();
					////////////////////////////////
					m_mapPopupMenuWindows.
						SetAt((HMENU)lParam,pPopupWnd->GetSafeHwnd());
					if(IsShowOnlyRecentlyUsedItems())
					{
						// setup hooks for mouse and keyboard messages
						if(g_pfnOldMouseHookProc==NULL)
						{
							g_pfnOldMouseHookProc=::SetWindowsHookEx(WH_MOUSE,
								MenuMouseHookProc,NULL,::GetCurrentThreadId());
						}
						if(g_pfnOldKeyboardHookProc==NULL)
						{
							g_pfnOldKeyboardHookProc=::SetWindowsHookEx(WH_KEYBOARD,
								MenuKeyboardHookProc,NULL,::GetCurrentThreadId());
						}
						//////////////////////////////////////////////
					}
				}
			}
/*
			UINT nFlags=HIWORD(wParam);
			if((nFlags&MF_HILITE)!=0 && !(nFlags==0xffff && lParam==NULL) &&
				LOWORD(wParam)!=-1)
			{
				while(m_nActivePopupMenuCount>0 && m_arrPopupMenusTrace[
					m_nActivePopupMenuCount-1].m_hPopupMenu!=(HMENU)lParam)
				{
					m_nActivePopupMenuCount--;
				}
			}
*/
			break;
		}

	case WM_OX_SAVEMENUSTATE:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc - WM_OX_SAVEMENUSTATE\n"));
		{
			// save info about recently used submenu items
			HMENU hMenu=(HMENU)wParam;
			CString sKey=(LPCTSTR)lParam;
			if(hMenu!=NULL)
			{
				VERIFY(SaveRUSubmenusState(hMenu,
					sKey+_T("_RecentlyUsedSubmenuItems")));
			}
		}

	case WM_OX_LOADMENUSTATE:
		TRACE(_T("COXBitmapMenuOrganizer::MenuOrganizerProc\n"));
		{
			// load info about recently used submenu items
			HMENU hMenu=(HMENU)wParam;
			CString sKey=(LPCTSTR)lParam;
			if(hMenu!=NULL)
			{
				VERIFY(LoadRUSubmenusState(hMenu,
					sKey+_T("_RecentlyUsedSubmenuItems")));
			}
		}

	default:
			// Do nothing special
			;
	}

	return result;
}


void COXBitmapMenuOrganizer::UpdateActivePopupMenuCount()
{
	int nTraceLength=PtrToInt(m_arrPopupMenusTrace.GetSize());

	if(nTraceLength==0)
	{
		m_nActivePopupMenuCount=0;
		return;
	}
	
	int nIndex=0;
	for(nIndex=0; nIndex<nTraceLength; nIndex++)
	{
		HWND hWnd=NULL;
		if(!m_mapPopupMenuWindows.
			Lookup(m_arrPopupMenusTrace[nIndex].m_hPopupMenu,hWnd))
		{
			break;
		}
	
		if(!::IsWindow(hWnd) || !::IsWindowVisible(hWnd))
		{
			break;
		}
	}

	if(nIndex<m_nActivePopupMenuCount)
	{
		m_nActivePopupMenuCount=nIndex;
	}
}


CMenu* COXBitmapMenuOrganizer::OwnFindPopupMenuFromID(CMenu* pMenu, UINT nID)
{
	ASSERT_VALID(pMenu);

	// walk through all items, looking for ID match
	UINT_PTR nItems=pMenu->GetMenuItemCount();
	UINT_PTR nItemID=0;
	for (int iItem=0; iItem < (int)nItems; iItem++)
	{
		// Always check the menu item itself first
		nItemID=pMenu->GetMenuItemID(iItem);
		if(nItemID==(UINT)-1)
		{
			// ... If it is a cascade menu, use its handle instead of its ID (which is always -1)
			//     So appearently Windows passes the HMENU instead of the ID for cascade manus
			//     in MEASUREITEMSTRUCT when sending WM_MEASUREITEM
			nItemID=(UINT_PTR)pMenu->GetSubMenu(iItem)->GetSafeHmenu();
		}

		if(nItemID==nID || nID==-1)
		{
			// ... it is an item inside our popup
			pMenu=CMenu::FromHandlePermanent(pMenu->m_hMenu);
			return pMenu;
		}

		// Then check child menus
		CMenu* pPopup=pMenu->GetSubMenu(iItem);
		if(pPopup != NULL)
		{
			// ... Recurse to child popup
			pPopup=OwnFindPopupMenuFromID(pPopup, nID);
			// ... Check popups on this popup
			if(pPopup != NULL)
				return pPopup;
		}
	}
	// ... Not found
	return NULL;
}

void COXBitmapMenuOrganizer::ConvertBitmapMenu(COXBitmapMenu* pBitmapMenu,
											   BOOL bNewBitmapMenu/*=TRUE*/)
{
	ASSERT(pBitmapMenu!=NULL);

	UINT uItemID;
	COXImageInfo* pImageInfo;
	int nCount=pBitmapMenu->GetMenuItemCount();

	int nAmpIndex;
	MENUITEMINFO miiGet, miiPut;
	CString sText;

	COXArrSavedMenuItem arrSavedMenuItems;
	BOOL bPrevSepBeforeHidden=TRUE;

	//Make all the menu items OwnerDrawn
	int nIndex=0;
	for(nIndex=0; nIndex < nCount; nIndex++)
	{
		// Even cascade menu item should be made owner drawn
		//  so that the text of these items is aligned properly

		::ZeroMemory(&miiGet, sizeof(miiGet));
		miiGet.cbSize=sizeof(miiGet);
		miiGet.fMask=MIIM_TYPE|MIIM_ID|MIIM_STATE|MIIM_DATA|
			MIIM_SUBMENU|MIIM_CHECKMARKS;
		miiGet.fType=MFT_STRING;
		miiGet.dwTypeData = NULL;
		::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiGet);
		++miiGet.cch;
		miiGet.dwTypeData=sText.GetBuffer(miiGet.cch + 1);
		// Gets the item info
		miiGet.dwTypeData[0]=_T('\0');
		::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiGet);
		sText.ReleaseBuffer();
		
#if _MFC_VER>0x0421
#ifndef _AFX_NO_OLE_SUPPORT
		if(miiGet.fType & MFT_SEPARATOR)
		{
			if(m_pFrameWnd->m_pNotifyHook!=NULL)
			{
				if(m_pFrameWnd->m_pNotifyHook->m_pActiveItem!=NULL)
				{
//					continue;
				}
			}
		}
#endif	//	_AFX_NO_OLE_SUPPORT
#endif	//	_MFC_VER>0x0421

		if(bNewBitmapMenu && !m_bForceToDisplayHiddenItems && 
			!IsInCustomizationMode() && IsShowOnlyRecentlyUsedItems() && 
			(!IsRecentlyUsed(miiGet.wID) || 
			!IsSubmenuRecentlyUsed(miiGet.hSubMenu) ||
			((miiGet.fType & MFT_SEPARATOR) && bPrevSepBeforeHidden)))
		{
			OXSAVEDMENUITEM smi;
			smi.nIndex=nIndex;
			smi.miInfo=miiGet;
			if(miiGet.hSubMenu!=NULL)
			{
				smi.miInfo.hSubMenu=CopyPopupMenu(miiGet.hSubMenu);
			}
			smi.sText=sText;
			ASSERT(smi.miInfo.wID!=-1 || ::IsMenu(smi.miInfo.hSubMenu));
			arrSavedMenuItems.Add(smi);

			if(!(miiGet.fType & MFT_SEPARATOR) && !bPrevSepBeforeHidden && nIndex>0)
			{
				if(pBitmapMenu->GetMenuItemID(nIndex-1)==0)
				{
					bPrevSepBeforeHidden=TRUE;
				}
			}
		}
		else
		{
			BOOL bConvertToOwnerdraw=((miiGet.fType & MFT_OWNERDRAW)==0);

			uItemID=((miiGet.hSubMenu==NULL) ? miiGet.wID : (UINT)-1);

			//Makes the item owner-drawn and sets the ItemInfo to the ItemData
			// which in turn will be used in COXBitmapMenu while drawing
			::ZeroMemory(&miiPut, sizeof(miiPut));
			miiPut.cbSize=sizeof(miiPut);
			miiPut.fMask=(bConvertToOwnerdraw ? MIIM_TYPE : 0) | MIIM_DATA | MIIM_ID;
			miiPut.fType=(miiGet.fType & ~MFT_STRING) | MFT_OWNERDRAW;

			switch(miiGet.wID)
			{
				// Restore
			case 61728:
				miiPut.wID = ID_OXBITMAPMENU_RESTORE;
				break;
				// Minimize
			case 61472:
				miiPut.wID = ID_OXBITMAPMENU_MINIMIZE;
				break;
				// Close
			case 61536:
				miiPut.wID = ID_OXBITMAPMENU_CLOSE;
				break;
			default:
				miiPut.wID = miiGet.wID;
			}			
	
			// Gets the ImageInfo for the command if exist
			if(!m_mapCommandToImageInfo.Lookup(uItemID,pImageInfo))
			{
				CImageList* pImageList;
				CString sUResource=GetUniqueResourceString(uItemID,FALSE);
				
				// if the Normal menuitem is not already added
				if(!m_mapStringToImageList.Lookup(sUResource, pImageList))
				{
					m_mapStringToImageList[sUResource]=pImageList=&m_DefaultImgList;
				}

				ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
				pImageInfo=new COXImageInfo(pImageList, 0, TRUE);
				//sets the mapping between MenuItem ID and Image Info
				m_mapCommandToImageInfo[uItemID]=pImageInfo;
			}			

			COXItemInfo* pItemInfo=NULL;
			if(miiGet.dwItemData != 0 && !bNewBitmapMenu)
			{
				pItemInfo=(COXItemInfo*)miiGet.dwItemData;
				miiPut.dwItemData=(DWORD_PTR)pItemInfo;
				if(miiGet.fType==MFT_STRING)
				{
					pItemInfo->SetText(sText);
				}
			}
			else
			{		

				pItemInfo=new COXItemInfo(pImageInfo, sText);
				TRACE(_T("\nCreated COXItemInfo at %x - Line: %d, %s"), pItemInfo, __LINE__, __FILE__);
				miiPut.dwItemData=(DWORD_PTR)pItemInfo;
				pBitmapMenu->AddItemInfo(pItemInfo);
			}			

			// Put the menuitem with the new data back in its place
			::SetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiPut);

			// A mapping is maintained for keyboard access chars of menu items and 
			// the commands IDs.
			nAmpIndex=sText.Find('&'); 
			TCHAR LoCase=_T('\0');
			if(nAmpIndex!=-1)
			{
				LoCase=(TCHAR)towlower(sText[nAmpIndex+1]);
				(pBitmapMenu->m_KeyAccessMap)[LoCase]=nIndex;
			}

			bPrevSepBeforeHidden=FALSE;			
		}
	}	

	if(bNewBitmapMenu)
	{
		if(arrSavedMenuItems.GetSize()>0)
		{			
			// Gets the ImageInfo for the command if exist
			if(!m_mapCommandToImageInfo.Lookup(ID_OX_SHOWALLITEMS,pImageInfo))
			{
				CString sUResource=GetUniqueResourceString(ID_OX_SHOWALLITEMS,FALSE);
				CImageList* pImageList;
				m_mapStringToImageList[sUResource]=pImageList=&m_DefaultImgList;
				ASSERT(AfxIsValidAddress(pImageList, sizeof(CImageList)));
				pImageInfo=new COXImageInfo(pImageList, 0, TRUE);
				//sets the mapping between MenuItem ID and Image Info
				m_mapCommandToImageInfo[ID_OX_SHOWALLITEMS]=pImageInfo;
			}			

			COXItemInfo* pItemInfo=new COXItemInfo(pImageInfo,_T(""));
			pBitmapMenu->AddItemInfo(pItemInfo);

			// add expansion item
			pBitmapMenu->
				AppendMenu(MF_OWNERDRAW,ID_OX_SHOWALLITEMS,(LPCTSTR)pItemInfo);
		}		

		ASSERT(!m_mapSavedMenuItems.RemoveKey(pBitmapMenu));
		m_mapSavedMenuItems.SetAt(pBitmapMenu,arrSavedMenuItems);
		
		for(nIndex= PtrToInt(arrSavedMenuItems.GetSize())-1; nIndex>=0; nIndex--)
		{
			OXSAVEDMENUITEM smi=arrSavedMenuItems[nIndex];
			VERIFY(pBitmapMenu->DeleteMenu(smi.nIndex,MF_BYPOSITION));
		}
	}


	//Calculates the various internal extents
	pBitmapMenu->CalcExtents();
}


void COXBitmapMenuOrganizer::RestoreBitmapMenu(COXBitmapMenu* pBitmapMenu, 
											   BOOL bCopyText/*=TRUE*/)
{
	BOOL bDeferDeletion = FALSE;

	// remove it from the list if it hasn't been removed yet
	POSITION pos=m_BitmapMenuList.GetHeadPosition();
	while(pos!=NULL)
	{
		if(m_BitmapMenuList.GetAt(pos)==pBitmapMenu)
		{
			TRACE(_T("\nRemoving bitmapmenu at %x - Line: %d, %s"), pBitmapMenu, __LINE__, __FILE__);
			m_BitmapMenuList.RemoveAt(pos);
			break;
		}
		m_BitmapMenuList.GetNext(pos);
	}

	// remove expansion item
	if(::IsMenu(pBitmapMenu->m_hMenu) && pBitmapMenu->GetMenuItemCount()>0)
	{
		if(pBitmapMenu->GetMenuItemID(pBitmapMenu->GetMenuItemCount()-1)==
			ID_OX_SHOWALLITEMS)
		{
			bDeferDeletion = TRUE;
			pBitmapMenu->DeleteMenu(pBitmapMenu->GetMenuItemCount()-1,MF_BYPOSITION);
		}
	}

	MENUITEMINFO miiGet, miiPut;
	CString sText;

	if(bCopyText && ::IsMenu(pBitmapMenu->m_hMenu))
	{
		int nCount=pBitmapMenu->GetMenuItemCount();

		// Put the strings of the menu's back in, the ownerdraw state has emptied them.
		for(int nIndex=0; nIndex < nCount; nIndex++)
		{
			::ZeroMemory(&miiGet, sizeof(miiGet));
			miiGet.cbSize=sizeof(miiGet);
			miiGet.fMask=MIIM_TYPE | MIIM_DATA;
			// Gets the item info
			::GetMenuItemInfo(pBitmapMenu->GetSafeHmenu(), nIndex, TRUE, &miiGet);

			// all item must have been converted to ownerdraw
			// only the items that has been added programmatically 
			// and hasn't been displayed yet won't have ownerdraw style
			if((miiGet.fType&MFT_OWNERDRAW)!=0)
			{
				COXItemInfo* pItemInfo=(COXItemInfo*)miiGet.dwItemData;
				if(pItemInfo!=NULL)
				{
					sText=pItemInfo->GetText();

					// Put the text text back into the menu
					::ZeroMemory(&miiPut, sizeof(miiPut));
					miiPut.cbSize=sizeof(miiPut);
					miiPut.fMask=MIIM_TYPE|MIIM_DATA;
					if((miiGet.fType&MFT_SEPARATOR)==0)
					{
						miiPut.fType=(miiGet.fType&~MFT_OWNERDRAW)|MFT_STRING;
					}
					else
					{
						miiPut.fType=(miiGet.fType&~MFT_OWNERDRAW);
					}
					miiPut.cch=sText.GetLength();
					miiPut.dwTypeData=sText.GetBuffer(miiPut.cch);
					miiPut.dwItemData=0;
					// Put the menuitem with the new data back in its place
					::SetMenuItemInfo(pBitmapMenu->GetSafeHmenu(),nIndex,TRUE,&miiPut);
					sText.ReleaseBuffer();
				}
			}
		}
	}

	COXArrSavedMenuItem arrSavedMenuItems;
	VERIFY(m_mapSavedMenuItems.Lookup(pBitmapMenu,arrSavedMenuItems));
	if(::IsMenu(pBitmapMenu->m_hMenu))
	{
		for(int nIndex=0; nIndex<arrSavedMenuItems.GetSize(); nIndex++)
		{
			OXSAVEDMENUITEM smi=arrSavedMenuItems[nIndex];
			smi.miInfo.dwTypeData=(LPTSTR)((LPCTSTR)smi.sText);
			VERIFY(::InsertMenuItem(pBitmapMenu->GetSafeHmenu(),
				smi.nIndex,TRUE,&smi.miInfo));
		}
	}
	VERIFY(m_mapSavedMenuItems.RemoveKey(pBitmapMenu));


	//TRACE(_T("\npBitmapMenu at %0x\n"),pBitmapMenu);

	//  - 9.3 patch - defer deletion of bitmap till restored bitmap displayed 
	if(!bDeferDeletion) {
		pBitmapMenu->Detach();
		delete pBitmapMenu;
		pBitmapMenu = NULL;
	}
	else {
		if( m_pDeferedBM != NULL) {
			delete m_pDeferedBM;
		}
		pBitmapMenu->Detach();
		m_pDeferedBM = pBitmapMenu;
	}
}


void COXBitmapMenuOrganizer::ShowOnlyRecentlyUsedItems(BOOL bShowOnlyRecentlyUsed)
{
	if(bShowOnlyRecentlyUsed!=m_bShowOnlyRecentlyUsed)
	{	
		m_bShowOnlyRecentlyUsed=bShowOnlyRecentlyUsed;

		POSITION pos=m_BitmapMenuList.GetHeadPosition();
		while(pos!=NULL)
		{
			COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
			COXBitmapMenuPopupWnd* pPopupWnd=pBitmapMenu->GetPopupWnd();
			if(pPopupWnd!=NULL && ::IsWindow(pPopupWnd->GetSafeHwnd()))
			{
				pPopupWnd->OnMenuChanged();
			}
		}
	}
}


BOOL COXBitmapMenuOrganizer::ExcludeFromRecentlyUsed(int nCmdID)
{
	ASSERT(nCmdID>=0);
	
	if(nCmdID==0)
	{
		// separators cannot be hidden
		return FALSE;
	}
	
	if(!IsRecentlyUsed(nCmdID))
	{
		// not a recently used item
		return FALSE;
	}

	m_mapHiddenCommands.SetAt(nCmdID,0);
	
	return TRUE;
}


BOOL COXBitmapMenuOrganizer::ExcludeFromRecentlyUsed(CMenu* pMenu, int nItemIndex)
{
	ASSERT(pMenu!=NULL);
	ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());
	
	int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
	if(nCmdID==-1)
	{
		// submenu
		ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
		return ExcludeSubmenuFromRecentlyUsed(
			pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
	}
	else
	{
		return ExcludeFromRecentlyUsed(nCmdID);
	}
}


BOOL COXBitmapMenuOrganizer::ExcludeSubmenuFromRecentlyUsed(HMENU hPopupMenu)
{
	ASSERT(hPopupMenu!=NULL);
	
	if(!IsSubmenuRecentlyUsed(hPopupMenu))
	{
		// not a recently used submenu
		return FALSE;
	}

	m_mapHiddenSubmenus.SetAt(hPopupMenu,0);
	
	return TRUE;
}



BOOL COXBitmapMenuOrganizer::AddToRecentlyUsed(int nCmdID)
{
	ASSERT(nCmdID>0);

	if(!m_mapHiddenCommands.RemoveKey(nCmdID))
	{
		// this command is already marked as recently used
		return FALSE;
	}

	return TRUE;
}


BOOL COXBitmapMenuOrganizer::AddToRecentlyUsed(CMenu* pMenu, int nItemIndex)
{
	ASSERT(pMenu!=NULL);
	ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());

	int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
	if(nCmdID==-1)
	{
		// submenu
		ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
		return AddSubmenuToRecentlyUsed(pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
	}
	else
	{
		return AddToRecentlyUsed(nCmdID);
	}
}


BOOL COXBitmapMenuOrganizer::AddSubmenuToRecentlyUsed(HMENU hPopupMenu)
{
	ASSERT(hPopupMenu!=NULL);

	if(!m_mapHiddenSubmenus.RemoveKey(hPopupMenu))
	{
		// this submenu is already marked as recently used
		return FALSE;
	}

	return TRUE;
}



BOOL COXBitmapMenuOrganizer::IsRecentlyUsed(int nCmdID) const 
{ 
	int nDummy=-1;
	return (!m_mapHiddenCommands.Lookup(nCmdID,nDummy)); 
}


BOOL COXBitmapMenuOrganizer::IsRecentlyUsed(CMenu* pMenu, int nItemIndex) const 
{ 
	if (nItemIndex == -1)
		return TRUE;
	ASSERT(pMenu!=NULL);
	ASSERT(nItemIndex>=0 && nItemIndex<(int)pMenu->GetMenuItemCount());

	int nCmdID=(int)pMenu->GetMenuItemID(nItemIndex);
	if(nCmdID==-1)
	{
		// submenu
		ASSERT(pMenu->GetSubMenu(nItemIndex)!=NULL);
		return IsSubmenuRecentlyUsed(pMenu->GetSubMenu(nItemIndex)->GetSafeHmenu());
	}
	else
	{
		return IsRecentlyUsed(nCmdID);
	}
}


BOOL COXBitmapMenuOrganizer::IsSubmenuRecentlyUsed(HMENU hPopupMenu) const 
{ 
	int nDummy=-1;
	return (!m_mapHiddenSubmenus.Lookup(hPopupMenu,nDummy)); 
}



void COXBitmapMenuOrganizer::SetCutomizationMode(BOOL bInCutomizationMode,
												 HWND hWndCustomizeOrganizer/*=NULL*/) 
{ 
	if(m_bInCutomizationMode!=bInCutomizationMode)
	{
		m_bInCutomizationMode=bInCutomizationMode;
		if(m_bInCutomizationMode)
		{
			if(IsShowOnlyRecentlyUsedItems() && !m_bForceToDisplayHiddenItems)
			{
				POSITION pos=m_BitmapMenuList.GetHeadPosition();
				while(pos!=NULL)
				{
					COXBitmapMenu* pBitmapMenu=m_BitmapMenuList.GetNext(pos);
					RestoreBitmapMenu(pBitmapMenu,TRUE);
//					delete pBitmapMenu;
				}
			}
		}
	}
	m_hWndCustomizeOrganizer=hWndCustomizeOrganizer;
}


BOOL COXBitmapMenuOrganizer::SaveRUCommandsState(LPCTSTR lpszSubKey)
{
#ifndef _MAC
	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
	{
		sProfileName=_T("RecentlyUsedMenuItems");
	}
	CString sValueName=_T("RUContents");
	
	CMemFile memFile;
	CArchive ar(&memFile,CArchive::store);
	VERIFY(SaveRUCommandsContents(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("RUItemsDataSize");
	pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength);

	return TRUE;
#else
	return FALSE;
#endif
}


BOOL COXBitmapMenuOrganizer::LoadRUCommandsState(LPCTSTR lpszSubKey)
{
#ifndef _MAC
	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
	{
		sProfileName=_T("RecentlyUsedMenuItems");
	}
	CString sValueName=_T("RUItemsDataSize");
	int nSavedBufferLength=
		pApp->GetProfileInt(sProfileName,sValueName,-1);
	sValueName=_T("RUContents");
	if(nSavedBufferLength!=-1)
	{
		ASSERT(nSavedBufferLength>0);
		UINT nBufferLength=0;
		BYTE* pBuffer=NULL;
		if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength))
		{
			ASSERT(nBufferLength>0);
			ASSERT(pBuffer!=NULL);
			CMemFile memFile(pBuffer,nBufferLength);
			CArchive ar(&memFile,CArchive::load);
			VERIFY(LoadRUCommandsContents(ar));
			ar.Close();
			memFile.Detach();
			delete[] pBuffer;
		}
	}
	return TRUE;
#else
	return FALSE;
#endif
}


BOOL COXBitmapMenuOrganizer::SaveRUCommandsContents(CArchive& ar)
{
	int nCommandsCount=PtrToInt(m_mapHiddenCommands.GetCount());
	ar<<nCommandsCount;
	POSITION pos=m_mapHiddenCommands.GetStartPosition();
	while(pos!=NULL)
	{
		int nCmdID=-1;
		int nIndex=-1;
		m_mapHiddenCommands.GetNextAssoc(pos,nCmdID,nIndex);
		ASSERT(nCmdID>0);
		ar<<nCmdID;
	}

	return TRUE;
}

BOOL COXBitmapMenuOrganizer::LoadRUCommandsContents(CArchive& ar)
{
	// remove all items from the list of hidden commands
	m_mapHiddenCommands.RemoveAll();

	DWORD dwCommandsCount=0;
	ar>>dwCommandsCount;
	for(int nIndex=0; nIndex<(int)dwCommandsCount; nIndex++)
	{
		DWORD dwCmdID=0;
		ar>>dwCmdID;
		ASSERT(dwCmdID>0);
		ExcludeFromRecentlyUsed((int)dwCmdID);
	}	

	return TRUE;
}


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

	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
	{
		sProfileName=_T("RecentlyUsedSubmenuItems");
	}
	CString sValueName=_T("RUContents");
	
	CMemFile memFile;
	CArchive ar(&memFile,CArchive::store);
	VERIFY(SaveRUSubmenusContents(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("RUItemsDataSize");
	pApp->WriteProfileInt(sProfileName,sValueName,nBufferLength);

	return TRUE;
#else
	return FALSE;
#endif
}


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

	CWinApp* pApp=AfxGetApp();
	CString sProfileName=lpszSubKey;
	if(sProfileName.IsEmpty())
	{
		sProfileName=_T("RecentlyUsedSubmenuItems");
	}
	CString sValueName=_T("RUItemsDataSize");
	int nSavedBufferLength=
		pApp->GetProfileInt(sProfileName,sValueName,-1);
	sValueName=_T("RUContents");
	if(nSavedBufferLength!=-1)
	{
		ASSERT(nSavedBufferLength>0);
		UINT nBufferLength=0;
		BYTE* pBuffer=NULL;
		if(pApp->GetProfileBinary(sProfileName,sValueName,&pBuffer,&nBufferLength))
		{
			ASSERT(nBufferLength>0);
			ASSERT(pBuffer!=NULL);
			CMemFile memFile(pBuffer,nBufferLength);
			CArchive ar(&memFile,CArchive::load);
			VERIFY(LoadRUSubmenusContents(hMenu,ar));
			ar.Close();
			memFile.Detach();
			delete[] pBuffer;
		}
	}
	return TRUE;
#else
	return FALSE;
#endif
}


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

	int nSubmenusCount=PtrToInt(m_mapHiddenSubmenus.GetCount());
	ar<<nSubmenusCount;
	POSITION pos=m_mapHiddenSubmenus.GetStartPosition();
	while(pos!=NULL)
	{
		HMENU hPopupMenu=NULL;
		int nIndex=-1;
		m_mapHiddenSubmenus.GetNextAssoc(pos,hPopupMenu,nIndex);
		ASSERT(hPopupMenu!=NULL);
		if(::IsMenu(hPopupMenu))
		{
			CArray<int,int> arrPath;
			if(FindPopupMenuPath(hPopupMenu,hMenu,arrPath))
			{
				for(int nIndex=0; nIndex<arrPath.GetSize(); nIndex++)
				{
					ar<<arrPath[nIndex];
				}
			}
		}
		// end of path
		ar<<-1;
	}

	return TRUE;
}

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

	// remove all items from the list of hidden submenus
	m_mapHiddenSubmenus.RemoveAll();

	DWORD dwSubmenusCount=0;
	ar>>dwSubmenusCount;
	for(int nIndex=0; nIndex<(int)dwSubmenusCount; nIndex++)
	{
		DWORD dwItemIndex;
		CArray<int,int> arrPath;
		do
		{
			ar>>dwItemIndex;
			if(dwItemIndex!=-1)
			{
				arrPath.Add(dwItemIndex);
			}
		} while(dwItemIndex!=-1);

		HMENU hPopupMenu=NULL;
		if(arrPath.GetSize()>0)
		{
			HMENU hParentMenu=hMenu;
			for(int nPathIndex=0; nPathIndex<arrPath.GetSize(); nPathIndex++)
			{
				hParentMenu=GetSubMenu(hParentMenu,arrPath[nPathIndex]);
				if(hParentMenu==NULL)
				{
					TRACE(_T("COXBitmapMenuOrganizer::LoadRUSubmenusContents: failed to load RU submenu\n"));
					break;
				}
			}
			hPopupMenu=hParentMenu;
		}

		if(hPopupMenu!=NULL)
		{
			ExcludeSubmenuFromRecentlyUsed(hPopupMenu);
		}
	}	

	return TRUE;
}


COXBitmapMenuOrganizer* COXBitmapMenuOrganizer::FindOrganizer(HWND hWnd)
{
	COXBitmapMenuOrganizer* pOrganizer=NULL;
	if(!m_allMenuOrganizers.Lookup(hWnd,pOrganizer))
	{
		return NULL;
	}
	else
	{
		return pOrganizer;
	}
}


BOOL COXBitmapMenuOrganizer::IsTopLevelPopupMenu(HMENU hPopupMenu)
{
	ASSERT(hPopupMenu!=NULL);
	ASSERT(::IsMenu(hPopupMenu));
	ASSERT(IsAttached());

	CMenu* pMenu=m_pFrameWnd->GetMenu();
	if(pMenu==NULL)
		return FALSE;

	BOOL bFound=FALSE;
	for(int nIndex=0; nIndex<(int)pMenu->GetMenuItemCount(); nIndex++)
	{
		CMenu* pTopLevelPopupMenu=pMenu->GetSubMenu(nIndex);
		if(pTopLevelPopupMenu!=NULL && 
			pTopLevelPopupMenu->GetSafeHmenu()==hPopupMenu)
		{
			bFound=TRUE;
			break;
		}
	}

	return bFound;
}


HMENU COXBitmapMenuOrganizer::CopyPopupMenu(HMENU hMenuDest)
{
	HMENU hMenu=::CreatePopupMenu();
	ASSERT(hMenu!=NULL);
	m_arrCreatedPopupMenus.Add(hMenu);
	if(!IsSubmenuRecentlyUsed(hMenuDest))
	{
		AddSubmenuToRecentlyUsed(hMenuDest);
		ExcludeSubmenuFromRecentlyUsed(hMenu);
	}

	MENUITEMINFO miInfo;
	CString sText;

	for(int nIndex=0; nIndex<::GetMenuItemCount(hMenuDest); nIndex++)
	{
		// Even cascade menu item should be made owner drawn
		//  so that the text of these items is align properly

		::ZeroMemory(&miInfo,sizeof(miInfo));
		miInfo.cbSize=sizeof(miInfo);
		miInfo.fMask=MIIM_TYPE|MIIM_ID|MIIM_STATE|MIIM_DATA|
			MIIM_SUBMENU|MIIM_CHECKMARKS;
		miInfo.fType=MFT_STRING;
		miInfo.cch=300;
		miInfo.dwTypeData=sText.GetBuffer(miInfo.cch);
		// Gets the item info
		miInfo.dwTypeData[0]=_T('\0');
		::GetMenuItemInfo(hMenuDest,nIndex,TRUE,&miInfo);
		if(miInfo.hSubMenu!=NULL)
		{
			miInfo.hSubMenu=CopyPopupMenu(miInfo.hSubMenu);
		}
		VERIFY(::InsertMenuItem(hMenu,nIndex,TRUE,&miInfo));
		sText.ReleaseBuffer();
	}

	return hMenu;
}


BOOL COXBitmapMenuOrganizer::FindPopupMenuPath(HMENU hPopupMenu, 
											   HMENU hParentMenu, 
											   CArray<int,int>& arrPath)
{
	ASSERT(hPopupMenu!=NULL);
	ASSERT(::IsMenu(hPopupMenu));
	ASSERT(hParentMenu!=NULL);
	ASSERT(::IsMenu(hParentMenu));

	int nItemCount=::GetMenuItemCount(hParentMenu);
	for(int nIndex=0; nIndex<nItemCount; nIndex++)
	{
		HMENU hSubmenu=::GetSubMenu(hParentMenu,nIndex);
		if(hSubmenu==hPopupMenu || 
			(hSubmenu!=NULL && FindPopupMenuPath(hPopupMenu,hSubmenu,arrPath)))
		{
			arrPath.InsertAt(0,nIndex);
			return TRUE;
		}
	}

	return FALSE;
}


LRESULT CALLBACK COXBitmapMenuOrganizer::
MenuMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif

	TRACE(_T("COXBitmapMenuOrganizer::MenuMouseHookProc code: %0X, wParam: %0X, lParam: %0X \n"));

	ASSERT(g_pfnOldMouseHookProc!=NULL);

	if(nCode<0)
	{
		// have to call the default implementation
	    return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
	}

	if(wParam!=WM_LBUTTONDOWN && wParam!=WM_RBUTTONDOWN && 
		wParam!=WM_LBUTTONUP && wParam!=WM_RBUTTONUP && 
		wParam!=WM_LBUTTONDBLCLK && wParam!=WM_RBUTTONDBLCLK)
	{
		// have to call the default implementation
	    return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
	}

	COXBitmapMenuOrganizer* pBMOrganizer=
		COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
	ASSERT(pBMOrganizer!=NULL);
	ASSERT(pBMOrganizer->IsShowOnlyRecentlyUsedItems());

	DWORD dwMessagePos=::GetMessagePos();
	POINTS points=MAKEPOINTS(dwMessagePos);
	CPoint ptLast(points.x,points.y);
	CWnd* pWnd=CWnd::WindowFromPoint(ptLast);
	ASSERT(pWnd!=NULL);
	// find if pWnd is on of the windows that host popup menus
	POSITION pos=pBMOrganizer->m_mapPopupMenuWindows.GetStartPosition();
	while(pos!=NULL)
	{
		HMENU hMenu=NULL;
		HWND hWnd=NULL;
		pBMOrganizer->m_mapPopupMenuWindows.GetNextAssoc(pos,hMenu,hWnd);
		ASSERT(hMenu!=NULL);
		ASSERT(hWnd!=NULL);
		if(pWnd->GetSafeHwnd()==hWnd)
		{
			ASSERT(::IsMenu(hMenu));
			// find the menu in the trace array
			BOOL bFound=FALSE;
			int nIndex=0;
			for(nIndex=0; 
				nIndex<pBMOrganizer->m_arrPopupMenusTrace.GetSize(); nIndex++)
			{
				if(pBMOrganizer->m_arrPopupMenusTrace[nIndex].m_hPopupMenu==hMenu)
				{
					bFound=TRUE;
					break;
				}
			}
			ASSERT(bFound);
			if(pBMOrganizer->m_nActivePopupMenuCount>nIndex+1)
			{
				BOOL bFoundPopupMenuToClose=FALSE;
				for(int nIndexPopupWnd=nIndex+1; 
					nIndexPopupWnd<pBMOrganizer->m_arrPopupMenusTrace.GetSize(); 
					nIndexPopupWnd++)
				{
					// try to find and close the remaining popup menus
					HWND hWnd=NULL;
					if(pBMOrganizer->m_mapPopupMenuWindows.Lookup(pBMOrganizer->
						m_arrPopupMenusTrace[nIndexPopupWnd].m_hPopupMenu,hWnd))
					{
						if(::IsWindow(hWnd))
						{
							::SendMessage(hWnd,WM_KEYDOWN,VK_ESCAPE,0x00010001);
						}
						bFoundPopupMenuToClose=TRUE;
					}
				}
				if(bFoundPopupMenuToClose)
				{
					pBMOrganizer->m_nActivePopupMenuCount=nIndex+1;
				}
			}

			// check if "Show All items" menu item has been clicked
			int nMenuItemIndex=::MenuItemFromPoint(hWnd,hMenu,ptLast);
			if(nMenuItemIndex!=-1)
			{
				int nCmdID=::GetMenuItemID(hMenu,nMenuItemIndex);
				switch(nCmdID)
				{
				case ID_OX_SHOWALLITEMS:
					{
						if(wParam!=WM_LBUTTONDOWN && wParam!=WM_RBUTTONDOWN)
						{
							pBMOrganizer->m_pFrameWnd->PostMessage(WM_COMMAND,
								MAKEWPARAM(ID_OX_SHOWALLITEMS,0));
						}
						// modicication Manfred Drasch - return removed
 						// return 1;
					}
				}
			}
		}
	}

    return ::CallNextHookEx(g_pfnOldMouseHookProc,nCode,wParam,lParam);
}


LRESULT CALLBACK COXBitmapMenuOrganizer::
MenuKeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
#if defined (_WINDLL)
#if defined (_AFXDLL)
	AFX_MANAGE_STATE(AfxGetAppModuleState());
#else
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
#endif
	ASSERT(g_pfnOldKeyboardHookProc!=NULL);

// v9.3 update 01 modification - removed by Manfred Drasch
// avoid crash with return over arrow menu item

// 	if(nCode<0)
// 	{
// 		// have to call the default implementation
// 	    return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
// 	}
// 
// 	if(wParam!=VK_RETURN)
// 	{
// 		// have to call the default implementation
// 	    return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
// 	}
// 	
// 	COXBitmapMenuOrganizer* pBMOrganizer=
// 		COXBitmapMenuOrganizer::FindOrganizer(AfxGetMainWnd()->GetSafeHwnd());
// 	ASSERT(pBMOrganizer!=NULL);
// 	ASSERT(pBMOrganizer->IsShowOnlyRecentlyUsedItems());
// 
// 	CWnd* pWnd=CWnd::GetDesktopWindow()->GetTopWindow();
// 	ASSERT(pWnd!=NULL);
// 	// find if pWnd is on of the windows that host popup menus
// 	POSITION pos=pBMOrganizer->m_mapPopupMenuWindows.GetStartPosition();
// 	while(pos!=NULL)
// 	{
// 		HMENU hMenu=NULL;
// 		HWND hWnd=NULL;
// 		pBMOrganizer->m_mapPopupMenuWindows.GetNextAssoc(pos,hMenu,hWnd);
// 		ASSERT(hMenu!=NULL);
// 		ASSERT(hWnd!=NULL);
// 		if(pWnd->GetSafeHwnd()==hWnd)
// 		{
// 			MENUITEMINFO miInfo={ sizeof(MENUITEMINFO) };
// 			miInfo.fMask=MIIM_ID|MIIM_STATE;
// 			VERIFY(::GetMenuItemInfo(hMenu,::GetMenuItemCount(hMenu)-1,TRUE,&miInfo));
// 			if(miInfo.wID==ID_OX_SHOWALLITEMS && (miInfo.fState&MFS_HILITE))
// 			{
// 				if((lParam&0xe0000000)==0)
// 				{
// 					pBMOrganizer->m_pFrameWnd->PostMessage(WM_COMMAND,
// 						MAKEWPARAM(ID_OX_SHOWALLITEMS,0));
// 				}
// 				
// 				return 1;
// 			}
// 		}
// 	}
// 
// end modification Manfred Drasch

    return ::CallNextHookEx(g_pfnOldKeyboardHookProc,nCode,wParam,lParam);
}


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