Windows2000/private/shell/shell32/unicpp/sdflditm.cpp
2020-09-30 17:12:32 +02:00

1101 lines
28 KiB
C++

#include "stdafx.h"
#pragma hdrstop
#include "prop.h"
#define TF_SHELLAUTO TF_CUSTOM1
#define CMD_ID_FIRST 1
#define CMD_ID_LAST 0x7fff
#define DEFINE_FLOAT_STUFF // Do this because DATE is being used below
class CFolderItemVerbs;
class CEnumFolderItemVerbs;
class CFolderItemVerb;
HRESULT CFolderItemVerbs_Create(CFolderItem *psdfi, FolderItemVerbs **ppid);
class CFolderItemVerbs : public FolderItemVerbs,
public CObjectSafety,
protected CImpIDispatch
{
friend class CEnumFolderItemVerbs;
friend class CFolderItemVerb;
public:
CFolderItemVerbs(CFolderItem *psdfi);
BOOL Init(void);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IDispatch
virtual STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
{ return CImpIDispatch::GetTypeInfoCount(pctinfo); }
virtual STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
{ return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
virtual STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
{ return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
virtual STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
{ return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
// FolderItemVerbs
STDMETHODIMP get_Application(IDispatch **ppid);
STDMETHODIMP get_Parent(IDispatch **ppid);
STDMETHODIMP get_Count(long *plCount);
STDMETHODIMP Item(VARIANT, FolderItemVerb**);
STDMETHODIMP _NewEnum(IUnknown **);
private:
~CFolderItemVerbs(void);
LONG m_cRef;
CFolderItem *m_psdfi;
HMENU m_hmenu;
IContextMenu *m_pcm;
};
class CEnumFolderItemVerbs : public IEnumVARIANT,
public CObjectSafety
{
public:
CEnumFolderItemVerbs(CFolderItemVerbs *psdfiv);
BOOL Init();
// IUnknown
STDMETHODIMP QueryInterface(REFIID, void **);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IEnumFORMATETC
STDMETHODIMP Next(ULONG, VARIANT *, ULONG *);
STDMETHODIMP Skip(ULONG);
STDMETHODIMP Reset(void);
STDMETHODIMP Clone(IEnumVARIANT **);
private:
~CEnumFolderItemVerbs();
LONG m_cRef;
int m_iCur;
CFolderItemVerbs *m_psdfiv;
};
HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **pfiv);
class CFolderItemVerb :
public FolderItemVerb,
public CObjectSafety,
protected CImpIDispatch
{
friend class CFolderItemVerbs;
public:
CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id);
// IUnknown
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
// IDispatch
virtual STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
{ return CImpIDispatch::GetTypeInfoCount(pctinfo); }
virtual STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
{ return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
virtual STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
{ return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
virtual STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
{ return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
// FolderItemVerbs
STDMETHODIMP get_Application(IDispatch **ppid);
STDMETHODIMP get_Parent(IDispatch **ppid);
STDMETHODIMP get_Name(BSTR *pbs);
STDMETHODIMP DoIt();
private:
~CFolderItemVerb(void);
LONG m_cRef;
CFolderItemVerbs *m_psdfivs;
UINT m_id;
};
// in:
// psdf folder that contains pidl
// pidl pidl retlative to psdf (the item in this folder)
HRESULT CFolderItem_Create(CFolder *psdf, LPCITEMIDLIST pidl, FolderItem **ppid)
{
*ppid = NULL;
HRESULT hr = E_OUTOFMEMORY;
CFolderItem* psdfi = new CFolderItem();
if (psdfi)
{
hr = psdfi->Init(psdf, pidl);
if (SUCCEEDED(hr))
hr = psdfi->QueryInterface(IID_FolderItem, (void **)ppid);
psdfi->Release();
}
return hr;
}
// in:
// pidl fully qualified pidl
// hwnd hacks
HRESULT CFolderItem_CreateFromIDList(HWND hwnd, LPCITEMIDLIST pidl, FolderItem **ppfi)
{
HRESULT hr;
LPITEMIDLIST pidlParent = ILClone(pidl);
if (pidlParent)
{
ILRemoveLastID(pidlParent);
CFolder *psdf;
hr = CFolder_Create2(hwnd, pidlParent, NULL, &psdf);
if (SUCCEEDED(hr))
{
hr = CFolderItem_Create(psdf, ILFindLastID(pidl), ppfi);
psdf->Release();
}
ILFree(pidlParent);
}
else
hr = E_OUTOFMEMORY;
return hr;
}
CFolderItem::CFolderItem() :
m_cRef(1), m_psdf(NULL), m_pidl(NULL),
CImpIDispatch(&LIBID_Shell32, 1, 0, &IID_FolderItem2)
{
DllAddRef();
}
CFolderItem::~CFolderItem(void)
{
if (m_pidl)
ILFree(m_pidl);
m_psdf->Release();
DllRelease();
}
HRESULT CFolderItem::Init(CFolder *psdf, LPCITEMIDLIST pidl)
{
m_psdf = psdf;
m_psdf->AddRef();
return SHILClone(pidl, &m_pidl);
}
STDMETHODIMP CFolderItem::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CFolderItem, FolderItem2),
QITABENTMULTI(CFolderItem, FolderItem, FolderItem2),
QITABENTMULTI(CFolderItem, IDispatch, FolderItem2),
QITABENTMULTI(CFolderItem, IPersist, IPersistFolder2),
QITABENTMULTI(CFolderItem, IPersistFolder, IPersistFolder2),
QITABENT(CFolderItem, IPersistFolder2),
QITABENT(CFolderItem, IObjectSafety),
{ 0 },
};
HRESULT hr = QISearch(this, qit, riid, ppv);
if (FAILED(hr) && IsEqualGUID(CLSID_ShellFolderItem, riid))
{
*ppv = (CFolderItem *)this; // unrefed
hr = S_OK;
}
return hr;
}
STDMETHODIMP_(ULONG) CFolderItem::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CFolderItem::Release(void)
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
//The FolderItem implementation
STDMETHODIMP CFolderItem::get_Application(IDispatch **ppid)
{
// Let the folder object handle security and reference counting of site, etc
return m_psdf->get_Application(ppid);
}
STDMETHODIMP CFolderItem::get_Parent(IDispatch **ppid)
{
// Assume that the Folder object is the parent of this object...
HRESULT hr = m_psdf->QueryInterface(IID_IDispatch, (void **)ppid);
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)ppid);
return hr;
}
HRESULT CFolderItem::_ItemName(UINT dwFlags, BSTR *pbs)
{
HRESULT hr = S_OK;
STRRET strret;
if (SUCCEEDED(m_psdf->m_psf->GetDisplayNameOf(m_pidl, dwFlags, &strret)))
{
*pbs = StrRetToBStr(m_pidl, &strret);
}
else
{
*pbs = SysAllocString(L"");
hr = S_FALSE;
}
return *pbs ? hr : E_OUTOFMEMORY;
}
STDMETHODIMP CFolderItem::get_Name(BSTR *pbs)
{
return _ItemName(SHGDN_INFOLDER, pbs);
}
STDMETHODIMP CFolderItem::put_Name(BSTR bs)
{
HRESULT hr;
LPITEMIDLIST pidlOut;
if (_SecurityVetosRequest())
return E_ACCESSDENIED;
hr = m_psdf->m_psf->SetNameOf(m_psdf->m_hwnd, m_pidl, bs, SHGDN_INFOLDER, &pidlOut);
if (SUCCEEDED(hr))
{
ILFree(m_pidl);
m_pidl = pidlOut;
}
return hr;
}
// BUGBUG: this should validate that the path is a file system
// object (SFGAO_FILESYSTEM)
STDMETHODIMP CFolderItem::get_Path(BSTR *pbs)
{
return _ItemName(SHGDN_FORPARSING, pbs);
}
STDMETHODIMP CFolderItem::get_GetLink(IDispatch **ppid)
{
HRESULT hr = CShortcut_CreateIDispatch(m_psdf->m_hwnd, m_psdf->m_psf, m_pidl, ppid);
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)ppid);
return hr;
}
// BUGBUG:: this should return Folder **...
STDMETHODIMP CFolderItem::get_GetFolder(IDispatch **ppid /* Folder **ppf */)
{
*ppid = NULL;
// If in Safe mode we fail this one...
if (_SecurityVetosRequest())
return E_ACCESSDENIED;
HRESULT hr;
LPITEMIDLIST pidl = ILCombine(m_psdf->m_pidl, m_pidl);
if (pidl)
{
hr = CFolder_Create(NULL, pidl, NULL, IID_IDispatch, (void **)ppid);
if (SUCCEEDED(hr))
{
if (_dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)ppid);
}
ILFree(pidl);
}
else
hr = E_OUTOFMEMORY;
return hr;
}
HRESULT CFolderItem::_CheckAttribute(ULONG ulAttrIn, VARIANT_BOOL * pb)
{
ULONG ulAttr = ulAttrIn;
HRESULT hr = m_psdf->m_psf->GetAttributesOf(1, (LPCITEMIDLIST*)&m_pidl, &ulAttr);
*pb = (SUCCEEDED(hr) && (ulAttr & ulAttrIn)) ? VARIANT_TRUE : VARIANT_FALSE;
return hr;
}
HRESULT CFolderItem::_GetUIObjectOf(REFIID riid, void **ppv)
{
return m_psdf->m_psf->GetUIObjectOf(m_psdf->m_hwnd, 1, (LPCITEMIDLIST*)&m_pidl, riid, NULL, ppv);
}
// returns:
// TRUE fail the call due to security
// FALSE OK, go for it
BOOL CFolderItem::_SecurityVetosRequest(void)
{
if (!_dwSafetyOptions)
return FALSE; // We are not running in safe mode so say everything is OK...
if (!m_psdf)
return TRUE;
return IsSafePage(m_psdf->_punkSite) != S_OK;
}
// allow friend classes to get the IDList for a CFolderItem automation object
LPCITEMIDLIST CFolderItem::_GetIDListFromVariant(const VARIANT *pv)
{
LPCITEMIDLIST pidl = NULL;
if (pv)
{
VARIANT v;
if (pv->vt == (VT_BYREF | VT_VARIANT) && pv->pvarVal)
v = *pv->pvarVal;
else
v = *pv;
switch (v.vt)
{
case VT_DISPATCH | VT_BYREF:
if (v.ppdispVal == NULL)
break;
v.pdispVal = *v.ppdispVal;
// fall through...
case VT_DISPATCH:
CFolderItem *pfi;
if (v.pdispVal && SUCCEEDED(v.pdispVal->QueryInterface(CLSID_ShellFolderItem, (void **)&pfi)))
{
pidl = pfi->m_pidl; // alias
}
break;
}
}
return pidl;
}
STDMETHODIMP CFolderItem::get_IsLink(VARIANT_BOOL * pb)
{
return _CheckAttribute(SFGAO_LINK, pb);
}
STDMETHODIMP CFolderItem::get_IsFolder(VARIANT_BOOL * pb)
{
return _CheckAttribute(SFGAO_FOLDER, pb);
}
STDMETHODIMP CFolderItem::get_IsFileSystem(VARIANT_BOOL * pb)
{
return _CheckAttribute(SFGAO_FILESYSTEM, pb);
}
STDMETHODIMP CFolderItem::get_IsBrowsable(VARIANT_BOOL * pb)
{
return _CheckAttribute(SFGAO_BROWSABLE, pb);
}
STDMETHODIMP CFolderItem::get_ModifyDate(DATE *pdt)
{
WIN32_FIND_DATA finddata;
if (SUCCEEDED(SHGetDataFromIDList(m_psdf->m_psf, m_pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
{
WORD wDosDate, wDosTime;
FILETIME filetime;
FileTimeToLocalFileTime(&finddata.ftLastWriteTime, &filetime);
FileTimeToDosDateTime(&filetime, &wDosDate, &wDosTime);
DosDateTimeToVariantTime(wDosDate, wDosTime, pdt);
}
return NOERROR;
}
STDMETHODIMP CFolderItem::put_ModifyDate(DATE dt)
{
HRESULT hr = S_FALSE;
SYSTEMTIME st;
FILETIME ftLocal, ft;
BSTR bstrPath;
if (SUCCEEDED(VariantTimeToSystemTime(dt, &st)) && SystemTimeToFileTime(&st, &ftLocal) && LocalFileTimeToFileTime(&ftLocal, &ft) && SUCCEEDED(get_Path(&bstrPath)))
{
TCHAR szPath[MAX_PATH];
SHUnicodeToTChar(bstrPath, szPath, ARRAYSIZE(szPath));
SysFreeString(bstrPath);
HANDLE hFile = CreateFile(szPath, GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_OPEN_NO_RECALL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
if (SetFileTime(hFile, NULL, NULL, &ft))
{
hr = S_OK;
}
CloseHandle(hFile);
}
}
return hr;
}
// BUGBUG:: Should see about getting larger numbers through
STDMETHODIMP CFolderItem::get_Size(LONG *pul)
{
WIN32_FIND_DATA finddata;
if (SUCCEEDED(SHGetDataFromIDList(m_psdf->m_psf, m_pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
{
*pul = (LONG)finddata.nFileSizeLow;
}
else
{
*pul = 0L;
}
return NOERROR; // Scripts don't like error return values
}
STDMETHODIMP CFolderItem::get_Type(BSTR *pbs)
{
VARIANT var;
var.vt = VT_EMPTY;
if (SUCCEEDED(ExtendedProperty(L"Type", &var)) && var.vt == VT_BSTR)
{
*pbs = SysAllocString(var.bstrVal);
}
else
{
*pbs = SysAllocString(L"");
}
VariantClear(&var);
return *pbs ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP CFolderItem::ExtendedProperty(BSTR bstrPropName, VARIANT *pvRet)
{
HRESULT hr = S_OK; // Java scripts barf on E_FAIL
pvRet->vt = VT_EMPTY;
// currently, MCNL is 80, guidstr is 39, and 6 is the width of an int
if (StrCmpIW(bstrPropName, L"infotip") == 0)
{
// They want the info tip for the item.
if (m_pidl && m_psdf)
{
TCHAR szInfo[INFOTIPSIZE];
GetInfoTip(m_psdf->m_psf, m_pidl, szInfo, ARRAYSIZE(szInfo));
hr = InitVariantFromStr(pvRet, szInfo);
}
}
else if (m_psdf->m_psf2)
{
SHCOLUMNID scid;
TCHAR szTemp[128];
SHUnicodeToTChar(bstrPropName, szTemp, ARRAYSIZE(szTemp));
if (ParseSCIDString(szTemp, &scid, NULL))
{
// Note that GetDetailsEx expects an absolute pidl
m_psdf->m_psf2->GetDetailsEx(m_pidl, &scid, pvRet);
}
}
return hr;
}
STDMETHODIMP CFolderItem::Verbs(FolderItemVerbs **ppfic)
{
HRESULT hr = CFolderItemVerbs_Create(SAFECAST(this, CFolderItem*), ppfic);
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)ppfic);
return hr;
}
// Helper function to invoke a verb on an array of pidls.
HRESULT InvokeVerbHelper(VARIANT vVerb, VARIANT vArgs, LPCITEMIDLIST *ppidl, int cItems, DWORD dwSafetyOptions, CFolder * psdf)
{
IContextMenu *pcm;
BOOL fDefaultVerb = TRUE;
TCHAR szCmd[128];
TCHAR szURL[MAX_URL_STRING];
DWORD dwPolicy = 0, dwContext = 0;
BOOL bSafeZone;
MENUITEMINFO mii;
bSafeZone = !dwSafetyOptions || (psdf->_punkSite && IsSafePage(psdf->_punkSite) == S_OK);
switch (vVerb.vt)
{
case VT_BSTR:
if (!bSafeZone)
return E_ACCESSDENIED; // not allowed in safe mode
fDefaultVerb = FALSE;
SHUnicodeToTChar(vVerb.bstrVal, szCmd, ARRAYSIZE(szCmd));
break;
}
// Do a zones check
if (!bSafeZone)
{
LPITEMIDLIST pidl;
for (int i = 0; i < cItems; i++)
{
pidl = ILCombine(psdf->m_pidl, ppidl[i]);
if (pidl)
{
SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szURL, SIZECHARS(szURL), NULL);
ILFree(pidl);
ZoneCheckUrlEx(szURL, &dwPolicy, SIZEOF(dwPolicy), &dwContext, SIZEOF(dwContext),
URLACTION_SHELL_VERB, PUAF_NOUI, NULL);
dwPolicy = GetUrlPolicyPermissions(dwPolicy);
if (dwPolicy != URLPOLICY_ALLOW)
{
return E_ACCESSDENIED;
}
}
}
}
if (SUCCEEDED(psdf->m_psf->GetUIObjectOf(psdf->m_hwnd, cItems, ppidl, IID_IContextMenu, NULL, (void **)&pcm)) && pcm)
{
HMENU hmenu = CreatePopupMenu();
pcm->QueryContextMenu(hmenu, 0, CMD_ID_FIRST, CMD_ID_LAST, fDefaultVerb ? CMF_DEFAULTONLY : CMF_CANRENAME);
int idCmd = 0, iItem;
if (fDefaultVerb)
idCmd = GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0);
else
{
// Lets try to find a verb that matches name:
// BUGBUG:: Right now must match & in verbs...
int i;
MENUITEMINFO mii;
TCHAR szText[128]; // should be big enough for this
for (i = GetMenuItemCount(hmenu)-1; i >= 0; i--)
{
mii.cbSize = sizeof(MENUITEMINFO);
mii.dwTypeData = szText;
mii.fMask = MIIM_ID | MIIM_TYPE;
mii.cch = ARRAYSIZE(szText);
mii.fType = MFT_SEPARATOR; // to avoid ramdom result.
mii.dwItemData = 0;
GetMenuItemInfo(hmenu, i, TRUE, &mii);
if (lstrcmpi(szText, szCmd) == 0)
{
idCmd = mii.wID;
break;
}
}
}
// If we couldn't find it the old way see if it is a canonical verb
if (!idCmd && (-1 != (iItem = GetMenuIndexForCanonicalVerb(hmenu, pcm, CMD_ID_FIRST, vVerb.bstrVal))))
{
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_ID;
if (GetMenuItemInfo(hmenu, iItem, MF_BYPOSITION, &mii))
idCmd = mii.wID;
}
if (idCmd)
{
CMINVOKECOMMANDINFO ici = {
sizeof(CMINVOKECOMMANDINFO),
0L,
psdf->m_hwnd,
NULL,
NULL, NULL,
SW_SHOWNORMAL,
};
ici.lpVerb = (LPSTR)MAKEINTRESOURCE(idCmd - CMD_ID_FIRST);
char szArgs[MAX_PATH]; // max size we will currently use.
// See if we are supposed to pass any arguments on the command line
switch (vArgs.vt)
{
case VT_BSTR:
SHUnicodeToAnsi(vArgs.bstrVal, szArgs, ARRAYSIZE(szArgs));
ici.lpParameters = szArgs;
break;
}
// Finally invoke the command
pcm->InvokeCommand(&ici);
}
DestroyMenu(hmenu);
pcm->Release();
}
return NOERROR;
}
STDMETHODIMP CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
{
return InvokeVerbHelper(vVerb, vArgs, (LPCITEMIDLIST *)&m_pidl, 1, _dwSafetyOptions, m_psdf);
}
STDMETHODIMP CFolderItem::InvokeVerb(VARIANT vVerb)
{
VARIANT vtEmpty = {VT_EMPTY};
return InvokeVerbEx(vVerb, vtEmpty);
}
STDMETHODIMP CFolderItem::GetClassID(CLSID *pClassID)
{
*pClassID = CLSID_ShellFolderItem;
return E_NOTIMPL;
}
STDMETHODIMP CFolderItem::Initialize(LPCITEMIDLIST pidl)
{
return E_NOTIMPL;
}
STDMETHODIMP CFolderItem::GetCurFolder(LPITEMIDLIST *ppidl)
{
LPITEMIDLIST pidlFolder;
HRESULT hr = SHGetIDListFromUnk(m_psdf->m_psf, &pidlFolder);
if (S_OK == hr)
{
hr = SHILCombine(pidlFolder, m_pidl, ppidl);
ILFree(pidlFolder);
}
else
hr = E_FAIL;
return hr;
}
HRESULT CFolderItemVerbs_Create(CFolderItem *psdfi, FolderItemVerbs ** ppid)
{
*ppid = NULL;
HRESULT hr = E_OUTOFMEMORY;
CFolderItemVerbs* pfiv = new CFolderItemVerbs(psdfi);
if (pfiv)
{
if (pfiv->Init())
hr = pfiv->QueryInterface(IID_FolderItemVerbs, (void **)ppid);
pfiv->Release();
}
return hr;
}
CFolderItemVerbs::CFolderItemVerbs(CFolderItem *psdfi) :
m_cRef(1), m_hmenu(NULL), m_pcm(NULL),
m_psdfi(psdfi), CImpIDispatch(&LIBID_Shell32, 1, 0, &IID_FolderItemVerbs)
{
DllAddRef();
m_psdfi->AddRef();
}
CFolderItemVerbs::~CFolderItemVerbs(void)
{
DllRelease();
if (m_pcm)
m_pcm->Release();
if (m_hmenu)
DestroyMenu(m_hmenu);
m_psdfi->Release();
}
BOOL CFolderItemVerbs::Init()
{
TraceMsg(TF_SHELLAUTO, "CFolderItemVerbs::Init called");
// Start of only doing default verb...
if (SUCCEEDED(m_psdfi->_GetUIObjectOf(IID_IContextMenu, (void **)&m_pcm)) && m_pcm)
{
m_hmenu = CreatePopupMenu();
if (FAILED(m_pcm->QueryContextMenu(m_hmenu, 0, CMD_ID_FIRST, CMD_ID_LAST, 0)))
return FALSE;
}
else
return FALSE;
// Just for the heck of it, remove junk like sepearators from the menu...
int i;
MENUITEMINFO mii;
TCHAR szText[80]; // should be big enough for this
for (i = GetMenuItemCount(m_hmenu) - 1; i >= 0; i--)
{
mii.cbSize = sizeof(MENUITEMINFO);
mii.dwTypeData = szText;
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.cch = ARRAYSIZE(szText);
mii.fType = MFT_SEPARATOR; // to avoid ramdom result.
mii.dwItemData = 0;
GetMenuItemInfo(m_hmenu, i, TRUE, &mii);
if (mii.fType & MFT_SEPARATOR)
DeleteMenu(m_hmenu, i, MF_BYPOSITION);
}
return TRUE;
}
STDMETHODIMP CFolderItemVerbs::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CFolderItemVerbs, FolderItemVerbs),
QITABENT(CFolderItemVerbs, IObjectSafety),
QITABENTMULTI(CFolderItemVerbs, IDispatch, FolderItemVerbs),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CFolderItemVerbs::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CFolderItemVerbs::Release(void)
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
STDMETHODIMP CFolderItemVerbs::get_Application(IDispatch **ppid)
{
return m_psdfi->get_Application(ppid);
}
STDMETHODIMP CFolderItemVerbs::get_Parent(IDispatch **ppid)
{
*ppid = NULL;
return E_NOTIMPL;
}
STDMETHODIMP CFolderItemVerbs::get_Count(long *plCount)
{
*plCount = 0;
if (m_psdfi->_SecurityVetosRequest())
return E_ACCESSDENIED;
*plCount = GetMenuItemCount(m_hmenu);
return NOERROR;
}
STDMETHODIMP CFolderItemVerbs::Item(VARIANT index, FolderItemVerb **ppid)
{
*ppid = NULL;
if (m_psdfi->_SecurityVetosRequest())
return E_ACCESSDENIED;
// This is sortof gross, but if we are passed a pointer to another variant, simply
// update our copy here...
if (index.vt == (VT_BYREF | VT_VARIANT) && index.pvarVal)
index = *index.pvarVal;
switch (index.vt)
{
case VT_ERROR:
QueryInterface(IID_IDispatch, (void **)ppid);
break;
case VT_I2:
index.lVal = (long)index.iVal;
// And fall through...
case VT_I4:
if ((index.lVal >= 0) && (index.lVal <= GetMenuItemCount(m_hmenu)))
{
CFolderItemVerb_Create(this, GetMenuItemID(m_hmenu, index.lVal), ppid);
}
break;
#ifdef LATER // Should match strings in menu...
case VT_BSTR:
{
// map canonical name into item id
if (SUCCEEDED(hr))
{
CFolderItemVerb_Create(this, GetMenuItemID(index.lVal), ppid);
}
return hr;
}
break;
#endif // Later
default:
return E_NOTIMPL;
}
if (*ppid && _dwSafetyOptions)
return MakeSafeForScripting((IUnknown**)ppid);
return NOERROR;
}
STDMETHODIMP CFolderItemVerbs::_NewEnum(IUnknown **ppunk)
{
*ppunk = NULL;
if (m_psdfi->_SecurityVetosRequest())
return E_ACCESSDENIED;
HRESULT hr = E_OUTOFMEMORY;
CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(SAFECAST(this, CFolderItemVerbs*));
if (pNew)
{
if (pNew->Init())
hr = pNew->QueryInterface(IID_IEnumVARIANT, (void **)ppunk);
pNew->Release();
}
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting(ppunk);
return hr;
}
CEnumFolderItemVerbs::CEnumFolderItemVerbs(CFolderItemVerbs *pfiv) :
m_cRef(1), m_iCur(0), m_psdfiv(pfiv)
{
m_psdfiv->AddRef();
DllAddRef();
}
CEnumFolderItemVerbs::~CEnumFolderItemVerbs(void)
{
DllRelease();
m_psdfiv->Release();
}
BOOL CEnumFolderItemVerbs::Init()
{
return TRUE; // Currently no initialization needed
}
STDMETHODIMP CEnumFolderItemVerbs::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CEnumFolderItemVerbs, IEnumVARIANT),
QITABENT(CEnumFolderItemVerbs, IObjectSafety),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::Release(void)
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
STDMETHODIMP CEnumFolderItemVerbs::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar)
{
ULONG cReturn = 0;
HRESULT hr;
if (!pulVar)
{
if (cVar != 1)
return E_POINTER;
}
else
*pulVar = 0;
if (!pVar || m_iCur >= GetMenuItemCount(m_psdfiv->m_hmenu))
return S_FALSE;
while (m_iCur < GetMenuItemCount(m_psdfiv->m_hmenu) && cVar > 0)
{
FolderItemVerb *pidv;
hr = CFolderItemVerb_Create(m_psdfiv, GetMenuItemID(m_psdfiv->m_hmenu, m_iCur), &pidv);
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)&pidv);
m_iCur++;
if (SUCCEEDED(hr))
{
pVar->pdispVal = pidv;
pVar->vt = VT_DISPATCH;
pVar++;
cReturn++;
cVar--;
}
}
if (pulVar)
*pulVar = cReturn;
return NOERROR;
}
STDMETHODIMP CEnumFolderItemVerbs::Skip(ULONG cSkip)
{
if ((int)(m_iCur+cSkip) >= GetMenuItemCount(m_psdfiv->m_hmenu))
return S_FALSE;
m_iCur+=cSkip;
return NOERROR;
}
STDMETHODIMP CEnumFolderItemVerbs::Reset(void)
{
m_iCur = 0;
return NOERROR;
}
STDMETHODIMP CEnumFolderItemVerbs::Clone(IEnumVARIANT **ppEnum)
{
*ppEnum = NULL;
HRESULT hr = E_OUTOFMEMORY;
CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(m_psdfiv);
if (pNew)
{
if (pNew->Init())
hr = pNew->QueryInterface(IID_IEnumVARIANT, (void **)ppEnum);
pNew->Release();
}
if (SUCCEEDED(hr) && _dwSafetyOptions)
hr = MakeSafeForScripting((IUnknown**)ppEnum);
return hr;
}
HRESULT CFolderItemVerb_Create(CFolderItemVerbs *psdfivs, UINT id, FolderItemVerb **ppid)
{
*ppid = NULL;
HRESULT hr = E_OUTOFMEMORY;
CFolderItemVerb* psdfiv = new CFolderItemVerb(psdfivs, id);
if (psdfiv)
{
hr = psdfiv->QueryInterface(IID_FolderItemVerb, (void **)ppid);
psdfiv->Release();
}
return hr;
}
CFolderItemVerb::CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id) :
m_cRef(1), m_psdfivs(psdfivs), m_id(id),
CImpIDispatch(&LIBID_Shell32, 1, 0, &IID_FolderItemVerb)
{
m_psdfivs->AddRef();
DllAddRef();
}
CFolderItemVerb::~CFolderItemVerb(void)
{
DllRelease();
m_psdfivs->Release();
}
STDMETHODIMP CFolderItemVerb::QueryInterface(REFIID riid, void **ppv)
{
static const QITAB qit[] = {
QITABENT(CFolderItemVerb, FolderItemVerb),
QITABENT(CFolderItemVerb, IObjectSafety),
QITABENTMULTI(CFolderItemVerb, IDispatch, FolderItemVerb),
{ 0 },
};
return QISearch(this, qit, riid, ppv);
}
STDMETHODIMP_(ULONG) CFolderItemVerb::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CFolderItemVerb::Release(void)
{
if (InterlockedDecrement(&m_cRef))
return m_cRef;
delete this;
return 0;
}
STDMETHODIMP CFolderItemVerb::get_Application(IDispatch **ppid)
{
return m_psdfivs->get_Application(ppid);
}
STDMETHODIMP CFolderItemVerb::get_Parent(IDispatch **ppid)
{
*ppid = NULL;
return E_NOTIMPL;
}
STDMETHODIMP CFolderItemVerb::get_Name(BSTR *pbs)
{
TCHAR szMenuText[MAX_PATH];
// Warning: did not check security here as could not get here if unsafe...
GetMenuString(m_psdfivs->m_hmenu, m_id, szMenuText, ARRAYSIZE(szMenuText), MF_BYCOMMAND);
*pbs = SysAllocStringT(szMenuText);
return *pbs ? S_OK : E_OUTOFMEMORY;
}
STDMETHODIMP CFolderItemVerb::DoIt()
{
CMINVOKECOMMANDINFO ici = {
sizeof(CMINVOKECOMMANDINFO),
0L,
NULL,
NULL,
NULL, NULL,
SW_SHOWNORMAL,
};
// Warning: did not check security here as could not get here if unsafe...
ici.lpVerb = (LPSTR)MAKEINTRESOURCE(m_id - CMD_ID_FIRST);
return m_psdfivs->m_pcm->InvokeCommand(&ici);
}