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.

724 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. ASSERT( 0 != _cRef );
  151. ULONG cRef = InterlockedDecrement(&_cRef);
  152. if ( 0 == cRef )
  153. {
  154. delete this;
  155. }
  156. return cRef;
  157. }
  158. STDAPI CDynamicStorage_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  159. {
  160. *ppv = NULL;
  161. if (punkOuter)
  162. return CLASS_E_NOAGGREGATION;
  163. HRESULT hr = E_OUTOFMEMORY;
  164. CDynamicStorage *pstgf = new CDynamicStorage();
  165. if (pstgf)
  166. {
  167. hr = pstgf->_Init();
  168. if (SUCCEEDED(hr))
  169. {
  170. hr = pstgf->QueryInterface(riid, ppv);
  171. }
  172. pstgf->Release();
  173. }
  174. return hr;
  175. }
  176. HRESULT CDynamicStorage::_InsertItem(LPWSTR pszTag, IShellItem *psi, DSTGF dstgf)
  177. {
  178. HRESULT hr = E_OUTOFMEMORY;
  179. DYNASTGDATA* pData = (DYNASTGDATA*)LocalAlloc(LPTR, sizeof(DYNASTGDATA));
  180. if (pData)
  181. {
  182. hr = SHStrDup(pszTag, &pData->pwszTag);
  183. if (SUCCEEDED(hr))
  184. {
  185. pData->psi = psi;
  186. pData->psi->AddRef();
  187. if (!(dstgf & DSTGF_ALLOWDUP))
  188. {
  189. int i = _dpaData.Search(pData, 0, s_DataCompare, 0, 0);
  190. if (i != -1)
  191. {
  192. s_DataDestroy(_dpaData.GetPtr(i), NULL);
  193. _dpaData.DeletePtr(i);
  194. }
  195. }
  196. // i != -1 if we succeeded, at which point pass out the data pointer or
  197. // ensure that we clean up.
  198. if (-1 == _dpaData.AppendPtr(pData))
  199. {
  200. s_DataDestroy(pData, NULL);
  201. hr = E_FAIL;
  202. }
  203. }
  204. }
  205. return hr;
  206. }
  207. // IDynamicStorage
  208. STDMETHODIMP CDynamicStorage::AddIDList(DWORD cpidl, LPITEMIDLIST* rgpidl, DSTGF dstgf)
  209. {
  210. if (!rgpidl || !cpidl)
  211. return E_INVALIDARG;
  212. HRESULT hr = S_OK;
  213. for (DWORD i = 0; SUCCEEDED(hr) && i < cpidl; i++)
  214. {
  215. IShellItem *psi;
  216. hr = SHCreateShellItem(NULL, NULL, rgpidl[i], &psi);
  217. if (SUCCEEDED(hr))
  218. {
  219. LPWSTR pszName;
  220. hr = psi->GetDisplayName(SIGDN_PARENTRELATIVEFORADDRESSBAR, &pszName);
  221. if (SUCCEEDED(hr))
  222. {
  223. hr = _InsertItem(pszName, psi, dstgf);
  224. CoTaskMemFree(pszName);
  225. }
  226. psi->Release();
  227. }
  228. }
  229. return hr;
  230. }
  231. HRESULT CDynamicStorage::BindToItem(LPCWSTR pwszName, REFIID riid, void **ppv)
  232. {
  233. HRESULT hr = STG_E_FILENOTFOUND;
  234. DYNASTGDATA data = {(LPWSTR)pwszName};
  235. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  236. if (iResult != -1)
  237. {
  238. DYNASTGDATA* pData = _dpaData.GetPtr(iResult);
  239. if (pData && riid == IID_IShellItem)
  240. hr = pData->psi->QueryInterface(riid, ppv);
  241. else
  242. hr = E_NOINTERFACE;
  243. }
  244. return hr;
  245. }
  246. HRESULT CDynamicStorage::EnumItems(IEnumShellItems **ppesi)
  247. {
  248. *ppesi = NULL;
  249. IEnumShellItems *penum = NULL;
  250. HRESULT hr = CDynamicStorageEnum_CreateInstance(NULL, IID_PPV_ARG(IEnumShellItems, &penum));
  251. if (SUCCEEDED(hr))
  252. {
  253. hr = ((CDynamicStorageEnum*)penum)->Init(this);
  254. if (FAILED(hr))
  255. {
  256. penum->Release();
  257. }
  258. }
  259. if (SUCCEEDED(hr))
  260. {
  261. *ppesi = penum;
  262. }
  263. return hr;
  264. }
  265. HRESULT CDynamicStorage::_Init()
  266. {
  267. return _dpaData.Create(DYNSTG_DPA_GROW_SIZE) ? S_OK : E_OUTOFMEMORY;
  268. }
  269. HRESULT CDynamicStorage::_EnsureDirectory()
  270. {
  271. HRESULT hr = S_OK;
  272. if (!_pstgTemp)
  273. {
  274. hr = E_FAIL;
  275. WCHAR wszTempDir[MAX_PATH];
  276. if (GetTempPath(ARRAYSIZE(wszTempDir), wszTempDir))
  277. {
  278. LPITEMIDLIST pidl;
  279. hr = SHILCreateFromPath(wszTempDir, &pidl, NULL);
  280. if (SUCCEEDED(hr))
  281. {
  282. hr = SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IStorage, &_pstgTempDir));
  283. if (SUCCEEDED(hr))
  284. {
  285. hr = StgMakeUniqueName(_pstgTempDir, L"dynastg", IID_PPV_ARG(IStorage, &_pstgTemp));
  286. if (SUCCEEDED(hr))
  287. {
  288. STATSTG statstg = {0};
  289. hr = _pstgTemp->Stat(&statstg, STATFLAG_DEFAULT);
  290. if (SUCCEEDED(hr))
  291. _pwszTemp = statstg.pwcsName;
  292. }
  293. if (FAILED(hr))
  294. {
  295. ATOMICRELEASE(_pstgTempDir); // if we failed, _pwszTemp could not have been allocated...
  296. ATOMICRELEASE(_pstgTemp);
  297. }
  298. }
  299. ILFree(pidl);
  300. }
  301. }
  302. }
  303. return hr;
  304. }
  305. int CDynamicStorage::s_DataCompare(DYNASTGDATA *pData1, DYNASTGDATA *pData2, LPARAM lParam)
  306. {
  307. return lstrcmp(pData1->pwszTag, pData2->pwszTag);
  308. }
  309. HRESULT CDynamicStorage::_GetStream(int i, DWORD grfMode, IStream **ppstm)
  310. {
  311. *ppstm = NULL;
  312. HRESULT hr = E_FAIL;
  313. DYNASTGDATA* pData = _dpaData.GetPtr(i);
  314. if (pData)
  315. {
  316. IBindCtx *pbc;
  317. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  318. if (SUCCEEDED(hr))
  319. {
  320. hr = pData->psi->BindToHandler(pbc, BHID_Stream, IID_PPV_ARG(IStream, ppstm));
  321. pbc->Release();
  322. }
  323. }
  324. return hr;
  325. }
  326. STDMETHODIMP CDynamicStorage::OpenStream(const WCHAR * pwcsName,
  327. void * reserved1,
  328. DWORD grfMode,
  329. DWORD reserved2,
  330. IStream ** ppstm)
  331. {
  332. if (reserved1 || reserved2)
  333. return E_INVALIDARG;
  334. HRESULT hr = STG_E_FILENOTFOUND;
  335. DYNASTGDATA data = {(LPWSTR)pwcsName};
  336. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  337. if (iResult != -1)
  338. {
  339. hr = _GetStream(iResult, grfMode, ppstm);
  340. }
  341. return hr;
  342. }
  343. HRESULT CDynamicStorage::_GetStorage(int i, DWORD grfMode, IStorage **ppstg)
  344. {
  345. *ppstg = NULL;
  346. HRESULT hr = E_FAIL;
  347. DYNASTGDATA* pData = _dpaData.GetPtr(i);
  348. if (pData)
  349. {
  350. IBindCtx *pbc;
  351. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  352. if (SUCCEEDED(hr))
  353. {
  354. hr = pData->psi->BindToHandler(pbc, BHID_Storage, IID_PPV_ARG(IStorage, ppstg));
  355. pbc->Release();
  356. }
  357. }
  358. return hr;
  359. }
  360. STDMETHODIMP CDynamicStorage::OpenStorage(const WCHAR * pwcsName,
  361. IStorage * pstgPriority,
  362. DWORD grfMode,
  363. SNB snbExclude,
  364. DWORD reserved,
  365. IStorage ** ppstg)
  366. {
  367. if (pstgPriority || snbExclude || reserved)
  368. return E_INVALIDARG;
  369. HRESULT hr = STG_E_FILENOTFOUND;
  370. DYNASTGDATA data = {(LPWSTR)pwcsName};
  371. INT iResult = _dpaData.Search(&data, 0, s_DataCompare, 0, 0);
  372. if (iResult != -1)
  373. {
  374. hr = _GetStorage(iResult, grfMode, ppstg);
  375. }
  376. return hr;
  377. }
  378. STDMETHODIMP CDynamicStorage::EnumElements(DWORD reserved1,
  379. void * reserved2,
  380. DWORD reserved3,
  381. IEnumSTATSTG ** ppenum)
  382. {
  383. if (reserved1 || reserved2 || reserved3 || !ppenum)
  384. return E_INVALIDARG;
  385. *ppenum = NULL;
  386. IEnumSTATSTG* pEnumObj = NULL;
  387. HRESULT hr = CDynamicStorageEnum_CreateInstance(NULL, IID_PPV_ARG(IEnumSTATSTG, &pEnumObj));
  388. if (SUCCEEDED(hr))
  389. {
  390. hr = ((CDynamicStorageEnum*)pEnumObj)->Init(this);
  391. if (FAILED(hr))
  392. {
  393. pEnumObj->Release();
  394. }
  395. }
  396. if (SUCCEEDED(hr))
  397. {
  398. *ppenum = pEnumObj;
  399. }
  400. return hr;
  401. }
  402. STDMETHODIMP CDynamicStorage::MoveElementTo(const WCHAR * pwcsName,
  403. IStorage * pstgDest,
  404. const WCHAR* pwcsNewName,
  405. DWORD grfFlags)
  406. {
  407. if (!pwcsName || !pstgDest || !pwcsNewName || grfFlags != STGMOVE_COPY)
  408. return E_INVALIDARG;
  409. IStorage* pStorageSrc;
  410. HRESULT hr = OpenStorage(pwcsName, NULL, STGM_READ, NULL, 0, &pStorageSrc);
  411. if (SUCCEEDED(hr))
  412. {
  413. IStorage* pStorageDest;
  414. hr = pstgDest->CreateStorage(pwcsNewName, STGM_WRITE | STGM_CREATE, 0, 0, &pStorageDest);
  415. if (SUCCEEDED(hr))
  416. {
  417. hr = pStorageSrc->CopyTo(0, NULL, NULL, pStorageDest);
  418. }
  419. }
  420. else
  421. {
  422. IStream* pStreamSrc;
  423. hr = OpenStream(pwcsName, NULL, STGM_READ, 0, &pStreamSrc);
  424. if (SUCCEEDED(hr))
  425. {
  426. IStream* pStreamDest;
  427. hr = pstgDest->CreateStream(pwcsNewName, STGM_WRITE | STGM_CREATE, 0, 0, &pStreamDest);
  428. if (SUCCEEDED(hr))
  429. {
  430. ULARGE_INTEGER ulSize = {0xffffffff, 0xffffffff};
  431. hr = pStreamSrc->CopyTo(pStreamDest, ulSize, NULL, NULL);
  432. pStreamDest->Release();
  433. }
  434. pStreamSrc->Release();
  435. }
  436. }
  437. return hr;
  438. }
  439. STDMETHODIMP CDynamicStorage::CreateStream(const WCHAR *pwcsName,
  440. DWORD grfMode,
  441. DWORD reserved1,
  442. DWORD reserved2,
  443. IStream **ppstm)
  444. {
  445. *ppstm = NULL;
  446. HRESULT hr = _EnsureDirectory();
  447. if (SUCCEEDED(hr))
  448. {
  449. hr = _pstgTemp->CreateStream(pwcsName, grfMode, 0, 0, ppstm);
  450. if (SUCCEEDED(hr))
  451. {
  452. hr = E_FAIL;
  453. WCHAR wszPath[MAX_PATH];
  454. if (GetTempPath(ARRAYSIZE(wszPath), wszPath) && PathCombine(wszPath, wszPath, _pwszTemp))
  455. {
  456. STATSTG statstg;
  457. if (SUCCEEDED((*ppstm)->Stat(&statstg, 0)))
  458. {
  459. LPITEMIDLIST pidl;
  460. if (PathCombine(wszPath, wszPath, statstg.pwcsName) && SUCCEEDED(SHILCreateFromPath(wszPath, &pidl, NULL)))
  461. {
  462. hr = AddIDList(1, &pidl, DSTGF_NONE);
  463. ILFree(pidl);
  464. }
  465. CoTaskMemFree(statstg.pwcsName);
  466. }
  467. }
  468. if (FAILED(hr))
  469. {
  470. // no need to DeleteElement here because the whole temp storage
  471. // will be deleted in destructor
  472. ATOMICRELEASE(*ppstm);
  473. }
  474. }
  475. }
  476. return hr;
  477. }
  478. CDynamicStorageEnum::CDynamicStorageEnum(): _cRef(1)
  479. {
  480. }
  481. CDynamicStorageEnum::~CDynamicStorageEnum()
  482. {
  483. if (_pDynStorage)
  484. _pDynStorage->Release();
  485. if (_psfParent)
  486. _psfParent->Release();
  487. ILFree(_pidlParent);
  488. }
  489. STDMETHODIMP CDynamicStorageEnum::Init(CDynamicStorage* pDynStorage)
  490. {
  491. _pDynStorage = pDynStorage;
  492. _pDynStorage->AddRef();
  493. _cItems = _pDynStorage->_dpaData.GetPtrCount();
  494. _cPos = 0;
  495. return S_OK;
  496. }
  497. STDMETHODIMP CDynamicStorageEnum::QueryInterface(REFIID iid, void** ppv)
  498. {
  499. static const QITAB qit[] =
  500. {
  501. QITABENT(CDynamicStorageEnum, IEnumSTATSTG),
  502. QITABENT(CDynamicStorageEnum, IEnumShellItems),
  503. { 0 },
  504. };
  505. return QISearch(this, qit, iid, ppv);
  506. }
  507. ULONG STDMETHODCALLTYPE CDynamicStorageEnum::AddRef()
  508. {
  509. return ::InterlockedIncrement(&_cRef);
  510. }
  511. ULONG STDMETHODCALLTYPE CDynamicStorageEnum::Release()
  512. {
  513. ASSERT( 0 != _cRef );
  514. ULONG cRef = InterlockedDecrement(&_cRef);
  515. if ( 0 == cRef )
  516. {
  517. delete this;
  518. }
  519. return cRef;
  520. }
  521. STDAPI CDynamicStorageEnum_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  522. {
  523. *ppv = NULL;
  524. if (punkOuter)
  525. return CLASS_E_NOAGGREGATION;
  526. HRESULT hr = E_OUTOFMEMORY;
  527. CDynamicStorageEnum *pstgEnum = new CDynamicStorageEnum();
  528. if (pstgEnum)
  529. {
  530. hr = pstgEnum->QueryInterface(riid, ppv);
  531. pstgEnum->Release();
  532. }
  533. return hr;
  534. }
  535. STDMETHODIMP CDynamicStorageEnum::Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched)
  536. {
  537. if (!rgelt || celt != 1)
  538. return E_INVALIDARG;
  539. if (pceltFetched)
  540. *pceltFetched = 0;
  541. *rgelt = NULL;
  542. if (_cPos >= _cItems)
  543. return S_FALSE;
  544. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  545. DYNASTGDATA* pData = _pDynStorage->_dpaData.GetPtr(_cPos++);
  546. HRESULT hr;
  547. if (_cPos > _cItems)
  548. {
  549. hr = S_FALSE;
  550. }
  551. else
  552. {
  553. ASSERTMSG(pData != NULL, "dynamic storage has null DPA item");
  554. hr = S_OK;
  555. rgelt[0] = pData->psi;
  556. rgelt[0]->AddRef();
  557. if (pceltFetched)
  558. *pceltFetched = 1;
  559. }
  560. return hr;
  561. }
  562. STDMETHODIMP CDynamicStorageEnum::Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
  563. {
  564. // ISSUE: for now, we only support calling next asking for one item
  565. if (!rgelt || celt != 1)
  566. return E_INVALIDARG;
  567. if (_cPos >= _cItems)
  568. return S_FALSE;
  569. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  570. ZeroMemory(rgelt, sizeof(STATSTG)); // per COM conventions
  571. if (pceltFetched)
  572. *pceltFetched = 0;
  573. HRESULT hr = E_FAIL;
  574. IStorage *pstg;
  575. IStream *pstm;
  576. if (SUCCEEDED(_pDynStorage->_GetStream(_cPos, STGM_READ, &pstm)))
  577. {
  578. hr = pstm->Stat(rgelt, STATFLAG_DEFAULT);
  579. pstm->Release();
  580. }
  581. else if (SUCCEEDED(_pDynStorage->_GetStorage(_cPos, STGM_READ, &pstg)))
  582. {
  583. hr = pstg->Stat(rgelt, STATFLAG_DEFAULT);
  584. pstg->Release();
  585. }
  586. if (SUCCEEDED(hr))
  587. {
  588. _cPos++;
  589. if (pceltFetched)
  590. *pceltFetched = 1;
  591. }
  592. return hr;
  593. }
  594. STDMETHODIMP CDynamicStorageEnum::Skip(ULONG celt)
  595. {
  596. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  597. HRESULT hr;
  598. if (_cPos + celt > _cItems)
  599. {
  600. _cPos = _cItems;
  601. hr = S_FALSE;
  602. }
  603. else
  604. {
  605. _cPos += celt;
  606. hr = S_OK;
  607. }
  608. return hr;
  609. }
  610. STDMETHODIMP CDynamicStorageEnum::Reset()
  611. {
  612. ASSERTMSG(_pDynStorage != NULL, "dynamic storage enumerator initialized with NULL dynamic storage");
  613. _cPos = 0;
  614. return S_OK;
  615. }