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.

995 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: ido.cpp
  7. //
  8. // Contents: Special data object implementation to optimize drag/drop
  9. //
  10. // Classes: CDragDataObject
  11. //
  12. // Functions: CreateDragDataObject
  13. //
  14. // History: dd-mmm-yy Author Comment
  15. // 30-Sep-94 ricksa Created
  16. //
  17. // Notes:
  18. //
  19. //--------------------------------------------------------------------------
  20. #include <le2int.h>
  21. #include <utils.h>
  22. #include <dragopt.h>
  23. #include <clipdata.h>
  24. // Format for name of shared memory
  25. OLECHAR szSharedMemoryTemplate[] = OLESTR("DragDrop%lx");
  26. // Maximum size of string for name of shared memory. This is the size of the
  27. // template plus the maximum number of hex digits in a long.
  28. const int DRAG_SM_NAME_MAX = sizeof(szSharedMemoryTemplate)
  29. + sizeof(DWORD) * 2;
  30. // Useful function for getting an enumerator
  31. HRESULT wGetEnumFormatEtc(
  32. IDataObject *pDataObj,
  33. DWORD dwDirection,
  34. IEnumFORMATETC **ppIEnum);
  35. //+-------------------------------------------------------------------------
  36. //
  37. // Class: CDragDataObject
  38. //
  39. // Purpose: Server side data object for drag that creates enumerator
  40. // for shared formats.
  41. //
  42. // Interface: QueryInterface
  43. // AddRef
  44. // Release
  45. // GetData
  46. // GetDataHere
  47. // QueryGetData
  48. // GetCanonicalFormatEtc
  49. // SetData
  50. // EnumFormatEtc
  51. // DAdvise
  52. // DUnadvise
  53. // EnumDAdvise
  54. //
  55. // History: dd-mmm-yy Author Comment
  56. // 30-Sep-94 Ricksa Created
  57. //
  58. // Notes: This class only exists for return the enumerator. For
  59. // all other operations it will simply pass the operation on
  60. // to the real data object.
  61. //
  62. //--------------------------------------------------------------------------
  63. class CDragDataObject : public IDataObject, public CPrivAlloc
  64. {
  65. public:
  66. CDragDataObject(
  67. void *pvMarshaledDataObject,
  68. DWORD dwSmId);
  69. ~CDragDataObject(void);
  70. //
  71. // IUnknown
  72. //
  73. STDMETHODIMP QueryInterface(
  74. REFIID riid,
  75. void **ppvObject);
  76. STDMETHODIMP_(ULONG) AddRef(void);
  77. STDMETHODIMP_(ULONG) Release(void);
  78. //
  79. // IDataObject
  80. //
  81. STDMETHODIMP GetData(
  82. FORMATETC *pformatetcIn,
  83. STGMEDIUM *pmedium);
  84. STDMETHODIMP GetDataHere(
  85. FORMATETC *pformatetc,
  86. STGMEDIUM *pmedium);
  87. STDMETHODIMP QueryGetData(
  88. FORMATETC *pformatetc);
  89. STDMETHODIMP GetCanonicalFormatEtc(
  90. FORMATETC *pformatectIn,
  91. FORMATETC *pformatetcOut);
  92. STDMETHODIMP SetData(
  93. FORMATETC *pformatetc,
  94. STGMEDIUM *pmedium,
  95. BOOL fRelease);
  96. STDMETHODIMP EnumFormatEtc(
  97. DWORD dwDirection,
  98. IEnumFORMATETC **ppenumFormatEtc);
  99. STDMETHODIMP DAdvise(
  100. FORMATETC *pformatetc,
  101. DWORD advf,
  102. IAdviseSink *pAdvSink,
  103. DWORD *pdwConnection);
  104. STDMETHODIMP DUnadvise(DWORD dwConnection);
  105. STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
  106. private:
  107. IDataObject * GetRealDataObjPtr(void);
  108. HRESULT GetFormatEtcDataArray(void);
  109. ULONG _cRefs;
  110. void * _pvMarshaledDataObject;
  111. IDataObject * _pIDataObject;
  112. FORMATETCDATAARRAY *m_pFormatEtcDataArray;
  113. DWORD _dwSmId;
  114. };
  115. //+-------------------------------------------------------------------------
  116. //
  117. // Member: CDragDataObject::CDragDataObject
  118. //
  119. // Synopsis: Create server side object for drag
  120. //
  121. // History: dd-mmm-yy Author Comment
  122. // 30-Sep-94 Ricksa Created
  123. //
  124. //--------------------------------------------------------------------------
  125. CDragDataObject::CDragDataObject(void *pvMarshaledDataObject, DWORD dwSmId)
  126. : _cRefs(1), _pvMarshaledDataObject(pvMarshaledDataObject), _dwSmId(dwSmId),
  127. _pIDataObject(NULL), m_pFormatEtcDataArray(NULL)
  128. {
  129. // Header does all the work
  130. }
  131. //+-------------------------------------------------------------------------
  132. //
  133. // Member: CDragDataObject::~CDragDataObject
  134. //
  135. // Synopsis: Free any resources connected with this object
  136. //
  137. // History: dd-mmm-yy Author Comment
  138. // 30-Sep-94 Ricksa Created
  139. //
  140. // Note:
  141. //
  142. //--------------------------------------------------------------------------
  143. CDragDataObject::~CDragDataObject(void)
  144. {
  145. // Release held pointer since we no longer need it.
  146. if (_pIDataObject)
  147. {
  148. _pIDataObject->Release();
  149. }
  150. // this memory was allocated in RemPrivDragDrop, getif.cxx
  151. if( _pvMarshaledDataObject )
  152. {
  153. PrivMemFree(_pvMarshaledDataObject);
  154. }
  155. if (m_pFormatEtcDataArray)
  156. {
  157. if (0 == --m_pFormatEtcDataArray->_cRefs)
  158. {
  159. PrivMemFree(m_pFormatEtcDataArray);
  160. m_pFormatEtcDataArray = NULL;
  161. }
  162. }
  163. }
  164. //+-------------------------------------------------------------------------
  165. //
  166. // Member: CDragDataObject::GetRealDataObjPtr
  167. //
  168. // Synopsis: Get the pointer to the real data object from the client
  169. //
  170. // Returns: NULL - could not unmarshal drag source's data object
  171. // ~NULL - pointer to drag source's data object
  172. //
  173. // History: dd-mmm-yy Author Comment
  174. // 30-Sep-94 Ricksa Created
  175. //
  176. //--------------------------------------------------------------------------
  177. IDataObject *CDragDataObject::GetRealDataObjPtr(void)
  178. {
  179. if (_pIDataObject == NULL)
  180. {
  181. _pIDataObject = UnmarshalDragDataObject(_pvMarshaledDataObject);
  182. LEERROR(!_pIDataObject, "Unable to unmarshal dnd data object");
  183. }
  184. return _pIDataObject;
  185. }
  186. //+-------------------------------------------------------------------------
  187. //
  188. // Member: CDragDataObject::GetFormatEtcDataArray (private)
  189. //
  190. // Synopsis: if don't already have shared formats for enumeraor.
  191. //
  192. // Effects:
  193. //
  194. // Arguments: void
  195. //
  196. // Requires:
  197. //
  198. // Returns: HRESULT
  199. //
  200. // Signals:
  201. //
  202. // Modifies:
  203. //
  204. // Derivation:
  205. //
  206. // Algorithm:
  207. //
  208. // History: dd-mmm-yy Author Comment
  209. // 13-Jun-94 Ricksa author
  210. //
  211. // Notes:
  212. //
  213. //--------------------------------------------------------------------------
  214. HRESULT CDragDataObject::GetFormatEtcDataArray(void)
  215. {
  216. OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX];
  217. HANDLE hSharedMemory;
  218. FORMATETCDATAARRAY *pFormatEtcDataArray = NULL;
  219. if (m_pFormatEtcDataArray)
  220. return NOERROR;
  221. wsprintf(szSharedMemoryName, szSharedMemoryTemplate, _dwSmId);
  222. // Create the shared memory object
  223. hSharedMemory = OpenFileMapping(FILE_MAP_READ, FALSE, szSharedMemoryName);
  224. if (hSharedMemory != NULL)
  225. {
  226. // Map in the shared memory
  227. pFormatEtcDataArray = (FORMATETCDATAARRAY *) MapViewOfFile(hSharedMemory,
  228. FILE_MAP_READ, 0, 0, 0);
  229. if (NULL == pFormatEtcDataArray)
  230. {
  231. CloseHandle(hSharedMemory);
  232. hSharedMemory = NULL;
  233. }
  234. }
  235. if (pFormatEtcDataArray)
  236. {
  237. size_t stSize;
  238. GetCopiedFormatEtcDataArraySize (pFormatEtcDataArray, &stSize);
  239. m_pFormatEtcDataArray = (FORMATETCDATAARRAY *) PrivMemAlloc(stSize);
  240. if (m_pFormatEtcDataArray)
  241. {
  242. CopyFormatEtcDataArray (m_pFormatEtcDataArray, pFormatEtcDataArray, stSize, FALSE);
  243. Assert(1 == m_pFormatEtcDataArray->_cRefs);
  244. }
  245. UnmapViewOfFile(pFormatEtcDataArray);
  246. CloseHandle(hSharedMemory);
  247. }
  248. return m_pFormatEtcDataArray ? NOERROR : E_OUTOFMEMORY;
  249. }
  250. //+-------------------------------------------------------------------------
  251. //
  252. // Member: CDragDataObject::QueryInterface
  253. //
  254. // Synopsis: Get new interface
  255. //
  256. // Arguments: [riid] - interface id of requested interface
  257. // [ppvObject] - where to put the new interface pointer
  258. //
  259. // Returns: NOERROR - interface was instantiated
  260. // E_FAIL - could not unmarshal source's data object
  261. // other - some error occurred.
  262. //
  263. // History: dd-mmm-yy Author Comment
  264. // 30-Sep-94 Ricksa Created
  265. //
  266. // Note:
  267. //
  268. //--------------------------------------------------------------------------
  269. STDMETHODIMP CDragDataObject::QueryInterface(
  270. REFIID riid,
  271. void **ppvObject)
  272. {
  273. if(IsEqualIID(riid, IID_IDataObject) ||
  274. IsEqualIID(riid, IID_IUnknown))
  275. {
  276. *ppvObject = this;
  277. AddRef();
  278. return NOERROR;
  279. }
  280. return (GetRealDataObjPtr() != NULL)
  281. ? _pIDataObject->QueryInterface(riid, ppvObject)
  282. : E_FAIL;
  283. }
  284. //+-------------------------------------------------------------------------
  285. //
  286. // Member: CDragDataObject::AddRef
  287. //
  288. // Synopsis: Create server side object for drag
  289. //
  290. // Returns: Current reference count
  291. //
  292. // History: dd-mmm-yy Author Comment
  293. // 30-Sep-94 Ricksa Created
  294. //
  295. //--------------------------------------------------------------------------
  296. STDMETHODIMP_(ULONG) CDragDataObject::AddRef(void)
  297. {
  298. DDDebugOut((DEB_ITRACE, "ADDREF == %d\n", _cRefs + 1));
  299. return ++_cRefs;
  300. }
  301. //+-------------------------------------------------------------------------
  302. //
  303. // Member: CDragDataObject::Release
  304. //
  305. // Synopsis: Decrement reference count to the object
  306. //
  307. // Returns: Current reference count to the object
  308. //
  309. // History: dd-mmm-yy Author Comment
  310. // 30-Sep-94 Ricksa Created
  311. //
  312. //--------------------------------------------------------------------------
  313. STDMETHODIMP_(ULONG) CDragDataObject::Release(void)
  314. {
  315. ULONG cRefs = --_cRefs;
  316. DDDebugOut((DEB_ITRACE, "RELEASE == %d\n", cRefs));
  317. if (cRefs == 0)
  318. {
  319. delete this;
  320. }
  321. return cRefs;
  322. }
  323. //+-------------------------------------------------------------------------
  324. //
  325. // Member: CDragDataObject::GetData
  326. //
  327. // Synopsis: Create server side object for drag
  328. //
  329. // Arguments: [pformatetcIn] - format for requested data
  330. // [pmedium] - storage medium
  331. //
  332. // Returns: NOERROR - operation was successful
  333. // Other - operation failed
  334. //
  335. // History: dd-mmm-yy Author Comment
  336. // 30-Sep-94 Ricksa Created
  337. //
  338. // Note: This just forwards the operation to the source data object
  339. // if possible.
  340. //
  341. //--------------------------------------------------------------------------
  342. STDMETHODIMP CDragDataObject::GetData(
  343. FORMATETC *pformatetcIn,
  344. STGMEDIUM *pmedium)
  345. {
  346. return (GetRealDataObjPtr() != NULL)
  347. ? _pIDataObject->GetData(pformatetcIn, pmedium)
  348. : E_FAIL;
  349. }
  350. //+-------------------------------------------------------------------------
  351. //
  352. // Member: CDragDataObject::GetDataHere
  353. //
  354. // Synopsis: Create server side object for drag
  355. //
  356. // Arguments: [pformatetc] - format for requested data
  357. // [pmedium] - storage medium
  358. //
  359. // Returns: NOERROR - operation was successful
  360. // Other - operation failed
  361. //
  362. // History: dd-mmm-yy Author Comment
  363. // 30-Sep-94 Ricksa Created
  364. //
  365. // Note: This just forwards the operation to the source data object
  366. // if possible.
  367. //
  368. //--------------------------------------------------------------------------
  369. STDMETHODIMP CDragDataObject::GetDataHere(
  370. FORMATETC *pformatetc,
  371. STGMEDIUM *pmedium)
  372. {
  373. return (GetRealDataObjPtr() != NULL)
  374. ? _pIDataObject->GetDataHere(pformatetc, pmedium)
  375. : E_FAIL;
  376. }
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Member: CDragDataObject::QueryGetData
  380. //
  381. // Synopsis: Create server side object for drag
  382. //
  383. // Arguments: [pformatetc] - format to verify
  384. //
  385. // Returns: NOERROR - operation was successful
  386. // Other - operation failed
  387. //
  388. // History: dd-mmm-yy Author Comment
  389. // 30-Sep-94 Ricksa Created
  390. //
  391. // Note: This just forwards the operation to the source data object
  392. // if possible.
  393. //
  394. //--------------------------------------------------------------------------
  395. STDMETHODIMP CDragDataObject::QueryGetData(FORMATETC *pformatetc)
  396. {
  397. return (GetRealDataObjPtr() != NULL)
  398. ? _pIDataObject->QueryGetData(pformatetc)
  399. : E_FAIL;
  400. }
  401. //+-------------------------------------------------------------------------
  402. //
  403. // Member: CDragDataObject::GetCanonicalFormatEtc
  404. //
  405. // Synopsis: Create server side object for drag
  406. //
  407. // Arguments: [pformatetcIn] - input format
  408. // [pformatetcOut] - output format
  409. //
  410. // Returns: NOERROR - operation was successful
  411. // Other - operation failed
  412. //
  413. // History: dd-mmm-yy Author Comment
  414. // 30-Sep-94 Ricksa Created
  415. //
  416. // Note: This just forwards the operation to the source data object
  417. // if possible.
  418. //
  419. //--------------------------------------------------------------------------
  420. STDMETHODIMP CDragDataObject::GetCanonicalFormatEtc(
  421. FORMATETC *pformatetcIn,
  422. FORMATETC *pformatetcOut)
  423. {
  424. return (GetRealDataObjPtr() != NULL)
  425. ? _pIDataObject->GetCanonicalFormatEtc(pformatetcIn, pformatetcOut)
  426. : E_FAIL;
  427. }
  428. //+-------------------------------------------------------------------------
  429. //
  430. // Member: CDragDataObject::SetData
  431. //
  432. // Synopsis: Create server side object for drag
  433. //
  434. // Arguments: [pformatetc] - format for set
  435. // [pmedium] - medium to use
  436. // [fRelease] - who releases
  437. //
  438. // Returns: NOERROR - operation was successful
  439. // Other - operation failed
  440. //
  441. // History: dd-mmm-yy Author Comment
  442. // 30-Sep-94 Ricksa Created
  443. //
  444. // Note: This just forwards the operation to the source data object
  445. // if possible.
  446. //
  447. //--------------------------------------------------------------------------
  448. STDMETHODIMP CDragDataObject::SetData(
  449. FORMATETC *pformatetc,
  450. STGMEDIUM *pmedium,
  451. BOOL fRelease)
  452. {
  453. return (GetRealDataObjPtr() != NULL)
  454. ? _pIDataObject->SetData(pformatetc, pmedium, fRelease)
  455. : E_FAIL;
  456. }
  457. //+-------------------------------------------------------------------------
  458. //
  459. // Member: CDragDataObject::EnumFormatEtc
  460. //
  461. // Synopsis: Create server side object for drag
  462. //
  463. // Arguments: [dwDirection] - direction of formats either set or get
  464. // [ppenumFormatEtc] - where to put enumerator
  465. //
  466. // Returns: NOERROR - operation succeeded.
  467. //
  468. // Algorithm: If format enumerator requested is for a data get, the
  469. // create our private enumerator object otherwise pass
  470. // the request to the real data object.
  471. //
  472. // History: dd-mmm-yy Author Comment
  473. // 30-Sep-94 Ricksa Created
  474. //
  475. // Note: For the data set direction, we just use the data object of
  476. // the drop source.
  477. //
  478. //--------------------------------------------------------------------------
  479. STDMETHODIMP CDragDataObject::EnumFormatEtc(
  480. DWORD dwDirection,
  481. IEnumFORMATETC **ppenumFormatEtc)
  482. {
  483. HRESULT hr;
  484. // Create our enumerator
  485. if (dwDirection == DATADIR_GET)
  486. {
  487. // In the data get case we use our overridden enumerator.
  488. // This s/b the typical case with Drag and Drop.
  489. *ppenumFormatEtc = NULL;
  490. GetFormatEtcDataArray();
  491. if (m_pFormatEtcDataArray)
  492. {
  493. // enumerator implementation in Clipdata.cpp
  494. *ppenumFormatEtc = new CEnumFormatEtcDataArray(m_pFormatEtcDataArray,0);
  495. }
  496. hr = *ppenumFormatEtc ? NOERROR : E_OUTOFMEMORY;
  497. }
  498. else
  499. {
  500. // Call through to the real data object because this is the
  501. // set case. In general, this won't happen during Drag and Drop.
  502. hr = (GetRealDataObjPtr() != NULL)
  503. ? _pIDataObject->EnumFormatEtc(dwDirection, ppenumFormatEtc)
  504. : E_FAIL;
  505. }
  506. return hr;
  507. }
  508. //+-------------------------------------------------------------------------
  509. //
  510. // Member: CDragDataObject::DAdvise
  511. //
  512. // Synopsis: Create server side object for drag
  513. //
  514. // Arguments: [pformatetc] - format to be advised on
  515. // [advf] - type of advise
  516. // [pAdvSink] - advise to notify
  517. // [pdwConnection] - connection id for advise
  518. //
  519. // Returns: NOERROR - operation was successful
  520. // Other - operation failed
  521. //
  522. // History: dd-mmm-yy Author Comment
  523. // 30-Sep-94 Ricksa Created
  524. //
  525. // Note: This just forwards the operation to the source data object
  526. // if possible.
  527. //
  528. //--------------------------------------------------------------------------
  529. STDMETHODIMP CDragDataObject::DAdvise(
  530. FORMATETC *pformatetc,
  531. DWORD advf,
  532. IAdviseSink *pAdvSink,
  533. DWORD *pdwConnection)
  534. {
  535. return (GetRealDataObjPtr() != NULL)
  536. ? _pIDataObject->DAdvise(pformatetc, advf, pAdvSink, pdwConnection)
  537. : E_FAIL;
  538. }
  539. //+-------------------------------------------------------------------------
  540. //
  541. // Member: CDragDataObject::DUnadvise
  542. //
  543. // Synopsis: Create server side object for drag
  544. //
  545. // Arguments: [dwConnection] - connection id for advise
  546. //
  547. // Returns: NOERROR - operation was successful
  548. // Other - operation failed
  549. //
  550. // History: dd-mmm-yy Author Comment
  551. // 30-Sep-94 Ricksa Created
  552. //
  553. // Note: This just forwards the operation to the source data object
  554. // if possible.
  555. //
  556. //--------------------------------------------------------------------------
  557. STDMETHODIMP CDragDataObject::DUnadvise(DWORD dwConnection)
  558. {
  559. return (GetRealDataObjPtr() != NULL)
  560. ? _pIDataObject->DUnadvise(dwConnection)
  561. : E_FAIL;
  562. }
  563. //+-------------------------------------------------------------------------
  564. //
  565. // Member: CDragDataObject::EnumDAdvise
  566. //
  567. // Synopsis: Create server side object for drag
  568. //
  569. // Arguments: [ppenumAdvise] - where to put the enumerator
  570. //
  571. // Returns: NOERROR - operation was successful
  572. // Other - operation failed
  573. //
  574. // History: dd-mmm-yy Author Comment
  575. // 30-Sep-94 Ricksa Created
  576. //
  577. // Note: This just forwards the operation to the source data object
  578. // if possible.
  579. //
  580. //--------------------------------------------------------------------------
  581. STDMETHODIMP CDragDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
  582. {
  583. return (GetRealDataObjPtr() != NULL)
  584. ? _pIDataObject->EnumDAdvise(ppenumAdvise)
  585. : E_FAIL;
  586. }
  587. //+-------------------------------------------------------------------------
  588. //
  589. // Member: CreateDragDataObject
  590. //
  591. // Synopsis: Create the server side data object for format enumeration
  592. //
  593. // Arguments: [pvMarshaledDataObject] - marshaled real data object buffer
  594. // [dwSmId] - id for the shared memory
  595. // [ppIDataObject] - output data object.
  596. //
  597. // Returns: NOERROR - could create the object
  598. // E_OUTOFMEMORY - could not create the object
  599. //
  600. //
  601. // History: dd-mmm-yy Author Comment
  602. // 30-Sep-94 Ricksa Created
  603. //
  604. // Note:
  605. //
  606. //--------------------------------------------------------------------------
  607. HRESULT CreateDragDataObject(
  608. void *pvMarshaledDataObject,
  609. DWORD dwSmId,
  610. IDataObject **ppIDataObject)
  611. {
  612. CDragDataObject *pDragDataObject =
  613. new CDragDataObject(pvMarshaledDataObject, dwSmId);
  614. if (pDragDataObject != NULL)
  615. {
  616. *ppIDataObject = pDragDataObject;
  617. }
  618. // The only thing that can fail here is the memory allocation of
  619. // CDragDataObject thus there are only two error returns.
  620. return (pDragDataObject != NULL) ? NOERROR : E_OUTOFMEMORY;
  621. }
  622. //+-------------------------------------------------------------------------
  623. //
  624. // Member: CreateSharedDragFormats
  625. //
  626. // Synopsis: Put the data formats for the data object in shared memory.
  627. //
  628. // Arguments: [pIDataObject] - data object to use for formats.
  629. //
  630. // Returns: NULL - could not create enumerator
  631. // ~NULL - handle to shared memory
  632. //
  633. // Algorithm: First calculate the size of the required memory by enumerating
  634. // the formats. Then allocate the memory and map it into the
  635. // process. Then enumerate the formats again placing them in
  636. // the shared memory. Finally, map the memory out of the
  637. // process and return the handle the file mapping to the
  638. // caller.
  639. //
  640. // History: dd-mmm-yy Author Comment
  641. // 30-Sep-94 Ricksa Created
  642. //
  643. //--------------------------------------------------------------------------
  644. HANDLE CreateSharedDragFormats(IDataObject *pIDataObject)
  645. {
  646. // Handle to the shared memory for formats
  647. HANDLE hSharedMemory = NULL;
  648. // Pointer to share memory
  649. FORMATETCDATAARRAY *pFormatEtcDataArray = NULL;
  650. // Size required for the shared memory
  651. DWORD dwSize = 0;
  652. // Count of FORMATETCs contained in the enumerator
  653. DWORD cFormatEtc = 0;
  654. // Buffer for name of shared memory for enumerator
  655. OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX];
  656. // Work pointer to shared memory for storing FORMATETCs from the enumerator.
  657. FORMATETCDATA *pFormatEtcData;
  658. // Work ptr to shared memory for storing DVTARGETDEVICEs from enumerator.
  659. BYTE *pbDvTarget = NULL;
  660. //
  661. // Calculate the size of the formats
  662. //
  663. // Get the format enumerator
  664. IEnumFORMATETC *penum = NULL;
  665. HRESULT hr = wGetEnumFormatEtc(pIDataObject, DATADIR_GET, &penum);
  666. FORMATETC FormatEtc;
  667. if( hr != NOERROR )
  668. {
  669. // not all apps support enumerators (yahoo). Also, we may
  670. // have run out of memory or encountered some other error.
  671. DDDebugOut((DEB_WARN, "WARNING: Failed to get formatetc enumerator"
  672. ", error code (%lx)", hr));
  673. goto exitRtn;
  674. }
  675. // Enumerate the data one at a time because this is a local operation
  676. // and it make the code simpler.
  677. while ((hr = penum->Next(1, &FormatEtc, NULL)) == S_OK)
  678. {
  679. // Bump the entry count
  680. cFormatEtc++;
  681. // Bump the size by the size of another FORMATETC.
  682. dwSize += sizeof(FORMATETCDATA);
  683. // Is there a device target associated with the FORMATETC?
  684. if (FormatEtc.ptd != NULL)
  685. {
  686. // Bump the size required by the size of the target device
  687. dwSize += FormatEtc.ptd->tdSize;
  688. // Free the target device
  689. CoTaskMemFree(FormatEtc.ptd);
  690. }
  691. }
  692. // HRESULT s/b S_FALSE at the end of the enumeration.
  693. if (hr != S_FALSE)
  694. {
  695. goto errRtn;
  696. }
  697. // the enumerator may have been empty
  698. if( dwSize == 0 )
  699. {
  700. DDDebugOut((DEB_WARN, "WARNING: Empty formatetc enumerator"));
  701. goto exitRtn;
  702. }
  703. dwSize += sizeof(FORMATETCDATAARRAY); // add space for _cFormats and one extra FORMATETC for FALSE in enumerator.
  704. //
  705. // Create shared memory for the type enumeration
  706. //
  707. // Build name of shared memory - make it unique by using the thread id.
  708. wsprintf(szSharedMemoryName, szSharedMemoryTemplate, GetCurrentThreadId());
  709. // Create the shared memory object
  710. hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
  711. PAGE_READWRITE, 0, dwSize, szSharedMemoryName);
  712. // Did the file mapping get created?
  713. if (hSharedMemory == NULL)
  714. {
  715. goto errRtn;
  716. }
  717. // Map in the memory
  718. pFormatEtcDataArray = (FORMATETCDATAARRAY *) MapViewOfFile(
  719. hSharedMemory,
  720. FILE_MAP_WRITE,
  721. 0, // High-order 32 bits of file offset
  722. 0, // Low-order 32 bits of file offset
  723. 0); // Number of bytes to map; 0 means all.
  724. // Could we map the memory?
  725. if (pFormatEtcDataArray == NULL)
  726. {
  727. goto errRtn;
  728. }
  729. // We can initialize the size of the array now.
  730. pFormatEtcDataArray->_dwSig = 0;
  731. pFormatEtcDataArray->_dwSize = dwSize;
  732. pFormatEtcDataArray->_cFormats = cFormatEtc;
  733. pFormatEtcDataArray->_cRefs = 1;
  734. pFormatEtcDataArray->_fIs64BitArray = IS_WIN64;
  735. //
  736. // Copy the formats into the shared memory
  737. //
  738. // Get back to the start of the enumeration
  739. penum->Reset();
  740. // This is the pointer to where we will copy the data from the
  741. // enumeration.
  742. pFormatEtcData = &pFormatEtcDataArray->_FormatEtcData[0];
  743. // put DvTarget past last valid FormatEtc + 1 to handle S_FALSE enumerator case.
  744. pbDvTarget = (BYTE *) (&pFormatEtcDataArray->_FormatEtcData[cFormatEtc + 1]);
  745. // Loop loading the formats into the shared memory.
  746. while (penum->Next(1,&(pFormatEtcData->_FormatEtc), NULL) != S_FALSE)
  747. {
  748. // Is there a DVTARGETDEVICE?
  749. if (pFormatEtcData->_FormatEtc.ptd != NULL)
  750. {
  751. // Copy the device target data
  752. memcpy(pbDvTarget,pFormatEtcData->_FormatEtc.ptd,(pFormatEtcData->_FormatEtc.ptd)->tdSize);
  753. // Free the target device data
  754. CoTaskMemFree(pFormatEtcData->_FormatEtc.ptd);
  755. // NOTE: For this shared memory structure, we override the
  756. // FORMATETC field so that it is that offset to the DVTARGETDEVICE
  757. // from the beginning of the shared memory rather than a direct
  758. // pointer to the structure. This is because we can't guarantee
  759. // the base of shared memory in different processes.
  760. pFormatEtcData->_FormatEtc.ptd = (DVTARGETDEVICE *)
  761. (pbDvTarget - (BYTE *) pFormatEtcDataArray);
  762. // Bump pointer of where to copy target to next available
  763. // byte for copy.
  764. pbDvTarget += ((DVTARGETDEVICE *) pbDvTarget)->tdSize;
  765. Assert(dwSize >= (DWORD) (pbDvTarget - (BYTE *) pFormatEtcDataArray));
  766. }
  767. // Bug#18669 - if dwAspect was set to NULL the 16 bit dlls would
  768. // set it to content.
  769. if ( (NULL == pFormatEtcData->_FormatEtc.dwAspect) && IsWOWThread() )
  770. {
  771. pFormatEtcData->_FormatEtc.dwAspect = DVASPECT_CONTENT;
  772. pFormatEtcData->_FormatEtc.lindex = -1; // CorelDraw also puts up a lindex of 0
  773. }
  774. // Bump the pointer in the table of FORMATETCs to the next slot
  775. pFormatEtcData++;
  776. }
  777. Assert( dwSize >= (DWORD) ( (BYTE *) pFormatEtcData - (BYTE *) pFormatEtcDataArray));
  778. Assert( dwSize >= (DWORD) ( (BYTE *) pbDvTarget - (BYTE *) pFormatEtcDataArray));
  779. // Successful enumeration always ends with S_FALSE.
  780. if (hr == S_FALSE)
  781. {
  782. goto exitRtn;
  783. }
  784. errRtn:
  785. if (hSharedMemory != NULL)
  786. {
  787. CloseHandle(hSharedMemory);
  788. hSharedMemory = NULL;
  789. }
  790. exitRtn:
  791. if( penum )
  792. {
  793. // HACK ALERT: Do not release the enumerator if the calling application
  794. // was Interleaf 6.0, otherwise they will fault in the release call.
  795. if (!IsTaskName(L"ILEAF6.EXE"))
  796. {
  797. penum->Release();
  798. }
  799. }
  800. if (pFormatEtcDataArray != NULL)
  801. {
  802. // Only remote clients will use this memory so we unmap it
  803. // out of our address space.
  804. UnmapViewOfFile(pFormatEtcDataArray);
  805. }
  806. return hSharedMemory;
  807. }