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

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