windows-nt/Source/XPSP1/NT/shell/ext/cabview/menu.cpp
2020-09-26 16:20:57 +08:00

460 lines
11 KiB
C++

//*******************************************************************************************
//
// Filename : Menu.cpp
//
// Implementations for CCabItemMenu methods
//
// Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
//
//*******************************************************************************************
#include "pch.h"
#include "thisdll.h"
#include "resource.h"
#include "folder.h"
#include "menu.h"
#include "dataobj.h"
#include "cabitms.h"
// Copy a menu onto the beginning or end of another menu
// Adds uIDAdjust to each menu ID (pass in 0 for no adjustment)
// Will not add any item whose adjusted ID is greater than uMaxIDAdjust
// (pass in 0xffff to allow everything)
// Returns one more than the maximum adjusted ID that is used
//
BOOL _SHIsMenuSeparator(HMENU hm, int i)
{
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_TYPE;
mii.cch = 0; // WARNING: We MUST initialize it to 0!!!
if (!GetMenuItemInfo(hm, i, TRUE, &mii))
{
return(FALSE);
}
if (mii.fType & MFT_SEPARATOR)
{
return(TRUE);
}
return(FALSE);
}
//===================================================================
// Cab_MergeMenu parameter
//
#define MM_ADDSEPARATOR 0x00000001L
#define MM_SUBMENUSHAVEIDS 0x00000002L
UINT Cab_MergeMenus(HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
{
int nItem;
HMENU hmSubMenu;
BOOL bAlreadySeparated;
MENUITEMINFO miiSrc;
TCHAR szName[256];
UINT uTemp, uIDMax = uIDAdjust;
if (!hmDst || !hmSrc)
{
goto MM_Exit;
}
nItem = GetMenuItemCount(hmDst);
if (uInsert >= (UINT)nItem)
{
uInsert = (UINT)nItem;
bAlreadySeparated = TRUE;
}
else
{
bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);;
}
if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
{
// Add a separator between the menus
InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
bAlreadySeparated = TRUE;
}
// Go through the menu items and clone them
for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
{
miiSrc.cbSize = sizeof(MENUITEMINFO);
miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
// We need to reset this every time through the loop in case
// menus DON'T have IDs
miiSrc.fType = MFT_STRING;
miiSrc.dwTypeData = szName;
miiSrc.dwItemData = 0;
miiSrc.cch = ARRAYSIZE(szName);
if (!GetMenuItemInfo(hmSrc, nItem, TRUE, &miiSrc))
{
continue;
}
if (miiSrc.fType & MFT_SEPARATOR)
{
// This is a separator; don't put two of them in a row
if (bAlreadySeparated)
{
continue;
}
bAlreadySeparated = TRUE;
}
else if (miiSrc.hSubMenu)
{
if (uFlags & MM_SUBMENUSHAVEIDS)
{
// Adjust the ID and check it
miiSrc.wID += uIDAdjust;
if (miiSrc.wID > uIDAdjustMax)
{
continue;
}
if (uIDMax <= miiSrc.wID)
{
uIDMax = miiSrc.wID + 1;
}
}
else
{
// Don't set IDs for submenus that didn't have
// them already
miiSrc.fMask &= ~MIIM_ID;
}
hmSubMenu = miiSrc.hSubMenu;
miiSrc.hSubMenu = CreatePopupMenu();
if (!miiSrc.hSubMenu)
{
goto MM_Exit;
}
uTemp = Cab_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust,
uIDAdjustMax, uFlags&MM_SUBMENUSHAVEIDS);
if (uIDMax <= uTemp)
{
uIDMax = uTemp;
}
bAlreadySeparated = FALSE;
}
else
{
// Adjust the ID and check it
miiSrc.wID += uIDAdjust;
if (miiSrc.wID > uIDAdjustMax)
{
continue;
}
if (uIDMax <= miiSrc.wID)
{
uIDMax = miiSrc.wID + 1;
}
bAlreadySeparated = FALSE;
}
if (!InsertMenuItem(hmDst, uInsert, TRUE, &miiSrc))
{
goto MM_Exit;
}
}
// Ensure the correct number of separators at the beginning of the
// inserted menu items
if (uInsert == 0)
{
if (bAlreadySeparated)
{
DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
}
}
else
{
if (_SHIsMenuSeparator(hmDst, uInsert-1))
{
if (bAlreadySeparated)
{
DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
}
}
else
{
if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
{
// Add a separator between the menus
InsertMenu(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
}
}
}
MM_Exit:
return(uIDMax);
}
CCabItemMenu::CCabItemMenu(HWND hwndOwner, CCabFolder*pcf, LPCABITEM *apit, UINT cpit)
: m_lSel(8)
{
m_hwndOwner = hwndOwner;
m_pcfHere = pcf;
pcf->AddRef();
// No need to check return value here; check in QueryInterface
m_lSel.AddItems(apit, cpit);
}
CCabItemMenu::~CCabItemMenu()
{
m_pcfHere->Release();
}
// *** IUnknown methods ***
STDMETHODIMP CCabItemMenu::QueryInterface(
REFIID riid,
LPVOID FAR* ppvObj)
{
*ppvObj = NULL;
if (m_lSel.GetState() == CCabItemList::State_OutOfMem)
{
return(E_OUTOFMEMORY);
}
LPUNKNOWN pObj;
if (riid == IID_IUnknown)
{
pObj = (LPUNKNOWN)(IUnknown*)((IContextMenu*)this);
// The (IShellFolder*) ^^^ up there is to disambiguate :) the reference
}
else if (riid == IID_IContextMenu)
{
pObj = (LPUNKNOWN)(IContextMenu*)this;
}
else
{
return(E_NOINTERFACE);
}
pObj->AddRef();
*ppvObj = pObj;
return(NOERROR);
}
STDMETHODIMP_(ULONG) CCabItemMenu::AddRef(void)
{
return(m_cRef.AddRef());
}
STDMETHODIMP_(ULONG) CCabItemMenu::Release(void)
{
if (!m_cRef.Release())
{
delete this;
return(0);
}
return(m_cRef.GetRef());
}
// *** IContextMenu methods ***
STDMETHODIMP CCabItemMenu::QueryContextMenu(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags)
{
HMENU hmMerge = LoadPopupMenu(MENU_ITEMCONTEXT, 0);
if (!hmMerge)
{
return(E_OUTOFMEMORY);
}
if (CMF_DVFILE & uFlags)
{
// No "copy" item on the file menu:
RemoveMenu(hmMerge, IDC_ITEM_COPY, MF_BYCOMMAND);
}
UINT idMax = Cab_MergeMenus(hmenu, hmMerge, indexMenu, idCmdFirst, idCmdLast,
MM_ADDSEPARATOR);
DestroyMenu(hmMerge);
SetMenuDefaultItem(hmenu, IDC_ITEM_EXTRACT+idCmdFirst, FALSE);
return(ResultFromShort(idMax - idCmdFirst));
}
STDMETHODIMP CCabItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
if (lpici->cbSize < SIZEOF(CMINVOKECOMMANDINFO))
{
return E_INVALIDARG;
}
if (HIWORD(lpici->lpVerb))
{
// Deal with string commands
LPCMINVOKECOMMANDINFOEX lpicix = (LPCMINVOKECOMMANDINFOEX) lpici; // This value is only usable when fCmdInfoEx is true
#ifdef UNICODE
BOOL fUnicode = FALSE;
if ((lpici->cbSize >= CMICEXSIZE_NT4) && ((lpici->fMask & CMIC_MASK_UNICODE) == CMIC_MASK_UNICODE))
{
fUnicode = TRUE;
}
#endif
LPCTSTR pszVerb;
#ifdef UNICODE
WCHAR szVerb[MAX_PATH];
if (!fUnicode || lpicix->lpVerbW == NULL)
{
SHAnsiToUnicode(lpici->lpVerb, szVerb, ARRAYSIZE(szVerb));
pszVerb = szVerb;
}
else
pszVerb = lpicix->lpVerbW;
#else
pszVerb = lpici->lpVerb;
#endif
UINT idCmd = 0;
if (NULL != pszVerb)
{
if (0 == lstrcmpi(pszVerb, TEXT("copy")))
{
idCmd = IDC_ITEM_COPY;
}
else if (0 == lstrcmpi(pszVerb, TEXT("extract")))
{
idCmd = IDC_ITEM_EXTRACT;
}
}
lpici->lpVerb = (LPCSTR) IntToPtr(idCmd);
}
switch ((UINT)LOWORD((DWORD_PTR)lpici->lpVerb))
{
case IDC_ITEM_EXTRACT:
{
TCHAR szHere[MAX_PATH];
if (!m_pcfHere->GetPath(szHere))
{
return(E_UNEXPECTED);
}
UINT cPidls = m_lSel.GetCount();
if (0 == cPidls)
{
return(E_UNEXPECTED);
}
IDataObject* pdo = (IDataObject*) (new CCabObj(m_hwndOwner, m_pcfHere,
m_lSel.GetArray(), cPidls));
if (NULL == pdo)
{
return(E_OUTOFMEMORY);
}
// the object is created with a zero ref count, so we need to temporarily
// bump it up if we're going to use it:
pdo->AddRef();
CCabExtract ceHere(szHere);
BOOL fResult = ceHere.ExtractToFolder(m_hwndOwner, pdo, ShouldExtract, (LPARAM)this);
pdo->Release();
return fResult ? S_OK : E_FAIL;
}
case IDC_ITEM_COPY:
{
UINT cPidls = m_lSel.GetCount();
if (cPidls > 0)
{
IDataObject* pObj = (IDataObject*) (new CCabObj(m_hwndOwner, m_pcfHere,
m_lSel.GetArray(), cPidls));
if (NULL != pObj)
{
// the object is created with a zero ref count, so we need to temporarily
// bump it up if we're going to use it:
pObj->AddRef();
HRESULT hr = OleSetClipboard(pObj);
pObj->Release();
return hr;
}
}
return E_FAIL;
}
default:
return(E_INVALIDARG);
}
return(NOERROR);
}
STDMETHODIMP CCabItemMenu::GetCommandString(
UINT_PTR idCmd,
UINT uType,
UINT * pwReserved,
LPSTR pszName,
UINT cchMax)
{
return(E_NOTIMPL);
}
HGLOBAL * CALLBACK CCabItemMenu::ShouldExtract(LPCTSTR pszFile, DWORD dwSize, UINT date,
UINT time, UINT attribs, LPARAM lParam)
{
CCabItemMenu *pThis = (CCabItemMenu*)lParam;
if (pThis->m_lSel.IsInList(pszFile, dwSize, date, time, attribs))
{
return(EXTRACT_TRUE);
}
// Copy nothing for now
return(EXTRACT_FALSE);
}
HMENU CCabItemMenu::LoadPopupMenu(UINT id, UINT uSubMenu)
{
HMENU hmParent = LoadMenu(g_ThisDll.GetInstance(), MAKEINTRESOURCE(id));
if (!hmParent)
{
return(NULL);
}
HMENU hmPopup = GetSubMenu(hmParent, 0);
RemoveMenu(hmParent, uSubMenu, MF_BYPOSITION);
DestroyMenu(hmParent);
return(hmPopup);
}