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.

1139 lines
33 KiB

  1. #include "shellprv.h"
  2. #include "util.h"
  3. #include "datautil.h"
  4. #include "idlcomm.h"
  5. #include "stgutil.h"
  6. #include "ole2dup.h"
  7. // determines if a string pszChild refers to a stream/storage that exists
  8. // in the parent storage pStorageParent.
  9. STDAPI_(BOOL) StgExists(IStorage * pStorageParent, LPCTSTR pszChild)
  10. {
  11. BOOL fResult = FALSE;
  12. WCHAR wszChild[MAX_PATH];
  13. HRESULT hr;
  14. DWORD grfModeOpen = STGM_READ;
  15. IStream * pStreamOpened;
  16. RIPMSG(pszChild && IS_VALID_STRING_PTR(pszChild, -1), "StgExists: caller passed bad pszPath");
  17. SHTCharToUnicode(pszChild, wszChild, ARRAYSIZE(wszChild));
  18. hr = pStorageParent->OpenStream(wszChild, NULL, grfModeOpen, 0, &pStreamOpened);
  19. if (SUCCEEDED(hr))
  20. {
  21. pStreamOpened->Release();
  22. fResult = TRUE;
  23. }
  24. else
  25. {
  26. IStorage * pStorageOpened;
  27. hr = pStorageParent->OpenStorage(wszChild, NULL, grfModeOpen, NULL, 0, &pStorageOpened);
  28. if (SUCCEEDED(hr))
  29. {
  30. pStorageOpened->Release();
  31. fResult = TRUE;
  32. }
  33. }
  34. return fResult;
  35. }
  36. STDAPI StgCopyFileToStream(LPCTSTR pszSrc, IStream *pStream)
  37. {
  38. IStream *pStreamSrc;
  39. DWORD grfModeSrc = STGM_READ | STGM_DIRECT | STGM_SHARE_DENY_WRITE;
  40. HRESULT hr = SHCreateStreamOnFileEx(pszSrc, grfModeSrc, 0, FALSE, NULL, &pStreamSrc);
  41. if (SUCCEEDED(hr))
  42. {
  43. ULARGE_INTEGER ulMax = {-1, -1};
  44. hr = pStreamSrc->CopyTo(pStream, ulMax, NULL, NULL);
  45. pStreamSrc->Release();
  46. }
  47. if (SUCCEEDED(hr))
  48. {
  49. hr = pStream->Commit(STGC_DEFAULT);
  50. }
  51. return hr;
  52. }
  53. STDAPI StgDeleteUsingDataObject(HWND hwnd, UINT uFlags, IDataObject *pdtobj)
  54. {
  55. // TODO: stick this into aidan's pidl storage and delete via dave's engine
  56. HRESULT hr = E_FAIL;
  57. STGMEDIUM medium;
  58. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  59. if (pida)
  60. {
  61. IStorage *pstg;
  62. LPCITEMIDLIST pidlFolder = IDA_GetIDListPtr(pida, -1);
  63. hr = StgBindToObject(pidlFolder, STGM_READWRITE, IID_PPV_ARG(IStorage, &pstg));
  64. if (SUCCEEDED(hr))
  65. {
  66. IShellFolder *psf;
  67. hr = pstg->QueryInterface(IID_PPV_ARG(IShellFolder, &psf));
  68. if (SUCCEEDED(hr))
  69. {
  70. for (UINT i = 0; (i < pida->cidl) && SUCCEEDED(hr); i++)
  71. {
  72. LPCITEMIDLIST pidl = IDA_GetIDListPtr(pida, i);
  73. WCHAR wzName[MAX_PATH];
  74. hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, wzName, ARRAYSIZE(wzName));
  75. if (SUCCEEDED(hr))
  76. {
  77. hr = pstg->DestroyElement(wzName);
  78. }
  79. }
  80. if (SUCCEEDED(hr))
  81. hr = pstg->Commit(STGC_DEFAULT);
  82. SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST | SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, pidlFolder, NULL);
  83. psf->Release();
  84. }
  85. pstg->Release();
  86. }
  87. HIDA_ReleaseStgMedium(pida, &medium);
  88. }
  89. return hr;
  90. }
  91. STDAPI StgBindToObject(LPCITEMIDLIST pidl, DWORD grfMode, REFIID riid, void **ppv)
  92. {
  93. IBindCtx *pbc;
  94. HRESULT hr = BindCtx_CreateWithMode(grfMode, &pbc);
  95. if (SUCCEEDED(hr))
  96. {
  97. hr = SHBindToObjectEx(NULL, pidl, pbc, riid, ppv);
  98. pbc->Release();
  99. }
  100. return hr;
  101. }
  102. typedef HRESULT (WINAPI * PSTGOPENSTORAGEONHANDLE)(HANDLE,DWORD,void*,void*,REFIID,void**);
  103. STDAPI SHStgOpenStorageOnHandle(HANDLE h, DWORD grfMode, void *res1, void *res2, REFIID riid, void **ppv)
  104. {
  105. static PSTGOPENSTORAGEONHANDLE pfn = NULL;
  106. if (pfn == NULL)
  107. {
  108. HMODULE hmodOle32 = LoadLibraryA("ole32.dll");
  109. if (hmodOle32)
  110. {
  111. pfn = (PSTGOPENSTORAGEONHANDLE)GetProcAddress(hmodOle32, "StgOpenStorageOnHandle");
  112. }
  113. }
  114. if (pfn)
  115. {
  116. return pfn(h, grfMode, res1, res2, riid, ppv);
  117. }
  118. else
  119. {
  120. return E_OUTOFMEMORY;
  121. }
  122. }
  123. STDAPI StgOpenStorageOnFolder(LPCTSTR pszFolder, DWORD grfFlags, REFIID riid, void **ppv)
  124. {
  125. *ppv = NULL;
  126. DWORD dwDesiredAccess, dwShareMode, dwCreationDisposition;
  127. HRESULT hr = ModeToCreateFileFlags(grfFlags, FALSE, &dwDesiredAccess, &dwShareMode, &dwCreationDisposition);
  128. if (SUCCEEDED(hr))
  129. {
  130. // For IPropertySetStorage, we don't want to unnecessarily tie up access to the folder, if all
  131. // we're doing is dealing with property sets. The implementation of IPropertySetStorage for
  132. // NTFS files is defined so that the sharing/access only applies to the property set stream, not
  133. // it's other streams. So it makes sense to do a CreateFile on a folder with full sharing, while perhaps specifying
  134. // STGM_SHARE_EXCLUSIVE for the property set storage.
  135. if (riid == IID_IPropertySetStorage)
  136. dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
  137. HANDLE h = CreateFile(pszFolder, dwDesiredAccess, dwShareMode, NULL,
  138. dwCreationDisposition, FILE_FLAG_BACKUP_SEMANTICS, INVALID_HANDLE_VALUE);
  139. if (INVALID_HANDLE_VALUE != h)
  140. {
  141. hr = SHStgOpenStorageOnHandle(h, grfFlags, NULL, NULL, riid, ppv);
  142. CloseHandle(h);
  143. }
  144. else
  145. {
  146. hr = HRESULT_FROM_WIN32(GetLastError());
  147. }
  148. }
  149. return hr;
  150. }
  151. class CDocWrapperStorage : public IStorage
  152. {
  153. public:
  154. CDocWrapperStorage(LPCTSTR szPath, CDocWrapperStorage *pstgParent, IStorage *pstg);
  155. ~CDocWrapperStorage();
  156. public:
  157. // IUnknown
  158. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  159. STDMETHODIMP_(ULONG) AddRef();
  160. STDMETHODIMP_(ULONG) Release();
  161. // IStorage
  162. STDMETHODIMP Revert()
  163. { return _pstgInner->Revert(); }
  164. STDMETHODIMP DestroyElement(LPCWSTR pszRel)
  165. { return _pstgInner->DestroyElement(pszRel); }
  166. STDMETHODIMP RenameElement(LPCWSTR pwcsOldName, LPCWSTR pwcsNewName)
  167. { return _pstgInner->RenameElement(pwcsOldName, pwcsNewName); }
  168. STDMETHODIMP SetElementTimes(LPCWSTR pszRel, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
  169. { return _pstgInner->SetElementTimes(pszRel, pctime, patime, pmtime); }
  170. STDMETHODIMP SetClass(REFCLSID clsid)
  171. { return _pstgInner->SetClass(clsid); }
  172. STDMETHODIMP SetStateBits(DWORD grfStateBits, DWORD grfMask)
  173. { return _pstgInner->SetStateBits(grfStateBits, grfMask); }
  174. STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  175. { return _pstgInner->Stat(pstatstg, grfStatFlag); }
  176. STDMETHODIMP CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
  177. { return _pstgInner->CopyTo(ciidExclude, rgiidExclude, snbExclude, pstgDest); }
  178. STDMETHODIMP MoveElementTo(LPCWSTR pszRel, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  179. { return _pstgInner->MoveElementTo(pszRel, pstgDest, pwcsNewName, grfFlags); }
  180. STDMETHODIMP EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum)
  181. { return _pstgInner->EnumElements(reserved1, reserved2, reserved3, ppenum); }
  182. STDMETHODIMP Commit(DWORD grfCommitFlags);
  183. STDMETHODIMP CreateStream(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStream **ppstm);
  184. STDMETHODIMP OpenStream(LPCWSTR pszRel, VOID *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
  185. STDMETHODIMP CreateStorage(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStorage **ppstg);
  186. STDMETHODIMP OpenStorage(LPCWSTR pszRel, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
  187. protected:
  188. LONG _cRef;
  189. IStorage *_pstgInner;
  190. CDocWrapperStorage *_pstgParent;
  191. TCHAR _szPath[MAX_PATH];
  192. STDMETHODIMP _MakeNewStorage(DWORD grfMode, CDocWrapperStorage **ppwstg);
  193. STDMETHODIMP _GetRelPath(LPTSTR pszRelPath);
  194. STDMETHODIMP _GetNewRootStorage(DWORD grfMode, CDocWrapperStorage **ppwstgRoot);
  195. STDMETHODIMP _ReOpen(LPCTSTR pszRelPath, DWORD grfMode, CDocWrapperStorage **ppwstg);
  196. STDMETHODIMP _OpenStorage(LPCWSTR pszRel, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, CDocWrapperStorage **ppwstg);
  197. };
  198. class CDocWrapperStream : public IStream
  199. {
  200. public:
  201. CDocWrapperStream(CDocWrapperStorage *pstgParent, IStream *pstm);
  202. ~CDocWrapperStream();
  203. public:
  204. // IUnknown
  205. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  206. STDMETHODIMP_(ULONG) AddRef();
  207. STDMETHODIMP_(ULONG) Release();
  208. // IStream
  209. STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead)
  210. { return _pstmInner->Read(pv, cb, pcbRead); }
  211. STDMETHODIMP Write(void const *pv, ULONG cb, ULONG *pcbWritten)
  212. { return _pstmInner->Write(pv, cb, pcbWritten); }
  213. STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  214. { return _pstmInner->Seek(dlibMove, dwOrigin, plibNewPosition); }
  215. STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
  216. { return _pstmInner->SetSize(libNewSize); }
  217. STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  218. { return _pstmInner->CopyTo(pstm, cb, pcbRead, pcbWritten); }
  219. STDMETHODIMP Commit(DWORD grfCommitFlags)
  220. { return _pstmInner->Commit(grfCommitFlags); }
  221. STDMETHODIMP Revert()
  222. { return _pstmInner->Revert(); }
  223. STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  224. { return _pstmInner->LockRegion(libOffset, cb, dwLockType); }
  225. STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  226. { return _pstmInner->UnlockRegion(libOffset, cb, dwLockType); }
  227. STDMETHODIMP Clone(IStream **ppstm)
  228. { return _pstmInner->Clone(ppstm); }
  229. STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  230. { return _pstmInner->Stat(pstatstg, grfStatFlag); }
  231. protected:
  232. LONG _cRef;
  233. IStream *_pstmInner;
  234. CDocWrapperStorage *_pstgParent;
  235. };
  236. // this switches up the grfMode for elements in a docfile.
  237. // docfiles are limited to ALWAYS opening elements in exclusive mode, so we
  238. // enforce that here.
  239. DWORD _MungeModeForElements(DWORD grfMode)
  240. {
  241. grfMode &= ~(STGM_TRANSACTED | STGM_SHARE_DENY_NONE | STGM_SHARE_DENY_WRITE | STGM_SHARE_DENY_READ);
  242. grfMode |= STGM_DIRECT | STGM_SHARE_EXCLUSIVE;
  243. return grfMode;
  244. }
  245. // this switches up the grfMode for the root storage for a docfile.
  246. // if we open the root in exclusive mode, then we're in trouble for sure since
  247. // nobody else can get to any of the elements.
  248. // the root is the only guy that docfiles can share too so we take advantage
  249. // of that by enforcing STGM_TRANSACTED and STGM_SHARE_DENY_NONE.
  250. DWORD _MungeModeForRoot(DWORD grfMode)
  251. {
  252. grfMode &= ~(STGM_DIRECT | STGM_SHARE_DENY_READ | STGM_SHARE_DENY_WRITE | STGM_SHARE_EXCLUSIVE);
  253. grfMode |= STGM_TRANSACTED | STGM_SHARE_DENY_NONE;
  254. return grfMode;
  255. }
  256. STDAPI StgGetStorageFromFile(LPCWSTR wzPath, DWORD grfMode, IStorage **ppstg)
  257. {
  258. IStorage *pstgUnwrapped;
  259. HRESULT hr = StgOpenStorageEx(wzPath, _MungeModeForRoot(grfMode), STGFMT_ANY, 0, NULL, NULL, IID_PPV_ARG(IStorage, &pstgUnwrapped));
  260. if (SUCCEEDED(hr))
  261. {
  262. // wrap the docfile storage.
  263. CDocWrapperStorage *pwstg = new CDocWrapperStorage(wzPath, NULL, pstgUnwrapped);
  264. if (pwstg)
  265. {
  266. hr = pwstg->QueryInterface(IID_PPV_ARG(IStorage, ppstg));
  267. pwstg->Release();
  268. }
  269. else
  270. {
  271. hr = E_OUTOFMEMORY;
  272. }
  273. pstgUnwrapped->Release();
  274. }
  275. return hr;
  276. }
  277. // CDocWrapperStorage
  278. CDocWrapperStorage::CDocWrapperStorage(LPCTSTR pszPath, CDocWrapperStorage *pstgParent, IStorage *pstg) :
  279. _cRef(1)
  280. {
  281. _pstgParent = pstgParent;
  282. if (_pstgParent)
  283. _pstgParent->AddRef();
  284. _pstgInner = pstg;
  285. _pstgInner->AddRef();
  286. // if this is the root docfile storage, keep track of the fs path that was used to
  287. // open it (since we might need to open it again).
  288. lstrcpyn(_szPath, pszPath, ARRAYSIZE(_szPath));
  289. DllAddRef();
  290. }
  291. CDocWrapperStorage::~CDocWrapperStorage()
  292. {
  293. ATOMICRELEASE(_pstgParent);
  294. ATOMICRELEASE(_pstgInner);
  295. DllRelease();
  296. }
  297. // IUnknown
  298. STDMETHODIMP_(ULONG) CDocWrapperStorage::AddRef()
  299. {
  300. return InterlockedIncrement(&_cRef);
  301. }
  302. STDMETHODIMP_(ULONG) CDocWrapperStorage::Release()
  303. {
  304. if (InterlockedDecrement(&_cRef))
  305. return _cRef;
  306. delete this;
  307. return 0;
  308. }
  309. HRESULT CDocWrapperStorage::QueryInterface(REFIID riid, void **ppv)
  310. {
  311. static const QITAB qit[] =
  312. {
  313. QITABENT(CDocWrapperStorage, IStorage), // IID_IStorage
  314. { 0 },
  315. };
  316. // NOTE: this will fail on IPropertySetStorage.
  317. // can the docfile storage be aggregated?
  318. // in any case the IPropertySetStorage routines don't need to use this
  319. // wrapper for any lifetime issues.
  320. return QISearch(this, qit, riid, ppv);
  321. }
  322. // IStorage
  323. STDMETHODIMP CDocWrapperStorage::Commit(DWORD grfCommitFlags)
  324. {
  325. HRESULT hr = _pstgInner->Commit(grfCommitFlags);
  326. if (_pstgParent && SUCCEEDED(hr))
  327. hr = _pstgParent->Commit(grfCommitFlags);
  328. return hr;
  329. }
  330. STDMETHODIMP CDocWrapperStorage::CreateStream(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStream **ppstm)
  331. {
  332. IStream *pstm;
  333. HRESULT hr = _pstgInner->CreateStream(pwcsName, _MungeModeForElements(grfMode), res1, res2, &pstm);
  334. if (SUCCEEDED(hr))
  335. {
  336. CDocWrapperStream *pwstm = new CDocWrapperStream(this, pstm);
  337. if (pwstm)
  338. {
  339. hr = pwstm->QueryInterface(IID_PPV_ARG(IStream, ppstm));
  340. pwstm->Release();
  341. }
  342. else
  343. {
  344. hr = E_OUTOFMEMORY;
  345. }
  346. pstm->Release();
  347. }
  348. return hr;
  349. }
  350. STDMETHODIMP CDocWrapperStorage::CreateStorage(LPCWSTR pwcsName, DWORD grfMode, DWORD res1, DWORD res2, IStorage **ppstg)
  351. {
  352. IStorage *pstg;
  353. HRESULT hr = _pstgInner->CreateStorage(pwcsName, _MungeModeForElements(grfMode), res1, res2, &pstg);
  354. if (SUCCEEDED(hr))
  355. {
  356. CDocWrapperStorage *pwstg = new CDocWrapperStorage(NULL, this, pstg);
  357. if (pwstg)
  358. {
  359. hr = pwstg->QueryInterface(IID_PPV_ARG(IStorage, ppstg));
  360. pwstg->Release();
  361. }
  362. else
  363. {
  364. hr = E_OUTOFMEMORY;
  365. }
  366. pstg->Release();
  367. }
  368. return hr;
  369. }
  370. // TODO: move this away from a MAX_PATH total length restriction
  371. // gets a "path" relative from the root storage down to this element.
  372. // see comments for _MakeNewStorage.
  373. STDMETHODIMP CDocWrapperStorage::_GetRelPath(LPTSTR pszRelPath)
  374. {
  375. HRESULT hr = S_OK;
  376. if (_pstgParent)
  377. {
  378. // first get the path up to here from the root.
  379. hr = _pstgParent->_GetRelPath(pszRelPath);
  380. if (SUCCEEDED(hr))
  381. {
  382. STATSTG stat;
  383. hr = Stat(&stat, STATFLAG_DEFAULT);
  384. if (SUCCEEDED(hr))
  385. {
  386. // now append the name of this element.
  387. if (!PathAppend(pszRelPath, stat.pwcsName))
  388. hr = E_FAIL;
  389. CoTaskMemFree(stat.pwcsName);
  390. }
  391. }
  392. }
  393. else
  394. {
  395. // we are the root, so init the string.
  396. pszRelPath[0] = 0;
  397. }
  398. return hr;
  399. }
  400. // opens another instance of the root storage.
  401. // see comments for _MakeNewStorage.
  402. STDMETHODIMP CDocWrapperStorage::_GetNewRootStorage(DWORD grfMode, CDocWrapperStorage **ppwstgRoot)
  403. {
  404. HRESULT hr = S_OK;
  405. if (_pstgParent)
  406. {
  407. // get it from our parent.
  408. hr = _pstgParent->_GetNewRootStorage(grfMode, ppwstgRoot);
  409. }
  410. else
  411. {
  412. // we are the root.
  413. IStorage *pstgUnwrapped;
  414. hr = StgOpenStorageEx(_szPath, _MungeModeForRoot(grfMode), STGFMT_ANY, 0, NULL, NULL, IID_PPV_ARG(IStorage, &pstgUnwrapped));
  415. if (SUCCEEDED(hr))
  416. {
  417. *ppwstgRoot = new CDocWrapperStorage(_szPath, NULL, pstgUnwrapped);
  418. if (!*ppwstgRoot)
  419. hr = E_OUTOFMEMORY;
  420. pstgUnwrapped->Release();
  421. }
  422. }
  423. return hr;
  424. }
  425. // opens storages using the "path" in pszRelPath.
  426. // see comments for _MakeNewStorage.
  427. STDMETHODIMP CDocWrapperStorage::_ReOpen(LPCTSTR pszRelPath, DWORD grfMode, CDocWrapperStorage **ppwstg)
  428. {
  429. HRESULT hr = S_OK;
  430. // no relative path signifies that we want this storage itself
  431. if (!pszRelPath || !pszRelPath[0])
  432. {
  433. *ppwstg = this;
  434. AddRef();
  435. }
  436. else
  437. {
  438. TCHAR szElementName[MAX_PATH];
  439. hr = _NextSegment(&pszRelPath, szElementName, ARRAYSIZE(szElementName), TRUE);
  440. if (SUCCEEDED(hr))
  441. {
  442. CDocWrapperStorage *pwstg;
  443. hr = _OpenStorage(szElementName, NULL, grfMode, NULL, 0, &pwstg);
  444. if (SUCCEEDED(hr))
  445. {
  446. hr = pwstg->_ReOpen(pszRelPath, grfMode, ppwstg);
  447. pwstg->Release();
  448. }
  449. }
  450. }
  451. return hr;
  452. }
  453. // NOTE: this is needed if we want to open an element of the docfile in non-exclusive mode.
  454. // to do that we need to get back to the root, open another copy of the root in
  455. // non-exclusive mode, and then come back down.
  456. STDMETHODIMP CDocWrapperStorage::_MakeNewStorage(DWORD grfMode, CDocWrapperStorage **ppwstg)
  457. {
  458. TCHAR szRelPath[MAX_PATH];
  459. HRESULT hr = _GetRelPath(szRelPath);
  460. if (SUCCEEDED(hr))
  461. {
  462. CDocWrapperStorage *pwstgRoot;
  463. hr = _GetNewRootStorage(grfMode, &pwstgRoot);
  464. if (SUCCEEDED(hr))
  465. {
  466. hr = pwstgRoot->_ReOpen(szRelPath, grfMode, ppwstg);
  467. pwstgRoot->Release();
  468. }
  469. }
  470. return hr;
  471. }
  472. STDMETHODIMP CDocWrapperStorage::OpenStream(LPCWSTR pwcsName, void *res1, DWORD grfMode, DWORD res2, IStream **ppstm)
  473. {
  474. IStream *pstm;
  475. HRESULT hr = _pstgInner->OpenStream(pwcsName, res1, _MungeModeForElements(grfMode), res2, &pstm);
  476. if (hr == STG_E_ACCESSDENIED)
  477. {
  478. // we're in trouble -- the stream has been opened with SHARE_EXCLUSIVE already
  479. // so we need to back up to the root storage, open another instance of that,
  480. // and come back down here.
  481. CDocWrapperStorage *pstgNew;
  482. hr = _MakeNewStorage(grfMode, &pstgNew);
  483. if (SUCCEEDED(hr))
  484. {
  485. hr = pstgNew->OpenStream(pwcsName, res1, grfMode, res2, ppstm);
  486. pstgNew->Release();
  487. }
  488. }
  489. else if (SUCCEEDED(hr))
  490. {
  491. CDocWrapperStream *pwstm = new CDocWrapperStream(this, pstm);
  492. if (pwstm)
  493. {
  494. hr = pwstm->QueryInterface(IID_PPV_ARG(IStream, ppstm));
  495. pwstm->Release();
  496. }
  497. else
  498. {
  499. hr = E_OUTOFMEMORY;
  500. }
  501. pstm->Release();
  502. }
  503. return hr;
  504. }
  505. STDMETHODIMP CDocWrapperStorage::_OpenStorage(LPCWSTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD res, CDocWrapperStorage **ppwstg)
  506. {
  507. IStorage *pstg;
  508. HRESULT hr = _pstgInner->OpenStorage(pwcsName, pstgPriority, _MungeModeForElements(grfMode), snbExclude, res, &pstg);
  509. if (hr == STG_E_ACCESSDENIED)
  510. {
  511. // we're in trouble -- the storage has been opened with SHARE_EXCLUSIVE already
  512. // so we need to back up to the root storage, open another instance of that,
  513. // and come back down here.
  514. CDocWrapperStorage *pstgNew;
  515. hr = _MakeNewStorage(grfMode, &pstgNew);
  516. if (SUCCEEDED(hr))
  517. {
  518. hr = pstgNew->_OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, res, ppwstg);
  519. pstgNew->Release();
  520. }
  521. }
  522. else if (SUCCEEDED(hr))
  523. {
  524. *ppwstg = new CDocWrapperStorage(NULL, this, pstg);
  525. if (!*ppwstg)
  526. hr = E_OUTOFMEMORY;
  527. pstg->Release();
  528. }
  529. return hr;
  530. }
  531. STDMETHODIMP CDocWrapperStorage::OpenStorage(LPCWSTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD res, IStorage **ppstg)
  532. {
  533. CDocWrapperStorage *pwstg;
  534. HRESULT hr = _OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, res, &pwstg);
  535. if (SUCCEEDED(hr))
  536. {
  537. hr = pwstg->QueryInterface(IID_PPV_ARG(IStorage, ppstg));
  538. pwstg->Release();
  539. }
  540. else
  541. hr = E_OUTOFMEMORY;
  542. return hr;
  543. }
  544. // CDocWrapperStream
  545. CDocWrapperStream::CDocWrapperStream(CDocWrapperStorage *pstgParent, IStream *pstm) :
  546. _cRef(1)
  547. {
  548. _pstgParent = pstgParent;
  549. _pstgParent->AddRef();
  550. _pstmInner = pstm;
  551. _pstmInner->AddRef();
  552. DllAddRef();
  553. }
  554. CDocWrapperStream::~CDocWrapperStream()
  555. {
  556. ATOMICRELEASE(_pstgParent);
  557. ATOMICRELEASE(_pstmInner);
  558. DllRelease();
  559. }
  560. // IUnknown
  561. STDMETHODIMP_(ULONG) CDocWrapperStream::AddRef()
  562. {
  563. return InterlockedIncrement(&_cRef);
  564. }
  565. STDMETHODIMP_(ULONG) CDocWrapperStream::Release()
  566. {
  567. if (InterlockedDecrement(&_cRef))
  568. return _cRef;
  569. delete this;
  570. return 0;
  571. }
  572. HRESULT CDocWrapperStream::QueryInterface(REFIID riid, void **ppv)
  573. {
  574. static const QITAB qit[] =
  575. {
  576. QITABENT(CDocWrapperStream, IStream), // IID_IStream
  577. { 0 },
  578. };
  579. return QISearch(this, qit, riid, ppv);
  580. }
  581. // CShortcutStorage
  582. class CShortcutStorage : public IStorage
  583. {
  584. public:
  585. CShortcutStorage(IStorage *pstg);
  586. ~CShortcutStorage();
  587. public:
  588. // IUnknown
  589. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  590. STDMETHODIMP_(ULONG) AddRef();
  591. STDMETHODIMP_(ULONG) Release();
  592. // IStorage
  593. STDMETHODIMP CreateStream(LPCWSTR pszRel, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm)
  594. { return _pstgInner->CreateStream(pszRel, grfMode, reserved1, reserved2, ppstm); }
  595. STDMETHODIMP CreateStorage(LPCWSTR pszRel, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStorage **ppstg)
  596. { return _pstgInner->CreateStorage(pszRel, grfMode, reserved1, reserved2, ppstg); }
  597. STDMETHODIMP Commit(DWORD grfCommitFlags)
  598. { return _pstgInner->Commit(grfCommitFlags); }
  599. STDMETHODIMP Revert()
  600. { return _pstgInner->Revert(); }
  601. STDMETHODIMP DestroyElement(LPCWSTR pszRel)
  602. { return _pstgInner->DestroyElement(pszRel); }
  603. STDMETHODIMP RenameElement(LPCWSTR pwcsOldName, LPCWSTR pwcsNewName)
  604. { return _pstgInner->RenameElement(pwcsOldName, pwcsNewName); }
  605. STDMETHODIMP SetElementTimes(LPCWSTR pszRel, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime)
  606. { return _pstgInner->SetElementTimes(pszRel, pctime, patime, pmtime); }
  607. STDMETHODIMP SetClass(REFCLSID clsid)
  608. { return _pstgInner->SetClass(clsid); }
  609. STDMETHODIMP SetStateBits(DWORD grfStateBits, DWORD grfMask)
  610. { return _pstgInner->SetStateBits(grfStateBits, grfMask); }
  611. STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  612. { return _pstgInner->Stat(pstatstg, grfStatFlag); }
  613. STDMETHODIMP OpenStream(LPCWSTR pszRel, VOID *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm);
  614. STDMETHODIMP OpenStorage(LPCWSTR pszRel, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg);
  615. STDMETHODIMP CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest)
  616. { return E_NOTIMPL; };
  617. STDMETHODIMP MoveElementTo(LPCWSTR pszRel, IStorage *pstgDest, LPCWSTR pwcsNewName, DWORD grfFlags)
  618. { return E_NOTIMPL; };
  619. STDMETHODIMP EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum);
  620. protected:
  621. LONG _cRef;
  622. IStorage *_pstgInner;
  623. };
  624. class CShortcutStream : public IStream
  625. {
  626. public:
  627. CShortcutStream(LPCWSTR pwzRealName, IStream *pstm);
  628. ~CShortcutStream();
  629. public:
  630. // IUnknown
  631. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  632. STDMETHODIMP_(ULONG) AddRef();
  633. STDMETHODIMP_(ULONG) Release();
  634. // IStream
  635. STDMETHODIMP Read(void *pv, ULONG cb, ULONG *pcbRead)
  636. { return _pstmInner->Read(pv, cb, pcbRead); }
  637. STDMETHODIMP Write(void const *pv, ULONG cb, ULONG *pcbWritten)
  638. { return _pstmInner->Write(pv, cb, pcbWritten); }
  639. STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  640. { return _pstmInner->Seek(dlibMove, dwOrigin, plibNewPosition); }
  641. STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
  642. { return _pstmInner->SetSize(libNewSize); }
  643. STDMETHODIMP CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  644. { return _pstmInner->CopyTo(pstm, cb, pcbRead, pcbWritten); }
  645. STDMETHODIMP Commit(DWORD grfCommitFlags)
  646. { return _pstmInner->Commit(grfCommitFlags); }
  647. STDMETHODIMP Revert()
  648. { return _pstmInner->Revert(); }
  649. STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  650. { return _pstmInner->LockRegion(libOffset, cb, dwLockType); }
  651. STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  652. { return _pstmInner->UnlockRegion(libOffset, cb, dwLockType); }
  653. STDMETHODIMP Clone(IStream **ppstm)
  654. { return _pstmInner->Clone(ppstm); }
  655. STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag);
  656. protected:
  657. LONG _cRef;
  658. WCHAR _wzName[MAX_PATH];
  659. IStream *_pstmInner;
  660. };
  661. class CShortcutStorageEnumSTATSTG : public IEnumSTATSTG
  662. {
  663. public:
  664. // IUnknown
  665. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  666. STDMETHODIMP_(ULONG) AddRef();
  667. STDMETHODIMP_(ULONG) Release();
  668. // IEnumSTATSTG
  669. STDMETHODIMP Skip(ULONG celt)
  670. { return _penumInner->Skip(celt); };
  671. STDMETHODIMP Reset()
  672. { return _penumInner->Reset(); };
  673. STDMETHODIMP Clone(IEnumSTATSTG **ppenum)
  674. { return _penumInner->Clone(ppenum); };
  675. STDMETHODIMP Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched);
  676. protected:
  677. CShortcutStorageEnumSTATSTG(CShortcutStorage *psstg, IEnumSTATSTG *penum);
  678. ~CShortcutStorageEnumSTATSTG();
  679. private:
  680. LONG _cRef;
  681. CShortcutStorage *_psstg;
  682. IEnumSTATSTG *_penumInner;
  683. friend CShortcutStorage;
  684. };
  685. CShortcutStorage::CShortcutStorage(IStorage *pstg) :
  686. _cRef(1),
  687. _pstgInner(pstg)
  688. {
  689. _pstgInner->AddRef();
  690. DllAddRef();
  691. }
  692. CShortcutStorage::~CShortcutStorage()
  693. {
  694. ATOMICRELEASE(_pstgInner);
  695. DllRelease();
  696. }
  697. // IUnknown
  698. STDMETHODIMP_(ULONG) CShortcutStorage::AddRef()
  699. {
  700. return InterlockedIncrement(&_cRef);
  701. }
  702. STDMETHODIMP_(ULONG) CShortcutStorage::Release()
  703. {
  704. if (InterlockedDecrement(&_cRef))
  705. return _cRef;
  706. delete this;
  707. return 0;
  708. }
  709. HRESULT CShortcutStorage::QueryInterface(REFIID riid, void **ppv)
  710. {
  711. static const QITAB qit[] =
  712. {
  713. QITABENT(CShortcutStorage, IStorage),
  714. { 0 },
  715. };
  716. return QISearch(this, qit, riid, ppv);
  717. }
  718. // IStorage
  719. STDMETHODIMP CShortcutStorage::OpenStream(LPCWSTR pwcsName, void *res1, DWORD grfMode, DWORD res2, IStream **ppstm)
  720. {
  721. IStream *pstmLink;
  722. HRESULT hr = _pstgInner->OpenStream(pwcsName, res1, grfMode, res2, &pstmLink);
  723. if (SUCCEEDED(hr))
  724. {
  725. IPersistStream *pps;
  726. hr = SHCoCreateInstance(NULL, &CLSID_ShellLink, NULL, IID_PPV_ARG(IPersistStream, &pps));
  727. if (SUCCEEDED(hr))
  728. {
  729. hr = pps->Load(pstmLink);
  730. IShellLink *psl;
  731. if (SUCCEEDED(hr))
  732. hr = pps->QueryInterface(IID_PPV_ARG(IShellLink, &psl));
  733. if (SUCCEEDED(hr))
  734. {
  735. LPITEMIDLIST pidl;
  736. hr = psl->GetIDList(&pidl);
  737. if (hr == S_OK)
  738. {
  739. IStream *pstmReal;
  740. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IStream, pidl, &pstmReal));
  741. if (SUCCEEDED(hr))
  742. {
  743. CShortcutStream *psstm = new CShortcutStream(pwcsName, pstmReal);
  744. if (psstm)
  745. {
  746. hr = psstm->QueryInterface(IID_PPV_ARG(IStream, ppstm));
  747. psstm->Release();
  748. }
  749. else
  750. {
  751. hr = E_OUTOFMEMORY;
  752. }
  753. pstmReal->Release();
  754. }
  755. ILFree(pidl);
  756. }
  757. else
  758. {
  759. // munge S_FALSE into E_FAIL (initialization must have failed for the link)
  760. hr = SUCCEEDED(hr) ? E_FAIL : hr;
  761. }
  762. psl->Release();
  763. }
  764. pps->Release();
  765. }
  766. // fall back to the non-link stream
  767. if (FAILED(hr))
  768. {
  769. hr = pstmLink->QueryInterface(IID_PPV_ARG(IStream, ppstm));
  770. }
  771. pstmLink->Release();
  772. }
  773. return hr;
  774. }
  775. STDMETHODIMP CShortcutStorage::OpenStorage(LPCWSTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD res, IStorage **ppstg)
  776. {
  777. IStorage *pstg;
  778. HRESULT hr = _pstgInner->OpenStorage(pwcsName, pstgPriority, grfMode, snbExclude, res, &pstg);
  779. if (SUCCEEDED(hr))
  780. {
  781. CShortcutStorage *psstg = new CShortcutStorage(pstg);
  782. if (psstg)
  783. {
  784. hr = psstg->QueryInterface(IID_PPV_ARG(IStorage, ppstg));
  785. psstg->Release();
  786. }
  787. else
  788. {
  789. hr = E_OUTOFMEMORY;
  790. }
  791. pstg->Release();
  792. }
  793. return hr;
  794. }
  795. STDMETHODIMP CShortcutStorage::EnumElements(DWORD res1, void *res2, DWORD res3, IEnumSTATSTG **ppenum)
  796. {
  797. IEnumSTATSTG *penum;
  798. HRESULT hr = _pstgInner->EnumElements(res1, res2, res3, &penum);
  799. if (SUCCEEDED(hr))
  800. {
  801. CShortcutStorageEnumSTATSTG *pssenum = new CShortcutStorageEnumSTATSTG(this, penum);
  802. if (pssenum)
  803. {
  804. *ppenum = (IEnumSTATSTG *) pssenum;
  805. hr = S_OK;
  806. }
  807. else
  808. {
  809. *ppenum = NULL;
  810. hr = E_OUTOFMEMORY;
  811. }
  812. penum->Release();
  813. }
  814. return hr;
  815. }
  816. // CShortcutStorageEnumSTATSTG
  817. CShortcutStorageEnumSTATSTG::CShortcutStorageEnumSTATSTG(CShortcutStorage *psstg, IEnumSTATSTG *penum) :
  818. _cRef(1)
  819. {
  820. _psstg = psstg;
  821. _psstg->AddRef();
  822. _penumInner = penum;
  823. _penumInner->AddRef();
  824. DllAddRef();
  825. }
  826. CShortcutStorageEnumSTATSTG::~CShortcutStorageEnumSTATSTG()
  827. {
  828. ATOMICRELEASE(_psstg);
  829. ATOMICRELEASE(_penumInner);
  830. DllRelease();
  831. }
  832. // IUnknown
  833. STDMETHODIMP_(ULONG) CShortcutStorageEnumSTATSTG::AddRef()
  834. {
  835. return InterlockedIncrement(&_cRef);
  836. }
  837. STDMETHODIMP_(ULONG) CShortcutStorageEnumSTATSTG::Release()
  838. {
  839. if (InterlockedDecrement(&_cRef))
  840. return _cRef;
  841. delete this;
  842. return 0;
  843. }
  844. HRESULT CShortcutStorageEnumSTATSTG::QueryInterface(REFIID riid, void **ppv)
  845. {
  846. static const QITAB qit[] =
  847. {
  848. QITABENT(CShortcutStorageEnumSTATSTG, IEnumSTATSTG),
  849. { 0 },
  850. };
  851. return QISearch(this, qit, riid, ppv);
  852. }
  853. // IStorage
  854. HRESULT CShortcutStorageEnumSTATSTG::Next(ULONG celt, STATSTG *rgelt, ULONG *pceltFetched)
  855. {
  856. ASSERTMSG((rgelt != NULL), "bad input parameter rgelt in CShortcutStorageEnumSTATSTG::Next");
  857. ZeroMemory(rgelt, sizeof(STATSTG)); // per COM conventions
  858. STATSTG stat;
  859. // we just get the next element from the inner enumeration so that we can
  860. // get the name of it and keep our ordering. all the other data is useless.
  861. HRESULT hr = _penumInner->Next(1, &stat, NULL);
  862. if (hr == S_OK)
  863. {
  864. switch (stat.type)
  865. {
  866. case STGTY_STORAGE:
  867. // if it's a storage, the data is good enough.
  868. memcpy(rgelt, &stat, sizeof(STATSTG));
  869. break;
  870. case STGTY_STREAM:
  871. // we need to dereference the link and get the real data.
  872. IStream *pstm;
  873. // TODO: make sure that nobody else has this guy open in exclusive mode.
  874. hr = _psstg->OpenStream(stat.pwcsName, NULL, STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pstm);
  875. if (SUCCEEDED(hr))
  876. {
  877. hr = pstm->Stat(rgelt, STATFLAG_DEFAULT);
  878. pstm->Release();
  879. }
  880. CoTaskMemFree(stat.pwcsName);
  881. break;
  882. default:
  883. ASSERTMSG(FALSE, "Unknown type in storage.");
  884. break;
  885. }
  886. if (SUCCEEDED(hr) && pceltFetched)
  887. *pceltFetched = 1;
  888. }
  889. return hr;
  890. }
  891. // CShortcutStream
  892. CShortcutStream::CShortcutStream(LPCWSTR pwzRealName, IStream *pstm) :
  893. _cRef(1),
  894. _pstmInner(pstm)
  895. {
  896. _pstmInner->AddRef();
  897. lstrcpyn(_wzName, pwzRealName, ARRAYSIZE(_wzName));
  898. DllAddRef();
  899. }
  900. CShortcutStream::~CShortcutStream()
  901. {
  902. ATOMICRELEASE(_pstmInner);
  903. DllRelease();
  904. }
  905. // IUnknown
  906. STDMETHODIMP_(ULONG) CShortcutStream::AddRef()
  907. {
  908. return InterlockedIncrement(&_cRef);
  909. }
  910. STDMETHODIMP_(ULONG) CShortcutStream::Release()
  911. {
  912. if (InterlockedDecrement(&_cRef))
  913. return _cRef;
  914. delete this;
  915. return 0;
  916. }
  917. HRESULT CShortcutStream::QueryInterface(REFIID riid, void **ppv)
  918. {
  919. static const QITAB qit[] =
  920. {
  921. QITABENT(CShortcutStream, IStream),
  922. { 0 },
  923. };
  924. return QISearch(this, qit, riid, ppv);
  925. }
  926. // IStream
  927. HRESULT CShortcutStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  928. {
  929. ASSERTMSG((pstatstg != NULL), "bad input parameter pstatstg in CShortcutStream::Stat");
  930. STATSTG stat;
  931. HRESULT hr = _pstmInner->Stat(&stat, grfStatFlag);
  932. if (SUCCEEDED(hr))
  933. {
  934. // move all the fields over (we won't change most of em)
  935. memcpy(pstatstg, &stat, sizeof(STATSTG));
  936. // overwrite the name field with what we have
  937. if (grfStatFlag == STATFLAG_DEFAULT)
  938. {
  939. hr = SHStrDup(_wzName, &pstatstg->pwcsName);
  940. CoTaskMemFree(stat.pwcsName);
  941. }
  942. }
  943. return hr;
  944. }
  945. STDAPI CShortcutStorage_CreateInstance(IStorage *pstg, REFIID riid, void **ppv)
  946. {
  947. if (!pstg)
  948. return E_INVALIDARG;
  949. CShortcutStorage *pscstg = new CShortcutStorage(pstg);
  950. if (!pscstg)
  951. return E_OUTOFMEMORY;
  952. HRESULT hr = pscstg->QueryInterface(riid, ppv);
  953. pscstg->Release();
  954. return hr;
  955. }