//******************************************************************************************* // // 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); }