Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

859 lines
22 KiB

  1. #include "precomp.h"
  2. #include "shconv.h"
  3. #pragma hdrstop
  4. class CEnumFolderItems;
  5. class CFolderItems : public FolderItems3,
  6. public IPersistFolder,
  7. public CObjectSafety,
  8. public CObjectWithSite,
  9. protected CImpIDispatch
  10. {
  11. friend CEnumFolderItems;
  12. public:
  13. CFolderItems(CFolder *psdf, BOOL fSelected);
  14. // IUnknown
  15. STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
  16. STDMETHOD_(ULONG, AddRef)(void);
  17. STDMETHOD_(ULONG, Release)(void);
  18. // IDispatch
  19. STDMETHODIMP GetTypeInfoCount(UINT *pctinfo)
  20. { return CImpIDispatch::GetTypeInfoCount(pctinfo); }
  21. STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **pptinfo)
  22. { return CImpIDispatch::GetTypeInfo(itinfo, lcid, pptinfo); }
  23. STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR ** rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
  24. { return CImpIDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); }
  25. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr)
  26. { return CImpIDispatch::Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); }
  27. // FolderItems
  28. STDMETHODIMP get_Application(IDispatch **ppid);
  29. STDMETHODIMP get_Parent (IDispatch **ppid);
  30. STDMETHODIMP get_Count(long *pCount);
  31. STDMETHODIMP Item(VARIANT, FolderItem**);
  32. STDMETHODIMP _NewEnum(IUnknown **);
  33. // FolderItems2
  34. STDMETHODIMP InvokeVerbEx(VARIANT vVerb, VARIANT vArgs);
  35. // FolderItems3
  36. STDMETHODIMP Filter(long grfFlags, BSTR bstrFilter);
  37. STDMETHODIMP get_Verbs(FolderItemVerbs **ppfic);
  38. // IPersist
  39. STDMETHODIMP GetClassID(CLSID *pClassID);
  40. // IPersistFolder
  41. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  42. protected:
  43. HDPA _GetHDPA();
  44. UINT _GetHDPACount();
  45. BOOL_PTR _CopyItem(UINT iItem, LPCITEMIDLIST pidl);
  46. LONG _cRef;
  47. CFolder *_psdf;
  48. HDPA _hdpa;
  49. BOOL _fSelected;
  50. BOOL _fGotAllItems;
  51. IEnumIDList *_penum;
  52. UINT _cNumEnumed;
  53. LONG _grfFlags;
  54. LPTSTR _pszFileSpec;
  55. HRESULT _SecurityCheck();
  56. void _ResetIDListArray();
  57. virtual ~CFolderItems(void);
  58. BOOL _IncludeItem(IShellFolder *psf, LPCITEMIDLIST pidl);
  59. virtual HRESULT _EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidl);
  60. STDMETHODIMP _GetUIObjectOf(REFIID riid, void ** ppv);
  61. };
  62. // CFolderItemsF(rom)D(ifferent)F(olders)
  63. class CFolderItemsFDF : public CFolderItems,
  64. public IInsertItem
  65. {
  66. public:
  67. // TODO: add callback pointer to constructor
  68. CFolderItemsFDF(CFolder *psdf);
  69. // IUnknown override
  70. STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
  71. STDMETHOD_(ULONG, AddRef)(void) {return CFolderItems::AddRef();};
  72. STDMETHOD_(ULONG, Release)(void) {return CFolderItems::Release();};
  73. // IInsertItem
  74. STDMETHOD(InsertItem)(LPCITEMIDLIST pidl);
  75. protected:
  76. virtual HRESULT _EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidl);
  77. };
  78. //Enumerator of whatever is held in the collection
  79. class CEnumFolderItems : public IEnumVARIANT
  80. {
  81. public:
  82. CEnumFolderItems(CFolderItems *pfdritms);
  83. // IUnknown
  84. STDMETHODIMP QueryInterface(REFIID, void **);
  85. STDMETHODIMP_(ULONG) AddRef(void);
  86. STDMETHODIMP_(ULONG) Release(void);
  87. // IEnumFORMATETC
  88. STDMETHODIMP Next(ULONG, VARIANT *, ULONG *);
  89. STDMETHODIMP Skip(ULONG);
  90. STDMETHODIMP Reset(void);
  91. STDMETHODIMP Clone(IEnumVARIANT **);
  92. private:
  93. ~CEnumFolderItems();
  94. LONG _cRef;
  95. CFolderItems *_pfdritms;
  96. UINT _iCur;
  97. };
  98. HRESULT CFolderItems_Create(CFolder *psdf, BOOL fSelected, FolderItems **ppitems)
  99. {
  100. *ppitems = NULL;
  101. HRESULT hr = E_OUTOFMEMORY;
  102. CFolderItems* psdfi = new CFolderItems(psdf, fSelected);
  103. if (psdfi)
  104. {
  105. hr = psdfi->QueryInterface(IID_PPV_ARG(FolderItems, ppitems));
  106. psdfi->Release();
  107. }
  108. return hr;
  109. }
  110. CFolderItems::CFolderItems(CFolder *psdf, BOOL fSelected) :
  111. _cRef(1),
  112. _psdf(psdf),
  113. _fSelected(fSelected),
  114. _grfFlags(SHCONTF_FOLDERS | SHCONTF_NONFOLDERS),
  115. CImpIDispatch(SDSPATCH_TYPELIB, IID_FolderItems3)
  116. {
  117. DllAddRef();
  118. if (_psdf)
  119. _psdf->AddRef();
  120. ASSERT(_hdpa == NULL);
  121. ASSERT(_pszFileSpec == NULL);
  122. }
  123. HRESULT CFolderItems::GetClassID(CLSID *pClassID)
  124. {
  125. *pClassID = CLSID_FolderItemsFDF;
  126. return S_OK;
  127. }
  128. HRESULT CFolderItems::Initialize(LPCITEMIDLIST pidl)
  129. {
  130. ASSERT(_psdf == NULL);
  131. return CFolder_Create2(NULL, pidl, NULL, &_psdf);
  132. }
  133. int FreePidlCallBack(void *pv, void *)
  134. {
  135. ILFree((LPITEMIDLIST)pv);
  136. return 1;
  137. }
  138. HRESULT CFolderItems::_SecurityCheck()
  139. {
  140. if (!_dwSafetyOptions)
  141. return S_OK;
  142. return _psdf->_SecurityCheck();
  143. }
  144. void CFolderItems::_ResetIDListArray(void)
  145. {
  146. // destory the DPA, and lets reset the counters and pointers
  147. if (_hdpa)
  148. {
  149. DPA_DestroyCallback(_hdpa, FreePidlCallBack, 0);
  150. _hdpa = NULL;
  151. }
  152. _fGotAllItems = FALSE;
  153. _cNumEnumed = 0;
  154. ATOMICRELEASE(_penum); // may be NULL
  155. }
  156. CFolderItems::~CFolderItems(void)
  157. {
  158. _ResetIDListArray();
  159. Str_SetPtr(&_pszFileSpec, NULL);
  160. if (_psdf)
  161. _psdf->Release();
  162. DllRelease();
  163. }
  164. HDPA CFolderItems::_GetHDPA()
  165. {
  166. if (NULL == _hdpa)
  167. _hdpa = ::DPA_Create(0);
  168. return _hdpa;
  169. }
  170. UINT CFolderItems::_GetHDPACount()
  171. {
  172. UINT count = 0;
  173. HDPA hdpa = _GetHDPA();
  174. if (hdpa)
  175. count = DPA_GetPtrCount(hdpa);
  176. return count;
  177. }
  178. BOOL_PTR CFolderItems::_CopyItem(UINT iItem, LPCITEMIDLIST pidl)
  179. {
  180. LPITEMIDLIST pidlT = ILClone(pidl);
  181. if (pidlT)
  182. {
  183. if ( -1 == ::DPA_InsertPtr(_hdpa, iItem, pidlT) )
  184. {
  185. ILFree(pidlT);
  186. pidlT = NULL; // failure
  187. }
  188. }
  189. return (BOOL_PTR)pidlT;
  190. }
  191. // check the item name against the file spec and see if we should include it
  192. BOOL CFolderItems::_IncludeItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  193. {
  194. BOOL fInclude = TRUE; // by default include it...
  195. if ( _pszFileSpec )
  196. {
  197. // see if we can resolve the link on this object
  198. LPITEMIDLIST pidlFromLink = NULL;
  199. IShellLink *psl;
  200. if ( SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (void **)&psl)) )
  201. {
  202. psl->GetIDList(&pidlFromLink);
  203. psl->Release();
  204. pidl = pidlFromLink;
  205. }
  206. // then apply the file spec
  207. TCHAR szName[MAX_PATH];
  208. SHGetNameAndFlags(pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, szName, ARRAYSIZE(szName), NULL);
  209. fInclude = PathMatchSpec(szName, _pszFileSpec);
  210. ILFree(pidlFromLink);
  211. }
  212. return fInclude;
  213. }
  214. // in:
  215. // iItemNeeded zero based index
  216. //
  217. //
  218. // returns:
  219. // S_OK in range value
  220. // S_FALSE out of range value
  221. //
  222. HRESULT CFolderItems::_EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidlItem)
  223. {
  224. HRESULT hr = S_FALSE; // assume out of range
  225. if (_GetHDPA())
  226. {
  227. LPCITEMIDLIST pidl = (LPCITEMIDLIST)DPA_GetPtr(_hdpa, iItemNeeded);
  228. if (pidl)
  229. {
  230. if (ppidlItem)
  231. *ppidlItem = pidl;
  232. hr = S_OK;
  233. }
  234. else if (!_fGotAllItems)
  235. {
  236. IShellFolderView *psfv;
  237. if (SUCCEEDED(_psdf->GetShellFolderView(&psfv)))
  238. {
  239. if (_fSelected)
  240. {
  241. // we can only request the entire selection, therefore
  242. // do so and populate our array with those.
  243. UINT cItems;
  244. LPCITEMIDLIST *ppidl = NULL;
  245. if (SUCCEEDED(psfv->GetSelectedObjects(&ppidl, &cItems)) && ppidl)
  246. {
  247. for (UINT i = 0; i < cItems; i++)
  248. _CopyItem(i, ppidl[i]);
  249. LocalFree(ppidl);
  250. }
  251. _fGotAllItems = TRUE;
  252. hr = _EnsureItem(iItemNeeded, ppidlItem);
  253. }
  254. else
  255. {
  256. UINT cItems;
  257. if (SUCCEEDED(psfv->GetObjectCount(&cItems)))
  258. {
  259. // if there is no file spec then we can just request the item
  260. // that we want, otherwise we must collect them all
  261. // from the view.
  262. if (iItemNeeded < cItems)
  263. {
  264. LPCITEMIDLIST pidl;
  265. if (SUCCEEDED(GetObjectSafely(psfv, &pidl, iItemNeeded)))
  266. {
  267. if (_CopyItem(iItemNeeded, pidl))
  268. {
  269. hr = _EnsureItem(iItemNeeded, ppidlItem);
  270. }
  271. }
  272. }
  273. }
  274. }
  275. psfv->Release();
  276. }
  277. else
  278. {
  279. // we don't have an enumerator, so lets request it
  280. if (NULL == _penum)
  281. _psdf->_psf->EnumObjects(NULL, _grfFlags, &_penum);
  282. if (NULL == _penum)
  283. {
  284. _fGotAllItems = TRUE; // enum empty, we are done
  285. }
  286. else
  287. {
  288. // get more while our count is less than the index
  289. while (_cNumEnumed <= iItemNeeded)
  290. {
  291. LPITEMIDLIST pidl;
  292. if (S_OK == _penum->Next(1, &pidl, NULL))
  293. {
  294. if ( _IncludeItem(_psdf->_psf, pidl) &&
  295. (-1 != ::DPA_AppendPtr(_hdpa, pidl)) )
  296. {
  297. _cNumEnumed++;
  298. }
  299. else
  300. {
  301. ILFree(pidl);
  302. }
  303. }
  304. else
  305. {
  306. ATOMICRELEASE(_penum);
  307. _fGotAllItems = TRUE;
  308. break;
  309. }
  310. }
  311. }
  312. hr = _EnsureItem(iItemNeeded, ppidlItem);
  313. }
  314. }
  315. }
  316. else
  317. hr = E_OUTOFMEMORY;
  318. return hr;
  319. }
  320. STDMETHODIMP CFolderItems::QueryInterface(REFIID riid, void ** ppv)
  321. {
  322. static const QITAB qit[] = {
  323. QITABENT(CFolderItems, FolderItems3),
  324. QITABENTMULTI(CFolderItems, FolderItems, FolderItems3),
  325. QITABENTMULTI(CFolderItems, IDispatch, FolderItems3),
  326. QITABENT(CFolderItems, IObjectSafety),
  327. QITABENT(CFolderItems, IPersistFolder),
  328. { 0 },
  329. };
  330. return QISearch(this, qit, riid, ppv);
  331. }
  332. STDMETHODIMP_(ULONG) CFolderItems::AddRef(void)
  333. {
  334. return InterlockedIncrement(&_cRef);
  335. }
  336. STDMETHODIMP_(ULONG) CFolderItems::Release(void)
  337. {
  338. if (InterlockedDecrement(&_cRef))
  339. return _cRef;
  340. delete this;
  341. return 0;
  342. }
  343. // FolderItems implementation
  344. STDMETHODIMP CFolderItems::get_Application(IDispatch **ppid)
  345. {
  346. // let the folder object do the work...
  347. return _psdf->get_Application(ppid);
  348. }
  349. STDMETHODIMP CFolderItems::get_Parent(IDispatch **ppid)
  350. {
  351. *ppid = NULL;
  352. return E_NOTIMPL;
  353. }
  354. STDMETHODIMP CFolderItems::get_Count(long *pCount)
  355. {
  356. HRESULT hr = _SecurityCheck();
  357. if (SUCCEEDED(hr))
  358. {
  359. hr = E_FAIL;
  360. IShellFolderView *psfv = NULL;
  361. // get the items from the view, we can do this if we don't have
  362. // a spec.
  363. if ( !_pszFileSpec )
  364. {
  365. hr = _psdf->GetShellFolderView(&psfv);
  366. if (SUCCEEDED(hr))
  367. {
  368. UINT cCount;
  369. hr = _fSelected ? psfv->GetSelectedCount(&cCount) : psfv->GetObjectCount(&cCount);
  370. *pCount = cCount;
  371. psfv->Release();
  372. }
  373. }
  374. // either we failed to get to the view, or the file spec won't allow us
  375. if ( _pszFileSpec || FAILED(hr) )
  376. {
  377. // Well it looks like we need to finish the iteration now to get this!
  378. *pCount = SUCCEEDED(_EnsureItem(-1, NULL)) ? _GetHDPACount() : 0;
  379. hr = S_OK;
  380. }
  381. }
  382. return hr;
  383. }
  384. // Folder.Items.Item(1)
  385. // Folder.Items.Item("file name")
  386. // Folder.Items.Item() - same as Folder.Self
  387. STDMETHODIMP CFolderItems::Item(VARIANT index, FolderItem **ppid)
  388. {
  389. HRESULT hr = _SecurityCheck();
  390. if (SUCCEEDED(hr))
  391. {
  392. hr = S_FALSE;
  393. *ppid = NULL;
  394. // This is sortof gross, but if we are passed a pointer to another variant, simply
  395. // update our copy here...
  396. if (index.vt == (VT_BYREF | VT_VARIANT) && index.pvarVal)
  397. index = *index.pvarVal;
  398. switch (index.vt)
  399. {
  400. case VT_ERROR:
  401. {
  402. // No Parameters, generate a folder item for the folder itself...
  403. Folder * psdfParent;
  404. hr = _psdf->get_ParentFolder(&psdfParent);
  405. if (SUCCEEDED(hr) && psdfParent)
  406. {
  407. hr = CFolderItem_Create((CFolder*)psdfParent, ILFindLastID(_psdf->_pidl), ppid);
  408. psdfParent->Release();
  409. }
  410. }
  411. break;
  412. case VT_I2:
  413. index.lVal = (long)index.iVal;
  414. // And fall through...
  415. case VT_I4:
  416. {
  417. LPCITEMIDLIST pidl;
  418. hr = _EnsureItem(index.lVal, &pidl); // Get the asked for item...
  419. if (S_OK == hr)
  420. hr = CFolderItem_Create(_psdf, pidl, ppid);
  421. }
  422. break;
  423. case VT_BSTR:
  424. {
  425. LPITEMIDLIST pidl;
  426. hr = _psdf->_psf->ParseDisplayName(NULL, NULL, index.bstrVal, NULL, &pidl, NULL);
  427. if (SUCCEEDED(hr))
  428. {
  429. hr = CFolderItem_Create(_psdf, pidl, ppid);
  430. ILFree(pidl);
  431. }
  432. }
  433. break;
  434. default:
  435. return E_NOTIMPL;
  436. }
  437. if (hr != S_OK) // Error values cause problems in Java script
  438. {
  439. *ppid = NULL;
  440. hr = S_FALSE;
  441. }
  442. else if (ppid && _dwSafetyOptions)
  443. {
  444. hr = MakeSafeForScripting((IUnknown**)ppid);
  445. }
  446. }
  447. return hr;
  448. }
  449. STDMETHODIMP CFolderItems::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
  450. {
  451. long cItems;
  452. // Note: if not safe, we'll fail in get_Count with E_ACCESSDENIED
  453. HRESULT hr = get_Count(&cItems);
  454. if (SUCCEEDED(hr) && cItems)
  455. {
  456. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems);
  457. if (ppidl)
  458. {
  459. for (int i = 0; i < cItems; i++)
  460. {
  461. _EnsureItem(i, &ppidl[i]);
  462. }
  463. // BUGBUG: shouldn't worry about items from different folders here?
  464. hr = _psdf->InvokeVerbHelper(vVerb, vArgs, ppidl, cItems, _dwSafetyOptions);
  465. LocalFree(ppidl);
  466. }
  467. else
  468. hr = E_OUTOFMEMORY;
  469. }
  470. return hr;
  471. }
  472. //
  473. // fIncludeFolders => includ folders in the enumeration (TRUE by default)
  474. // bstrFilter = filespec to apply while enumerating
  475. //
  476. STDMETHODIMP CFolderItems::Filter(LONG grfFlags, BSTR bstrFileSpec)
  477. {
  478. HRESULT hr = _SecurityCheck();
  479. if (SUCCEEDED(hr))
  480. {
  481. _grfFlags = grfFlags;
  482. Str_SetPtr(&_pszFileSpec, bstrFileSpec);
  483. _ResetIDListArray();
  484. }
  485. return hr;
  486. }
  487. STDMETHODIMP CFolderItems::_GetUIObjectOf(REFIID riid, void ** ppv)
  488. {
  489. *ppv = NULL;
  490. HRESULT hr = E_FAIL;
  491. long cItems;
  492. if (SUCCEEDED(get_Count(&cItems)) && cItems)
  493. {
  494. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems);
  495. if (ppidl)
  496. {
  497. for (int i = 0; i < cItems; i++)
  498. {
  499. _EnsureItem(i, &ppidl[i]);
  500. }
  501. // BUGBUG: shouldn't worry about items from different folders here?
  502. hr = _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, cItems, ppidl, riid, NULL, ppv);
  503. LocalFree(ppidl);
  504. }
  505. else
  506. hr = E_OUTOFMEMORY;
  507. }
  508. return hr;
  509. }
  510. STDMETHODIMP CFolderItems::get_Verbs(FolderItemVerbs **ppfic)
  511. {
  512. *ppfic = NULL;
  513. HRESULT hr = _SecurityCheck();
  514. if (SUCCEEDED(hr))
  515. {
  516. hr = S_FALSE;
  517. IContextMenu *pcm;
  518. if (SUCCEEDED(_GetUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm))))
  519. {
  520. hr = CFolderItemVerbs_Create(pcm, ppfic);
  521. if (SUCCEEDED(hr) && _dwSafetyOptions)
  522. {
  523. hr = MakeSafeForScripting((IUnknown**)ppfic);
  524. if (SUCCEEDED(hr))
  525. {
  526. // Set the folder's site to FolderItemVerbs
  527. IUnknown_SetSite(*ppfic, _psdf->_punkSite);
  528. }
  529. }
  530. pcm->Release();
  531. }
  532. }
  533. return hr;
  534. }
  535. // supports VB "For Each" statement
  536. STDMETHODIMP CFolderItems::_NewEnum(IUnknown **ppunk)
  537. {
  538. *ppunk = NULL;
  539. HRESULT hr = _SecurityCheck();
  540. if (SUCCEEDED(hr))
  541. {
  542. hr = E_OUTOFMEMORY;
  543. CEnumFolderItems *pNew = new CEnumFolderItems(this);
  544. if (pNew)
  545. {
  546. hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  547. pNew->Release();
  548. if (SUCCEEDED(hr) && _dwSafetyOptions)
  549. {
  550. hr = MakeSafeForScripting(ppunk);
  551. }
  552. }
  553. }
  554. return hr;
  555. }
  556. HRESULT CFolderItemsFDF_Create(CFolder *psdf, FolderItems **ppitems)
  557. {
  558. *ppitems = NULL;
  559. HRESULT hr = E_OUTOFMEMORY;
  560. CFolderItemsFDF* psdfi = new CFolderItemsFDF(psdf);
  561. if (psdfi)
  562. {
  563. hr = psdfi->QueryInterface(IID_PPV_ARG(FolderItems, ppitems));
  564. psdfi->Release();
  565. }
  566. return hr;
  567. }
  568. STDAPI CFolderItemsFDF_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
  569. {
  570. HRESULT hr = E_OUTOFMEMORY;
  571. *ppv = NULL;
  572. CFolderItemsFDF *pfi = new CFolderItemsFDF(NULL);
  573. if (pfi)
  574. {
  575. hr = pfi->QueryInterface(riid, ppv);
  576. pfi->Release();
  577. }
  578. return hr;
  579. }
  580. CFolderItemsFDF::CFolderItemsFDF(CFolder *psdf) : CFolderItems(psdf, FALSE)
  581. {
  582. }
  583. HRESULT CFolderItemsFDF::QueryInterface(REFIID riid, void ** ppv)
  584. {
  585. HRESULT hr = CFolderItems::QueryInterface(riid, ppv);
  586. if (FAILED(hr))
  587. {
  588. static const QITAB qit[] = {
  589. QITABENT(CFolderItemsFDF, IInsertItem),
  590. { 0 },
  591. };
  592. hr = QISearch(this, qit, riid, ppv);
  593. }
  594. return hr;
  595. }
  596. HRESULT CFolderItemsFDF::InsertItem(LPCITEMIDLIST pidl)
  597. {
  598. HRESULT hr = S_FALSE;
  599. if (_GetHDPA())
  600. {
  601. LPITEMIDLIST pidlTemp;
  602. hr = SHILClone(pidl, &pidlTemp);
  603. if (SUCCEEDED(hr))
  604. {
  605. if (DPA_AppendPtr(_hdpa, pidlTemp) == -1)
  606. {
  607. ILFree(pidlTemp);
  608. hr = E_FAIL;
  609. }
  610. }
  611. }
  612. return hr;
  613. }
  614. HRESULT CFolderItemsFDF::_EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidlItem)
  615. {
  616. HRESULT hr = S_FALSE; // assume out of range
  617. if (ppidlItem)
  618. *ppidlItem = NULL;
  619. if (_GetHDPA())
  620. {
  621. LPCITEMIDLIST pidl = (LPCITEMIDLIST)DPA_GetPtr(_hdpa, iItemNeeded);
  622. if (pidl)
  623. {
  624. if (ppidlItem)
  625. *ppidlItem = pidl;
  626. hr = S_OK;
  627. }
  628. }
  629. return hr;
  630. }
  631. // CEnumFolderItems implementation of IEnumVARIANT
  632. CEnumFolderItems::CEnumFolderItems(CFolderItems *pfdritms) :
  633. _cRef(1),
  634. _pfdritms(pfdritms),
  635. _iCur(0)
  636. {
  637. _pfdritms->AddRef();
  638. DllAddRef();
  639. }
  640. CEnumFolderItems::~CEnumFolderItems(void)
  641. {
  642. _pfdritms->Release();
  643. DllRelease();
  644. }
  645. STDMETHODIMP CEnumFolderItems::QueryInterface(REFIID riid, void ** ppv)
  646. {
  647. static const QITAB qit[] = {
  648. QITABENT(CEnumFolderItems, IEnumVARIANT),
  649. { 0 },
  650. };
  651. return QISearch(this, qit, riid, ppv);
  652. }
  653. STDMETHODIMP_(ULONG) CEnumFolderItems::AddRef(void)
  654. {
  655. return InterlockedIncrement(&_cRef);
  656. }
  657. STDMETHODIMP_(ULONG) CEnumFolderItems::Release(void)
  658. {
  659. if (InterlockedDecrement(&_cRef))
  660. return _cRef;
  661. delete this;
  662. return 0;
  663. }
  664. STDMETHODIMP CEnumFolderItems::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar)
  665. {
  666. ULONG cReturn = 0;
  667. HRESULT hr = S_OK;
  668. if (!pulVar && (cVar != 1))
  669. return E_POINTER;
  670. while (cVar)
  671. {
  672. LPCITEMIDLIST pidl;
  673. if (S_OK == _pfdritms->_EnsureItem(_iCur + cVar - 1, &pidl))
  674. {
  675. FolderItem *pid;
  676. hr = CFolderItem_Create(_pfdritms->_psdf, pidl, &pid);
  677. _iCur++;
  678. if (_pfdritms->_dwSafetyOptions && SUCCEEDED(hr))
  679. hr = MakeSafeForScripting((IUnknown**)&pid);
  680. if (SUCCEEDED(hr))
  681. {
  682. pVar->pdispVal = pid;
  683. pVar->vt = VT_DISPATCH;
  684. pVar++;
  685. cReturn++;
  686. cVar--;
  687. }
  688. else
  689. break;
  690. }
  691. else
  692. break;
  693. }
  694. if (SUCCEEDED(hr))
  695. {
  696. if (pulVar)
  697. *pulVar = cReturn;
  698. hr = cReturn ? S_OK : S_FALSE;
  699. }
  700. return hr;
  701. }
  702. STDMETHODIMP CEnumFolderItems::Skip(ULONG cSkip)
  703. {
  704. if ((_iCur + cSkip) >= _pfdritms->_GetHDPACount())
  705. return S_FALSE;
  706. _iCur += cSkip;
  707. return NOERROR;
  708. }
  709. STDMETHODIMP CEnumFolderItems::Reset(void)
  710. {
  711. _iCur = 0;
  712. return NOERROR;
  713. }
  714. STDMETHODIMP CEnumFolderItems::Clone(IEnumVARIANT **ppenum)
  715. {
  716. *ppenum = NULL;
  717. HRESULT hr = E_OUTOFMEMORY;
  718. CEnumFolderItems *pNew = new CEnumFolderItems(_pfdritms);
  719. if (pNew)
  720. {
  721. hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, ppenum));
  722. pNew->Release();
  723. }
  724. return hr;
  725. }