|
|
#include "precomp.h"
#include "shconv.h"
#pragma hdrstop
class CEnumFolderItems;
class CFolderItems : public FolderItems3, public IPersistFolder, public CObjectSafety, public CObjectWithSite, protected CImpIDispatch { friend CEnumFolderItems;
public: CFolderItems(CFolder *psdf, BOOL fSelected);
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(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); }
// FolderItems
STDMETHODIMP get_Application(IDispatch **ppid); STDMETHODIMP get_Parent (IDispatch **ppid); STDMETHODIMP get_Count(long *pCount); STDMETHODIMP Item(VARIANT, FolderItem**); STDMETHODIMP _NewEnum(IUnknown **);
// FolderItems2
STDMETHODIMP InvokeVerbEx(VARIANT vVerb, VARIANT vArgs);
// FolderItems3
STDMETHODIMP Filter(long grfFlags, BSTR bstrFilter); STDMETHODIMP get_Verbs(FolderItemVerbs **ppfic);
// IPersist
STDMETHODIMP GetClassID(CLSID *pClassID);
// IPersistFolder
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
protected: HDPA _GetHDPA(); UINT _GetHDPACount(); BOOL_PTR _CopyItem(UINT iItem, LPCITEMIDLIST pidl);
LONG _cRef; CFolder *_psdf; HDPA _hdpa; BOOL _fSelected; BOOL _fGotAllItems; IEnumIDList *_penum; UINT _cNumEnumed; LONG _grfFlags; LPTSTR _pszFileSpec;
HRESULT _SecurityCheck(); void _ResetIDListArray(); virtual ~CFolderItems(void); BOOL _IncludeItem(IShellFolder *psf, LPCITEMIDLIST pidl); virtual HRESULT _EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidl); STDMETHODIMP _GetUIObjectOf(REFIID riid, void ** ppv); };
// CFolderItemsF(rom)D(ifferent)F(olders)
class CFolderItemsFDF : public CFolderItems, public IInsertItem { public: // TODO: add callback pointer to constructor
CFolderItemsFDF(CFolder *psdf);
// IUnknown override
STDMETHOD(QueryInterface)(REFIID riid, void ** ppv); STDMETHOD_(ULONG, AddRef)(void) {return CFolderItems::AddRef();}; STDMETHOD_(ULONG, Release)(void) {return CFolderItems::Release();};
// IInsertItem
STDMETHOD(InsertItem)(LPCITEMIDLIST pidl); protected: virtual HRESULT _EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidl); };
//Enumerator of whatever is held in the collection
class CEnumFolderItems : public IEnumVARIANT { public: CEnumFolderItems(CFolderItems *pfdritms);
// 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: ~CEnumFolderItems();
LONG _cRef; CFolderItems *_pfdritms; UINT _iCur; };
HRESULT CFolderItems_Create(CFolder *psdf, BOOL fSelected, FolderItems **ppitems) { *ppitems = NULL; HRESULT hr = E_OUTOFMEMORY; CFolderItems* psdfi = new CFolderItems(psdf, fSelected); if (psdfi) { hr = psdfi->QueryInterface(IID_PPV_ARG(FolderItems, ppitems)); psdfi->Release(); } return hr; }
CFolderItems::CFolderItems(CFolder *psdf, BOOL fSelected) : _cRef(1), _psdf(psdf), _fSelected(fSelected), _grfFlags(SHCONTF_FOLDERS | SHCONTF_NONFOLDERS), CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItems3) { DllAddRef();
if (_psdf) _psdf->AddRef();
ASSERT(_hdpa == NULL); ASSERT(_pszFileSpec == NULL); }
HRESULT CFolderItems::GetClassID(CLSID *pClassID) { *pClassID = CLSID_FolderItemsFDF; return S_OK; }
HRESULT CFolderItems::Initialize(LPCITEMIDLIST pidl) { ASSERT(_psdf == NULL); return CFolder_Create2(NULL, pidl, NULL, &_psdf); }
int FreePidlCallBack(void *pv, void *) { ILFree((LPITEMIDLIST)pv); return 1; }
HRESULT CFolderItems::_SecurityCheck() { if (!_dwSafetyOptions) return S_OK; return _psdf->_SecurityCheck(); }
void CFolderItems::_ResetIDListArray(void) { // destory the DPA, and lets reset the counters and pointers
if (_hdpa) { DPA_DestroyCallback(_hdpa, FreePidlCallBack, 0); _hdpa = NULL; }
_fGotAllItems = FALSE; _cNumEnumed = 0;
ATOMICRELEASE(_penum); // may be NULL
}
CFolderItems::~CFolderItems(void) { _ResetIDListArray(); Str_SetPtr(&_pszFileSpec, NULL);
if (_psdf) _psdf->Release();
DllRelease(); }
HDPA CFolderItems::_GetHDPA() { if (NULL == _hdpa) _hdpa = ::DPA_Create(0); return _hdpa; }
UINT CFolderItems::_GetHDPACount() { UINT count = 0; HDPA hdpa = _GetHDPA(); if (hdpa) count = DPA_GetPtrCount(hdpa); return count; }
BOOL_PTR CFolderItems::_CopyItem(UINT iItem, LPCITEMIDLIST pidl) { LPITEMIDLIST pidlT = ILClone(pidl); if (pidlT) { if ( -1 == ::DPA_InsertPtr(_hdpa, iItem, pidlT) ) { ILFree(pidlT); pidlT = NULL; // failure
} } return (BOOL_PTR)pidlT; }
// check the item name against the file spec and see if we should include it
BOOL CFolderItems::_IncludeItem(IShellFolder *psf, LPCITEMIDLIST pidl) { BOOL fInclude = TRUE; // by default include it...
if ( _pszFileSpec ) { // see if we can resolve the link on this object
LPITEMIDLIST pidlFromLink = NULL; IShellLink *psl;
if ( SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (void **)&psl)) ) { psl->GetIDList(&pidlFromLink); psl->Release(); pidl = pidlFromLink; }
// then apply the file spec
TCHAR szName[MAX_PATH]; SHGetNameAndFlags(pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, szName, ARRAYSIZE(szName), NULL); fInclude = PathMatchSpec(szName, _pszFileSpec);
ILFree(pidlFromLink); }
return fInclude; }
// in:
// iItemNeeded zero based index
//
//
// returns:
// S_OK in range value
// S_FALSE out of range value
//
HRESULT CFolderItems::_EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidlItem) { HRESULT hr = S_FALSE; // assume out of range
if (_GetHDPA()) { LPCITEMIDLIST pidl = (LPCITEMIDLIST)DPA_GetPtr(_hdpa, iItemNeeded); if (pidl) { if (ppidlItem) *ppidlItem = pidl; hr = S_OK; } else if (!_fGotAllItems) { IShellFolderView *psfv; if (SUCCEEDED(_psdf->GetShellFolderView(&psfv))) { if (_fSelected) { // we can only request the entire selection, therefore
// do so and populate our array with those.
UINT cItems; LPCITEMIDLIST *ppidl = NULL; if (SUCCEEDED(psfv->GetSelectedObjects(&ppidl, &cItems)) && ppidl) { for (UINT i = 0; i < cItems; i++) _CopyItem(i, ppidl[i]);
LocalFree(ppidl); } _fGotAllItems = TRUE; hr = _EnsureItem(iItemNeeded, ppidlItem); } else { UINT cItems; if (SUCCEEDED(psfv->GetObjectCount(&cItems))) { // if there is no file spec then we can just request the item
// that we want, otherwise we must collect them all
// from the view.
if (iItemNeeded < cItems) { LPCITEMIDLIST pidl; if (SUCCEEDED(GetObjectSafely(psfv, &pidl, iItemNeeded))) { if (_CopyItem(iItemNeeded, pidl)) { hr = _EnsureItem(iItemNeeded, ppidlItem); } } } } } psfv->Release(); } else { // we don't have an enumerator, so lets request it
if (NULL == _penum) _psdf->_psf->EnumObjects(NULL, _grfFlags, &_penum);
if (NULL == _penum) { _fGotAllItems = TRUE; // enum empty, we are done
} else { // get more while our count is less than the index
while (_cNumEnumed <= iItemNeeded) { LPITEMIDLIST pidl; if (S_OK == _penum->Next(1, &pidl, NULL)) { if ( _IncludeItem(_psdf->_psf, pidl) && (-1 != ::DPA_AppendPtr(_hdpa, pidl)) ) { _cNumEnumed++; } else { ILFree(pidl); } } else { ATOMICRELEASE(_penum); _fGotAllItems = TRUE; break; } } } hr = _EnsureItem(iItemNeeded, ppidlItem); } } } else hr = E_OUTOFMEMORY; return hr; }
STDMETHODIMP CFolderItems::QueryInterface(REFIID riid, void ** ppv) { static const QITAB qit[] = { QITABENT(CFolderItems, FolderItems3), QITABENTMULTI(CFolderItems, FolderItems, FolderItems3), QITABENTMULTI(CFolderItems, IDispatch, FolderItems3), QITABENT(CFolderItems, IObjectSafety), QITABENT(CFolderItems, IPersistFolder), { 0 }, }; return QISearch(this, qit, riid, ppv); }
STDMETHODIMP_(ULONG) CFolderItems::AddRef(void) { return InterlockedIncrement(&_cRef); }
STDMETHODIMP_(ULONG) CFolderItems::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
// FolderItems implementation
STDMETHODIMP CFolderItems::get_Application(IDispatch **ppid) { // let the folder object do the work...
return _psdf->get_Application(ppid); }
STDMETHODIMP CFolderItems::get_Parent(IDispatch **ppid) { *ppid = NULL; return E_NOTIMPL; }
STDMETHODIMP CFolderItems::get_Count(long *pCount) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = E_FAIL; IShellFolderView *psfv = NULL;
// get the items from the view, we can do this if we don't have
// a spec.
if ( !_pszFileSpec ) { hr = _psdf->GetShellFolderView(&psfv); if (SUCCEEDED(hr)) { UINT cCount; hr = _fSelected ? psfv->GetSelectedCount(&cCount) : psfv->GetObjectCount(&cCount); *pCount = cCount; psfv->Release(); } }
// either we failed to get to the view, or the file spec won't allow us
if ( _pszFileSpec || FAILED(hr) ) { // Well it looks like we need to finish the iteration now to get this!
*pCount = SUCCEEDED(_EnsureItem(-1, NULL)) ? _GetHDPACount() : 0; hr = S_OK; } } return hr; }
// Folder.Items.Item(1)
// Folder.Items.Item("file name")
// Folder.Items.Item() - same as Folder.Self
STDMETHODIMP CFolderItems::Item(VARIANT index, FolderItem **ppid) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = S_FALSE; *ppid = NULL;
// 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: { // No Parameters, generate a folder item for the folder itself...
Folder * psdfParent; hr = _psdf->get_ParentFolder(&psdfParent); if (SUCCEEDED(hr) && psdfParent) { hr = CFolderItem_Create((CFolder*)psdfParent, ILFindLastID(_psdf->_pidl), ppid); psdfParent->Release(); } } break;
case VT_I2: index.lVal = (long)index.iVal; // And fall through...
case VT_I4: { LPCITEMIDLIST pidl; hr = _EnsureItem(index.lVal, &pidl); // Get the asked for item...
if (S_OK == hr) hr = CFolderItem_Create(_psdf, pidl, ppid); } break;
case VT_BSTR: { LPITEMIDLIST pidl; hr = _psdf->_psf->ParseDisplayName(NULL, NULL, index.bstrVal, NULL, &pidl, NULL); if (SUCCEEDED(hr)) { hr = CFolderItem_Create(_psdf, pidl, ppid); ILFree(pidl); } } break;
default: return E_NOTIMPL; }
if (hr != S_OK) // Error values cause problems in Java script
{ *ppid = NULL; hr = S_FALSE; } else if (ppid && _dwSafetyOptions) { hr = MakeSafeForScripting((IUnknown**)ppid); } } return hr; }
STDMETHODIMP CFolderItems::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs) { long cItems; // Note: if not safe, we'll fail in get_Count with E_ACCESSDENIED
HRESULT hr = get_Count(&cItems); if (SUCCEEDED(hr) && cItems) { LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems); if (ppidl) { for (int i = 0; i < cItems; i++) { _EnsureItem(i, &ppidl[i]); }
hr = _psdf->InvokeVerbHelper(vVerb, vArgs, ppidl, cItems, _dwSafetyOptions);
LocalFree(ppidl); } else hr = E_OUTOFMEMORY; } return hr; }
//
// fIncludeFolders => includ folders in the enumeration (TRUE by default)
// bstrFilter = filespec to apply while enumerating
//
STDMETHODIMP CFolderItems::Filter(LONG grfFlags, BSTR bstrFileSpec) { HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { _grfFlags = grfFlags; Str_SetPtr(&_pszFileSpec, bstrFileSpec); _ResetIDListArray(); } return hr; }
STDMETHODIMP CFolderItems::_GetUIObjectOf(REFIID riid, void ** ppv) { *ppv = NULL; HRESULT hr = E_FAIL; long cItems; if (SUCCEEDED(get_Count(&cItems)) && cItems) { LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems); if (ppidl) { for (int i = 0; i < cItems; i++) { _EnsureItem(i, &ppidl[i]); }
hr = _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, cItems, ppidl, riid, NULL, ppv);
LocalFree(ppidl); } else hr = E_OUTOFMEMORY; } return hr; }
STDMETHODIMP CFolderItems::get_Verbs(FolderItemVerbs **ppfic) { *ppfic = NULL; 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; }
// supports VB "For Each" statement
STDMETHODIMP CFolderItems::_NewEnum(IUnknown **ppunk) { *ppunk = NULL; HRESULT hr = _SecurityCheck(); if (SUCCEEDED(hr)) { hr = E_OUTOFMEMORY; CEnumFolderItems *pNew = new CEnumFolderItems(this); if (pNew) { hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); pNew->Release();
if (SUCCEEDED(hr) && _dwSafetyOptions) { hr = MakeSafeForScripting(ppunk); } } } return hr; }
STDAPI CFolderItemsFDF_CreateInstance(IUnknown *punk, REFIID riid, void **ppv) { HRESULT hr = E_OUTOFMEMORY; *ppv = NULL;
CFolderItemsFDF *pfi = new CFolderItemsFDF(NULL); if (pfi) { hr = pfi->QueryInterface(riid, ppv); pfi->Release(); }
return hr; }
CFolderItemsFDF::CFolderItemsFDF(CFolder *psdf) : CFolderItems(psdf, FALSE) { }
HRESULT CFolderItemsFDF::QueryInterface(REFIID riid, void ** ppv) { HRESULT hr = CFolderItems::QueryInterface(riid, ppv);
if (FAILED(hr)) { static const QITAB qit[] = { QITABENT(CFolderItemsFDF, IInsertItem), { 0 }, }; hr = QISearch(this, qit, riid, ppv); } return hr; }
HRESULT CFolderItemsFDF::InsertItem(LPCITEMIDLIST pidl) { HRESULT hr = S_FALSE;
if (_GetHDPA()) { LPITEMIDLIST pidlTemp; hr = SHILClone(pidl, &pidlTemp); if (SUCCEEDED(hr)) { if (DPA_AppendPtr(_hdpa, pidlTemp) == -1) { ILFree(pidlTemp); hr = E_FAIL; } } } return hr; }
HRESULT CFolderItemsFDF::_EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidlItem) { HRESULT hr = S_FALSE; // assume out of range
if (ppidlItem) *ppidlItem = NULL;
if (_GetHDPA()) { LPCITEMIDLIST pidl = (LPCITEMIDLIST)DPA_GetPtr(_hdpa, iItemNeeded); if (pidl) { if (ppidlItem) *ppidlItem = pidl; hr = S_OK; } } return hr; }
// CEnumFolderItems implementation of IEnumVARIANT
CEnumFolderItems::CEnumFolderItems(CFolderItems *pfdritms) : _cRef(1), _pfdritms(pfdritms), _iCur(0) { _pfdritms->AddRef(); DllAddRef(); }
CEnumFolderItems::~CEnumFolderItems(void) { _pfdritms->Release(); DllRelease(); }
STDMETHODIMP CEnumFolderItems::QueryInterface(REFIID riid, void ** ppv) { static const QITAB qit[] = { QITABENT(CEnumFolderItems, IEnumVARIANT), { 0 }, }; return QISearch(this, qit, riid, ppv); }
STDMETHODIMP_(ULONG) CEnumFolderItems::AddRef(void) { return InterlockedIncrement(&_cRef); }
STDMETHODIMP_(ULONG) CEnumFolderItems::Release(void) { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
STDMETHODIMP CEnumFolderItems::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar) { ULONG cReturn = 0; HRESULT hr = S_OK;
if (!pulVar && (cVar != 1)) return E_POINTER;
while (cVar) { LPCITEMIDLIST pidl; if (S_OK == _pfdritms->_EnsureItem(_iCur + cVar - 1, &pidl)) { FolderItem *pid;
hr = CFolderItem_Create(_pfdritms->_psdf, pidl, &pid); _iCur++;
if (_pfdritms->_dwSafetyOptions && SUCCEEDED(hr)) hr = MakeSafeForScripting((IUnknown**)&pid);
if (SUCCEEDED(hr)) { pVar->pdispVal = pid; pVar->vt = VT_DISPATCH; pVar++; cReturn++; cVar--; } else break; } else break; }
if (SUCCEEDED(hr)) { if (pulVar) *pulVar = cReturn; hr = cReturn ? S_OK : S_FALSE; }
return hr; }
STDMETHODIMP CEnumFolderItems::Skip(ULONG cSkip) { if ((_iCur + cSkip) >= _pfdritms->_GetHDPACount()) return S_FALSE;
_iCur += cSkip; return NOERROR; }
STDMETHODIMP CEnumFolderItems::Reset(void) { _iCur = 0; return NOERROR; }
STDMETHODIMP CEnumFolderItems::Clone(IEnumVARIANT **ppenum) { *ppenum = NULL; HRESULT hr = E_OUTOFMEMORY; CEnumFolderItems *pNew = new CEnumFolderItems(_pfdritms); if (pNew) { hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, ppenum)); pNew->Release(); } return hr; }
|