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.

3808 lines
91 KiB

  1. #define STATIC
  2. //+----------------------------------------------------------------------------
  3. //
  4. // File:
  5. // clipbrd.cpp
  6. //
  7. // Contents:
  8. // OLE2 clipboard handling
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History:
  15. // 24-Jan-94 alexgo first pass at converting to Cairo-style
  16. // memory allocation
  17. // 01/11/94 - alexgo - added VDATEHEAP macro to every function
  18. // 12/31/93 - ChrisWe - fixed string argument to Warn(); did some
  19. // additional cleanup and formatting
  20. // 12/08/93 - ChrisWe - added necessary casts to GlobalLock() calls
  21. // resulting from removing bogus GlobalLock() macros in
  22. // le2int.h
  23. // 12/08/93 - continuing cleanup
  24. // 12/07/93 - ChrisWe - format some functions, free handle on
  25. // error condition (GlobalLock() failure) in MakeObjectLink
  26. // 12/06/93 - ChrisWe - begin file cleanup; use new map_uhw.h to
  27. // avoid bogus unions in Clipboard functions
  28. // 11/28/93 - ChrisWe - make default parameter explicit on
  29. // UtDupGlobal call
  30. // 11/22/93 - ChrisWe - replace overloaded ==, != with
  31. // IsEqualIID and IsEqualCLSID
  32. //
  33. //-----------------------------------------------------------------------------
  34. #include <le2int.h>
  35. #pragma SEG(clipbrd)
  36. #include <map_uhw.h>
  37. #include <create.h>
  38. #include <clipbrd.h>
  39. #include <scode.h>
  40. #include <objerror.h>
  41. #include <reterr.h>
  42. #include <ole1cls.h>
  43. #include <ostm2stg.h>
  44. // REVIEW #include "cmonimp.h" // for CreateOle1FileMoniker()
  45. #ifdef _MAC
  46. # include <string.h>
  47. # pragma segment ClipBrd
  48. // On the Macintosh, the clipboard is always open. We define a macro for
  49. // OpenClipboard that returns TRUE. When this is used for error checking,
  50. // the compiler should optimize away any code that depends on testing this,
  51. // since it is a constant.
  52. # define OpenClipboard(x) TRUE
  53. // On the Macintosh, the clipboard is not closed. To make all code behave
  54. // as if everything is OK, we define a macro for CloseClipboard that returns
  55. // TRUE. When this is used for error checking, the compiler should optimize
  56. // away any code that depends on testing this, since it is a constant.
  57. # define CloseClipboard() TRUE
  58. #endif // _MAC
  59. ASSERTDATA
  60. #ifdef MAC_REVIEW
  61. All code is commented out for MAC currently. It is very Windows
  62. specific, and has to written for MAC.
  63. #endif
  64. // declarations of local functions
  65. //+----------------------------------------------------------------------------
  66. //
  67. // Function:
  68. // wNativeStreamToHandle, static
  69. //
  70. // Synopsis:
  71. // Reads the contents of a length prefixed stream into a piece
  72. // of HGLOBAL memory.
  73. //
  74. // Arguments:
  75. // [pstm] -- pointer to the IStream instance to read material
  76. // from; the stream should be positioned just before
  77. // the length prefix
  78. // [ph] -- pointer to where to return the handle to the allocated
  79. // HGLOBAL.
  80. //
  81. // Returns:
  82. // HRESULT
  83. //
  84. // Notes:
  85. // REVIEW, this looks like something that should be a Ut function
  86. //
  87. // History:
  88. // 12/13/93 - ChrisWe - file inspection and cleanup
  89. //
  90. //-----------------------------------------------------------------------------
  91. STATIC INTERNAL wNativeStreamToHandle(LPSTREAM pstm, LPHANDLE ph);
  92. //+----------------------------------------------------------------------------
  93. //
  94. // Function:
  95. // wStorageToHandle, static
  96. //
  97. // Synopsis:
  98. // Copy an IStorage instance to a (new) handle.
  99. //
  100. // The contents of the IStorage instance are duplicated in
  101. // a new HGLOBAL based IStorage instance, less any
  102. // STREAMTYPE_CACHE streams.
  103. //
  104. // Arguments:
  105. // [pstg] -- pointer to the IStorage instance to copy
  106. // [ph] -- pointer to where to return the new handle.
  107. //
  108. // Returns:
  109. // HRESULT
  110. //
  111. // Notes:
  112. // REVIEW, this looks like something that should be a Ut function
  113. //
  114. // History:
  115. // 12/13/93 - ChrisWe - file inspection and cleanup
  116. //
  117. //-----------------------------------------------------------------------------
  118. STATIC INTERNAL wStorageToHandle(LPSTORAGE pstg, LPHANDLE ph);
  119. //+----------------------------------------------------------------------------
  120. //
  121. // Function:
  122. // wProgIDFromCLSID, static
  123. //
  124. // Synopsis:
  125. // Maps a CLSID to a string program/object name
  126. //
  127. // Maps CLSID_StdOleLink, which is not listed in the registry.
  128. //
  129. // Arguments:
  130. // [clsid] -- the class id to get the program id for
  131. // [psz] -- pointer to where to return the pointer to the newly
  132. // allocated string
  133. //
  134. // Returns:
  135. // HRESULT
  136. //
  137. // Notes:
  138. //
  139. // History:
  140. // 12/13/93 - ChrisWe - file inspection and cleanup
  141. //
  142. //-----------------------------------------------------------------------------
  143. FARINTERNAL wProgIDFromCLSID(REFCLSID clsid, LPOLESTR FAR* psz);
  144. //+----------------------------------------------------------------------------
  145. //
  146. // Function:
  147. // CreateObjectDescriptor, static
  148. //
  149. // Synopsis:
  150. // Creates and initializes an OBJECTDESCRIPTOR from the given
  151. // parameters
  152. //
  153. // Arguments:
  154. // [clsid] -- the class ID of the object being transferred
  155. // [dwAspect] -- the display aspect drawn by the source of the
  156. // transfer
  157. // [psizel] -- pointer to the size of the object
  158. // [ppointl] -- pointer to the mouse offset in the object that
  159. // initiated a drag-drop transfer
  160. // [dwStatus] -- the OLEMISC status flags for the object
  161. // being transferred
  162. // [lpszFullUserTypeName] -- the full user type name of the
  163. // object being transferred
  164. // [lpszSrcOfCopy] -- a human readable name for the object
  165. // being transferred
  166. //
  167. // Returns:
  168. // If successful, A handle to the new OBJECTDESCRIPTOR; otherwise
  169. // NULL.
  170. //
  171. // Notes:
  172. // REVIEW, this seems generally useful for anyone using the
  173. // clipboard, or drag-drop; perhaps it should be exported.
  174. //
  175. // History:
  176. // 12/07/93 - ChrisWe - file inspection and cleanup
  177. //
  178. //-----------------------------------------------------------------------------
  179. STATIC INTERNAL_(HGLOBAL) CreateObjectDescriptor(CLSID clsid, DWORD dwAspect,
  180. const SIZEL FAR *psizel, const POINTL FAR *ppointl,
  181. DWORD dwStatus, LPOLESTR lpszFullUserTypeName,
  182. LPOLESTR lpszSrcOfCopy);
  183. // $$$
  184. STATIC INTERNAL_(void) RemoveClipDataObject(void);
  185. // REVIEW, is this local, redeclaration, or what?
  186. // Worker routine for CClipDataObject::GetData() below
  187. // NOTE: may be called with pmedium of NULL (even though this is not legal).
  188. // NOTE: also may be called with
  189. //
  190. // $$$
  191. STATIC HRESULT GetOle2Format(LPFORMATETC pforetc, LPSTGMEDIUM pmedium);
  192. // $$$
  193. STATIC INTERNAL ObjectLinkToMonikerStream(LPOLESTR grszFileItem, DWORD cbFile,
  194. REFCLSID clsid, LPSTREAM pstm);
  195. //+----------------------------------------------------------------------------
  196. //
  197. // Function:
  198. // IsNetDDEObjectLink, static
  199. //
  200. // Synopsis:
  201. // Determines if the cfObjectLink object on the clipboard
  202. // refers to a network file (one prefixed with \\server\share...)
  203. //
  204. // Effects:
  205. //
  206. // Arguments:
  207. // [fMustOpen] -- Indicates that the clipboard must be opened
  208. // before retrieving the cfObjectLink data format. If
  209. // the clipboard is already open, it is left that way.
  210. //
  211. // Returns:
  212. // TRUE, if the cfObjectLink data item is a network file,
  213. // FALSE otherwise
  214. //
  215. // Notes:
  216. // REVIEW, what is this about: This returns TRUE if it can't
  217. // open the clipboard, with a comment to the effect that this
  218. // will cause a failure.
  219. //
  220. // History:
  221. // 01/04/94 - ChrisWe - formatting
  222. //
  223. //-----------------------------------------------------------------------------
  224. STATIC FARINTERNAL_(BOOL) IsNetDDEObjectLink(BOOL fMustOpen);
  225. // $$$
  226. STATIC INTERNAL_(BOOL) OrderingIs(const CLIPFORMAT cf1, const CLIPFORMAT cf2);
  227. //+----------------------------------------------------------------------------
  228. //
  229. // Function:
  230. // wOwnerLinkClassIsStdOleLink, static
  231. //
  232. // Synopsis:
  233. // Checks to see that the clipboard format registered as
  234. // cfOwnerLink is actually the standard Ole Link.
  235. //
  236. // Arguments:
  237. // [fOpenClipbrd] -- If true, signifies that the clipboard
  238. // is must be opened--it isn't already open. If it is
  239. // already open, it is left open.
  240. //
  241. // Returns:
  242. // TRUE if cfOwnerLink is actually the standard OLE link,
  243. // FALSE otherwise.
  244. //
  245. // Notes:
  246. //
  247. // History:
  248. // 01/04/93 - ChrisWe - formatted
  249. //
  250. //-----------------------------------------------------------------------------
  251. STATIC INTERNAL_(BOOL) wOwnerLinkClassIsStdOleLink(BOOL fOpenClipbrd);
  252. STATIC INTERNAL_(BOOL) wEmptyClipboard(void);
  253. STATIC const OLECHAR szStdOleLink[] = OLESTR("OLE2Link");
  254. STATIC const OLECHAR szClipboardWndClass[] = OLESTR("CLIPBOARDWNDCLASS");
  255. // DataObject 'posted' on clipboard
  256. //
  257. // pClipDataObj assumed to be valid in the context of the
  258. // process that owns the clipboard.
  259. //
  260. // pClipDataObj == NULL => GetClipboardData(cfDataObject) == NULL
  261. // => hClipDataObj == NULL
  262. //
  263. // To enable delayed marshalling of ClipDataObj must keep the pointer
  264. // in a global variable: initially SetClipboardData(cfDataObject, NULL);
  265. // marshal ClipDataObj only when GetClipboardData(cfDataObject) is called
  266. //
  267. STATIC LPDATAOBJECT pClipDataObj = NULL; // Pointer to the object
  268. // This always corresponds to what is on the clipboard as cfDataObject format
  269. // May be NULL, indicating either that cfDataObject is on clipboard but not
  270. // rendered. or cfDataObject is not on clipboard.
  271. STATIC HANDLE hClipDataObj = NULL;
  272. STATIC INTERNAL MakeObjectLink(LPDATAOBJECT pDataObj, LPSTREAM pStream,
  273. LPHANDLE ph, BOOL fOwnerLink/*= FALSE*/);
  274. STATIC INTERNAL GetClassFromDescriptor(LPDATAOBJECT pDataObj, LPCLSID pclsid,
  275. BOOL fLink, BOOL fUser, LPOLESTR FAR* pszSrcOfCopy);
  276. //+----------------------------------------------------------------------------
  277. //
  278. // Class:
  279. // CClipEnumFormatEtc
  280. //
  281. // Purpose:
  282. // Provides an enumerator for the data object CClipDataObject
  283. //
  284. // Interface:
  285. // IEnumFORMATETC
  286. // CClipEnumFormatEtc
  287. // constructor - this creates an instance that is
  288. // nearly ready to use; the created instance must still
  289. // be Init()ed before use, or have it's internal members
  290. // (except for the reference count) copied from an
  291. // existing enumerator, as in a clone operation.
  292. // Init
  293. // Initializes the enumerator to be at the beginning in
  294. // its scan state.
  295. //
  296. // Notes:
  297. //
  298. // History:
  299. // 12/10/93 - ChrisWe - file inspection and cleanup
  300. //
  301. //-----------------------------------------------------------------------------
  302. class FAR CClipEnumFormatEtc : public IEnumFORMATETC, public CPrivAlloc
  303. {
  304. public:
  305. // IUnknown methods
  306. STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPLPVOID ppvObj);
  307. STDMETHOD_(ULONG,AddRef)(THIS);
  308. STDMETHOD_(ULONG,Release)(THIS);
  309. // IEnumFORMATETC methods
  310. STDMETHOD(Next)(THIS_ ULONG celt, FORMATETC FAR * rgelt,
  311. ULONG FAR* pceltFetched);
  312. STDMETHOD(Skip)(THIS_ ULONG celt);
  313. STDMETHOD(Reset)(THIS);
  314. STDMETHOD(Clone)(THIS_ IEnumFORMATETC FAR* FAR* ppenum);
  315. // constructor
  316. CClipEnumFormatEtc();
  317. // initializer
  318. void Init(void);
  319. private:
  320. INTERNAL NextOne(FORMATETC FAR* pforetc);
  321. ULONG m_refs; // reference count
  322. CLIPFORMAT m_cfCurrent; // the last returned format on the clipboard
  323. CLIPFORMAT m_cfForceNext; // if non-0, the next format to be enumerated
  324. unsigned m_uFlag;
  325. #define CLIPENUMF_LINKSOURCEAVAILABLE 0x0001
  326. /* is cfObjectLink somewhere on the clipboard? */
  327. #define CLIPENUMF_DONE 0x0002 /* forces enumerator to stop */
  328. SET_A5;
  329. };
  330. // $$$
  331. #pragma SEG(OleSetClipboard)
  332. STDAPI OleSetClipboard(LPDATAOBJECT pDataObj)
  333. {
  334. VDATEHEAP();
  335. if (pDataObj)
  336. VDATEIFACE(pDataObj);
  337. if (!OpenClipboard(GetClipboardWindow()))
  338. return(ReportResult(0, CLIPBRD_E_CANT_OPEN, 0, 0));
  339. #ifndef _MAC
  340. if (!wEmptyClipboard())
  341. {
  342. // Also will clear pClipDaObj
  343. Verify(CloseClipboard());
  344. return(ReportResult(0, CLIPBRD_E_CANT_EMPTY, 0, 0));
  345. }
  346. #endif // _MAC
  347. // Save both pointer to the object
  348. pClipDataObj = pDataObj;
  349. if (pDataObj != NULL)
  350. {
  351. pClipDataObj->AddRef();
  352. // Post required clipboard formats
  353. //
  354. // "..., which makes the passed IDataObject accessible
  355. // from the clipboard"
  356. //
  357. // Delay marshalling until needed by passing NULL handle
  358. SetClipboardData(cfDataObject, NULL);
  359. // REVIEW, what if this wasn't NULL before? Did we just
  360. // drop a handle on the floor?
  361. hClipDataObj = NULL;
  362. SetOle1ClipboardFormats(pDataObj);
  363. }
  364. return(CloseClipboard() ? NOERROR :
  365. ResultFromScode(CLIPBRD_E_CANT_CLOSE));
  366. }
  367. #pragma SEG(OleGetClipboard)
  368. STDAPI OleGetClipboard(LPDATAOBJECT FAR* ppDataObj)
  369. {
  370. VDATEHEAP();
  371. HRESULT hresult;
  372. HANDLE hMem;
  373. BOOL fOpen;
  374. IStream FAR* pStm;
  375. // validate the output parameter
  376. VDATEPTROUT(ppDataObj, LPDATAOBJECT);
  377. // initialize this for error returns
  378. *ppDataObj = NULL;
  379. if (!(fOpen = OpenClipboard(GetClipboardWindow())))
  380. {
  381. // REVIEW - clipboard opened by caller
  382. // If clipboard opended by this task (thread)
  383. // it won't change during this call
  384. if (GetWindowThreadProcessId(GetOpenClipboardWindow(),NULL) !=
  385. GetCurrentThreadId())
  386. {
  387. // spec says return S_FALSE if someone else owns
  388. // clipboard
  389. return(ReportResult(0, S_FALSE, 0, 0));
  390. }
  391. }
  392. if (pClipDataObj == NULL)
  393. hresult = CreateClipboardDataObject(ppDataObj);
  394. else // not the fake data object
  395. {
  396. // try to get a data object off the clipboard
  397. hMem = GetClipboardData(cfDataObject);
  398. if (hMem == NULL)
  399. {
  400. hresult = ReportResult(0, CLIPBRD_E_BAD_DATA, 0, 0);
  401. goto Exit;
  402. }
  403. // "..., which makes the passed IDataObject accessible
  404. // from the clipboard"
  405. //
  406. // Create shared memory stream on top of clipboard data.
  407. // UnMarshal object's interface
  408. pStm = CloneMemStm(hMem);
  409. if (pStm == NULL)
  410. {
  411. hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  412. goto Exit;
  413. }
  414. hresult = CoUnmarshalInterface(pStm, IID_IDataObject,
  415. (LPLPVOID)ppDataObj);
  416. pStm->Release();
  417. if (GetScode(hresult) == RPC_E_CANTPOST_INSENDCALL)
  418. {
  419. // This happens when inplace object gets WM_INITMENU,
  420. // and it is trying to Get the clipboard object, to
  421. // decide whether to enable Paste and PasteLink menus.
  422. // For this case we can create the fake data object
  423. // and return the pointer to it.
  424. hresult = CreateClipboardDataObject(ppDataObj);
  425. }
  426. }
  427. if (hresult != NOERROR)
  428. *ppDataObj = NULL;
  429. Exit:
  430. #ifdef MAC_REVIEW
  431. Does mac have to trash the hMem handle, ericoe
  432. #endif
  433. if (fOpen && !CloseClipboard())
  434. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  435. return(hresult);
  436. }
  437. // OleFlushClipboard
  438. //
  439. // Remove the DataObject from the clipboard, but leave hGlobal-based formats
  440. // including OLE1 formats on the clipboard (for use after the server app
  441. // exits).
  442. //
  443. #pragma SEG(OleFlushClipboard)
  444. STDAPI OleFlushClipboard(void)
  445. {
  446. VDATEHEAP();
  447. HWND hwnd;
  448. BOOL fOpen;
  449. CLIPFORMAT cf = 0;
  450. HRESULT hresult = NOERROR;
  451. hwnd = GetClipboardWindow();
  452. if (hwnd == GetClipboardOwner()) // Caller owns the clipboard
  453. {
  454. fOpen = OpenClipboard(hwnd);
  455. ErrZS(fOpen, CLIPBRD_E_CANT_OPEN);
  456. // Make sure all formats are rendered
  457. while (cf = EnumClipboardFormats(cf)) // not ==
  458. {
  459. if (cf != cfDataObject)
  460. GetClipboardData(cf); // ignore return value
  461. }
  462. // this does OleSetClipboard(cfDataObject, NULL)
  463. RemoveClipDataObject();
  464. errRtn:
  465. if (fOpen && !CloseClipboard())
  466. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  467. }
  468. return(hresult);
  469. }
  470. #pragma SEG(OleIsCurrentClipboard)
  471. STDAPI OleIsCurrentClipboard(LPDATAOBJECT pDataObj)
  472. {
  473. VDATEHEAP();
  474. HWND hwnd;
  475. // validate parameters
  476. VDATEIFACE(pDataObj);
  477. hwnd = GetClipboardWindow();
  478. if (hwnd == GetClipboardOwner())
  479. {
  480. // Caller owns the clipboard, pClipDataObj valid in caller's
  481. // address space
  482. return(ReportResult(0, ((pClipDataObj == pDataObj) ? S_OK :
  483. S_FALSE), 0, 0));
  484. }
  485. // someone else owns the clipboard
  486. return(ResultFromScode(S_FALSE));
  487. }
  488. // Implementation of fake clipboard data object
  489. //+----------------------------------------------------------------------------
  490. //
  491. // Member:
  492. // CClipDataObject::QueryInterface, public
  493. //
  494. // Synopsis:
  495. // implements IUnknown::QueryInterface
  496. //
  497. // Arguments:
  498. // [riid] -- the IID of the desired interface
  499. // [ppv] -- pointer to where to return the requested interface
  500. // pointer
  501. //
  502. // Returns:
  503. // E_NOINTERFACE, S_OK
  504. //
  505. // History:
  506. // 12/06/93 - ChrisWe - file inspection and cleanup
  507. //
  508. //-----------------------------------------------------------------------------
  509. #pragma SEG(CClipDataObject_QueryInterface)
  510. STDMETHODIMP CClipDataObject::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  511. {
  512. VDATEHEAP();
  513. HRESULT hresult;
  514. M_PROLOG(this);
  515. // initialize this for error return
  516. *ppvObj = NULL;
  517. // validate parameters
  518. VDATEPTROUT(ppvObj, LPVOID);
  519. VDATEIID(riid);
  520. if (IsEqualIID(riid, IID_IDataObject) ||
  521. IsEqualIID(riid, IID_IUnknown))
  522. {
  523. AddRef(); // A pointer to this object is returned
  524. *ppvObj = (void FAR *)(IDataObject FAR *)this;
  525. hresult = NOERROR;
  526. }
  527. else
  528. {
  529. // Not accessible or unsupported interface
  530. hresult = ReportResult(0, E_NOINTERFACE, 0, 0);
  531. }
  532. return hresult;
  533. }
  534. //+----------------------------------------------------------------------------
  535. //
  536. // Member:
  537. // CClipDataObject::AddRef, public
  538. //
  539. // Synopsis:
  540. // implements IUnknown::AddRef
  541. //
  542. // Arguments:
  543. // none
  544. //
  545. // Returns:
  546. // The new reference count of the object
  547. //
  548. // History:
  549. // 12/06/93 - ChrisWe - file inspection
  550. //
  551. //-----------------------------------------------------------------------------
  552. #pragma SEG(CClipDataObject_AddRef)
  553. STDMETHODIMP_(ULONG) CClipDataObject::AddRef(void)
  554. {
  555. VDATEHEAP();
  556. M_PROLOG(this);
  557. return(++m_refs);
  558. }
  559. //+----------------------------------------------------------------------------
  560. //
  561. // Member:
  562. // CClipDataObject::Release, internal
  563. //
  564. // Synopsis:
  565. // Decrements the reference count of the object, freeing it
  566. // if the last reference has gone away
  567. //
  568. // Arguments:
  569. // none
  570. //
  571. // Returns:
  572. // The new reference count of the object.
  573. //
  574. // History:
  575. // 12/06/93 - ChrisWe - file inspection and cleanup
  576. //
  577. //-----------------------------------------------------------------------------
  578. #pragma SEG(CClipDataObject_Release)
  579. STDMETHODIMP_(ULONG) CClipDataObject::Release(void)
  580. {
  581. VDATEHEAP();
  582. M_PROLOG(this);
  583. if (--m_refs != 0) // Still used by others
  584. return(m_refs);
  585. delete this; // Free storage
  586. return(0);
  587. }
  588. //+----------------------------------------------------------------------------
  589. //
  590. // Member:
  591. // CClipDataObject::GetData, public
  592. //
  593. // Synopsis:
  594. // implements IDataObject::GetData
  595. //
  596. // Retrieves data from the system clipboard, if data is available
  597. // in the requested format
  598. //
  599. // Arguments:
  600. // [pformatetcIn] -- the desired format to retrieve the data in
  601. // [pmedium] -- the medium the data will be retrieved in
  602. //
  603. // Returns:
  604. // HRESULT
  605. //
  606. // Notes:
  607. //
  608. // History:
  609. // 12/06/93 - ChrisWe - file inspection and cleanup
  610. //
  611. //-----------------------------------------------------------------------------
  612. #pragma SEG(CClipDataObject_GetData)
  613. STDMETHODIMP CClipDataObject::GetData(LPFORMATETC pformatetcIn,
  614. LPSTGMEDIUM pmedium)
  615. {
  616. VDATEHEAP();
  617. M_PROLOG(this);
  618. // validate parameters
  619. VDATEPTRIN(pformatetcIn, FORMATETC);
  620. VDATEPTROUT(pmedium, STGMEDIUM);
  621. pmedium->tymed = TYMED_NULL;
  622. pmedium->pUnkForRelease = NULL;
  623. // REVIEW, what result does this have?
  624. return(GetDataHere(pformatetcIn, pmedium));
  625. }
  626. //+----------------------------------------------------------------------------
  627. //
  628. // Function:
  629. // CClipDataObject::GetDataHere, internal
  630. //
  631. // Synopsis:
  632. // implements IDataObject::GetDataHere
  633. //
  634. // Retrieves the requested data from the clipboard, if possible.
  635. //
  636. // Arguments:
  637. // [pformatetcIn] -- the format the requestor would like
  638. // [pmedium] -- the medium the requestor would like the
  639. // data returned on
  640. // REVIEW, this doesn't seem to be used in the expected
  641. // way here.
  642. //
  643. // Returns:
  644. // HRESULT
  645. //
  646. // Notes:
  647. // This is written to accept a NULL [pmedium] so that it can be
  648. // used to do the work for QueryGetData(). In that case
  649. // it just asks the clipboard with IsClipboardFormatAvailable().
  650. //
  651. // History:
  652. // 12/06/93 - ChrisWe - file inspection and cleanup
  653. //
  654. //-----------------------------------------------------------------------------
  655. #pragma SEG(CClipDataObject_GetDataHere)
  656. STDMETHODIMP CClipDataObject::GetDataHere(LPFORMATETC pformatetcIn,
  657. LPSTGMEDIUM pmedium)
  658. {
  659. VDATEHEAP();
  660. HANDLE hData;
  661. CLIPFORMAT cf;
  662. DWORD tymed;
  663. M_PROLOG(this);
  664. // validate parameters
  665. if (pmedium)
  666. VDATEPTROUT(pmedium, STGMEDIUM);
  667. VDATEPTRIN(pformatetcIn, FORMATETC);
  668. VERIFY_LINDEX(pformatetcIn->lindex);
  669. if (pformatetcIn->ptd != NULL)
  670. return(ReportResult(0, DV_E_DVTARGETDEVICE, 0, 0));
  671. if (pformatetcIn->dwAspect
  672. && !(pformatetcIn->dwAspect & DVASPECT_CONTENT))
  673. return(ReportResult(0, DV_E_DVASPECT, 0, 0));
  674. cf = pformatetcIn->cfFormat;
  675. tymed = pformatetcIn->tymed;
  676. if (cf == cfEmbeddedObject || cf == cfEmbedSource ||
  677. cf == cfLinkSource || (cf == cfLinkSrcDescriptor &&
  678. !IsClipboardFormatAvailable(cfLinkSrcDescriptor))
  679. || (cf == cfObjectDescriptor &&
  680. !IsClipboardFormatAvailable(cfObjectDescriptor)))
  681. {
  682. return(GetOle2Format(pformatetcIn, pmedium));
  683. }
  684. //
  685. // REVIEW: probably should be able to return data in any of flat
  686. // mediums. For now only return hglobal.
  687. //
  688. if (((cf == CF_BITMAP) || (cf == CF_PALETTE)) && (tymed & TYMED_GDI))
  689. tymed = TYMED_GDI;
  690. else if ((cf == CF_METAFILEPICT) && (tymed & TYMED_MFPICT))
  691. tymed = TYMED_MFPICT;
  692. else if (tymed & TYMED_HGLOBAL)
  693. tymed = TYMED_HGLOBAL;
  694. else
  695. return(ReportResult(0, DV_E_TYMED, 0, 0));
  696. if (pmedium == NULL)
  697. return(IsClipboardFormatAvailable(cf) ? NOERROR :
  698. ReportResult(0, DV_E_CLIPFORMAT, 0, 0));
  699. // initialize for error return case
  700. pmedium->pUnkForRelease = NULL;
  701. pmedium->hGlobal = NULL;
  702. // We just want to take the clipboard data and pass it on. We don't
  703. // want to get into the business of copying the data
  704. if (pmedium->tymed != TYMED_NULL)
  705. return(ReportResult(0, E_NOTIMPL, 0, 0));
  706. if (!OpenClipboard(GetClipboardWindow()))
  707. return(ReportResult(0, CLIPBRD_E_CANT_OPEN, 0, 0));
  708. hData = GetClipboardData(cf);
  709. if (hData == NULL)
  710. {
  711. Verify(CloseClipboard());
  712. return(ReportResult(0, DV_E_CLIPFORMAT, 0, 0));
  713. }
  714. pmedium->tymed = tymed;
  715. pmedium->hGlobal = OleDuplicateData(hData, cf, GMEM_MOVEABLE);
  716. return(CloseClipboard() ? NOERROR :
  717. ResultFromScode(CLIPBRD_E_CANT_CLOSE));
  718. }
  719. //+----------------------------------------------------------------------------
  720. //
  721. // Member:
  722. // CClipDataObject::QueryGetData, internal
  723. //
  724. // Synopsis:
  725. // implements IDataObject::QueryGetData
  726. //
  727. // determines if the requested data can be fetched
  728. //
  729. // Arguments:
  730. // [pformatetcIn] -- checks to see if this format is available
  731. //
  732. // Returns:
  733. //
  734. // Notes:
  735. //
  736. // History:
  737. // 12/06/93 - ChrisWe - file inspection and cleanup
  738. //
  739. //-----------------------------------------------------------------------------
  740. #pragma SEG(CClipDataObject_QueryGetData)
  741. STDMETHODIMP CClipDataObject::QueryGetData(LPFORMATETC pformatetcIn)
  742. {
  743. VDATEHEAP();
  744. M_PROLOG(this);
  745. return(NOERROR == GetDataHere(pformatetcIn, NULL) ? NOERROR :
  746. ResultFromScode(S_FALSE));
  747. }
  748. //+----------------------------------------------------------------------------
  749. //
  750. // Member:
  751. // CClipDataObject::GetCanonicalFormatEtc, public
  752. //
  753. // Synopsis:
  754. // implements IDataObject::GetCanonicalFormatEtc
  755. //
  756. // Arguments:
  757. // [pformatetc] -- the format for which we'd like a base
  758. // equivalence class
  759. // [pformatetcOut] -- the equivalence class
  760. //
  761. // Returns:
  762. // S_OK
  763. //
  764. // Notes:
  765. //
  766. // History:
  767. // 12/06/93 - ChrisWe - file inspection and cleanup
  768. //
  769. //-----------------------------------------------------------------------------
  770. #pragma SEG(CClipDataObject_GetCanonicalFormatEtc)
  771. STDMETHODIMP CClipDataObject::GetCanonicalFormatEtc(LPFORMATETC pformatetc,
  772. LPFORMATETC pformatetcOut)
  773. {
  774. VDATEHEAP();
  775. M_PROLOG(this);
  776. // validate parameters
  777. VDATEPTRIN(pformatetc, FORMATETC);
  778. VDATEPTROUT(pformatetcOut, FORMATETC);
  779. VERIFY_LINDEX(pformatetc->lindex);
  780. // set return values
  781. INIT_FORETC(*pformatetcOut);
  782. pformatetcOut->cfFormat = pformatetc->cfFormat;
  783. // Handle cfEmbeddedObject, cfEmbedSource, cfLinkSource
  784. // REVIEW, this must be a reference to the fact that UtFormatToTymed
  785. // only currently (12/06/93) returns anything explicit for
  786. // CF_METAFILEPICT, CF_PALETTE, and CF_BITMAP. For anything else
  787. // it returns TYMED_HGLOBAL. I don't know what the correct
  788. // values should be for the above mentioned items....
  789. pformatetcOut->tymed = UtFormatToTymed(pformatetc->cfFormat);
  790. return(NOERROR);
  791. }
  792. //+----------------------------------------------------------------------------
  793. //
  794. // Member:
  795. // CClipDataObject::SetData, public
  796. //
  797. // Synopsis:
  798. // implements IDataObject::SetData
  799. //
  800. // Arguments:
  801. // [pformatetc] -- the format the data is in
  802. // [pmedium] -- the storage medium the data is in
  803. // [fRelease] -- indicates that the callee should release
  804. // the storage medium when it is done with it
  805. //
  806. // Returns:
  807. // E_NOTIMPL
  808. //
  809. // Notes:
  810. // It is not allowed to set things on the clipboard
  811. // with this. Technically, it would be possible to do. Would
  812. // it be useful to implement this so that it worked? Would we
  813. // be able to release the storage medium correctly?
  814. // REVIEW, if we're not going to allow it, shouldn't we have
  815. // a better error message than E_NOTIMPL? That seems to indicate
  816. // brokenness, rather than planned decision....
  817. //
  818. // History:
  819. // 12/06/93 - ChrisWe - file inspection and cleanup
  820. //
  821. //-----------------------------------------------------------------------------
  822. #pragma SEG(CClipDataObject_SetData)
  823. STDMETHODIMP CClipDataObject::SetData(LPFORMATETC pformatetc,
  824. STGMEDIUM FAR* pmedium, BOOL fRelease)
  825. {
  826. VDATEHEAP();
  827. M_PROLOG(this);
  828. return(ReportResult(0, E_NOTIMPL, 0, 0));
  829. }
  830. //+----------------------------------------------------------------------------
  831. //
  832. // Member:
  833. // CClipDataObject::EnumFormatEtc, public
  834. //
  835. // Synopsis:
  836. // implements IDataObject::EnumFormatEtc
  837. //
  838. // Arguments:
  839. // [dwDirection] -- flags from DATADIR_*
  840. // [ppenumFormatEtc] -- pointer to where to return the enumerator
  841. //
  842. // Returns:
  843. // E_OUTOFMEMORY, S_OK
  844. //
  845. // Notes:
  846. //
  847. // History:
  848. // 12/08/93 - ChrisWe - file inspection and cleanup
  849. //
  850. //-----------------------------------------------------------------------------
  851. #pragma SEG(CClipDataObject_EnumFormatEtc)
  852. STDMETHODIMP CClipDataObject::EnumFormatEtc(DWORD dwDirection,
  853. LPENUMFORMATETC FAR* ppenumFormatEtc)
  854. {
  855. VDATEHEAP();
  856. HRESULT hresult = NOERROR;
  857. CClipEnumFormatEtc *pCCEFE; // the newly created enumerator
  858. A5_PROLOG(this);
  859. // validate parameters
  860. VDATEPTROUT(ppenumFormatEtc, LPENUMFORMATETC);
  861. // initialize this for error returns
  862. *ppenumFormatEtc = NULL;
  863. // REVIEW, a user could potentially be very confused by this,
  864. // since DATADIR_SET is a valid argument. Perhaps it would be
  865. // better to return an empty enumerator, OR, create a new error
  866. // code for this condition?
  867. if (dwDirection != DATADIR_GET)
  868. return(ResultFromScode(E_NOTIMPL));
  869. // open the clipboard, so we can enumerate the available formats
  870. // REVIEW, I believe the enumerator repeatedly does this, so
  871. // why Open and Close the clipboard here?
  872. if (!OpenClipboard(GetClipboardWindow()))
  873. {
  874. AssertSz(0,"EnumFormatEtc cannont OpenClipboard");
  875. return(ReportResult(0, CLIPBRD_E_CANT_OPEN, 0, 0));
  876. }
  877. // allocate the enumerator
  878. pCCEFE = new CClipEnumFormatEtc;
  879. if (pCCEFE == NULL)
  880. hresult = ResultFromScode(E_OUTOFMEMORY);
  881. // initialize the enumerator, and prepare to return it
  882. pCCEFE->Init();
  883. *ppenumFormatEtc = (IEnumFORMATETC FAR *)pCCEFE;
  884. if (!CloseClipboard())
  885. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  886. RESTORE_A5();
  887. return(hresult);
  888. }
  889. //+----------------------------------------------------------------------------
  890. //
  891. // Member:
  892. // CClipDataObject::DAdvise, public
  893. //
  894. // Synopsis:
  895. // implements IDataObject::DAdvise
  896. //
  897. // Arguments:
  898. // [pFormatetc] -- the format we are interested in being
  899. // advised of changes to
  900. // [advf] -- the advise control flags, from ADVF_*
  901. // [pAdvSink] -- pointer to the advise sink to use for
  902. // notifications
  903. // [pdwConnection] -- pointer to a DWORD where DAdvise() can
  904. // return a token that identifies this advise connection
  905. //
  906. // Returns:
  907. // E_NOTIMPL
  908. //
  909. // Notes:
  910. //
  911. // History:
  912. // 12/08/93 - ChrisWe - file inspection and cleanup
  913. //
  914. //-----------------------------------------------------------------------------
  915. #pragma SEG(CClipDataObject_DAdvise)
  916. STDMETHODIMP CClipDataObject::DAdvise(FORMATETC FAR* pFormatetc, DWORD advf,
  917. IAdviseSink FAR* pAdvSink, DWORD FAR* pdwConnection)
  918. {
  919. VDATEHEAP();
  920. M_PROLOG(this);
  921. VDATEPTROUT(pdwConnection, DWORD);
  922. *pdwConnection = 0;
  923. return(ReportResult(0, E_NOTIMPL, 0, 0));
  924. }
  925. //+----------------------------------------------------------------------------
  926. //
  927. // Member:
  928. // CClipDataObject::DUnadvise, public
  929. //
  930. // Synopsis:
  931. // implements IDataObject::Dunadvise
  932. //
  933. // Arguments:
  934. // [dwConnection] -- a connection identification token, as
  935. // returned by DAdvise()
  936. //
  937. // Returns:
  938. // E_NOTIMPL
  939. //
  940. // Notes:
  941. //
  942. // History:
  943. // 12/08/93 - ChrisWe - file inspection and cleanup
  944. //
  945. //-----------------------------------------------------------------------------
  946. #pragma SEG(CClipDataObject_DUnadvise)
  947. STDMETHODIMP CClipDataObject::DUnadvise(DWORD dwConnection)
  948. {
  949. VDATEHEAP();
  950. M_PROLOG(this);
  951. return(ReportResult(0, E_NOTIMPL, 0, 0));
  952. }
  953. //+----------------------------------------------------------------------------
  954. //
  955. // Member:
  956. // CClipDataObject::EnumDAdvise, public
  957. //
  958. // Synopsis:
  959. // implements IDataObject::EnumDAdvise
  960. //
  961. // Arguments:
  962. // [ppenumAdvise] -- pointer to where to return the enumerator
  963. //
  964. // Returns:
  965. // E_NOTIMPL
  966. //
  967. // Notes:
  968. //
  969. // History:
  970. // 12/08/93 - ChrisWe - file inspection and cleanup
  971. //
  972. //-----------------------------------------------------------------------------
  973. #pragma SEG(CClipDataObject_EnumDAdvise)
  974. STDMETHODIMP CClipDataObject::EnumDAdvise(LPENUMSTATDATA FAR* ppenumAdvise)
  975. {
  976. VDATEHEAP();
  977. M_PROLOG(this);
  978. VDATEPTROUT(ppenumAdvise, LPENUMSTATDATA FAR*);
  979. *ppenumAdvise = NULL;
  980. return(ReportResult(0, E_NOTIMPL, 0, 0));
  981. }
  982. //+----------------------------------------------------------------------------
  983. //
  984. // Member:
  985. // CClipDataObject::CClipDataObject, public
  986. //
  987. // Synopsis:
  988. // constructor
  989. //
  990. // Arguments:
  991. // none
  992. //
  993. // Notes:
  994. // returns with reference count set to 1
  995. //
  996. // History:
  997. // 12/08/93 - ChrisWe - created
  998. //
  999. //-----------------------------------------------------------------------------
  1000. CClipDataObject::CClipDataObject()
  1001. {
  1002. VDATEHEAP();
  1003. m_refs = 1;
  1004. }
  1005. //+----------------------------------------------------------------------------
  1006. //
  1007. // Function:
  1008. // CreateClipboardDataObject, internal
  1009. //
  1010. // Synopsis:
  1011. // Creates an instance of CClipDataObject, manifested as
  1012. // an IDataObject.
  1013. //
  1014. // Arguments:
  1015. // [ppDataObj] -- pointer to where to return the IDataObject
  1016. // instance
  1017. //
  1018. // Returns:
  1019. // OLE_E_BLANK, if there are no registered clipboard formats
  1020. // (and *ppDataObj will be NULL)
  1021. // E_OUTOFMEMORY, S_OK
  1022. //
  1023. // Notes:
  1024. //
  1025. // History:
  1026. // 12/08/93 - ChrisWe - file inspection and cleanup
  1027. //
  1028. //-----------------------------------------------------------------------------
  1029. #pragma SEG(CreateClipboardDataObject)
  1030. INTERNAL CreateClipboardDataObject(LPDATAOBJECT FAR* ppDataObj)
  1031. {
  1032. VDATEHEAP();
  1033. // initialize this for error returns
  1034. *ppDataObj = NULL;
  1035. if (CountClipboardFormats() == 0)
  1036. return(ReportResult(0, OLE_E_BLANK, 0, 0));
  1037. *ppDataObj = new CClipDataObject;
  1038. if (*ppDataObj == NULL)
  1039. return(ReportResult(0, E_OUTOFMEMORY, 0, 0));
  1040. return NOERROR;
  1041. }
  1042. // Implemetation of FORMATETC enumerator for the above fake clipboard data
  1043. // object
  1044. //+----------------------------------------------------------------------------
  1045. //
  1046. // Member:
  1047. // CClipEnumFormatEtc::QueryInterface, public
  1048. //
  1049. // Synopsis:
  1050. // implements IUnknown::QueryInterface
  1051. //
  1052. // Arguments:
  1053. // [riid] -- the IID of the desired interface
  1054. // [ppv] -- pointer to where to return the requested interface
  1055. // pointer
  1056. //
  1057. // Returns:
  1058. // E_NOINTERFACE, S_OK
  1059. //
  1060. // History:
  1061. // 12/06/93 - ChrisWe - file inspection and cleanup
  1062. //
  1063. //-----------------------------------------------------------------------------
  1064. #pragma SEG(CClipEnumFormatEtc_QueryInterface)
  1065. STDMETHODIMP CClipEnumFormatEtc::QueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  1066. {
  1067. VDATEHEAP();
  1068. HRESULT hresult;
  1069. M_PROLOG(this);
  1070. // Two interfaces supported: IUnknown, IEnumFORMATETC
  1071. if (IsEqualIID(riid, IID_IEnumFORMATETC) ||
  1072. IsEqualIID(riid, IID_IUnknown))
  1073. {
  1074. AddRef(); // A pointer to this object is returned
  1075. *ppvObj = (void FAR *)(IEnumFORMATETC FAR *)this;
  1076. hresult = NOERROR;
  1077. }
  1078. else
  1079. {
  1080. // Not accessible or unsupported interface
  1081. *ppvObj = NULL;
  1082. hresult = ReportResult(0, E_NOINTERFACE, 0, 0);
  1083. }
  1084. return hresult;
  1085. }
  1086. //+----------------------------------------------------------------------------
  1087. //
  1088. // Member:
  1089. // CClipEnumFormatEtc::AddRef, public
  1090. //
  1091. // Synopsis:
  1092. // implements IUnknown::AddRef
  1093. //
  1094. // Arguments:
  1095. // none
  1096. //
  1097. // Returns:
  1098. // The new reference count of the object
  1099. //
  1100. // History:
  1101. // 12/06/93 - ChrisWe - file inspection
  1102. //
  1103. //-----------------------------------------------------------------------------
  1104. #pragma SEG(CClipEnumFormatEtc_AddRef)
  1105. STDMETHODIMP_(ULONG) CClipEnumFormatEtc::AddRef(void)
  1106. {
  1107. VDATEHEAP();
  1108. M_PROLOG(this);
  1109. return(++m_refs);
  1110. }
  1111. //+----------------------------------------------------------------------------
  1112. //
  1113. // Member:
  1114. // CClipEnumFormatEtc::Release, internal
  1115. //
  1116. // Synopsis:
  1117. // Decrements the reference count of the object, freeing it
  1118. // if the last reference has gone away
  1119. //
  1120. // Arguments:
  1121. // none
  1122. //
  1123. // Returns:
  1124. // The new reference count of the object.
  1125. //
  1126. // History:
  1127. // 12/06/93 - ChrisWe - file inspection and cleanup
  1128. //
  1129. //-----------------------------------------------------------------------------
  1130. #pragma SEG(CClipEnumFormatEtc_Release)
  1131. STDMETHODIMP_(ULONG) CClipEnumFormatEtc::Release(void)
  1132. {
  1133. VDATEHEAP();
  1134. M_PROLOG(this);
  1135. if (--m_refs != 0) // Still used by others
  1136. return(m_refs);
  1137. delete this; // Free storage
  1138. return(0);
  1139. }
  1140. //+----------------------------------------------------------------------------
  1141. //
  1142. // Member:
  1143. // CClipEnumFormatEtc::Next, public
  1144. //
  1145. // Synopsis:
  1146. // implements IEnumFORMATETC::Next
  1147. //
  1148. // Arguments:
  1149. // [celt] -- the number of elements the caller would like
  1150. // returned
  1151. // [rgelt] -- a pointer to space where the elements may be
  1152. // returned
  1153. // [pceltFetched] -- a pointer to where to return a count of
  1154. // the number of elements fetched; May be NULL.
  1155. //
  1156. // Returns:
  1157. // S_OK if the requested number of items is retrieved, or
  1158. // S_FALSE, if fewer than the requested number is retrieved
  1159. //
  1160. // Notes:
  1161. //
  1162. // History:
  1163. // 12/06/93 - ChrisWe - file inspection and cleanup
  1164. //
  1165. //-----------------------------------------------------------------------------
  1166. #pragma SEG(CClipEnumFormatEtc_Next)
  1167. STDMETHODIMP CClipEnumFormatEtc::Next(ULONG celt, FORMATETC FAR * rgelt,
  1168. ULONG FAR* pceltFetched)
  1169. {
  1170. VDATEHEAP();
  1171. ULONG celtSoFar; // count of elements fetched so far
  1172. ULONG celtDummy; // used to avoid retesting pceltFetched
  1173. // did the caller ask for the number of elements fetched?
  1174. if (pceltFetched != NULL)
  1175. {
  1176. // validate the pointer
  1177. VDATEPTROUT(pceltFetched, ULONG);
  1178. // initialize for error return
  1179. *pceltFetched = 0;
  1180. }
  1181. else
  1182. {
  1183. // point at the dummy so we can assign *pceltFetched w/o test
  1184. pceltFetched = &celtDummy;
  1185. // if pceltFetched == NULL, can only ask for 1 element
  1186. if (celt != 1)
  1187. return(ResultFromScode(E_INVALIDARG));
  1188. }
  1189. // validate parameters
  1190. VDATEPTROUT(rgelt, FORMATETC);
  1191. if (celt != 0)
  1192. VDATEPTROUT(rgelt + celt - 1, FORMATETC);
  1193. // fetch the items
  1194. for(celtSoFar = 0; celtSoFar < celt; ++rgelt, ++celtSoFar)
  1195. {
  1196. if (NextOne(rgelt) != NOERROR)
  1197. break;
  1198. }
  1199. *pceltFetched = celtSoFar;
  1200. return(celtSoFar < celt ? ResultFromScode(S_FALSE) : NOERROR);
  1201. }
  1202. //+----------------------------------------------------------------------------
  1203. //
  1204. // Member:
  1205. // CClipEnumFormatEtc::NextOne, private
  1206. //
  1207. // Synopsis:
  1208. // Workhorse function for CClipEnumFormatEtc::Next(); iterates
  1209. // over the available formats on the clipboard using the
  1210. // appropriate win32s APIs.
  1211. //
  1212. // Arguments:
  1213. // [pforetc] -- pointer to a FORMATETC to fill in with the
  1214. // next format
  1215. //
  1216. // Returns:
  1217. // HRESULT
  1218. //
  1219. // Notes:
  1220. // This skips over cfDataObject, cfObjectLink, and cfOwnerLink.
  1221. // cfObjectLink and cfOwnerLink are returned after all other
  1222. // formats; cfDataObject is not returned at all.
  1223. //
  1224. // History:
  1225. // 01/04/93 - ChrisWe - file inspection and cleanup
  1226. //
  1227. //-----------------------------------------------------------------------------
  1228. #pragma SEG(CClipEnumFormatEtc_NextOne)
  1229. INTERNAL CClipEnumFormatEtc::NextOne(FORMATETC FAR* pforetc)
  1230. {
  1231. VDATEHEAP();
  1232. CLIPFORMAT cfNext;
  1233. HRESULT hresult;
  1234. M_PROLOG(this);
  1235. // Initialize the FORMATETC we're going to fetch into
  1236. INIT_FORETC(*pforetc);
  1237. // is there a CLIPFORMAT that we want to force to be next?
  1238. if (m_cfForceNext != 0)
  1239. {
  1240. // return the format we're forcing to be next
  1241. pforetc->cfFormat = m_cfForceNext;
  1242. pforetc->tymed = UtFormatToTymed(m_cfForceNext);
  1243. // there's no more format to force to be next
  1244. m_cfForceNext = 0;
  1245. return(NOERROR);
  1246. }
  1247. // if the enumerator is done, get out
  1248. if (m_uFlag & CLIPENUMF_DONE)
  1249. return(ResultFromScode(S_FALSE));
  1250. // if we can't open the clipboard, we can't enumerate the formats on it
  1251. if (!OpenClipboard(GetClipboardWindow()))
  1252. {
  1253. AssertSz(0, "CClipEnumFormatEtc::Next cannot OpenClipboard");
  1254. return(ReportResult(0, CLIPBRD_E_CANT_OPEN, 0, 0));
  1255. }
  1256. // error state so far
  1257. hresult = NOERROR;
  1258. // get the next format to be returned by the enumerator
  1259. cfNext = EnumClipboardFormats(m_cfCurrent);
  1260. TryAgain:
  1261. // skip cfDataObject
  1262. if (cfNext == cfDataObject)
  1263. cfNext = EnumClipboardFormats(cfNext);
  1264. if (cfNext == cfObjectLink)
  1265. {
  1266. if (!IsNetDDEObjectLink(FALSE))
  1267. {
  1268. // Hack to make sure CF_LINKSOURCE is last.
  1269. m_uFlag |= CLIPENUMF_LINKSOURCEAVAILABLE;
  1270. }
  1271. // skip cfObjectlink for now
  1272. cfNext = EnumClipboardFormats(cfNext);
  1273. goto TryAgain;
  1274. }
  1275. if (cfNext == cfOwnerLink)
  1276. {
  1277. if (!IsClipboardFormatAvailable(cfNative)
  1278. || OrderingIs(cfOwnerLink, cfNative))
  1279. {
  1280. // This is the case of copying a link object from a
  1281. // 1.0 container EmbeddedObject will need to be
  1282. // generated on request in GetData.
  1283. pforetc->cfFormat = cfEmbeddedObject;
  1284. pforetc->tymed = TYMED_ISTORAGE;
  1285. goto errRtn;
  1286. }
  1287. else
  1288. {
  1289. // skip cfOwnerlink
  1290. cfNext = EnumClipboardFormats(cfNext);
  1291. goto TryAgain;
  1292. }
  1293. }
  1294. // is there nothing more on the clipboard?
  1295. if (cfNext == 0)
  1296. {
  1297. // mark the enumeration as done
  1298. m_uFlag |= CLIPENUMF_DONE;
  1299. if (m_uFlag & CLIPENUMF_LINKSOURCEAVAILABLE)
  1300. {
  1301. // Prevent infinite loop. Return S_FALSE next time.
  1302. cfNext = cfObjectLink;
  1303. }
  1304. else
  1305. {
  1306. hresult = ResultFromScode(S_FALSE);
  1307. goto errRtn;
  1308. }
  1309. }
  1310. if (cfNext == cfNative)
  1311. {
  1312. if (IsClipboardFormatAvailable(cfOwnerLink) &&
  1313. OrderingIs(cfNative, cfOwnerLink))
  1314. {
  1315. pforetc->cfFormat = wOwnerLinkClassIsStdOleLink(FALSE) ?
  1316. cfEmbeddedObject : cfEmbedSource;
  1317. pforetc->tymed = TYMED_ISTORAGE;
  1318. if (!IsClipboardFormatAvailable(cfObjectDescriptor))
  1319. {
  1320. // cfObjectDescriptor may be directly on the
  1321. // clipboard if it was flushed.
  1322. m_cfForceNext = cfObjectDescriptor;
  1323. }
  1324. }
  1325. else
  1326. {
  1327. // Native without ownerlink is useless
  1328. cfNext = EnumClipboardFormats(cfNext);
  1329. goto TryAgain;
  1330. }
  1331. }
  1332. else if (cfNext == cfObjectLink)
  1333. {
  1334. pforetc->cfFormat = cfLinkSource;
  1335. pforetc->tymed = TYMED_ISTREAM;
  1336. if (!IsClipboardFormatAvailable(cfLinkSrcDescriptor))
  1337. {
  1338. // cfLinkSrcDescriptor may be directly on the clipboard
  1339. // if it was flushed.
  1340. m_cfForceNext = cfLinkSrcDescriptor;
  1341. }
  1342. }
  1343. else
  1344. {
  1345. pforetc->cfFormat = cfNext;
  1346. pforetc->tymed = UtFormatToTymed(cfNext);
  1347. }
  1348. errRtn:
  1349. m_cfCurrent = cfNext;
  1350. if (!CloseClipboard())
  1351. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  1352. return(hresult);
  1353. }
  1354. //+----------------------------------------------------------------------------
  1355. //
  1356. // Member:
  1357. // CClipEnumFormatEtc::Skip, public
  1358. //
  1359. // Synopsis:
  1360. // Implements IEnumFORMATETC::Skip
  1361. //
  1362. // Arguments:
  1363. // [celt] -- the number of elements to skip in the enumeration
  1364. //
  1365. // Returns:
  1366. // S_FALSE, if fewer elements were available than [celt]
  1367. // S_TRUE, otherwise
  1368. //
  1369. // Notes:
  1370. //
  1371. // History:
  1372. // 12/10/93 - ChrisWe - file inspection and cleanup
  1373. //
  1374. //-----------------------------------------------------------------------------
  1375. #pragma SEG(CClipEnumFormatEtc_Skip)
  1376. STDMETHODIMP CClipEnumFormatEtc::Skip(ULONG celt)
  1377. {
  1378. VDATEHEAP();
  1379. ULONG celtSoFar; // a count of the elements we've skipped so far
  1380. FORMATETC formatetc; // a dummy FORMATETC to fetch formats into
  1381. M_PROLOG(this);
  1382. // skip over as many formats as requested
  1383. for(celtSoFar = 0; (celtSoFar < celt) &&
  1384. (NextOne(&formatetc) == NOERROR); ++celtSoFar)
  1385. ;
  1386. return((celtSoFar < celt) ? ResultFromScode(S_FALSE) : NOERROR);
  1387. }
  1388. //+----------------------------------------------------------------------------
  1389. //
  1390. // Member:
  1391. // CClipEnumFormatEtc::Reset, public
  1392. //
  1393. // Synopsis:
  1394. // implements IEnumFORMATETC::Reset
  1395. //
  1396. // Arguments:
  1397. // none
  1398. //
  1399. // Returns:
  1400. // S_OK
  1401. //
  1402. // Notes:
  1403. //
  1404. // History:
  1405. // 12/10/93 - ChrisWe - file inspection and cleanup
  1406. //
  1407. //-----------------------------------------------------------------------------
  1408. #pragma SEG(CClipEnumFormatEtc_Reset)
  1409. STDMETHODIMP CClipEnumFormatEtc::Reset(void)
  1410. {
  1411. VDATEHEAP();
  1412. Init();
  1413. return(NOERROR);
  1414. }
  1415. //+----------------------------------------------------------------------------
  1416. //
  1417. // Member:
  1418. // CClipEnumFormatEtc::Clone, public
  1419. //
  1420. // Synopsis:
  1421. // implements IEnumFORMATETC::Clone
  1422. //
  1423. // Arguments:
  1424. // [ppenum] -- pointer to where to return the new enumerator
  1425. //
  1426. // Returns:
  1427. // E_OUTOFMEMORY, S_OK
  1428. //
  1429. // Notes:
  1430. //
  1431. // History:
  1432. // 12/10/93 - ChrisWe - file inspection and cleanup
  1433. //
  1434. //-----------------------------------------------------------------------------
  1435. #pragma SEG(CClipEnumFormatEtc_Clone)
  1436. STDMETHODIMP CClipEnumFormatEtc::Clone(IEnumFORMATETC FAR* FAR* ppenum)
  1437. {
  1438. VDATEHEAP();
  1439. CClipEnumFormatEtc FAR* pECB; // pointer to the new enumerator
  1440. M_PROLOG(this);
  1441. // validate parameters
  1442. VDATEPTROUT(ppenum, LPENUMFORMATETC);
  1443. // allocate the new enumerator
  1444. *ppenum = pECB = new CClipEnumFormatEtc;
  1445. if (pECB == NULL)
  1446. return(ResultFromScode(E_OUTOFMEMORY));
  1447. // set the clone enumerator to be in the same state as this one
  1448. pECB->m_cfCurrent = m_cfCurrent;
  1449. pECB->m_uFlag = m_uFlag;
  1450. pECB->m_cfForceNext = m_cfForceNext;
  1451. return(NOERROR);
  1452. }
  1453. //+----------------------------------------------------------------------------
  1454. //
  1455. // Member:
  1456. // CClipEnumFormatEtc::CClipEnumFormatEtc, public
  1457. //
  1458. // Synopsis:
  1459. // constructor
  1460. //
  1461. // Arguments:
  1462. // none
  1463. //
  1464. // Notes:
  1465. // returns with reference count set to 1
  1466. //
  1467. // History:
  1468. // 12/10/93 - ChrisWe - created
  1469. //
  1470. //-----------------------------------------------------------------------------
  1471. CClipEnumFormatEtc::CClipEnumFormatEtc()
  1472. {
  1473. VDATEHEAP();
  1474. m_refs = 1;
  1475. }
  1476. //+----------------------------------------------------------------------------
  1477. //
  1478. // Member:
  1479. // CClipEnumFormatEtc::Init, public
  1480. //
  1481. // Synopsis:
  1482. // Initializes enumerator, preparing it for use.
  1483. //
  1484. // Arguments:
  1485. // none
  1486. //
  1487. // Notes:
  1488. //
  1489. // History:
  1490. // 12/10/93 - ChrisWe - created
  1491. //
  1492. //-----------------------------------------------------------------------------
  1493. void CClipEnumFormatEtc::Init(void)
  1494. {
  1495. VDATEHEAP();
  1496. M_PROLOG(this);
  1497. // initialize enumerator to be at beginning of scan state
  1498. m_cfCurrent = 0;
  1499. m_uFlag = 0;
  1500. m_cfForceNext = 0;
  1501. }
  1502. // $$$
  1503. // ObjectLinkToMonikerStream
  1504. //
  1505. // grszFileItem == szFileName\0szItemName\0\0
  1506. // i.e. the tail end of an ObjectLink
  1507. // cbFile == strlen(szFileName)
  1508. //
  1509. // Create a moniker from the ObjectLink and serialize it to pstm
  1510. //
  1511. #pragma SEG(ObjectLinkToMonikerStream)
  1512. STATIC INTERNAL ObjectLinkToMonikerStream(LPOLESTR grszFileItem, DWORD cbFile,
  1513. REFCLSID clsid, LPSTREAM pstm)
  1514. {
  1515. VDATEHEAP();
  1516. HRESULT hr = NOERROR;
  1517. LPMONIKER pmk = NULL;
  1518. LPMONIKER pmkFile = NULL;
  1519. LPMONIKER pmkItem = NULL;
  1520. LPPERSISTSTREAM ppersiststm = NULL;
  1521. #ifdef WIN32 // REVIEW, no 16 bit interop
  1522. return(ReportResult(0, E_NOTIMPL, 0, 0));
  1523. // REVIEW, this seems to be used by GetOle2Format().
  1524. #else
  1525. Assert(grszFileItem);
  1526. Assert(cbFile == (DWORD)_xstrlen(grszFileItem) + 1);
  1527. if (NOERROR != (hr = CreateOle1FileMoniker(grszFileItem, clsid,
  1528. &pmkFile)))
  1529. {
  1530. AssertSz (0, "Cannot create file moniker");
  1531. goto errRtn;
  1532. }
  1533. grszFileItem += cbFile;
  1534. if (*grszFileItem)
  1535. {
  1536. if (NOERROR != (hr = CreateItemMoniker(OLESTR("!"),
  1537. grszFileItem, &pmkItem)))
  1538. {
  1539. AssertSz(0, "Cannot create file moniker");
  1540. goto errRtn;
  1541. }
  1542. if (NOERROR != (hr = CreateGenericComposite(pmkFile,
  1543. pmkItem, &pmk)))
  1544. {
  1545. AssertSz(0, "Cannot create composite moniker");
  1546. goto errRtn;
  1547. }
  1548. }
  1549. else
  1550. {
  1551. // No item
  1552. pmk = pmkFile;
  1553. pmk->AddRef();
  1554. }
  1555. if (NOERROR != (hr = pmk->QueryInterface(IID_IPersistStream,
  1556. (LPLPVOID)&ppersiststm)))
  1557. {
  1558. AssertSz(0, "Cannot get IPersistStream from moniker");
  1559. goto errRtn;
  1560. }
  1561. if (NOERROR != (hr = OleSaveToStream(ppersiststm, pstm)))
  1562. {
  1563. AssertSz(0, "Cannot save to Persist Stream");
  1564. goto errRtn;
  1565. }
  1566. errRtn:
  1567. if (pmk)
  1568. pmk->Release();
  1569. if (pmkFile)
  1570. pmkFile->Release();
  1571. if (pmkItem)
  1572. pmkItem->Release();
  1573. if (ppersiststm)
  1574. ppersiststm->Release();
  1575. return hr;
  1576. #endif // WIN32
  1577. }
  1578. //+----------------------------------------------------------------------------
  1579. //
  1580. // Function:
  1581. // wHandleToStorage, static
  1582. //
  1583. // Synopsis:
  1584. // Copies the contents of a handle to a native clipboard
  1585. // format to an IStorage instance.
  1586. //
  1587. // Arguments:
  1588. // [pstg] -- the IStorage instance to copy the handle contents to
  1589. // [hNative] -- a handle to a native clipboard format
  1590. //
  1591. // Returns:
  1592. // HRESULT
  1593. //
  1594. // Notes:
  1595. // REVIEW, this seems to assume that the handle was already
  1596. // an IStorage instance disguised as an OLE1.0 object for the
  1597. // sake of a containing OLE1.0 object, and creates a copy of
  1598. // the underlying OLE2.0 stuff in the target storage.
  1599. //
  1600. // The Cache streams are removed from the handle based storage
  1601. // before copying to the target.
  1602. // REVIEW, it's not clear if the caller would like this. Perhaps
  1603. // they should just not be copied....
  1604. //
  1605. // History:
  1606. // 12/10/93 - ChrisWe - file inspection and cleanup
  1607. //
  1608. //-----------------------------------------------------------------------------
  1609. #pragma SEG(wHandleToStorage)
  1610. STATIC INTERNAL wHandleToStorage(LPSTORAGE pstg, HANDLE hNative)
  1611. {
  1612. VDATEHEAP();
  1613. LPLOCKBYTES plkbyt = NULL;
  1614. LPSTORAGE pstgNative = NULL;
  1615. HRESULT hresult;
  1616. RetErr(CreateILockBytesOnHGlobal(hNative, FALSE, &plkbyt));
  1617. if (NOERROR != (hresult = StgIsStorageILockBytes(plkbyt)))
  1618. {
  1619. AssertSz(0, "Native data is not an IStorage");
  1620. goto errRtn;
  1621. }
  1622. // This is really a 2.0 object disguised as a 1.0 object
  1623. // for the sake of its 1.0 container, so reconstitute
  1624. // the original IStorage from the native data.
  1625. if (NOERROR != (hresult = StgOpenStorageOnILockBytes(plkbyt, NULL,
  1626. STGM_DFRALL, NULL, 0, &pstgNative)))
  1627. {
  1628. AssertSz(0, "Couldn't open storage on native data");
  1629. goto errRtn;
  1630. }
  1631. ErrRtnH(UtDoStreamOperation(pstgNative, NULL, OPCODE_REMOVE,
  1632. STREAMTYPE_CACHE));
  1633. if (NOERROR != (hresult = pstgNative->CopyTo(0, NULL, NULL, pstg)))
  1634. {
  1635. AssertSz(0, "Couldn't copy storage");
  1636. goto errRtn;
  1637. }
  1638. errRtn:
  1639. if (pstgNative)
  1640. pstgNative->Release();
  1641. if (plkbyt)
  1642. plkbyt->Release();
  1643. return(hresult);
  1644. }
  1645. #ifndef WIN32 // REVIEW, can't find GetMetaFileBits() in win32
  1646. // REVIEW, seems to be OLE1
  1647. #pragma SEG(MfToPres)
  1648. INTERNAL MfToPres(HANDLE hMfPict, PPRES ppres)
  1649. {
  1650. VDATEHEAP();
  1651. LPMETAFILEPICT pMfPict;
  1652. Assert(ppres);
  1653. pMfPict = (LPMETAFILEPICT)GlobalLock(hMfPict);
  1654. RetZS(pMfPict, CLIPBRD_E_BAD_DATA);
  1655. ppres->m_format.m_ftag = ftagClipFormat;
  1656. ppres->m_format.m_cf = CF_METAFILEPICT;
  1657. ppres->m_ulHeight = pMfPict->yExt;
  1658. ppres->m_ulWidth = pMfPict->xExt;
  1659. // GetMetaFileBits() invalidates its parameter, therefore we must copy
  1660. ppres->m_data.m_h = GetMetaFileBits(CopyMetaFile(pMfPict->hMF, NULL));
  1661. ppres->m_data.m_cbSize = GlobalSize(ppres->m_data.m_h);
  1662. ppres->m_data.m_pv = GlobalLock(ppres->m_data.m_h);
  1663. GlobalUnlock(hMfPict);
  1664. return(NOERROR);
  1665. }
  1666. #pragma SEG(DibToPres)
  1667. INTERNAL DibToPres(HANDLE hDib, PPRES ppres)
  1668. {
  1669. VDATEHEAP();
  1670. BITMAPINFOHEADER FAR* pbminfohdr;
  1671. Assert(ppres);
  1672. pbminfohdr = (BITMAPINFOHEADER FAR*)GlobalLock(hDib);
  1673. RetZS(pbminfohdr, CLIPBRD_E_BAD_DATA);
  1674. ppres->m_format.m_ftag = ftagClipFormat;
  1675. ppres->m_format.m_cf = CF_DIB;
  1676. ppres->m_ulHeight = pbminfohdr->biHeight;
  1677. ppres->m_ulWidth = pbminfohdr->biWidth;
  1678. ppres->m_data.m_h = hDib;
  1679. ppres->m_data.m_pv = pbminfohdr;
  1680. ppres->m_data.m_cbSize = GlobalSize (hDib);
  1681. // Don't free the hDib because it is on the clipboard.
  1682. ppres->m_data.m_fNoFree = TRUE;
  1683. // Do not unlock hDib
  1684. return(NOERROR);
  1685. }
  1686. #pragma SEG(BmToPres)
  1687. INTERNAL BmToPres(HBITMAP hBM, PPRES ppres)
  1688. {
  1689. VDATEHEAP();
  1690. HANDLE hDib;
  1691. if (hDib = UtConvertBitmapToDib(hBM))
  1692. {
  1693. // this routine keeps hDib, it doesn't make a copy of it
  1694. return DibToPres(hDib, ppres);
  1695. }
  1696. return(ResultFromScode(E_OUTOFMEMORY));
  1697. }
  1698. #endif // WIN32
  1699. //$$$
  1700. // OrderingIs
  1701. //
  1702. // Return whether the relative ordering of cf1 and cf2 on the clipboard
  1703. // is "cf1 then cf2". Will return FALSE if cf1 is not on the clipboard,
  1704. // so OrderingIs (cf1, cf2) => IsClipboardFormatAvailable (cf1)
  1705. // Clipboard must be open.
  1706. //
  1707. INTERNAL_(BOOL) OrderingIs(const CLIPFORMAT cf1, const CLIPFORMAT cf2)
  1708. {
  1709. VDATEHEAP();
  1710. CLIPFORMAT cf = 0;
  1711. while (cf = EnumClipboardFormats(cf))
  1712. {
  1713. if (cf == cf1)
  1714. return(TRUE);
  1715. if (cf == cf2)
  1716. return(FALSE);
  1717. }
  1718. return(FALSE); // didn't find either format
  1719. }
  1720. // wMakeEmbedObjForLink
  1721. //
  1722. // Generate a storage (cfEmbedSource) for a link copied from a 1.0 container.
  1723. //
  1724. #pragma SEG(wMakeEmbedObjForLink)
  1725. INTERNAL wMakeEmbedObjForLink(LPSTORAGE pstg)
  1726. {
  1727. VDATEHEAP();
  1728. #ifdef WIN32 // REVIEW, seems to be OLE1
  1729. return(ReportResult(0, OLE_E_NOOLE1, 0, 0));
  1730. #else
  1731. GENOBJ genobj;
  1732. HANDLE hOwnerLink;
  1733. LPOLESTR pch;
  1734. HRESULT hresult;
  1735. genobj.m_class.Set(CLSID_StdOleLink);
  1736. genobj.m_ppres = new PRES;
  1737. RetZS(genobj.m_ppres, E_OUTOFMEMORY);
  1738. genobj.m_fLink = TRUE;
  1739. genobj.m_lnkupdopt = UPDATE_ALWAYS;
  1740. if (IsClipboardFormatAvailable(CF_METAFILEPICT))
  1741. {
  1742. RetErr(MfToPres(GetClipboardData(CF_METAFILEPICT),
  1743. genobj.m_ppres));
  1744. }
  1745. else if (IsClipboardFormatAvailable(CF_DIB))
  1746. {
  1747. RetErr(DibToPres(GetClipboardData(CF_DIB),
  1748. genobj.m_ppres));
  1749. }
  1750. else if (IsClipboardFormatAvailable(CF_BITMAP))
  1751. {
  1752. RetErr(BmToPres((HBITMAP)GetClipboardData(CF_BITMAP),
  1753. genobj.m_ppres));
  1754. }
  1755. else
  1756. {
  1757. delete genobj.m_ppres;
  1758. genobj.m_ppres = NULL;
  1759. genobj.m_fNoBlankPres = TRUE;
  1760. }
  1761. if (NULL == (hOwnerLink = GetClipboardData(cfOwnerLink)))
  1762. {
  1763. Assert(0);
  1764. return(ResultFromScode (DV_E_CLIPFORMAT));
  1765. }
  1766. if (NULL == (pch = GlobalLock(hOwnerLink)))
  1767. return(ResultFromScode(CLIPBRD_E_BAD_DATA));
  1768. genobj.m_classLast.Set(UtDupString(pch));
  1769. pch += _xstrlen(pch)+1;
  1770. genobj.m_szTopic = *pch ? UtDupString (pch) : NULL;
  1771. pch += _xstrlen(pch)+1;
  1772. genobj.m_szItem = *pch ? UtDupString (pch) : NULL;
  1773. GlobalUnlock(hOwnerLink);
  1774. hresult = GenericObjectToIStorage(genobj, pstg, NULL);
  1775. if (SUCCEEDED(hresult))
  1776. hresult = NOERROR;
  1777. if (!OrderingIs(cfNative, cfOwnerLink))
  1778. return(hresult);
  1779. else
  1780. {
  1781. // Case of copying an OLE 2 link from a 1.0 container.
  1782. // The first part of this function created a presentation
  1783. // stream from the presentation on the clipboard. The
  1784. // presentation is NOT already inside the Native data (i.e.,
  1785. // the cfEmbeddedObject) because we removed it to conserve
  1786. // space.
  1787. HGLOBAL h = GetClipboardData(cfNative);
  1788. RetZS(h, CLIPBRD_E_BAD_DATA);
  1789. return(wHandleToStorage(pstg, h));
  1790. }
  1791. #endif // WIN32
  1792. }
  1793. #pragma SEG(CreateObjectDescriptor)
  1794. STATIC INTERNAL_(HGLOBAL) CreateObjectDescriptor(CLSID clsid, DWORD dwAspect,
  1795. const SIZEL FAR *psizel, const POINTL FAR *ppointl,
  1796. DWORD dwStatus, LPOLESTR lpszFullUserTypeName,
  1797. LPOLESTR lpszSrcOfCopy)
  1798. {
  1799. VDATEHEAP();
  1800. DWORD dwFullUserTypeNameBLen; // length of lpszFullUserTypeName in BYTES
  1801. DWORD dwSrcOfCopyBLen; // length of lpszSrcOfCopy in BYTES
  1802. HGLOBAL hMem; // handle to the object descriptor
  1803. LPOBJECTDESCRIPTOR lpOD; // the new object descriptor
  1804. // Get the length of Full User Type Name; Add 1 for the null terminator
  1805. if (!lpszFullUserTypeName)
  1806. dwFullUserTypeNameBLen = 0;
  1807. else
  1808. dwFullUserTypeNameBLen = (_xstrlen(lpszFullUserTypeName) +
  1809. 1) * sizeof(OLECHAR);
  1810. // Get the Source of Copy string and it's length; Add 1 for the null
  1811. // terminator
  1812. if (lpszSrcOfCopy)
  1813. dwSrcOfCopyBLen = (_xstrlen(lpszSrcOfCopy) + 1) *
  1814. sizeof(OLECHAR);
  1815. else
  1816. {
  1817. // No src moniker so use user type name as source string.
  1818. lpszSrcOfCopy = lpszFullUserTypeName;
  1819. dwSrcOfCopyBLen = dwFullUserTypeNameBLen;
  1820. }
  1821. // allocate the memory where we'll put the object descriptor
  1822. hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
  1823. sizeof(OBJECTDESCRIPTOR) + dwFullUserTypeNameBLen +
  1824. dwSrcOfCopyBLen);
  1825. if (hMem == NULL)
  1826. goto error;
  1827. lpOD = (LPOBJECTDESCRIPTOR)GlobalLock(hMem);
  1828. if (lpOD == NULL)
  1829. goto error;
  1830. // Set the FullUserTypeName offset and copy the string
  1831. if (!lpszFullUserTypeName)
  1832. {
  1833. // zero offset indicates that string is not present
  1834. lpOD->dwFullUserTypeName = 0;
  1835. }
  1836. else
  1837. {
  1838. lpOD->dwFullUserTypeName = sizeof(OBJECTDESCRIPTOR);
  1839. _xmemcpy(((BYTE FAR *)lpOD)+lpOD->dwFullUserTypeName,
  1840. (const void FAR *)lpszFullUserTypeName,
  1841. dwFullUserTypeNameBLen);
  1842. }
  1843. // Set the SrcOfCopy offset and copy the string
  1844. if (!lpszSrcOfCopy)
  1845. {
  1846. // zero offset indicates that string is not present
  1847. lpOD->dwSrcOfCopy = 0;
  1848. }
  1849. else
  1850. {
  1851. lpOD->dwSrcOfCopy = sizeof(OBJECTDESCRIPTOR) +
  1852. dwFullUserTypeNameBLen;
  1853. _xmemcpy(((BYTE FAR *)lpOD)+lpOD->dwSrcOfCopy,
  1854. (const void FAR *)lpszSrcOfCopy,
  1855. dwSrcOfCopyBLen);
  1856. }
  1857. // Initialize the rest of the OBJECTDESCRIPTOR
  1858. lpOD->cbSize = sizeof(OBJECTDESCRIPTOR) + dwFullUserTypeNameBLen +
  1859. dwSrcOfCopyBLen;
  1860. lpOD->clsid = clsid;
  1861. lpOD->dwDrawAspect = dwAspect;
  1862. lpOD->sizel = *psizel;
  1863. lpOD->pointl = *ppointl;
  1864. lpOD->dwStatus = dwStatus;
  1865. GlobalUnlock(hMem);
  1866. return(hMem);
  1867. error:
  1868. if (hMem)
  1869. {
  1870. GlobalUnlock(hMem);
  1871. GlobalFree(hMem);
  1872. }
  1873. return(NULL);
  1874. }
  1875. #pragma SEG(wOwnerLinkClassIsStdOleLink)
  1876. STATIC INTERNAL_(BOOL) wOwnerLinkClassIsStdOleLink(BOOL fOpenClipbrd)
  1877. {
  1878. VDATEHEAP();
  1879. BOOL f = FALSE;
  1880. LPOLESTR sz = NULL;
  1881. HANDLE h; // handle for clipboard data
  1882. if (fOpenClipbrd && !OpenClipboard(GetClipboardWindow()))
  1883. return(FALSE);
  1884. h = GetClipboardData(cfOwnerLink);
  1885. ErrZ(h);
  1886. sz = (LPOLESTR)GlobalLock(h);
  1887. ErrZ(sz);
  1888. f = (0 == _xstrcmp(szStdOleLink, sz));
  1889. errRtn:
  1890. if (sz)
  1891. GlobalUnlock(h);
  1892. if (fOpenClipbrd)
  1893. Verify(CloseClipboard());
  1894. return(f);
  1895. }
  1896. #pragma SEG(IsNetDDEObjectLink)
  1897. STATIC FARINTERNAL_(BOOL) IsNetDDEObjectLink(BOOL fMustOpen)
  1898. {
  1899. VDATEHEAP();
  1900. BOOL fAnswer;
  1901. HANDLE hObjLink;
  1902. LPOLESTR pObjLink;
  1903. if (fMustOpen)
  1904. {
  1905. if (!OpenClipboard(GetClipboardWindow()))
  1906. return(TRUE); // cause a failure
  1907. }
  1908. hObjLink = GetClipboardData(cfObjectLink);
  1909. pObjLink = (LPOLESTR)GlobalLock(hObjLink);
  1910. if (NULL==pObjLink)
  1911. {
  1912. fAnswer = TRUE;// cause a failure
  1913. goto errRtn;
  1914. }
  1915. // Net DDE :"classnames" are of the form:
  1916. // \\machinename\NDDE$\0$pagename.ole
  1917. fAnswer = (OLESTR('\\')==pObjLink[0] && OLESTR('\\')==pObjLink[1]);
  1918. GlobalUnlock(hObjLink);
  1919. errRtn:
  1920. if (fMustOpen)
  1921. CloseClipboard();
  1922. return(fAnswer);
  1923. }
  1924. // $$$ Continue
  1925. // Handle cfEmbeddedObject, cfEmbedSource, cfLinkSource, cfObjectDescriptor,
  1926. // cfLinkDesciptor
  1927. //
  1928. #pragma SEG(GetOle2Format)
  1929. HRESULT GetOle2Format(LPFORMATETC pforetc, LPSTGMEDIUM pmedium)
  1930. {
  1931. VDATEHEAP();
  1932. CLIPFORMAT cf; // local copy of pforetc->cfFormat
  1933. HRESULT hresult; // error state so far
  1934. DWORD cbDoc, cbClass, cbItemName;
  1935. HANDLE hOle1;
  1936. HANDLE hNative;
  1937. STGMEDIUM stgm;
  1938. CLSID clsid;
  1939. LPOLESTR szDoc;
  1940. // the following variables are used in error cleanup situations, and
  1941. // need to be initialized to NULL so the cleanup code does not try
  1942. // to free things that haven't been used
  1943. LPOLESTR szClass = NULL;
  1944. LPOLESTR szItemName = NULL;
  1945. IStream FAR* pstm = NULL;
  1946. IStorage FAR* pstg = NULL;
  1947. // validate parameters
  1948. VERIFY_LINDEX(pforetc->lindex);
  1949. cf = pforetc->cfFormat;
  1950. Assert ((cf == cfEmbeddedObject) || (cf == cfEmbedSource)
  1951. || (cf == cfLinkSource) || (cf == cfLinkSrcDescriptor)
  1952. || (cf == cfObjectDescriptor));
  1953. // Verify availability of format
  1954. if ((cf == cfEmbedSource) && (!IsClipboardFormatAvailable(cfNative) ||
  1955. !IsClipboardFormatAvailable(cfOwnerLink)))
  1956. {
  1957. return(ResultFromScode(DV_E_CLIPFORMAT));
  1958. }
  1959. if ((cf == cfObjectDescriptor) &&
  1960. !IsClipboardFormatAvailable(cfOwnerLink))
  1961. {
  1962. return(ResultFromScode(DV_E_CLIPFORMAT));
  1963. }
  1964. if (((cf == cfLinkSource) || (cf == cfLinkSrcDescriptor)) &&
  1965. (!IsClipboardFormatAvailable(cfObjectLink) ||
  1966. IsNetDDEObjectLink(TRUE)))
  1967. {
  1968. return(ResultFromScode(DV_E_CLIPFORMAT));
  1969. }
  1970. if (!OpenClipboard(GetClipboardWindow()))
  1971. return(ReportResult(0, CLIPBRD_E_CANT_OPEN, 0, 0));
  1972. // After this point, don't just return in case of error any more
  1973. // as the clipboard is open. From here on, either goto OK_Exit,
  1974. // or errRtn, depending on the reason for quitting.
  1975. if (cf == cfEmbeddedObject)
  1976. {
  1977. if (!IsClipboardFormatAvailable(cfOwnerLink) ||
  1978. (OrderingIs(cfNative, cfOwnerLink) &&
  1979. !wOwnerLinkClassIsStdOleLink(FALSE)))
  1980. #ifdef NEVER
  1981. /*
  1982. REVIEW
  1983. ChrisWe, 1/6/94. I'm not at all sure about this. The original code for the
  1984. condition above is as below, with the unary negation. But it seems that
  1985. If we want embedded source we want to fail if the cfOwnerLink is for a link,
  1986. not if it isn't a link. The below code seems to agree with that.
  1987. This agrees with what OleSetClipboard does when you try to put
  1988. cfEmbeddedObject on the clipboard. All of the above are true, and everything
  1989. is alright. I don't see how this negation can work on win16 unless there's
  1990. a compiler bug or something weird is going on.
  1991. */
  1992. //!wOwnerLinkClassIsStdOleLink(FALSE)))
  1993. #endif // NEVER
  1994. {
  1995. hresult = ResultFromScode (DV_E_CLIPFORMAT);
  1996. goto OK_Exit; // Close clipboard and exit
  1997. }
  1998. }
  1999. // Is it just a query?
  2000. if (pmedium == NULL)
  2001. {
  2002. hresult = NOERROR;
  2003. goto OK_Exit; // Close clipboard and exit
  2004. }
  2005. // Get all the data we need out of the OLE1 formats
  2006. hOle1 = GetClipboardData(((cf == cfEmbedSource) ||
  2007. (cf == cfEmbeddedObject) ||
  2008. (cf == cfObjectDescriptor)) ?
  2009. cfOwnerLink : cfObjectLink);
  2010. if (hOle1 == NULL)
  2011. {
  2012. hresult = ReportResult(0, DV_E_CLIPFORMAT, 0, 0);
  2013. goto errRtn;
  2014. }
  2015. szClass = (LPOLESTR)GlobalLock(hOle1);
  2016. if (szClass == NULL)
  2017. {
  2018. hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  2019. goto errRtn;
  2020. }
  2021. if ((hresult = wCLSIDFromProgID(szClass, &clsid,
  2022. /*fForceAssign*/ TRUE)) != NOERROR)
  2023. goto errRtn;
  2024. cbClass = _xstrlen(szClass) + 1;
  2025. szDoc = szClass + cbClass;
  2026. cbDoc = _xstrlen(szDoc) + 1;
  2027. szItemName = szDoc + cbDoc;
  2028. cbItemName = _xstrlen(szItemName) + 1;
  2029. if (cf == cfEmbedSource)
  2030. {
  2031. if (NULL == (hNative = GetClipboardData(cfNative)))
  2032. {
  2033. hresult = ReportResult(0, DV_E_CLIPFORMAT, 0, 0);
  2034. goto errRtn;
  2035. }
  2036. }
  2037. stgm = *pmedium; // just an alias mechanism
  2038. // REVIEW, NO, this makes a copy!!!
  2039. // Choose and allocate medium
  2040. if (pmedium->tymed == TYMED_NULL)
  2041. {
  2042. // none of our media need this
  2043. stgm.pUnkForRelease = NULL;
  2044. // GetData: Callee chooses medium
  2045. if (((cf == cfEmbedSource) || (cf == cfEmbeddedObject)) &&
  2046. (pforetc->tymed & TYMED_ISTORAGE))
  2047. {
  2048. // Choose Storage (Per spec)
  2049. stgm.tymed = TYMED_ISTORAGE;
  2050. hresult = StgCreateDocfile(NULL, STGM_CREATE |
  2051. STGM_SALL | STGM_DELETEONRELEASE,
  2052. 0, &pstg);
  2053. if (hresult != NOERROR)
  2054. goto errRtn;
  2055. stgm.pstg = pstg;
  2056. }
  2057. else if ((cf == cfLinkSource) &&
  2058. (pforetc->tymed & TYMED_ISTREAM))
  2059. {
  2060. // Choose Stream (Per spec)
  2061. stgm.tymed = TYMED_ISTREAM;
  2062. pstm = CreateMemStm((cbClass + cbDoc)*sizeof(OLECHAR),
  2063. NULL);
  2064. if (pstm == NULL)
  2065. {
  2066. hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  2067. goto errRtn;
  2068. }
  2069. stgm.pstm = pstm;
  2070. }
  2071. else if (((cf == cfLinkSrcDescriptor) ||
  2072. (cf == cfObjectDescriptor)) &&
  2073. (pforetc->tymed & TYMED_HGLOBAL))
  2074. {
  2075. // Do not need to allocate handle now,
  2076. // will be allocated below.
  2077. stgm.tymed = TYMED_HGLOBAL;
  2078. }
  2079. else
  2080. {
  2081. // don't understand any other media types
  2082. hresult = ResultFromScode(DV_E_TYMED);
  2083. goto errRtn;
  2084. }
  2085. }
  2086. else // GetDataHere
  2087. {
  2088. if ((((cf == cfEmbedSource) || (cf == cfEmbeddedObject)) &&
  2089. !(pmedium->tymed &= TYMED_ISTORAGE)) ||
  2090. (cf==cfLinkSource &&
  2091. !(pmedium->tymed &= TYMED_ISTREAM)) ||
  2092. (cf == cfObjectDescriptor) ||
  2093. (cf == cfLinkSrcDescriptor))
  2094. {
  2095. hresult = ResultFromScode(DV_E_TYMED);
  2096. goto errRtn;
  2097. }
  2098. }
  2099. // Write the data to the medium
  2100. switch (stgm.tymed)
  2101. {
  2102. case TYMED_ISTORAGE:
  2103. if (cf == cfEmbedSource)
  2104. {
  2105. if (!CoIsOle1Class(clsid))
  2106. {
  2107. hresult = wHandleToStorage(stgm.pstg, hNative);
  2108. if (hresult != NOERROR)
  2109. {
  2110. hresult = ResultFromScode(
  2111. DV_E_CLIPFORMAT);
  2112. goto errRtn;
  2113. }
  2114. }
  2115. else
  2116. {
  2117. #ifdef WIN32 // REVIEW, no OLE1-2 interop
  2118. return(ReportResult(0, OLE_E_NOOLE1, 0, 0));
  2119. #else
  2120. // Create a storage for a 1.0 object
  2121. ErrRtnH(WriteClassStg(stgm.pstg,clsid));
  2122. // If we ever decide to write a Format and
  2123. // User Type for link objects, we'll need to
  2124. // remove this check
  2125. if (clsid != CLSID_StdOleLink)
  2126. {
  2127. if (wWriteFmtUserType(stgm.pstg,clsid)
  2128. != NOERROR)
  2129. {
  2130. // This happens when the class
  2131. // is not registered. Use class
  2132. // name as user Type
  2133. WriteFmtUserTypeStg(stgm.pstg,
  2134. RegisterClipboardFormat(szClass),
  2135. szClass);
  2136. }
  2137. }
  2138. hresult = StSave10NativeData(stgm.pstg,
  2139. hNative, FALSE);
  2140. if (hresult != NOERROR)
  2141. {
  2142. hresult = ResultFromScode(
  2143. DV_E_CLIPFORMAT);
  2144. goto errRtn;
  2145. }
  2146. if (IsValidReadPtrIn(szItemName, 1)
  2147. && (szItemName[0] != '\0'))
  2148. {
  2149. StSave10ItemName(stgm.pstg, szItemName);
  2150. }
  2151. #endif // WIN32
  2152. }
  2153. }
  2154. else if (cf == cfEmbeddedObject)
  2155. {
  2156. hresult = wMakeEmbedObjForLink(stgm.pstg);
  2157. if (hresult != NOERROR)
  2158. {
  2159. hresult = ResultFromScode(DV_E_CLIPFORMAT);
  2160. goto errRtn;
  2161. }
  2162. }
  2163. else
  2164. {
  2165. Assert(0);
  2166. hresult = ResultFromScode(DV_E_CLIPFORMAT);
  2167. goto errRtn;
  2168. }
  2169. break;
  2170. case TYMED_ISTREAM:
  2171. if (NOERROR != (hresult = ObjectLinkToMonikerStream(szDoc,
  2172. cbDoc, clsid, stgm.pstm)))
  2173. {
  2174. AssertSz(0, "Cannot make Serialized moniker");
  2175. goto errRtn;
  2176. }
  2177. hresult = WriteClassStm(stgm.pstm, clsid);
  2178. break;
  2179. case TYMED_HGLOBAL:
  2180. {
  2181. LPOLESTR szSrcOfCopy;
  2182. STATIC const SIZEL sizel = {0, 0};
  2183. STATIC const POINTL pointl = {0, 0};
  2184. LONG cb; // holds the sizeof(szFullName), and the query
  2185. // return length
  2186. OLECHAR szFullName[256];
  2187. Assert((cf == cfObjectDescriptor) ||
  2188. (cf == cfLinkSrcDescriptor));
  2189. Assert(clsid != CLSID_NULL);
  2190. // allocate a string to hold the source name. Note that when
  2191. // this is composed below, we don't need to add an extra
  2192. // character for the '\\'; cbDob and cbItemName both already
  2193. // include the terminating NULL for the string, so the
  2194. // backslash simply occupies one of those
  2195. szSrcOfCopy = (LPOLESTR)PubMemAlloc((size_t)(cbDoc +
  2196. cbItemName)*sizeof(OLECHAR));
  2197. ErrZS(szSrcOfCopy, E_OUTOFMEMORY);
  2198. // construct the copy source name
  2199. _xstrcpy(szSrcOfCopy, szDoc);
  2200. _xstrcat(szSrcOfCopy, OLESTR("\\"));
  2201. _xstrcat(szSrcOfCopy, szItemName);
  2202. // NULL terminate the string in case it is left untouched
  2203. szFullName[0] = OLECHAR('\0');
  2204. // set the result buffer size, and query the registry
  2205. cb = sizeof(szFullName);
  2206. RegQueryValue(HKEY_CLASSES_ROOT, szClass, szFullName, &cb);
  2207. // check to see that the buffer was big enough for the name
  2208. // REVIEW, if asserts aren't in the retail code, then we should
  2209. // test for this, and possibly allocate a buffer big enough
  2210. Assert(cb <= sizeof(szFullName));
  2211. stgm.hGlobal = CreateObjectDescriptor(clsid, DVASPECT_CONTENT,
  2212. &sizel, &pointl,
  2213. OLEMISC_CANTLINKINSIDE | OLEMISC_CANLINKBYOLE1,
  2214. szFullName, szSrcOfCopy);
  2215. PubMemFree(szSrcOfCopy);
  2216. break;
  2217. }
  2218. default:
  2219. // catch any cases we missed
  2220. Assert(0);
  2221. }
  2222. // copy back the results
  2223. *pmedium = stgm;
  2224. goto OK_Exit;
  2225. errRtn:
  2226. // free storage if we used it
  2227. if (pstg != NULL)
  2228. pstg->Release();
  2229. // free stream if we used it
  2230. if (pstm != NULL)
  2231. pstm->Release();
  2232. OK_Exit:
  2233. if (szClass != NULL)
  2234. GlobalUnlock(hOle1);
  2235. if (!CloseClipboard())
  2236. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  2237. return(hresult);
  2238. }
  2239. #pragma SEG(Is10CompatibleLinkSource)
  2240. STATIC INTERNAL Is10CompatibleLinkSource(LPDATAOBJECT pDataObj)
  2241. {
  2242. VDATEHEAP();
  2243. FORMATETC formatetc;
  2244. STGMEDIUM medium;
  2245. LPLINKSRCDESCRIPTOR pLinkDescriptor;
  2246. BOOL fCompatible;
  2247. INIT_FORETC(formatetc);
  2248. formatetc.cfFormat = cfLinkSrcDescriptor;
  2249. formatetc.tymed = TYMED_HGLOBAL;
  2250. RetErr(pDataObj->GetData(&formatetc, &medium));
  2251. pLinkDescriptor = (LPLINKSRCDESCRIPTOR)GlobalLock(medium.hGlobal);
  2252. RetZS(pLinkDescriptor, E_HANDLE);
  2253. fCompatible = (pLinkDescriptor->dwStatus & OLEMISC_CANLINKBYOLE1) != 0;
  2254. GlobalUnlock(medium.hGlobal);
  2255. ReleaseStgMedium(&medium);
  2256. return(fCompatible ? NOERROR : ResultFromScode(S_FALSE));
  2257. }
  2258. // returns clsid based on [LinkSrc,Object]Desciptor; for persist class from
  2259. // ObjectDescriptor which is a link, returns CLSID_StdOleLink;
  2260. // NOTE: the OLEMISC_ISLINKOBJECT bit is ignored in the link src descriptor.
  2261. #pragma SEG(GetClassFromDescriptor)
  2262. STATIC INTERNAL GetClassFromDescriptor(LPDATAOBJECT pDataObj, LPCLSID pclsid,
  2263. BOOL fLink, BOOL fUser, LPOLESTR FAR* pszSrcOfCopy)
  2264. {
  2265. VDATEHEAP();
  2266. FORMATETC formatetc;
  2267. STGMEDIUM medium;
  2268. LPOBJECTDESCRIPTOR pObjDescriptor;
  2269. HRESULT hresult;
  2270. INIT_FORETC(formatetc);
  2271. formatetc.cfFormat = fLink ? cfLinkSrcDescriptor : cfObjectDescriptor;
  2272. formatetc.tymed = TYMED_HGLOBAL;
  2273. medium.tymed = TYMED_NULL;
  2274. hresult = pDataObj->GetData(&formatetc, &medium);
  2275. AssertOutStgmedium(hresult, &medium);
  2276. if (hresult != NOERROR)
  2277. return(hresult);
  2278. pObjDescriptor = (LPOBJECTDESCRIPTOR)GlobalLock(medium.hGlobal);
  2279. RetZS(pObjDescriptor, E_HANDLE);
  2280. *pclsid = (!fLink && !fUser &&
  2281. (pObjDescriptor->dwStatus & OLEMISC_ISLINKOBJECT)) ?
  2282. CLSID_StdOleLink : pObjDescriptor->clsid;
  2283. if (pszSrcOfCopy)
  2284. {
  2285. *pszSrcOfCopy = UtDupString((LPOLESTR)
  2286. (((BYTE FAR *)pObjDescriptor) +
  2287. pObjDescriptor->dwSrcOfCopy));
  2288. }
  2289. GlobalUnlock(medium.hGlobal);
  2290. ReleaseStgMedium(&medium);
  2291. return(NOERROR);
  2292. }
  2293. #pragma SEG(SetOle1ClipboardFormats)
  2294. FARINTERNAL SetOle1ClipboardFormats(LPDATAOBJECT pDataObj)
  2295. {
  2296. VDATEHEAP();
  2297. HRESULT hresult; // error state so far
  2298. LPENUMFORMATETC penumFormatEtc; // the data object's FORMATETC enum
  2299. FORMATETC foretc; // used to hold the results of the enumerator Next()
  2300. BOOL fLinkSourceAvail = FALSE;
  2301. BOOL fLinkSrcDescAvail = FALSE;
  2302. BOOL fEmbedObjAvail = FALSE;
  2303. CLSID clsid;
  2304. // Enumerate all formats offered by data object, set clipboard
  2305. // with formats retrievable onhGbal.
  2306. hresult = pDataObj->EnumFormatEtc(DATADIR_GET, &penumFormatEtc);
  2307. if (hresult != NOERROR)
  2308. return(hresult);
  2309. while((hresult = penumFormatEtc->Next(1, &foretc, NULL)) == NOERROR)
  2310. {
  2311. if ((foretc.cfFormat == cfEmbedSource) ||
  2312. (foretc.cfFormat == cfEmbeddedObject))
  2313. {
  2314. if (foretc.cfFormat == cfEmbeddedObject)
  2315. fEmbedObjAvail = TRUE;
  2316. // get the clsid of the object; user .vs. persist
  2317. // clsid ignored since we only test against the
  2318. // clsids below.
  2319. if (NOERROR == GetClassFromDescriptor(pDataObj, &clsid,
  2320. FALSE, FALSE, NULL) &&
  2321. !IsEqualCLSID(clsid,
  2322. CLSID_StaticMetafile) &&
  2323. !IsEqualCLSID(clsid, CLSID_StaticDib))
  2324. {
  2325. SetClipboardData(cfNative, NULL);
  2326. SetClipboardData(cfOwnerLink, NULL);
  2327. }
  2328. }
  2329. else if (foretc.cfFormat == cfLinkSource)
  2330. {
  2331. fLinkSourceAvail = TRUE;
  2332. }
  2333. else if (foretc.cfFormat == cfLinkSrcDescriptor)
  2334. {
  2335. fLinkSrcDescAvail = TRUE;
  2336. }
  2337. else
  2338. {
  2339. // use only those TYMEDs OLE1 supported
  2340. // make sure it is available
  2341. // use first (highest fidelity) one enumerated
  2342. if ((NULL == foretc.ptd) &&
  2343. (foretc.tymed & (TYMED_HGLOBAL |
  2344. TYMED_GDI | TYMED_MFPICT)) &&
  2345. (NOERROR == pDataObj->QueryGetData(
  2346. &foretc)) &&
  2347. !IsClipboardFormatAvailable(
  2348. foretc.cfFormat))
  2349. {
  2350. SetClipboardData(foretc.cfFormat, NULL);
  2351. }
  2352. }
  2353. PubMemFree(foretc.ptd);
  2354. }
  2355. // Do not allow 1.0 link to 2.0 embedded object.
  2356. if (fLinkSourceAvail && !fEmbedObjAvail &&
  2357. (NOERROR == Is10CompatibleLinkSource(pDataObj)))
  2358. {
  2359. // ObjectLink should be after any presentation formats
  2360. SetClipboardData(cfObjectLink, NULL);
  2361. if (fLinkSrcDescAvail)
  2362. {
  2363. // Only offer LinkSrcDesc if offering a link, ie,
  2364. // ObjectLink. If clipboard is flushed, we don't want
  2365. // to offer LinkSrcDesc thru the DataObj if we are not
  2366. // offering LinkSrc.
  2367. SetClipboardData(cfLinkSrcDescriptor, NULL);
  2368. }
  2369. }
  2370. // Were they all enumerated successfully?
  2371. if (GetScode(hresult) == S_FALSE)
  2372. hresult = NOERROR;
  2373. // release the enumerator
  2374. penumFormatEtc->Release();
  2375. return(hresult);
  2376. }
  2377. // RemoveClipDataObject
  2378. //
  2379. // Called from: WM_RENDERALLFORMATS, WM_DESTROYCLIPBOARD therefore
  2380. // clipboard is already open.
  2381. // We use hClipDataObj instead of calling GetClipboardData(cfDataObj)
  2382. // because GetClipboardData returns NULL (without asking us to render
  2383. // cfDataObject)--Windows bug?
  2384. //
  2385. #pragma SEG(RemoveClipDataObject)
  2386. STATIC INTERNAL_(void) RemoveClipDataObject(void)
  2387. {
  2388. VDATEHEAP();
  2389. IStream FAR* pStm;
  2390. if (pClipDataObj == NULL)
  2391. {
  2392. Assert(NULL == hClipDataObj);
  2393. return;
  2394. }
  2395. if (hClipDataObj != NULL)
  2396. {
  2397. pStm = CloneMemStm(hClipDataObj);
  2398. Assert(pStm != NULL);
  2399. CoReleaseMarshalData(pStm);
  2400. pStm->Release();
  2401. ReleaseMemStm(&hClipDataObj, /*fInternalOnly*/TRUE);
  2402. hClipDataObj = NULL;
  2403. SetClipboardData(cfDataObject, NULL);
  2404. // hClipDataObj freed by call !!
  2405. }
  2406. else
  2407. {
  2408. // The Clipboard Data Object was never rendered.
  2409. }
  2410. CoDisconnectObject(pClipDataObj, 0);
  2411. pClipDataObj->Release();
  2412. pClipDataObj = NULL;
  2413. }
  2414. // $$$
  2415. // Windows specifics
  2416. //
  2417. // Worker routines for ClipboardWndProc()
  2418. //
  2419. STATIC LRESULT RenderDataObject(void);
  2420. //+----------------------------------------------------------------------------
  2421. //
  2422. // Function:
  2423. // RenderOle1Format, static
  2424. //
  2425. // Synopsis:
  2426. // Ask object for data in the clip format that corresponds to the
  2427. // requested Ole1 clip format, which is one of cfOwnerLink,
  2428. // cfObjectLink, or cfNative.
  2429. //
  2430. // REVIEW, what does this mean? Is this an internal comment?
  2431. // Note that pDataObj should never point to a fake data object
  2432. // because it is either pClipDataObj or pointer to a proxy to an
  2433. // object pointed by pClipDataObj.
  2434. //
  2435. // Arguments:
  2436. // [cf] -- the desired clipboard format
  2437. // [pDataObj] -- pointer to the IDataObject instance to get the
  2438. // required rendition from
  2439. //
  2440. // Returns:
  2441. // A handle to memory containing the format. This memory handle
  2442. // is allocated appropriately for being placed on the clipboard.
  2443. // If the call is unsuccessful, the handle is NULL.
  2444. //
  2445. // Notes:
  2446. //
  2447. // History:
  2448. // 12/13/93 - ChrisWe - file inspection and cleanup
  2449. //
  2450. //-----------------------------------------------------------------------------
  2451. STATIC HANDLE RenderOle1Format(CLIPFORMAT cf, LPDATAOBJECT pDataObj);
  2452. //+----------------------------------------------------------------------------
  2453. //
  2454. // Function:
  2455. // RenderFormat, static
  2456. //
  2457. // Synopsis:
  2458. //REVIEW
  2459. // Ask object for data in the requested clip format.
  2460. // Ole1, Ole2 clip formats are not (and shouldn't be) handled.
  2461. // This is for private clipformats.
  2462. //
  2463. // Arguments:
  2464. // [cf] -- the requested clipboard format
  2465. // [pDataObj] -- the data object to get the rendition from
  2466. //
  2467. // Requires:
  2468. //
  2469. // Returns:
  2470. //
  2471. // Notes:
  2472. //
  2473. // History:
  2474. // 12/13/93 - ChrisWe - file inspection and cleanup
  2475. //
  2476. //-----------------------------------------------------------------------------
  2477. STATIC HANDLE RenderFormat(CLIPFORMAT cf, LPDATAOBJECT pDataObj);
  2478. //+----------------------------------------------------------------------------
  2479. //
  2480. // Function:
  2481. // RenderFormatAndAspect, static
  2482. //
  2483. // Synopsis:
  2484. // Allocate a new handle and render the requested data aspect
  2485. // in the requested format into it.
  2486. //
  2487. // Arguments:
  2488. // [cf] -- the desired clipboard format
  2489. // [pDataObj] -- the IDataObject to get the data from
  2490. // [dwAspect] -- the desired aspect
  2491. //
  2492. // Returns:
  2493. // the newly allocated handle, or NULL.
  2494. //
  2495. // Notes:
  2496. //
  2497. // History:
  2498. // 12/13/93 - ChrisWe - file inspection and cleanup
  2499. //
  2500. //-----------------------------------------------------------------------------
  2501. STATIC HANDLE RenderFormatAndAspect(CLIPFORMAT cf, LPDATAOBJECT pDataObj,
  2502. DWORD dwAspect);
  2503. #ifndef _MAC
  2504. STATIC HWND hwndClipboard = NULL; // Window used for Ole clipboard handling
  2505. // Process delayed rendering messages.
  2506. #pragma SEG(ClipboardWndProc)
  2507. extern "C" LRESULT CALLBACK __loadds ClipboardWndProc(HWND hwnd,
  2508. UINT message, WPARAM wparam, LPARAM lparam)
  2509. {
  2510. VDATEHEAP();
  2511. HANDLE hMem;
  2512. CLIPFORMAT cf;
  2513. switch(message)
  2514. {
  2515. case WM_RENDERFORMAT:
  2516. cf = wparam;
  2517. if (cf == cfDataObject)
  2518. return(RenderDataObject());
  2519. // An app had opened the clipboard and tried to get
  2520. // a format with a NULL handle. Ask object to provide data.
  2521. //
  2522. // Note that that while the above if() is executed in the
  2523. // context of the process owning the clipboard (that is
  2524. // pClipDataObj is valid) the code below may or may not
  2525. // that of the clipboard owner.
  2526. if (pClipDataObj == NULL)
  2527. return(0);
  2528. if ((cf == cfOwnerLink) || (cf == cfObjectLink) ||
  2529. (cf == cfNative))
  2530. hMem = RenderOle1Format(cf, pClipDataObj);
  2531. else
  2532. hMem = RenderFormat(cf, pClipDataObj);
  2533. if (hMem != NULL)
  2534. {
  2535. SetClipboardData(cf, hMem);
  2536. }
  2537. return(0);
  2538. case WM_RENDERALLFORMATS:
  2539. // Server app is going away.
  2540. // Open the clipboard and render all intresting formats.
  2541. if (!OpenClipboard(GetClipboardWindow()))
  2542. return(0);
  2543. if (pClipDataObj)
  2544. {
  2545. RemoveClipDataObject();
  2546. wEmptyClipboard();
  2547. }
  2548. // else clipboard was flushed, so we don't want to empty it
  2549. Verify(CloseClipboard());
  2550. return(0);
  2551. case WM_DESTROYCLIPBOARD:
  2552. // Another app is empting the clipboard; remove
  2553. // DataObject (if any).
  2554. // Note that that app had opened the clipboard
  2555. RemoveClipDataObject();
  2556. return(0);
  2557. }
  2558. return(DefWindowProc(hwnd, message, wparam, lparam));
  2559. }
  2560. #endif // _MAC
  2561. // An app tries to get access to object on clipboard
  2562. // Marshall its interface. Note that while that app
  2563. // may or may not be the process that owns the clipboard
  2564. // the code below is always executed by the clipboard owner.
  2565. //
  2566. // "..., which makes the passed IDataObject accessible
  2567. // from the clipboard"
  2568. //
  2569. #pragma SEG(RenderDataObject)
  2570. STATIC LRESULT RenderDataObject(void)
  2571. {
  2572. VDATEHEAP();
  2573. HRESULT hresult;
  2574. HANDLE hMem;
  2575. IStream FAR* pStm;
  2576. if (pClipDataObj == NULL)
  2577. return(0);
  2578. // Create shared memory stream to Marshal object's interface
  2579. pStm = CreateMemStm(MARSHALINTERFACE_MIN, &hMem);
  2580. if (pStm == NULL)
  2581. return(0);
  2582. // REVIEW - If data object's server is not running
  2583. // MarshalInterface will fail. It is possible (per spec)
  2584. // for an app to set the clipboard with a pointer to
  2585. // an object whose server is a different process (i.e.
  2586. // with a pointer to defhdnlr).
  2587. hresult = CoMarshalInterface(pStm, IID_IDataObject,
  2588. pClipDataObj, 0, NULL, MSHLFLAGS_TABLESTRONG);
  2589. pStm->Release();
  2590. if (hresult != NOERROR)
  2591. {
  2592. GlobalFree(hMem);
  2593. return(0);
  2594. }
  2595. SetClipboardData(cfDataObject, hMem);
  2596. hClipDataObj = hMem;
  2597. OleSetEnumFormatEtc(pClipDataObj, TRUE /*fClip*/);
  2598. return(0);
  2599. }
  2600. INTERNAL wSzFixNet(LPOLESTR FAR* pszIn)
  2601. {
  2602. VDATEHEAP();
  2603. #ifdef REVIEW32
  2604. //this doesn't seem to link well...look at it later
  2605. LPBC pbc = NULL;
  2606. UINT dummy = 0xFFFF;
  2607. LPOLESTR szOut = NULL;
  2608. HRESULT hresult= NOERROR;
  2609. RetErr(CreateBindCtx(0, &pbc));
  2610. ErrRtnH(SzFixNet(pbc, *pszIn, &szOut, &dummy));
  2611. if (szOut)
  2612. {
  2613. delete *pszIn;
  2614. *pszIn = szOut;
  2615. }
  2616. // else leave *pszIn unchanged
  2617. errRtn:
  2618. if (pbc)
  2619. pbc->Release();
  2620. return(hresult);
  2621. #endif //REVIEW32
  2622. return(E_NOTIMPL);
  2623. }
  2624. // MakeObjectLink
  2625. //
  2626. // Take the stream returned by GetData(CF_LINKSOURCE), which should be
  2627. // positioned just before the moniker,
  2628. // and create a clipboard handle for format ObjectLink or OwnerLink.
  2629. // (They look the same.)
  2630. //
  2631. // On entry:
  2632. // *ph is an un-alloc'd (probably NULL) handle
  2633. //
  2634. // On exit:
  2635. // If successful:
  2636. // *ph is the Owner/ObjectLink
  2637. // return NOERROR
  2638. // If cannot make ObjectLink: (because there are > 1 ItemMonikers)
  2639. // *ph = NULL
  2640. // return S_FALSE
  2641. //
  2642. //
  2643. // Stream ::= FileMoniker [:: ItemMoniker]
  2644. // ObjectLink ::= szClsid\0szFile\0szItem\0\0
  2645. //
  2646. #pragma SEG(MakeObjectLink)
  2647. INTERNAL MakeObjectLink(LPDATAOBJECT pDataObj, LPSTREAM pStream,
  2648. LPHANDLE ph, BOOL fOwnerLink)
  2649. {
  2650. VDATEHEAP();
  2651. HRESULT hr;
  2652. LPMONIKER pmk = NULL; // the moniker reconstituted from the stream
  2653. LPOLESTR szFile = NULL;
  2654. size_t cbFile; // length of szFile, if not NULL
  2655. LPOLESTR szItem = NULL;
  2656. size_t cbItem; // length of szItem, if not NULL
  2657. CLSID clsid;
  2658. LPOLESTR pszCid = NULL;
  2659. size_t cbCid; // length of pszCid, if not NULL
  2660. #ifdef MAYBE_LATER
  2661. LPMONIKER pmkReduced= NULL;
  2662. LPBC pbc = NULL;
  2663. #endif // MAYBE_LATER
  2664. UINT cb; // length of string to allocate for object link
  2665. LPOLESTR pch; // used to rove over the object link and fill it in
  2666. LARGE_INTEGER large_integer; // sets the seek position in the stream
  2667. // validate ph
  2668. VDATEPTROUT(ph, HANDLE);
  2669. // initialize this in case of error returns
  2670. *ph = NULL;
  2671. // validate remaining parameters
  2672. VDATEIFACE(pDataObj);
  2673. VDATEIFACE(pStream);
  2674. // move to the beginning of the stream
  2675. LISet32(large_integer, 0);
  2676. if (NOERROR != (hr = pStream->Seek(large_integer, STREAM_SEEK_SET,
  2677. NULL)))
  2678. {
  2679. AssertSz (0, "Cannot seek to beginning of stream\r\n");
  2680. goto errRtn;
  2681. }
  2682. // get the link moniker in active form
  2683. if (NOERROR != (hr = OleLoadFromStream(pStream, IID_IMoniker,
  2684. (LPLPVOID)&pmk)))
  2685. {
  2686. AssertSz (0, "Cannot get moniker from stream");
  2687. goto errRtn;
  2688. }
  2689. #ifdef MAYBE_LATER
  2690. // Reduction
  2691. if (NOERROR != (hr = CreateBindCtx(&pbc)))
  2692. {
  2693. AssertSz(0, "Cannot create bind ctx");
  2694. goto errRtn;
  2695. }
  2696. if (NOERROR != (hr = pmk->Reduce(pbc, MKRREDUCE_ALL, NULL,
  2697. &pmkReduced)))
  2698. {
  2699. AssertSz(0, "Cannot reduce moniker");
  2700. goto errRtn;
  2701. }
  2702. if (pmkReduced != NULL)
  2703. {
  2704. pmk->Release();
  2705. pmk = pmkReduced;
  2706. pmkReduced = NULL; // for ref counting reasons
  2707. }
  2708. else
  2709. {
  2710. Assert (hr == MK_REDUCED_TO_SELF);
  2711. }
  2712. #endif // MAYBE_LATER
  2713. // We now have the moniker, pmk.
  2714. //REVIEW32 Ole10_ParseMoniker has been temporarily removed
  2715. if (!fOwnerLink /* && (NOERROR != Ole10_ParseMoniker(pmk,
  2716. &szFile, &szItem)) */)
  2717. {
  2718. // Not a File or File::Item moniker
  2719. hr = ReportResult(0, S_FALSE, 0, 0);
  2720. goto errRtn;
  2721. }
  2722. wSzFixNet(&szFile);
  2723. // Determine class to put in first piece of ObjectLink
  2724. if (NOERROR != ReadClassStm(pStream, &clsid))
  2725. {
  2726. // get the clsid if the link source for use in ObjectLink
  2727. if (NOERROR != (hr = GetClassFromDescriptor(pDataObj, &clsid,
  2728. TRUE, TRUE, NULL)))
  2729. {
  2730. AssertSz (0, "Cannot determine clsid for file");
  2731. goto errRtn;
  2732. }
  2733. }
  2734. if ((hr = ProgIDFromCLSID(clsid, &pszCid)) != NOERROR)
  2735. goto errRtn;
  2736. // Allocate the ObjectLink handle.
  2737. cb = (cbCid = _xstrlen(pszCid)) + (cbFile = _xstrlen(szFile)) +
  2738. (szItem ? (cbItem = _xstrlen(szItem)) : 0) +
  2739. 4; // for the \0's
  2740. *ph = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cb*sizeof(OLECHAR));
  2741. if (NULL == *ph)
  2742. {
  2743. hr= ReportResult(0, E_OUTOFMEMORY, 0, 0);
  2744. goto errRtn;
  2745. }
  2746. pch = (LPOLESTR)GlobalLock(*ph);
  2747. if (NULL == pch)
  2748. {
  2749. hr = ReportResult(0, E_OUTOFMEMORY, 0, 0);
  2750. GlobalFree(*ph);
  2751. *ph = NULL;
  2752. goto errRtn;
  2753. }
  2754. // Fill in the ObjectLink handle.
  2755. _xstrcpy(pch, pszCid);
  2756. pch += cbCid + 1; // skip over string and its null terminator
  2757. // add the filename, and skip over its null terminator
  2758. if ((NULL == szFile) || fOwnerLink)
  2759. *pch++ = '\0';
  2760. else
  2761. {
  2762. _xstrcpy(pch, szFile);
  2763. pch += cbFile + 1;
  2764. }
  2765. // embedded 2.0 objs should have no item
  2766. if ((NULL == szItem) || fOwnerLink)
  2767. *pch++ = '\0';
  2768. else
  2769. {
  2770. _xstrcpy(pch, szItem);
  2771. pch += cbItem + 1;
  2772. }
  2773. // add final null terminator
  2774. *pch++ = '\0';
  2775. GlobalUnlock(*ph);
  2776. errRtn:
  2777. if (pmk)
  2778. pmk->Release();
  2779. #ifdef MAYBE_LATER
  2780. if (pbc)
  2781. pbc->Release();
  2782. #endif // MAYBE_LATER
  2783. if (pszCid)
  2784. PubMemFree(pszCid);
  2785. if (szFile)
  2786. PubMemFree(szFile);
  2787. if (szItem)
  2788. PubMemFree(szItem);
  2789. return(hr);
  2790. }
  2791. #pragma SEG(wNativeStreamToHandle)
  2792. STATIC INTERNAL wNativeStreamToHandle(LPSTREAM pstm, LPHANDLE ph)
  2793. {
  2794. VDATEHEAP();
  2795. HRESULT hresult = NOERROR;
  2796. DWORD dwSize; // the size of the stream content, stored in the stream
  2797. LPVOID pv;
  2798. ErrRtnH(StRead(pstm, &dwSize, sizeof(DWORD)));
  2799. ErrZS(*ph = GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, dwSize),
  2800. E_OUTOFMEMORY);
  2801. ErrZS(pv = GlobalLock(*ph), E_OUTOFMEMORY);
  2802. ErrRtnH(StRead(pstm, pv, dwSize));
  2803. errRtn:
  2804. if (pv)
  2805. GlobalUnlock(*ph);
  2806. return(hresult);
  2807. }
  2808. #pragma SEG(wStorageToHandle)
  2809. STATIC INTERNAL wStorageToHandle(LPSTORAGE pstg, LPHANDLE ph)
  2810. {
  2811. VDATEHEAP();
  2812. CLSID clsid;
  2813. HRESULT hresult = NOERROR; // error state so far
  2814. LPLOCKBYTES plbData = NULL; // lock bytes on HGlobal instance
  2815. LPSTORAGE pstgLB = NULL; // IStorage on ILockBytes on HGlobal
  2816. // validate parameters
  2817. VDATEPTROUT(ph, HANDLE);
  2818. RetErr(CreateILockBytesOnHGlobal(NULL, /*fDeleteOnRelease*/ FALSE,
  2819. &plbData));
  2820. ErrRtnH(StgCreateDocfileOnILockBytes(plbData, STGM_CREATE | STGM_SALL,
  2821. 0, &pstgLB));
  2822. // We remove the cache streams first, then copy, for three reasons:
  2823. // 1. We are free to modify pstg; it was the result of a GetData.
  2824. // 2. The CopyTo will have less work.
  2825. // 3. Presumably the ultimate docfile on memory will be less sparse
  2826. // (since we are not removing anything from it).
  2827. // read the class id
  2828. // REVIEW, why? This is not ever used anywhere!!! Can we remove it?
  2829. ErrRtnH(ReadClassStg(pstg, &clsid));
  2830. // remove the cache streams
  2831. ErrRtnH(UtDoStreamOperation(pstg, NULL, OPCODE_REMOVE,
  2832. STREAMTYPE_CACHE));
  2833. // Copy what was given to us into a storage we can convert to a handle
  2834. ErrRtnH(pstg->CopyTo(0, NULL, NULL, pstgLB));
  2835. ErrRtnH(GetHGlobalFromILockBytes(plbData, ph));
  2836. errRtn:
  2837. if (plbData)
  2838. plbData->Release();
  2839. if (pstgLB)
  2840. pstgLB->Release();
  2841. return(hresult);
  2842. }
  2843. #pragma SEG(wProgIDFromCLSID)
  2844. FARINTERNAL wProgIDFromCLSID(REFCLSID clsid, LPOLESTR FAR* psz)
  2845. {
  2846. VDATEHEAP();
  2847. HRESULT hresult;
  2848. if (NOERROR == (hresult = ProgIDFromCLSID(clsid, psz)))
  2849. return(NOERROR);
  2850. if (IsEqualCLSID(clsid, CLSID_StdOleLink))
  2851. {
  2852. *psz = UtDupString(szStdOleLink);
  2853. return(NOERROR);
  2854. }
  2855. return(hresult);
  2856. }
  2857. #pragma SEG(wCLSIDFromProgID)
  2858. FARINTERNAL wCLSIDFromProgID(LPOLESTR szClass, LPCLSID pclsid,
  2859. BOOL fForceAssign)
  2860. {
  2861. VDATEHEAP();
  2862. size_t len;
  2863. LONG cbValue;
  2864. OLECHAR sz[400];
  2865. if (0 == _xstrcmp(szClass, szStdOleLink))
  2866. {
  2867. *pclsid = CLSID_StdOleLink;
  2868. return NOERROR;
  2869. }
  2870. #ifdef NEVER
  2871. //REVIEW32: taken out for the moment
  2872. return(ResultFromScode(E_NOTIMPL));
  2873. #endif // NEVER
  2874. // return(CLSIDFromOle1Class(szClass, pclsid, fForceAssign));
  2875. //REVIEW
  2876. // This code is taken directly from the original 16 bit ole2 release
  2877. // implementation of CLSIDFromOle1Class. The Ole1 compatibility lookup
  2878. // is omitted. That implementation was in base\compapi.cpp
  2879. len = _xstrlen(szClass);
  2880. _xmemcpy((void *)sz, szClass, len*sizeof(OLECHAR));
  2881. sz[len] = OLESTR('\\');
  2882. _xstrcpy(sz+len+1, OLESTR("Clsid"));
  2883. if (RegQueryValue(HKEY_CLASSES_ROOT, sz, sz, &cbValue) == 0)
  2884. return(CLSIDFromString(sz, pclsid));
  2885. return(ResultFromScode(REGDB_E_KEYMISSING));
  2886. }
  2887. #pragma SEG(wGetEmbeddedObjectOrSource)
  2888. FARINTERNAL wGetEmbeddedObjectOrSource (LPDATAOBJECT pDataObj,
  2889. LPSTGMEDIUM pmedium)
  2890. {
  2891. VDATEHEAP();
  2892. HRESULT hresult;
  2893. FORMATETC foretc;
  2894. // Prepare formatetc
  2895. INIT_FORETC(foretc);
  2896. foretc.tymed = TYMED_ISTORAGE;
  2897. // Prepare medium for GetDataHere calls
  2898. pmedium->pUnkForRelease = NULL;
  2899. pmedium->tymed = TYMED_ISTORAGE;
  2900. RetErr(StgCreateDocfile(NULL,
  2901. STGM_CREATE | STGM_SALL | STGM_DELETEONRELEASE,
  2902. 0, &(pmedium->pstg)));
  2903. // Try cfEmbeddedObject Here
  2904. foretc.cfFormat = cfEmbeddedObject;
  2905. hresult = pDataObj->GetDataHere(&foretc,pmedium);
  2906. if (NOERROR == hresult)
  2907. return NOERROR;
  2908. // Try cfEmbedSource Here
  2909. foretc.cfFormat = cfEmbedSource;
  2910. hresult = pDataObj->GetDataHere(&foretc,pmedium);
  2911. if (NOERROR == hresult)
  2912. return NOERROR;
  2913. // Prepare medium for GetData calls, free temp stg
  2914. ReleaseStgMedium(pmedium);
  2915. // Try cfEmbeddedObject
  2916. foretc.cfFormat = cfEmbeddedObject;
  2917. hresult = pDataObj->GetData(&foretc,pmedium);
  2918. AssertOutStgmedium(hresult, pmedium);
  2919. if (NOERROR == hresult)
  2920. return NOERROR;
  2921. // Try cfEmbedSource
  2922. foretc.cfFormat = cfEmbedSource;
  2923. hresult = pDataObj->GetData(&foretc,pmedium);
  2924. AssertOutStgmedium(hresult, pmedium);
  2925. if (NOERROR == hresult)
  2926. return NOERROR;
  2927. // Failure
  2928. return(ResultFromScode(DV_E_FORMATETC));
  2929. }
  2930. #pragma SEG(RenderOle1Format)
  2931. STATIC HANDLE RenderOle1Format(CLIPFORMAT cf, LPDATAOBJECT pDataObj)
  2932. {
  2933. VDATEHEAP();
  2934. HRESULT hresult; // errors state so far
  2935. STGMEDIUM stgm; // dummy storage medium where returned handle may
  2936. // be created
  2937. // following variables are initialized so they can be used in error
  2938. // condition cleanup at the end of the function
  2939. LPSTREAM pstmNative = NULL; // native format stream that some formats
  2940. // may use
  2941. LPOLESTR pszCid = NULL; // a string that is the object class name
  2942. HANDLE hMem = NULL; // return value
  2943. // initialize the storage medium
  2944. stgm.tymed = TYMED_NULL;
  2945. stgm.pstg = NULL;
  2946. stgm.pUnkForRelease = NULL;
  2947. if (cf == cfOwnerLink)
  2948. {
  2949. LPOLESTR szSrcOfCopy; // text name of object being transferred
  2950. LPOLESTR pMem; // access to locked hMem
  2951. size_t uCidLen; // length of pszCid
  2952. size_t uSrcOfCopyLen; // length of szSrcOfCopy
  2953. CLSID clsid; // class id of the object being transferred
  2954. // get the clsid from the object; we care about getting the link
  2955. // clsid if the object is indeed a link.
  2956. ErrRtnH(GetClassFromDescriptor(pDataObj, &clsid, FALSE,
  2957. FALSE, &szSrcOfCopy));
  2958. // cfObjectDescriptor -> OwnerLink szClassname\0\0\0\0
  2959. // converts the link clsid specially
  2960. ErrRtnH(wProgIDFromCLSID(clsid, &pszCid));
  2961. uCidLen = _xstrlen(pszCid);
  2962. uSrcOfCopyLen = szSrcOfCopy ? _xstrlen(szSrcOfCopy) : 0;
  2963. hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE,
  2964. (uCidLen + uSrcOfCopyLen + 4)* sizeof(OLECHAR));
  2965. ErrZS(hMem, E_OUTOFMEMORY);
  2966. pMem = (LPOLESTR)GlobalLock(hMem);
  2967. ErrZS(pMem, E_OUTOFMEMORY);
  2968. // create the owner link format
  2969. _xmemcpy((void FAR *)pMem, (const void FAR *)pszCid,
  2970. uCidLen*sizeof(OLECHAR));
  2971. pMem += uCidLen;
  2972. *pMem = OLESTR('\0');
  2973. _xmemcpy((void FAR *)++pMem, (const void FAR *)szSrcOfCopy,
  2974. uSrcOfCopyLen*sizeof(OLECHAR));
  2975. pMem += uSrcOfCopyLen;
  2976. *pMem = OLESTR('\0');
  2977. *++pMem = OLESTR('\0');
  2978. PubMemFree(szSrcOfCopy);
  2979. GlobalUnlock(hMem);
  2980. }
  2981. else if (cf == cfObjectLink)
  2982. {
  2983. FORMATETC foretc; // format descriptor for rendition request
  2984. INIT_FORETC(foretc);
  2985. // First check if cfObjectLink is offered by the DataObject
  2986. // directly. Servers do this when they want OLE1 containers
  2987. // to link to something different from what OLE2 containers
  2988. // link to. For instance, they may provide a wrapper object
  2989. // of their own class so OLE1 conatiners can link to the
  2990. // outside of an embedded object.
  2991. foretc.tymed = TYMED_HGLOBAL;
  2992. foretc.cfFormat = cfObjectLink;
  2993. hresult = pDataObj->GetData(&foretc, &stgm);
  2994. AssertOutStgmedium(hresult, &stgm);
  2995. if (NOERROR == hresult)
  2996. hMem = UtDupGlobal(stgm.hGlobal, GMEM_MOVEABLE);
  2997. else
  2998. {
  2999. // Otherwise generate the ObjectLink from cfLinkSource
  3000. foretc.tymed = TYMED_ISTREAM;
  3001. foretc.cfFormat = cfLinkSource;
  3002. hresult = pDataObj->GetData(&foretc,&stgm);
  3003. AssertOutStgmedium(hresult, &stgm);
  3004. if (hresult != NOERROR)
  3005. {
  3006. Warn("Could not GetData(cfLinkSource, TYMED_ISTREAM)");
  3007. return(NULL);
  3008. }
  3009. // cfLinkSource -> ObjectLink ==
  3010. // szClassName\0szFile\0szItem\0\0
  3011. ErrRtnH(MakeObjectLink(pDataObj, stgm.pstm, &hMem,
  3012. FALSE));
  3013. }
  3014. }
  3015. else if (cf == cfNative)
  3016. {
  3017. ErrRtnH(wGetEmbeddedObjectOrSource(pDataObj, &stgm));
  3018. if (NOERROR == stgm.pstg->OpenStream(OLE10_NATIVE_STREAM, NULL,
  3019. STGM_SALL, 0, &pstmNative))
  3020. {
  3021. ErrRtnH(wNativeStreamToHandle(pstmNative, &hMem));
  3022. }
  3023. else
  3024. {
  3025. ErrRtnH(wStorageToHandle(stgm.pstg, &hMem));
  3026. }
  3027. Assert(hMem);
  3028. }
  3029. else
  3030. {
  3031. // unknown format
  3032. return(NULL);
  3033. }
  3034. errRtn:
  3035. ReleaseStgMedium(&stgm);
  3036. if (pstmNative)
  3037. pstmNative->Release();
  3038. if ((hresult != NOERROR) && (hMem != NULL))
  3039. {
  3040. GlobalFree(hMem);
  3041. hMem = NULL;
  3042. }
  3043. PubMemFree(pszCid);
  3044. return(hMem);
  3045. }
  3046. #pragma SEG(RenderFormatAndAspect)
  3047. STATIC HANDLE RenderFormatAndAspect(CLIPFORMAT cf, LPDATAOBJECT pDataObj,
  3048. DWORD dwAspect)
  3049. {
  3050. VDATEHEAP();
  3051. HRESULT hresult;
  3052. HANDLE hMem; // the return value
  3053. FORMATETC foretc; // the format descriptor for data requests based on cf
  3054. STGMEDIUM stgm; // the storage medium for data requests
  3055. // REVIEW: if object can't return hglobal probably should try all
  3056. // possible mediums, convert to hglobal. For now only try hglobal.
  3057. // initialize format descriptor
  3058. INIT_FORETC(foretc);
  3059. foretc.cfFormat = cf;
  3060. foretc.tymed = UtFormatToTymed(cf);
  3061. foretc.dwAspect = dwAspect;
  3062. // initialize medium for fetching
  3063. stgm.tymed = TYMED_NULL;
  3064. stgm.hGlobal = NULL;
  3065. hresult = pDataObj->GetData(&foretc, &stgm);
  3066. AssertOutStgmedium(hresult, &stgm);
  3067. if (hresult != NOERROR)
  3068. goto ErrorExit;
  3069. if (stgm.pUnkForRelease == NULL)
  3070. hMem = stgm.hGlobal;
  3071. else
  3072. {
  3073. hMem = OleDuplicateData(stgm.hGlobal, foretc.cfFormat,
  3074. GMEM_DDESHARE | GMEM_MOVEABLE);
  3075. ReleaseStgMedium(&stgm);
  3076. }
  3077. return(hMem);
  3078. ErrorExit:
  3079. return(NULL);
  3080. }
  3081. #pragma SEG(RenderFormat)
  3082. STATIC HANDLE RenderFormat(CLIPFORMAT cf, LPDATAOBJECT pDataObj)
  3083. {
  3084. VDATEHEAP();
  3085. HANDLE h;
  3086. if (h = RenderFormatAndAspect(cf, pDataObj, DVASPECT_CONTENT))
  3087. return(h);
  3088. if (h = RenderFormatAndAspect(cf, pDataObj, DVASPECT_DOCPRINT))
  3089. return(h);
  3090. if (h = RenderFormatAndAspect(cf, pDataObj, DVASPECT_THUMBNAIL))
  3091. return(h);
  3092. return(RenderFormatAndAspect(cf, pDataObj, DVASPECT_ICON));
  3093. }
  3094. // Mapping of thread ID to a clipboard window handle.
  3095. // WIN32 : Only looks for thread IDs of the current process; resides in
  3096. // instance data.
  3097. // REVIEW, if the OLE compound document model is single-threaded, do we need
  3098. // this? There should only be one thread ID => one window handle
  3099. STATIC CMapUintHwnd FAR * pTaskToClip = NULL;
  3100. #ifndef _MAC
  3101. // Get clipboard window handle of the current process.
  3102. //
  3103. #pragma SEG(GetClipboardWindow)
  3104. HWND GetClipboardWindow(void)
  3105. {
  3106. VDATEHEAP();
  3107. HWND hwnd;
  3108. if ((NULL == pTaskToClip) &&
  3109. (pTaskToClip = new CMapUintHwnd()) == NULL)
  3110. return NULL;
  3111. if (!pTaskToClip->Lookup(GetCurrentThreadId(), hwnd))
  3112. {
  3113. // Create an invisible window which will handle all of this
  3114. // app's delay rendering messages. Even though hInstance is
  3115. // specified as being the DLL's rather than the app's, the
  3116. // thread whose stack this function is called with is the one
  3117. // whose msg queue will be associated with this window.
  3118. hwnd = CreateWindow(szClipboardWndClass, OLESTR(""), WS_POPUP,
  3119. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  3120. CW_USEDEFAULT, NULL, NULL, hmodOLE2,
  3121. NULL);
  3122. if (hwnd != NULL)
  3123. Verify(pTaskToClip->SetAt(GetCurrentThreadId(), hwnd));
  3124. }
  3125. return(hwnd);
  3126. }
  3127. #endif // _MAC
  3128. // this keeps track of the number of times the clipboard has been
  3129. // initialized; it is incremented for each initialization, and decremented
  3130. // for each uninitialization
  3131. // REVIEW, does this variable have to be per-thread, or per-process for the DLL?
  3132. STATIC ULONG cClipboardInit = 0;
  3133. #pragma SEG(ClipboardInitialize)
  3134. FARINTERNAL_(BOOL) ClipboardInitialize(void)
  3135. {
  3136. VDATEHEAP();
  3137. #ifndef _MAC
  3138. WNDCLASS wc;
  3139. // One time initializtaion (when loaded for the first time)
  3140. if (cClipboardInit++ == 0)
  3141. {
  3142. // The first process to load this DLL
  3143. // Register Clipboard window class
  3144. wc.style = 0;
  3145. wc.lpfnWndProc = ClipboardWndProc;
  3146. wc.cbClsExtra = 0;
  3147. wc.cbWndExtra = 4; // REVIEW, what's this the sizeof()?
  3148. wc.hInstance = hmodOLE2;
  3149. wc.hIcon = NULL;
  3150. wc.hCursor = NULL;
  3151. wc.hbrBackground = NULL;
  3152. wc.lpszMenuName = NULL;
  3153. wc.lpszClassName = szClipboardWndClass;
  3154. // register this window class, returning if we fail
  3155. if (!RegisterClass(&wc))
  3156. {
  3157. cClipboardInit--;
  3158. return(FALSE);
  3159. }
  3160. }
  3161. // Remove the current htask from the map; the only reason this
  3162. // htask would be in the map is that it got reused
  3163. // REVIEW, if CD model is single threaded, do we need this?
  3164. if (pTaskToClip != NULL)
  3165. pTaskToClip->RemoveKey(GetCurrentThreadId());
  3166. #endif // _MAC
  3167. return(TRUE);
  3168. }
  3169. //+-------------------------------------------------------------------------
  3170. //
  3171. // Function: ClipboardUninitialize
  3172. //
  3173. // Synopsis:
  3174. //
  3175. // Effects:
  3176. //
  3177. // Modifies:
  3178. //
  3179. // Algorithm:
  3180. //
  3181. // History: 15-Feb-94 AlexT Added delete call (and this comment block)
  3182. //
  3183. // Notes:
  3184. //
  3185. //--------------------------------------------------------------------------
  3186. #pragma SEG(ClipboardUninitialize)
  3187. FARINTERNAL_(void) ClipboardUninitialize(void)
  3188. {
  3189. VDATEHEAP();
  3190. #ifndef _MAC
  3191. HWND hwnd;
  3192. // REVIEW, do we need this pTaskToClip stuff?
  3193. if (pTaskToClip != NULL &&
  3194. pTaskToClip->Lookup(GetCurrentThreadId(), hwnd))
  3195. {
  3196. DestroyWindow(hwnd);
  3197. pTaskToClip->RemoveKey(GetCurrentThreadId());
  3198. }
  3199. // Last process using this DLL?
  3200. if (--cClipboardInit == 0)
  3201. {
  3202. // NULL out in case dll is not actually unloaded
  3203. delete pTaskToClip;
  3204. pTaskToClip = NULL;
  3205. // since the last reference has gone away, unregister wnd class
  3206. UnregisterClass(szClipboardWndClass, hmodOLE2);
  3207. }
  3208. #endif // _MAC
  3209. }
  3210. STATIC INTERNAL_(BOOL) wEmptyClipboard(void)
  3211. {
  3212. VDATEHEAP();
  3213. OleRemoveEnumFormatEtc(TRUE /*fClip*/);
  3214. return(EmptyClipboard());
  3215. }