460 lines
11 KiB
C++
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);
|
|
}
|