191 lines
5.3 KiB
C++
191 lines
5.3 KiB
C++
/*--------------------------------------------------------------------------*
|
||
*
|
||
* Microsoft Windows
|
||
* Copyright (C) Microsoft Corporation, 1992 - 1999
|
||
*
|
||
* File: sysmenu.cpp
|
||
*
|
||
* Contents: Implementation file for system menu modification functions
|
||
*
|
||
* History: 04-Feb-98 jeffro Created
|
||
*
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
#include "stdafx.h"
|
||
#include "sysmenu.h"
|
||
#include "mmcres.h"
|
||
#include <list>
|
||
#include <algorithm>
|
||
|
||
|
||
typedef std::list<HWND> WindowList;
|
||
|
||
|
||
|
||
/*--------------------------------------------------------------------------*
|
||
* GetWindowList
|
||
*
|
||
*
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
static WindowList& GetWindowList()
|
||
{
|
||
static WindowList List;
|
||
return (List);
|
||
}
|
||
|
||
|
||
|
||
/*--------------------------------------------------------------------------*
|
||
* WipeWindowList
|
||
*
|
||
* Removes no-longer-valid windows from the Window-to-addition map.
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
void WipeWindowList ()
|
||
{
|
||
WindowList& List = GetWindowList();
|
||
WindowList::iterator it = List.begin();
|
||
|
||
while (it != List.end())
|
||
{
|
||
// if the window isn't valid, erase it
|
||
if (!::IsWindow (*it))
|
||
{
|
||
WindowList::iterator itErase = it++;
|
||
List.erase(itErase);
|
||
}
|
||
|
||
// this one's OK, check the next one
|
||
else
|
||
++it;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*--------------------------------------------------------------------------*
|
||
* AppendToSystemMenu
|
||
*
|
||
* Returns number of menu items appended.
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
int AppendToSystemMenu (CWnd* pwnd, int nSubmenuIndex)
|
||
{
|
||
DECLARE_SC(sc, TEXT("AppendToSystemMenu"));
|
||
|
||
CMenu menuSysAdditions;
|
||
sc = menuSysAdditions.LoadMenu (IDR_SYSMENU_ADDITIONS) ? S_OK : E_FAIL;
|
||
if (sc)
|
||
return 0;
|
||
|
||
CMenu* pSubMenu = menuSysAdditions.GetSubMenu (nSubmenuIndex);
|
||
sc = ScCheckPointers(pSubMenu, E_UNEXPECTED);
|
||
if (sc)
|
||
return 0;
|
||
|
||
return (AppendToSystemMenu (pwnd, pSubMenu));
|
||
}
|
||
|
||
|
||
|
||
/*--------------------------------------------------------------------------*
|
||
* AppendToSystemMenu
|
||
*
|
||
* Returns number of menu items appended.
|
||
*
|
||
*--------------------------------------------------------------------------*/
|
||
|
||
int AppendToSystemMenu (CWnd* pwnd, CMenu* pMenuToAppend, CMenu* pSysMenu)
|
||
{
|
||
DECLARE_SC(sc, TEXT("AppendToSystemMenu"));
|
||
sc = ScCheckPointers(pwnd, pMenuToAppend);
|
||
if (sc)
|
||
return 0;
|
||
|
||
if ( (!::IsWindow (pwnd->m_hWnd)) ||
|
||
(!::IsMenu (pMenuToAppend->m_hMenu)) )
|
||
{
|
||
sc = E_UNEXPECTED;
|
||
return 0;
|
||
}
|
||
|
||
// no system menu? get one
|
||
if (pSysMenu == NULL)
|
||
pSysMenu = pwnd->GetSystemMenu (FALSE);
|
||
|
||
// still no system menu? bail
|
||
if (pSysMenu == NULL)
|
||
return (0);
|
||
|
||
// clean out the map
|
||
WipeWindowList ();
|
||
|
||
// if this is the first addition to this window, append a separator
|
||
WindowList& List = GetWindowList();
|
||
WindowList::iterator itEnd = List.end();
|
||
|
||
if (std::find (List.begin(), itEnd, pwnd->m_hWnd) == itEnd)
|
||
{
|
||
List.push_back (pwnd->m_hWnd);
|
||
|
||
// If this is a child window & the next window item has not yet been added
|
||
if ( (pwnd->GetStyle() & WS_CHILD) &&
|
||
(pSysMenu->GetMenuState (SC_NEXTWINDOW, MF_BYCOMMAND) == 0xFFFFFFFF))
|
||
{
|
||
// Windows exhibits odd behavior by always handing us a non-child system menu
|
||
// The text is currently wrong and diaplays "alt-f4" as the shortcut
|
||
// instead of "ctrl-f4". The following code fixes that.
|
||
CString strClose;
|
||
LoadString(strClose, IDS_CLOSE);
|
||
sc = pSysMenu->ModifyMenu( SC_CLOSE, MF_STRING | MF_BYCOMMAND, SC_CLOSE, strClose ) ? S_OK : E_FAIL;
|
||
sc.TraceAndClear();
|
||
|
||
// Add a separator
|
||
sc = pSysMenu->AppendMenu (MF_SEPARATOR) ? S_OK : E_FAIL;
|
||
sc.TraceAndClear();
|
||
|
||
// Add the "Next" item
|
||
CString strNext;
|
||
LoadString(strNext, IDS_NEXTWINDOW);
|
||
sc = pSysMenu->AppendMenu( MF_STRING, SC_NEXTWINDOW, strNext ) ? S_OK : E_FAIL;
|
||
sc.TraceAndClear();
|
||
}
|
||
|
||
sc = pSysMenu->AppendMenu (MF_SEPARATOR) ? S_OK : E_FAIL;
|
||
sc.TraceAndClear();
|
||
}
|
||
|
||
int cAppendedItems = 0;
|
||
|
||
int cItemsToAppend = pMenuToAppend->GetMenuItemCount ();
|
||
TCHAR szMenuText[64];
|
||
|
||
MENUITEMINFO mii;
|
||
mii.cbSize = sizeof (mii);
|
||
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_SUBMENU;
|
||
mii.dwTypeData = szMenuText;
|
||
|
||
for (int i = 0; i < cItemsToAppend; i++)
|
||
{
|
||
ASSERT (mii.dwTypeData == szMenuText);
|
||
mii.cch = countof (szMenuText);
|
||
if (! ::GetMenuItemInfo (pMenuToAppend->m_hMenu, i, TRUE, &mii))
|
||
sc.FromLastError().TraceAndClear();
|
||
|
||
// this code can't handle cascaded additions to the system menu
|
||
ASSERT (mii.hSubMenu == NULL);
|
||
|
||
// if the menu item is a separator or isn't already there, append it
|
||
if ((mii.fType & MFT_SEPARATOR) ||
|
||
(pSysMenu->GetMenuState (mii.wID, MF_BYCOMMAND) == 0xFFFFFFFF))
|
||
{
|
||
pSysMenu->AppendMenu (mii.fType, mii.wID, szMenuText);
|
||
cAppendedItems++;
|
||
}
|
||
}
|
||
|
||
// return the number of items appended
|
||
return (cAppendedItems);
|
||
}
|