Leaked source code of windows server 2003
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.

848 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. ASSERT( 0 != _cRef );
  339. ULONG cRef = InterlockedDecrement(&_cRef);
  340. if ( 0 == cRef )
  341. {
  342. delete this;
  343. }
  344. return cRef;
  345. }
  346. // FolderItems implementation
  347. STDMETHODIMP CFolderItems::get_Application(IDispatch **ppid)
  348. {
  349. // let the folder object do the work...
  350. return _psdf->get_Application(ppid);
  351. }
  352. STDMETHODIMP CFolderItems::get_Parent(IDispatch **ppid)
  353. {
  354. *ppid = NULL;
  355. return E_NOTIMPL;
  356. }
  357. STDMETHODIMP CFolderItems::get_Count(long *pCount)
  358. {
  359. HRESULT hr = _SecurityCheck();
  360. if (SUCCEEDED(hr))
  361. {
  362. hr = E_FAIL;
  363. IShellFolderView *psfv = NULL;
  364. // get the items from the view, we can do this if we don't have
  365. // a spec.
  366. if ( !_pszFileSpec )
  367. {
  368. hr = _psdf->GetShellFolderView(&psfv);
  369. if (SUCCEEDED(hr))
  370. {
  371. UINT cCount;
  372. hr = _fSelected ? psfv->GetSelectedCount(&cCount) : psfv->GetObjectCount(&cCount);
  373. *pCount = cCount;
  374. psfv->Release();
  375. }
  376. }
  377. // either we failed to get to the view, or the file spec won't allow us
  378. if ( _pszFileSpec || FAILED(hr) )
  379. {
  380. // Well it looks like we need to finish the iteration now to get this!
  381. *pCount = SUCCEEDED(_EnsureItem(-1, NULL)) ? _GetHDPACount() : 0;
  382. hr = S_OK;
  383. }
  384. }
  385. return hr;
  386. }
  387. // Folder.Items.Item(1)
  388. // Folder.Items.Item("file name")
  389. // Folder.Items.Item() - same as Folder.Self
  390. STDMETHODIMP CFolderItems::Item(VARIANT index, FolderItem **ppid)
  391. {
  392. HRESULT hr = _SecurityCheck();
  393. if (SUCCEEDED(hr))
  394. {
  395. hr = S_FALSE;
  396. *ppid = NULL;
  397. // This is sortof gross, but if we are passed a pointer to another variant, simply
  398. // update our copy here...
  399. if (index.vt == (VT_BYREF | VT_VARIANT) && index.pvarVal)
  400. index = *index.pvarVal;
  401. switch (index.vt)
  402. {
  403. case VT_ERROR:
  404. {
  405. // No Parameters, generate a folder item for the folder itself...
  406. Folder * psdfParent;
  407. hr = _psdf->get_ParentFolder(&psdfParent);
  408. if (SUCCEEDED(hr) && psdfParent)
  409. {
  410. hr = CFolderItem_Create((CFolder*)psdfParent, ILFindLastID(_psdf->_pidl), ppid);
  411. psdfParent->Release();
  412. }
  413. }
  414. break;
  415. case VT_I2:
  416. index.lVal = (long)index.iVal;
  417. // And fall through...
  418. case VT_I4:
  419. {
  420. LPCITEMIDLIST pidl;
  421. hr = _EnsureItem(index.lVal, &pidl); // Get the asked for item...
  422. if (S_OK == hr)
  423. hr = CFolderItem_Create(_psdf, pidl, ppid);
  424. }
  425. break;
  426. case VT_BSTR:
  427. {
  428. LPITEMIDLIST pidl;
  429. hr = _psdf->_psf->ParseDisplayName(NULL, NULL, index.bstrVal, NULL, &pidl, NULL);
  430. if (SUCCEEDED(hr))
  431. {
  432. hr = CFolderItem_Create(_psdf, pidl, ppid);
  433. ILFree(pidl);
  434. }
  435. }
  436. break;
  437. default:
  438. return E_NOTIMPL;
  439. }
  440. if (hr != S_OK) // Error values cause problems in Java script
  441. {
  442. *ppid = NULL;
  443. hr = S_FALSE;
  444. }
  445. else if (ppid && _dwSafetyOptions)
  446. {
  447. hr = MakeSafeForScripting((IUnknown**)ppid);
  448. }
  449. }
  450. return hr;
  451. }
  452. STDMETHODIMP CFolderItems::InvokeVerbEx(VARIANT vVerb, VARIANT vArgs)
  453. {
  454. long cItems;
  455. // Note: if not safe, we'll fail in get_Count with E_ACCESSDENIED
  456. HRESULT hr = get_Count(&cItems);
  457. if (SUCCEEDED(hr) && cItems)
  458. {
  459. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems);
  460. if (ppidl)
  461. {
  462. for (int i = 0; i < cItems; i++)
  463. {
  464. _EnsureItem(i, &ppidl[i]);
  465. }
  466. hr = _psdf->InvokeVerbHelper(vVerb, vArgs, ppidl, cItems, _dwSafetyOptions);
  467. LocalFree(ppidl);
  468. }
  469. else
  470. hr = E_OUTOFMEMORY;
  471. }
  472. return hr;
  473. }
  474. //
  475. // fIncludeFolders => includ folders in the enumeration (TRUE by default)
  476. // bstrFilter = filespec to apply while enumerating
  477. //
  478. STDMETHODIMP CFolderItems::Filter(LONG grfFlags, BSTR bstrFileSpec)
  479. {
  480. HRESULT hr = _SecurityCheck();
  481. if (SUCCEEDED(hr))
  482. {
  483. _grfFlags = grfFlags;
  484. Str_SetPtr(&_pszFileSpec, bstrFileSpec);
  485. _ResetIDListArray();
  486. }
  487. return hr;
  488. }
  489. STDMETHODIMP CFolderItems::_GetUIObjectOf(REFIID riid, void ** ppv)
  490. {
  491. *ppv = NULL;
  492. HRESULT hr = E_FAIL;
  493. long cItems;
  494. if (SUCCEEDED(get_Count(&cItems)) && cItems)
  495. {
  496. LPCITEMIDLIST *ppidl = (LPCITEMIDLIST *)LocalAlloc(LPTR, SIZEOF(*ppidl) * cItems);
  497. if (ppidl)
  498. {
  499. for (int i = 0; i < cItems; i++)
  500. {
  501. _EnsureItem(i, &ppidl[i]);
  502. }
  503. hr = _psdf->_psf->GetUIObjectOf(_psdf->_hwnd, cItems, ppidl, riid, NULL, ppv);
  504. LocalFree(ppidl);
  505. }
  506. else
  507. hr = E_OUTOFMEMORY;
  508. }
  509. return hr;
  510. }
  511. STDMETHODIMP CFolderItems::get_Verbs(FolderItemVerbs **ppfic)
  512. {
  513. *ppfic = NULL;
  514. HRESULT hr = _SecurityCheck();
  515. if (SUCCEEDED(hr))
  516. {
  517. hr = S_FALSE;
  518. IContextMenu *pcm;
  519. if (SUCCEEDED(_GetUIObjectOf(IID_PPV_ARG(IContextMenu, &pcm))))
  520. {
  521. hr = CFolderItemVerbs_Create(pcm, ppfic);
  522. if (SUCCEEDED(hr) && _dwSafetyOptions)
  523. {
  524. hr = MakeSafeForScripting((IUnknown**)ppfic);
  525. if (SUCCEEDED(hr))
  526. {
  527. // Set the folder's site to FolderItemVerbs
  528. IUnknown_SetSite(*ppfic, _psdf->_punkSite);
  529. }
  530. }
  531. pcm->Release();
  532. }
  533. }
  534. return hr;
  535. }
  536. // supports VB "For Each" statement
  537. STDMETHODIMP CFolderItems::_NewEnum(IUnknown **ppunk)
  538. {
  539. *ppunk = NULL;
  540. HRESULT hr = _SecurityCheck();
  541. if (SUCCEEDED(hr))
  542. {
  543. hr = E_OUTOFMEMORY;
  544. CEnumFolderItems *pNew = new CEnumFolderItems(this);
  545. if (pNew)
  546. {
  547. hr = pNew->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  548. pNew->Release();
  549. if (SUCCEEDED(hr) && _dwSafetyOptions)
  550. {
  551. hr = MakeSafeForScripting(ppunk);
  552. }
  553. }
  554. }
  555. return hr;
  556. }
  557. STDAPI CFolderItemsFDF_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
  558. {
  559. HRESULT hr = E_OUTOFMEMORY;
  560. *ppv = NULL;
  561. CFolderItemsFDF *pfi = new CFolderItemsFDF(NULL);
  562. if (pfi)
  563. {
  564. hr = pfi->QueryInterface(riid, ppv);
  565. pfi->Release();
  566. }
  567. return hr;
  568. }
  569. CFolderItemsFDF::CFolderItemsFDF(CFolder *psdf) : CFolderItems(psdf, FALSE)
  570. {
  571. }
  572. HRESULT CFolderItemsFDF::QueryInterface(REFIID riid, void ** ppv)
  573. {
  574. HRESULT hr = CFolderItems::QueryInterface(riid, ppv);
  575. if (FAILED(hr))
  576. {
  577. static const QITAB qit[] = {
  578. QITABENT(CFolderItemsFDF, IInsertItem),
  579. { 0 },
  580. };
  581. hr = QISearch(this, qit, riid, ppv);
  582. }
  583. return hr;
  584. }
  585. HRESULT CFolderItemsFDF::InsertItem(LPCITEMIDLIST pidl)
  586. {
  587. HRESULT hr = S_FALSE;
  588. if (_GetHDPA())
  589. {
  590. LPITEMIDLIST pidlTemp;
  591. hr = SHILClone(pidl, &pidlTemp);
  592. if (SUCCEEDED(hr))
  593. {
  594. if (DPA_AppendPtr(_hdpa, pidlTemp) == -1)
  595. {
  596. ILFree(pidlTemp);
  597. hr = E_FAIL;
  598. }
  599. }
  600. }
  601. return hr;
  602. }
  603. HRESULT CFolderItemsFDF::_EnsureItem(UINT iItemNeeded, LPCITEMIDLIST *ppidlItem)
  604. {
  605. HRESULT hr = S_FALSE; // assume out of range
  606. if (ppidlItem)
  607. *ppidlItem = NULL;
  608. if (_GetHDPA())
  609. {
  610. LPCITEMIDLIST pidl = (LPCITEMIDLIST)DPA_GetPtr(_hdpa, iItemNeeded);
  611. if (pidl)
  612. {
  613. if (ppidlItem)
  614. *ppidlItem = pidl;
  615. hr = S_OK;
  616. }
  617. }
  618. return hr;
  619. }
  620. // CEnumFolderItems implementation of IEnumVARIANT
  621. CEnumFolderItems::CEnumFolderItems(CFolderItems *pfdritms) :
  622. _cRef(1),
  623. _pfdritms(pfdritms),
  624. _iCur(0)
  625. {
  626. _pfdritms->AddRef();
  627. DllAddRef();
  628. }
  629. CEnumFolderItems::~CEnumFolderItems(void)
  630. {
  631. _pfdritms->Release();
  632. DllRelease();
  633. }
  634. STDMETHODIMP CEnumFolderItems::QueryInterface(REFIID riid, void ** ppv)
  635. {
  636. static const QITAB qit[] = {
  637. QITABENT(CEnumFolderItems, IEnumVARIANT),
  638. { 0 },
  639. };
  640. return QISearch(this, qit, riid, ppv);
  641. }
  642. STDMETHODIMP_(ULONG) CEnumFolderItems::AddRef(void)
  643. {
  644. return InterlockedIncrement(&_cRef);
  645. }
  646. STDMETHODIMP_(ULONG) CEnumFolderItems::Release(void)
  647. {
  648. ASSERT( 0 != _cRef );
  649. ULONG cRef = InterlockedDecrement(&_cRef);
  650. if ( 0 == cRef )
  651. {
  652. delete this;
  653. }
  654. return cRef;
  655. }
  656. STDMETHODIMP CEnumFolderItems::Next(ULONG cVar, VARIANT *pVar, ULONG *pulVar)
  657. {
  658. ULONG cReturn = 0;
  659. HRESULT hr = S_OK;
  660. if (!pulVar && (cVar != 1))
  661. return E_POINTER;
  662. while (cVar)
  663. {
  664. LPCITEMIDLIST pidl;
  665. if (S_OK == _pfdritms->_EnsureItem(_iCur + cVar - 1, &pidl))
  666. {
  667. FolderItem *pid;
  668. hr = CFolderItem_Create(_pfdritms->_psdf, pidl, &pid);
  669. _iCur++;
  670. if (_pfdritms->_dwSafetyOptions && SUCCEEDED(hr))
  671. hr = MakeSafeForScripting((IUnknown**)&pid);
  672. if (SUCCEEDED(hr))
  673. {
  674. pVar->pdispVal = pid;
  675. pVar->vt = VT_DISPATCH;
  676. pVar++;
  677. cReturn++;
  678. cVar--;
  679. }
  680. else
  681. break;
  682. }
  683. else
  684. break;
  685. }
  686. if (SUCCEEDED(hr))
  687. {
  688. if (pulVar)
  689. *pulVar = cReturn;
  690. hr = cReturn ? S_OK : S_FALSE;
  691. }
  692. return hr;
  693. }
  694. STDMETHODIMP CEnumFolderItems::Skip(ULONG cSkip)
  695. {
  696. if ((_iCur + cSkip) >= _pfdritms->_GetHDPACount())
  697. return S_FALSE;
  698. _iCur += cSkip;
  699. return NOERROR;
  700. }
  701. STDMETHODIMP CEnumFolderItems::Reset(void)
  702. {
  703. _iCur = 0;
  704. return NOERROR;
  705. }
  706. STDMETHODIMP CEnumFolderItems::Clone(IEnumVARIANT **ppenum)
  707. {
  708. *ppenum = NULL;
  709. HRESULT hr = E_OUTOFMEMORY;
  710. CEnumFolderItems *pNew = new CEnumFolderItems(_pfdritms);
  711. if (pNew)
  712. {
  713. hr = pNew->QueryInterface(IID_PPV_ARG(IEnumVARIANT, ppenum));
  714. pNew->Release();
  715. }
  716. return hr;
  717. }