Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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