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.

1406 lines
34 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module - DXFROBJ.C |
  5. *
  6. * implementation of a generic IDataObject data transfer object.
  7. * This object is suitable for use in OLE clipboard and drag drop
  8. * operations
  9. *
  10. * Author: <nl>
  11. * alexgo (4/25/95)
  12. *
  13. * Revisions: <nl>
  14. * murrays (7/13/95) auto-doc'd and added cf_RTF
  15. *
  16. * Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
  17. */
  18. #include "_common.h"
  19. #include "_edit.h"
  20. #include "_dxfrobj.h"
  21. #include "_range.h"
  22. #include "hash.h"
  23. #define NUMOBJCOPIEDFORWAITCURSOR 1
  24. #ifdef PEGASUS
  25. #define NUMCHARCOPIEDFORWAITCURSOR 4096
  26. #else
  27. #define NUMCHARCOPIEDFORWAITCURSOR 16384
  28. #endif
  29. //
  30. // Common Data types
  31. //
  32. // If you change g_rgFETC[], change g_rgDOI[] and enum FETCINDEX and CFETC in
  33. // _dxfrobj.h accordingly, and register nonstandard clipboard formats in
  34. // RegisterFETCs(). Order entries in order of most desirable to least, e.g.,
  35. // RTF in front of plain text.
  36. //REVIEW (keithcu) All but the first column is const--separate into 2 data structures?
  37. FORMATETC g_rgFETC[] =
  38. {
  39. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // CF_RTFUTF8
  40. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // cf_RTF
  41. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // RTF with NCRs for nonASCII
  42. {0, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},// EmbObject
  43. {0, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},// EmbSource
  44. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // ObjDesc
  45. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // LnkSource
  46. {CF_METAFILEPICT, NULL, DVASPECT_CONTENT, -1, TYMED_MFPICT},
  47. {CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
  48. {CF_BITMAP, NULL, DVASPECT_CONTENT, -1, TYMED_GDI},
  49. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // RTF with no objs
  50. {CF_UNICODETEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
  51. {CF_TEXT, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL},
  52. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // Filename
  53. {0, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}, // CF_RTFASTEXT
  54. {0, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE},// Text with objs
  55. {0, NULL, DVASPECT_CONTENT, -1, TYMED_ISTORAGE} // Richedit
  56. };
  57. // Keep in sync with above and with FETCINDEX and CFETC
  58. const DWORD g_rgDOI[] =
  59. {
  60. DOI_CANPASTERICH, // RTF in UTF8 encoding
  61. DOI_CANPASTERICH, // RTF
  62. DOI_CANPASTERICH, // RTF with NCRs for nonASCII
  63. DOI_CANPASTEOLE, // Embedded Object
  64. DOI_CANPASTEOLE, // Embed Source
  65. DOI_NONE, // Object Descriptor
  66. DOI_CANPASTEOLE, // Link Source
  67. DOI_CANPASTEOLE, // Metafile
  68. DOI_CANPASTEOLE, // DIB
  69. DOI_CANPASTEOLE, // Bitmap
  70. DOI_CANPASTERICH, // RTF with no objects
  71. DOI_CANPASTEPLAIN, // Unicode plain text
  72. DOI_CANPASTEPLAIN, // ANSI plain text
  73. DOI_CANPASTEOLE, // Filename
  74. DOI_CANPASTEPLAIN, // Pastes RTF as text
  75. DOI_CANPASTERICH, // Richedit Text
  76. DOI_CANPASTERICH // RichEdit Text w/formatting
  77. };
  78. /*
  79. * RegisterFETCs()
  80. *
  81. * @func
  82. * Register nonstandard format ETCs. Called when DLL is loaded
  83. */
  84. void RegisterFETCs()
  85. {
  86. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "RegisterFETCs");
  87. #ifdef RTF_HASHCACHE
  88. HashKeyword_Init(); // Init rtf control keyword hash table.
  89. #endif
  90. #ifndef MACPORT
  91. g_rgFETC[iRtfFETC].cfFormat // Note: cfFormats are WORDs
  92. = (WORD)RegisterClipboardFormatA("Rich Text Format");
  93. g_rgFETC[iRtfUtf8].cfFormat
  94. = (WORD)RegisterClipboardFormatA("RTF in UTF8");
  95. g_rgFETC[iRtfNCRforNonASCII].cfFormat
  96. = (WORD)RegisterClipboardFormatA("RTF with NCRs for nonASCII");
  97. g_rgFETC[iRtfAsTextFETC].cfFormat
  98. = (WORD)RegisterClipboardFormatA("RTF As Text");
  99. g_rgFETC[iRichEdit].cfFormat
  100. = (WORD)RegisterClipboardFormatA("RICHEDIT");
  101. g_rgFETC[iObtDesc].cfFormat
  102. = (WORD)RegisterClipboardFormatA(CF_OBJECTDESCRIPTOR);
  103. g_rgFETC[iEmbObj].cfFormat
  104. = (WORD)RegisterClipboardFormatA(CF_EMBEDDEDOBJECT);
  105. g_rgFETC[iEmbSrc].cfFormat
  106. = (WORD)RegisterClipboardFormatA(CF_EMBEDSOURCE);
  107. g_rgFETC[iLnkSrc].cfFormat
  108. = (WORD)RegisterClipboardFormatA(CF_LINKSOURCE);
  109. g_rgFETC[iRtfNoObjs].cfFormat
  110. = (WORD)RegisterClipboardFormatA("Rich Text Format Without Objects");
  111. g_rgFETC[iTxtObj].cfFormat
  112. = (WORD)RegisterClipboardFormatA("RichEdit Text and Objects");
  113. g_rgFETC[iFilename].cfFormat
  114. = (WORD)RegisterClipboardFormatA(CF_FILENAME);
  115. #else
  116. // MacPort: Should we even bother to register the clipboard formats if we
  117. // are not going to use WLM clipboard???
  118. if(!g_rgFETC[iRtfFETC].cfFormat)
  119. {
  120. g_rgFETC[iRtfFETC].cfFormat = RegisterClipboardFormatA("RTF ");
  121. g_rgFETC[iRtfFETC].cfFormat = 'RTF ';
  122. }
  123. if(!g_rgFETC[iRtfAsTextFETC].cfFormat)
  124. {
  125. g_rgFETC[iRtfAsTextFETC].cfFormat = RegisterClipboardFormatA("RTFT");
  126. g_rgFETC[iRtfAsTextFETC].cfFormat = 'RTFT';
  127. }
  128. if(!g_rgFETC[iRichEdit].cfFormat)
  129. {
  130. g_rgFETC[iRichEdit].cfFormat = RegisterClipboardFormatA("RTE ");
  131. g_rgFETC[iRichEdit].cfFormat = 'RTE ';
  132. }
  133. if(!g_rgFETC[iObtDesc].cfFormat)
  134. {
  135. g_rgFETC[iObtDesc].cfFormat = RegisterClipboardFormatA(CF_OBJECTDESCRIPTOR);
  136. g_rgFETC[iObtDesc].cfFormat = cfObjectDescriptor;
  137. }
  138. if(!g_rgFETC[iEmbObj].cfFormat)
  139. {
  140. g_rgFETC[iEmbObj].cfFormat = RegisterClipboardFormatA(CF_EMBEDDEDOBJECT);
  141. g_rgFETC[iEmbObj].cfFormat = cfEmbeddedObject;
  142. }
  143. if(!g_rgFETC[iEmbSrc].cfFormat)
  144. {
  145. g_rgFETC[iEmbSrc].cfFormat = RegisterClipboardFormatA(CF_EMBEDSOURCE);
  146. g_rgFETC[iEmbSrc].cfFormat = cfEmbedSource;
  147. }
  148. if(!g_rgFETC[iLnkSrc].cfFormat)
  149. {
  150. g_rgFETC[iLnkSrc].cfFormat = RegisterClipboardFormatA(CF_LINKSOURCE);
  151. g_rgFETC[iLnkSrc].cfFormat = cfLinkSource;
  152. }
  153. if(!g_rgFETC[iRtfNoObjs].cfFormat)
  154. {
  155. g_rgFETC[iRtfNoObjs].cfFormat = RegisterClipboardFormatA("RwoO");
  156. g_rgFETC[iRtfNoObjs].cfFormat = 'RwoO';
  157. }
  158. if(!g_rgFETC[iTxtObj].cfFormat)
  159. {
  160. g_rgFETC[iTxtObj].cfFormat = RegisterClipboardFormatA("RTnO");
  161. g_rgFETC[iTxtObj].cfFormat = 'RTnO';
  162. }
  163. if(!g_rgFETC[iFilename].cfFormat)
  164. {
  165. g_rgFETC[iFilename].cfFormat = RegisterClipboardFormatA(CF_FILENAME);
  166. g_rgFETC[iFilename].cfFormat = cfFileName;
  167. }
  168. if(!g_rgFETC[iRtfUtf8].cfFormat)
  169. {
  170. g_rgFETC[iRtfUtf8].cfFormat = RegisterClipboardFormatA("UTF8 RTF");
  171. g_rgFETC[iRtfUtf8].cfFormat = 'UTF8 RTF';
  172. }
  173. #endif
  174. }
  175. //
  176. // CDataTransferObj PUBLIC methods
  177. //
  178. /*
  179. * CDataTransferObj::QueryInterface (riid, ppv)
  180. *
  181. * @mfunc
  182. * QueryInterface for CDataTransferObj
  183. *
  184. * @rdesc
  185. * HRESULT
  186. */
  187. STDMETHODIMP CDataTransferObj::QueryInterface (
  188. REFIID riid, // @parm Reference to requested interface ID
  189. void ** ppv) // @parm out parm for interface ptr
  190. {
  191. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::QueryInterface");
  192. if(!ppv)
  193. return E_INVALIDARG;
  194. *ppv = NULL;
  195. if(IsZombie()) // Check for range zombie
  196. return CO_E_RELEASED;
  197. HRESULT hresult = E_NOINTERFACE;
  198. if( IsEqualIID(riid, IID_IUnknown) ||
  199. IsEqualIID(riid, IID_IDataObject) ||
  200. IsEqualIID(riid, IID_IRichEditDO) )
  201. {
  202. *ppv = this;
  203. AddRef();
  204. hresult = NOERROR;
  205. }
  206. return hresult;
  207. }
  208. /*
  209. * CDataTransferObj::AddRef()
  210. *
  211. * @mfunc
  212. * IUnknown method
  213. *
  214. * @rdesc
  215. * ULONG - incremented reference count
  216. */
  217. STDMETHODIMP_(ULONG) CDataTransferObj::AddRef()
  218. {
  219. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::AddRef");
  220. return ++_crefs;
  221. }
  222. /*
  223. * CDataTransferObj::Release()
  224. *
  225. * @mfunc
  226. * IUnknown method
  227. *
  228. * @rdesc
  229. * ULONG - decremented reference count
  230. */
  231. STDMETHODIMP_(ULONG) CDataTransferObj::Release()
  232. {
  233. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::Release");
  234. _crefs--;
  235. if( _crefs == 0 )
  236. {
  237. GlobalFree(_hPlainText);
  238. GlobalFree(_hRtfText);
  239. GlobalFree(_hRtfUtf8);
  240. GlobalFree(_hRtfNCRforNonASCII);
  241. delete this;
  242. return 0;
  243. }
  244. return _crefs;
  245. }
  246. /*
  247. * CDataTransferObj::DAdvise (pFormatetc, advf, pAdvSink, pdwConnection)
  248. *
  249. * @mfunc
  250. * establish an advisory connection
  251. *
  252. * @rdesc
  253. * HRESULT = OLE_E_ADVISENOTSUPPORTED
  254. *
  255. * @devnote
  256. * this is a data transfer object, thus the data is a "snapshot" and
  257. * cannot change -- no advises are supported.
  258. */
  259. STDMETHODIMP CDataTransferObj::DAdvise(
  260. FORMATETC * pFormatetc,
  261. DWORD advf,
  262. IAdviseSink *pAdvSink,
  263. DWORD *pdwConnection)
  264. {
  265. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::DAdvise");
  266. return OLE_E_ADVISENOTSUPPORTED;
  267. }
  268. /*
  269. * CDataTransferObj::DUnadvise (dwConnection)
  270. *
  271. * @mfunc
  272. * destroy an advisory connection
  273. *
  274. * @rdesc
  275. * HRESULT = OLE_E_ADVISENOTSUPPORTED
  276. *
  277. * @devnote
  278. * this is a data transfer object, thus the data is a "snapshot" and
  279. * cannot change -- no advises are supported.
  280. */
  281. STDMETHODIMP CDataTransferObj::DUnadvise(
  282. DWORD dwConnection)
  283. {
  284. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::DUnadvise");
  285. return OLE_E_ADVISENOTSUPPORTED;
  286. }
  287. /*
  288. * CDataTransferObj::EnumDAdvise (ppenumAdvise)
  289. *
  290. * @mfunc
  291. * enumerate advisory connections
  292. *
  293. * @rdesc
  294. * HRESULT = OLE_E_ADVISENOTSUPPORTED
  295. *
  296. * @devnote
  297. * this is a data transfer object, thus the data is a "snapshot" and
  298. * cannot change -- no advises are supported.
  299. */
  300. STDMETHODIMP CDataTransferObj::EnumDAdvise(
  301. IEnumSTATDATA ** ppenumAdvise)
  302. {
  303. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::EnumDAdvise");
  304. return OLE_E_ADVISENOTSUPPORTED;
  305. }
  306. /*
  307. * CDataTransferObj::EnumFormatEtc (dwDirection, ppenumFormatEtc)
  308. *
  309. * @mfunc
  310. * returns an enumerator which lists all of the available formats in
  311. * this data transfer object
  312. *
  313. * @rdesc
  314. * HRESULT
  315. *
  316. * @devnote
  317. * we have no 'set' formats for this object
  318. */
  319. STDMETHODIMP CDataTransferObj::EnumFormatEtc(
  320. DWORD dwDirection, // @parm DATADIR_GET/SET
  321. IEnumFORMATETC **ppenumFormatEtc) // @parm out parm for enum FETC interface
  322. {
  323. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::EnumFormatEtc");
  324. if(!ppenumFormatEtc)
  325. return E_INVALIDARG;
  326. *ppenumFormatEtc = NULL;
  327. if(IsZombie()) // Check for range zombie
  328. return CO_E_RELEASED;
  329. HRESULT hr = NOERROR;
  330. #ifdef DEBUG
  331. if (dwDirection == DATADIR_SET && !_ped->Get10Mode())
  332. {
  333. Tracef(TRCSEVNONE, "RichEdit 2.0 EnumFormatEtc called with DATADIR_SET");
  334. }
  335. #endif
  336. //Need riched10 compatibility hack to ignore dwDirection
  337. if(dwDirection == DATADIR_GET || _ped->Get10Mode())
  338. hr = CEnumFormatEtc::Create(_prgFormats, _cTotal, ppenumFormatEtc);
  339. return hr;
  340. }
  341. /*
  342. * CDataTransferObj::GetCanonicalFormatEtc( pformatetc, pformatetcOut)
  343. *
  344. * @mfunc
  345. * from the given formatetc, return a more standard (or canonical)
  346. * format.
  347. *
  348. * @rdesc
  349. * HRESULT = E_NOTIMPL
  350. *
  351. * @devnote
  352. * (alexgo): we may need to write this routine if we ever do anything
  353. * snazzy with printers
  354. */
  355. STDMETHODIMP CDataTransferObj::GetCanonicalFormatEtc(
  356. FORMATETC *pformatetc,
  357. FORMATETC *pformatetcOut)
  358. {
  359. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::GetCanonicalFormatEtc");
  360. return E_NOTIMPL;
  361. }
  362. /*
  363. * CDataTransferObj::GetData (pformatetcIn, pmedium)
  364. *
  365. * @mfunc
  366. * retrieves data of the specified format
  367. *
  368. * @rdesc
  369. * HRESULT
  370. */
  371. STDMETHODIMP CDataTransferObj::GetData(
  372. FORMATETC *pformatetcIn,
  373. STGMEDIUM *pmedium )
  374. {
  375. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::GetData");
  376. FillMemory(pmedium, '\0', sizeof(STGMEDIUM));
  377. pmedium->tymed = TYMED_NULL;
  378. if(IsZombie()) // Check for range zombie
  379. return CO_E_RELEASED;
  380. CLIPFORMAT cf = pformatetcIn->cfFormat;
  381. HRESULT hr = E_OUTOFMEMORY; // Default not enuf RAM
  382. // now handle 'native' richedit formats.
  383. if( cf && pformatetcIn->tymed & TYMED_HGLOBAL )
  384. {
  385. if( cf == CF_UNICODETEXT )
  386. pmedium->hGlobal = DuplicateHGlobal(TextToHglobal(_hPlainText, tPlain));
  387. else if(cf == CF_TEXT)
  388. pmedium->hGlobal = TextHGlobalWtoA(TextToHglobal(_hPlainText, tPlain));
  389. else if(cf == cf_RTF || cf == cf_RTFASTEXT || cf == cf_RTFNOOBJS)
  390. pmedium->hGlobal = DuplicateHGlobal(TextToHglobal(_hRtfText, tRtf));
  391. else if(cf == cf_RTFUTF8)
  392. pmedium->hGlobal = DuplicateHGlobal(TextToHglobal(_hRtfUtf8, tRtfUtf8));
  393. else if(cf == cf_RTFNCRFORNONASCII)
  394. pmedium->hGlobal = DuplicateHGlobal(TextToHglobal(_hRtfNCRforNonASCII, tRtfNCRforNonASCII));
  395. else
  396. hr = DV_E_FORMATETC;
  397. if (hr == E_OUTOFMEMORY)
  398. {
  399. if( pmedium->hGlobal ) // Succeeded
  400. {
  401. pmedium->tymed = TYMED_HGLOBAL;
  402. hr = NOERROR;
  403. }
  404. return hr;
  405. }
  406. }
  407. if ((cf == cf_EMBEDDEDOBJECT ||
  408. cf == cf_EMBEDSOURCE) &&
  409. (pformatetcIn->tymed & TYMED_ISTORAGE))
  410. {
  411. _pObjStg = GetDataForEmbeddedObject( _pOleObj, pmedium->pstg );
  412. pmedium->tymed = TYMED_ISTORAGE;
  413. if (NULL == pmedium->pstg)
  414. pmedium->pstg = _pObjStg;
  415. hr = _pObjStg != NULL ? NOERROR : hr;
  416. return hr;
  417. }
  418. // Go through richedit's formats and see if there are any matches
  419. if( cf == cf_OBJECTDESCRIPTOR &&
  420. (pformatetcIn->tymed & TYMED_HGLOBAL) &&
  421. _hObjDesc)
  422. {
  423. pmedium->hGlobal = DuplicateHGlobal(_hObjDesc);
  424. pmedium->tymed = TYMED_HGLOBAL;
  425. return NOERROR;
  426. }
  427. // First propogate the message to the object and see if it handles the format
  428. if (_pOleObj)
  429. {
  430. // Include the formats supported by the object
  431. IDataObject * pdataobj = NULL;
  432. if (FAILED(_pOleObj->GetClipboardData(0, &pdataobj)) || pdataobj == NULL)
  433. _pOleObj->QueryInterface(IID_IDataObject, (void**) &pdataobj);
  434. if (pdataobj)
  435. {
  436. hr = pdataobj->GetData(pformatetcIn, pmedium);
  437. pdataobj->Release();
  438. if (SUCCEEDED(hr))
  439. {
  440. if ((cf == cf_EMBEDDEDOBJECT || cf == cf_EMBEDSOURCE) && _pOleObj)
  441. {
  442. OleSaveSiteFlags(pmedium->pstg, _dwFlags, _dwUser, _dvaspect);
  443. }
  444. return S_OK;
  445. }
  446. }
  447. }
  448. if( cf == CF_METAFILEPICT )
  449. {
  450. pmedium->hMetaFilePict = OleDuplicateData(_hMFPict, CF_METAFILEPICT, 0);
  451. pmedium->tymed = TYMED_MFPICT;
  452. return NOERROR;
  453. }
  454. if( cf == CF_DIB )
  455. {
  456. if( _ped->HasObjects() && _cch == 1 )
  457. {
  458. COleObject *pobj = _ped->_pobjmgr->GetObjectFromCp(_cpMin);
  459. if (pobj)
  460. {
  461. HGLOBAL hdib = pobj->GetHdata();
  462. if (hdib)
  463. {
  464. pmedium->hGlobal = DuplicateHGlobal(hdib);
  465. pmedium->tymed = TYMED_HGLOBAL;
  466. }
  467. }
  468. }
  469. return NOERROR;
  470. }
  471. return DV_E_FORMATETC;
  472. }
  473. /*
  474. * CDataTransferObj::GetDataForEmbeddedObject (pformatetc, lpstgdest)
  475. *
  476. * @mfunc
  477. * retrieves data for embedded object
  478. *
  479. * @rdesc
  480. * LPSTORAGE
  481. *
  482. */
  483. LPSTORAGE CDataTransferObj::GetDataForEmbeddedObject(
  484. LPOLEOBJECT pOleObj,
  485. LPSTORAGE lpstgdest)
  486. {
  487. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::GetDataForEmbeddedObject");
  488. HRESULT hr, hr1;
  489. LPPERSISTSTORAGE pperstg;
  490. if (_pObjStg != NULL && lpstgdest != NULL)
  491. {
  492. // We saved the data previously. Copy it to destination.
  493. hr = _pObjStg->CopyTo(0, NULL, NULL, lpstgdest);
  494. if (hr == NOERROR)
  495. {
  496. lpstgdest->Commit(STGC_DEFAULT);
  497. return _pObjStg;
  498. }
  499. return NULL;
  500. }
  501. if (_pObjStg != NULL && lpstgdest == NULL)
  502. {
  503. // We saved the data previously. Return a reference
  504. _pObjStg->AddRef();
  505. return _pObjStg;
  506. }
  507. // We don't have a saved copy. Create One.
  508. hr = pOleObj->QueryInterface( IID_IPersistStorage, (void **) &pperstg );
  509. if (hr != NOERROR)
  510. return NULL;
  511. if (lpstgdest == NULL)
  512. {
  513. // It is null. We have to create our own.
  514. LPLOCKBYTES lpLockBytes = NULL;
  515. hr = CreateILockBytesOnHGlobal(NULL, TRUE, // delete on release
  516. (LPLOCKBYTES *)&lpLockBytes);
  517. if (hr != NOERROR)
  518. {
  519. pperstg->Release();
  520. return NULL;
  521. }
  522. hr = StgCreateDocfileOnILockBytes(
  523. lpLockBytes,
  524. STGM_READWRITE | STGM_TRANSACTED | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  525. 0, // reserved
  526. &lpstgdest
  527. );
  528. lpLockBytes->Release();
  529. if (hr != NOERROR)
  530. {
  531. pperstg->Release();
  532. return NULL;
  533. }
  534. _pObjStg = lpstgdest;
  535. }
  536. else
  537. {
  538. // Force the data to be saved
  539. _pObjStg = GetDataForEmbeddedObject( _pOleObj, NULL );
  540. pperstg->Release();
  541. return GetDataForEmbeddedObject( _pOleObj, lpstgdest );
  542. }
  543. // OLE2NOTE: even if OleSave returns an error you should still call
  544. // SaveCompleted.
  545. hr = OleSave( pperstg, lpstgdest, FALSE /* fSameAsLoad */ );
  546. hr1 = pperstg->SaveCompleted(NULL);
  547. if (hr != NOERROR || hr1 != NOERROR) // Should we use SUCCEED macros ????
  548. lpstgdest = NULL;
  549. pperstg->Release();
  550. return _pObjStg;
  551. }
  552. /*
  553. * CDataTransferObj::GetDataorObjectDescriptor (pformatetc, pmedium)
  554. *
  555. * @mfunc
  556. * retrieves data for embedded object descriptor
  557. *
  558. * @rdesc
  559. * HRESULT
  560. */
  561. HGLOBAL CDataTransferObj::GetDataForObjectDescriptor(
  562. LPOLEOBJECT pOleObj,
  563. DWORD dwAspect,
  564. SIZEL* psizel)
  565. {
  566. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::GetDataForObjectDescriptor");
  567. POINTL ptl = {0};
  568. SIZEL sizel = {0};
  569. if (psizel)
  570. {
  571. sizel.cx = psizel->cx;
  572. sizel.cy = psizel->cy;
  573. }
  574. if (_hObjDesc == NULL)
  575. {
  576. _hObjDesc = OleGetObjectDescriptorDataFromOleObject(
  577. pOleObj,
  578. dwAspect,
  579. ptl,
  580. &sizel
  581. );
  582. }
  583. return _hObjDesc;
  584. }
  585. /*
  586. * CDataTransferObj::GetDataHere (pformatetc, pmedium)
  587. *
  588. * @mfunc
  589. * retrieves data of the specified format into the given medium
  590. *
  591. * @rdesc
  592. * HRESULT = E_NOTIMPL
  593. *
  594. * @devnote (alexgo): technically, we're supposed to support transfers
  595. * into hglobals, but I'd rather not at the moment.
  596. */
  597. STDMETHODIMP CDataTransferObj::GetDataHere(
  598. FORMATETC *pformatetc,
  599. STGMEDIUM *pmedium)
  600. {
  601. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::GetDataHere");
  602. CLIPFORMAT cf = pformatetc->cfFormat;
  603. HRESULT hr = DV_E_FORMATETC;
  604. if(IsZombie()) // Check for range zombie
  605. return CO_E_RELEASED;
  606. if( (cf == cf_EMBEDDEDOBJECT ||
  607. cf == cf_EMBEDSOURCE) &&
  608. (pformatetc->tymed & TYMED_ISTORAGE))
  609. {
  610. // For some reason the NT4.0 and Win95 Shell
  611. // ask for the EMBEDSOURCE format.
  612. _pObjStg = GetDataForEmbeddedObject( _pOleObj, pmedium->pstg );
  613. pmedium->tymed = TYMED_ISTORAGE;
  614. if (NULL == pmedium->pstg)
  615. pmedium->pstg = _pObjStg;
  616. hr = pmedium->pstg != NULL ? NOERROR : hr;
  617. return hr;
  618. }
  619. if( cf == cf_OBJECTDESCRIPTOR &&
  620. (pformatetc->tymed & TYMED_HGLOBAL) &&
  621. _hObjDesc)
  622. {
  623. pmedium->hGlobal = DuplicateHGlobal(_hObjDesc);
  624. pmedium->tymed = TYMED_HGLOBAL;
  625. return NOERROR;
  626. }
  627. // First propogate the message to the object and see if it handles the format
  628. if (_pOleObj)
  629. {
  630. // Include the formats supported by the object
  631. IDataObject * pdataobj = NULL;
  632. if (FAILED(_pOleObj->GetClipboardData(0, &pdataobj)) || pdataobj == NULL)
  633. _pOleObj->QueryInterface(IID_IDataObject, (void**) &pdataobj);
  634. if (pdataobj)
  635. {
  636. hr = pdataobj->GetData(pformatetc, pmedium);
  637. pdataobj->Release();
  638. if (hr == S_OK)
  639. {
  640. if ((cf == cf_EMBEDDEDOBJECT || cf == cf_EMBEDSOURCE) && _pOleObj)
  641. {
  642. OleSaveSiteFlags(pmedium->pstg, _dwFlags, _dwUser, _dvaspect);
  643. }
  644. return S_OK;
  645. }
  646. }
  647. }
  648. return E_NOTIMPL;
  649. }
  650. /*
  651. * CDataTransferObj::QueryGetData (pformatetc)
  652. *
  653. * @mfunc
  654. * Queries whether the given format is available in this data object
  655. *
  656. * @rdesc
  657. * HRESULT
  658. */
  659. STDMETHODIMP CDataTransferObj::QueryGetData(
  660. FORMATETC *pformatetc ) // @parm FETC to look for
  661. {
  662. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::QueryGetData");
  663. if(IsZombie()) // Check for range zombie
  664. return CO_E_RELEASED;
  665. DWORD cFETC = _cTotal;
  666. while (cFETC--) // Maybe faster to search from start
  667. {
  668. if( pformatetc->cfFormat == _prgFormats[cFETC].cfFormat &&
  669. (pformatetc->tymed & _prgFormats[cFETC].tymed) )
  670. {
  671. return NOERROR;
  672. }
  673. }
  674. return DV_E_FORMATETC;
  675. }
  676. /*
  677. * CDataTransferObj::SetData (pformatetc, pmedium, fRelease)
  678. *
  679. * @mfunc
  680. * allows data to be set into this data object
  681. *
  682. * @rdesc
  683. * HRESULT = E_FAIL
  684. *
  685. * @devnote
  686. * as we are a data transfer object with a "snapshot" of data,
  687. * we do not allow it to be replaced
  688. */
  689. STDMETHODIMP CDataTransferObj::SetData(
  690. FORMATETC *pformatetc,
  691. STGMEDIUM *pmedium,
  692. BOOL fRelease)
  693. {
  694. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::SetData");
  695. return E_FAIL;
  696. }
  697. /*
  698. * CDataTransferObj::OnPreReplaceRange (cp, cchDel, cchNew, cpFormatMin,
  699. * cpFormatMax)
  700. *
  701. * @mfunc implementation of ITxNotify::OnPreReplaceRange
  702. * called before changes are made to the backing store
  703. */
  704. void CDataTransferObj::OnPreReplaceRange(
  705. LONG cp, //@parm cp of the changes
  706. LONG cchDel, //@parm #of chars deleted
  707. LONG cchNew, //@parm # of chars added
  708. LONG cpFormatMin, //@parm min cp of formatting changes
  709. LONG cpFormatMax) //@parm max cp of formatting changes
  710. {
  711. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::OnPreReplaceRange");
  712. if(CONVERT_TO_PLAIN != cp && CP_INFINITE != cp)
  713. {
  714. if(cp > _cpMin + _cch)
  715. return; // Change beyond our extent
  716. if(cp + cchDel < _cpMin)
  717. {
  718. _cpMin += (cchNew - cchDel); // Change before our extent
  719. return;
  720. }
  721. }
  722. // FUTURE (murrays): save only one master format (UTF8 RTF or better
  723. // CTxtStory) and generate individual ones in GetData and GetDataHere.
  724. _hPlainText = TextToHglobal(_hPlainText, tPlain);
  725. _hRtfText = TextToHglobal(_hRtfText, tRtf);
  726. if(_ped->GetCharFlags() & ~(fLATIN1 | fSYMBOL))
  727. _hRtfUtf8 = TextToHglobal(_hRtfUtf8, tRtfUtf8);
  728. }
  729. /*
  730. * CDataTransferObj::OnPostReplaceRange(cp, cchDel, cchNew, cpFormatMin,
  731. * cpFormatMax)
  732. * @mfunc implementation of ITxNotify::OnPostReplaceRange
  733. * called after changes are made to the backing store
  734. *
  735. * @comm we use this method to keep our cp's up-to-date
  736. */
  737. void CDataTransferObj::OnPostReplaceRange(
  738. LONG cp, //@parm cp of the changes
  739. LONG cchDel, //@parm #of chars deleted
  740. LONG cchNew, //@parm # of chars added
  741. LONG cpFormatMin, //@parm min cp of formatting changes
  742. LONG cpFormatMax) //@parm max cp of formatting changes
  743. {
  744. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::OnPostReplaceRange");
  745. // Nothing to do
  746. return;
  747. }
  748. /*
  749. * CDataTransferObj::Zombie ()
  750. *
  751. * @mfunc
  752. * Turn this object into a zombie
  753. */
  754. void CDataTransferObj::Zombie ()
  755. {
  756. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CDataTransferObj::Zombie");
  757. _ped = NULL;
  758. }
  759. /*
  760. * CDataTransferObj::Create(ped, prg, lStreamFormat)
  761. *
  762. * @mfunc
  763. * static function to create CDataTransferObj. Used to force users
  764. * not to create this object on the stack, which would break OLE's
  765. * liveness rules.
  766. *
  767. * @rdesc
  768. * new CDataTransferObj *
  769. */
  770. CDataTransferObj *CDataTransferObj::Create(
  771. CTxtEdit *ped, // @parm ped to which this DataObject belongs
  772. CTxtRange *prg, // @parm range for the data object
  773. LONG lStreamFormat) // @parm stream format to use in Rtf conversion
  774. {
  775. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::Create");
  776. Assert(CFETC == ARRAY_SIZE(g_rgFETC) && CFETC == ARRAY_SIZE(g_rgDOI));
  777. LONG ch;
  778. CNotifyMgr * pnm;
  779. CDataTransferObj *pdo = new CDataTransferObj(ped);
  780. if( !pdo )
  781. {
  782. ped->GetCallMgr()->SetOutOfMemory();
  783. return NULL;
  784. }
  785. LONG cpMin, cpMost;
  786. pdo->_cch = prg->GetRange(cpMin, cpMost);
  787. pdo->_cpMin = cpMin;
  788. pdo->_lStreamFormat = lStreamFormat;
  789. pnm = ped->GetNotifyMgr();
  790. if(pnm)
  791. pnm->Add( (ITxNotify *) pdo );
  792. //Set the object count.
  793. pdo->_cObjs = 0;
  794. if( ped->HasObjects() )
  795. pdo->_cObjs = ped->_pobjmgr->CountObjectsInRange(cpMin, cpMost);
  796. int cTotal = !ped->IsRich() ? 2 :
  797. (ped->GetCharFlags() & ~(fLATIN1 | fSYMBOL)) ? 7 : 5;
  798. int cExtraFmtEtc = 0;
  799. COleObject *pobj = NULL;
  800. FORMATETC rgfetc[255];
  801. BOOL bValidOleObj = FALSE;
  802. // We only support 2 formats in the play text case
  803. if ( !ped->IsRich() )
  804. {
  805. pdo->_cTotal = cTotal;
  806. pdo->_prgFormats = new FORMATETC[cTotal];
  807. if (!pdo->_prgFormats)
  808. goto ErrorExit;
  809. // Plain-text case
  810. pdo->_prgFormats[0] = g_rgFETC[iAnsiFETC];
  811. pdo->_prgFormats[1] = g_rgFETC[iUnicodeFETC];
  812. return pdo;
  813. }
  814. // We need to count the number of supported formats
  815. if (ped->HasObjects() && pdo->_cch == 1 && prg->GetChar(&ch) == NOERROR && ch == WCH_EMBEDDING)
  816. {
  817. pobj = ped->_pobjmgr->GetObjectFromCp(pdo->_cpMin);
  818. pdo->_dwFlags = pobj->GetFlags();
  819. pdo->_dwUser = pobj->GetUser();
  820. pdo->_dvaspect =pobj->GetAspect();
  821. IUnknown * punk = pobj->GetIUnknown();
  822. // We want to query IOleObject on which formats it supports. And add that to the
  823. // FORMATETC array.
  824. if (punk && punk->QueryInterface(IID_IOleObject,(void **) &pdo->_pOleObj) == NOERROR)
  825. {
  826. bValidOleObj = TRUE;
  827. // Include the formats supported by the object
  828. IDataObject * pdataobj = NULL;
  829. if (FAILED(pdo->_pOleObj->GetClipboardData(0, &pdataobj)) || pdataobj == NULL)
  830. pdo->_pOleObj->QueryInterface(IID_IDataObject, (void**) &pdataobj);
  831. if (pdataobj)
  832. {
  833. IEnumFORMATETC *pifetc = NULL;
  834. // 1.0 didn't check the return value of EnumFormatEtc. This is important because ccMail
  835. // will return an OLE error although it actually succeeds in setting the formatetc
  836. if ((SUCCEEDED(pdataobj->EnumFormatEtc( DATADIR_GET, &pifetc)) || ped->Get10Mode()) && pifetc)
  837. {
  838. AssertSz(pifetc, "IEnumFormatEtc is NULL");
  839. // Copy the formats which are supported by the object
  840. while((pifetc->Next(1, &rgfetc[cExtraFmtEtc], NULL)) == S_OK && cExtraFmtEtc < 255)
  841. cExtraFmtEtc++;
  842. pifetc->Release();
  843. }
  844. pdataobj->Release();
  845. }
  846. }
  847. }
  848. pdo->_cTotal = cTotal + cExtraFmtEtc;
  849. pdo->_prgFormats = new FORMATETC[pdo->_cTotal];
  850. if (!pdo->_prgFormats)
  851. goto ErrorExit;
  852. if (pobj)
  853. {
  854. // copy over formats supported by the object itself
  855. if (cExtraFmtEtc)
  856. memcpy(pdo->_prgFormats, rgfetc, cExtraFmtEtc * sizeof(FORMATETC));
  857. // copy formats supported by Richedit as a container
  858. // Have an OLE object: offer all OLE formats plus RTF
  859. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iEmbObj]; // EmbeddedObject
  860. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iObtDesc]; // ObjectDescriptor
  861. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iMfPict]; // Metafile
  862. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iRtfFETC]; // RTF
  863. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iRtfNoObjs]; // RTF with no objects
  864. }
  865. else
  866. {
  867. // Regular rich-text case
  868. pdo->_prgFormats[0] = g_rgFETC[iRtfFETC]; // RTF
  869. pdo->_prgFormats[1] = g_rgFETC[iRtfNoObjs]; // RTF with no objects
  870. pdo->_prgFormats[2] = g_rgFETC[iRtfAsTextFETC]; // RTF as Text
  871. pdo->_prgFormats[3] = g_rgFETC[iAnsiFETC]; // ANSI plain text
  872. pdo->_prgFormats[4] = g_rgFETC[iUnicodeFETC]; // Unicode plain text
  873. cExtraFmtEtc = 5;
  874. }
  875. // We only offer up the six formats that we know how to handle in GetData.
  876. // The actual values differ somewhat from regular rich text and text
  877. // with embedded objects
  878. if (cTotal == 7)
  879. {
  880. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iRtfUtf8]; // RTF in UTF-8
  881. pdo->_prgFormats[cExtraFmtEtc++] = g_rgFETC[iRtfNCRforNonASCII];
  882. }
  883. // Get the embedded object formats now
  884. if (bValidOleObj)
  885. {
  886. SIZEL sizel;
  887. pobj->GetSizel(sizel);
  888. pdo->_hObjDesc = pdo->GetDataForObjectDescriptor( pdo->_pOleObj, pobj->GetDvaspect(), &sizel);
  889. pdo->_pObjStg = pdo->GetDataForEmbeddedObject( pdo->_pOleObj, NULL );
  890. pdo->_hMFPict = (HMETAFILE) OleStdGetMetafilePictFromOleObject( pdo->_pOleObj,
  891. pobj->GetDvaspect(), NULL, NULL);
  892. }
  893. return pdo;
  894. ErrorExit:
  895. pdo->_cTotal = 0;
  896. pdo->Release();
  897. ped->GetCallMgr()->SetOutOfMemory();
  898. return NULL;
  899. }
  900. /*
  901. * CDataTransferObj::TextToHglobal(hText, tKind)
  902. *
  903. * @mfunc
  904. * Instantiates text on demand for the data object.
  905. *
  906. * @rdesc
  907. * HGLOBAL
  908. */
  909. HGLOBAL CDataTransferObj::TextToHglobal(
  910. HGLOBAL &hText,
  911. TEXTKIND tKind)
  912. {
  913. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::PlainTextToHglobal");
  914. if (hText == NULL)
  915. {
  916. CTxtRange rg(_ped, _cpMin, -_cch);
  917. if (tKind == tPlain)
  918. {
  919. hText = _ped->GetDTE()->UnicodePlainTextFromRange(&rg);
  920. }
  921. else if(_ped->IsRich())
  922. {
  923. LONG lStreamFormat = _lStreamFormat;
  924. if(tKind == tRtfUtf8)
  925. lStreamFormat = LOWORD(lStreamFormat) | SF_USECODEPAGE | (CP_UTF8 << 16);
  926. else if(tKind == tRtfNCRforNonASCII)
  927. lStreamFormat |= SF_NCRFORNONASCII;
  928. hText = _ped->GetDTE()->RtfFromRange(&rg, lStreamFormat);
  929. }
  930. }
  931. return hText;
  932. }
  933. //
  934. // CDataTransferObj PRIVATE methods
  935. //
  936. /*
  937. * CDataTransferObj::CDataTransferObj()
  938. *
  939. * @mfunc
  940. * Private constructor
  941. */
  942. CDataTransferObj::CDataTransferObj( CTxtEdit *ped )
  943. {
  944. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::CDataTransferObj");
  945. _ped = ped;
  946. _crefs = 1;
  947. _cTotal = CFETC;
  948. _prgFormats = g_rgFETC;
  949. _cch = 0;
  950. _cObjs = 0;
  951. }
  952. /*
  953. * CDataTransferObj::~CDataTransferObj
  954. *
  955. * @mfunc
  956. * Private destructor
  957. */
  958. CDataTransferObj::~CDataTransferObj()
  959. {
  960. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDataTransferObj::~CDataTransferObj");
  961. // No need to monitor notifications any more
  962. CNotifyMgr *pnm;
  963. if(_ped)
  964. {
  965. pnm = _ped->GetNotifyMgr();
  966. if(pnm)
  967. pnm->Remove( (ITxNotify *)this );
  968. }
  969. if( _prgFormats && _prgFormats != g_rgFETC)
  970. delete _prgFormats;
  971. if (_pOleObj)
  972. _pOleObj->Release();
  973. if (_pObjStg)
  974. _pObjStg->Release();
  975. #ifndef NOMETAFILES
  976. if (_hMFPict)
  977. (void) DeleteMetaFile(_hMFPict);
  978. #endif
  979. GlobalFree(_hObjDesc);
  980. }
  981. //
  982. // CEnumFormatEtc PUBLIC methods
  983. //
  984. /*
  985. * CEnumFormatEtc::QueryInterface (riid, ppvObj)
  986. *
  987. * @mfunc
  988. * IUnknown method
  989. *
  990. * @rdesc
  991. * HRESULT
  992. */
  993. STDMETHODIMP CEnumFormatEtc::QueryInterface(
  994. REFIID riid, // @parm Reference to requested interface ID
  995. void ** ppv) // @parm out parm for interface ptr
  996. {
  997. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::QueryInterface");
  998. HRESULT hresult = E_NOINTERFACE;
  999. *ppv = NULL;
  1000. if( IsEqualIID(riid, IID_IUnknown) ||
  1001. IsEqualIID(riid, IID_IEnumFORMATETC) )
  1002. {
  1003. *ppv = this;
  1004. AddRef();
  1005. hresult = NOERROR;
  1006. }
  1007. return hresult;
  1008. }
  1009. /*
  1010. * CEnumFormatEtc::AddRef()
  1011. *
  1012. * @mfunc
  1013. * IUnknown method
  1014. *
  1015. * @rdesc
  1016. * ULONG - incremented reference count
  1017. */
  1018. STDMETHODIMP_(ULONG) CEnumFormatEtc::AddRef( )
  1019. {
  1020. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::AddRef");
  1021. return ++_crefs;
  1022. }
  1023. /*
  1024. * CEnumFormatEtc::Release()
  1025. *
  1026. * @mfunc
  1027. * IUnknown method
  1028. *
  1029. * @rdesc
  1030. * ULONG - decremented reference count
  1031. */
  1032. STDMETHODIMP_(ULONG) CEnumFormatEtc::Release( )
  1033. {
  1034. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Release");
  1035. _crefs--;
  1036. if( _crefs == 0 )
  1037. {
  1038. delete this;
  1039. return 0;
  1040. }
  1041. return _crefs;
  1042. }
  1043. /*
  1044. * CEnumFormatEtc::Next (celt, rgelt, pceltFetched)
  1045. *
  1046. * @mfunc
  1047. * fetches the next [celt] elements in our formatetc collection
  1048. *
  1049. * @rdesc
  1050. * HRESULT
  1051. */
  1052. STDMETHODIMP CEnumFormatEtc::Next( ULONG celt, FORMATETC *rgelt,
  1053. ULONG *pceltFetched)
  1054. {
  1055. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Next");
  1056. HRESULT hresult = NOERROR;
  1057. ULONG cFetched;
  1058. if( pceltFetched == NULL && celt != 1 )
  1059. {
  1060. // the spec says that if pceltFetched == NULL, then
  1061. // the count of elements to fetch must be 1
  1062. return E_INVALIDARG;
  1063. }
  1064. // we can only grab as many elements as there are left
  1065. if( celt > _cTotal - _iCurrent )
  1066. {
  1067. cFetched = _cTotal - _iCurrent;
  1068. hresult = S_FALSE;
  1069. }
  1070. else
  1071. cFetched = celt;
  1072. // Only copy if we have elements to copy
  1073. if( cFetched > 0 )
  1074. {
  1075. memcpy( rgelt, _prgFormats + _iCurrent,
  1076. cFetched * sizeof(FORMATETC) );
  1077. }
  1078. _iCurrent += cFetched;
  1079. if( pceltFetched )
  1080. *pceltFetched = cFetched;
  1081. return hresult;
  1082. }
  1083. /*
  1084. * CEnumFormatEtc::Skip
  1085. *
  1086. * @mfunc
  1087. * skips the next [celt] formats
  1088. *
  1089. * @rdesc
  1090. * HRESULT
  1091. */
  1092. STDMETHODIMP CEnumFormatEtc::Skip( ULONG celt )
  1093. {
  1094. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Skip");
  1095. HRESULT hresult = NOERROR;
  1096. _iCurrent += celt;
  1097. if( _iCurrent > _cTotal )
  1098. {
  1099. // whoops, skipped too far ahead. Set us to the max limit.
  1100. _iCurrent = _cTotal;
  1101. hresult = S_FALSE;
  1102. }
  1103. return hresult;
  1104. }
  1105. /*
  1106. * CEnumFormatEtc::Reset
  1107. *
  1108. * @mfunc
  1109. * resets the seek pointer to zero
  1110. *
  1111. * @rdesc
  1112. * HRESULT
  1113. */
  1114. STDMETHODIMP CEnumFormatEtc::Reset( void )
  1115. {
  1116. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Reset");
  1117. _iCurrent = 0;
  1118. return NOERROR;
  1119. }
  1120. /*
  1121. * CEnumFormatEtc::Clone
  1122. *
  1123. * @mfunc
  1124. * clones the enumerator
  1125. *
  1126. * @rdesc
  1127. * HRESULT
  1128. */
  1129. STDMETHODIMP CEnumFormatEtc::Clone( IEnumFORMATETC **ppIEnum )
  1130. {
  1131. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Clone");
  1132. return CEnumFormatEtc::Create(_prgFormats, _cTotal, ppIEnum);
  1133. }
  1134. /*
  1135. * CEnumFormatEtc::Create (prgFormats, cTotal, hr)
  1136. *
  1137. * @mfunc
  1138. * creates a new format enumerator
  1139. *
  1140. * @rdesc
  1141. * HRESULT
  1142. *
  1143. * @devnote
  1144. * *copies* the formats passed in. We do this as it simplifies
  1145. * memory management under OLE object liveness rules
  1146. */
  1147. HRESULT CEnumFormatEtc::Create( FORMATETC *prgFormats, ULONG cTotal,
  1148. IEnumFORMATETC **ppenum )
  1149. {
  1150. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::Create");
  1151. CEnumFormatEtc *penum = new CEnumFormatEtc();
  1152. if(penum)
  1153. {
  1154. // _iCurrent, _crefs are set in the constructor
  1155. if( cTotal > 0 )
  1156. {
  1157. penum->_prgFormats = new FORMATETC[cTotal];
  1158. if( penum->_prgFormats )
  1159. {
  1160. penum->_cTotal = cTotal;
  1161. memcpy(penum->_prgFormats, prgFormats,
  1162. cTotal * sizeof(FORMATETC));
  1163. *ppenum = penum;
  1164. return NOERROR;
  1165. }
  1166. }
  1167. delete penum;
  1168. }
  1169. return E_OUTOFMEMORY;
  1170. }
  1171. //
  1172. // CEnumFormatEtc PRIVATE methods
  1173. //
  1174. /*
  1175. * CEnumFormatEtc::CEnumFormatEtc()
  1176. *
  1177. * @mfunc
  1178. * Private constructor
  1179. */
  1180. CEnumFormatEtc::CEnumFormatEtc()
  1181. {
  1182. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::CEnumFormatEtc");
  1183. _cTotal = 0;
  1184. _crefs = 1;
  1185. _prgFormats = NULL;
  1186. _iCurrent = 0;
  1187. }
  1188. /*
  1189. * CEnumFormatEtc::~CEnumFormatEtc()
  1190. *
  1191. * @mfunc
  1192. * Private destructor
  1193. */
  1194. CEnumFormatEtc::~CEnumFormatEtc( void )
  1195. {
  1196. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CEnumFormatEtc::~CEnumFormatEtc");
  1197. if( _prgFormats )
  1198. delete _prgFormats;
  1199. }