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.

1200 lines
28 KiB

  1. //*******************************************************************************************
  2. //
  3. // Filename : DataObj.cpp
  4. //
  5. // Implementation file for CObjFormats and CCabObj
  6. //
  7. // Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
  8. //
  9. //*******************************************************************************************
  10. #include "pch.h"
  11. #include "ccstock.h"
  12. #include "thisdll.h"
  13. #include "folder.h"
  14. #include "dataobj.h"
  15. #include "cabitms.h"
  16. UINT CCabObj::s_uFileGroupDesc = 0;
  17. UINT CCabObj::s_uFileContents = 0;
  18. UINT CCabObj::s_uPersistedDataObject = 0;
  19. UINT CCabObj::s_uHIDA = 0;
  20. // {dfe49cfe-cd09-11d2-9643-00c04f79adf0}
  21. const GUID CLSID_CabViewDataObject = {0xdfe49cfe, 0xcd09, 0x11d2, 0x96, 0x43, 0x00, 0xc0, 0x4f, 0x79, 0xad, 0xf0};
  22. #define MAX_CHUNK (60*1024) /* max mouthful to CopyTo from CCabStream */
  23. class CCabStream : public IStream
  24. {
  25. public:
  26. CCabStream(HGLOBAL hStream,DWORD dwStreamLength);
  27. ~CCabStream(void);
  28. // *** IUnknown methods ***
  29. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  30. STDMETHODIMP_(ULONG) AddRef();
  31. STDMETHODIMP_(ULONG) Release();
  32. // *** IStream methods ***
  33. STDMETHODIMP Read(void *pv,ULONG cb,ULONG *pcbRead);
  34. STDMETHODIMP Write(const void *pv,ULONG cb,ULONG *pcbWritten);
  35. STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition);
  36. STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize);
  37. STDMETHODIMP CopyTo(IStream * pstm, ULARGE_INTEGER cb, ULARGE_INTEGER * pcbRead, ULARGE_INTEGER * pcbWritten);
  38. STDMETHODIMP Commit(DWORD grfCommitFlags);
  39. STDMETHODIMP Revert(void);
  40. STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
  41. STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType);
  42. STDMETHODIMP Stat(STATSTG * pstatstg, DWORD grfStatFlag);
  43. STDMETHODIMP Clone(IStream ** ppstm);
  44. private:
  45. CRefCount m_cRef;
  46. CRefDll m_cRefDll;
  47. HGLOBAL m_hStream;
  48. DWORD m_dwStreamLength;
  49. DWORD m_dwStreamPosition;
  50. };
  51. CCabStream::CCabStream(HGLOBAL hStream,DWORD dwStreamLength)
  52. {
  53. m_hStream = hStream;
  54. m_dwStreamLength = dwStreamLength;
  55. m_dwStreamPosition = 0;
  56. AddRef();
  57. }
  58. CCabStream::~CCabStream(void)
  59. {
  60. GlobalFree(m_hStream);
  61. }
  62. STDMETHODIMP CCabStream::QueryInterface(
  63. REFIID riid,
  64. LPVOID FAR* ppvObj)
  65. {
  66. *ppvObj = NULL;
  67. LPUNKNOWN pObj;
  68. if (riid == IID_IUnknown)
  69. {
  70. pObj = (IUnknown*)((IStream *)this);
  71. }
  72. else if (riid == IID_IStream)
  73. {
  74. pObj = (IUnknown*)((IStream *)this);
  75. }
  76. else
  77. {
  78. return(E_NOINTERFACE);
  79. }
  80. pObj->AddRef();
  81. *ppvObj = pObj;
  82. return(NOERROR);
  83. }
  84. STDMETHODIMP_(ULONG) CCabStream::AddRef(void)
  85. {
  86. return(m_cRef.AddRef());
  87. }
  88. STDMETHODIMP_(ULONG) CCabStream::Release(void)
  89. {
  90. if (!m_cRef.Release())
  91. {
  92. delete this;
  93. return(0);
  94. }
  95. return(m_cRef.GetRef());
  96. }
  97. STDMETHODIMP CCabStream::Read(void * pv, ULONG cb, ULONG * pcbRead)
  98. {
  99. *pcbRead = 0;
  100. if (m_dwStreamPosition < m_dwStreamLength)
  101. {
  102. if (cb > (m_dwStreamLength - m_dwStreamPosition))
  103. {
  104. *pcbRead = (m_dwStreamLength - m_dwStreamPosition);
  105. }
  106. else
  107. {
  108. *pcbRead = cb;
  109. }
  110. CopyMemory(pv,(char *) m_hStream + m_dwStreamPosition,*pcbRead);
  111. m_dwStreamPosition += *pcbRead;
  112. }
  113. return(S_OK);
  114. }
  115. STDMETHODIMP CCabStream::Write(const void * pv, ULONG cb, ULONG * pcbWritten)
  116. {
  117. return(E_NOTIMPL);
  118. }
  119. STDMETHODIMP CCabStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition)
  120. {
  121. switch (dwOrigin)
  122. {
  123. case STREAM_SEEK_SET:
  124. m_dwStreamPosition = dlibMove.LowPart;
  125. break;
  126. case STREAM_SEEK_CUR:
  127. m_dwStreamPosition += dlibMove.LowPart;
  128. break;
  129. case STREAM_SEEK_END:
  130. m_dwStreamPosition = m_dwStreamLength + dlibMove.LowPart;
  131. break;
  132. default:
  133. return(STG_E_INVALIDFUNCTION);
  134. }
  135. if (plibNewPosition)
  136. {
  137. (*plibNewPosition).LowPart = m_dwStreamPosition;
  138. (*plibNewPosition).HighPart = 0;
  139. }
  140. return(S_OK);
  141. }
  142. STDMETHODIMP CCabStream::SetSize(ULARGE_INTEGER libNewSize)
  143. {
  144. return(E_NOTIMPL);
  145. }
  146. STDMETHODIMP CCabStream::CopyTo(IStream * pstm, ULARGE_INTEGER cb, ULARGE_INTEGER * pcbRead, ULARGE_INTEGER * pcbWritten)
  147. {
  148. HRESULT hRes;
  149. unsigned long cbActual = cb.LowPart;
  150. unsigned long cbWritten;
  151. unsigned long cbChunk;
  152. if (pcbRead)
  153. {
  154. (*pcbRead).LowPart = 0;
  155. (*pcbRead).HighPart = 0;
  156. }
  157. if (pcbWritten)
  158. {
  159. (*pcbWritten).LowPart = 0;
  160. (*pcbWritten).HighPart = 0;
  161. }
  162. hRes = S_OK;
  163. if (m_dwStreamPosition < m_dwStreamLength)
  164. {
  165. if (cbActual > (m_dwStreamLength - m_dwStreamPosition))
  166. {
  167. cbActual = (m_dwStreamLength - m_dwStreamPosition);
  168. }
  169. while (cbActual)
  170. {
  171. if (cbActual > MAX_CHUNK)
  172. {
  173. cbChunk = MAX_CHUNK;
  174. }
  175. else
  176. {
  177. cbChunk = cbActual;
  178. }
  179. hRes = pstm->Write((char *) m_hStream + m_dwStreamPosition,cbChunk,&cbWritten);
  180. if (FAILED(hRes))
  181. {
  182. break;
  183. }
  184. m_dwStreamPosition += cbChunk;
  185. if (pcbRead)
  186. {
  187. (*pcbRead).LowPart += cbChunk;
  188. (*pcbRead).HighPart = 0;
  189. }
  190. if (pcbWritten)
  191. {
  192. (*pcbWritten).LowPart += cbWritten;
  193. (*pcbWritten).HighPart = 0;
  194. }
  195. cbActual -= cbChunk;
  196. }
  197. }
  198. return(hRes);
  199. }
  200. STDMETHODIMP CCabStream::Commit(DWORD grfCommitFlags)
  201. {
  202. return(E_NOTIMPL);
  203. }
  204. STDMETHODIMP CCabStream::Revert(void)
  205. {
  206. return(E_NOTIMPL);
  207. }
  208. STDMETHODIMP CCabStream::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  209. {
  210. return(E_NOTIMPL);
  211. }
  212. STDMETHODIMP CCabStream::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  213. {
  214. return(E_NOTIMPL);
  215. }
  216. STDMETHODIMP CCabStream::Stat(STATSTG * pstatstg, DWORD grfStatFlag)
  217. {
  218. return(E_NOTIMPL);
  219. }
  220. STDMETHODIMP CCabStream::Clone(IStream ** ppstm)
  221. {
  222. return(E_NOTIMPL);
  223. }
  224. class CObjFormats : public IEnumFORMATETC
  225. {
  226. public:
  227. CObjFormats(UINT cfmt, const FORMATETC afmt[]);
  228. ~CObjFormats();
  229. // *** IUnknown methods ***
  230. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  231. STDMETHODIMP_(ULONG) AddRef();
  232. STDMETHODIMP_(ULONG) Release();
  233. // *** IEnumFORMATETC methods ***
  234. STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed);
  235. STDMETHODIMP Skip(ULONG celt);
  236. STDMETHODIMP Reset();
  237. STDMETHODIMP Clone(IEnumFORMATETC ** ppenum);
  238. private:
  239. CRefCount m_cRef;
  240. CRefDll m_cRefDll;
  241. UINT m_iFmt;
  242. UINT m_cFmt;
  243. FORMATETC *m_aFmt;
  244. } ;
  245. CObjFormats::CObjFormats(UINT cfmt, const FORMATETC afmt[])
  246. {
  247. m_iFmt = 0;
  248. m_cFmt = cfmt;
  249. m_aFmt = new FORMATETC[cfmt];
  250. if (m_aFmt)
  251. {
  252. CopyMemory(m_aFmt, afmt, cfmt*sizeof(afmt[0]));
  253. }
  254. }
  255. CObjFormats::~CObjFormats()
  256. {
  257. if (m_aFmt)
  258. {
  259. delete m_aFmt;
  260. }
  261. }
  262. // *** IUnknown methods ***
  263. STDMETHODIMP CObjFormats::QueryInterface(
  264. REFIID riid,
  265. LPVOID FAR* ppvObj)
  266. {
  267. *ppvObj = NULL;
  268. if (!m_aFmt)
  269. {
  270. return(E_OUTOFMEMORY);
  271. }
  272. LPUNKNOWN pObj;
  273. if (riid == IID_IUnknown)
  274. {
  275. pObj = (IUnknown*)((IEnumFORMATETC*)this);
  276. }
  277. else if (riid == IID_IEnumFORMATETC)
  278. {
  279. pObj = (IUnknown*)((IEnumFORMATETC*)this);
  280. }
  281. else
  282. {
  283. return(E_NOINTERFACE);
  284. }
  285. pObj->AddRef();
  286. *ppvObj = pObj;
  287. return(NOERROR);
  288. }
  289. STDMETHODIMP_(ULONG) CObjFormats::AddRef(void)
  290. {
  291. return(m_cRef.AddRef());
  292. }
  293. STDMETHODIMP_(ULONG) CObjFormats::Release(void)
  294. {
  295. if (!m_cRef.Release())
  296. {
  297. delete this;
  298. return(0);
  299. }
  300. return(m_cRef.GetRef());
  301. }
  302. STDMETHODIMP CObjFormats::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
  303. {
  304. UINT cfetch;
  305. HRESULT hres = S_FALSE; // assume less numbers
  306. if (m_iFmt < m_cFmt)
  307. {
  308. cfetch = m_cFmt - m_iFmt;
  309. if (cfetch >= celt)
  310. {
  311. cfetch = celt;
  312. hres = S_OK;
  313. }
  314. CopyMemory(rgelt, &m_aFmt[m_iFmt], cfetch * sizeof(FORMATETC));
  315. m_iFmt += cfetch;
  316. }
  317. else
  318. {
  319. cfetch = 0;
  320. }
  321. if (pceltFethed)
  322. {
  323. *pceltFethed = cfetch;
  324. }
  325. return hres;
  326. }
  327. STDMETHODIMP CObjFormats::Skip(ULONG celt)
  328. {
  329. m_iFmt += celt;
  330. if (m_iFmt > m_cFmt)
  331. {
  332. m_iFmt = m_cFmt;
  333. return S_FALSE;
  334. }
  335. return S_OK;
  336. }
  337. STDMETHODIMP CObjFormats::Reset()
  338. {
  339. m_iFmt = 0;
  340. return S_OK;
  341. }
  342. STDMETHODIMP CObjFormats::Clone(IEnumFORMATETC ** ppenum)
  343. {
  344. return(E_NOTIMPL);
  345. }
  346. HRESULT CabViewDataObject_CreateInstance(REFIID riid, LPVOID *ppvObj)
  347. {
  348. HRESULT hr;
  349. CCabObj* pco = new CCabObj();
  350. if (NULL != pco)
  351. {
  352. pco->AddRef();
  353. hr = pco->QueryInterface(riid, ppvObj);
  354. pco->Release();
  355. }
  356. else
  357. {
  358. hr = E_OUTOFMEMORY;
  359. }
  360. return hr;
  361. }
  362. CCabObj::CCabObj(HWND hwndOwner, CCabFolder *pcf, LPCABITEM *apit, UINT cpit)
  363. : m_lSel(8), m_lContents(NULL)
  364. {
  365. m_pcfHere = pcf;
  366. pcf->AddRef();
  367. m_hwndOwner = hwndOwner;
  368. m_lSel.AddItems(apit, cpit);
  369. }
  370. // constructor used when we're co-created:
  371. CCabObj::CCabObj() : m_pcfHere(NULL), m_hwndOwner(NULL), m_lSel(8), m_lContents(NULL)
  372. {
  373. };
  374. CCabObj::~CCabObj()
  375. {
  376. if (m_lContents != NULL)
  377. {
  378. int cItems = m_lSel.GetCount();
  379. while (cItems--)
  380. {
  381. if (m_lContents[cItems] != NULL)
  382. {
  383. GlobalFree(m_lContents[cItems]);
  384. m_lContents[cItems] = NULL;
  385. }
  386. }
  387. GlobalFree(m_lContents);
  388. m_lContents = NULL;
  389. }
  390. if (m_pcfHere)
  391. {
  392. m_pcfHere->Release();
  393. }
  394. }
  395. // *** IUnknown methods ***
  396. STDMETHODIMP CCabObj::QueryInterface(
  397. REFIID riid,
  398. LPVOID FAR* ppvObj)
  399. {
  400. *ppvObj = NULL;
  401. if (m_lSel.GetState() == CCabItemList::State_OutOfMem)
  402. {
  403. return(E_OUTOFMEMORY);
  404. }
  405. LPUNKNOWN pObj;
  406. if (riid == IID_IUnknown)
  407. {
  408. pObj = (IUnknown*)((IDataObject*)this);
  409. }
  410. else if (riid == IID_IDataObject)
  411. {
  412. pObj = (IUnknown*)((IDataObject*)this);
  413. }
  414. else if (riid == IID_IPersist)
  415. {
  416. pObj = (IUnknown*)((IPersist*)this);
  417. }
  418. else if (riid == IID_IPersistStream)
  419. {
  420. pObj = (IUnknown*)((IPersistStream*)this);
  421. }
  422. else
  423. {
  424. return(E_NOINTERFACE);
  425. }
  426. pObj->AddRef();
  427. *ppvObj = pObj;
  428. return(NOERROR);
  429. }
  430. STDMETHODIMP_(ULONG) CCabObj::AddRef(void)
  431. {
  432. return(m_cRef.AddRef());
  433. }
  434. STDMETHODIMP_(ULONG) CCabObj::Release(void)
  435. {
  436. if (!m_cRef.Release())
  437. {
  438. delete this;
  439. return(0);
  440. }
  441. return(m_cRef.GetRef());
  442. }
  443. /////////////////////////////////
  444. ////// IPersistStream Impl
  445. /////////////////////////////////
  446. typedef struct
  447. {
  448. DWORD dwVersion;
  449. DWORD dwExtraSize; // After pidl list
  450. DWORD dwReserved1;
  451. DWORD dwReserved2;
  452. } CABVIEWDATAOBJ_PERSISTSTRUCT;
  453. /*****************************************************************************\
  454. FUNCTION: IPersistStream::Load
  455. DESCRIPTION:
  456. See IPersistStream::Save() for the layout of the stream.
  457. \*****************************************************************************/
  458. HRESULT CCabObj::Load(IStream *pStm)
  459. {
  460. HRESULT hr = E_INVALIDARG;
  461. if (pStm)
  462. {
  463. CABVIEWDATAOBJ_PERSISTSTRUCT cvdops;
  464. DWORD dwNumPidls;
  465. hr = pStm->Read(&cvdops, SIZEOF(cvdops), NULL); // #1
  466. // If we rev the version, read it now (cvdops.dwVersion)
  467. if (SUCCEEDED(hr))
  468. {
  469. LPITEMIDLIST pidl = NULL; // ILLoadFromStream frees the param
  470. // ASSERT(!m_pff);
  471. hr = ILLoadFromStream(pStm, &pidl); // #2
  472. if (SUCCEEDED(hr))
  473. {
  474. IShellFolder* psf;
  475. hr = SHGetDesktopFolder(&psf);
  476. if (SUCCEEDED(hr))
  477. {
  478. if (m_pcfHere)
  479. {
  480. m_pcfHere->Release();
  481. m_pcfHere = NULL;
  482. }
  483. hr = psf->BindToObject(pidl, NULL, CLSID_CabFolder, (void **)&m_pcfHere);
  484. psf->Release();
  485. }
  486. ILFree(pidl);
  487. }
  488. }
  489. if (SUCCEEDED(hr))
  490. {
  491. hr = pStm->Read(&dwNumPidls, SIZEOF(dwNumPidls), NULL); // #3
  492. }
  493. if (SUCCEEDED(hr))
  494. {
  495. for (int nIndex = 0; (nIndex < (int)dwNumPidls) && SUCCEEDED(hr); nIndex++)
  496. {
  497. LPITEMIDLIST pidl = NULL; // ILLoadFromStream frees the param
  498. hr = ILLoadFromStream(pStm, &pidl); // #4
  499. if (SUCCEEDED(hr))
  500. {
  501. hr = m_lSel.AddItems((LPCABITEM*) &pidl, 1);
  502. ILFree(pidl);
  503. }
  504. }
  505. }
  506. if (SUCCEEDED(hr))
  507. {
  508. // We may be reading a version newer than us, so skip their data.
  509. if (0 != cvdops.dwExtraSize)
  510. {
  511. LARGE_INTEGER li = {0};
  512. li.LowPart = cvdops.dwExtraSize;
  513. hr = pStm->Seek(li, STREAM_SEEK_CUR, NULL);
  514. }
  515. }
  516. }
  517. // don't return success codes other than S_OK:
  518. return SUCCEEDED(hr) ? S_OK : hr;
  519. }
  520. /*****************************************************************************\
  521. FUNCTION: IPersistStream::Save
  522. DESCRIPTION:
  523. The stream will be layed out in the following way:
  524. Version 1:
  525. 1. CABVIEWDATAOBJ_PERSISTSTRUCT - Constant sized data.
  526. <PidlList BEGIN>
  527. 2. PIDL pidl - Pidl for m_pcfHere. It will be a public pidl (fully qualified
  528. from the shell root)
  529. 3. DWORD dwNumPidls - Number of pidls coming.
  530. 4. PIDL pidl(n) - Pidl in slot (n) of m_lSel
  531. <PidlList END>
  532. \*****************************************************************************/
  533. HRESULT CCabObj::Save(IStream *pStm, BOOL fClearDirty)
  534. {
  535. HRESULT hr = E_INVALIDARG;
  536. if (pStm)
  537. {
  538. CABVIEWDATAOBJ_PERSISTSTRUCT cvdops = {0};
  539. DWORD dwNumPidls = m_lSel.GetCount();
  540. cvdops.dwVersion = 1;
  541. hr = pStm->Write(&cvdops, SIZEOF(cvdops), NULL); // #1
  542. if (SUCCEEDED(hr))
  543. {
  544. if (m_pcfHere)
  545. {
  546. LPITEMIDLIST pidl;
  547. hr = m_pcfHere->GetCurFolder(&pidl);
  548. if (SUCCEEDED(hr))
  549. {
  550. hr = ILSaveToStream(pStm, pidl); // #2
  551. ILFree(pidl);
  552. }
  553. }
  554. else
  555. {
  556. hr = E_FAIL;
  557. }
  558. }
  559. if (SUCCEEDED(hr))
  560. hr = pStm->Write(&dwNumPidls, SIZEOF(dwNumPidls), NULL); // #3
  561. if (SUCCEEDED(hr))
  562. {
  563. for (int nIndex = 0; (nIndex < (int)dwNumPidls) && SUCCEEDED(hr); nIndex++)
  564. {
  565. hr = ILSaveToStream(pStm, (LPCITEMIDLIST) m_lSel[nIndex]); // #4
  566. }
  567. }
  568. }
  569. return hr;
  570. }
  571. #define MAX_STREAM_SIZE (500 * 1024) // 500k
  572. /*****************************************************************************\
  573. FUNCTION: IPersistStream::GetSizeMax
  574. DESCRIPTION:
  575. Now this is tough. I can't calculate the real value because I don't know
  576. how big the hglobals are going to be for the user provided data. I will
  577. assume everything fits in
  578. \*****************************************************************************/
  579. HRESULT CCabObj::GetSizeMax(ULARGE_INTEGER * pcbSize)
  580. {
  581. if (pcbSize)
  582. {
  583. pcbSize->HighPart = 0;
  584. pcbSize->LowPart = MAX_STREAM_SIZE;
  585. }
  586. return E_NOTIMPL;
  587. }
  588. /*****************************************************************************\
  589. DESCRIPTION:
  590. Allocate an hglobal of the indicated size, initialized from the
  591. specified buffer.
  592. \*****************************************************************************/
  593. HRESULT StgMediumWriteHGlobal(HGLOBAL *phglob, LPVOID pv, SIZE_T cb)
  594. {
  595. HRESULT hres = E_OUTOFMEMORY;
  596. *phglob = 0; // Rules are rules
  597. if (cb)
  598. {
  599. *phglob = (HGLOBAL) LocalAlloc(LPTR, cb);
  600. if (*phglob)
  601. {
  602. hres = S_OK;
  603. CopyMemory(*phglob, pv, cb);
  604. }
  605. }
  606. else
  607. hres = E_INVALIDARG; // Can't clone a discardable block
  608. return hres;
  609. }
  610. /*****************************************************************************\
  611. DESCRIPTION:
  612. When the copy source goes away (the process shuts down), it calls
  613. OleFlushClipboard. OLE will then copy our data, release us, and then
  614. give out our data later. This works for most things except for:
  615. 1. When lindex needs to very. This doesn't work because ole doesn't know
  616. how to ask us how may lindexs they need to copy.
  617. 2. If this object has a private interface OLE doesn't know about. For us,
  618. it's IAsyncOperation.
  619. To get around this problem, we want OLE to recreate us when some possible
  620. paste target calls OleGetClipboard. We want OLE to call OleLoadFromStream()
  621. to have us CoCreated and reload our persisted data via IPersistStream.
  622. OLE doesn't want to do this by default or they may have backward compat
  623. problems so they want a sign from the heavens, or at least from us, that
  624. we will work. They ping our "OleClipboardPersistOnFlush" clipboard format
  625. to ask this.
  626. \*****************************************************************************/
  627. HRESULT _RenderOlePersist(STGMEDIUM * pStgMedium)
  628. {
  629. // The actual cookie value is opaque to the outside world. Since
  630. // we don't use it either, we just leave it at zero in case we use
  631. // it in the future. It's mere existence will cause OLE to do the
  632. // use our IPersistStream, which is what we want.
  633. DWORD dwCookie = 0;
  634. return StgMediumWriteHGlobal(&pStgMedium->hGlobal, &dwCookie, sizeof(dwCookie));
  635. }
  636. STDMETHODIMP CCabObj::GetData(FORMATETC *pfmt, STGMEDIUM *pmedium)
  637. {
  638. ZeroMemory(pmedium, sizeof(*pmedium));
  639. if (!InitFileGroupDesc())
  640. {
  641. return(E_UNEXPECTED);
  642. }
  643. if (pfmt->cfFormat == s_uFileGroupDesc)
  644. {
  645. if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) && pfmt->lindex==-1
  646. && (pfmt->tymed&TYMED_HGLOBAL))
  647. {
  648. int cItems = m_lSel.GetCount();
  649. if (cItems < 1)
  650. {
  651. return(E_UNEXPECTED);
  652. }
  653. FILEGROUPDESCRIPTOR *pfgd = (FILEGROUPDESCRIPTOR *)GlobalAlloc(GMEM_FIXED,
  654. sizeof(FILEGROUPDESCRIPTOR) + (cItems-1)*sizeof(FILEDESCRIPTOR));
  655. if (!pfgd)
  656. {
  657. return(E_OUTOFMEMORY);
  658. }
  659. pfgd->cItems = cItems;
  660. for (--cItems; cItems>=0; --cItems)
  661. {
  662. LPCABITEM pItem = m_lSel[cItems];
  663. FILETIME ft;
  664. pfgd->fgd[cItems].dwFlags = FD_ATTRIBUTES|FD_WRITESTIME|FD_FILESIZE|FD_PROGRESSUI;
  665. pfgd->fgd[cItems].dwFileAttributes = pItem->uFileAttribs;
  666. DosDateTimeToFileTime(pItem->uFileDate, pItem->uFileTime,&ft);
  667. LocalFileTimeToFileTime(&ft, &pfgd->fgd[cItems].ftLastWriteTime);
  668. pfgd->fgd[cItems].nFileSizeHigh = 0;
  669. pfgd->fgd[cItems].nFileSizeLow = pItem->dwFileSize;
  670. LPCWSTR pszName;
  671. WSTR_ALIGNED_STACK_COPY(&pszName, pItem->szName);
  672. lstrcpyn(pfgd->fgd[cItems].cFileName, PathFindFileName(pszName),
  673. ARRAYSIZE(pfgd->fgd[cItems].cFileName));
  674. }
  675. pmedium->tymed = TYMED_HGLOBAL;
  676. pmedium->hGlobal = (HGLOBAL)pfgd;
  677. pmedium->pUnkForRelease = NULL;
  678. return(NOERROR);
  679. }
  680. return(E_INVALIDARG);
  681. }
  682. if (!InitFileContents())
  683. {
  684. return(E_UNEXPECTED);
  685. }
  686. if (pfmt->cfFormat == s_uFileContents)
  687. {
  688. if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT))
  689. {
  690. if (pfmt->tymed & TYMED_ISTREAM)
  691. {
  692. int cItems = m_lSel.GetCount();
  693. if ((-1 == pfmt->lindex) || (pfmt->lindex >= cItems))
  694. {
  695. return(E_INVALIDARG);
  696. }
  697. HRESULT hRes = InitContents();
  698. if (FAILED(hRes))
  699. {
  700. return(hRes);
  701. }
  702. if (!m_lContents[pfmt->lindex])
  703. {
  704. return(E_OUTOFMEMORY);
  705. }
  706. CCabStream *stream = new CCabStream(m_lContents[pfmt->lindex],m_lSel[pfmt->lindex]->dwFileSize);
  707. if (!stream)
  708. {
  709. return(E_OUTOFMEMORY);
  710. }
  711. pmedium->tymed = TYMED_ISTREAM;
  712. pmedium->pstm = stream;
  713. pmedium->pUnkForRelease = NULL;
  714. m_lContents[pfmt->lindex] = NULL;
  715. return(NOERROR);
  716. }
  717. if (pfmt->tymed&TYMED_HGLOBAL)
  718. {
  719. int cItems = m_lSel.GetCount();
  720. if (pfmt->lindex >= cItems)
  721. {
  722. return(E_INVALIDARG);
  723. }
  724. HRESULT hRes = InitContents();
  725. if (FAILED(hRes))
  726. {
  727. return(hRes);
  728. }
  729. if (!m_lContents[pfmt->lindex])
  730. {
  731. return(E_OUTOFMEMORY);
  732. }
  733. pmedium->tymed = TYMED_HGLOBAL;
  734. pmedium->hGlobal = m_lContents[pfmt->lindex];
  735. pmedium->pUnkForRelease = NULL;
  736. m_lContents[pfmt->lindex] = NULL;
  737. return(NOERROR);
  738. }
  739. }
  740. return(E_INVALIDARG);
  741. }
  742. if (!InitPersistedDataObject())
  743. {
  744. return E_UNEXPECTED;
  745. }
  746. if (pfmt->cfFormat == s_uPersistedDataObject)
  747. {
  748. if ((pfmt->ptd == NULL) &&
  749. (pfmt->dwAspect & DVASPECT_CONTENT) &&
  750. (pfmt->lindex == -1) &&
  751. (pfmt->tymed & TYMED_HGLOBAL))
  752. {
  753. return _RenderOlePersist(pmedium);
  754. }
  755. else
  756. {
  757. return E_INVALIDARG;
  758. }
  759. }
  760. if (!InitHIDA())
  761. {
  762. return E_UNEXPECTED;
  763. }
  764. if (pfmt->cfFormat == s_uHIDA)
  765. {
  766. HRESULT hr = E_INVALIDARG;
  767. if ((pfmt->ptd == NULL) &&
  768. (pfmt->dwAspect & DVASPECT_CONTENT) &&
  769. (pfmt->lindex == -1) &&
  770. (pfmt->tymed & TYMED_HGLOBAL))
  771. {
  772. LPITEMIDLIST pidl;
  773. hr = m_pcfHere->GetCurFolder(&pidl);
  774. if (SUCCEEDED(hr))
  775. {
  776. HIDA hida = HIDA_Create(pidl, m_lSel.GetCount(), (LPCITEMIDLIST*)m_lSel.GetArray());
  777. if (hida)
  778. {
  779. pmedium->tymed = TYMED_HGLOBAL;
  780. pmedium->hGlobal = hida;
  781. hr = S_OK;
  782. }
  783. else
  784. {
  785. hr = E_OUTOFMEMORY;
  786. }
  787. ILFree(pidl);
  788. }
  789. }
  790. return hr;
  791. }
  792. return(E_NOTIMPL);
  793. }
  794. STDMETHODIMP CCabObj::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  795. {
  796. return(E_NOTIMPL);
  797. }
  798. STDMETHODIMP CCabObj::QueryGetData(FORMATETC *pfmt)
  799. {
  800. if (!InitFileGroupDesc())
  801. {
  802. return(E_UNEXPECTED);
  803. }
  804. if (pfmt->cfFormat == s_uFileGroupDesc)
  805. {
  806. if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT) && pfmt->lindex==-1
  807. && (pfmt->tymed&TYMED_HGLOBAL))
  808. {
  809. return(S_OK);
  810. }
  811. return(E_INVALIDARG);
  812. }
  813. if (!InitFileContents())
  814. {
  815. return(E_UNEXPECTED);
  816. }
  817. if (pfmt->cfFormat == s_uFileContents)
  818. {
  819. if (pfmt->ptd==NULL && (pfmt->dwAspect&DVASPECT_CONTENT)
  820. && (pfmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL)))
  821. {
  822. return(S_OK);
  823. }
  824. return(E_INVALIDARG);
  825. }
  826. if (!InitPersistedDataObject())
  827. {
  828. return(E_UNEXPECTED);
  829. }
  830. if (pfmt->cfFormat == s_uPersistedDataObject)
  831. {
  832. if (pfmt->ptd == NULL && (pfmt->dwAspect & DVASPECT_CONTENT)
  833. && (pfmt->tymed & TYMED_HGLOBAL))
  834. {
  835. return(S_OK);
  836. }
  837. return(E_INVALIDARG);
  838. }
  839. if (!InitHIDA())
  840. {
  841. return(E_UNEXPECTED);
  842. }
  843. if (pfmt->cfFormat == s_uHIDA)
  844. {
  845. if (pfmt->ptd == NULL && (pfmt->dwAspect & DVASPECT_CONTENT)
  846. && (pfmt->tymed & TYMED_HGLOBAL))
  847. {
  848. return(S_OK);
  849. }
  850. return(E_INVALIDARG);
  851. }
  852. return(E_NOTIMPL);
  853. }
  854. STDMETHODIMP CCabObj::GetCanonicalFormatEtc(FORMATETC *pformatetcIn, FORMATETC *pformatetcOut)
  855. {
  856. return(E_NOTIMPL);
  857. }
  858. STDMETHODIMP CCabObj::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
  859. {
  860. return(E_NOTIMPL);
  861. }
  862. STDMETHODIMP CCabObj::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
  863. {
  864. if (!InitFileGroupDesc() || !InitFileContents() || !InitPersistedDataObject() || !InitHIDA())
  865. {
  866. return(E_UNEXPECTED);
  867. }
  868. FORMATETC fmte[] = {
  869. {(USHORT)s_uFileContents, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL|TYMED_ISTREAM },
  870. {(USHORT)s_uFileGroupDesc, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  871. {(USHORT)s_uPersistedDataObject, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  872. {(USHORT)s_uHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL },
  873. };
  874. CObjFormats *pFmts = new CObjFormats(ARRAYSIZE(fmte), fmte);
  875. if (!pFmts)
  876. {
  877. return(E_OUTOFMEMORY);
  878. }
  879. pFmts->AddRef();
  880. HRESULT hRes = pFmts->QueryInterface(IID_IEnumFORMATETC, (LPVOID *)ppenumFormatEtc);
  881. pFmts->Release();
  882. return(hRes);
  883. }
  884. STDMETHODIMP CCabObj::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink,
  885. DWORD *pdwConnection)
  886. {
  887. return(E_NOTIMPL);
  888. }
  889. STDMETHODIMP CCabObj::DUnadvise(DWORD dwConnection)
  890. {
  891. return(E_NOTIMPL);
  892. }
  893. STDMETHODIMP CCabObj::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  894. {
  895. return(E_NOTIMPL);
  896. }
  897. BOOL CCabObj::InitFileGroupDesc()
  898. {
  899. if (s_uFileGroupDesc)
  900. {
  901. return(TRUE);
  902. }
  903. s_uFileGroupDesc = RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
  904. return(s_uFileGroupDesc != 0);
  905. }
  906. BOOL CCabObj::InitFileContents()
  907. {
  908. if (s_uFileContents)
  909. {
  910. return(TRUE);
  911. }
  912. s_uFileContents = RegisterClipboardFormat(CFSTR_FILECONTENTS);
  913. return(s_uFileContents != 0);
  914. }
  915. #define CFSTR_OLECLIPBOARDPERSISTONFLUSH TEXT("OleClipboardPersistOnFlush")
  916. BOOL CCabObj::InitPersistedDataObject()
  917. {
  918. if (s_uPersistedDataObject)
  919. {
  920. return(TRUE);
  921. }
  922. s_uPersistedDataObject = RegisterClipboardFormat(CFSTR_OLECLIPBOARDPERSISTONFLUSH);
  923. return(s_uPersistedDataObject != 0);
  924. }
  925. BOOL CCabObj::InitHIDA()
  926. {
  927. if (s_uHIDA)
  928. {
  929. return(TRUE);
  930. }
  931. s_uHIDA = RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  932. return(s_uHIDA != 0);
  933. }
  934. HGLOBAL * CALLBACK CCabObj::ShouldExtract(LPCTSTR pszFile, DWORD dwSize, UINT date,
  935. UINT time, UINT attribs, LPARAM lParam)
  936. {
  937. CCabObj *pThis = (CCabObj*)lParam;
  938. int iItem = pThis->m_lSel.FindInList(pszFile, dwSize, date, time, attribs);
  939. if (iItem < 0)
  940. {
  941. return(EXTRACT_FALSE);
  942. }
  943. // Copy nothing for now
  944. return(&(pThis->m_lContents[iItem]));
  945. }
  946. HRESULT CCabObj::InitContents()
  947. {
  948. if (m_lContents)
  949. {
  950. return S_OK;
  951. }
  952. int iCount = m_lSel.GetCount();
  953. if (iCount < 1)
  954. {
  955. return E_UNEXPECTED;
  956. }
  957. m_lContents = (HGLOBAL *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,
  958. sizeof(HGLOBAL)*m_lSel.GetCount());
  959. if (!m_lContents)
  960. {
  961. return E_OUTOFMEMORY;
  962. }
  963. TCHAR szHere[MAX_PATH];
  964. if ((NULL == m_pcfHere) || (!m_pcfHere->GetPath(szHere)))
  965. {
  966. return E_UNEXPECTED;
  967. }
  968. CCabExtract ceHere(szHere);
  969. ceHere.ExtractItems(m_hwndOwner, DIR_MEM, ShouldExtract, (LPARAM)this);
  970. return S_OK;
  971. }