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.

722 lines
20 KiB

  1. #include "shellprv.h"
  2. #include <shlobj.h>
  3. #include <shellapi.h>
  4. #include <shlobj.h>
  5. #include <shlobjp.h>
  6. #include <assert.h>
  7. #include <shlwapi.h>
  8. #include <stgutil.h>
  9. #include <datautil.h>
  10. #include <idlcomm.h>
  11. #include <dpa.h>
  12. #include <objbase.h>
  13. #define DSTYPE_STORAGE 0x1
  14. #define DSTYPE_STREAM 0x2
  15. // do not change order of these parameters, we have some in line variable initializations going on
  16. typedef struct
  17. {
  18. LPWSTR pwszTag;
  19. IShellItem *psi;
  20. DWORD_PTR grfMode;
  21. } DYNASTGDATA;
  22. // Prototype definitions
  23. STDAPI CDynamicStorage_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv);
  24. STDAPI CDynamicStorageEnum_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv);
  25. class CDynamicStorage : public IStorage, public IDynamicStorage
  26. {
  27. friend class CDynamicStorageEnum;
  28. friend HRESULT CDynamicStorage_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv);
  29. public:
  30. CDynamicStorage();
  31. ~CDynamicStorage();
  32. // IUnknown
  33. STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
  34. ULONG STDMETHODCALLTYPE AddRef();
  35. ULONG STDMETHODCALLTYPE Release();
  36. // IDynamicStorage
  37. STDMETHODIMP AddIDList(DWORD cpidl, LPITEMIDLIST* rgpidl, DSTGF dstgf);
  38. STDMETHODIMP BindToItem(LPCWSTR pwszName, REFIID riid, void **ppv);
  39. STDMETHODIMP EnumItems(IEnumShellItems **ppesi);
  40. // IStorage
  41. // we only implement: CreateStream, OpenStream, OpenStorage, MoveElementTo, EnumElements.
  42. // others just return E_NOTIMPL;
  43. STDMETHODIMP CreateStream(const WCHAR * pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm);
  44. STDMETHODIMP OpenStream(const WCHAR *pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
  45. STDMETHODIMP CreateStorage(const WCHAR *pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg)
  46. { return E_NOTIMPL; }
  47. STDMETHODIMP OpenStorage(const WCHAR *pwcsName, IStorage * pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage ** ppstg);
  48. STDMETHODIMP CopyTo(DWORD ciidExclude, IID const * rgiidExclude, SNB snbExclude, IStorage * pstgDest)
  49. { return E_NOTIMPL; }
  50. STDMETHODIMP MoveElementTo(const WCHAR * pwcsName, IStorage * pstgDest, const WCHAR * pwcsNewName, DWORD grfFlags);
  51. STDMETHODIMP Commit(DWORD grfCommitFlags)
  52. { return S_OK; }
  53. STDMETHODIMP Revert(void)
  54. { return E_NOTIMPL; }
  55. STDMETHODIMP EnumElements(DWORD reserved1, void * reserved2, DWORD reserved3, IEnumSTATSTG ** ppenum);
  56. STDMETHODIMP DestroyElement(const WCHAR* pwcsName)
  57. { return E_NOTIMPL; }
  58. STDMETHODIMP RenameElement(const WCHAR * pwcsOldName, const WCHAR * pwcsNewName)
  59. { return E_NOTIMPL; }
  60. STDMETHODIMP SetElementTimes(const WCHAR * pwcsName, FILETIME const * pctime, FILETIME const * patime, FILETIME const * pmtime)
  61. { return E_NOTIMPL; }
  62. STDMETHODIMP SetClass(REFCLSID clsid)
  63. { return E_NOTIMPL; }
  64. STDMETHODIMP SetStateBits(DWORD grfStateBits, DWORD grfMask)
  65. { return E_NOTIMPL; }
  66. STDMETHODIMP Stat(STATSTG * pstatstg, DWORD grfStatFlag)
  67. { return E_NOTIMPL; }
  68. private:
  69. HRESULT _Init();
  70. HRESULT _EnsureDirectory();
  71. HRESULT _InsertItem(LPWSTR pszTag, IShellItem *psi, DSTGF dstgf);
  72. HRESULT _GetStream(int i, DWORD grfMode, IStream **ppstm);
  73. HRESULT _GetStorage(int i, DWORD grfMode, IStorage **ppstg);
  74. static int s_DataCompare(DYNASTGDATA *pData1, DYNASTGDATA *pData2, LPARAM lParam);
  75. static int s_DataDestroy(DYNASTGDATA* pData, void* pv);
  76. private:
  77. CDPA<DYNASTGDATA> _dpaData;
  78. IStorage* _pstgTemp; // pointer to our temp subfolder
  79. IStorage* _pstgTempDir; // the temp folder itself
  80. LPWSTR _pwszTemp; // name of our temp subfolder
  81. LONG _cRef;
  82. };
  83. class CDynamicStorageEnum : public IEnumSTATSTG
  84. , public IEnumShellItems
  85. {
  86. public:
  87. CDynamicStorageEnum();
  88. ~CDynamicStorageEnum();
  89. STDMETHODIMP Init(CDynamicStorage* pDynStorage);
  90. // IUnknown
  91. STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
  92. ULONG STDMETHODCALLTYPE AddRef();
  93. ULONG STDMETHODCALLTYPE Release();
  94. // IEnumXXX
  95. STDMETHODIMP Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched);
  96. STDMETHODIMP Clone(IEnumShellItems **ppenum) { return E_NOTIMPL; }
  97. STDMETHODIMP Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched);
  98. STDMETHODIMP Skip(ULONG celt);
  99. STDMETHODIMP Reset();
  100. STDMETHODIMP Clone(IEnumSTATSTG **ppenum) { return E_NOTIMPL; }
  101. private:
  102. CDynamicStorage *_pDynStorage;
  103. IShellFolder *_psfParent;
  104. LPITEMIDLIST _pidlParent;
  105. ULONG _cItems;
  106. ULONG _cPos;
  107. LONG _cRef;
  108. };
  109. #define DYNSTG_DPA_GROW_SIZE 10
  110. CDynamicStorage::CDynamicStorage(): _cRef(1)
  111. {
  112. }
  113. int CDynamicStorage::s_DataDestroy(DYNASTGDATA* pData, void* pv)
  114. {
  115. ASSERTMSG(pData != NULL, "NULL dynamic storage data element");
  116. CoTaskMemFree(pData->pwszTag);
  117. pData->psi->Release();
  118. LocalFree(pData);
  119. return 1;
  120. }
  121. CDynamicStorage::~CDynamicStorage()
  122. {
  123. _dpaData.DestroyCallback(s_DataDestroy, NULL);
  124. if (_pstgTemp)
  125. {
  126. ASSERT(_pstgTempDir);
  127. _pstgTempDir->DestroyElement(_pwszTemp);
  128. _pstgTempDir->Release();
  129. _pstgTemp->Release();
  130. CoTaskMemFree(_pwszTemp);
  131. }
  132. }
  133. // IUnknown
  134. STDMETHODIMP CDynamicStorage::QueryInterface(REFIID iid, void** ppv)
  135. {
  136. static const QITAB qit[] =
  137. {
  138. QITABENT(CDynamicStorage, IDynamicStorage),
  139. QITABENT(CDynamicStorage, IStorage),
  140. { 0 },
  141. };
  142. return QISearch(this, qit, iid, ppv);
  143. }
  144. ULONG STDMETHODCALLTYPE CDynamicStorage::AddRef()
  145. {
  146. return ::InterlockedIncrement(&_cRef);
  147. }
  148. ULONG STDMETHODCALLTYPE CDynamicStorage::Release()
  149. {
  150. if (::InterlockedDecrement(&_cRef) == 0)
  151. {
  152. delete this;
  153. return 0;
  154. }
  155. return _cRef;
  156. }
  157. STDAPI CDynamicStorage_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  158. {
  159. *ppv = NULL;
  160. if (punkOuter)
  161. return CLASS_E_NOAGGREGATION;
  162. HRESULT hr = E_OUTOFMEMORY;
  163. CDynamicStorage *pstgf = new CDynamicStorage();
  164. if (pstgf)
  165. {
  166. hr = pstgf->_Init();
  167. if (SUCCEEDED(hr))
  168. {
  169. hr = pstgf->QueryInterface(riid, ppv);
  170. }
  171. pstgf->Release();
  172. }
  173. return hr;
  174. }
  175. HRESULT CDynamicStorage::_InsertItem(LPWSTR pszTag, IShellItem *psi, DSTGF dstgf)
  176. {
  177. HRESULT hr = E_OUTOFMEMORY;
  178. DYNASTGDATA* pData = (DYNASTGDATA*)LocalAlloc(LPTR, sizeof(DYNASTGDATA));
  179. if (pData)
  180. {
  181. hr = SHStrDup(pszTag, &pData->pwszTag);
  182. if (SUCCEEDED(hr))
  183. {
  184. pData->psi = psi;
  185. pData->psi->AddRef();
  186. if (!(dstgf & DSTGF_ALLOWDUP))
  187. {
  188. int i = _dpaData.Search(pData, 0, s_DataCompare, 0, 0);
  189. if (i != -1)
  190. {
  191. s_DataDestroy(_dpaData.GetPtr(i), NULL);
  192. _dpaData.DeletePtr(i);
  193. }
  194. }
  195. // i != -1 if we succeeded, at which point pass out the data pointer or
  196. // ensure that we clean up.
  197. if (-1 == _dpaData.AppendPtr(pData))
  198. {
  199. s_DataDestroy(pData, NULL);
  200. hr = E_FAIL;
  201. }
  202. }
  203. }
  204. return hr;
  205. }
  206. // IDynamicStorage
  207. STDMETHODIMP CDynamicStorage::AddIDList(DWORD cpidl, LPITEMIDLIST* rgpidl, DSTGF dstgf)
  208. {
  209. if (!rgpidl || !cpidl)
  210. return E_INVALIDARG;
  211. HRESULT hr = S_OK;
  212. for (DWORD i = 0; SUCCEEDED(hr) && i < cpidl; i++)
  213. {
  214. IShellItem *psi;
  215. hr = SHCreateShellItem(NULL, NULL, rgpidl[i], &psi);
  216. if (SUCCEEDED(hr))
  217. {
  218. LPWSTR pszName;
  219. hr = psi->GetDisplayName(SIGDN_PARENTRELATIVEFORADDRESSBAR, &pszName);
  220. if (SUCCEEDED(hr))
  221. {
  222. hr = _InsertItem(pszName, psi, dstgf);
  223. CoTaskMemFree(pszName);
  224. }
  225. psi->Release();
  226. }
  227. }
  228. return hr;
  229. }
  230. HRESULT CDynamicStorage::BindToItem(LPCWSTR pwszName, REFIID riid, void **ppv)
  231. {
  232. HRESULT hr = STG_E_FILENOTFOUND;
  233. DYNASTGDATA data = {(LPWSTR)pwszName};
  234. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  235. if (iResult != -1)
  236. {
  237. DYNASTGDATA* pData = _dpaData.GetPtr(iResult);
  238. if (pData && riid == IID_IShellItem)
  239. hr = pData->psi->QueryInterface(riid, ppv);
  240. else
  241. hr = E_NOINTERFACE;
  242. }
  243. return hr;
  244. }
  245. HRESULT CDynamicStorage::EnumItems(IEnumShellItems **ppesi)
  246. {
  247. *ppesi = NULL;
  248. IEnumShellItems *penum = NULL;
  249. HRESULT hr = CDynamicStorageEnum_CreateInstance(NULL, IID_PPV_ARG(IEnumShellItems, &penum));
  250. if (SUCCEEDED(hr))
  251. {
  252. hr = ((CDynamicStorageEnum*)penum)->Init(this);
  253. if (FAILED(hr))
  254. {
  255. penum->Release();
  256. }
  257. }
  258. if (SUCCEEDED(hr))
  259. {
  260. *ppesi = penum;
  261. }
  262. return hr;
  263. }
  264. HRESULT CDynamicStorage::_Init()
  265. {
  266. return _dpaData.Create(DYNSTG_DPA_GROW_SIZE) ? S_OK : E_OUTOFMEMORY;
  267. }
  268. HRESULT CDynamicStorage::_EnsureDirectory()
  269. {
  270. HRESULT hr = S_OK;
  271. if (!_pstgTemp)
  272. {
  273. hr = E_FAIL;
  274. WCHAR wszTempDir[MAX_PATH];
  275. if (GetTempPath(ARRAYSIZE(wszTempDir), wszTempDir))
  276. {
  277. LPITEMIDLIST pidl;
  278. hr = SHILCreateFromPath(wszTempDir, &pidl, NULL);
  279. if (SUCCEEDED(hr))
  280. {
  281. hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IStorage, &_pstgTempDir));
  282. if (SUCCEEDED(hr))
  283. {
  284. hr = StgMakeUniqueName(_pstgTempDir, L"dynastg", IID_PPV_ARG(IStorage, &_pstgTemp));
  285. if (SUCCEEDED(hr))
  286. {
  287. STATSTG statstg = {0};
  288. hr = _pstgTemp->Stat(&statstg, STATFLAG_DEFAULT);
  289. if (SUCCEEDED(hr))
  290. _pwszTemp = statstg.pwcsName;
  291. }
  292. if (FAILED(hr))
  293. {
  294. ATOMICRELEASE(_pstgTempDir); // if we failed, _pwszTemp could not have been allocated...
  295. ATOMICRELEASE(_pstgTemp);
  296. }
  297. }
  298. ILFree(pidl);
  299. }
  300. }
  301. }
  302. return hr;
  303. }
  304. int CDynamicStorage::s_DataCompare(DYNASTGDATA *pData1, DYNASTGDATA *pData2, LPARAM lParam)
  305. {
  306. return lstrcmp(pData1->pwszTag, pData2->pwszTag);
  307. }
  308. HRESULT CDynamicStorage::_GetStream(int i, DWORD grfMode, IStream **ppstm)
  309. {
  310. *ppstm = NULL;
  311. HRESULT hr = E_FAIL;
  312. DYNASTGDATA* pData = _dpaData.GetPtr(i);
  313. if (pData)
  314. {
  315. IBindCtx *pbc;
  316. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  317. if (SUCCEEDED(hr))
  318. {
  319. hr = pData->psi->BindToHandler(pbc, BHID_Stream, IID_PPV_ARG(IStream, ppstm));
  320. pbc->Release();
  321. }
  322. }
  323. return hr;
  324. }
  325. STDMETHODIMP CDynamicStorage::OpenStream(const WCHAR * pwcsName,
  326. void * reserved1,
  327. DWORD grfMode,
  328. DWORD reserved2,
  329. IStream ** ppstm)
  330. {
  331. if (reserved1 || reserved2)
  332. return E_INVALIDARG;
  333. HRESULT hr = STG_E_FILENOTFOUND;
  334. DYNASTGDATA data = {(LPWSTR)pwcsName};
  335. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  336. if (iResult != -1)
  337. {
  338. hr = _GetStream(iResult, grfMode, ppstm);
  339. }
  340. return hr;
  341. }
  342. HRESULT CDynamicStorage::_GetStorage(int i, DWORD grfMode, IStorage **ppstg)
  343. {
  344. *ppstg = NULL;
  345. HRESULT hr = E_FAIL;
  346. DYNASTGDATA* pData = _dpaData.GetPtr(i);
  347. if (pData)
  348. {
  349. IBindCtx *pbc;
  350. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  351. if (SUCCEEDED(hr))
  352. {
  353. hr = pData->psi->BindToHandler(pbc, BHID_Storage, IID_PPV_ARG(IStorage, ppstg));
  354. pbc->Release();
  355. }
  356. }
  357. return hr;
  358. }
  359. STDMETHODIMP CDynamicStorage::OpenStorage(const WCHAR * pwcsName,
  360. IStorage * pstgPriority,
  361. DWORD grfMode,
  362. SNB snbExclude,
  363. DWORD reserved,
  364. IStorage ** ppstg)
  365. {
  366. if (pstgPriority || snbExclude || reserved)
  367. return E_INVALIDARG;
  368. HRESULT hr = STG_E_FILENOTFOUND;
  369. DYNASTGDATA data = {(LPWSTR)pwcsName};
  370. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  371. if (iResult != -1)
  372. {
  373. hr = _GetStorage(iResult, grfMode, ppstg);
  374. }
  375. return hr;
  376. }
  377. STDMETHODIMP CDynamicStorage::EnumElements(DWORD reserved1,
  378. void * reserved2,
  379. DWORD reserved3,
  380. IEnumSTATSTG ** ppenum)
  381. {
  382. if (reserved1 || reserved2 || reserved3 || !ppenum)
  383. return E_INVALIDARG;
  384. *ppenum = NULL;
  385. IEnumSTATSTG* pEnumObj = NULL;
  386. HRESULT hr = CDynamicStorageEnum_CreateInstance(NULL, IID_PPV_ARG(IEnumSTATSTG, &pEnumObj));
  387. if (SUCCEEDED(hr))
  388. {
  389. hr = ((CDynamicStorageEnum*)pEnumObj)->Init(this);
  390. if (FAILED(hr))
  391. {
  392. pEnumObj->Release();
  393. }
  394. }
  395. if (SUCCEEDED(hr))
  396. {
  397. *ppenum = pEnumObj;
  398. }
  399. return hr;
  400. }
  401. STDMETHODIMP CDynamicStorage::MoveElementTo(const WCHAR * pwcsName,
  402. IStorage * pstgDest,
  403. const WCHAR* pwcsNewName,
  404. DWORD grfFlags)
  405. {
  406. if (!pwcsName || !pstgDest || !pwcsNewName || grfFlags != STGMOVE_COPY)
  407. return E_INVALIDARG;
  408. IStorage* pStorageSrc;
  409. HRESULT hr = OpenStorage(pwcsName, NULL, STGM_READ, NULL, 0, &pStorageSrc);
  410. if (SUCCEEDED(hr))
  411. {
  412. IStorage* pStorageDest;
  413. hr = pstgDest->CreateStorage(pwcsNewName, STGM_WRITE | STGM_CREATE, 0, 0, &pStorageDest);
  414. if (SUCCEEDED(hr))
  415. {
  416. hr = pStorageSrc->CopyTo(0, NULL, NULL, pStorageDest);
  417. }
  418. }
  419. else
  420. {
  421. IStream* pStreamSrc;
  422. hr = OpenStream(pwcsName, NULL, STGM_READ, 0, &pStreamSrc);
  423. if (SUCCEEDED(hr))
  424. {
  425. IStream* pStreamDest;
  426. hr = pstgDest->CreateStream(pwcsNewName, STGM_WRITE | STGM_CREATE, 0, 0, &pStreamDest);
  427. if (SUCCEEDED(hr))
  428. {
  429. ULARGE_INTEGER ulSize = {0xffffffff, 0xffffffff};
  430. hr = pStreamSrc->CopyTo(pStreamDest, ulSize, NULL, NULL);
  431. pStreamDest->Release();
  432. }
  433. pStreamSrc->Release();
  434. }
  435. }
  436. return hr;
  437. }
  438. STDMETHODIMP CDynamicStorage::CreateStream(const WCHAR *pwcsName,
  439. DWORD grfMode,
  440. DWORD reserved1,
  441. DWORD reserved2,
  442. IStream **ppstm)
  443. {
  444. *ppstm = NULL;
  445. HRESULT hr = _EnsureDirectory();
  446. if (SUCCEEDED(hr))
  447. {
  448. hr = _pstgTemp->CreateStream(pwcsName, grfMode, 0, 0, ppstm);
  449. if (SUCCEEDED(hr))
  450. {
  451. hr = E_FAIL;
  452. WCHAR wszPath[MAX_PATH];
  453. if (GetTempPath(ARRAYSIZE(wszPath), wszPath) && PathCombine(wszPath, wszPath, _pwszTemp))
  454. {
  455. STATSTG statstg;
  456. if (SUCCEEDED((*ppstm)->Stat(&statstg, 0)))
  457. {
  458. LPITEMIDLIST pidl;
  459. if (PathCombine(wszPath, wszPath, statstg.pwcsName) && SUCCEEDED(SHILCreateFromPath(wszPath, &pidl, NULL)))
  460. {
  461. hr = AddIDList(1, &pidl, DSTGF_NONE);
  462. ILFree(pidl);
  463. }
  464. CoTaskMemFree(statstg.pwcsName);
  465. }
  466. }
  467. if (FAILED(hr))
  468. {
  469. // no need to DeleteElement here because the whole temp storage
  470. // will be deleted in destructor
  471. ATOMICRELEASE(*ppstm);
  472. }
  473. }
  474. }
  475. return hr;
  476. }
  477. CDynamicStorageEnum::CDynamicStorageEnum(): _cRef(1)
  478. {
  479. }
  480. CDynamicStorageEnum::~CDynamicStorageEnum()
  481. {
  482. if (_pDynStorage)
  483. _pDynStorage->Release();
  484. if (_psfParent)
  485. _psfParent->Release();
  486. ILFree(_pidlParent);
  487. }
  488. STDMETHODIMP CDynamicStorageEnum::Init(CDynamicStorage* pDynStorage)
  489. {
  490. _pDynStorage = pDynStorage;
  491. _pDynStorage->AddRef();
  492. _cItems = _pDynStorage->_dpaData.GetPtrCount();
  493. _cPos = 0;
  494. return S_OK;
  495. }
  496. STDMETHODIMP CDynamicStorageEnum::QueryInterface(REFIID iid, void** ppv)
  497. {
  498. static const QITAB qit[] =
  499. {
  500. QITABENT(CDynamicStorageEnum, IEnumSTATSTG),
  501. QITABENT(CDynamicStorageEnum, IEnumShellItems),
  502. { 0 },
  503. };
  504. return QISearch(this, qit, iid, ppv);
  505. }
  506. ULONG STDMETHODCALLTYPE CDynamicStorageEnum::AddRef()
  507. {
  508. return ::InterlockedIncrement(&_cRef);
  509. }
  510. ULONG STDMETHODCALLTYPE CDynamicStorageEnum::Release()
  511. {
  512. if (::InterlockedDecrement(&_cRef) == 0)
  513. {
  514. delete this;
  515. return 0;
  516. }
  517. return _cRef;
  518. }
  519. STDAPI CDynamicStorageEnum_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  520. {
  521. *ppv = NULL;
  522. if (punkOuter)
  523. return CLASS_E_NOAGGREGATION;
  524. HRESULT hr = E_OUTOFMEMORY;
  525. CDynamicStorageEnum *pstgEnum = new CDynamicStorageEnum();
  526. if (pstgEnum)
  527. {
  528. hr = pstgEnum->QueryInterface(riid, ppv);
  529. pstgEnum->Release();
  530. }
  531. return hr;
  532. }
  533. STDMETHODIMP CDynamicStorageEnum::Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched)
  534. {
  535. if (!rgelt || celt != 1)
  536. return E_INVALIDARG;
  537. if (pceltFetched)
  538. *pceltFetched = 0;
  539. *rgelt = NULL;
  540. if (_cPos >= _cItems)
  541. return S_FALSE;
  542. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  543. DYNASTGDATA* pData = _pDynStorage->_dpaData.GetPtr(_cPos++);
  544. HRESULT hr;
  545. if (_cPos > _cItems)
  546. {
  547. hr = S_FALSE;
  548. }
  549. else
  550. {
  551. ASSERTMSG(pData != NULL, "dynamic storage has null DPA item");
  552. hr = S_OK;
  553. rgelt[0] = pData->psi;
  554. rgelt[0]->AddRef();
  555. if (pceltFetched)
  556. *pceltFetched = 1;
  557. }
  558. return hr;
  559. }
  560. STDMETHODIMP CDynamicStorageEnum::Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
  561. {
  562. // ISSUE: for now, we only support calling next asking for one item
  563. if (!rgelt || celt != 1)
  564. return E_INVALIDARG;
  565. if (_cPos >= _cItems)
  566. return S_FALSE;
  567. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  568. ZeroMemory(rgelt, sizeof(STATSTG)); // per COM conventions
  569. if (pceltFetched)
  570. *pceltFetched = 0;
  571. HRESULT hr = E_FAIL;
  572. IStorage *pstg;
  573. IStream *pstm;
  574. if (SUCCEEDED(_pDynStorage->_GetStream(_cPos, STGM_READ, &pstm)))
  575. {
  576. hr = pstm->Stat(rgelt, STATFLAG_DEFAULT);
  577. pstm->Release();
  578. }
  579. else if (SUCCEEDED(_pDynStorage->_GetStorage(_cPos, STGM_READ, &pstg)))
  580. {
  581. hr = pstg->Stat(rgelt, STATFLAG_DEFAULT);
  582. pstg->Release();
  583. }
  584. if (SUCCEEDED(hr))
  585. {
  586. _cPos++;
  587. if (pceltFetched)
  588. *pceltFetched = 1;
  589. }
  590. return hr;
  591. }
  592. STDMETHODIMP CDynamicStorageEnum::Skip(ULONG celt)
  593. {
  594. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  595. HRESULT hr;
  596. if (_cPos + celt > _cItems)
  597. {
  598. _cPos = _cItems;
  599. hr = S_FALSE;
  600. }
  601. else
  602. {
  603. _cPos += celt;
  604. hr = S_OK;
  605. }
  606. return hr;
  607. }
  608. STDMETHODIMP CDynamicStorageEnum::Reset()
  609. {
  610. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  611. _cPos = 0;
  612. return S_OK;
  613. }