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.

4658 lines
143 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996.
  5. //
  6. // File: clipapi.cpp
  7. //
  8. // Contents: Clipboard related OLE API's
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. // OleFlushClipboard
  14. // OleGetClipboard
  15. // OleIsCurrentClipboard
  16. // OleSetClipboard
  17. //
  18. // History: dd-mmm-yy Author Comment
  19. // 12-Aug-94 alexgo added support for transfering
  20. // DVASPECT_ICON, etc.
  21. // 08-Aug-94 BruceMa Memory sift fix
  22. // 10-Jun-94 alexgo added support for OLE1 Containers
  23. // 17-May-94 alexgo created OleOpenClipboard and enhanced
  24. // code to mimize the times when the
  25. // clipboard is kept open.
  26. // 25-Apr-94 alexgo made thread-safe for the apartment model
  27. // 16-Mar-94 alexgo author
  28. //
  29. //--------------------------------------------------------------------------
  30. #include <le2int.h>
  31. #include <getif.hxx>
  32. #include <clipbrd.h>
  33. #include <olesem.hxx>
  34. #include <ostm2stg.h> // for wProgIDFromCLSID
  35. #include "clipdata.h"
  36. //
  37. // types local to this file
  38. //
  39. typedef enum tagCLIPWNDFLAGS
  40. {
  41. CLIPWND_REMOVEFROMCLIPBOARD = 1,
  42. CLIPWND_IGNORECLIPBOARD = 2,
  43. CLIPWND_DONTCALLAPP = 4
  44. } CLIPWNDFLAGS;
  45. typedef enum tagGETCLSIDFLAGS
  46. {
  47. USE_NORMAL_CLSID = 1,
  48. USE_STANDARD_LINK = 2,
  49. } GETCLSIDFLAGS;
  50. //
  51. // functions local to this file. They are not "static" so the symbols
  52. // show up in ntsd debug builds.
  53. //
  54. extern "C" LRESULT ClipboardWndProc( HWND, UINT, WPARAM, LPARAM );
  55. HRESULT GetDataFromDescriptor(IDataObject *pDataObj, LPCLSID pclsid,
  56. UINT cf, GETCLSIDFLAGS fFlags,
  57. LPOLESTR *ppszSrcOfCopy,
  58. DWORD *pdwStatus);
  59. HRESULT GetDataFromStorage(IDataObject *pDataObj, UINT cf,
  60. STGMEDIUM *pmedium, IStorage **ppstg);
  61. HRESULT GetDataFromStream(IDataObject *pDataObj, UINT cf,
  62. STGMEDIUM *pmedium, IStream **ppstm);
  63. HRESULT GetNative(IDataObject *pDataObj, STGMEDIUM *pmedium);
  64. HRESULT GetObjectLink(IDataObject *pDataObj, STGMEDIUM *pmedium);
  65. HRESULT GetOwnerLink(IDataObject *pDataObj, STGMEDIUM *pmedium);
  66. HRESULT HandleFromHandle(IDataObject *pDataObj, FORMATETC *pformatetc,
  67. STGMEDIUM *pmedium);
  68. HRESULT MapCFToFormatetc( UINT cf, FORMATETC *pformatetc );
  69. HRESULT RemoveClipboardDataObject( HWND hClipWnd, DWORD fFlags );
  70. HRESULT RenderFormat( HWND hClipWnd, UINT cf, IDataObject *pDataObj );
  71. HRESULT SetClipboardDataObject( HWND hClipWnd, IDataObject *pDataObj );
  72. HRESULT SetClipboardFormats( HWND hClipWnd, IDataObject *pDataObj );
  73. HWND VerifyCallerIsClipboardOwner( void );
  74. HGLOBAL PersistDataObjectToHGlobal(IDataObject *lpDataObj);
  75. HRESULT LoadPersistedDataObjectFromHGlobal(HGLOBAL hglobal,
  76. IDataObject **ppDataObj);
  77. void SetClipDataObjectInTLS(IDataObject **ppDataObj, DWORD dwClipSeqNum,
  78. BOOL fIsClipWrapper);
  79. void GetClipDataObjectFromTLS(IDataObject **ppDataObj);
  80. HRESULT CreateClipDataObjectFromPersistedData(IDataObject **ppDataObj);
  81. HRESULT CreateWrapperClipDataObjectFromFormatsArray(IDataObject **ppDataObj);
  82. //
  83. //static variables
  84. //
  85. // vcClipboardInit is used to keep track of the number of times Clipboard
  86. // Initialize is called (right now, only from OleInitialize), so that we
  87. // only create a private clipboard window class once per dll (even though
  88. // the many threads may need their own instance of the window class in the
  89. // apartment model).
  90. static ULONG vcClipboardInit;
  91. // vszClipboardWndClass is the name of the window class used by OLE to
  92. // create private clipboard windows for copy/paste and other clipboard
  93. // data transfers.
  94. #ifdef _CHICAGO_
  95. // Note: we have to create a unique string so that get
  96. // register a unique class for each 16 bit app.
  97. // The class space is global on chicago.
  98. //
  99. char g_vszClipboardWndClass[] = "CLIPBRDWNDCLASS 0x######## ";
  100. #define vszClipboardWndClass g_vszClipboardWndClass
  101. #define ClpWNDCLASS WNDCLASSA
  102. #define ClpRegisterClass RegisterClassA
  103. #define ClpUnregisterClass UnregisterClassA
  104. #define ClpCreateWindowEx SSCreateWindowExA
  105. #else
  106. static const OLECHAR vszClipboardWndClass[] = OLESTR("CLIPBRDWNDCLASS");
  107. #define ClpWNDCLASS WNDCLASS
  108. #define ClpRegisterClass RegisterClass
  109. #define ClpUnregisterClass UnregisterClass
  110. #define ClpCreateWindowEx CreateWindowEx
  111. #endif
  112. // Mutex used to synchronize clipboard initialization / cleanup
  113. extern COleStaticMutexSem g_mxsSingleThreadOle;
  114. extern ATOM g_aDropTargetMarshalHwnd; // Atom for Delayed DragDrop Marshaling.
  115. // WindowLong Offset for storing private data.
  116. // so don't have to go to the clipboard to fetch it.
  117. #define WL_ClipPrivateData 0
  118. //
  119. // functions (in alphabetical order)
  120. //
  121. //+-------------------------------------------------------------------------
  122. //
  123. // Function: ClipboardInitialize (private)
  124. //
  125. // Synopsis: Creates the private clipboard window class (if necessary)
  126. //
  127. // Effects:
  128. //
  129. // Arguments: void
  130. //
  131. // Requires: hmodOLE2 must be initialized
  132. //
  133. // Returns: TRUE upon success, false otherwise
  134. //
  135. // Signals:
  136. //
  137. // Modifies:
  138. //
  139. // Algorithm: Register the clipboard class only once per dll instance
  140. // (or more specifically, every time vcClipboardInit == 0,
  141. // which may happen multiple times in a WOW box).
  142. //
  143. // History: dd-mmm-yy Author Comment
  144. // 23-Oct-94 alexgo fixed up Chicago WOW hacks (see comments)
  145. // 25-Apr-94 alexgo updated to the apartment model
  146. // 16-Mar-94 alexgo author
  147. //
  148. // Notes:
  149. //
  150. //--------------------------------------------------------------------------
  151. BOOL ClipboardInitialize( void )
  152. {
  153. ClpWNDCLASS wc;
  154. BOOL fRet = TRUE;
  155. VDATEHEAP();
  156. LEDebugOut((DEB_ITRACE, "%p _IN ClipboardInitialize ( )\n", NULL));
  157. // serialize access to this function
  158. // we'll unlock the mutex automatically in "lck"'s destructor
  159. // (called at function exit)
  160. COleStaticLock lck(g_mxsSingleThreadOle);
  161. // One time initializtaion (when loaded for the first time)
  162. if (vcClipboardInit == 0)
  163. {
  164. #ifdef _CHICAGO_
  165. if (IsWOWThread())
  166. {
  167. wsprintfA(vszClipboardWndClass,"CLIPBRDWNDCLASS %08X",
  168. CoGetCurrentProcess());
  169. }
  170. #endif // _CHICAGO_
  171. // Register Clipboard window class
  172. wc.style = 0;
  173. wc.lpfnWndProc = ClipboardWndProc;
  174. wc.cbClsExtra = 0;
  175. wc.cbWndExtra = sizeof(void *);
  176. AssertSz(g_hmodOLE2, "Dll instance variable not set");
  177. wc.hInstance = g_hmodOLE2; //global vairable set in
  178. //ole2.cpp
  179. wc.hIcon = NULL;
  180. wc.hCursor = NULL;
  181. wc.hbrBackground = NULL;
  182. wc.lpszMenuName = NULL;
  183. wc.lpszClassName = vszClipboardWndClass;
  184. // register this window class, returning if we fail
  185. if (!ClpRegisterClass(&wc))
  186. {
  187. LEWARN(FALSE, "ClipboardInitialize RegisterClass failed!");
  188. // it is possible that our dll got unloaded without us
  189. // having called unregister, so we call it here and try
  190. // again.
  191. ClpUnregisterClass( vszClipboardWndClass, g_hmodOLE2 );
  192. if (!ClpRegisterClass(&wc))
  193. {
  194. LEWARN(FALSE, "ClipboardInitialize RegisterClass failed again!");
  195. LEDebugOut((DEB_WARN,
  196. "WARNING: RegisterClass failed\n"));
  197. fRet = FALSE;
  198. goto errRtn;
  199. }
  200. }
  201. vcClipboardInit++;
  202. }
  203. errRtn:
  204. LEDebugOut((DEB_ITRACE, "%p OUT ClipboardIntialize ( %lu )\n",
  205. NULL, fRet));
  206. return fRet;
  207. }
  208. //+-------------------------------------------------------------------------
  209. //
  210. // Function: ClipboardUnitialize (internal)
  211. //
  212. // Synopsis: Uninitializes the clipboard for the current thread.
  213. //
  214. // Effects:
  215. //
  216. // Arguments: void
  217. //
  218. // Returns: void
  219. //
  220. // Signals:
  221. //
  222. // Modifies:
  223. //
  224. // Algorithm:
  225. //
  226. // History: dd-mmm-yy Author Comment
  227. // 23-Oct-94 alexgo fixed up Chicago WOW hacks (see comments)
  228. // 25-Apr-94 alexgo made thread-safe
  229. // 16-Mar-94 alexgo author
  230. //
  231. // Notes:
  232. //
  233. //--------------------------------------------------------------------------
  234. void ClipboardUninitialize(void)
  235. {
  236. HRESULT hrTls;
  237. VDATEHEAP();
  238. //
  239. // This cleanup is done during OleUninitialize, but not
  240. // if somebody does FreeLibrary(OLE32.DLL). That would cause
  241. // us to leak the class register and any clipboard window. We have
  242. // gotten around the class re-register problem above in the
  243. // ClipboardInitialize function, but we still leak a window.
  244. //
  245. // But since it is illegal to unload OLE32 without uninitializing
  246. // first, whoever does that can fully expect all kinds of leaks.
  247. //
  248. LEDebugOut((DEB_ITRACE, "%p _IN ClipboardUninitialize ( )\n", NULL));
  249. COleTls tls(hrTls);
  250. if (NOERROR == hrTls)
  251. {
  252. #ifndef _CHICAGO_
  253. if(tls->pDataObjClip)
  254. {
  255. if (tls->fIsClipWrapper)
  256. {
  257. ((CClipDataObject *)tls->pDataObjClip)->InternalRelease();
  258. }
  259. else
  260. {
  261. (tls->pDataObjClip)->Release();
  262. }
  263. tls->pDataObjClip = NULL;
  264. }
  265. #endif // _CHICAGO_
  266. if(tls->hwndClip)
  267. {
  268. // destroy the window and NULL out the hwnd in the thread
  269. // storage
  270. Verify(SSDestroyWindow(tls->hwndClip));
  271. tls->hwndClip = NULL;
  272. }
  273. }
  274. }
  275. //+-------------------------------------------------------------------------
  276. //
  277. // Function: ClipboardProcessUnitialize (internal)
  278. //
  279. // Synopsis: Uninitializes the clipboard. If this the last such time,
  280. // then the private clipboard window class is unregistered.
  281. //
  282. // Effects:
  283. //
  284. // Arguments: void
  285. //
  286. // Requires: hmodOLE2 must be initialized before calling this function
  287. //
  288. // Returns: void
  289. //
  290. // Signals:
  291. //
  292. // Modifies:
  293. //
  294. // Algorithm:
  295. //
  296. // History: dd-mmm-yy Author Comment
  297. // 23-Oct-94 alexgo fixed up Chicago WOW hacks (see comments)
  298. // 25-Apr-94 alexgo made thread-safe
  299. // 16-Mar-94 alexgo author
  300. //
  301. // Notes:
  302. //
  303. //--------------------------------------------------------------------------
  304. void ClipboardProcessUninitialize(void)
  305. {
  306. // serialize access for the apartment model
  307. COleStaticLock lck(g_mxsSingleThreadOle);
  308. if(vcClipboardInit == 1)
  309. {
  310. vcClipboardInit--;
  311. BOOL fRet = ClpUnregisterClass(vszClipboardWndClass,
  312. g_hmodOLE2);
  313. LEWARN(!fRet, "UnRegisterClass failed!");
  314. }
  315. LEDebugOut((DEB_ITRACE, "%p OUT ClipboardUninitialize ( )\n", NULL));
  316. }
  317. //+-------------------------------------------------------------------------
  318. //
  319. // Function: ClipboardWndProc
  320. //
  321. // Synopsis: Window message procedure for the private clipboard window
  322. //
  323. // Effects:
  324. //
  325. // Arguments: [hWnd] -- handle to private clipboard window
  326. // [msg] -- the Window message
  327. // [wParam] -- parameter 1
  328. // [lParam] -- parameter 2
  329. //
  330. // Requires:
  331. //
  332. // Returns: LRESULT
  333. //
  334. // Signals:
  335. //
  336. // Modifies:
  337. //
  338. // Algorithm: processes messages sent to the private clipboard window:
  339. // WM_DESTROYCLIPBOARD: somebody else is taking ownership
  340. // of the clipboard, so release the data object
  341. // (if any)
  342. // WM_RENDERFORMAT: a request has been made for data of the
  343. // specified format--actually put it on the clipboard
  344. // WM_RENDERALLFORMATS: the app is going away, so empty the
  345. // clipboard! The app is supposed to call
  346. // OleFlushClipboard before exiting, if it hasn't, then
  347. // we can only assume that the app is terminating
  348. // "abnormally". We currently do nothing for this call
  349. //
  350. // History: dd-mmm-yy Author Comment
  351. // 23-Oct-94 alexgo added support for eating WM_CANCELMODE
  352. // messages
  353. // 20-Mar-94 alexgo author
  354. //
  355. // Notes:
  356. //
  357. //--------------------------------------------------------------------------
  358. extern "C" LRESULT ClipboardWndProc( HWND hWnd, UINT msg, WPARAM wParam,
  359. LPARAM lParam )
  360. {
  361. LRESULT lresult = 0;
  362. IDataObject * pDataObj = NULL;
  363. UINT cf;
  364. HRESULT hresult;
  365. VDATEHEAP();
  366. LEDebugOut((DEB_ITRACE, "%p _IN ClipboardWndProc ( %lx , %u , %lu ,"
  367. " %ld )\n", NULL, hWnd, msg, wParam, lParam));
  368. AssertSz((GetCurrentThreadId()
  369. == GetWindowThreadProcessId(hWnd, NULL)),
  370. "Clip window not on current thread");
  371. switch( msg )
  372. {
  373. // note that the clipboard should *NOT* be opened for these messages
  374. case WM_OLE_CLIPBRD_MARSHALDROPTARGET:
  375. {
  376. HWND hwndDropTarget = (HWND) lParam;
  377. // Request has come through to marshal the DropTarget
  378. // Associated with the hwndDropTarget.
  379. // Assign the Endpoint Property, If Success, remove the property.
  380. if(NOERROR == AssignEndpointProperty(hwndDropTarget))
  381. {
  382. Win4Assert(NULL != g_aDropTargetMarshalHwnd);
  383. RemoveProp(hwndDropTarget,(LPCWSTR) g_aDropTargetMarshalHwnd);
  384. }
  385. }
  386. break;
  387. case WM_RENDERALLFORMATS:
  388. // this message is sent to us if this window (the private
  389. // clipboard window) is about to be destroyed.
  390. // We don't currently do anything for this message.
  391. // REVIEW: in the future, we may want to render all the
  392. // remaining formats. However, the app is *supposed* to
  393. // call OleFlushClipboard to accomplish this task.
  394. Assert(lresult == 0);
  395. break;
  396. case WM_DESTROYCLIPBOARD:
  397. // we get this message when somebody else takes ownership
  398. // of the clipboard. Since our app may have an AddRef'ed
  399. // data object already there, we need to remove it.
  400. // there is no need to open the clipboard (since we specify
  401. // the IGNORECLIPBOARD flag)
  402. RemoveClipboardDataObject(hWnd, CLIPWND_IGNORECLIPBOARD);
  403. Assert(lresult == 0);
  404. break;
  405. case WM_RENDERFORMAT:
  406. cf = (UINT)wParam;
  407. pDataObj = (IDataObject *)GetProp( hWnd,
  408. CLIPBOARD_DATA_OBJECT_PROP);
  409. if( !pDataObj )
  410. {
  411. LEDebugOut((DEB_ERROR, "ERROR!: No data object "
  412. "on the private window\n"));
  413. break;
  414. }
  415. // now render the data onto the clipboard
  416. hresult = RenderFormat( hWnd, cf, pDataObj);
  417. #if DBG == 1
  418. if( hresult != NOERROR )
  419. {
  420. char szBuf[256];
  421. char *pszBuf;
  422. // we have to do predefined formats by hand
  423. if( cf > 0xC000 )
  424. {
  425. SSGetClipboardFormatNameA(cf, szBuf, 256);
  426. pszBuf = szBuf;
  427. }
  428. else
  429. {
  430. switch( cf )
  431. {
  432. case CF_METAFILEPICT:
  433. pszBuf = "CF_METAFILEPICT";
  434. break;
  435. case CF_BITMAP:
  436. pszBuf = "CF_BITMAP";
  437. break;
  438. case CF_DIB:
  439. pszBuf = "CF_DIB";
  440. break;
  441. case CF_PALETTE:
  442. pszBuf = "CF_PALETTE";
  443. break;
  444. case CF_TEXT:
  445. pszBuf = "CF_TEXT";
  446. break;
  447. case CF_UNICODETEXT:
  448. pszBuf = "CF_UNICODETEXT";
  449. break;
  450. case CF_ENHMETAFILE:
  451. pszBuf = "CF_ENHMETAFILE";
  452. break;
  453. default:
  454. pszBuf = "UNKNOWN Default Format";
  455. break;
  456. }
  457. }
  458. LEDebugOut((DEB_WARN, "WARNING: Unable to render "
  459. "format '%s' (%x)\n", pszBuf, cf));
  460. }
  461. #endif // DBG == 1
  462. Assert(lresult == 0);
  463. break;
  464. case WM_CANCELMODE:
  465. // we want to swallow the WM_CANCELMODE message. This
  466. // allows us to start drag drop, alt-tab to another app
  467. // (which causes a WM_CANCELMODE message) and continue
  468. // dragging.
  469. Assert(lresult == 0);
  470. break;
  471. case WM_DESTROY:
  472. // apps are supposed to call OleSetClipboard(NULL) or
  473. // OleFlushClipboard() before terminating a thread. However,
  474. // not all apps do what they're supposed to, so just
  475. // remove as much state as we can safely do
  476. // Potentially, we could use CLIPWND_REMOVEFROMCLIPBOARD
  477. // here. However, getting in this situation should be
  478. // somewhat unusual, so we don't want to do any more work
  479. // than absolutely necessary. Even though we'll leave a
  480. // hwnd on the clipboard in g_cfDataObject, that hwnd
  481. // will soon be invalid (because it's the one getting this
  482. // WM_DESTROY message).
  483. #if DBG == 1
  484. // do some debug checking first though
  485. if( GetWindowLongPtr( hWnd, WL_ClipPrivateData) != 0 )
  486. {
  487. LEDebugOut((DEB_WARN, "WARNING: App did not cleanup the "
  488. "clipboard properly, OleSetClipboard(NULL) or "
  489. "OleFlushClipboard not called"));
  490. }
  491. #endif // DBG == 1
  492. RemoveClipboardDataObject(hWnd, (CLIPWND_DONTCALLAPP |
  493. CLIPWND_IGNORECLIPBOARD));
  494. Assert(lresult == 0);
  495. break;
  496. default:
  497. lresult = SSDefWindowProc( hWnd, msg, wParam, lParam);
  498. break;
  499. }
  500. LEDebugOut((DEB_ITRACE, "%p OUT ClipboardWndProc ( %ld )\n", NULL,
  501. lresult));
  502. return lresult;
  503. }
  504. //+-------------------------------------------------------------------------
  505. //
  506. // Function: ClipSetCaptureForDrag
  507. //
  508. // Synopsis: Sets mouse capture mode for a drag operation
  509. //
  510. // Arguments: [pdrgop] - pointer to object that handles drag operation
  511. //
  512. // Returns: S_OK -- it worked
  513. // E_FAIL -- unexpected failure occurred.
  514. //
  515. // Algorithm: Get the clipboard window for the thread. Record the drag
  516. // drag operation pointer on the window for use by capture
  517. // mode. then turn on capture mode.
  518. //
  519. // History: dd-mmm-yy Author Comment
  520. // 21-Apr-94 ricksa created
  521. //
  522. // Notes: The purpose of this function is to hide where the drag
  523. // pointer is stored for the window.
  524. //
  525. //--------------------------------------------------------------------------
  526. HRESULT ClipSetCaptureForDrag(CDragOperation *pdrgop)
  527. {
  528. // Default to failure
  529. HRESULT hr = ResultFromScode(E_FAIL);
  530. // We will use the clipboard window to capture the mouse but we
  531. // must have a clipboard window so we make sure it is created
  532. // if it is not already there.
  533. HWND hWndClip = GetPrivateClipboardWindow(CLIP_CREATEIFNOTTHERE);
  534. if (hWndClip != NULL)
  535. {
  536. AssertSz((GetCurrentThreadId()
  537. == GetWindowThreadProcessId(hWndClip, NULL)),
  538. "Clip window not on current thread");
  539. // Capture the mouse
  540. SetCapture(hWndClip);
  541. // Teller the caller that we worked.
  542. hr = NOERROR;
  543. }
  544. return hr;
  545. }
  546. //+-------------------------------------------------------------------------
  547. //
  548. // Function: ClipReleaseCaptureForDrag
  549. //
  550. // Synopsis: Clean up drag mouse capture
  551. //
  552. // Algorithm: Get the clipboard window for the thread. Turn the drag
  553. // operation pointer into null. Then release the capture.
  554. //
  555. // History: dd-mmm-yy Author Comment
  556. // 21-Apr-94 ricksa created
  557. //
  558. // Notes: It is assumed that the clip board window and the thread
  559. // doing drag and drop are on the same thread. Therefore,
  560. // there should be no race between clean up here and
  561. // the use of the pointer in the clipboard window proc.
  562. //
  563. //--------------------------------------------------------------------------
  564. void ClipReleaseCaptureForDrag(void)
  565. {
  566. // Stop the mouse capture
  567. ReleaseCapture();
  568. }
  569. //+-------------------------------------------------------------------------
  570. //
  571. // Function: GetDataFromDescriptor
  572. //
  573. // Synopsis: Retrieves object descriptor data from the specified
  574. // clipboard format and fetches the clsid, SrcOfCopy
  575. // string, and status flags
  576. //
  577. // Effects:
  578. //
  579. // Arguments: [pDataObj] -- the source data object
  580. // [pclsid] -- where to put the clsid
  581. // [cf] -- the clipboard format to retrieve
  582. // [fFlags] -- clsid conversion flags
  583. // [ppszSrcOfCopy] -- where to put an ALLOCATED (public
  584. // allocator) copy of the SrcOfCopy
  585. // string.
  586. // [pdwStatus] -- where to put the status bits
  587. //
  588. // Requires:
  589. //
  590. // Returns: HRESULT
  591. //
  592. // Signals:
  593. //
  594. // Modifies:
  595. //
  596. // Algorithm: see synopsis
  597. //
  598. // History: dd-mmm-yy Author Comment
  599. // 18-Aug-94 alexgo added support for fetching dwStatus
  600. // 10-Jun-94 alexgo author
  601. //
  602. // Notes:
  603. //
  604. //--------------------------------------------------------------------------
  605. HRESULT GetDataFromDescriptor(IDataObject *pDataObj, LPCLSID pclsid,
  606. UINT cf, GETCLSIDFLAGS fFlags,
  607. LPOLESTR *ppszSrcOfCopy,
  608. DWORD *pdwStatus)
  609. {
  610. HRESULT hresult;
  611. FORMATETC formatetc;
  612. STGMEDIUM medium;
  613. LPOBJECTDESCRIPTOR pObjDesc;
  614. VDATEHEAP();
  615. LEDebugOut((DEB_ITRACE, "%p _IN GetDataFromDescriptor ( %p , "
  616. "%p , %d , %lx , %p, %p )\n", NULL, pDataObj, pclsid, cf,
  617. fFlags, ppszSrcOfCopy, pdwStatus));
  618. // we don't bother with extensive attempts to fetch the
  619. // OLE2 data since we're only using it to construct OLE1. If
  620. // the data is offered in a non-standard way, the the worse
  621. // that will happen is that you can't paste an *object* to
  622. // an OLE1 container. 16bit was even more strict in that
  623. // you *always* had to offer OLE2 formats on standard mediums.
  624. INIT_FORETC(formatetc);
  625. formatetc.cfFormat = (CLIPFORMAT) cf;
  626. formatetc.tymed = TYMED_HGLOBAL;
  627. _xmemset(&medium, 0, sizeof(STGMEDIUM));
  628. hresult = pDataObj->GetData(&formatetc, &medium);
  629. if( hresult != NOERROR )
  630. {
  631. goto logRtn;
  632. }
  633. Win4Assert(medium.tymed != TYMED_NULL);
  634. pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(medium.hGlobal);
  635. if( !pObjDesc )
  636. {
  637. hresult = ResultFromScode(E_OUTOFMEMORY);
  638. goto errRtn;
  639. }
  640. if( pclsid )
  641. {
  642. // if we want to use the standard link AND the object really
  643. // is a link object (potentially a custom link), then
  644. // just set the clsid to the be the standard link object
  645. if( (fFlags & USE_STANDARD_LINK) &&
  646. (pObjDesc->dwStatus & OLEMISC_ISLINKOBJECT) )
  647. {
  648. *pclsid = CLSID_StdOleLink;
  649. }
  650. else
  651. {
  652. *pclsid = pObjDesc->clsid;
  653. }
  654. }
  655. if( ppszSrcOfCopy )
  656. {
  657. if( pObjDesc->dwSrcOfCopy )
  658. {
  659. *ppszSrcOfCopy = UtDupString(
  660. (LPOLESTR)(((BYTE *)pObjDesc)+pObjDesc->dwSrcOfCopy));
  661. }
  662. else
  663. {
  664. *ppszSrcOfCopy = UtDupString(OLESTR(""));
  665. }
  666. if( !*ppszSrcOfCopy )
  667. {
  668. hresult = ResultFromScode(E_OUTOFMEMORY);
  669. }
  670. }
  671. if( pdwStatus )
  672. {
  673. *pdwStatus = pObjDesc->dwStatus;
  674. }
  675. GlobalUnlock(medium.hGlobal);
  676. errRtn:
  677. ReleaseStgMedium(&medium);
  678. logRtn:
  679. LEDebugOut((DEB_ITRACE, "%p OUT GetDataFromDescriptor ( %lx ) "
  680. "[ %p ]\n", NULL, hresult,
  681. (ppszSrcOfCopy) ? *ppszSrcOfCopy : 0 ));
  682. return hresult;
  683. }
  684. //+-------------------------------------------------------------------------
  685. //
  686. // Function: GetDataFromStorage
  687. //
  688. // Synopsis: Calls GetData[Here] for TYMED_ISTORAGE and returns the
  689. // results on either an HGLOBAL or memory-based storage
  690. //
  691. // Effects:
  692. //
  693. // Arguments: [pDataObj] -- the source data object
  694. // [pformatetc] -- formatetc to retrieve
  695. // [pmedium] -- where to put the resulting HGlobal, may
  696. // be NULL
  697. // [ppstg] -- where to save the real IStorage
  698. // (may be NULL)
  699. //
  700. // Requires: if pmedium is specified, then pmedium->tymed must be
  701. // TYMED_HGLOBAL
  702. //
  703. // Returns: HRESULT
  704. //
  705. // Signals:
  706. //
  707. // Modifies:
  708. //
  709. // Algorithm: we create a storage on memory
  710. // first try to GetDataHere to that storage, if that fails, then
  711. // do a GetData and CopyTo the returned storage to our memory
  712. // storage.
  713. //
  714. // History: dd-mmm-yy Author Comment
  715. // 11-Apr-94 alexgo author
  716. //
  717. // Notes: NB!!: The caller takes ownership of the data--if an hglobal
  718. // is requested, then it must be explicitly GlobalFree'd.
  719. // Similarly, the returned storage must be released and both
  720. // release mechanisms must be called if both data items are
  721. // returned.
  722. //
  723. //--------------------------------------------------------------------------
  724. HRESULT GetDataFromStorage(IDataObject *pDataObj, FORMATETC *pformatetc,
  725. STGMEDIUM *pmedium, IStorage **ppstg)
  726. {
  727. HRESULT hresult;
  728. STGMEDIUM memmedium; // for the memory-based IStorage
  729. ILockBytes * pLockBytes;
  730. BOOL fDeleteOnRelease = FALSE;
  731. FORMATETC fetctemp;
  732. VDATEHEAP();
  733. LEDebugOut((DEB_ITRACE, "%p _IN GetDataFromStorage ( %p , %p , %p"
  734. " )\n", NULL, pDataObj, pformatetc, pmedium));
  735. #if DBG ==1
  736. if( pmedium )
  737. {
  738. Assert(pmedium->tymed == TYMED_HGLOBAL);
  739. }
  740. #endif // DBG ==1
  741. Assert(pformatetc->tymed & TYMED_ISTORAGE);
  742. // don't stomp on the in-parameter
  743. fetctemp = *pformatetc;
  744. fetctemp.tymed = TYMED_ISTORAGE;
  745. _xmemset(&memmedium, 0, sizeof(STGMEDIUM));
  746. memmedium.tymed = TYMED_ISTORAGE;
  747. // the only time we want the hglobal that the storage will be
  748. // constructed from to be automatically deleted is if the caller
  749. // only requested a storage to be returned.
  750. if( ppstg && !pmedium )
  751. {
  752. fDeleteOnRelease = TRUE;
  753. }
  754. hresult = UtCreateStorageOnHGlobal( NULL,
  755. fDeleteOnRelease,
  756. &(memmedium.pstg), &pLockBytes);
  757. if( hresult != NOERROR )
  758. {
  759. goto errRtn;
  760. }
  761. // first try to do a GetDataHere call
  762. hresult = pDataObj->GetDataHere( &fetctemp, &memmedium );
  763. if( hresult != NOERROR )
  764. {
  765. STGMEDIUM appmedium; // a medium that is filled
  766. // in by the app
  767. _xmemset(&appmedium, 0, sizeof(STGMEDIUM));
  768. // hmmm, that didn't work, try for a plain GetData call
  769. hresult = pDataObj->GetData(&fetctemp, &appmedium);
  770. if( hresult == NOERROR )
  771. {
  772. // now do the CopyTo
  773. hresult = appmedium.pstg->CopyTo(0, NULL, NULL,
  774. memmedium.pstg);
  775. // we are now done with the app supplied medium
  776. ReleaseStgMedium(&appmedium);
  777. }
  778. }
  779. // release the storage unless there's no error and the
  780. // caller requested a copy
  781. if( ppstg && hresult == NOERROR )
  782. {
  783. *ppstg = memmedium.pstg;
  784. // we need to do a Commit here to flush cached data to
  785. // disk (in this case, to the hglobal). The release
  786. // below in the alternate code path will automatically
  787. // cause a Commit
  788. memmedium.pstg->Commit(STGC_DEFAULT);
  789. }
  790. else
  791. {
  792. memmedium.pstg->Release();
  793. }
  794. // now retrieve the HGLOBAL from the storage. NB! It is very
  795. // important to do this *after* the release; the final release
  796. // on the storage causes a Commit. (Alternately, we can simply
  797. // call Commit--see above).
  798. if( hresult == NOERROR && pmedium )
  799. {
  800. hresult = GetHGlobalFromILockBytes(pLockBytes,
  801. &(pmedium->hGlobal));
  802. }
  803. pLockBytes->Release();
  804. errRtn:
  805. LEDebugOut((DEB_ITRACE, "%p OUT GetDataFromStorage ( %lx )\n",
  806. NULL, hresult));
  807. return hresult;
  808. }
  809. //+-------------------------------------------------------------------------
  810. //
  811. // Function: GetDataFromStream
  812. //
  813. // Synopsis: Calls GetData[Here] for TYMED_ISTREAM and returns the
  814. // results on an HGLOBAL
  815. //
  816. // Effects:
  817. //
  818. // Arguments: [pDataObj] -- the source data object
  819. // [pformatetc] -- the formatetc to retrieve
  820. // [pmedium] -- where to put the resulting HGlobal.
  821. // (may be NULL)
  822. // [ppstm] -- where to put the stream ( may be NULL )
  823. //
  824. // Requires:
  825. //
  826. // Returns: HRESULT
  827. //
  828. // Signals:
  829. //
  830. // Modifies:
  831. //
  832. // Algorithm: we create a stream on memory
  833. // first try to GetDataHere to that stream, if that fails, then
  834. // do a GetData and CopyTo the returned stream to our memory
  835. // stream.
  836. //
  837. // History: dd-mmm-yy Author Comment
  838. // 11-Apr-94 alexgo author
  839. //
  840. // Notes: NB!!: The caller takes ownership fo the data returned, either
  841. // GlobalFree or Release (or both) must be called.
  842. //
  843. //--------------------------------------------------------------------------
  844. HRESULT GetDataFromStream(IDataObject *pDataObj, FORMATETC *pformatetc,
  845. STGMEDIUM *pmedium, IStream **ppstm)
  846. {
  847. HRESULT hresult;
  848. STGMEDIUM memmedium; // for the memory-based IStream
  849. HGLOBAL hglobal = NULL;
  850. BOOL fDeleteOnRelease = FALSE;
  851. FORMATETC fetctemp;
  852. VDATEHEAP();
  853. LEDebugOut((DEB_ITRACE, "%p _IN GetDataFromStream ( %p , %p , %p )\n",
  854. NULL, pDataObj, pformatetc, pmedium));
  855. // the only time we want the underlying hglobal for the stream to
  856. // be automatically deleted is if the caller only wanted the
  857. // stream returned.
  858. if( ppstm && !pmedium )
  859. {
  860. fDeleteOnRelease = TRUE;
  861. }
  862. Assert( pformatetc->tymed & TYMED_ISTREAM );
  863. // don't stomp on the in-parameter
  864. fetctemp = *pformatetc;
  865. fetctemp.tymed = TYMED_ISTREAM;
  866. _xmemset(&memmedium, 0, sizeof(STGMEDIUM));
  867. memmedium.tymed = TYMED_ISTREAM;
  868. hresult = CreateStreamOnHGlobal( NULL,
  869. fDeleteOnRelease,
  870. &(memmedium.pstm));
  871. if( hresult != NOERROR )
  872. {
  873. goto logRtn;
  874. }
  875. // first try to do a GetDataHere call
  876. hresult = pDataObj->GetDataHere( &fetctemp, &memmedium );
  877. if( hresult != NOERROR )
  878. {
  879. if (hresult == E_OUTOFMEMORY)
  880. {
  881. goto errRtn;
  882. }
  883. STGMEDIUM appmedium; // a medium that is filled
  884. // in by the app
  885. LARGE_INTEGER li;
  886. ULARGE_INTEGER uli;
  887. ULARGE_INTEGER uliWritten;
  888. #if DBG == 1
  889. ULARGE_INTEGER uliEnd;
  890. #endif
  891. _xmemset(&appmedium, 0, sizeof(STGMEDIUM));
  892. // hmmm, that didn't work, try for a plain GetData call
  893. hresult = pDataObj->GetData( &fetctemp, &appmedium );
  894. if( hresult != NOERROR )
  895. {
  896. // oh well, we tried. Cleanup and away we go
  897. goto errRtn;
  898. }
  899. // now do the CopyTo. In order to do this, we need
  900. // to get the size of the returned stream, reset its
  901. // seek pointer to the beginning and then do a stream
  902. // CopyTo.
  903. LISet32(li, 0);
  904. hresult = appmedium.pstm->Seek(li, STREAM_SEEK_CUR, &uli);
  905. if( hresult != NOERROR )
  906. {
  907. ReleaseStgMedium(&appmedium);
  908. goto errRtn;
  909. }
  910. #if DBG == 1
  911. // According to the spec, the end of the data should be
  912. // positioned at the current seek pointer (which is
  913. // not necessarily the end of the stream). Here we will
  914. // see if the current seek pointer is at the *end* of the
  915. // stream. If the current seek is NOT equal to the end,
  916. // then there is a good chance of a bug somewhere in the
  917. // system (so we'll print a warning)
  918. hresult = appmedium.pstm->Seek(li, STREAM_SEEK_END, &uliEnd);
  919. // we don't return on error for debug builds so retail
  920. // and debug have exactly the same behaviour
  921. if( hresult == NOERROR )
  922. {
  923. // compare the two seek pointers. The high parts
  924. // *must* be zero (or we're hosed, since all of
  925. // this is taking place in memory
  926. Assert(uliEnd.HighPart == 0);
  927. LEWARN(uliEnd.LowPart != uli.LowPart,
  928. "Stream seek pointer "
  929. "not at end, possible error");
  930. }
  931. else
  932. {
  933. LEDebugOut((DEB_ERROR, "ERROR!: IStream->Seek failed!"
  934. "\n"));
  935. // FALL-THROUGH!! This is deliberate--even
  936. // though we're in an error case, we want
  937. // debug && retail to have the same behaviour
  938. // (besides, we'll most likely fail in the
  939. // Seek call below).
  940. }
  941. #endif // DBG == 1
  942. // now backup to the beginning
  943. hresult = appmedium.pstm->Seek(li, STREAM_SEEK_SET, NULL);
  944. if( hresult != NOERROR )
  945. {
  946. ReleaseStgMedium(&appmedium);
  947. goto errRtn;
  948. }
  949. // now that we know how many bytes to copy, actually do so.
  950. hresult = appmedium.pstm->CopyTo(memmedium.pstm, uli,
  951. NULL, &uliWritten);
  952. if( hresult == NOERROR )
  953. {
  954. // make sure we got enough data
  955. if( uli.LowPart != uliWritten.LowPart )
  956. {
  957. // we probably ran out of memory
  958. // trying to resize the memory stream
  959. hresult = ResultFromScode(E_OUTOFMEMORY);
  960. }
  961. }
  962. // we are now done with the app supplied medium
  963. ReleaseStgMedium(&appmedium);
  964. }
  965. // now fetch the hglobal from the [resized] memory stream
  966. if( hresult == NOERROR )
  967. {
  968. hresult = GetHGlobalFromStream(memmedium.pstm, &hglobal);
  969. }
  970. errRtn:
  971. // if the caller wanted the stream, then give it to him
  972. // (only if there was no error)
  973. // otherwise, release it
  974. if( hresult == NOERROR && ppstm )
  975. {
  976. *ppstm = memmedium.pstm;
  977. // we do not need to call Commit in this case; our
  978. // implementation of memory streams guarantees that
  979. // the underlying hglobal always contains flushed
  980. // information.
  981. }
  982. else
  983. {
  984. if(memmedium.pstm)
  985. {
  986. memmedium.pstm->Release();
  987. }
  988. }
  989. // if there was an error, then would have never allocated the
  990. // hglobal
  991. if( hresult == NOERROR && pmedium)
  992. {
  993. pmedium->hGlobal = hglobal;
  994. }
  995. logRtn:
  996. LEDebugOut((DEB_ITRACE, "%p OUT GetDataFromStream ( %lx )\n",
  997. NULL, hresult));
  998. return hresult;
  999. }
  1000. //+-------------------------------------------------------------------------
  1001. //
  1002. // Function: GetNative
  1003. //
  1004. // Synopsis: Retrieves or syntesizes OLE1 Native data format
  1005. //
  1006. // Effects:
  1007. //
  1008. // Arguments: [pDataObj] -- the source data object
  1009. // [pmedium] -- where to put the data
  1010. //
  1011. // Requires: pmedium->tymed must be TYMED_HGLOBAL
  1012. //
  1013. // Returns: HRESULT
  1014. //
  1015. // Signals:
  1016. //
  1017. // Modifies:
  1018. //
  1019. // Algorithm:
  1020. // cfNative is an OLE1 format consisting of an aribtrary
  1021. // hGlobal. It is up to the source app to interpret any
  1022. // data therein; OLE1 containers merely store and forward it.
  1023. //
  1024. // first fetch either EmbedSource or EmbeddedObject
  1025. // then check to see if that NATIVE_STREAM exists. If so,
  1026. // then this was an object created from an OLE1 server and
  1027. // we should just offer it's native data.
  1028. // Otherwise, the object is an OLE2 object, and we should
  1029. // offer it's storage as the native data.
  1030. //
  1031. // History: dd-mmm-yy Author Comment
  1032. // 10-Jun-94 alexgo author
  1033. //
  1034. // Notes:
  1035. //
  1036. //--------------------------------------------------------------------------
  1037. HRESULT GetNative( IDataObject *pDataObj, STGMEDIUM *pmedium)
  1038. {
  1039. HRESULT hresult;
  1040. IStorage * pstg = NULL;
  1041. IStream * pstm = NULL;
  1042. UINT cf;
  1043. HGLOBAL hNative = NULL;
  1044. DWORD dwSize = 0;
  1045. LPVOID pv;
  1046. FORMATETC formatetc;
  1047. VDATEHEAP();
  1048. LEDebugOut((DEB_ITRACE, "%p _IN GetNative ( %p , %p )\n", NULL,
  1049. pDataObj, pmedium));
  1050. Assert(pmedium->tymed == TYMED_HGLOBAL);
  1051. if( SSIsClipboardFormatAvailable(g_cfEmbeddedObject) )
  1052. {
  1053. cf = g_cfEmbeddedObject;
  1054. }
  1055. else if( SSIsClipboardFormatAvailable(g_cfEmbedSource) )
  1056. {
  1057. cf = g_cfEmbedSource;
  1058. }
  1059. else
  1060. {
  1061. hresult = ResultFromScode(E_UNEXPECTED);
  1062. LEDebugOut((DEB_ERROR, "ERROR!: Native data should not "
  1063. "be on clipboard!!\n"));
  1064. goto errRtn;
  1065. }
  1066. INIT_FORETC(formatetc);
  1067. formatetc.cfFormat = (CLIPFORMAT) cf;
  1068. formatetc.tymed = TYMED_ISTORAGE;
  1069. hresult = GetDataFromStorage(pDataObj, &formatetc, pmedium, &pstg);
  1070. if( hresult != NOERROR )
  1071. {
  1072. goto errRtn;
  1073. }
  1074. hresult = pstg->OpenStream(OLE10_NATIVE_STREAM, NULL, STGM_SALL, 0,
  1075. &pstm);
  1076. if( hresult == NOERROR )
  1077. {
  1078. // we had ole1 data originally, just use it.
  1079. hresult = StRead(pstm, &dwSize, sizeof(DWORD));
  1080. if( hresult != NOERROR )
  1081. {
  1082. goto errRtn;
  1083. }
  1084. hNative = GlobalAlloc((GMEM_SHARE | GMEM_MOVEABLE), dwSize);
  1085. if( !hNative )
  1086. {
  1087. LEDebugOut((DEB_WARN, "WARNING: GlobalAlloc failed!"
  1088. "\n"));
  1089. hresult = ResultFromScode(E_OUTOFMEMORY);
  1090. goto errRtn;
  1091. }
  1092. pv = GlobalLock(hNative);
  1093. if( !pv )
  1094. {
  1095. LEDebugOut((DEB_WARN, "WARNING: GlobalLock failed!"
  1096. "\n"));
  1097. hresult = ResultFromScode(E_OUTOFMEMORY);
  1098. goto errRtn;
  1099. }
  1100. // now copy the data from the stream into the hglobal
  1101. hresult = StRead(pstm, pv, dwSize);
  1102. GlobalUnlock(hNative);
  1103. if( hresult != NOERROR )
  1104. {
  1105. goto errRtn;
  1106. }
  1107. // this is bit is counter-intuitive. The hglobal
  1108. // we have in pmedium->hGlobal still has a storage on
  1109. // top of it, so we must release our stream, then
  1110. // the storage, and finally free the hglobal so we
  1111. // don't leak memory. We've already allocated another
  1112. // hglobal in this routine to return the Native data.
  1113. pstm->Release();
  1114. pstg->Release();
  1115. GlobalFree(pmedium->hGlobal);
  1116. // now we assign pmedium->hGlobal to the hglobal we
  1117. // just created so we can pass it out
  1118. pmedium->hGlobal = hNative;
  1119. // don't release the streams again
  1120. goto logRtn;
  1121. }
  1122. else
  1123. {
  1124. // storage for an OLE2 object. pmedium->hGlobal
  1125. // should already contain the data we need to put
  1126. // on the clipboard (from the GetDataFromStorage call)
  1127. Assert(pmedium->hGlobal);
  1128. hresult = NOERROR;
  1129. }
  1130. errRtn:
  1131. if( pstm )
  1132. {
  1133. pstm->Release();
  1134. }
  1135. if( pstg )
  1136. {
  1137. pstg->Release();
  1138. }
  1139. if( hresult != NOERROR )
  1140. {
  1141. GlobalFree(pmedium->hGlobal);
  1142. }
  1143. logRtn:
  1144. LEDebugOut((DEB_ITRACE, "%p OUT GetNative ( %lx ) [ %lx ]\n",
  1145. NULL, hresult, pmedium->hGlobal));
  1146. return hresult;
  1147. }
  1148. //+-------------------------------------------------------------------------
  1149. //
  1150. // Function: GetObjectLink
  1151. //
  1152. // Synopsis: Synthesizes OLE1 ObjectLink format from LinkSource data
  1153. //
  1154. // Effects:
  1155. //
  1156. // Arguments: [pDataObj] -- the source data object
  1157. // [pmedium] -- where to put the data
  1158. //
  1159. // Requires: pmedium->tymed must be TYMED_HGLOBAL
  1160. //
  1161. // Returns: HRESULT
  1162. //
  1163. // Signals:
  1164. //
  1165. // Modifies:
  1166. //
  1167. // Algorithm: Get the LinkSource data, which contains a serialized
  1168. // moniker. Load the moniker from the stream and parse it
  1169. // to retrieve the file name and item name (if available).
  1170. // Get the class ID of the link source from either the
  1171. // LinkSource stream or from LinkSrcDescriptor.
  1172. // Once these strings are converted to ANSI, we can build
  1173. // the ObjectLink format, which looks like:
  1174. //
  1175. // classname\0filename\0itemname\0\0
  1176. //
  1177. // History: dd-mmm-yy Author Comment
  1178. // 10-Jun-94 alexgo author
  1179. // Notes:
  1180. //
  1181. //--------------------------------------------------------------------------
  1182. HRESULT GetObjectLink( IDataObject *pDataObj, STGMEDIUM *pmedium)
  1183. {
  1184. HRESULT hresult;
  1185. IStream * pstm = NULL;
  1186. IMoniker * pmk = NULL;
  1187. CLSID clsid;
  1188. LPOLESTR pszFile = NULL,
  1189. pszClass = NULL,
  1190. pszItem = NULL;
  1191. LPSTR pszFileA = NULL,
  1192. pszClassA = NULL,
  1193. pszItemA = NULL,
  1194. pszObjectLink;
  1195. DWORD cbszFileA = 0,
  1196. cbszClassA = 0,
  1197. cbszItemA = 0;
  1198. LARGE_INTEGER li;
  1199. FORMATETC formatetc;
  1200. VDATEHEAP();
  1201. LEDebugOut((DEB_ITRACE, "%p _IN GetObjectLink ( %p , %p )\n", NULL,
  1202. pDataObj, pmedium));
  1203. Assert(pmedium->tymed == TYMED_HGLOBAL);
  1204. // fetch LinkSource data
  1205. INIT_FORETC(formatetc);
  1206. formatetc.cfFormat = g_cfLinkSource;
  1207. formatetc.tymed = TYMED_ISTREAM;
  1208. hresult = GetDataFromStream(pDataObj, &formatetc, NULL, &pstm);
  1209. if( hresult != NOERROR )
  1210. {
  1211. goto errRtn;
  1212. }
  1213. // reset the stream seek pointer to the beginning
  1214. LISet32(li, 0);
  1215. hresult = pstm->Seek(li, STREAM_SEEK_SET, NULL);
  1216. if( hresult != NOERROR )
  1217. {
  1218. goto errRtn;
  1219. }
  1220. // load the moniker from the stream, so we can parse out
  1221. // it's underlying file and item name
  1222. hresult = OleLoadFromStream(pstm, IID_IMoniker, (LPLPVOID)&pmk);
  1223. if( hresult != NOERROR )
  1224. {
  1225. goto errRtn;
  1226. }
  1227. hresult = Ole10_ParseMoniker(pmk, &pszFile, &pszItem);
  1228. if( hresult != NOERROR )
  1229. {
  1230. goto errRtn;
  1231. }
  1232. // now fetch the class ID so we can construct the ClassName
  1233. hresult = ReadClassStm(pstm, &clsid);
  1234. if( hresult != NOERROR )
  1235. {
  1236. // it is possible that the stream does not contain
  1237. // the clsid of the link source. In this case, we should
  1238. // fetch it from the LinkSourceDescriptor
  1239. hresult = GetDataFromDescriptor(pDataObj, &clsid,
  1240. g_cfLinkSrcDescriptor,
  1241. USE_NORMAL_CLSID, NULL, NULL);
  1242. if( hresult != NOERROR )
  1243. {
  1244. goto errRtn;
  1245. }
  1246. }
  1247. hresult = ProgIDFromCLSID(clsid, &pszClass);
  1248. if( hresult != NOERROR )
  1249. {
  1250. goto errRtn;
  1251. }
  1252. // by this point, we should have all of our strings. Convert
  1253. // them to ANSI and stuff them in an hglobal.
  1254. hresult = UtPutUNICODEData(_xstrlen(pszClass)+1, pszClass, &pszClassA,
  1255. NULL, &cbszClassA);
  1256. if( hresult != NOERROR )
  1257. {
  1258. goto errRtn;
  1259. }
  1260. else if( pszClassA == NULL )
  1261. {
  1262. hresult = ResultFromScode(E_FAIL);
  1263. goto errRtn;
  1264. }
  1265. hresult = UtPutUNICODEData(_xstrlen(pszFile)+1, pszFile, &pszFileA,
  1266. NULL, &cbszFileA);
  1267. if( hresult != NOERROR )
  1268. {
  1269. goto errRtn;
  1270. }
  1271. // we are allowed to have a NULL item name
  1272. if( pszItem )
  1273. {
  1274. hresult = UtPutUNICODEData(_xstrlen(pszItem)+1, pszItem,
  1275. &pszItemA, NULL, &cbszItemA);
  1276. if( hresult != NOERROR )
  1277. {
  1278. goto errRtn;
  1279. }
  1280. }
  1281. // we allocate 2 extra bytes for terminating '\0''s. (if the
  1282. // item name is NULL, we should be safe and terminate it with a
  1283. // zero as well, so we'll end up with 3 \0's at the end.
  1284. pmedium->hGlobal = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE ),
  1285. cbszClassA + cbszFileA + cbszItemA + 2);
  1286. if( !pmedium->hGlobal )
  1287. {
  1288. hresult = ResultFromScode(E_OUTOFMEMORY);
  1289. goto errRtn;
  1290. }
  1291. pszObjectLink = (LPSTR)GlobalLock(pmedium->hGlobal);
  1292. if( !pszObjectLink )
  1293. {
  1294. hresult = ResultFromScode(E_OUTOFMEMORY);
  1295. goto errRtn;
  1296. }
  1297. _xmemcpy(pszObjectLink, pszClassA, cbszClassA);
  1298. pszObjectLink += cbszClassA;
  1299. _xmemcpy(pszObjectLink, pszFileA, cbszFileA);
  1300. pszObjectLink += cbszFileA;
  1301. if( pszItemA )
  1302. {
  1303. _xmemcpy(pszObjectLink, pszItemA, cbszItemA);
  1304. pszObjectLink += cbszItemA;
  1305. }
  1306. else
  1307. {
  1308. *pszObjectLink = '\0';
  1309. pszObjectLink++;
  1310. }
  1311. *pszObjectLink = '\0';
  1312. GlobalUnlock(pmedium->hGlobal);
  1313. errRtn:
  1314. if( pmk )
  1315. {
  1316. pmk->Release();
  1317. }
  1318. if( pszClass )
  1319. {
  1320. PubMemFree(pszClass);
  1321. }
  1322. if( pszFile )
  1323. {
  1324. PubMemFree(pszFile);
  1325. }
  1326. if( pszItem )
  1327. {
  1328. PubMemFree(pszItem);
  1329. }
  1330. if( pszClassA )
  1331. {
  1332. PubMemFree(pszClassA);
  1333. }
  1334. if( pszFileA )
  1335. {
  1336. PubMemFree(pszFileA);
  1337. }
  1338. if( pszItemA )
  1339. {
  1340. PubMemFree(pszItemA);
  1341. }
  1342. if( pstm )
  1343. {
  1344. pstm->Release();
  1345. }
  1346. if( hresult != NOERROR )
  1347. {
  1348. if( pmedium->hGlobal )
  1349. {
  1350. GlobalFree(pmedium->hGlobal);
  1351. pmedium->hGlobal = NULL;
  1352. }
  1353. }
  1354. LEDebugOut((DEB_ITRACE, "%p OUT GetObjectLink ( %lx ) [ %lx ]\n",
  1355. NULL, hresult, pmedium->hGlobal));
  1356. return hresult;
  1357. }
  1358. //+-------------------------------------------------------------------------
  1359. //
  1360. // Function: GetOwnerLink
  1361. //
  1362. // Synopsis: Synthesizes OLE1 OwnerLink format from ObjectDescriptor data
  1363. //
  1364. // Effects:
  1365. //
  1366. // Arguments: [pDataObj] -- the source data object
  1367. // [pmedium] -- where to put the data
  1368. //
  1369. // Requires:
  1370. //
  1371. // Returns: HRESULT
  1372. //
  1373. // Signals:
  1374. //
  1375. // Modifies:
  1376. //
  1377. // Algorithm: fetch the clsid and SrcOfCopy string from data offered
  1378. // in cfObjectDescriptor. Then turn the class ID into
  1379. // the prog ID and then turn all strings into ANSI. From
  1380. // this, we can build the OwnerLink format data, which looks
  1381. // like:
  1382. // szClass\0SrcOfCopy\0\0\0
  1383. //
  1384. // History: dd-mmm-yy Author Comment
  1385. // 10-Jun-94 alexgo author
  1386. // Notes:
  1387. //
  1388. //--------------------------------------------------------------------------
  1389. HRESULT GetOwnerLink( IDataObject *pDataObj, STGMEDIUM *pmedium)
  1390. {
  1391. HRESULT hresult;
  1392. LPOLESTR pszSrcOfCopy = NULL,
  1393. pszClass = NULL;
  1394. LPSTR pszSrcOfCopyA = NULL,
  1395. pszClassA = NULL,
  1396. pszOwnerLink;
  1397. DWORD cbszClassA = 0,
  1398. cbszSrcOfCopyA;
  1399. CLSID clsid;
  1400. VDATEHEAP();
  1401. LEDebugOut((DEB_ITRACE, "%p _IN GetOwnerLink ( %p , %p )\n", NULL,
  1402. pDataObj, pmedium));
  1403. hresult = GetDataFromDescriptor(pDataObj, &clsid,
  1404. g_cfObjectDescriptor, USE_STANDARD_LINK,
  1405. &pszSrcOfCopy, NULL);
  1406. if( hresult != NOERROR )
  1407. {
  1408. goto errRtn;
  1409. }
  1410. // 16bit code called wProgIDFromCLSID, but in when
  1411. // constructing ObjectLink, simply called ProgIDFromCLSID
  1412. // directly. The w version of the function special-cases
  1413. // the prog-id string for a Link object (specifically, "OLE2Link")
  1414. // we need to do it here to handle the case of copying an OLE2
  1415. // link object to an ole1 container, and then copying the object
  1416. // from the ole1 container back to an ole2 container.
  1417. hresult = wProgIDFromCLSID(clsid, &pszClass);
  1418. if( hresult != NOERROR )
  1419. {
  1420. goto errRtn;
  1421. }
  1422. // now convert all our data to ANSI
  1423. hresult = UtPutUNICODEData(_xstrlen(pszClass)+1, pszClass,
  1424. &pszClassA, NULL, &cbszClassA);
  1425. if( hresult != NOERROR )
  1426. {
  1427. goto errRtn;
  1428. }
  1429. hresult = UtPutUNICODEData(_xstrlen(pszSrcOfCopy)+1, pszSrcOfCopy,
  1430. &pszSrcOfCopyA, NULL, &cbszSrcOfCopyA);
  1431. if( hresult != NOERROR )
  1432. {
  1433. goto errRtn;
  1434. }
  1435. // now allocate an HGLOBAL for OwnerLink and stuff the
  1436. // string data in there. We alloc 2 extra bytes for
  1437. // the terminating NULL characters.
  1438. pmedium->hGlobal = GlobalAlloc((GMEM_MOVEABLE | GMEM_SHARE |
  1439. GMEM_ZEROINIT),
  1440. cbszClassA + cbszSrcOfCopyA + 2);
  1441. if( !pmedium->hGlobal )
  1442. {
  1443. hresult = ResultFromScode(E_OUTOFMEMORY);
  1444. goto errRtn;
  1445. }
  1446. pszOwnerLink = (LPSTR)GlobalLock(pmedium->hGlobal);
  1447. if( !pszOwnerLink )
  1448. {
  1449. hresult = ResultFromScode(E_OUTOFMEMORY);
  1450. goto errRtn;
  1451. }
  1452. _xmemcpy(pszOwnerLink, pszClassA, cbszClassA);
  1453. pszOwnerLink += cbszClassA;
  1454. _xmemcpy(pszOwnerLink, pszSrcOfCopyA, cbszSrcOfCopyA);
  1455. pszOwnerLink += cbszSrcOfCopyA;
  1456. *pszOwnerLink = '\0';
  1457. pszOwnerLink++;
  1458. *pszOwnerLink = '\0';
  1459. GlobalUnlock(pmedium->hGlobal);
  1460. errRtn:
  1461. if( pszClass )
  1462. {
  1463. PubMemFree(pszClass);
  1464. }
  1465. if( pszSrcOfCopy )
  1466. {
  1467. PubMemFree(pszSrcOfCopy);
  1468. }
  1469. if( pszClassA )
  1470. {
  1471. PubMemFree(pszClassA);
  1472. }
  1473. if( pszSrcOfCopyA )
  1474. {
  1475. PubMemFree(pszSrcOfCopyA);
  1476. }
  1477. if( hresult != NOERROR )
  1478. {
  1479. if( pmedium->hGlobal )
  1480. {
  1481. GlobalFree(pmedium->hGlobal);
  1482. pmedium->hGlobal = NULL;
  1483. }
  1484. }
  1485. LEDebugOut((DEB_ITRACE, "%p OUT GetOwnerLink ( %lx ) [ %lx ]\n",
  1486. NULL, hresult, pmedium->hGlobal));
  1487. return hresult;
  1488. }
  1489. //+-------------------------------------------------------------------------
  1490. //
  1491. // Function: GetPrivateClipboardWindow (internal)
  1492. //
  1493. // Synopsis: Finds the private ole-clipboard window associated with
  1494. // the current appartment (creating one if necessary).
  1495. //
  1496. // Effects:
  1497. //
  1498. // Arguments: [fFlags] -- if CLIP_CREATEIFNOTTHERE, then a window
  1499. // will be created if none already exists
  1500. // if CLIP_QUERY, the current clipboard
  1501. // window (if any) will be returned.
  1502. //
  1503. // Requires:
  1504. //
  1505. // Returns: HWND (NULL on failure)
  1506. //
  1507. // Signals:
  1508. //
  1509. // Modifies:
  1510. //
  1511. // Algorithm:
  1512. //
  1513. // History: dd-mmm-yy Author Comment
  1514. // 16-Mar-94 alexgo author
  1515. //
  1516. // Notes:
  1517. //
  1518. //--------------------------------------------------------------------------
  1519. HWND GetPrivateClipboardWindow( CLIPWINDOWFLAGS fFlags )
  1520. {
  1521. HWND hClipWnd = 0;
  1522. HRESULT hr;
  1523. VDATEHEAP();
  1524. LEDebugOut((DEB_ITRACE, "%p _IN GetPrivateClipboardWindow ( %lx )\n",
  1525. NULL, fFlags));
  1526. COleTls tls(hr);
  1527. if (SUCCEEDED(hr))
  1528. {
  1529. hClipWnd = tls->hwndClip;
  1530. if( !hClipWnd && (fFlags & CLIP_CREATEIFNOTTHERE) )
  1531. {
  1532. // NOTE: do not need to Stack Switch since the
  1533. // the windows is in ole itself.
  1534. if (ClipboardInitialize())
  1535. {
  1536. hClipWnd = ClpCreateWindowEx(NULL,vszClipboardWndClass, NULL,
  1537. WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  1538. CW_USEDEFAULT,
  1539. #ifdef HWND_MESSAGE // HWND_MESSAGE is not yet defined on Chicago.
  1540. HWND_MESSAGE,
  1541. #else
  1542. NULL,
  1543. #endif // HWND_MESSAGE
  1544. NULL, g_hmodOLE2, NULL);
  1545. // if we can't create the window, print an error
  1546. LEERROR(!hClipWnd, "Unable to create private clipboard win");
  1547. // now set the hwnd into our thread-local storage
  1548. tls->hwndClip = hClipWnd;
  1549. }
  1550. }
  1551. }
  1552. LEDebugOut((DEB_ITRACE, "%p OUT GetPrivateClipboardWindow ( %lx )\n",
  1553. NULL, hClipWnd));
  1554. // hClipWnd should always be a valid window
  1555. #if DBG ==1
  1556. if( hClipWnd )
  1557. {
  1558. Assert(IsWindow(hClipWnd));
  1559. }
  1560. #endif // DBG == 1
  1561. return hClipWnd;
  1562. }
  1563. //+-------------------------------------------------------------------------
  1564. //
  1565. // Function: HandleFromHandle
  1566. //
  1567. // Synopsis: Calls IDataObject->GetData for the given format and returns
  1568. // the resulting handle (duplicated if necessary).
  1569. //
  1570. // Effects:
  1571. //
  1572. // Arguments: [pDataObj] -- the source data object
  1573. // [pformatetc] -- the formatetc
  1574. // [pmedium] -- the tymed to use for GetData and where
  1575. // to return the data
  1576. //
  1577. // Requires:
  1578. //
  1579. // Returns: HRESULT
  1580. //
  1581. // Signals:
  1582. //
  1583. // Modifies:
  1584. //
  1585. // Algorithm: if data object sets pUnkForRelease after the GetData call,
  1586. // we'll duplicate the returned data. Otherwise, we just pass
  1587. // out the results of GetData
  1588. //
  1589. // History: dd-mmm-yy Author Comment
  1590. // 11-Apr-94 alexgo author
  1591. //
  1592. // Notes:
  1593. //
  1594. //--------------------------------------------------------------------------
  1595. HRESULT HandleFromHandle(IDataObject *pDataObj, FORMATETC *pformatetc,
  1596. STGMEDIUM *pmedium)
  1597. {
  1598. HRESULT hresult;
  1599. STGMEDIUM tempmedium;
  1600. VDATEHEAP();
  1601. LEDebugOut((DEB_ITRACE, "%p _IN HandleFromHandle ( %p , %p , %p )\n",
  1602. NULL, pDataObj, pformatetc, pmedium));
  1603. _xmemset(&tempmedium, 0, sizeof(STGMEDIUM));
  1604. hresult = pDataObj->GetData(pformatetc, &tempmedium);
  1605. if( hresult == NOERROR )
  1606. {
  1607. if( tempmedium.pUnkForRelease )
  1608. {
  1609. pmedium->hGlobal = OleDuplicateData(
  1610. tempmedium.hGlobal, pformatetc->cfFormat,
  1611. GMEM_MOVEABLE | GMEM_DDESHARE );
  1612. if( !pmedium->hGlobal )
  1613. {
  1614. hresult = ResultFromScode(E_OUTOFMEMORY);
  1615. // fall through so we release the original
  1616. // data
  1617. }
  1618. // now release the original data
  1619. ReleaseStgMedium(&tempmedium);
  1620. }
  1621. else
  1622. {
  1623. pmedium->hGlobal = tempmedium.hGlobal;
  1624. }
  1625. }
  1626. // we don't ever try a GetDataHere for handles
  1627. LEDebugOut((DEB_ITRACE, "%p OUT HandleFromHandle ( %lx )\n",
  1628. hresult));
  1629. return hresult;
  1630. }
  1631. //+-------------------------------------------------------------------------
  1632. //
  1633. // Function: MapCFToFormatetc
  1634. //
  1635. // Synopsis: Given a clipboard format, find the corresponding formatetc
  1636. // in our private data
  1637. //
  1638. // Effects:
  1639. //
  1640. // Arguments: [hClipWnd] -- the hwnd of our private clipboard window
  1641. // [cf] -- the clipboard format in question
  1642. // [pformatec] -- the formatetc to fill in
  1643. //
  1644. // Requires:
  1645. //
  1646. // Returns: HRESULT
  1647. //
  1648. // Signals:
  1649. //
  1650. // Modifies:
  1651. //
  1652. // Algorithm:
  1653. //
  1654. // History: dd-mmm-yy Author Comment
  1655. // 12-Aug-94 alexgo author
  1656. //
  1657. // Notes:
  1658. //
  1659. //--------------------------------------------------------------------------
  1660. HRESULT MapCFToFormatetc( HWND hClipWnd, UINT cf, FORMATETC *pformatetc )
  1661. {
  1662. FORMATETCDATAARRAY *pFormatEtcDataArray;
  1663. HRESULT hresult = S_FALSE;
  1664. VDATEHEAP();
  1665. LEDebugOut((DEB_ITRACE, "%p _IN MapCFToFormatetc ( %x , %p )\n",
  1666. NULL, cf, pformatetc));
  1667. pFormatEtcDataArray = (FORMATETCDATAARRAY *) GetWindowLongPtr( hClipWnd, WL_ClipPrivateData );
  1668. LEERROR(!pFormatEtcDataArray, "No private clipboard data!!");
  1669. Assert(pFormatEtcDataArray);
  1670. if( pFormatEtcDataArray )
  1671. {
  1672. DWORD dwNumFormats = pFormatEtcDataArray->_cFormats;
  1673. FORMATETCDATA *pFormatEtcData = &(pFormatEtcDataArray->_FormatEtcData[0]);
  1674. Assert(pFormatEtcDataArray->_dwSig == 0);
  1675. while( dwNumFormats-- )
  1676. {
  1677. if(pFormatEtcData->_FormatEtc.cfFormat == cf)
  1678. {
  1679. *pformatetc = pFormatEtcData->_FormatEtc;
  1680. if (pformatetc->ptd)
  1681. {
  1682. pformatetc->ptd = (DVTARGETDEVICE *)
  1683. ((BYTE *) pFormatEtcDataArray + (ULONG_PTR) pformatetc->ptd );
  1684. }
  1685. hresult = S_OK;
  1686. break;
  1687. }
  1688. ++pFormatEtcData;
  1689. }
  1690. }
  1691. if( S_FALSE == hresult )
  1692. {
  1693. // Win95 will ask to RenderFormats that it is synthesizing.
  1694. // Under NT the only time this should fail is if the caller asked for one of
  1695. // our synthesized OLE 1.0 formats.
  1696. #ifndef _CHICAGO_
  1697. AssertSz( (cf == g_cfObjectLink) || (cf == g_cfOwnerLink) || (cf == g_cfNative),"Unknown Format");
  1698. #endif // _CHICAGO_
  1699. INIT_FORETC(*pformatetc);
  1700. pformatetc->cfFormat = (CLIPFORMAT) cf;
  1701. pformatetc->tymed = TYMED_HGLOBAL;
  1702. }
  1703. LEDebugOut((DEB_ITRACE, "%p OUT MapCFToFormatec ( )\n", NULL ));
  1704. return hresult;
  1705. }
  1706. //+-------------------------------------------------------------------------
  1707. // Function: OleFlushClipboard
  1708. //
  1709. // Synopsis: Removes the data object from the clipboard (as the app is
  1710. // going away). The formats it supports will be rendered on
  1711. // the clipboard so that the data may still be 'pasted' by
  1712. // other apps.
  1713. //
  1714. // Effects:
  1715. //
  1716. // Arguments: void
  1717. //
  1718. // Requires: the caller must be the owner of the clipboard
  1719. //
  1720. // Returns: HRESULT
  1721. //
  1722. // Signals:
  1723. //
  1724. // Modifies:
  1725. //
  1726. // Algorithm: 1. Make sure the caller is the clipboard window owner
  1727. // 2. flush format data onto the clipboard
  1728. // 3. remove the clipboard data object
  1729. //
  1730. // History: dd-mmm-yy Author Comment
  1731. // 16-Mar-94 alexgo author
  1732. //
  1733. // Notes:
  1734. //
  1735. //--------------------------------------------------------------------------
  1736. STDAPI OleFlushClipboard( void )
  1737. {
  1738. OLETRACEIN((API_OleFlushClipboard, NOPARAM));
  1739. HRESULT hresult;
  1740. HWND hClipWnd;
  1741. HANDLE handle;
  1742. FORMATETCDATAARRAY *pFormatEtcDataArray;
  1743. VDATEHEAP();
  1744. LEDebugOut((DEB_TRACE, "%p _IN OleFlushClipboard ( )\n", NULL));
  1745. if( (hClipWnd = VerifyCallerIsClipboardOwner()) == NULL)
  1746. {
  1747. //caller is not the clipboard owner, so return with an
  1748. //error
  1749. hresult = ResultFromScode(E_FAIL);
  1750. goto errRtn;
  1751. }
  1752. //
  1753. // BEGIN: OPENCLIPBOARD
  1754. //
  1755. // now open the clipboard so we can add and remove data
  1756. hresult = OleOpenClipboard(hClipWnd, NULL);
  1757. if( hresult != NOERROR )
  1758. {
  1759. goto errRtn;
  1760. }
  1761. // now go through all of the formats on the clipboard and render
  1762. // each one. Doing a GetClipboardData will force rendering for
  1763. // any as yet unrendered formats
  1764. // on error we have to live with clipboard not being flushed properly.
  1765. pFormatEtcDataArray = (FORMATETCDATAARRAY *) GetWindowLongPtr( hClipWnd, WL_ClipPrivateData );
  1766. if (pFormatEtcDataArray)
  1767. {
  1768. FORMATETCDATA *pCurFormat;
  1769. FORMATETCDATA *pNextFreeLocation; // location to copy FormatEtc to if Rendered Data.
  1770. DWORD dwNumFormats = pFormatEtcDataArray->_cFormats;
  1771. DWORD dwFlushedFormats = 0;
  1772. FORMATETCDATAARRAY *pClipFormatEtcDataArray;
  1773. HANDLE hglobal;
  1774. BOOL fPersistDataObjOnFlush;
  1775. fPersistDataObjOnFlush = (pFormatEtcDataArray->_dwMiscArrayFlags
  1776. & FETC_PERSIST_DATAOBJ_ON_FLUSH);
  1777. pNextFreeLocation = pCurFormat = &(pFormatEtcDataArray->_FormatEtcData[0]);
  1778. // loop through enumerator updating it as we go.
  1779. // warning: RenderFormat will be using the Same structure so it must always be
  1780. // valid when GetClipboardData is Called.
  1781. if (!fPersistDataObjOnFlush)
  1782. {
  1783. // this is the normal path most calls will take
  1784. while( dwNumFormats-- )
  1785. {
  1786. if (TRUE == pCurFormat->fSaveOnFlush)
  1787. {
  1788. // we ignore the return of GetClipboardData. Even if
  1789. // fails, we ought to flush as many as we can and then
  1790. // remove our data object.
  1791. *pNextFreeLocation = *pCurFormat;
  1792. ++pNextFreeLocation;
  1793. ++dwFlushedFormats;
  1794. handle = SSGetClipboardData(pCurFormat->_FormatEtc.cfFormat);
  1795. LEWARN( !handle, "GetClipboardData failed!");
  1796. }
  1797. ++pCurFormat;
  1798. } // while
  1799. // We will not offer these if PersistDataObjOnFlush is requested.
  1800. if (pFormatEtcDataArray->_dwMiscArrayFlags & FETC_OFFER_OLE1)
  1801. {
  1802. handle = SSGetClipboardData(g_cfNative);
  1803. LEWARN( !handle, "GetClipboardData failed for cfNative!");
  1804. handle = SSGetClipboardData(g_cfOwnerLink);
  1805. LEWARN( !handle, "GetClipboardData failed for cfOwnerLink!");
  1806. }
  1807. if (pFormatEtcDataArray->_dwMiscArrayFlags & FETC_OFFER_OBJLINK)
  1808. {
  1809. handle = SSGetClipboardData(g_cfObjectLink);
  1810. LEWARN( !handle, "GetClipboardData failed!");
  1811. }
  1812. }
  1813. else
  1814. {
  1815. // This is the special path if the provider requested that we
  1816. // persist the data Object at OleFlushCB time, instead of
  1817. // flushing individual formats.
  1818. while( dwNumFormats-- )
  1819. {
  1820. if (pCurFormat->_FormatEtc.cfFormat
  1821. == g_cfOleClipboardPersistOnFlush)
  1822. {
  1823. // We will flush on this single format if the app requested
  1824. // PersistDataObjOnFlush functionality. The idea being that
  1825. // since the app is requesting this functionality it is
  1826. // indicating that after OleFlushClipboard a paste will
  1827. // will require the real object to be re-hydrated.
  1828. // Since that is the case, there is not much point flushing
  1829. // other formats as the real object should be around
  1830. // at Paste time to provide data for all other formats
  1831. // directly.
  1832. *pNextFreeLocation = *pCurFormat;
  1833. ++pNextFreeLocation;
  1834. ++dwFlushedFormats;
  1835. handle = SSGetClipboardData(pCurFormat->_FormatEtc.cfFormat);
  1836. LEWARN( !handle, "GetClipboardData failed!");
  1837. break; // we are done
  1838. }
  1839. ++pCurFormat;
  1840. } // while
  1841. // Now do our SaveToStream magic if the clipboard data object
  1842. // owner requested for it.
  1843. HANDLE hglobal;
  1844. // Get the IDataObject pointer from the clipboard
  1845. IDataObject *lpDataObj = (IDataObject *) GetProp(hClipWnd,
  1846. CLIPBOARD_DATA_OBJECT_PROP);
  1847. Assert(lpDataObj);
  1848. hglobal = PersistDataObjectToHGlobal(lpDataObj);
  1849. LEWARN(!hglobal, "Could not persist data object!");
  1850. // We cannot do much if this fails. We will just not be able
  1851. // to rehydrate the DataObject when someone calls OleGetClipboard
  1852. if (hglobal)
  1853. {
  1854. if (SSSetClipboardData(g_cfMoreOlePrivateData, hglobal))
  1855. {
  1856. hglobal = NULL; //Clipboard takes ownership
  1857. }
  1858. else
  1859. {
  1860. LEWARN(FALSE,
  1861. "SetClipboardData failed for cfMoreOlePrivateData");
  1862. GlobalFree(hglobal);
  1863. hglobal = NULL;
  1864. }
  1865. }
  1866. // Turn off the flags so they get copied correctly in g_cfOlePrivateData.
  1867. pFormatEtcDataArray->_dwMiscArrayFlags &= ~FETC_OFFER_OLE1;
  1868. pFormatEtcDataArray->_dwMiscArrayFlags &= ~FETC_OFFER_OBJLINK;
  1869. } // if fPersistDataObjOnFlush
  1870. // upate the number of Formats.
  1871. pFormatEtcDataArray->_cFormats = dwFlushedFormats;
  1872. // Data has been rendered and Enumerator Data has been updated..
  1873. // update the enumerator on the clipboard. This is necessary even if
  1874. // it doesn't change to update the Sequence Number.
  1875. // REVIEW: Should we keep the enumerator around at all
  1876. // in PersistDataObjOnFlush case?
  1877. if ( hglobal = GlobalAlloc((GMEM_MOVEABLE|GMEM_DDESHARE),
  1878. pFormatEtcDataArray->_dwSize) )
  1879. {
  1880. if(pClipFormatEtcDataArray = (FORMATETCDATAARRAY *) GlobalLock(
  1881. hglobal))
  1882. {
  1883. _xmemcpy (pClipFormatEtcDataArray,
  1884. pFormatEtcDataArray,
  1885. pFormatEtcDataArray->_dwSize);
  1886. GlobalUnlock(hglobal);
  1887. if(SSSetClipboardData(g_cfOlePrivateData, hglobal))
  1888. {
  1889. hglobal = NULL; // on success clipboard takes ownsership
  1890. }
  1891. }
  1892. if (hglobal)
  1893. {
  1894. GlobalFree(hglobal);
  1895. }
  1896. }
  1897. } //if pFormatEtcDataArray
  1898. // Note: pFormatEtcDataArray is PrivMemFree-d in RemoveClipboardDataObject
  1899. // now get rid of the data object on the clipboard && local
  1900. // clipboard window
  1901. hresult = RemoveClipboardDataObject(hClipWnd,
  1902. CLIPWND_REMOVEFROMCLIPBOARD);
  1903. // now close the clipboard
  1904. if( !SSCloseClipboard() )
  1905. {
  1906. LEDebugOut((DEB_WARN, "WARNING: Can't close clipboard!\n"));
  1907. // if hresult != NOERROR, then RemoveClipboardDataObject
  1908. // failed--as it would be the first failure, we do not want
  1909. // to mask that error code with CLIPBRD_E_CANT_CLOSE.
  1910. if( hresult == NOERROR )
  1911. {
  1912. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  1913. }
  1914. }
  1915. //
  1916. // END: CLOSECLIPBOARD
  1917. //
  1918. errRtn:
  1919. LEDebugOut((DEB_TRACE, "%p OUT OleFlushClipboard ( %lx )\n", NULL,
  1920. hresult));
  1921. OLETRACEOUT((API_OleFlushClipboard, hresult));
  1922. return hresult;
  1923. }
  1924. //+-------------------------------------------------------------------------
  1925. //
  1926. // Function: OleGetClipboard
  1927. //
  1928. // Synopsis: Retrieves an IDataObject * from the clipboard.
  1929. //
  1930. // Effects:
  1931. //
  1932. // Arguments: [ppDataObj] -- where to put the data object pointer
  1933. //
  1934. // Requires:
  1935. //
  1936. // Returns: HRESULT
  1937. //
  1938. // Signals:
  1939. //
  1940. // Modifies:
  1941. //
  1942. // Algorithm:
  1943. // Excepting a hack for 16bit, we open the clipboard and
  1944. // prefetch any private clipboard formats we may have
  1945. // put there (currently g_cfDataObject and g_cfOlePrivateData).
  1946. //
  1947. // We then always create a fake data object to return to the
  1948. // caller. The QueryInterface on this data object is tweaked
  1949. // in such a way to preserve identity (see CClipDataObject::
  1950. // QueryInterface). This fake data object always tries to
  1951. // satisfy requests (such as QueryGetData) locally by using
  1952. // information stored internally (from g_cfOlePrivateData) or
  1953. // by looking on the clipboard. This has a significant
  1954. // speed advantage. If there is a real data object on the
  1955. // clipboard, then we will fetch the interface only when
  1956. // needed. See clipdata.cpp for more details.
  1957. // NOTE: In the async support (persist on flush) case, we do
  1958. // not use this Fake data object. Read further below about
  1959. // the persist on flush mechanism.
  1960. //
  1961. // To retrieve the marshalled IDataObject pointer, we first
  1962. // look for g_cfDataObject on the clipboard and retrieve the
  1963. // hGlobal associated with that format. The hGlobal contains
  1964. // the window handle of the private clipboard window of the
  1965. // process that called OleSetClipboard. We use this window
  1966. // handle to RPC over to the server process and get the
  1967. // IDataObject data transfer object. This is exactly the same
  1968. // mechanism used by Drag'n'Drop. As mentioned above, we do
  1969. // this only when necessary as an optimization.
  1970. //
  1971. // Async Clipboard (Persist on Flush) Mechanism:
  1972. // ---------------------------------------------
  1973. // We have added a capability for the clipboard data object to
  1974. // re-hydrate itself when someone calls OleGetClipboard after
  1975. // OleFlushClipboard. The idea being that OleFlushClipboard forces
  1976. // a data object to flush *all* its formats which may be expensive
  1977. // to flush and also that lindex etc are not honored during
  1978. // flushing. So some data object providers find that inefficient.
  1979. //
  1980. // To get the async capability, a data object must offer data on
  1981. // a format called "OleClipboardPersistOnFlush". This works
  1982. // as a flag telling OLE to use this async mechanism. Also, the
  1983. // DataObject *must* support IPersistStream for the magic to work.
  1984. //
  1985. // When OleSetClipboard is called, if we notice this special format
  1986. // we set a flag during SetClipboardFormats. Then, during OleFlushCB
  1987. // we flush only this single format. OLE does not care otherwise for
  1988. // what data is offered on this format. However, to keep things simple
  1989. // we will ask people to keep ptd=NULL, dwAspect=CONTENT, lindex=-1,
  1990. // and tymed=HGLOBAL.
  1991. //
  1992. // More importantly, during OleFlushCB, we save the DataObject into
  1993. // a stream, wrap it in an HGLOBAL and store it on the clipboard in
  1994. // a private format called "MoreOlePrivateData".
  1995. //
  1996. // When OleGetClipboard is called, the availability of this private
  1997. // format on the clipboard is a signal that we should recreate
  1998. // the DataObject from its persisted state and hand it to the caller,
  1999. // instead of using the standard way (of handing back an OLE wrapper).
  2000. // Thus, once OleGetCB succeeds, the client is directly talking to
  2001. // the real DataObject and OLE is completely out of the way (except
  2002. // that we keep the DataObject handed out in the TLS so that
  2003. // repeated OleGetCBs are fast).
  2004. //
  2005. //
  2006. // History: dd-mmm-yy Author Comment
  2007. // 30-Jun-94 alexgo added a hack for hosehead 16bit apps
  2008. // 16-May-94 alexgo reduced the amount of work done between
  2009. // Open and CloseClipboard
  2010. // 16-Mar-94 alexgo author
  2011. //
  2012. // Notes: We must only hold the clipboard open for a small amount of
  2013. // time because apps are calling OleGetClipboard to poll the
  2014. // clipboard state during idle time. If the clipboard is held
  2015. // open for a long period of time, this leads to frequent
  2016. // collisions between multiple apps running simultaneously.
  2017. // In particular, we should not make any rpc's during the time
  2018. // in which we hold the clipboard open.
  2019. //
  2020. // If we are in WOW and the caller of OleGetClipboard is
  2021. // the clipboard owner, then we will simply return the data
  2022. // object straight from our private clipboard window. We
  2023. // need to do this because some 16bit apps (such as Project)
  2024. // have broken reference counting. See comments below in
  2025. // the code.
  2026. //
  2027. //--------------------------------------------------------------------------
  2028. STDAPI OleGetClipboard( IDataObject **ppDataObj )
  2029. {
  2030. OLETRACEIN((API_OleGetClipboard, PARAMFMT("ppDataObj= %p"), ppDataObj));
  2031. LEDebugOut((DEB_TRACE, "%p _IN OleGetClipboard(%p)\n", NULL, ppDataObj));
  2032. // Local variables
  2033. HRESULT hresult;
  2034. HWND hClipWnd = NULL; // clipboard owner
  2035. HGLOBAL hOlePrivateData = NULL;
  2036. // Validation checks
  2037. VDATEHEAP();
  2038. VDATEPTROUT_LABEL(ppDataObj, IDataObject *, errNoChkRtn, hresult);
  2039. *ppDataObj = NULL;
  2040. //
  2041. // HACK ALERT!!!!
  2042. //
  2043. // 16bit Project has a cute reference counting scheme; if they
  2044. // own the clipboard, they just call Release on the data object
  2045. // they put on the clipboard instead of the data object we
  2046. // return from OleGetClipboard (thanks guys).
  2047. //
  2048. // to work around this, if we are in wow and the caller owns
  2049. // the clipboard, we simply AddRef the data object given to us
  2050. // in OleSetClipboard and return it.
  2051. //
  2052. // We do NOT do this for 32bit OLE for several reasons:
  2053. // 1. Even though the caller owns the clipboard, he
  2054. // does not necessarily control the data object given to
  2055. // OleSetClipboard (for example, he can get a data object
  2056. // from IOO::GetClipboardData). Thus, it is important
  2057. // that we wrap the data object on the clipboard
  2058. // (see comments above in the algorithm section)
  2059. // 2. Hopefully, the new algorithm makes it harder for
  2060. // apps to get away with doing bad stuff
  2061. if( IsWOWThread() )
  2062. {
  2063. hClipWnd = VerifyCallerIsClipboardOwner();
  2064. if( hClipWnd != NULL )
  2065. {
  2066. // the caller does own the clipboard, just
  2067. // return the data object put there
  2068. *ppDataObj = (IDataObject *)GetProp( hClipWnd,
  2069. CLIPBOARD_DATA_OBJECT_PROP);
  2070. if( *ppDataObj )
  2071. {
  2072. (*ppDataObj)->AddRef();
  2073. hresult = NOERROR;
  2074. // leave the OleGetClipboard
  2075. }
  2076. // else FALL-THROUGH!!
  2077. // This is the case where the clipboard has
  2078. // been flushed but the calling app is still the
  2079. // 'owner'. We need to construct a fake data
  2080. // object in this case.
  2081. }
  2082. } // end of 16-bit Hack.
  2083. // see if there is a DataObject that has been handed out.
  2084. #ifndef _CHICAGO_
  2085. if (NULL == *ppDataObj)
  2086. {
  2087. GetClipDataObjectFromTLS(ppDataObj);
  2088. // *ppDataObj will be non-NULL if this succeeds.
  2089. if (*ppDataObj)
  2090. {
  2091. hresult = NOERROR;
  2092. }
  2093. }
  2094. #endif // _CHICAGO_
  2095. // If still don't have a DataObject try to retrieve one from the Clipboard.
  2096. if (NULL == *ppDataObj)
  2097. {
  2098. if (SSIsClipboardFormatAvailable(g_cfMoreOlePrivateData))
  2099. {
  2100. // This indicates that someone has called OleFlushClipboard and
  2101. // requested the persistDataObjOnFlush option.
  2102. hresult = CreateClipDataObjectFromPersistedData(ppDataObj);
  2103. }
  2104. else
  2105. {
  2106. // This is the normal route that most calls will take!
  2107. hresult = CreateWrapperClipDataObjectFromFormatsArray(ppDataObj);
  2108. }
  2109. }
  2110. #if DBG == 1
  2111. // make the data object is non-NULL on success and NULL on failure
  2112. if( hresult != NOERROR )
  2113. {
  2114. Assert(*ppDataObj == NULL);
  2115. }
  2116. else
  2117. {
  2118. Assert(*ppDataObj != NULL);
  2119. }
  2120. #endif // DBG == 1
  2121. LEDebugOut((DEB_TRACE, "%p OUT OleGetClipboard ( %lx ) [ %p ]\n",
  2122. NULL, hresult, *ppDataObj));
  2123. // register the new IDataObject interface for HookOle
  2124. CALLHOOKOBJECTCREATE(hresult,CLSID_NULL,IID_IDataObject,
  2125. (IUnknown **)ppDataObj);
  2126. errNoChkRtn:
  2127. OLETRACEOUT((API_OleGetClipboard, hresult));
  2128. return hresult;
  2129. }
  2130. //+-------------------------------------------------------------------------
  2131. //
  2132. // Function: GetClipDataObjectFromTLS
  2133. //
  2134. // Synopsis: Get the cached dataObject pointer from TLS if fresh.
  2135. //
  2136. // Arguments: [ppDataObj] Out pointer for returning pDataObject
  2137. //
  2138. // Returns: void (caller must use the out parameter).
  2139. //
  2140. // Algorithm: 1. check if the dataObject we have in TLS is up to date.
  2141. // 2. if uptodate, AddRef it and return
  2142. // 3. if not, Release the TLS data object and clear the field.
  2143. //
  2144. // History: dd-mmm-yy Author Comment
  2145. // 02-May-99 MPrabhu Created
  2146. //
  2147. //+-------------------------------------------------------------------------
  2148. void GetClipDataObjectFromTLS(IDataObject **ppDataObj)
  2149. {
  2150. Assert(ppDataObj && *ppDataObj==NULL);
  2151. HRESULT hresult;
  2152. COleTls tls(hresult);
  2153. if (SUCCEEDED(hresult))
  2154. {
  2155. // attempt to get from TLS
  2156. if (tls->pDataObjClip)
  2157. {
  2158. // Is the dataObject up to date?
  2159. if (GetClipboardSequenceNumber() == tls->dwClipSeqNum)
  2160. {
  2161. // It is up to date, AddRef it as appropriate.
  2162. if (tls->fIsClipWrapper)
  2163. {
  2164. // We handed out the wrapper. Weak AddRef.
  2165. ((CClipDataObject*)tls->pDataObjClip)->AddRef(); // !!!!should not not not be strong increment.
  2166. }
  2167. else
  2168. {
  2169. // We do a strong AddRef ... with the callers
  2170. // responsibility to call Release() corresponding
  2171. // to each successful call to OleGetClipboard.
  2172. (tls->pDataObjClip)->AddRef();
  2173. }
  2174. *ppDataObj = tls->pDataObjClip;
  2175. }
  2176. else
  2177. {
  2178. // Our cached data object is stale. Clear it.
  2179. // !!this should be a strong release on the data object.
  2180. if (tls->fIsClipWrapper)
  2181. {
  2182. ((CClipDataObject*)tls->pDataObjClip)->InternalRelease();
  2183. }
  2184. else
  2185. {
  2186. (tls->pDataObjClip)->Release();
  2187. }
  2188. // Clear the tls dataObj as it is useless.
  2189. tls->pDataObjClip = NULL;
  2190. *ppDataObj = NULL;
  2191. // Reset the fIsClipWrapper to the more common possibility
  2192. // This is just to play it safe.
  2193. tls->fIsClipWrapper = TRUE;
  2194. }
  2195. }
  2196. else
  2197. {
  2198. // Don't have a data object in TLS
  2199. *ppDataObj = NULL;
  2200. }
  2201. }
  2202. else
  2203. {
  2204. // Tls contructor failed
  2205. *ppDataObj = NULL;
  2206. }
  2207. }
  2208. //+-------------------------------------------------------------------------
  2209. //
  2210. // Function: SetClipDataObjectInTLS
  2211. //
  2212. // Synopsis: Set the given DataObject in TLS.
  2213. //
  2214. // Arguments: [pDataObj] DataObject pointer to set in TLS
  2215. // [dwClipSeqNum] Win32 ClipBrd Sequence Number corresponding
  2216. // to this data object.
  2217. //
  2218. // [fIsClipWrapper]Is this our wrapper dataObject?
  2219. //
  2220. // Returns: void
  2221. //
  2222. // Algorithm: 1. Set the fields in the TLS, AddRefing the dataObject
  2223. // as appropriate.
  2224. //
  2225. // History: dd-mmm-yy Author Comment
  2226. // 02-May-99 MPrabhu Created
  2227. //
  2228. //+-------------------------------------------------------------------------
  2229. void SetClipDataObjectInTLS(
  2230. IDataObject *pDataObj,
  2231. DWORD dwClipSeqNum,
  2232. BOOL fIsClipWrapper)
  2233. {
  2234. HRESULT hresult;
  2235. COleTls tls(hresult);
  2236. if (SUCCEEDED(hresult))
  2237. {
  2238. Assert(NULL == tls->pDataObjClip);
  2239. // We must do a Strong AddRef!
  2240. if (fIsClipWrapper)
  2241. {
  2242. ((CClipDataObject *) pDataObj)->InternalAddRef();
  2243. }
  2244. else
  2245. {
  2246. pDataObj->AddRef();
  2247. }
  2248. tls->pDataObjClip = pDataObj;
  2249. // We need to remember this so that we can do the right
  2250. // thing later (call the correct AddRef, Release etc).
  2251. tls->fIsClipWrapper = fIsClipWrapper;
  2252. tls->dwClipSeqNum = dwClipSeqNum;
  2253. }
  2254. }
  2255. //+-------------------------------------------------------------------------
  2256. //
  2257. // Function: CreateClipDataObjectFromPersistedData
  2258. //
  2259. // Synopsis: Creates the real DataObject from persisted data. This is used
  2260. // during OleGetClipboard for the persist-on-flush case.
  2261. //
  2262. // Arguments: [ppDataObj] Out pointer for returning the IDataObject*
  2263. //
  2264. // Returns: HRESULT
  2265. //
  2266. // Algorithm: 1. Open clipboard and get a copy of the persisted data.
  2267. // 2. Load the DataObject from the persisted form.
  2268. // 3. Set in TLS if DataObject is loaded successfully.
  2269. //
  2270. // History: dd-mmm-yy Author Comment
  2271. // 02-May-99 MPrabhu Created
  2272. //
  2273. //+-------------------------------------------------------------------------
  2274. HRESULT CreateClipDataObjectFromPersistedData(IDataObject **ppDataObj)
  2275. {
  2276. HRESULT hresult;
  2277. HGLOBAL hMoreOlePrivateData, hMoreOlePrivateDataCopy;
  2278. DWORD dwClipSequenceNumber;
  2279. // This format has to be on the clipboard if we are here.
  2280. Assert(SSIsClipboardFormatAvailable(g_cfMoreOlePrivateData));
  2281. // Get Sequence first in case Clipboard Changes while setting up DataObject.
  2282. dwClipSequenceNumber = GetClipboardSequenceNumber();
  2283. // The original data object provider called OleFlushClipboard
  2284. // and requested the PersistDataObjOnFlush support
  2285. // We have the data object persisted in a Stream on hGlobal
  2286. // wrapped in our private format ("MoreOlePrivateData").
  2287. // Open the clipboard in preparation for the get
  2288. //
  2289. // BEGIN: OPENCLIPBOARD
  2290. //
  2291. hresult = OleOpenClipboard(NULL, NULL);
  2292. if (SUCCEEDED(hresult))
  2293. {
  2294. hMoreOlePrivateData = SSGetClipboardData(g_cfMoreOlePrivateData);
  2295. AssertSz(hMoreOlePrivateData,
  2296. "Could not get clipboard data for cfMoreOlePrivateData!");
  2297. // We make a copy of the global private data to not keep
  2298. // the clipboard locked for too long.
  2299. hMoreOlePrivateDataCopy = UtDupGlobal(
  2300. hMoreOlePrivateData,
  2301. 0 ); //GMEM_FIXED (GlobalAlloc flags)
  2302. #if DBG == 1
  2303. BOOL fCloseClipSucceeded =
  2304. #endif // DBG
  2305. SSCloseClipboard();
  2306. #if DBG == 1
  2307. // We only report this error in debug
  2308. if (!fCloseClipSucceeded)
  2309. {
  2310. LEDebugOut((DEB_ERROR, "ERROR: CloseClipboard failed!\n"));
  2311. }
  2312. #endif // DBG
  2313. //
  2314. // END: CLOSECLIPBOARD
  2315. //
  2316. // Try to revive the DataObject from the serialized stream
  2317. if (hMoreOlePrivateDataCopy)
  2318. {
  2319. hresult = LoadPersistedDataObjectFromHGlobal(
  2320. hMoreOlePrivateDataCopy,
  2321. ppDataObj) ;
  2322. AssertSz(SUCCEEDED(hresult),
  2323. "Failed to load DataObj from MoreOlePrivateData!");
  2324. }
  2325. else
  2326. {
  2327. hresult = E_OUTOFMEMORY;
  2328. *ppDataObj = NULL;
  2329. }
  2330. if (SUCCEEDED(hresult))
  2331. {
  2332. // Hold on to the dataObject pointer so that subsequent
  2333. // OleGetClipboard calls are fast.
  2334. SetClipDataObjectInTLS(
  2335. *ppDataObj,
  2336. dwClipSequenceNumber,
  2337. FALSE /*fIsWrapper*/ );
  2338. }
  2339. }
  2340. else
  2341. {
  2342. // OpenClipboard failed.
  2343. *ppDataObj = NULL;
  2344. LEDebugOut((DEB_ERROR, "ERROR: OleOpenClipboard failed!\n"));
  2345. }
  2346. return hresult;
  2347. }
  2348. //+-------------------------------------------------------------------------
  2349. //
  2350. // Function: CreateWrapperClipDataObjectFromFormatsArray
  2351. //
  2352. // Synopsis: Creates a fake wrapper data object based on the formatEtcArray
  2353. // on the clipboard.
  2354. //
  2355. // Arguments: [ppDataObj] Out pointer for returning the IDataObject*
  2356. //
  2357. // Returns: HRESULT
  2358. //
  2359. // Algorithm: 1. Open clipboard and get a copy of the format array data.
  2360. // 2. Create the wrapper data object (CClipDataObject).
  2361. // 3. Set in TLS if everything went well.
  2362. // [See notes of OleGetClipboard for more details].
  2363. //
  2364. // History: dd-mmm-yy Author Comment
  2365. // 02-May-99 MPrabhu Created from the original OleGetClipBrd
  2366. // 16-Sep-99 a-olegi Fixed regression from NT4
  2367. //
  2368. //+-------------------------------------------------------------------------
  2369. HRESULT CreateWrapperClipDataObjectFromFormatsArray(IDataObject **ppDataObj)
  2370. {
  2371. HRESULT hresult;
  2372. DWORD dwClipSequenceNumber;
  2373. FORMATETCDATAARRAY *pFormatEtcDataArray = NULL;
  2374. // Get Sequence first in case Clipboard Changes while setting up DataObject.
  2375. #ifdef _CHICAGO_
  2376. dwClipSequenceNumber = 0;
  2377. #else
  2378. dwClipSequenceNumber = GetClipboardSequenceNumber();
  2379. #endif // _CHICAGO_
  2380. //
  2381. // BEGIN: OPENCLIPBOARD
  2382. //
  2383. hresult = OleOpenClipboard(NULL, NULL);
  2384. if(SUCCEEDED(hresult))
  2385. {
  2386. // Try to fetch the formatetc data. Note that we may
  2387. // not need to use this data if we can successfully rpc
  2388. // over to the clipboard data source process to get the original
  2389. // data object.
  2390. // again, we don't worry about capturing errors here; if something
  2391. // fails, then prgFormats will remain NULL
  2392. if( SSIsClipboardFormatAvailable(g_cfOlePrivateData) )
  2393. {
  2394. HGLOBAL hOlePrivateData;
  2395. FORMATETCDATAARRAY *pClipFormats;
  2396. hOlePrivateData = SSGetClipboardData(g_cfOlePrivateData);
  2397. if( hOlePrivateData)
  2398. {
  2399. // hOlePrivateData is an hglobal with a
  2400. // zero terminated array of formatetcs in it.
  2401. //
  2402. // we count them up and copy into an
  2403. // *allocated* peice of memory, which may get passed
  2404. // to our fake clipboard data object.
  2405. pClipFormats = (FORMATETCDATAARRAY *)GlobalLock(hOlePrivateData);
  2406. // jsimmons - windows bug 357734. This code previously assumed
  2407. // that GlobalLock could never fail. Well, we have user dumps
  2408. // to prove otherwise. The cause of the failure is unknown.
  2409. Win4Assert((pClipFormats != NULL) && "GlobalLock failed!");
  2410. if (!pClipFormats)
  2411. {
  2412. hresult = HRESULT_FROM_WIN32(GetLastError());
  2413. }
  2414. else if( (pClipFormats->_dwSig == 0) && (pClipFormats->_dwSize > 0) )
  2415. {
  2416. // mfeingol - Windows bug 124621
  2417. //
  2418. // This is needed for 32/64 interop
  2419. // We could be receiving a FORMATETCDATAARRAY from
  2420. // a 32 or a 64 bit process here, and because FORMATETC
  2421. // structures contain a pointer field, the blobs we get from
  2422. // the clipboard look different depending on their origin.
  2423. //
  2424. // This code could still run into trouble if we have some kind
  2425. // of network clipboard operating here, but for local machine
  2426. // operations and 32/64 bit interop, we should be okay
  2427. size_t stSize;
  2428. GetCopiedFormatEtcDataArraySize (pClipFormats, &stSize);
  2429. // Signature must be zero and _cFormats > 0
  2430. pFormatEtcDataArray = (FORMATETCDATAARRAY *)PrivMemAlloc(
  2431. stSize);
  2432. // Oleg Ivanov (a-olegi) 9/16 NTBUG #382054
  2433. //
  2434. // Fixed regression from NT4. We must not blindly copy data
  2435. // from OlePrivateData. Rather, we will be conservative
  2436. // and check if each format is available. This fixes issues
  2437. // with major applications like Lotus 1-2-3 on Windows 2000.
  2438. if( pFormatEtcDataArray )
  2439. {
  2440. // Properly translate the clipboard's FORMATETCDATAARRAY into
  2441. // something we understand
  2442. CopyFormatEtcDataArray (pFormatEtcDataArray, pClipFormats, stSize, TRUE);
  2443. Assert(pFormatEtcDataArray->_cRefs == 1);
  2444. }
  2445. else
  2446. {
  2447. hresult = E_OUTOFMEMORY;
  2448. }
  2449. GlobalUnlock(hOlePrivateData);
  2450. }
  2451. } //if (hOlePrivateData)
  2452. } //if g_cfOlePrivateData is available
  2453. if( !SSCloseClipboard() )
  2454. {
  2455. LEDebugOut((DEB_ERROR, "ERROR: CloseClipboard failed!\n"));
  2456. ; // no-op to keep the compiler happy.
  2457. }
  2458. //
  2459. // END: CLOSECLIPBOARD
  2460. //
  2461. if (SUCCEEDED(hresult))
  2462. {
  2463. // Create our own clipboard data object. We will return
  2464. // this wrapper data object to the caller
  2465. // ownership of pFormatEtcDataArray is taken over by the ClipData.
  2466. hresult = CClipDataObject::Create(
  2467. ppDataObj,
  2468. pFormatEtcDataArray);
  2469. }
  2470. // if the Create call succeeds, the fake data object
  2471. // will take ownership of the formatetc array. If it
  2472. // failed, we should free it.
  2473. if (SUCCEEDED(hresult))
  2474. {
  2475. // Remeber DataObject handed out so can use it again.
  2476. SetClipDataObjectInTLS(
  2477. *ppDataObj,
  2478. dwClipSequenceNumber,
  2479. TRUE /*fIsWrapper*/);
  2480. }
  2481. else
  2482. {
  2483. if(pFormatEtcDataArray )
  2484. {
  2485. PrivMemFree(pFormatEtcDataArray);
  2486. }
  2487. }
  2488. }
  2489. else
  2490. {
  2491. // OpenClipboard failed.
  2492. *ppDataObj = NULL;
  2493. LEDebugOut((DEB_ERROR, "ERROR: OleOpenClipboard failed!\n"));
  2494. }
  2495. return hresult;
  2496. }
  2497. //+-------------------------------------------------------------------------
  2498. //
  2499. // Function: OleIsCurrentClipboard
  2500. //
  2501. // Synopsis: returns NOERROR if the given data object is still on the
  2502. // clipboard, false otherwise.
  2503. //
  2504. // Effects:
  2505. //
  2506. // Arguments: [pDataObj] -- the data object to check against
  2507. //
  2508. // Requires: g_cfDataObject must be registered
  2509. //
  2510. // Returns: S_OK, S_FALSE
  2511. //
  2512. // Signals:
  2513. //
  2514. // Modifies:
  2515. //
  2516. // Algorithm: 1. Verify caller is the clipboard owner
  2517. // 2. Compare the data object pointer on our private clipboard
  2518. // window against the data object pointer given by the caller
  2519. //
  2520. // History: dd-mmm-yy Author Comment
  2521. // 12-Aug-94 alexgo optimized
  2522. // 16-Mar-94 alexgo author
  2523. //
  2524. // Notes:
  2525. //
  2526. //--------------------------------------------------------------------------
  2527. STDAPI OleIsCurrentClipboard( IDataObject *pDataObj )
  2528. {
  2529. OLETRACEIN((API_OleIsCurrentClipboard, PARAMFMT("pDataObj= %p"), pDataObj));
  2530. HRESULT hresult = ResultFromScode(S_FALSE);
  2531. HWND hClipWnd;
  2532. IDataObject * pClipDataObject = NULL;
  2533. VDATEHEAP();
  2534. LEDebugOut((DEB_TRACE, "%p _IN OleIsCurrentClipboard ( %p )\n",
  2535. NULL, pDataObj));
  2536. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDataObject,(IUnknown **)&pDataObj);
  2537. if( pDataObj == NULL )
  2538. {
  2539. Assert(hresult == ResultFromScode(S_FALSE));
  2540. goto errRtn;
  2541. }
  2542. // the caller must be the current clipboard owner
  2543. if( (hClipWnd = VerifyCallerIsClipboardOwner()) == NULL )
  2544. {
  2545. LEDebugOut((DEB_WARN,
  2546. "WARNING: Caller not clipboard owner\n"));
  2547. Assert(hresult == ResultFromScode(S_FALSE));
  2548. goto errRtn;
  2549. }
  2550. // In order for the data object to *really* be on the clipboard,
  2551. // the g_cfDataObject must have the HWND of the private clipboard
  2552. // window (even if we still have the DataObject pointer stuck
  2553. // on the private clipboard window)
  2554. // HOWEVER, the data on the clipboard may change at any point
  2555. // in time that we don't hold it open. In order to check this data,
  2556. // we'd have to open the clipboard (a shared resource). Since
  2557. // we don't get any useful information from this check, we don't
  2558. // bother doing it.
  2559. // now get the pointer property from the window
  2560. pClipDataObject = (IDataObject *)GetProp(hClipWnd,
  2561. CLIPBOARD_DATA_OBJECT_PROP);
  2562. // since we are in the same process, we can directly compare
  2563. // these pointers.
  2564. if( pClipDataObject == pDataObj)
  2565. {
  2566. hresult = NOERROR;
  2567. }
  2568. else
  2569. {
  2570. hresult = ResultFromScode(S_FALSE);
  2571. }
  2572. errRtn:
  2573. LEDebugOut((DEB_TRACE, "%p OUT OleIsCurrentClipboard ( %lx )\n",
  2574. NULL, hresult));
  2575. OLETRACEOUT((API_OleIsCurrentClipboard, hresult));
  2576. return hresult;
  2577. }
  2578. //+-------------------------------------------------------------------------
  2579. //
  2580. // Function: OleOpenClipboard (internal)
  2581. //
  2582. // Synopsis: Opens the clipboard
  2583. //
  2584. // Effects:
  2585. //
  2586. // Arguments: [hClipWnd] -- open the clipboard with this window
  2587. // may be NULL.
  2588. // [phClipWnd] -- where to put the clipboard owner
  2589. // may be NULL
  2590. //
  2591. // Requires:
  2592. //
  2593. // Returns: NOERROR: the clipboard was opened successfully
  2594. // CLIPBRD_E_CANT_OPEN: could not open the clipboard
  2595. //
  2596. // Signals:
  2597. //
  2598. // Modifies:
  2599. //
  2600. // Algorithm: If we can't open the clipboard, we sleep for a bit and then
  2601. // try again (in case we collided with another app). This
  2602. // algorithm may need to be improved.
  2603. //
  2604. // History: dd-mmm-yy Author Comment
  2605. // 17-May-94 alexgo author
  2606. //
  2607. // Notes:
  2608. //
  2609. //--------------------------------------------------------------------------
  2610. HRESULT OleOpenClipboard( HWND hClipWnd, HWND *phClipWnd )
  2611. {
  2612. HRESULT hresult = NOERROR;
  2613. VDATEHEAP();
  2614. LEDebugOut((DEB_ITRACE, "%p _IN OleOpenClipboard ( %p )\n", NULL,
  2615. phClipWnd ));
  2616. if( hClipWnd == NULL )
  2617. {
  2618. // go ahead and create a clipboard window if we don't already
  2619. // have one
  2620. hClipWnd = GetPrivateClipboardWindow(CLIP_CREATEIFNOTTHERE);
  2621. }
  2622. if( !hClipWnd )
  2623. {
  2624. hresult = ResultFromScode(E_FAIL);
  2625. }
  2626. else if( !SSOpenClipboard(hClipWnd) )
  2627. {
  2628. // OpenClipboard will fail if another window (i.e. another
  2629. // process or thread) has it open
  2630. // sleep for a bit and then try again
  2631. LEDebugOut((DEB_WARN, "WARNING: First try to open clipboard "
  2632. "failed!, sleeping 1 second\n"));
  2633. Sleep(0); // give up our time quanta and allow somebody
  2634. // else to get scheduled in.
  2635. if( !SSOpenClipboard(hClipWnd) )
  2636. {
  2637. LEDebugOut((DEB_WARN,
  2638. "WARNING: Unable to open clipboard on "
  2639. "second try\n"));
  2640. hresult = ResultFromScode(CLIPBRD_E_CANT_OPEN);
  2641. }
  2642. }
  2643. if( phClipWnd )
  2644. {
  2645. *phClipWnd = hClipWnd;
  2646. }
  2647. LEDebugOut((DEB_ITRACE, "%p OUT OleOpenClipboard ( %lx ) "
  2648. "[ %p ]\n", NULL, hresult, (phClipWnd)? *phClipWnd : 0));
  2649. return hresult;
  2650. }
  2651. //+-------------------------------------------------------------------------
  2652. //
  2653. // Function: OleSetClipboard
  2654. //
  2655. // Synopsis: puts the given IDataObject on the clipboard
  2656. //
  2657. // Effects:
  2658. //
  2659. // Arguments: [pDataObj] -- the data object to put on the clipboard
  2660. // if NULL, the clipboard is cleared
  2661. //
  2662. // Requires:
  2663. //
  2664. // Returns: HRESULT
  2665. //
  2666. // Signals:
  2667. //
  2668. // Modifies:
  2669. //
  2670. // Algorithm: 1. clear the clipboard of any data object and other data
  2671. // that may be there.
  2672. // 2. Set [pDataOjbect] as the new clipboard data object
  2673. // 3. Set any downlevel formats on the clipboard for delayed
  2674. // rendering.
  2675. //
  2676. // History: dd-mmm-yy Author Comment
  2677. // 25-Nov-96 gopalk Fail the call if OleInitialize has not
  2678. // been called
  2679. // 11-Apr-94 alexgo added support for downlevel formats
  2680. // 24-Mar-94 alexgo allow NULL for pDataObject
  2681. // 16-Mar-94 alexgo author
  2682. //
  2683. // Notes:
  2684. //
  2685. //--------------------------------------------------------------------------
  2686. STDAPI OleSetClipboard( IDataObject *pDataObject )
  2687. {
  2688. OLETRACEIN((API_OleSetClipboard, PARAMFMT("pDataObject= %p"), pDataObject));
  2689. LEDebugOut((DEB_TRACE, "%p _IN OleSetClipboard(%p)\n", NULL, pDataObject));
  2690. // Local variables
  2691. HRESULT hresult = NOERROR;
  2692. HWND hClipWnd;
  2693. // Validation checks
  2694. VDATEHEAP();
  2695. if(!IsOleInitialized()) {
  2696. hresult = CO_E_NOTINITIALIZED;
  2697. goto logRtn;
  2698. }
  2699. CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IDataObject,(IUnknown **)&pDataObject);
  2700. //
  2701. //
  2702. // BEGIN: OPENCLIPBOARD
  2703. //
  2704. //
  2705. hresult = OleOpenClipboard(NULL, &hClipWnd);
  2706. if( hresult != NOERROR )
  2707. {
  2708. goto logRtn;
  2709. }
  2710. // now clear the data and take ownership of the clipboard with
  2711. // an EmptyClipboard call. Note that EmptyClipboard will call
  2712. // back to our private clipboard window proc (ClipboardWndProc)
  2713. // with a WM_DESTROYCLIPBOARD message. ClipboardWndProc will
  2714. // remove any existing data objects (and do the IDO->Release).
  2715. if( !SSEmptyClipboard() )
  2716. {
  2717. LEDebugOut((DEB_WARN, "WARNING: Unable to empty clipboard\n"));
  2718. hresult = ResultFromScode(CLIPBRD_E_CANT_EMPTY);
  2719. goto errRtn;
  2720. }
  2721. // NULL is a legal value for pDataObject. Basically, it says
  2722. // "clear the clipboard" (which was done above in the EmptyClipboard
  2723. // call).
  2724. if( pDataObject )
  2725. {
  2726. // now we set the data object onto the clipboard
  2727. hresult = SetClipboardDataObject(hClipWnd, pDataObject);
  2728. if( hresult == NOERROR )
  2729. {
  2730. // now set all of our downlevel formats on the
  2731. // clipboard
  2732. hresult = SetClipboardFormats(hClipWnd, pDataObject);
  2733. }
  2734. }
  2735. errRtn:
  2736. // now close the clipboard.
  2737. if( !SSCloseClipboard() )
  2738. {
  2739. LEDebugOut((DEB_WARN, "WARNING: Unable to close clipboard\n"));
  2740. // don't overwrite an earlier error code!
  2741. if( hresult == NOERROR )
  2742. {
  2743. hresult = ResultFromScode(CLIPBRD_E_CANT_CLOSE);
  2744. }
  2745. }
  2746. //
  2747. //
  2748. // END: CLOSECLIPBOARD
  2749. //
  2750. //
  2751. logRtn:
  2752. LEDebugOut((DEB_TRACE, "%p OUT OleSetClipboard ( %p ) \n", NULL,
  2753. hresult));
  2754. OLETRACEOUT((API_OleSetClipboard, hresult));
  2755. return hresult;
  2756. }
  2757. //+-------------------------------------------------------------------------
  2758. //
  2759. // Function: PersistDataObjectToHGlobal (internal)
  2760. //
  2761. // Synopsis: Saves the clibboard data object to a stream.
  2762. //
  2763. // Arguments: [lpDataObj] -- IDataobject pointer to persist
  2764. //
  2765. // Returns: HGLOBAL
  2766. //
  2767. // Algorithm: 1. Ask DataObject to persist itself into a stream created
  2768. // on an HGLOBAL and return the underlying HGLOBAL.
  2769. //
  2770. // History: dd-mmm-yy Author Comment
  2771. // 03-Mar-99 mprabhu author
  2772. //
  2773. //+-------------------------------------------------------------------------
  2774. HGLOBAL PersistDataObjectToHGlobal( IDataObject *pDataObj )
  2775. {
  2776. HRESULT hr = NOERROR;
  2777. HGLOBAL hglobal = NULL;
  2778. IPersistStream *lpPS = NULL;
  2779. IStream *lpStm;
  2780. hr = pDataObj->QueryInterface(IID_IPersistStream, (void **)&lpPS);
  2781. // We are in this function only because IDataObject owner promised to
  2782. // support this mechanism.
  2783. AssertSz(SUCCEEDED(hr),
  2784. "DataObject promised to but does not support IPersistStream");
  2785. hr = CreateStreamOnHGlobal(
  2786. NULL, // allocate hGlobal
  2787. FALSE, // do not delete on Release() since
  2788. &lpStm ); // the Win32 Clipboard will take ownership of hGlobal
  2789. if (SUCCEEDED(hr))
  2790. {
  2791. // Request the data object to save itself to the stream.
  2792. hr = OleSaveToStream(lpPS, lpStm);
  2793. if (SUCCEEDED(hr))
  2794. {
  2795. // Get the hGlobal under the stream
  2796. // (This gets handed over to the Win32 Clipboard)
  2797. hr = GetHGlobalFromStream(lpStm, &hglobal);
  2798. Assert(SUCCEEDED(hr));
  2799. }
  2800. }
  2801. if (lpPS)
  2802. lpPS->Release();
  2803. return hglobal;
  2804. }
  2805. //+-------------------------------------------------------------------------
  2806. //
  2807. // Function: LoadPersistedDataObjectFromHGlobal (internal)
  2808. //
  2809. // Synopsis: Loads the clibboard data object from an HGLOBAL
  2810. //
  2811. // Arguments: [hMorePrivateData] -- [in] a copy of hMoreOlePrivateData
  2812. // [ppDataObj] -- [out] loaded IDataObect
  2813. //
  2814. // Requires: the clipboard must be open
  2815. //
  2816. // Returns: HRESULT
  2817. //
  2818. // Algorithm: 1. Wrap the HGLOBAL in a stream and call OleLoadFromStream.
  2819. //
  2820. // History: dd-mmm-yy Author Comment
  2821. // 03-Mar-99 mprabhu author
  2822. //
  2823. //+-------------------------------------------------------------------------
  2824. HRESULT LoadPersistedDataObjectFromHGlobal(
  2825. HGLOBAL hMorePrivateData,
  2826. IDataObject **ppDataObj )
  2827. {
  2828. HRESULT hr;
  2829. IStream *lpStm;
  2830. AssertSz(hMorePrivateData, "NULL private data handle!");
  2831. hr = CreateStreamOnHGlobal(
  2832. hMorePrivateData,
  2833. TRUE, //delete on Release
  2834. &lpStm);
  2835. if (SUCCEEDED(hr))
  2836. {
  2837. hr = OleLoadFromStream(lpStm, IID_IDataObject, (void **)ppDataObj);
  2838. lpStm->Release();
  2839. }
  2840. return hr;
  2841. }
  2842. //+-------------------------------------------------------------------------
  2843. //
  2844. // Function: RemoveClipboardDataObject (internal)
  2845. //
  2846. // Synopsis: removes the g_cfDataObject format from the clipboard
  2847. // along with the associated information on the private
  2848. // clipboard window
  2849. //
  2850. // Effects: the DataObject pointer will be released.
  2851. //
  2852. // Arguments: [hClipWnd] -- handle to the private clipboard window
  2853. // [fFlags] -- if CLIPWND_REMOVEFROMCLIPBOARD, then we
  2854. // will remove g_cfDataObject from the clipboard
  2855. //
  2856. // Requires: the clipboard must be open
  2857. // g_cfDataObject must be set
  2858. //
  2859. // Returns: HRESULT
  2860. //
  2861. //
  2862. // Signals:
  2863. //
  2864. // Modifies:
  2865. //
  2866. // Algorithm: we first remove the g_cfDataObject format from the clipboard
  2867. // if fFlags == CLIPWND_REMOVEFROMCLIPBOARD (see comments
  2868. // regarding this in Notes) and then remove the properties on our
  2869. // local private clipboard window, and finally release the data
  2870. // object pointer
  2871. //
  2872. // History: dd-mmm-yy Author Comment
  2873. // 16-Mar-94 alexgo author
  2874. //
  2875. // Notes: This function succeeds if there is no clipboard data object.
  2876. //
  2877. // OleSetClipboard also calls this function to remove any data
  2878. // object that may be present from a previous OleSetClipboard
  2879. // call. (Note that the call is indirect; OleSetClipboard will
  2880. // call EmptyClipboard, which will get to our clipboard window
  2881. // proc with a WM_DESTROYCLIPBOARD message). OleFlushClipboard
  2882. // will also call this function.
  2883. //
  2884. // CLIPWND_REMOVEFROMCLIPBOARD (and CLIPWND_IGNORECLIPBOARD)
  2885. // are used to handle the two different cases in which we
  2886. // need to remove the clipboard data object:
  2887. // 1. Somebody has called EmptyClipboard(). We will
  2888. // get a WM_DESTROYCLIPBOARD message in our private
  2889. // clipboard window proc. If we have an AddRef'ed
  2890. // pointer on the clipboard (well, really on our
  2891. // private clipboard window), it is imperative that
  2892. // we do the corresponding Release. However, since
  2893. // we are doing this as a result of EmptyClipboard,
  2894. // there is no need to futz with data on the clipboard
  2895. // (as it's all being deleted anyway).
  2896. //
  2897. // 2. We are in an OleFlushClipboard call. Here we
  2898. // *want* the rest of the clipboard to remain (except
  2899. // for our data object pointer), so we just need to
  2900. // disable the g_cfDataObject information.
  2901. // this is currently implemented by
  2902. // EmptyClipboard, which will change once the data object
  2903. // is implemented.
  2904. //
  2905. //--------------------------------------------------------------------------
  2906. HRESULT RemoveClipboardDataObject( HWND hClipWnd, DWORD fFlags )
  2907. {
  2908. HRESULT hresult = NOERROR;
  2909. IDataObject * pDataObj;
  2910. FORMATETCDATAARRAY * pFormatEtcDataArray = NULL;
  2911. VDATEHEAP();
  2912. LEDebugOut((DEB_ITRACE, "%p _IN RemoveClipboardDataObject ( %lx , "
  2913. "%lx )\n", NULL, hClipWnd, fFlags ));
  2914. Assert(g_cfDataObject);
  2915. // get && remove the data object pointer. We rely on
  2916. // RemoveProp to correctly handle the race condition (somebody
  2917. // else doing a GetProp simultaneously with our call).
  2918. //
  2919. // We must not delete the property since some 16-bit applications
  2920. // rely on OleIsCurrentClipboard() during the IDataObject->Release().
  2921. //
  2922. pDataObj = (IDataObject *)GetProp(hClipWnd, CLIPBOARD_DATA_OBJECT_PROP);
  2923. // now get && remove && free our private clipboard data
  2924. pFormatEtcDataArray = (FORMATETCDATAARRAY *) SetWindowLongPtr( hClipWnd,
  2925. WL_ClipPrivateData,
  2926. (LONG_PTR) 0 );
  2927. if( pFormatEtcDataArray )
  2928. {
  2929. Assert(pFormatEtcDataArray->_cRefs == 1); // should be only person holding onto the FormatEtcDataArray.
  2930. PrivMemFree(pFormatEtcDataArray);
  2931. }
  2932. // if there is no data object, then we may have already
  2933. // removed it (from a previous call here).
  2934. if( pDataObj )
  2935. {
  2936. DWORD dwAssignAptID;
  2937. // pDataObj was AddRef'ed in SetClipboardDataObject
  2938. if( !(fFlags & CLIPWND_DONTCALLAPP) )
  2939. {
  2940. pDataObj->Release();
  2941. }
  2942. // now get rid of our endpoint property. If pDataObj is
  2943. // NULL, then there is no need to do this (which is why the
  2944. // call is in this if block!)
  2945. hresult = UnAssignEndpointProperty(hClipWnd,&dwAssignAptID);
  2946. //
  2947. // Now we can remove the property after the IDataObject->Release().
  2948. //
  2949. RemoveProp(hClipWnd, CLIPBOARD_DATA_OBJECT_PROP);
  2950. }
  2951. // else HRESULT == NOERROR from initialization
  2952. if( (fFlags & CLIPWND_REMOVEFROMCLIPBOARD) &&
  2953. SSIsClipboardFormatAvailable(g_cfDataObject) )
  2954. {
  2955. HGLOBAL hMem;
  2956. HWND * phMem;
  2957. // since we can't simply remove g_cfDataObject from the clipboard
  2958. // (and keep all the other formats), we'll simply replace
  2959. // the value (the HWND of our private clipboard window) with a
  2960. // NULL. Note that we only do this if g_cfDataObject really
  2961. // exists on the clipboard (see the conditional test above)
  2962. hMem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE,
  2963. sizeof(HWND));
  2964. if( !hMem )
  2965. {
  2966. LEDebugOut((DEB_WARN, "WARNING: GlobalAlloc failed!!"
  2967. "\n"));
  2968. hresult = ResultFromScode(E_OUTOFMEMORY);
  2969. // keep trying to remove the rest of our state
  2970. goto errRtn;
  2971. }
  2972. phMem = (HWND *)GlobalLock(hMem);
  2973. if( !phMem )
  2974. {
  2975. LEDebugOut((DEB_WARN, "WARNING: GlobalLock failed!!"
  2976. "\n"));
  2977. GlobalFree(hMem);
  2978. hresult = ResultFromScode(E_OUTOFMEMORY);
  2979. // keep trying to remove the rest of our state
  2980. goto errRtn;
  2981. }
  2982. *phMem = NULL;
  2983. GlobalUnlock(hMem);
  2984. if( !SSSetClipboardData(g_cfDataObject, hMem) )
  2985. {
  2986. LEDebugOut((DEB_WARN, "WARNING: Can't RESET clipboard"
  2987. " data with SetClipboardData\n"));
  2988. GlobalFree(hMem);
  2989. // FALL THROUGH!! This is deliberate. Even if
  2990. // we can't NULL out the data on the clipboard, we
  2991. // ought to at least try to remove the rpc endpoints
  2992. // and so forth on our private clipboard window.
  2993. }
  2994. }
  2995. errRtn:
  2996. LEDebugOut((DEB_ITRACE, "%p OUT RemoveClipboardDataObject ( %lx )\n",
  2997. NULL, hresult));
  2998. return hresult;
  2999. }
  3000. //+-------------------------------------------------------------------------
  3001. //
  3002. // Function: RenderFormat, private
  3003. //
  3004. // Synopsis: Grab the content data for the given clipboard format and
  3005. // put it on the clipboard
  3006. //
  3007. // Effects:
  3008. //
  3009. // Arguments: [hClipWnd] -- the clipboard window
  3010. /// [pDataObj] -- the data object from which to get the
  3011. // data
  3012. // [cf] -- the clipboard format to put on the
  3013. // clipboard
  3014. //
  3015. // Requires: the clipboard must be open for this function to work
  3016. //
  3017. // Returns: HRESULT
  3018. //
  3019. // Signals:
  3020. //
  3021. // Modifies:
  3022. //
  3023. // Algorithm: if format ==
  3024. // g_cfNative:
  3025. // copy either OLE10_NATIVE_STREAM (if available) into
  3026. // an hglobal or put the entire storage from EmbedSource
  3027. // or EmbeddedObject on top an hglobal
  3028. // g_cfOwnerLink:
  3029. // synthesize from g_cfObjectDescriptor
  3030. // g_cfObjectLink:
  3031. // synthesize from g_cfLinkSource if not offered
  3032. // directly by the app
  3033. // all others:
  3034. // find the formatetc corresponding to the clipboard
  3035. // format and ask for data directly using that
  3036. // formatetc. In the case of multiple TYMED's, we
  3037. // prefer TYMED_ISTORAGE, then TYMED_ISTREAM, then
  3038. // handle based mediums. TYMED_FILE is not supported.
  3039. //
  3040. // History: dd-mmm-yy Author Comment
  3041. // 30-Jan-97 rogerg RenderFormat will not Render formats to the native
  3042. // clipboard if not a format the Clipboard knows about
  3043. // and it is not on an HGLOBAL.
  3044. // 11-Aug-94 alexgo optimized; now use the object's original
  3045. // formatetc for GetData calls.
  3046. // 10-Jun-94 alexgo added OLE1 support
  3047. // 11-Apr-94 alexgo author
  3048. //
  3049. // Notes: In the ideal world, we simply ask for TYMED_HGLOBAL and
  3050. // DVASPECT_CONTENT and then stuff the resulting hglobal onto
  3051. // the clipboard. However, this would require apps honoring
  3052. // the contractual obligations of an interface, which, of course,
  3053. // doesn't happen.
  3054. //
  3055. // The 16bit code effectively special cased certain formats,
  3056. // notably cfEmbeddedOjbect, g_cfLinkSource, and g_cfEmbedSource.
  3057. // The algorithm above implements behaviour similar to the
  3058. // 16bit sources. Note that new apps can take advantage of
  3059. // this functionality for app-defined formats and simplify
  3060. // their data transfer IDataObject implementations.
  3061. //
  3062. //--------------------------------------------------------------------------
  3063. HRESULT RenderFormat( HWND hClipWnd, UINT cf, IDataObject *pDataObj )
  3064. {
  3065. HRESULT hresult = E_FAIL;
  3066. STGMEDIUM medium;
  3067. FORMATETC formatetc;
  3068. VDATEHEAP();
  3069. LEDebugOut((DEB_ITRACE, "%p _IN RenderFormat ( %u , %p )\n", NULL,
  3070. cf, pDataObj));
  3071. _xmemset(&medium, 0, sizeof(STGMEDIUM));
  3072. medium.tymed = TYMED_HGLOBAL;
  3073. if( cf == g_cfNative )
  3074. {
  3075. // OLE1 format: synthesize from OLE2 data
  3076. hresult = GetNative(pDataObj, &medium);
  3077. }
  3078. else if( cf == g_cfOwnerLink )
  3079. {
  3080. // OLE1 format: synthesize from OLE2 data
  3081. hresult = GetOwnerLink(pDataObj, &medium);
  3082. }
  3083. else if( cf == g_cfObjectLink )
  3084. {
  3085. // ObjectLink is a special OLE1 format. The 16bit OLE
  3086. // allowed apps to pass their own ObjectLink data, so
  3087. // we preserve that behaviour here. First check to see
  3088. // if we can fetch it directly; if not, then we synthesize
  3089. // it.
  3090. Assert(NOERROR != hresult);
  3091. if(S_OK == MapCFToFormatetc(hClipWnd, cf, &formatetc))
  3092. {
  3093. hresult = HandleFromHandle(pDataObj, &formatetc, &medium);
  3094. }
  3095. if(NOERROR != hresult)
  3096. {
  3097. hresult = GetObjectLink(pDataObj, &medium);
  3098. }
  3099. }
  3100. else if( cf == g_cfScreenPicture && IsWOWThread() )
  3101. {
  3102. //
  3103. // HACK ALERT!!!
  3104. //
  3105. // this is a really evil hack. XL 16bit puts a data format
  3106. // "Screen Picture" on the clipboard (which is really nothing
  3107. // more than a metafile). However, since neither OLE nor
  3108. // Windows knows anything about this metafile (it's just a
  3109. // 4byte number to us), the metafile is invalid after XL shuts
  3110. // down.
  3111. //
  3112. // The cute part is that Word 6 uses Screen Picture data
  3113. // first (even if it' is invalid). As a result, without
  3114. // this hack, you can't paste any objects from XL into Word after
  3115. // XL has shut down.
  3116. //
  3117. // The hack is to never allow "Screen Picture" data to ever be
  3118. // realized onto the clipboard. Word 6 then defaults to its
  3119. // "normal" OLE2 processing.
  3120. hresult = E_FAIL;
  3121. }
  3122. else
  3123. {
  3124. // find the original formatetc given to us by the data
  3125. // object and use that to fetch the data
  3126. Assert(NOERROR != hresult);
  3127. if (S_OK == MapCFToFormatetc(hClipWnd, cf, &formatetc))
  3128. {
  3129. // get the data according to the medium specified in formatetc
  3130. if( (formatetc.tymed & TYMED_ISTORAGE) )
  3131. {
  3132. hresult = GetDataFromStorage(pDataObj, &formatetc,
  3133. &medium, NULL);
  3134. }
  3135. else if( (formatetc.tymed & TYMED_ISTREAM) )
  3136. {
  3137. hresult = GetDataFromStream(pDataObj, &formatetc,
  3138. &medium, NULL);
  3139. }
  3140. else
  3141. {
  3142. Assert(NOERROR != hresult);
  3143. // we don't support TYMED_FILE
  3144. formatetc.tymed &= ~(TYMED_FILE);
  3145. // if the clipboard format is cf > 0xC000 then make sure only TYMED_HGLOBAL
  3146. // is rendered to the clibpoard. The native clipboard just puts the DWORD on the
  3147. // clipboard regardless of the data.
  3148. // NT 5.0 Change in behavior: This will break an application if it put a DWORD with a TYMED other
  3149. // than HGLOBAL and a native clipboard application tries to get it. .
  3150. if (cf > 0xC000)
  3151. {
  3152. formatetc.tymed &= TYMED_HGLOBAL;
  3153. }
  3154. // we don't need to do any more checking on the
  3155. // formatetc. Even if we have a 'bogus' formatetc,
  3156. // it's what the app told us it could support.
  3157. if (TYMED_NULL != formatetc.tymed) // Don't try to render TYMED_NULL
  3158. {
  3159. hresult = HandleFromHandle(pDataObj,
  3160. &formatetc,
  3161. &medium);
  3162. }
  3163. }
  3164. }
  3165. }
  3166. // if hresult is NOERROR, then we have successfully retrieved
  3167. // an HGLOBAL that can simply be stuffed onto the clipboard.
  3168. if(NOERROR == hresult)
  3169. {
  3170. Assert(NULL != medium.hGlobal);
  3171. if( !SSSetClipboardData(cf, medium.hGlobal ) )
  3172. {
  3173. LEDebugOut((DEB_WARN, "WARNING: SetClipboardData "
  3174. "failed!\n"));
  3175. // Can Crash GlobalFree in Cases if pass in garbage.
  3176. __try
  3177. {
  3178. ReleaseStgMedium(&medium);
  3179. }
  3180. __except (EXCEPTION_EXECUTE_HANDLER)
  3181. {
  3182. }
  3183. hresult = ResultFromScode(CLIPBRD_E_CANT_SET);
  3184. }
  3185. }
  3186. LEDebugOut((DEB_ITRACE, "%p OUT RenderFormat ( %lx )\n", NULL,
  3187. hresult));
  3188. return hresult;
  3189. }
  3190. //+-------------------------------------------------------------------------
  3191. //
  3192. // Function: SetClipboardDataObject (internal)
  3193. //
  3194. // Synopsis: Puts an IDataObject on the private clipboard window
  3195. // and a handle to the clipboard window on the clipboard
  3196. //
  3197. // Effects: pDataObject will get AddRef'ed
  3198. //
  3199. // Arguments: [hClipWnd] -- handle to the private clipboard window
  3200. // [pDataObject] -- the data object
  3201. //
  3202. // Requires: the clipboard must be open
  3203. // g_cfDataObject must already be registered
  3204. //
  3205. // Returns: HRESULT
  3206. //
  3207. // Signals:
  3208. //
  3209. // Modifies:
  3210. //
  3211. // Algorithm: We take the private clipboard window (passed as an
  3212. // argument) and put the data object pointer on it
  3213. // it as a private property. We also attach an rpc endpoint
  3214. // to this window as a public property and then put the
  3215. // window handle on the clipboard. OleGetClipboard will
  3216. // retrieve this window handle, get the rpc endpoint, and
  3217. // rpc over here (the set clipboard process) to get the
  3218. // IDataObject pointer (marshalled, of course ;-)
  3219. //
  3220. // History: dd-mmm-yy Author Comment
  3221. // 16-Mar-94 alexgo author
  3222. //
  3223. // Notes:
  3224. //
  3225. //--------------------------------------------------------------------------
  3226. HRESULT SetClipboardDataObject( HWND hClipWnd ,
  3227. IDataObject *pDataObject )
  3228. {
  3229. HRESULT hresult;
  3230. HWND * phMem;
  3231. HANDLE hMem;
  3232. DWORD dwAssignAptID;
  3233. VDATEHEAP();
  3234. LEDebugOut((DEB_ITRACE, "%p _IN SetClipboardDataObject ( %lx ,%p )\n",
  3235. NULL, hClipWnd, pDataObject ));
  3236. AssertSz(pDataObject, "Invalid data object");
  3237. Assert(g_cfDataObject);
  3238. // try to assign an endpoint property to the window
  3239. if( (hresult = AssignEndpointProperty(hClipWnd)) != NOERROR)
  3240. {
  3241. goto errRtn;
  3242. }
  3243. // put the data object pointer on the window
  3244. if( !SetProp(hClipWnd, CLIPBOARD_DATA_OBJECT_PROP, pDataObject) )
  3245. {
  3246. // uh-oh, try to back out, but don't worry if we fail
  3247. // from now on.
  3248. LEDebugOut((DEB_WARN, "WARNING: Unable to SetProp for the "
  3249. "data object pointer\n"));
  3250. UnAssignEndpointProperty(hClipWnd,&dwAssignAptID);
  3251. hresult = ResultFromScode(E_FAIL);
  3252. goto errRtn;
  3253. }
  3254. // now allocate memory for the HWND of the private clipboard
  3255. // window and put that on the clipboard
  3256. hMem = GlobalAlloc( GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(HWND));
  3257. if( !hMem )
  3258. {
  3259. LEDebugOut((DEB_WARN, "WARNING: GlobalAlloc failed!!\n"));
  3260. hresult = ResultFromScode(E_OUTOFMEMORY);
  3261. goto cleanup;
  3262. }
  3263. phMem = (HWND *)GlobalLock(hMem);
  3264. if( !phMem )
  3265. {
  3266. LEDebugOut((DEB_WARN, "WARNING: GlobalLock failed!!\n"));
  3267. hresult = ResultFromScode(E_OUTOFMEMORY);
  3268. goto cleanup;
  3269. }
  3270. *phMem = hClipWnd;
  3271. GlobalUnlock(hMem);
  3272. if( !SSSetClipboardData( g_cfDataObject, hMem ) )
  3273. {
  3274. LEDebugOut((DEB_WARN, "WARNING: SetClipboardData for "
  3275. "g_cfDataObject failed (%lx) !!\n", GetLastError()));
  3276. hresult = ResultFromScode(CLIPBRD_E_CANT_SET);
  3277. goto cleanup;
  3278. }
  3279. pDataObject->AddRef();
  3280. hresult = NOERROR;
  3281. goto errRtn;
  3282. cleanup:
  3283. UnAssignEndpointProperty(hClipWnd,&dwAssignAptID);
  3284. RemoveProp(hClipWnd, CLIPBOARD_DATA_OBJECT_PROP);
  3285. if( hMem )
  3286. {
  3287. GlobalFree(hMem);
  3288. }
  3289. errRtn:
  3290. LEDebugOut((DEB_ITRACE, "%p OUT SetClipboardDataObject ( %lx )\n",
  3291. NULL, hresult));
  3292. return hresult;
  3293. }
  3294. //+-------------------------------------------------------------------------
  3295. //
  3296. // Function: SetClipboardFormats
  3297. //
  3298. // Synopsis: enumerates the formats available from the data object and
  3299. // sets up the clipboard to delay-render those formats.
  3300. //
  3301. // Effects:
  3302. //
  3303. // Arguments: [hClipWnd] -- the clipboard window
  3304. // [pDataObj] -- the data object
  3305. //
  3306. // Requires: the clipboard must be open
  3307. //
  3308. // Returns: HRESULT
  3309. //
  3310. // Signals:
  3311. //
  3312. // Modifies:
  3313. //
  3314. // Algorithm: Simply enumerate all of the formats available on the object
  3315. // and set each up for delayed rendereing (via
  3316. // SetClipboardData(cf, NULL)). We also keep track of the
  3317. // "real" formatetc for each clipboard format that we'll render.
  3318. // These formatetc's are placed in an array and put on the
  3319. // clipboard as g_cfOlePrivateData.
  3320. //
  3321. // See Notes below for more discussion on this.
  3322. //
  3323. // OLE1 support: In order to allow OLE1 containers to
  3324. // paste OLE2 objects, we have to offer OLE1 formats in addition
  3325. // to OLE2 data. We'll offer OLE1 formats as follows:
  3326. //
  3327. // g_cfNative: if either EmbedSource or EmbeddedObject
  3328. // is available AND we can offer OwnerLink
  3329. // g_cfOwnerLink: if ObjectDescriptor is available AND
  3330. // we can offer Native
  3331. // g_cfObjectLink: if LinkSource is available
  3332. //
  3333. // We will offer the formats in in the order above.
  3334. //
  3335. // History: dd-mmm-yy Author Comment
  3336. // 4/13/95 rogerg Bug#10731 Graph 5.0 does not Include
  3337. // its ObjectDescriptor in its enumerator
  3338. // 22-Feb-95 alexgo restored broken 16bit behavior to
  3339. // make Lotus Freelance work
  3340. // 11-Apr-94 alexgo author
  3341. //
  3342. // Notes: For every clipboard format, we could do a QueryGetData
  3343. // to see if RenderFormat would actually succeed. However,
  3344. // this relies on the QueryGetData from the app to be both
  3345. // fast and accurate (definitely an unwarranted assumption).
  3346. //
  3347. // Of course, by *not* doing a QueryGetData, we are assuming
  3348. // that the formats enumerated by the data object are all
  3349. // "legal" for clipboard transmission.
  3350. //
  3351. // The "real" purpose of g_cfOlePrivateData is to allow us to
  3352. // determine whether private clipboard formats where originally
  3353. // IStorage based. This is especially important for
  3354. // OleFlushClipboard and copy/pasting mutiple objects. Transfer
  3355. // of multiple objects relies on private clipboard formats, which,
  3356. // in some apps, are only available on IStorage.
  3357. //
  3358. // These same apps rely on the Formatetc enumerator (or
  3359. // QueryGetData) to tell them that the private format is available
  3360. // on a storage (since it wasn't always in 16bit OLE). Since we
  3361. // *can* offer it to them on a storage (see clipdata.cpp), it
  3362. // is important that we preserve the fact that the data originally
  3363. // came from a storage.
  3364. //
  3365. // Instead of always *testing* the data at enumerator or Query
  3366. // time, we simply save the formatetc now (with [potentially]
  3367. // modified fields such as ptd).
  3368. //
  3369. // Also note that RenderFormat uses the information in
  3370. // OlePrivateData when trying to render clipboard formats.
  3371. //
  3372. //--------------------------------------------------------------------------
  3373. HRESULT SetClipboardFormats( HWND hClipWnd, IDataObject *pDataObj )
  3374. {
  3375. IEnumFORMATETC * pIEnum;
  3376. HRESULT hresult;
  3377. FORMATETC formatetc;
  3378. HGLOBAL hglobal, hcopy;
  3379. FORMATETCDATAARRAY* pFormatEtcDataArray;
  3380. FORMATETCDATAARRAY* pFormatEtcDataArrayCopy;
  3381. DWORD dwSize =0;
  3382. FORMATETCDATA *pFormatEtcData;
  3383. BYTE *pbDvTarget = NULL;
  3384. DWORD cFormats = 0;
  3385. BOOL fOfferNative = FALSE,
  3386. fOfferedNative = FALSE,
  3387. fOfferObjectLink = FALSE;
  3388. CLSID clsid;
  3389. DWORD dwStatus;
  3390. BOOL fHaveObjectDescriptor=FALSE;
  3391. // Flag to tell us if the data object owner wants us to use the
  3392. // special SaveToStream/LoadFromStream mechanish at OleFlushCB.
  3393. BOOL fPersistDataObjOnFlush=FALSE;
  3394. VDATEHEAP();
  3395. LEDebugOut((DEB_ITRACE, "%p _IN SetClipboardFormats ( %p )\n",
  3396. NULL, pDataObj));
  3397. // get the formatetc enumerator
  3398. hresult = pDataObj->EnumFormatEtc(DATADIR_GET, &pIEnum);
  3399. if( hresult != NOERROR )
  3400. {
  3401. goto errRtn;
  3402. }
  3403. // count up the available formats
  3404. pIEnum->Reset(); // Nt bug 284810
  3405. while( (hresult = pIEnum->Next(1, &formatetc, NULL)) == NOERROR )
  3406. {
  3407. // Bump the entry count
  3408. cFormats++;
  3409. // Bump the size by the size of another FormatEtcData.
  3410. dwSize += sizeof(FORMATETCDATA);
  3411. // Is there a device target associated with the FORMATETC?
  3412. if (formatetc.ptd != NULL)
  3413. {
  3414. // Bump the size required by the size of the target device
  3415. dwSize += formatetc.ptd->tdSize;
  3416. // Free the target device
  3417. CoTaskMemFree(formatetc.ptd);
  3418. }
  3419. if (g_cfObjectDescriptor == formatetc.cfFormat)
  3420. fHaveObjectDescriptor = TRUE;
  3421. }
  3422. // Bug#10731 - If no ObjectDescriptor in Enumertor increment cFormats in case we have to add it
  3423. // when we add the EmbedSource
  3424. if (!fHaveObjectDescriptor)
  3425. {
  3426. dwSize += sizeof(FORMATETCDATA);
  3427. }
  3428. dwSize += sizeof(FORMATETCDATAARRAY); // add space for _cFormats and one extra FORMATETC for FALSE in
  3429. // for our locally cached copy of the formats
  3430. pFormatEtcDataArrayCopy = (FORMATETCDATAARRAY *) PrivMemAlloc(dwSize);
  3431. if( pFormatEtcDataArrayCopy == NULL )
  3432. {
  3433. hresult = E_OUTOFMEMORY;
  3434. goto errRtn;
  3435. }
  3436. // since some of these may be duplicated clipboard formats, we
  3437. // are potentially allocating more memory than we need, but that's
  3438. // OK.
  3439. hglobal = GlobalAlloc((GMEM_MOVEABLE | GMEM_DDESHARE),dwSize);
  3440. if (hglobal == NULL)
  3441. {
  3442. pIEnum->Release();
  3443. hresult = ResultFromScode(E_OUTOFMEMORY);
  3444. goto errRtn;
  3445. }
  3446. pFormatEtcDataArray = (FORMATETCDATAARRAY *)GlobalLock(hglobal);
  3447. if( pFormatEtcDataArray == NULL )
  3448. {
  3449. GlobalFree(hglobal);
  3450. pIEnum->Release();
  3451. hresult = ResultFromScode(E_OUTOFMEMORY);
  3452. goto errRtn;
  3453. }
  3454. _xmemset(pFormatEtcDataArray, 0, dwSize);
  3455. // This is the pointer to where we will copy the data from the
  3456. // enumeration.
  3457. pFormatEtcData = &pFormatEtcDataArray->_FormatEtcData[0];
  3458. // put DvTarget past last valid FormatEtc + 1 to handle S_FALSE enumerator case.
  3459. pbDvTarget = (BYTE *) (&pFormatEtcDataArray->_FormatEtcData[cFormats + 1]);
  3460. cFormats = 0;
  3461. pIEnum->Reset();
  3462. while( (hresult = pIEnum->Next(1, &(pFormatEtcData->_FormatEtc), NULL))
  3463. == NOERROR )
  3464. {
  3465. // Excel5, 16bit, would offer data in it's enumerator
  3466. // that you couldn't actually fetch. Since this causes
  3467. // Paste Special behaviour to be broken, we have to fix it
  3468. // here.
  3469. if( IsWOWThread() )
  3470. {
  3471. hresult = pDataObj->QueryGetData(&(pFormatEtcData->_FormatEtc));
  3472. if( hresult != NOERROR )
  3473. {
  3474. // free the target device (if there is one)
  3475. if( pFormatEtcData->_FormatEtc.ptd )
  3476. {
  3477. LEDebugOut((DEB_WARN, "WARNING: Non-NULL ptd!\n"));
  3478. CoTaskMemFree(pFormatEtcData->_FormatEtc.ptd);
  3479. }
  3480. continue;
  3481. }
  3482. }
  3483. // Update ptd if one exists. Even if fail later doesn't matter since just won't
  3484. // have a FormatEtc that points to the ptd.
  3485. if (pFormatEtcData->_FormatEtc.ptd != NULL)
  3486. {
  3487. // Copy the device target data
  3488. memcpy( pbDvTarget,
  3489. pFormatEtcData->_FormatEtc.ptd,
  3490. (pFormatEtcData->_FormatEtc.ptd)->tdSize );
  3491. // Free the target device data
  3492. CoTaskMemFree(pFormatEtcData->_FormatEtc.ptd);
  3493. // NOTE: For this shared memory structure, we override the
  3494. // FORMATETC field so that it is that offset to the DVTARGETDEVICE
  3495. // from the beginning of the shared memory rather than a direct
  3496. // pointer to the structure. This is because we can't guarantee
  3497. // the base of shared memory in different processes.
  3498. pFormatEtcData->_FormatEtc.ptd = (DVTARGETDEVICE *)
  3499. (pbDvTarget - (BYTE *) pFormatEtcDataArray);
  3500. // Bump pointer of where to copy target to next available
  3501. // byte for copy.
  3502. pbDvTarget += ((DVTARGETDEVICE *) pbDvTarget)->tdSize;
  3503. Assert(dwSize >= (DWORD) (pbDvTarget - (BYTE *) pFormatEtcDataArray));
  3504. }
  3505. // we first need to check to see if the clipboard format is a
  3506. // user-defined GDI format. We do not know how to duplicate
  3507. // these, so we can't satisfy the GetData request.
  3508. if( pFormatEtcData->_FormatEtc.cfFormat >= CF_GDIOBJFIRST &&
  3509. pFormatEtcData->_FormatEtc.cfFormat <= CF_GDIOBJLAST )
  3510. {
  3511. LEDebugOut((DEB_WARN, "WARNING: caller attempted to "
  3512. "use a special GDI format (%lx)\n",
  3513. pFormatEtcData->_FormatEtc.cfFormat));
  3514. // keep going though and get the rest of the clipboard formats
  3515. continue;
  3516. }
  3517. // HACK ALERT!!!
  3518. if( IsWOWThread() )
  3519. {
  3520. // Word6 offers CF_BITMAP on HGLOBAL in it's enumerator
  3521. // but only succeeds the GetData call if TYMED_GDI is
  3522. // specified. So patch up the formatetc to reflect
  3523. // something more accurate.
  3524. if( (pFormatEtcData->_FormatEtc.cfFormat == CF_BITMAP ||
  3525. pFormatEtcData->_FormatEtc.cfFormat == CF_PALETTE ) &&
  3526. pFormatEtcData->_FormatEtc.tymed == TYMED_HGLOBAL )
  3527. {
  3528. pFormatEtcData->_FormatEtc.tymed = TYMED_GDI;
  3529. }
  3530. }
  3531. // determine if we should offer any OLE1 formats etc...
  3532. if( pFormatEtcData->_FormatEtc.cfFormat == g_cfEmbeddedObject ||
  3533. pFormatEtcData->_FormatEtc.cfFormat == g_cfEmbedSource )
  3534. {
  3535. fOfferNative = TRUE;
  3536. }
  3537. else if( pFormatEtcData->_FormatEtc.cfFormat == g_cfLinkSource )
  3538. {
  3539. fOfferObjectLink = TRUE;
  3540. // if the app offers ObjectLink itself, then we'll
  3541. // consider a private clipboard format and set
  3542. // it up for delayed rendering as any other format.
  3543. // We'll check for this down below.
  3544. }
  3545. else if ( pFormatEtcData->_FormatEtc.cfFormat
  3546. == g_cfOleClipboardPersistOnFlush )
  3547. {
  3548. if (!fPersistDataObjOnFlush)
  3549. {
  3550. Assert(pFormatEtcData->_FormatEtc.ptd == NULL);
  3551. Assert(pFormatEtcData->_FormatEtc.dwAspect == DVASPECT_CONTENT);
  3552. Assert(pFormatEtcData->_FormatEtc.lindex == -1);
  3553. Assert(pFormatEtcData->_FormatEtc.tymed & TYMED_HGLOBAL);
  3554. fPersistDataObjOnFlush = TRUE;
  3555. }
  3556. else
  3557. {
  3558. AssertSz(FALSE,
  3559. "Multiple cfOleClipboardPersistOnFlush offered by object.");
  3560. // We will use only the first instance.
  3561. }
  3562. }
  3563. // Bug#18669 - if dwAspect was set to NULL the 16 bit dlls would
  3564. // set it to content.
  3565. if ( (NULL == pFormatEtcData->_FormatEtc.dwAspect) && IsWOWThread() )
  3566. {
  3567. pFormatEtcData->_FormatEtc.dwAspect = DVASPECT_CONTENT;
  3568. pFormatEtcData->_FormatEtc.lindex = -1; // CorelDraw also has a lindex of 0.
  3569. }
  3570. // BUG 69893: Equation editor sets lindex to 0
  3571. // Change it to -1
  3572. if(pFormatEtcData->_FormatEtc.lindex == 0) {
  3573. LEDebugOut((DEB_WARN, "WARNING: Changing lindex from 0 to -1\n"));
  3574. pFormatEtcData->_FormatEtc.lindex = -1;
  3575. }
  3576. // if going to add to clipboard increment enumerator, else
  3577. // current information will get overwritten.
  3578. // if we haven't already setup this clipboard format, do so now.
  3579. if(!SSIsClipboardFormatAvailable(pFormatEtcData->_FormatEtc.cfFormat) )
  3580. {
  3581. pFormatEtcData->fSaveOnFlush = TRUE;
  3582. // no way to catch any errors
  3583. SSSetClipboardData(pFormatEtcData->_FormatEtc.cfFormat, NULL);
  3584. // Bug#10731 If we are adding the EmbedSource but there was no Object Descriptor in
  3585. // the Enumerator, see if we can add the Object Descriptor now.
  3586. if ( (pFormatEtcData->_FormatEtc.cfFormat == g_cfEmbedSource)
  3587. && !fHaveObjectDescriptor)
  3588. {
  3589. FORMATETC fetcObjDescriptor;
  3590. fetcObjDescriptor.cfFormat = g_cfObjectDescriptor;
  3591. fetcObjDescriptor.ptd = NULL;
  3592. fetcObjDescriptor.dwAspect = DVASPECT_CONTENT;
  3593. fetcObjDescriptor.lindex = -1;
  3594. fetcObjDescriptor.tymed = TYMED_HGLOBAL ;
  3595. if (S_OK == pDataObj->QueryGetData(&fetcObjDescriptor))
  3596. {
  3597. ++pFormatEtcData; // increment formatEtc to next format.
  3598. ++cFormats; // increment number of formats in enumerator.
  3599. SSSetClipboardData(g_cfObjectDescriptor, NULL);
  3600. pFormatEtcData->_FormatEtc = fetcObjDescriptor;
  3601. pFormatEtcData->fSaveOnFlush = TRUE;
  3602. }
  3603. }
  3604. }
  3605. // Bump the pointer in the table of FORMATETCs to the next slot
  3606. ++pFormatEtcData;
  3607. ++cFormats;
  3608. Assert( dwSize >= (DWORD) ( (BYTE *) pFormatEtcData - (BYTE *) pFormatEtcDataArray));
  3609. Assert( dwSize >= (DWORD) ( (BYTE *) pbDvTarget - (BYTE *) pFormatEtcDataArray));
  3610. // HACK ALERT!!!! Lotus Freelance 2.1 depends on getting
  3611. // cfNative *before* presentation formats (like CF_METAFILEPICT).
  3612. // Therefore, we emulate OLE16 behaviour and offer cfNative
  3613. // and cfOwnerLink immediately *after* cfEmbeddedObject or
  3614. // cfEmbedSource.
  3615. //
  3616. // NB! This hack destroys the exact ordering of formats
  3617. // offered by the data object given in OleSetClipboard
  3618. if( fOfferNative && !fOfferedNative )
  3619. {
  3620. // even if the calls below fail, don't put OLE1 formats
  3621. // the clipboard again.
  3622. fOfferedNative = TRUE;
  3623. // this call will fail if CF_OBJECTDESCRIPTOR is not
  3624. // available
  3625. hresult = GetDataFromDescriptor(pDataObj, &clsid,
  3626. g_cfObjectDescriptor,
  3627. USE_NORMAL_CLSID, NULL, NULL);
  3628. // we do not want static objects like metafiles and
  3629. // dib's to be treated as embeddings by OLE1 containers.
  3630. // They will be able to better handle the data as just
  3631. // a plain metafile
  3632. if( hresult == NOERROR &&
  3633. !IsEqualCLSID(clsid, CLSID_StaticMetafile) &&
  3634. !IsEqualCLSID(clsid, CLSID_StaticDib) &&
  3635. !IsEqualCLSID(clsid, CLSID_Picture_EnhMetafile))
  3636. {
  3637. SSSetClipboardData(g_cfNative, NULL);
  3638. SSSetClipboardData(g_cfOwnerLink, NULL);
  3639. pFormatEtcDataArray->_dwMiscArrayFlags |= FETC_OFFER_OLE1;
  3640. }
  3641. }
  3642. }
  3643. // Set FormatEtcDataArray Header Data.
  3644. pFormatEtcDataArray->_cFormats = cFormats;
  3645. pFormatEtcDataArray->_dwSig = 0;
  3646. pFormatEtcDataArray->_cRefs = 1;
  3647. pFormatEtcDataArray->_dwSize = dwSize;
  3648. pFormatEtcDataArray->_fIs64BitArray = IS_WIN64;
  3649. if (fPersistDataObjOnFlush)
  3650. {
  3651. pFormatEtcDataArray->_dwMiscArrayFlags |= FETC_PERSIST_DATAOBJ_ON_FLUSH;
  3652. }
  3653. // we don't need to do this now because we'll reset hresult
  3654. // to NOERROR below. Note that this does mean that we'll
  3655. // ignore any failure from the enumerator. We do this for two
  3656. // reasons:
  3657. // 1. The enumerator really should *not* fail on anything;
  3658. // all it should do is memcmp some stuff into the formatetc
  3659. // that we pass in. If it decides to fail at some point,
  3660. // then we'll just put on the clipboard whatever was
  3661. // enumerated 'til that point.
  3662. // 2. It is too late (88/28/94) to change for NT3.5 This
  3663. // behaviour (ingnoring failure) has been around for a while
  3664. // (see reason #1). It is possible that some apps are
  3665. // returning failure instead of S_FALSE to terminate.
  3666. // If we checked for failure and returned, we'd break those
  3667. // apps.
  3668. //
  3669. //if( hresult == ResultFromScode(S_FALSE) )
  3670. //{
  3671. // this is OK, means the enumerator terminated successfully
  3672. // hresult = NOERROR;
  3673. //}
  3674. pIEnum->Release();
  3675. // now set up any OLE1 formats we might need to offer.
  3676. // if the app offers ObjectLink itself, then we will have already
  3677. // set it up for delayed rendering in the enumerator loop above
  3678. if( fOfferObjectLink && !SSIsClipboardFormatAvailable(g_cfObjectLink) )
  3679. {
  3680. hresult = GetDataFromDescriptor(pDataObj, NULL,
  3681. g_cfLinkSrcDescriptor,
  3682. USE_NORMAL_CLSID, NULL, &dwStatus);
  3683. // there are some kinds of links that can't be linked to
  3684. // by OLE1 containers. Non-filename links (e.g. a progid
  3685. // moniker) and links to embeddings are common examples.
  3686. // Clipboard source providers indicate this state by
  3687. // setting the OLEMISC_CANLINKBYOLE1 bit in the status
  3688. // field of LinkSourceDescriptor
  3689. if( hresult == NOERROR && (dwStatus & OLEMISC_CANLINKBYOLE1) )
  3690. {
  3691. SSSetClipboardData(g_cfObjectLink, NULL);
  3692. pFormatEtcDataArray->_dwMiscArrayFlags |= FETC_OFFER_OBJLINK;
  3693. }
  3694. }
  3695. // even if the calls to GetDataFromDescriptor failed above, it only
  3696. // means that we can't render OLE1 formats. This is OK.
  3697. hresult = NOERROR;
  3698. // now keep a copy of the formats locally, ptds are set to be offsets from
  3699. // beginning of Structure so these don't need to be updated.
  3700. _xmemcpy(pFormatEtcDataArrayCopy, pFormatEtcDataArray, dwSize);
  3701. // now stuff the formatetc's on the clipboard and our private
  3702. // clipboard window (for use by RenderFormat).
  3703. SetWindowLongPtr(hClipWnd,
  3704. WL_ClipPrivateData,
  3705. (LONG_PTR) pFormatEtcDataArrayCopy);
  3706. GlobalUnlock(hglobal);
  3707. if( !SSSetClipboardData(g_cfOlePrivateData, hglobal) )
  3708. {
  3709. GlobalFree(hglobal); // on success, the clipboard will
  3710. // take ownership of our hglobal.
  3711. LEDebugOut((DEB_WARN, "WARNING: Unable to set clipboard "
  3712. "formats!\n"));
  3713. }
  3714. errRtn:
  3715. LEDebugOut((DEB_ITRACE, "%p OUT SetClipboardFormats ( %lx )\n", NULL,
  3716. hresult));
  3717. return hresult;
  3718. }
  3719. //+-------------------------------------------------------------------------
  3720. //
  3721. // Function: VerifyCallerIsClipboardOwner (internal)
  3722. //
  3723. // Synopsis: Checks to make sure the caller is the clipboard owner
  3724. //
  3725. // Effects:
  3726. //
  3727. // Arguments: void
  3728. //
  3729. // Requires:
  3730. //
  3731. // Returns: HWND to the private clipboard window (the owner of the
  3732. // clipboard) upon success
  3733. // NULL on failure.
  3734. //
  3735. // Signals:
  3736. //
  3737. // Modifies:
  3738. //
  3739. // Algorithm:
  3740. //
  3741. // History: dd-mmm-yy Author Comment
  3742. // 16-Mar-94 alexgo author
  3743. //
  3744. // Notes:
  3745. //
  3746. //--------------------------------------------------------------------------
  3747. HWND VerifyCallerIsClipboardOwner( void )
  3748. {
  3749. HWND hClipWnd,
  3750. hWndClipOwner;
  3751. VDATEHEAP();
  3752. LEDebugOut((DEB_ITRACE, "%p _IN VerifyCallerIsClipboardOwner ( )\n",
  3753. NULL ));
  3754. // don't create a window if none exists
  3755. hClipWnd = GetPrivateClipboardWindow( CLIP_QUERY );
  3756. if( hClipWnd )
  3757. {
  3758. hWndClipOwner = SSGetClipboardOwner();
  3759. if( hClipWnd != hWndClipOwner )
  3760. {
  3761. // caller is not owner, return NULL
  3762. hClipWnd = NULL;
  3763. }
  3764. }
  3765. LEDebugOut((DEB_ITRACE, "%p OUT VerifyCallerIsClipboardOwner "
  3766. "( %lx )\n", NULL, hClipWnd));
  3767. return hClipWnd;
  3768. }
  3769. void GetCopiedFormatEtcDataArraySize (FORMATETCDATAARRAY* pClipFormatEtcDataArray, size_t* pstSize)
  3770. {
  3771. AssertSz(pstSize, "Bad argument to GetCopiedFormatEtcDataArraySize");
  3772. #ifdef _WIN64
  3773. if (pClipFormatEtcDataArray->_fIs64BitArray)
  3774. {
  3775. *pstSize = pClipFormatEtcDataArray->_dwSize;
  3776. }
  3777. else
  3778. {
  3779. *pstSize = pClipFormatEtcDataArray->_dwSize +
  3780. (sizeof (FORMATETCDATAARRAY) - sizeof (FORMATETCDATAARRAY32)) +
  3781. (pClipFormatEtcDataArray->_cFormats - 1) * (sizeof (FORMATETCDATA) - sizeof (FORMATETCDATA32));
  3782. }
  3783. #else
  3784. if (pClipFormatEtcDataArray->_fIs64BitArray)
  3785. {
  3786. // Just subtract
  3787. *pstSize = pClipFormatEtcDataArray->_dwSize -
  3788. (sizeof (FORMATETCDATAARRAY64) - sizeof (FORMATETCDATAARRAY)) -
  3789. (pClipFormatEtcDataArray->_cFormats - 1) * (sizeof (FORMATETCDATA64) - sizeof (FORMATETCDATA));
  3790. }
  3791. else
  3792. {
  3793. *pstSize = pClipFormatEtcDataArray->_dwSize;
  3794. }
  3795. #endif
  3796. }
  3797. #ifdef _WIN64
  3798. inline void TranslateFormatEtcData (FORMATETCDATA* pFormatEtcData, FORMATETCDATA32* pClipFormatEtcData)
  3799. {
  3800. // Convert from 32 to 64 bit format
  3801. pFormatEtcData->fSaveOnFlush = pClipFormatEtcData->fSaveOnFlush;
  3802. pFormatEtcData->dwReserved1 = pClipFormatEtcData->dwReserved1;
  3803. pFormatEtcData->dwReserved2 = pClipFormatEtcData->dwReserved2;
  3804. pFormatEtcData->_FormatEtc.cfFormat = pClipFormatEtcData->_FormatEtc.cfFormat;
  3805. pFormatEtcData->_FormatEtc.ptd = (DVTARGETDEVICE FAR*) UlongToPtr (pClipFormatEtcData->_FormatEtc.ptd);
  3806. pFormatEtcData->_FormatEtc.dwAspect = pClipFormatEtcData->_FormatEtc.dwAspect;
  3807. pFormatEtcData->_FormatEtc.lindex = pClipFormatEtcData->_FormatEtc.lindex;
  3808. pFormatEtcData->_FormatEtc.tymed = pClipFormatEtcData->_FormatEtc.tymed;
  3809. AssertSz(!pFormatEtcData->_FormatEtc.ptd, "This field should always be null");
  3810. }
  3811. #else
  3812. inline void TranslateFormatEtcData (FORMATETCDATA* pFormatEtcData, FORMATETCDATA64* pClipFormatEtcData)
  3813. {
  3814. // Convert from 32 to 64 bit format
  3815. pFormatEtcData->fSaveOnFlush = pClipFormatEtcData->fSaveOnFlush;
  3816. pFormatEtcData->dwReserved1 = pClipFormatEtcData->dwReserved1;
  3817. pFormatEtcData->dwReserved2 = pClipFormatEtcData->dwReserved2;
  3818. pFormatEtcData->_FormatEtc.cfFormat = pClipFormatEtcData->_FormatEtc.cfFormat;
  3819. pFormatEtcData->_FormatEtc.ptd = (DVTARGETDEVICE FAR*) pClipFormatEtcData->_FormatEtc.ptd;
  3820. pFormatEtcData->_FormatEtc.dwAspect = pClipFormatEtcData->_FormatEtc.dwAspect;
  3821. pFormatEtcData->_FormatEtc.lindex = pClipFormatEtcData->_FormatEtc.lindex;
  3822. pFormatEtcData->_FormatEtc.tymed = pClipFormatEtcData->_FormatEtc.tymed;
  3823. AssertSz(!pFormatEtcData->_FormatEtc.ptd, "This field should always be null");
  3824. }
  3825. #endif
  3826. void CopyFormatEtcDataArray (
  3827. FORMATETCDATAARRAY* pFormatEtcDataArray,
  3828. FORMATETCDATAARRAY* pClipFormatEtcDataArray,
  3829. size_t stSize,
  3830. BOOL bCheckAvailable
  3831. )
  3832. {
  3833. DWORD i=0,k=0;
  3834. AssertSz(pFormatEtcDataArray && pClipFormatEtcDataArray, "Bad argument to CopyFormatEtcDataArray");
  3835. // copy header fields that are compatible on both types of structures
  3836. pFormatEtcDataArray->_dwSig = pClipFormatEtcDataArray->_dwSig;
  3837. pFormatEtcDataArray->_dwSize = pClipFormatEtcDataArray->_dwSize;
  3838. pFormatEtcDataArray->_cRefs = pClipFormatEtcDataArray->_cRefs;
  3839. pFormatEtcDataArray->_cFormats = pClipFormatEtcDataArray->_cFormats;
  3840. pFormatEtcDataArray->_dwMiscArrayFlags = pClipFormatEtcDataArray->_dwMiscArrayFlags;
  3841. // Check for compatible data array
  3842. if (pClipFormatEtcDataArray->_fIs64BitArray == IS_WIN64)
  3843. {
  3844. // Format is compatible
  3845. for(;i<pClipFormatEtcDataArray->_cFormats;i++)
  3846. {
  3847. if(!bCheckAvailable || SSIsClipboardFormatAvailable(pClipFormatEtcDataArray->_FormatEtcData[i]._FormatEtc.cfFormat))
  3848. {
  3849. pFormatEtcDataArray->_FormatEtcData[k] = pClipFormatEtcDataArray->_FormatEtcData[i];
  3850. k++;
  3851. }
  3852. else
  3853. {
  3854. pFormatEtcDataArray->_cFormats--;
  3855. }
  3856. }
  3857. }
  3858. else
  3859. {
  3860. #ifdef _WIN64
  3861. FORMATETCDATAARRAY32* pClipFormatEtcDataArray_ptr = (FORMATETCDATAARRAY32*) pClipFormatEtcDataArray;
  3862. #else
  3863. FORMATETCDATAARRAY64* pClipFormatEtcDataArray_ptr = (FORMATETCDATAARRAY64*) pClipFormatEtcDataArray;
  3864. #endif
  3865. for(;i<pClipFormatEtcDataArray_ptr->_cFormats;i++)
  3866. {
  3867. if(!bCheckAvailable || SSIsClipboardFormatAvailable(pClipFormatEtcDataArray_ptr->_FormatEtcData[i]._FormatEtc.cfFormat))
  3868. {
  3869. TranslateFormatEtcData (
  3870. pFormatEtcDataArray->_FormatEtcData + k,
  3871. pClipFormatEtcDataArray_ptr->_FormatEtcData + i
  3872. );
  3873. k++;
  3874. }
  3875. else
  3876. {
  3877. pFormatEtcDataArray->_cFormats--;
  3878. }
  3879. }
  3880. }
  3881. // set size
  3882. pFormatEtcDataArray->_dwSize = (DWORD) stSize;
  3883. // adjust the size of the new structure
  3884. pFormatEtcDataArray->_dwSize -= (i - k) * sizeof(FORMATETCDATA);
  3885. // set the 64 bit flag
  3886. pFormatEtcDataArray->_fIs64BitArray = IS_WIN64;
  3887. }