WindowsXP-SP1/shell/shell32/menuband/isfmenu.cpp
2020-09-30 16:53:49 +02:00

244 lines
6.3 KiB
C++

//
// isfmenu.cpp
//
// callback for chevron drop-down menu for isfbands
//
#include "shellprv.h"
#include "isfmenu.h"
#include "legacy.h"
#include "util.h"
// *** IUnknown methods ***
STDMETHODIMP CISFMenuCallback::QueryInterface (REFIID riid, LPVOID * ppvObj)
{
static const QITAB qit[] =
{
QITABENT(CISFMenuCallback, IShellMenuCallback),
QITABENT(CISFMenuCallback, IObjectWithSite),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
STDMETHODIMP_(ULONG) CISFMenuCallback::AddRef ()
{
return ++_cRef;
}
STDMETHODIMP_(ULONG) CISFMenuCallback::Release()
{
ASSERT(_cRef > 0);
_cRef--;
if( _cRef > 0)
return _cRef;
delete this;
return 0;
}
BOOL CISFMenuCallback::_IsVisible(LPITEMIDLIST pidl)
{
if (_poct) {
VARIANTARG v;
v.vt = VT_INT_PTR;
v.byref = pidl;
HRESULT hr = _poct->Exec(&CGID_ISFBand, ISFBID_ISITEMVISIBLE, 0, &v, NULL);
return (hr == S_OK);
}
return FALSE;
}
HRESULT IUnknown_SeekToZero(IUnknown* punk)
{
HRESULT hres = E_FAIL;
IStream* pstm;
if (punk && SUCCEEDED(punk->QueryInterface(IID_IStream, (void**)&pstm)))
{
// We need to seek to the beginning of the stream here. We don't do this in
// the menubands because it's rude: They should not seek to the beginning
// because there may be information that needs to be saved after them.
//Set the seek pointer at the beginning.
const LARGE_INTEGER li0 = {0};
hres = pstm->Seek(li0, STREAM_SEEK_SET, NULL);
pstm->Release();
}
return hres;
}
HRESULT CISFMenuCallback::_GetObject(LPSMDATA psmd, REFIID riid, void** ppvObj)
{
HRESULT hres = S_FALSE;
*ppvObj = NULL;
if (IsEqualIID(riid, IID_IStream))
{
if (_pidl && psmd->pidlFolder && psmd->pidlItem)
{
// Verify that the Cascading menuband is ONLY asking for this folder.
// because if there is a sub menu, It's going to ask again with the
// pidl of that folder, which we don't have the Stream for, and we
// can hose things pretty good if we indescriminatly hand out order streams
LPITEMIDLIST pidlFull = ILCombine(psmd->pidlFolder, psmd->pidlItem);
if (pidlFull)
{
if (_poct && ILIsEqual(pidlFull, _pidl))
{
VARIANTARG v = {0};
v.vt = VT_UNKNOWN;
hres = _poct->Exec(&CGID_ISFBand, ISFBID_GETORDERSTREAM, 0, NULL, &v);
if (SUCCEEDED(hres))
{
IUnknown_SeekToZero(v.punkVal);
hres = v.punkVal->QueryInterface(riid, ppvObj);
v.punkVal->Release();
}
}
ILFree(pidlFull);
}
}
}
return hres;
}
HRESULT CISFMenuCallback::_SetObject(LPSMDATA psmd, REFIID riid, void** ppvObj)
{
HRESULT hres = E_FAIL;
if (IsEqualIID(riid, IID_IStream))
{
if (_pidl && psmd->pidlFolder && psmd->pidlItem)
{
// Verify that the Cascading menuband is ONLY asking for this folder.
// because if there is a sub menu, It's going to ask again with the
// pidl of that folder, which we don't have the Stream for, and we
// can hose things pretty good if we indescriminatly hand out order streams
LPITEMIDLIST pidlFull = ILCombine(psmd->pidlFolder, psmd->pidlItem);
if (pidlFull)
{
if (_poct && ILIsEqual(pidlFull, _pidl))
{
ASSERT(ppvObj);
VARIANTARG v;
v.vt = VT_UNKNOWN;
v.punkVal = *(IUnknown**)ppvObj;
IUnknown_SeekToZero(*(IUnknown**)ppvObj);
hres = _poct->Exec(&CGID_ISFBand, ISFBID_SETORDERSTREAM, 0, &v, NULL);
}
ILFree(pidlFull);
}
}
}
return hres;
}
HRESULT CISFMenuCallback::_GetSFInfo(LPSMDATA psmd, PSMINFO psminfo)
{
// We only want to filter pidls if:
// 1) It's at the root of the links chevron menu
// 2) It's _IS_ visible in the links bar. We don't want to show links
// in this menu that are visible.
if (psmd->uIdAncestor == ANCESTORDEFAULT &&
(psminfo->dwMask & SMIM_FLAGS) &&
_IsVisible(psmd->pidlItem))
{
// not obscured on the subject isfband; exclude from menu
psminfo->dwFlags |= SMIF_HIDDEN;
}
return S_OK;
}
// *** IShellMenuCallback methods ***
STDMETHODIMP CISFMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr = S_FALSE;
switch (uMsg)
{
case SMC_SFEXEC:
hr = SHNavigateToFavorite(psmd->psf, psmd->pidlItem, _punkSite, SBSP_DEFBROWSER | SBSP_DEFMODE);
break;
case SMC_GETSFINFO:
hr = _GetSFInfo(psmd, (PSMINFO)lParam);
break;
case SMC_GETSFOBJECT:
hr = _GetObject(psmd, *((GUID*)wParam), (void**)lParam);
break;
case SMC_SETSFOBJECT:
hr = _SetObject(psmd, *((GUID*)wParam), (void**)lParam);
break;
}
return hr;
}
// *** IObjectWithSite methods ***
STDMETHODIMP CISFMenuCallback::SetSite(IUnknown* punkSite)
{
if (punkSite != _punkSite)
IUnknown_Set(&_punkSite, punkSite);
return S_OK;
}
HRESULT CISFMenuCallback::Initialize(IUnknown* punk)
{
HRESULT hr = E_FAIL;
if (punk)
hr = punk->QueryInterface(IID_IOleCommandTarget, (PVOID*)&_poct);
IShellFolderBand* psfb;
hr = punk->QueryInterface(IID_IShellFolderBand, (PVOID*)&psfb);
if (SUCCEEDED(hr))
{
BANDINFOSFB bi;
bi.dwMask = ISFB_MASK_IDLIST | ISFB_MASK_SHELLFOLDER;
hr = psfb->GetBandInfoSFB(&bi);
_pidl = bi.pidl;
if (bi.psf)
bi.psf->Release();
psfb->Release();
}
return hr;
}
CISFMenuCallback::CISFMenuCallback() : _cRef(1)
{
}
CISFMenuCallback::~CISFMenuCallback()
{
ASSERT(_cRef == 0);
ILFree(_pidl);
ATOMICRELEASE(_poct);
}