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.

441 lines
12 KiB

  1. #include "sfstorage.h"
  2. class CSFStorageEnum : public IEnumSTATSTG
  3. {
  4. public:
  5. // IUnknown
  6. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  7. STDMETHOD_(ULONG, AddRef)();
  8. STDMETHOD_(ULONG, Release)();
  9. // IEnumSTATSTG
  10. STDMETHOD(Skip)(ULONG celt)
  11. { return E_NOTIMPL; };
  12. STDMETHOD(Clone)(IEnumSTATSTG **ppenum)
  13. { return E_NOTIMPL; };
  14. STDMETHOD(Next)(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched);
  15. STDMETHOD(Reset)();
  16. protected:
  17. CSFStorageEnum(CSFStorage* psfstg);
  18. ~CSFStorageEnum();
  19. private:
  20. LONG _cRef;
  21. CSFStorage *_psfstg;
  22. IEnumIDList *_peidl;
  23. HRESULT _PidlToSTATSTG(LPCITEMIDLIST pidl, STATSTG *pstatstg);
  24. friend CSFStorage;
  25. };
  26. CSFStorageEnum::CSFStorageEnum(CSFStorage *psfstg) :
  27. _cRef(1)
  28. {
  29. _psfstg = psfstg;
  30. _psfstg->AddRef();
  31. DllAddRef();
  32. }
  33. CSFStorageEnum::~CSFStorageEnum()
  34. {
  35. _psfstg->Release();
  36. ATOMICRELEASE(_peidl);
  37. DllRelease();
  38. }
  39. STDMETHODIMP_(ULONG) CSFStorageEnum::AddRef()
  40. {
  41. return InterlockedIncrement(&_cRef);
  42. }
  43. STDMETHODIMP_(ULONG) CSFStorageEnum::Release()
  44. {
  45. if (InterlockedDecrement(&_cRef))
  46. return _cRef;
  47. delete this;
  48. return 0;
  49. }
  50. STDMETHODIMP CSFStorageEnum::QueryInterface(REFIID riid, void **ppv)
  51. {
  52. static const QITAB qit[] = {
  53. QITABENT(CSFStorageEnum, IEnumSTATSTG), // IEnumSTATSTG
  54. { 0 },
  55. };
  56. return QISearch(this, qit, riid, ppv);
  57. }
  58. HRESULT CSFStorageEnum::_PidlToSTATSTG(LPCITEMIDLIST pidl, STATSTG *pstatstg)
  59. {
  60. ZeroMemory(pstatstg, sizeof(STATSTG)); // per COM conventions
  61. VARIANT var;
  62. VariantInit(&var);
  63. HRESULT hr = _psfstg->GetDetailsEx(pidl, &SCID_FINDDATA, &var);
  64. if (SUCCEEDED(hr))
  65. {
  66. WIN32_FIND_DATAW wfd;
  67. if (VariantToBuffer(&var, &wfd, sizeof(wfd)))
  68. {
  69. pstatstg->atime = wfd.ftLastAccessTime;
  70. pstatstg->ctime = wfd.ftCreationTime;
  71. pstatstg->mtime = wfd.ftLastWriteTime;
  72. pstatstg->cbSize.HighPart = wfd.nFileSizeHigh;
  73. pstatstg->cbSize.LowPart = wfd.nFileSizeLow;
  74. pstatstg->type = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? STGTY_STORAGE : STGTY_STREAM;
  75. hr = SHStrDupW(wfd.cFileName, &pstatstg->pwcsName);
  76. }
  77. VariantClear(&var);
  78. }
  79. return hr;
  80. }
  81. STDMETHODIMP CSFStorageEnum::Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
  82. {
  83. ASSERT((celt != 1) ? (pceltFetched != NULL) : TRUE);
  84. HRESULT hr = S_OK;
  85. if (!_peidl)
  86. {
  87. hr = _psfstg->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &_peidl);
  88. }
  89. if (S_OK == hr)
  90. {
  91. hr = E_OUTOFMEMORY;
  92. LPITEMIDLIST *apidl = new LPITEMIDLIST[celt];
  93. if (apidl)
  94. {
  95. ULONG celtFetched;
  96. hr = _peidl->Next(celt, apidl, &celtFetched);
  97. if (SUCCEEDED(hr))
  98. {
  99. ULONG celtConverted = 0;
  100. ULONG i;
  101. for (i = 0; i < celtFetched; i++)
  102. {
  103. if (SUCCEEDED(_PidlToSTATSTG(apidl[i], &rgelt[celtConverted])))
  104. {
  105. celtConverted++;
  106. }
  107. }
  108. hr = (celtConverted == celt) ? S_OK : S_FALSE;
  109. if (pceltFetched)
  110. {
  111. *pceltFetched = celtConverted;
  112. }
  113. for (i = 0; i < celtFetched; i++)
  114. {
  115. ILFree(apidl[i]);
  116. }
  117. }
  118. delete apidl;
  119. }
  120. }
  121. return hr;
  122. }
  123. STDMETHODIMP CSFStorageEnum::Reset()
  124. {
  125. HRESULT hr = S_OK;
  126. if (_peidl)
  127. {
  128. hr = _peidl->Reset();
  129. }
  130. return hr;
  131. }
  132. HRESULT CSFStorage::_ParseAndVerify(LPCWSTR pwszName, LPBC pbc, LPITEMIDLIST *ppidl)
  133. {
  134. *ppidl = NULL;
  135. LPITEMIDLIST pidl;
  136. HRESULT hr = ParseDisplayName(NULL, pbc, (LPWSTR) pwszName, NULL, &pidl, NULL);
  137. if (SUCCEEDED(hr))
  138. {
  139. // must be single-level
  140. if (ILFindLastID(pidl) != pidl)
  141. {
  142. hr = E_FAIL;
  143. ILFree(pidl);
  144. }
  145. else
  146. {
  147. *ppidl = pidl;
  148. }
  149. }
  150. return hr;
  151. }
  152. HRESULT CSFStorage::_BindByName(LPCWSTR pwszName, LPBC pbcParse, DWORD grfMode, REFIID riid, void **ppv)
  153. {
  154. *ppv = NULL;
  155. LPITEMIDLIST pidl;
  156. HRESULT hr = _ParseAndVerify(pwszName, pbcParse, &pidl);
  157. if (SUCCEEDED(hr))
  158. {
  159. IBindCtx *pbc;
  160. hr = BindCtx_CreateWithMode(grfMode, &pbc);
  161. if (SUCCEEDED(hr))
  162. {
  163. hr = BindToObject(pidl, pbc, riid, ppv);
  164. pbc->Release();
  165. }
  166. ILFree(pidl);
  167. }
  168. return hr;
  169. }
  170. STDMETHODIMP CSFStorage::Commit(DWORD grfCommitFlags)
  171. {
  172. return S_OK;
  173. }
  174. STDMETHODIMP CSFStorage::Revert()
  175. {
  176. return E_NOTIMPL;
  177. }
  178. STDMETHODIMP CSFStorage::SetClass(REFCLSID clsid)
  179. {
  180. return E_NOTIMPL;
  181. }
  182. STDMETHODIMP CSFStorage::SetStateBits(DWORD grfStateBits, DWORD grfMask)
  183. {
  184. return E_NOTIMPL;
  185. }
  186. STDMETHODIMP CSFStorage::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  187. {
  188. // we can at least get the name to use in STATSTG.
  189. ZeroMemory(pstatstg, sizeof(STATSTG));
  190. LPITEMIDLIST pidl;
  191. HRESULT hr = SHGetIDListFromUnk(SAFECAST(this, IShellFolder2*), &pidl);
  192. if (SUCCEEDED(hr))
  193. {
  194. LPCITEMIDLIST pidlLast;
  195. IShellFolder *psf;
  196. hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  197. if (SUCCEEDED(hr))
  198. {
  199. TCHAR szName[MAX_PATH];
  200. hr = DisplayNameOf(psf, pidlLast, SHGDN_FORPARSING | SHGDN_INFOLDER, szName, ARRAYSIZE(szName));
  201. if (SUCCEEDED(hr))
  202. {
  203. // don't know what mode we were bound with, STGM_READ is good enough.
  204. pstatstg->grfMode = STGM_READ;
  205. if (!(grfStatFlag & STATFLAG_NONAME))
  206. {
  207. hr = SHStrDup(szName, &pstatstg->pwcsName);
  208. }
  209. }
  210. psf->Release();
  211. }
  212. ILFree(pidl);
  213. }
  214. return hr;
  215. }
  216. STDMETHODIMP CSFStorage::EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
  217. {
  218. HRESULT hr;
  219. CSFStorageEnum *penum = new CSFStorageEnum(this);
  220. if (penum)
  221. {
  222. *ppenum = (IEnumSTATSTG *) penum;
  223. hr = S_OK;
  224. }
  225. else
  226. {
  227. *ppenum = NULL;
  228. hr = E_OUTOFMEMORY;
  229. }
  230. return hr;
  231. }
  232. STDMETHODIMP CSFStorage::OpenStream(LPCWSTR pszRel, VOID *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm)
  233. {
  234. HRESULT hr = _BindByName(pszRel, NULL, grfMode, IID_PPV_ARG(IStream, ppstm));
  235. return MapWin32ErrorToSTG(hr);
  236. }
  237. STDMETHODIMP CSFStorage::OpenStorage(LPCWSTR pszRel, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg)
  238. {
  239. HRESULT hr = _BindByName(pszRel, NULL, grfMode, IID_PPV_ARG(IStorage, ppstg));
  240. return MapWin32ErrorToSTG(hr);
  241. }
  242. STDMETHODIMP CSFStorage::DestroyElement(LPCWSTR pszRel)
  243. {
  244. LPITEMIDLIST pidl;
  245. HRESULT hr = _ParseAndVerify(pszRel, NULL, &pidl);
  246. if (SUCCEEDED(hr))
  247. {
  248. hr = _DeleteItemByIDList(pidl);
  249. ILFree(pidl);
  250. }
  251. return hr;
  252. }
  253. STDMETHODIMP CSFStorage::RenameElement(LPCWSTR pwcsOldName, LPCWSTR pwcsNewName)
  254. {
  255. LPITEMIDLIST pidl;
  256. HRESULT hr = _ParseAndVerify(pwcsOldName, NULL, &pidl);
  257. if (SUCCEEDED(hr))
  258. {
  259. // ISSUE: this might put up UI
  260. hr = SetNameOf(NULL, pidl, pwcsNewName, SHGDN_FORPARSING, NULL);
  261. ILFree(pidl);
  262. }
  263. return hr;
  264. }
  265. STDMETHODIMP CSFStorage::SetElementTimes(LPCWSTR pszRel, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
  266. {
  267. // could have another virtual function here for the subclass to implement,
  268. // but nobody ever calls this function anyway.
  269. return E_NOTIMPL;
  270. }
  271. STDMETHODIMP CSFStorage::CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
  272. {
  273. // TODO filefldr doesnt implement this so apparently nobody needs it yet
  274. return E_NOTIMPL;
  275. }
  276. STDMETHODIMP CSFStorage::MoveElementTo(LPCWSTR pszRel, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  277. {
  278. return StgMoveElementTo(SAFECAST(this, IShellFolder *), SAFECAST(this, IStorage *), pszRel, pstgDest, pwcsNewName, grfFlags);
  279. }
  280. HRESULT CSFStorage::_CreateHelper(LPCWSTR pwcsName, DWORD grfMode, REFIID riid, void **ppv)
  281. {
  282. *ppv = NULL;
  283. HRESULT hr = S_OK;
  284. LPITEMIDLIST pidlTemp;
  285. if (!(grfMode & STGM_CREATE) && SUCCEEDED(_ParseAndVerify(pwcsName, NULL, &pidlTemp)))
  286. {
  287. ILFree(pidlTemp);
  288. hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  289. }
  290. if (SUCCEEDED(hr))
  291. {
  292. IBindCtx *pbcParse;
  293. hr = BindCtx_CreateWithMode(STGM_CREATE, &pbcParse);
  294. if (SUCCEEDED(hr))
  295. {
  296. LPITEMIDLIST pidl;
  297. hr = _ParseAndVerify(pwcsName, pbcParse, &pidl);
  298. if (SUCCEEDED(hr))
  299. {
  300. hr = _StgCreate(pidl, grfMode, riid, ppv);
  301. ILFree(pidl);
  302. }
  303. pbcParse->Release();
  304. }
  305. }
  306. return MapWin32ErrorToSTG(hr);
  307. }
  308. STDMETHODIMP CSFStorage::CreateStream(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStream **ppstm)
  309. {
  310. return _CreateHelper(pwcsName, grfMode, IID_PPV_ARG(IStream, ppstm));
  311. }
  312. STDMETHODIMP CSFStorage::CreateStorage(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStorage **ppstg)
  313. {
  314. return _CreateHelper(pwcsName, grfMode, IID_PPV_ARG(IStorage, ppstg));
  315. }
  316. // factored out of filefldr.cpp
  317. HRESULT StgMoveElementTo(IShellFolder *psf, IStorage *pstgSrc, LPCWSTR pwcsName, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  318. {
  319. if ((grfFlags != STGMOVE_MOVE) && (grfFlags != STGMOVE_COPY))
  320. return E_INVALIDARG;
  321. // Get the IDList for the source stream's file
  322. LPITEMIDLIST pidl;
  323. HRESULT hr = psf->ParseDisplayName(NULL, NULL, (LPWSTR) pwcsName, NULL, &pidl, NULL);
  324. if (SUCCEEDED(hr))
  325. {
  326. // Bind to the source file as an IStream
  327. IStream *pstmSrc;
  328. hr = psf->BindToObject(pidl, NULL, IID_PPV_ARG(IStream, &pstmSrc));
  329. if (SUCCEEDED(hr))
  330. {
  331. // Create the destination stream
  332. IStream *pstmDst;
  333. hr = pstgDest->CreateStream(pwcsNewName, STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, NULL, &pstmDst);
  334. if (SUCCEEDED(hr))
  335. {
  336. ULARGE_INTEGER ulMax = {-1, -1}; // whole thing
  337. hr = pstmSrc->CopyTo(pstmDst, ulMax, NULL, NULL);
  338. // If all went well this is a move (not a copy), remove the source
  339. if (SUCCEEDED(hr))
  340. {
  341. hr = pstmDst->Commit(STGC_DEFAULT);
  342. if (SUCCEEDED(hr) && (grfFlags == STGMOVE_MOVE))
  343. hr = pstgSrc->DestroyElement(pwcsName);
  344. }
  345. pstmDst->Release();
  346. }
  347. pstmSrc->Release();
  348. }
  349. else
  350. {
  351. IStorage *pstgSrc;
  352. hr = psf->BindToObject(pidl, NULL, IID_PPV_ARG(IStorage, &pstgSrc));
  353. if (SUCCEEDED(hr))
  354. {
  355. IStorage *pstgDst;
  356. hr = pstgDest->CreateStorage(pwcsNewName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, 0, NULL, &pstgDst);
  357. if (SUCCEEDED(hr))
  358. {
  359. IEnumSTATSTG *penum;
  360. if (S_OK == pstgSrc->EnumElements(0, NULL, 0, &penum))
  361. {
  362. STATSTG stat;
  363. while (S_OK == penum->Next(1, &stat, NULL))
  364. {
  365. hr = pstgSrc->MoveElementTo(stat.pwcsName, pstgDst, stat.pwcsName, grfFlags);
  366. if (SUCCEEDED(hr))
  367. hr = pstgDst->Commit(STGC_DEFAULT);
  368. CoTaskMemFree(stat.pwcsName);
  369. if (FAILED(hr))
  370. break;
  371. }
  372. penum->Release();
  373. }
  374. if (SUCCEEDED(hr))
  375. hr = pstgDst->Commit(STGC_DEFAULT);
  376. pstgDst->Release();
  377. }
  378. pstgSrc->Release();
  379. }
  380. }
  381. ILFree(pidl);
  382. }
  383. return hr;
  384. }