1148 lines
29 KiB
C++
1148 lines
29 KiB
C++
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
// BUGBUG: from shell32\prop.cpp
|
|
STDAPI_(BOOL) ParseSCIDString(LPCTSTR pszString, SHCOLUMNID *pscid, UINT *pidRes);
|
|
|
|
#define TF_SHELLAUTO TF_CUSTOM1
|
|
|
|
#define DEFINE_FLOAT_STUFF // Do this because DATE is being used below
|
|
|
|
class CFolderItemVerbs;
|
|
class CEnumFolderItemVerbs;
|
|
class CFolderItemVerb;
|
|
|
|
class CFolderItemVerbs : public FolderItemVerbs,
|
|
public CObjectSafety,
|
|
protected CImpIDispatch,
|
|
protected CObjectWithSite
|
|
{
|
|
friend class CEnumFolderItemVerbs;
|
|
friend class CFolderItemVerb;
|
|
|
|
public:
|
|
CFolderItemVerbs(IContextMenu *pcm);
|
|
BOOL Init(void);
|
|
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
// IDispatch
|
|
STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
|
|
{ return CImpIDispatch::GetTypeInfoCount(pctinfo); }
|
|
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
|
|
{ return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
|
|
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
|
|
{ return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
|
|
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);
|
|
HRESULT _SecurityCheck();
|
|
LONG _cRef;
|
|
HMENU _hmenu;
|
|
IContextMenu *_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 _cRef;
|
|
int _iCur;
|
|
CFolderItemVerbs *_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
|
|
STDMETHODIMP GetTypeInfoCount(UINT * pctinfo)
|
|
{ return CImpIDispatch::GetTypeInfoCount(pctinfo); }
|
|
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
|
|
{ return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
|
|
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid)
|
|
{ return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
|
|
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 _cRef;
|
|
CFolderItemVerbs *_psdfivs;
|
|
UINT _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_PPV_ARG(FolderItem, ppid));
|
|
psdfi->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDAPI CFolderItem_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
*ppv = NULL;
|
|
|
|
CFolderItem *pfi = new CFolderItem();
|
|
if (pfi)
|
|
{
|
|
hr = pfi->QueryInterface(riid, ppv);
|
|
pfi->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
// in:
|
|
// pidl fully qualified pidl
|
|
// hwnd hacks
|
|
|
|
HRESULT CFolderItem_CreateFromIDList(HWND hwnd, LPCITEMIDLIST pidl, FolderItem **ppfi)
|
|
{
|
|
LPITEMIDLIST pidlParent;
|
|
HRESULT hr = SHILClone(pidl, &pidlParent);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
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);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
CFolderItem::CFolderItem() :
|
|
_cRef(1), _psdf(NULL), _pidl(NULL),
|
|
CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItem2)
|
|
{
|
|
DllAddRef();
|
|
}
|
|
|
|
|
|
CFolderItem::~CFolderItem(void)
|
|
{
|
|
if (_pidl)
|
|
ILFree(_pidl);
|
|
if (_psdf)
|
|
_psdf->Release();
|
|
DllRelease();
|
|
}
|
|
|
|
HRESULT GetItemFolder(CFolder *psdfRoot, LPCITEMIDLIST pidl, CFolder **ppsdf)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(psdfRoot);
|
|
|
|
if (ILFindLastID(pidl) != pidl)
|
|
{
|
|
LPITEMIDLIST pidlIn = ILClone(pidl);
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
if (pidlIn && ILRemoveLastID(pidlIn))
|
|
{
|
|
LPITEMIDLIST pidlParent;
|
|
LPITEMIDLIST pidlFolder = NULL;
|
|
|
|
hr = psdfRoot->GetCurFolder(&pidlFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pidlParent = ILCombine(pidlFolder, pidlIn);
|
|
if (pidlParent)
|
|
{
|
|
hr = CFolder_Create2(NULL, pidlParent, NULL, ppsdf);
|
|
ILFree(pidlParent);
|
|
}
|
|
ILFree(pidlFolder);
|
|
}
|
|
}
|
|
ILFree(pidlIn);// ilfree does null check
|
|
}
|
|
else
|
|
{
|
|
*ppsdf = psdfRoot;
|
|
psdfRoot->AddRef();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFolderItem::Init(CFolder *psdf, LPCITEMIDLIST pidl)
|
|
{
|
|
HRESULT hr = GetItemFolder(psdf, pidl, &_psdf);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHILClone(ILFindLastID(pidl), &_pidl);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
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),
|
|
QITABENT(CFolderItem, IParentAndItem),
|
|
{ 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(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CFolderItem::Release(void)
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _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 _psdf->get_Application(ppid);
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::get_Parent(IDispatch **ppid)
|
|
{
|
|
// Assume that the Folder object is the parent of this object...
|
|
HRESULT hr = _psdf->QueryInterface(IID_PPV_ARG(IDispatch, ppid));
|
|
if (SUCCEEDED(hr) && _dwSafetyOptions)
|
|
hr = MakeSafeForScripting((IUnknown**)ppid);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFolderItem::_ItemName(UINT dwFlags, BSTR *pbs)
|
|
{
|
|
HRESULT hr;
|
|
STRRET strret;
|
|
if (SUCCEEDED(_psdf->_psf->GetDisplayNameOf(_pidl, dwFlags, &strret)))
|
|
{
|
|
hr = StrRetToBSTR(&strret, _pidl, pbs);
|
|
}
|
|
else
|
|
{
|
|
*pbs = SysAllocString(L"");
|
|
hr = (*pbs) ? S_FALSE : E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::get_Name(BSTR *pbs)
|
|
{
|
|
*pbs = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ItemName(SHGDN_INFOLDER, pbs);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::put_Name(BSTR bs)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidlOut;
|
|
hr = _psdf->_psf->SetNameOf(_psdf->_hwnd, _pidl, bs, SHGDN_INFOLDER, &pidlOut);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ILFree(_pidl);
|
|
_pidl = pidlOut;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// BUGBUG: this should validate that the path is a file system
|
|
// object (SFGAO_FILESYSTEM)
|
|
|
|
STDMETHODIMP CFolderItem::get_Path(BSTR *pbs)
|
|
{
|
|
*pbs = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = _ItemName(SHGDN_FORPARSING, pbs);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::get_GetLink(IDispatch **ppid)
|
|
{
|
|
*ppid = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CShortcut_CreateIDispatch(_psdf->_hwnd, _psdf->_psf, _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...
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
hr = SHILCombine(_psdf->_pidl, _pidl, &pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CFolder_Create(NULL, pidl, NULL, IID_PPV_ARG(IDispatch, ppid));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (_dwSafetyOptions)
|
|
{
|
|
// note, this is created without a site so script safety checks will fail
|
|
hr = MakeSafeForScripting((IUnknown**)ppid);
|
|
}
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CFolderItem::_CheckAttribute(ULONG ulAttrIn, VARIANT_BOOL * pb)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULONG ulAttr = ulAttrIn;
|
|
hr = _psdf->_psf->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &ulAttr);
|
|
*pb = (SUCCEEDED(hr) && (ulAttr & ulAttrIn)) ? VARIANT_TRUE : VARIANT_FALSE;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CFolderItem::_GetUIObjectOf(REFIID riid, void **ppv)
|
|
{
|
|
return _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, 1, (LPCITEMIDLIST*)&_pidl, riid, NULL, ppv);
|
|
}
|
|
|
|
|
|
HRESULT CFolderItem::_SecurityCheck()
|
|
{
|
|
if (!_dwSafetyOptions)
|
|
return S_OK;
|
|
|
|
return _psdf->_SecurityCheck();
|
|
}
|
|
|
|
// 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->_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)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WIN32_FIND_DATA finddata;
|
|
if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
|
|
{
|
|
WORD wDosDate, wDosTime;
|
|
FILETIME filetime;
|
|
FileTimeToLocalFileTime(&finddata.ftLastWriteTime, &filetime);
|
|
FileTimeToDosDateTime(&filetime, &wDosDate, &wDosTime);
|
|
DosDateTimeToVariantTime(wDosDate, wDosTime, pdt);
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::put_ModifyDate(DATE dt)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
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)
|
|
{
|
|
HRESULT hr =_SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WIN32_FIND_DATA finddata;
|
|
if (SUCCEEDED(SHGetDataFromIDList(_psdf->_psf, _pidl, SHGDFIL_FINDDATA, &finddata, sizeof(finddata))))
|
|
{
|
|
*pul = (LONG)finddata.nFileSizeLow;
|
|
}
|
|
else
|
|
{
|
|
*pul = 0L;
|
|
}
|
|
hr = S_OK; // Scripts don't like error return values
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::get_Type(BSTR *pbs)
|
|
{
|
|
*pbs = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
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);
|
|
hr = *pbs ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CFolderItem::ExtendedProperty(BSTR bstrPropName, VARIANT *pvRet)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_FAIL;
|
|
|
|
VariantInit(pvRet);
|
|
|
|
// 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 (_pidl && _psdf)
|
|
{
|
|
TCHAR szInfo[INFOTIPSIZE];
|
|
GetInfoTipHelp(_psdf->_psf, _pidl, szInfo, ARRAYSIZE(szInfo));
|
|
hr = InitVariantFromStr(pvRet, szInfo);
|
|
}
|
|
}
|
|
else if (_psdf->_psf2)
|
|
{
|
|
SHCOLUMNID scid;
|
|
TCHAR szTemp[128];
|
|
|
|
SHUnicodeToTChar(bstrPropName, szTemp, ARRAYSIZE(szTemp));
|
|
|
|
if (ParseSCIDString(szTemp, &scid, NULL))
|
|
{
|
|
// Note that GetDetailsEx expects an absolute pidl
|
|
hr = _psdf->_psf2->GetDetailsEx(_pidl, &scid, pvRet);
|
|
}
|
|
}
|
|
hr = FAILED(hr) ? S_FALSE : hr; // Java scripts barf on error values
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CFolderItem::Verbs(FolderItemVerbs **ppfic)
|
|
{
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = S_FALSE;
|
|
|
|
IContextMenu *pcm;
|
|
if (SUCCEEDED(_GetUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm))))
|
|
{
|
|
hr = CFolderItemVerbs_Create(pcm, ppfic);
|
|
if (SUCCEEDED(hr) && _dwSafetyOptions)
|
|
{
|
|
hr = MakeSafeForScripting((IUnknown**)ppfic);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Set the folder's site to FolderItemVerbs
|
|
IUnknown_SetSite(*ppfic, _psdf->_punkSite);
|
|
}
|
|
}
|
|
pcm->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
|
|
{
|
|
// security check handled by _psdf
|
|
return _psdf->InvokeVerbHelper(vVerb, vArgs, (LPCITEMIDLIST *)&_pidl, 1, _dwSafetyOptions);
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::InvokeVerb(VARIANT vVerb)
|
|
{
|
|
VARIANT vtEmpty = {VT_EMPTY};
|
|
return InvokeVerbEx(vVerb, vtEmpty);
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::GetClassID(CLSID *pClassID)
|
|
{
|
|
*pClassID = CLSID_ShellFolderItem;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
// IPersistFolder
|
|
// note, this duplicates some of CFolderItem::Init() functionality
|
|
|
|
STDMETHODIMP CFolderItem::Initialize(LPCITEMIDLIST pidl)
|
|
{
|
|
LPITEMIDLIST pidlParent;
|
|
HRESULT hr = SHILClone(pidl, &pidlParent);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(_pidl == NULL);
|
|
hr = SHILClone(ILFindLastID(pidlParent), &_pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Chop off the filename and get the folder that contains
|
|
// this FolderItem.
|
|
ILRemoveLastID(pidlParent);
|
|
|
|
// BUGBUG: we should find some way to get a valid hwnd to
|
|
// pass to CFolder_Create2 instead of NULL.
|
|
ASSERT(_psdf == NULL);
|
|
hr = CFolder_Create2(NULL, pidlParent, NULL, &_psdf);
|
|
}
|
|
ILFree(pidlParent);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::GetCurFolder(LPITEMIDLIST *ppidl)
|
|
{
|
|
LPITEMIDLIST pidlFolder;
|
|
HRESULT hr = SHGetIDListFromUnk(_psdf->_psf, &pidlFolder);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = SHILCombine(pidlFolder, _pidl, ppidl);
|
|
ILFree(pidlFolder);
|
|
}
|
|
else
|
|
hr = E_FAIL;
|
|
return hr;
|
|
}
|
|
|
|
// IParentAndItem
|
|
STDMETHODIMP CFolderItem::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidl)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItem::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl)
|
|
{
|
|
if (ppidlParent)
|
|
{
|
|
*ppidlParent = _psdf->_pidl ? ILClone(_psdf->_pidl) : NULL;
|
|
}
|
|
|
|
if (ppsf)
|
|
{
|
|
*ppsf = NULL;
|
|
if (_psdf && _psdf->_psf)
|
|
_psdf->_psf->QueryInterface(IID_PPV_ARG(IShellFolder, ppsf));
|
|
}
|
|
|
|
if (ppidl)
|
|
*ppidl = ILClone(_pidl);
|
|
|
|
|
|
if ((ppidlParent && !*ppidlParent)
|
|
|| (ppsf && !*ppsf)
|
|
|| (ppidl && !*ppidl))
|
|
{
|
|
// this is failure
|
|
// but we dont know what failed
|
|
if (ppsf && *ppsf)
|
|
(*ppsf)->Release();
|
|
if (ppidlParent)
|
|
ILFree(*ppidlParent);
|
|
if (ppidl)
|
|
ILFree(*ppidl);
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CFolderItemVerbs_Create(IContextMenu *pcm, FolderItemVerbs ** ppid)
|
|
{
|
|
*ppid = NULL;
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CFolderItemVerbs* pfiv = new CFolderItemVerbs(pcm);
|
|
if (pfiv)
|
|
{
|
|
if (pfiv->Init())
|
|
hr = pfiv->QueryInterface(IID_PPV_ARG(FolderItemVerbs, ppid));
|
|
pfiv->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
CFolderItemVerbs::CFolderItemVerbs(IContextMenu *pcm) :
|
|
_cRef(1), _hmenu(NULL),
|
|
_pcm(pcm), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerbs)
|
|
{
|
|
DllAddRef();
|
|
_pcm->AddRef();
|
|
}
|
|
|
|
CFolderItemVerbs::~CFolderItemVerbs(void)
|
|
{
|
|
DllRelease();
|
|
|
|
if (_pcm)
|
|
_pcm->Release();
|
|
|
|
if (_hmenu)
|
|
DestroyMenu(_hmenu);
|
|
}
|
|
|
|
BOOL CFolderItemVerbs::Init()
|
|
{
|
|
TraceMsg(TF_SHELLAUTO, "CFolderItemVerbs::Init called");
|
|
|
|
// Start of only doing default verb...
|
|
if (_pcm)
|
|
{
|
|
_hmenu = CreatePopupMenu();
|
|
if (FAILED(_pcm->QueryContextMenu(_hmenu, 0, CONTEXTMENU_IDCMD_FIRST, CONTEXTMENU_IDCMD_LAST, CMF_CANRENAME|CMF_NORMAL)))
|
|
return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
// Just for the heck of it, remove junk like sepearators from the menu...
|
|
for (int i = GetMenuItemCount(_hmenu) - 1; i >= 0; i--)
|
|
{
|
|
MENUITEMINFO mii;
|
|
TCHAR szText[80]; // should be big enough for this
|
|
|
|
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(_hmenu, i, TRUE, &mii);
|
|
if (mii.fType & MFT_SEPARATOR)
|
|
DeleteMenu(_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),
|
|
QITABENT(CFolderItemVerbs, IObjectWithSite),
|
|
{ 0 },
|
|
};
|
|
return QISearch(this, qit, riid, ppv);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CFolderItemVerbs::AddRef(void)
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CFolderItemVerbs::Release(void)
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItemVerbs::get_Application(IDispatch **ppid)
|
|
{
|
|
*ppid = NULL;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItemVerbs::get_Parent(IDispatch **ppid)
|
|
{
|
|
*ppid = NULL;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT CFolderItemVerbs::_SecurityCheck()
|
|
{
|
|
return (!_dwSafetyOptions || (IsSafePage(_punkSite) == S_OK)) ? S_OK : E_ACCESSDENIED;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CFolderItemVerbs::get_Count(long *plCount)
|
|
{
|
|
*plCount = 0;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*plCount = GetMenuItemCount(_hmenu);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItemVerbs::Item(VARIANT index, FolderItemVerb **ppid)
|
|
{
|
|
*ppid = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// 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_PPV_ARG(FolderItemVerb, ppid));
|
|
break;
|
|
|
|
case VT_I2:
|
|
index.lVal = (long)index.iVal;
|
|
// And fall through...
|
|
|
|
case VT_I4:
|
|
if ((index.lVal >= 0) && (index.lVal <= GetMenuItemCount(_hmenu)))
|
|
{
|
|
CFolderItemVerb_Create(this, GetMenuItemID(_hmenu, index.lVal), ppid);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
hr = E_NOTIMPL;
|
|
}
|
|
|
|
if (*ppid && _dwSafetyOptions)
|
|
{
|
|
hr = MakeSafeForScripting((IUnknown**)ppid);
|
|
}
|
|
else if (hr != E_NOTIMPL)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItemVerbs::_NewEnum(IUnknown **ppunk)
|
|
{
|
|
*ppunk = NULL;
|
|
HRESULT hr = _SecurityCheck();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(SAFECAST(this, CFolderItemVerbs*));
|
|
if (pNew)
|
|
{
|
|
if (pNew->Init())
|
|
hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
|
|
pNew->Release();
|
|
}
|
|
if (SUCCEEDED(hr) && _dwSafetyOptions)
|
|
hr = MakeSafeForScripting(ppunk);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
CEnumFolderItemVerbs::CEnumFolderItemVerbs(CFolderItemVerbs *pfiv) :
|
|
_cRef(1), _iCur(0), _psdfiv(pfiv)
|
|
{
|
|
_psdfiv->AddRef();
|
|
DllAddRef();
|
|
}
|
|
|
|
|
|
CEnumFolderItemVerbs::~CEnumFolderItemVerbs(void)
|
|
{
|
|
DllRelease();
|
|
_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(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CEnumFolderItemVerbs::Release(void)
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _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 || _iCur >= GetMenuItemCount(_psdfiv->_hmenu))
|
|
return S_FALSE;
|
|
|
|
while (_iCur < GetMenuItemCount(_psdfiv->_hmenu) && cVar > 0)
|
|
{
|
|
FolderItemVerb *pidv;
|
|
hr = CFolderItemVerb_Create(_psdfiv, GetMenuItemID(_psdfiv->_hmenu, _iCur), &pidv);
|
|
|
|
if (SUCCEEDED(hr) && _dwSafetyOptions)
|
|
hr = MakeSafeForScripting((IUnknown**)&pidv);
|
|
|
|
_iCur++;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pVar->pdispVal = pidv;
|
|
pVar->vt = VT_DISPATCH;
|
|
pVar++;
|
|
cReturn++;
|
|
cVar--;
|
|
}
|
|
}
|
|
|
|
if (pulVar)
|
|
*pulVar = cReturn;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CEnumFolderItemVerbs::Skip(ULONG cSkip)
|
|
{
|
|
if ((int)(_iCur + cSkip) >= GetMenuItemCount(_psdfiv->_hmenu))
|
|
return S_FALSE;
|
|
|
|
_iCur += cSkip;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CEnumFolderItemVerbs::Reset(void)
|
|
{
|
|
_iCur = 0;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CEnumFolderItemVerbs::Clone(IEnumVARIANT **ppEnum)
|
|
{
|
|
*ppEnum = NULL;
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CEnumFolderItemVerbs *pNew = new CEnumFolderItemVerbs(_psdfiv);
|
|
if (pNew)
|
|
{
|
|
if (pNew->Init())
|
|
hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, 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_PPV_ARG(FolderItemVerb, ppid));
|
|
psdfiv->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
CFolderItemVerb::CFolderItemVerb(CFolderItemVerbs *psdfivs, UINT id) :
|
|
_cRef(1), _psdfivs(psdfivs), _id(id),
|
|
CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItemVerb)
|
|
{
|
|
_psdfivs->AddRef();
|
|
DllAddRef();
|
|
}
|
|
|
|
CFolderItemVerb::~CFolderItemVerb(void)
|
|
{
|
|
DllRelease();
|
|
_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(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CFolderItemVerb::Release(void)
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CFolderItemVerb::get_Application(IDispatch **ppid)
|
|
{
|
|
// _psdfivs returns E_NOTIMPL
|
|
return _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(_psdfivs->_hmenu, _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(_id - CONTEXTMENU_IDCMD_FIRST);
|
|
return _psdfivs->_pcm->InvokeCommand(&ici);
|
|
}
|
|
|