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

538 lines
14 KiB
C++

#include "shellprv.h"
#include "defview.h"
#include "defviewp.h"
#include "contextmenu.h"
#include "ids.h"
#include "unicpp\deskhtm.h"
class CThumbnailMenu : public IContextMenu3,
public CComObjectRoot,
public IObjectWithSite
{
public:
BEGIN_COM_MAP(CThumbnailMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu3,IContextMenu3)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2,IContextMenu2)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu,IContextMenu)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
DECLARE_NOT_AGGREGATABLE(CThumbnailMenu)
CThumbnailMenu();
~CThumbnailMenu();
HRESULT Init(CDefView* pView, LPCITEMIDLIST * apidl, UINT cidl);
STDMETHOD(QueryContextMenu)(HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags);
STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
STDMETHOD(GetCommandString)(UINT_PTR idCmd,
UINT uType,
UINT * pwReserved,
LPSTR pszName,
UINT cchMax);
STDMETHOD(HandleMenuMsg)(UINT uMsg,
WPARAM wParam,
LPARAM lParam);
STDMETHOD(HandleMenuMsg2)(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
LRESULT* plRes);
STDMETHOD(SetSite)(IUnknown *punkSite);
STDMETHOD(GetSite)(REFIID riid, void **ppvSite);
protected:
LPCITEMIDLIST * _apidl;
UINT _cidl;
IContextMenu *_pMenu;
IContextMenu2 *_pMenu2;
BOOL _fCaptureAvail;
UINT _wID;
CDefView* _pView;
};
HRESULT CDefView::_CreateSelectionContextMenu(REFIID riid, void** ppv)
{
*ppv = NULL;
HRESULT hr = E_OUTOFMEMORY;
if (_IsImageMode() && !_IsOwnerData())
{
LPCITEMIDLIST* apidl;
UINT cidl;
_GetItemObjects(&apidl, SVGIO_SELECTION, &cidl);
if (apidl)
{
// get the context menu interface for the object ....
CComObject<CThumbnailMenu> * pMenuTmp = new CComObject<CThumbnailMenu>;
if (pMenuTmp)
{
pMenuTmp->AddRef(); // ATL is strange, start with zero ref
hr = pMenuTmp->Init(this, apidl, cidl);
if (SUCCEEDED(hr))
hr = pMenuTmp->QueryInterface(riid, ppv);
pMenuTmp->Release();
}
LocalFree((HLOCAL)apidl);
}
}
else
{
hr = GetItemObject(SVGIO_SELECTION, riid, ppv);
}
ASSERT((SUCCEEDED(hr) && *ppv) || (FAILED(hr) && !*ppv));
return hr;
}
LPCITEMIDLIST * DuplicateIDArray(LPCITEMIDLIST * apidl, UINT cidl)
{
LPCITEMIDLIST * apidlNew = (LPCITEMIDLIST *) LocalAlloc(LPTR, cidl * sizeof(LPCITEMIDLIST));
if (apidlNew)
{
CopyMemory(apidlNew, apidl, cidl * sizeof(LPCITEMIDLIST));
}
return apidlNew;
}
CThumbnailMenu::CThumbnailMenu()
{
_pMenu = NULL;
_pMenu2 = NULL;
_pView = NULL;
_apidl = NULL;
_cidl = NULL;
_fCaptureAvail = FALSE;
_wID = -1;
}
CThumbnailMenu::~CThumbnailMenu()
{
if (_pMenu)
{
_pMenu->Release();
}
if (_pMenu2)
{
_pMenu2->Release();
}
if (_pView)
{
_pView->Release();
}
if (_apidl)
{
LocalFree(_apidl);
}
}
HRESULT CThumbnailMenu::Init(CDefView*pView, LPCITEMIDLIST *apidl, UINT cidl)
{
if (cidl == 0)
return E_INVALIDARG;
// duplicate the array that holds the pointers ..
_apidl = DuplicateIDArray(apidl, cidl);
_cidl = cidl;
if (_apidl == NULL)
{
_cidl = 0;
return E_OUTOFMEMORY;
}
_pView = pView;
pView->AddRef();
// scan the pidl array and check for Extractors ...
for (int i = 0; i < (int) _cidl; i++)
{
IExtractImage *pExtract;
HRESULT hr = pView->_pshf->GetUIObjectOf(pView->_hwndView, 1, &_apidl[i], IID_PPV_ARG_NULL(IExtractImage, &pExtract));
if (SUCCEEDED(hr))
{
WCHAR szPath[MAX_PATH];
DWORD dwFlags = 0;
SIZE rgThumbSize;
pView->_GetThumbnailSize(&rgThumbSize);
hr = pExtract->GetLocation(szPath, ARRAYSIZE(szPath), NULL, &rgThumbSize, pView->_dwRecClrDepth, &dwFlags);
pExtract->Release();
if (dwFlags & (IEIFLAG_CACHE | IEIFLAG_REFRESH))
{
_fCaptureAvail = TRUE;
break;
}
}
else
{
// blank it out so we don't bother trying it if the user choses the command
_apidl[i] = NULL;
}
}
HRESULT hr = pView->_pshf->GetUIObjectOf(pView->_hwndMain, cidl, apidl,
IID_PPV_ARG_NULL(IContextMenu, & _pMenu));
if (SUCCEEDED(hr))
{
_pMenu->QueryInterface(IID_PPV_ARG(IContextMenu2, &_pMenu2));
}
return hr;
}
STDMETHODIMP CThumbnailMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu,
UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
ASSERT(_pMenu != NULL);
// generate the proper menu
HRESULT hr = _pMenu->QueryContextMenu(hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
if (SUCCEEDED(hr) && _fCaptureAvail)
{
// find the first separator and insert the menu text after it....
int cMenuSize = GetMenuItemCount(hmenu);
for (int iIndex = 0; iIndex < cMenuSize; iIndex ++)
{
WCHAR szText[80];
MENUITEMINFOW mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE;
mii.fType = 0;
mii.dwTypeData = szText;
mii.cch = 80;
GetMenuItemInfo(hmenu, iIndex, TRUE, &mii);
if (mii.fType & MFT_SEPARATOR)
{
szText[0] = 0;
LoadString(HINST_THISDLL, IDS_CREATETHUMBNAIL, szText, 80);
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.dwTypeData = szText;
mii.cch = 0;
// assuming 0 is the first id, therefore the next one = the count they returned
_wID = HRESULT_CODE(hr);
mii.wID = idCmdFirst + _wID;
InsertMenuItem(hmenu, iIndex, TRUE, & mii);
// we used an extra ID.
hr ++;
break;
}
}
}
return hr;
}
STDMETHODIMP CThumbnailMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
HRESULT hr = E_FAIL;
ASSERT(_pMenu != NULL);
if (pici->lpVerb != IntToPtr_(LPCSTR, _wID))
{
hr = _pMenu->InvokeCommand(pici);
}
else
{
// capture thumbnails .....
for (UINT i = 0; i < _cidl; i++)
{
if (_apidl[i])
{
UINT uiImage;
_pView->ExtractItem(&uiImage, -1, _apidl[i], TRUE, TRUE, PRIORITY_P5);
}
}
}
return hr;
}
STDMETHODIMP CThumbnailMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwRes, LPSTR pszName, UINT cchMax)
{
if (cchMax)
pszName[0] = 0;
if (!IS_INTRESOURCE(idCmd))
{
// it is really a text verb ...
LPSTR pszCommand = (LPSTR) idCmd;
if (lstrcmpA(pszCommand, "CaptureThumbnail") == 0)
{
return S_OK;
}
}
else
{
if (idCmd == _wID)
{
// it is ours ...
switch(uType)
{
case GCS_VERB:
StrCpyN((LPWSTR) pszName, TEXT("CaptureThumbnail"), cchMax);
break;
case GCS_HELPTEXT:
LoadString(HINST_THISDLL, IDS_CREATETHUMBNAILHELP, (LPWSTR) pszName, cchMax);
break;
case GCS_VALIDATE:
break;
default:
return E_INVALIDARG;
}
return S_OK;
}
}
return _pMenu->GetCommandString(idCmd, uType, pwRes, pszName, cchMax);
}
STDMETHODIMP CThumbnailMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plRes)
{
HRESULT hr = E_NOTIMPL;
if (uMsg == WM_MENUCHAR)
{
hr = SHForwardContextMenuMsg(_pMenu2, uMsg, wParam, lParam, plRes, FALSE);
}
else
{
hr = HandleMenuMsg(uMsg, wParam, lParam);
if (plRes)
*plRes = 0;
}
return hr;
}
STDMETHODIMP CThumbnailMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (_pMenu2 == NULL)
{
return E_NOTIMPL;
}
switch (uMsg)
{
case WM_DRAWITEM:
{
DRAWITEMSTRUCT * pdi = (DRAWITEMSTRUCT *)lParam;
if (pdi->CtlType == ODT_MENU && pdi->itemID == _wID)
{
return E_NOTIMPL;
}
}
break;
case WM_MEASUREITEM:
{
MEASUREITEMSTRUCT *pmi = (MEASUREITEMSTRUCT *)lParam;
if (pmi->CtlType == ODT_MENU && pmi->itemID == _wID)
{
return E_NOTIMPL;
}
}
break;
}
return _pMenu2->HandleMenuMsg(uMsg, wParam, lParam);
}
HRESULT CThumbnailMenu::SetSite(IUnknown *punkSite)
{
IUnknown_SetSite(_pMenu, punkSite);
return S_OK;
}
HRESULT CThumbnailMenu::GetSite(REFIID riid, void **ppvSite)
{
return IUnknown_GetSite(_pMenu, riid, ppvSite);
}
//
// To be called back from within CDefFolderMenu
//
// Returns:
// S_OK, if successfully processed.
// (S_FALSE), if default code should be used.
//
HRESULT CALLBACK DefView_DFMCallBackBG(IShellFolder *psf, HWND hwndOwner,
IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
switch(uMsg)
{
case DFM_VALIDATECMD:
case DFM_INVOKECOMMAND:
hr = S_FALSE;
break;
default:
hr = E_NOTIMPL;
break;
}
return hr;
}
// Create defview's POPUP_SFV_BACKGROUND menu
HRESULT CDefView::_Create_BackgrndHMENU(BOOL fViewMenuOnly, REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
*ppv = NULL;
HMENU hmContext = SHLoadPopupMenu(HINST_THISDLL, POPUP_SFV_BACKGROUND);
if (hmContext)
{
// HACK: we are only initializing the Paste command, so we don't
// need any attributes
Def_InitEditCommands(0, hmContext, SFVIDM_FIRST, _pdtgtBack,
DIEC_BACKGROUNDCONTEXT);
InitViewMenu(hmContext);
// Do a whole lot of desktop-only stuff for the actual desktop
if (_IsDesktop() && IsDesktopBrowser(_psb))
{
// We only want LargeIcons on the real desktop
// so we remove the View menu
DeleteMenu(hmContext, SFVIDM_MENU_VIEW, MF_BYCOMMAND);
// No Choose Columns either
DeleteMenu(hmContext, SFVIDM_VIEW_COLSETTINGS, MF_BYCOMMAND);
// Only put on ActiveDesktop menu item if it isn't restricted.
if (SHRestricted(REST_FORCEACTIVEDESKTOPON) ||
(!PolicyNoActiveDesktop() &&
!SHRestricted(REST_CLASSICSHELL) &&
!SHRestricted(REST_NOACTIVEDESKTOPCHANGES)))
{
HMENU hmenuAD;
// Load the menu and make the appropriate modifications
if (hmenuAD = SHLoadMenuPopup(HINST_THISDLL, POPUP_SFV_BACKGROUND_AD))
{
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;
if (GetMenuItemInfo(hmContext, SFVIDM_MENU_ARRANGE, FALSE, &mii))
{
// Get the present settings regarding HTML on desktop
SHELLSTATE ss;
SHGetSetSettings(&ss, SSF_DESKTOPHTML | SSF_HIDEICONS, FALSE);
if (!ss.fHideIcons)
CheckMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_ICONS, MF_BYCOMMAND | MF_CHECKED);
if (GetDesktopFlags() & COMPONENTS_LOCKED)
CheckMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_LOCK, MF_BYCOMMAND | MF_CHECKED);
// Hide the desktop cleanup wizard item if we're not allowed to run it
// (user is guest or policy forbids it)
if (IsOS(OS_ANYSERVER) || IsUserAGuest() || SHRestricted(REST_NODESKTOPCLEANUP))
{
DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_WIZARD, MF_BYCOMMAND);
}
Shell_MergeMenus(mii.hSubMenu, hmenuAD, (UINT)-1, 0, (UINT)-1, MM_ADDSEPARATOR);
}
DestroyMenu(hmenuAD);
}
}
}
if (fViewMenuOnly)
{
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;
GetMenuItemInfo(hmContext, SFVIDM_MENU_VIEW, MF_BYCOMMAND, &mii);
HMENU hmenuView = mii.hSubMenu;
RemoveMenu(hmContext, SFVIDM_MENU_VIEW, MF_BYCOMMAND);
DestroyMenu(hmContext);
hmContext = hmenuView;
}
hr = Create_ContextMenuOnHMENU(hmContext, _hwndView, riid, ppv);
}
return hr;
}
// Create defview's actual background context menu, an array of:
// defview's POPUP_SFV_BACKGROUND and
// the IShellFolder's CreateViewObject(IID_IContextMenu)
//
HRESULT CDefView::_CBackgrndMenu_CreateInstance(REFIID riid, void **ppv)
{
HRESULT hr = E_OUTOFMEMORY;
*ppv = NULL;
IContextMenu* pcmMenu;
hr = _Create_BackgrndHMENU(FALSE, IID_PPV_ARG(IContextMenu, &pcmMenu));
if (SUCCEEDED(hr))
{
IContextMenu* pcmView;
if (SUCCEEDED(_pshf->CreateViewObject(_hwndMain, IID_PPV_ARG(IContextMenu, &pcmView))))
{
IContextMenu* rgpcm[2] = {pcmMenu, pcmView};
hr = Create_ContextMenuOnContextMenuArray(rgpcm, ARRAYSIZE(rgpcm), riid, ppv);
pcmView->Release();
}
else
{
// Compat - RNAUI fails the CreateViewObject and they rely on simply having the default stuff...
//
hr = pcmMenu->QueryInterface(riid, ppv);
}
pcmMenu->Release();
}
return hr;
}