1 /* 2 * OLE 2 clipboard support 3 * 4 * Copyright 1999 Noel Borthwick <noel@macadamian.com> 5 * Copyright 2000 Abey George <abey@macadamian.com> 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * NOTES: 22 * This file contains the implementation for the OLE Clipboard and its 23 * internal interfaces. The OLE clipboard interacts with an IDataObject 24 * interface via the OleSetClipboard, OleGetClipboard and 25 * OleIsCurrentClipboard API's. An internal IDataObject delegates 26 * to a client supplied IDataObject or the WIN32 clipboard API depending 27 * on whether OleSetClipboard has been invoked. 28 * Here are some operating scenarios: 29 * 30 * 1. OleSetClipboard called: In this case the internal IDataObject 31 * delegates to the client supplied IDataObject. Additionally OLE takes 32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject 33 * items are placed on the Windows clipboard. This allows non OLE aware 34 * applications to access these. A local WinProc fields WM_RENDERFORMAT 35 * and WM_RENDERALLFORMATS messages in this case. 36 * 37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal 38 * IDataObject functionality wraps around the WIN32 clipboard API. 39 * 40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal 41 * IDataObject delegates to the source IDataObjects functionality directly, 42 * thereby bypassing the Windows clipboard. 43 * 44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt 45 * 46 * TODO: 47 * - Support for pasting between different processes. OLE clipboard support 48 * currently works only for in process copy and paste. Since we internally 49 * store a pointer to the source's IDataObject and delegate to that, this 50 * will fail if the IDataObject client belongs to a different process. 51 * - IDataObject::GetDataHere is not implemented 52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media 53 * by copying the storage into global memory. Subsequently the default 54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL 55 * back to TYMED_IStorage. 56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on 57 * clipboard in OleSetClipboard. 58 * 59 */ 60 61 #include <assert.h> 62 #include <stdarg.h> 63 #include <string.h> 64 #include <stdio.h> 65 66 #define COBJMACROS 67 #define NONAMELESSUNION 68 69 #include "windef.h" 70 #include "winbase.h" 71 #include "wingdi.h" 72 #include "winuser.h" 73 #include "winerror.h" 74 #include "winnls.h" 75 #include "ole2.h" 76 #include "wine/debug.h" 77 #include "olestd.h" 78 79 #include "storage32.h" 80 81 #include "compobj_private.h" 82 83 WINE_DEFAULT_DEBUG_CHANNEL(ole); 84 85 /* Structure of 'Ole Private Data' clipboard format */ 86 typedef struct 87 { 88 FORMATETC fmtetc; 89 DWORD first_use; /* Has this cf been added to the list already */ 90 DWORD unk[2]; 91 } ole_priv_data_entry; 92 93 typedef struct 94 { 95 DWORD unk1; 96 DWORD size; /* in bytes of the entire structure */ 97 DWORD unk2; 98 DWORD count; /* no. of format entries */ 99 DWORD unk3[2]; 100 ole_priv_data_entry entries[1]; /* array of size count */ 101 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */ 102 } ole_priv_data; 103 104 /***************************************************************************** 105 * td_offs_to_ptr 106 * 107 * Returns a ptr to a target device at a given offset from the 108 * start of the ole_priv_data. 109 * 110 * Used when unpacking ole private data from the clipboard. 111 */ 112 static inline DVTARGETDEVICE *td_offs_to_ptr(ole_priv_data *data, DWORD_PTR off) 113 { 114 if(off == 0) return NULL; 115 return (DVTARGETDEVICE*)((char*)data + off); 116 } 117 118 /***************************************************************************** 119 * td_get_offs 120 * 121 * Get the offset from the start of the ole_priv_data of the idx'th 122 * target device. 123 * 124 * Used when packing ole private data to the clipboard. 125 */ 126 static inline DWORD_PTR td_get_offs(ole_priv_data *data, DWORD idx) 127 { 128 if(data->entries[idx].fmtetc.ptd == NULL) return 0; 129 return (char*)data->entries[idx].fmtetc.ptd - (char*)data; 130 } 131 132 /**************************************************************************** 133 * Consumer snapshot. Represents the state of the ole clipboard 134 * returned by OleGetClipboard(). 135 */ 136 typedef struct snapshot 137 { 138 IDataObject IDataObject_iface; 139 LONG ref; 140 141 DWORD seq_no; /* Clipboard sequence number corresponding to this snapshot */ 142 143 IDataObject *data; /* If we unmarshal a remote data object we hold a ref here */ 144 } snapshot; 145 146 /**************************************************************************** 147 * ole_clipbrd 148 */ 149 typedef struct ole_clipbrd 150 { 151 snapshot *latest_snapshot; /* Latest consumer snapshot */ 152 153 HWND window; /* Hidden clipboard window */ 154 IDataObject *src_data; /* Source object passed to OleSetClipboard */ 155 ole_priv_data *cached_enum; /* Cached result from the enumeration of src data object */ 156 IStream *marshal_data; /* Stream onto which to marshal src_data */ 157 } ole_clipbrd; 158 159 static inline snapshot *impl_from_IDataObject(IDataObject *iface) 160 { 161 return CONTAINING_RECORD(iface, snapshot, IDataObject_iface); 162 } 163 164 typedef struct PresentationDataHeader 165 { 166 BYTE unknown1[28]; 167 DWORD dwObjectExtentX; 168 DWORD dwObjectExtentY; 169 DWORD dwSize; 170 } PresentationDataHeader; 171 172 /* 173 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize() 174 */ 175 static ole_clipbrd* theOleClipboard; 176 177 static CRITICAL_SECTION latest_snapshot_cs; 178 static CRITICAL_SECTION_DEBUG latest_snapshot_cs_debug = 179 { 180 0, 0, &latest_snapshot_cs, 181 { &latest_snapshot_cs_debug.ProcessLocksList, &latest_snapshot_cs_debug.ProcessLocksList }, 182 0, 0, { (DWORD_PTR)(__FILE__ ": clipboard last snapshot") } 183 }; 184 static CRITICAL_SECTION latest_snapshot_cs = { &latest_snapshot_cs_debug, -1, 0, 0, 0, 0 }; 185 186 static inline HRESULT get_ole_clipbrd(ole_clipbrd **clipbrd) 187 { 188 struct oletls *info = COM_CurrentInfo(); 189 *clipbrd = NULL; 190 191 if(!info->ole_inits) 192 return CO_E_NOTINITIALIZED; 193 *clipbrd = theOleClipboard; 194 195 return S_OK; 196 } 197 198 /* 199 * Name of our registered OLE clipboard window class 200 */ 201 static const WCHAR clipbrd_wndclass[] = {'C','L','I','P','B','R','D','W','N','D','C','L','A','S','S',0}; 202 203 UINT ownerlink_clipboard_format = 0; 204 UINT filename_clipboard_format = 0; 205 UINT filenameW_clipboard_format = 0; 206 UINT dataobject_clipboard_format = 0; 207 UINT embedded_object_clipboard_format = 0; 208 UINT embed_source_clipboard_format = 0; 209 UINT custom_link_source_clipboard_format = 0; 210 UINT link_source_clipboard_format = 0; 211 UINT object_descriptor_clipboard_format = 0; 212 UINT link_source_descriptor_clipboard_format = 0; 213 UINT ole_private_data_clipboard_format = 0; 214 215 static UINT wine_marshal_clipboard_format; 216 217 static inline const char *dump_fmtetc(FORMATETC *fmt) 218 { 219 if (!fmt) return "(null)"; 220 return wine_dbg_sprintf("cf %04x ptd %p aspect %x lindex %d tymed %x", 221 fmt->cfFormat, fmt->ptd, fmt->dwAspect, fmt->lindex, fmt->tymed); 222 } 223 224 /*---------------------------------------------------------------------* 225 * Implementation of the internal IEnumFORMATETC interface returned by 226 * the OLE clipboard's IDataObject. 227 *---------------------------------------------------------------------*/ 228 229 typedef struct enum_fmtetc 230 { 231 IEnumFORMATETC IEnumFORMATETC_iface; 232 LONG ref; 233 234 UINT pos; /* current enumerator position */ 235 ole_priv_data *data; 236 } enum_fmtetc; 237 238 static inline enum_fmtetc *impl_from_IEnumFORMATETC(IEnumFORMATETC *iface) 239 { 240 return CONTAINING_RECORD(iface, enum_fmtetc, IEnumFORMATETC_iface); 241 } 242 243 /************************************************************************ 244 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) 245 * 246 * See Windows documentation for more details on IUnknown methods. 247 */ 248 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface 249 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) 250 { 251 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 252 253 TRACE("(%p)->(IID: %s, %p)\n", This, debugstr_guid(riid), ppvObj); 254 255 *ppvObj = NULL; 256 257 if(IsEqualIID(riid, &IID_IUnknown) || 258 IsEqualIID(riid, &IID_IEnumFORMATETC)) 259 { 260 *ppvObj = iface; 261 } 262 263 if(*ppvObj) 264 { 265 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj); 266 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); 267 return S_OK; 268 } 269 270 TRACE("-- Interface: E_NOINTERFACE\n"); 271 return E_NOINTERFACE; 272 } 273 274 /************************************************************************ 275 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown) 276 * 277 */ 278 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) 279 { 280 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 281 TRACE("(%p)->(count=%u)\n",This, This->ref); 282 283 return InterlockedIncrement(&This->ref); 284 } 285 286 /************************************************************************ 287 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown) 288 * 289 * See Windows documentation for more details on IUnknown methods. 290 */ 291 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) 292 { 293 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 294 ULONG ref; 295 296 TRACE("(%p)->(count=%u)\n",This, This->ref); 297 298 ref = InterlockedDecrement(&This->ref); 299 if (!ref) 300 { 301 TRACE("() - destroying IEnumFORMATETC(%p)\n",This); 302 HeapFree(GetProcessHeap(), 0, This->data); 303 HeapFree(GetProcessHeap(), 0, This); 304 } 305 return ref; 306 } 307 308 /************************************************************************ 309 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) 310 * 311 * Standard enumerator members for IEnumFORMATETC 312 */ 313 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next 314 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) 315 { 316 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 317 UINT cfetch, i; 318 HRESULT hres = S_FALSE; 319 320 TRACE("(%p)->(pos=%u)\n", This, This->pos); 321 322 if (This->pos < This->data->count) 323 { 324 cfetch = This->data->count - This->pos; 325 if (cfetch >= celt) 326 { 327 cfetch = celt; 328 hres = S_OK; 329 } 330 331 for(i = 0; i < cfetch; i++) 332 { 333 hres = copy_formatetc(rgelt + i, &This->data->entries[This->pos++].fmtetc); 334 if(FAILED(hres)) return hres; 335 } 336 } 337 else 338 { 339 cfetch = 0; 340 } 341 342 if (pceltFethed) 343 { 344 *pceltFethed = cfetch; 345 } 346 347 return hres; 348 } 349 350 /************************************************************************ 351 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC) 352 * 353 * Standard enumerator members for IEnumFORMATETC 354 */ 355 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) 356 { 357 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 358 TRACE("(%p)->(num=%u)\n", This, celt); 359 360 This->pos += celt; 361 if (This->pos > This->data->count) 362 { 363 This->pos = This->data->count; 364 return S_FALSE; 365 } 366 return S_OK; 367 } 368 369 /************************************************************************ 370 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC) 371 * 372 * Standard enumerator members for IEnumFORMATETC 373 */ 374 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) 375 { 376 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 377 TRACE("(%p)->()\n", This); 378 379 This->pos = 0; 380 return S_OK; 381 } 382 383 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj); 384 385 /************************************************************************ 386 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) 387 * 388 * Standard enumerator members for IEnumFORMATETC 389 */ 390 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone 391 (LPENUMFORMATETC iface, LPENUMFORMATETC* obj) 392 { 393 enum_fmtetc *This = impl_from_IEnumFORMATETC(iface); 394 ole_priv_data *new_data; 395 DWORD i; 396 397 TRACE("(%p)->(%p)\n", This, obj); 398 399 if ( !obj ) return E_INVALIDARG; 400 *obj = NULL; 401 402 new_data = HeapAlloc(GetProcessHeap(), 0, This->data->size); 403 if(!new_data) return E_OUTOFMEMORY; 404 memcpy(new_data, This->data, This->data->size); 405 406 /* Fixup any target device ptrs */ 407 for(i = 0; i < This->data->count; i++) 408 new_data->entries[i].fmtetc.ptd = 409 td_offs_to_ptr(new_data, td_get_offs(This->data, i)); 410 411 return enum_fmtetc_construct(new_data, This->pos, obj); 412 } 413 414 static const IEnumFORMATETCVtbl efvt = 415 { 416 OLEClipbrd_IEnumFORMATETC_QueryInterface, 417 OLEClipbrd_IEnumFORMATETC_AddRef, 418 OLEClipbrd_IEnumFORMATETC_Release, 419 OLEClipbrd_IEnumFORMATETC_Next, 420 OLEClipbrd_IEnumFORMATETC_Skip, 421 OLEClipbrd_IEnumFORMATETC_Reset, 422 OLEClipbrd_IEnumFORMATETC_Clone 423 }; 424 425 /************************************************************************ 426 * enum_fmtetc_construct 427 * 428 * Creates an IEnumFORMATETC enumerator from ole_priv_data which it then owns. 429 */ 430 static HRESULT enum_fmtetc_construct(ole_priv_data *data, UINT pos, IEnumFORMATETC **obj) 431 { 432 enum_fmtetc* ef; 433 434 *obj = NULL; 435 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(*ef)); 436 if (!ef) return E_OUTOFMEMORY; 437 438 ef->ref = 1; 439 ef->IEnumFORMATETC_iface.lpVtbl = &efvt; 440 ef->data = data; 441 ef->pos = pos; 442 443 TRACE("(%p)->()\n", ef); 444 *obj = &ef->IEnumFORMATETC_iface; 445 return S_OK; 446 } 447 448 /*********************************************************************** 449 * dup_global_mem 450 * 451 * Helper method to duplicate an HGLOBAL chunk of memory 452 */ 453 static HRESULT dup_global_mem( HGLOBAL src, DWORD flags, HGLOBAL *dst ) 454 { 455 void *src_ptr, *dst_ptr; 456 DWORD size; 457 458 *dst = NULL; 459 if ( !src ) return S_FALSE; 460 461 size = GlobalSize(src); 462 463 *dst = GlobalAlloc( flags, size ); 464 if ( !*dst ) return E_OUTOFMEMORY; 465 466 src_ptr = GlobalLock(src); 467 dst_ptr = GlobalLock(*dst); 468 469 memcpy(dst_ptr, src_ptr, size); 470 471 GlobalUnlock(*dst); 472 GlobalUnlock(src); 473 474 return S_OK; 475 } 476 477 /*********************************************************************** 478 * dup_metafilepict 479 * 480 * Helper function to duplicate a handle to a METAFILEPICT, and the 481 * contained HMETAFILE. 482 */ 483 static HRESULT dup_metafilepict(HGLOBAL src, HGLOBAL *pdest) 484 { 485 HRESULT hr; 486 HGLOBAL dest; 487 METAFILEPICT *dest_ptr; 488 489 *pdest = NULL; 490 491 /* Copy the METAFILEPICT structure. */ 492 hr = dup_global_mem(src, GMEM_DDESHARE|GMEM_MOVEABLE, &dest); 493 if (FAILED(hr)) return hr; 494 495 dest_ptr = GlobalLock(dest); 496 if (!dest_ptr) return E_FAIL; 497 498 /* Give the new METAFILEPICT a separate HMETAFILE. */ 499 dest_ptr->hMF = CopyMetaFileW(dest_ptr->hMF, NULL); 500 if (dest_ptr->hMF) 501 { 502 GlobalUnlock(dest); 503 *pdest = dest; 504 return S_OK; 505 } 506 else 507 { 508 GlobalUnlock(dest); 509 GlobalFree(dest); 510 return E_FAIL; 511 } 512 } 513 514 /*********************************************************************** 515 * free_metafilepict 516 * 517 * Helper function to GlobalFree a handle to a METAFILEPICT, and also 518 * free the contained HMETAFILE. 519 */ 520 static void free_metafilepict(HGLOBAL src) 521 { 522 METAFILEPICT *src_ptr; 523 524 src_ptr = GlobalLock(src); 525 if (src_ptr) 526 { 527 DeleteMetaFile(src_ptr->hMF); 528 GlobalUnlock(src); 529 } 530 GlobalFree(src); 531 } 532 533 /*********************************************************************** 534 * dup_bitmap 535 * 536 * Helper function to duplicate an HBITMAP. 537 */ 538 static HRESULT dup_bitmap(HBITMAP src, HBITMAP *pdest) 539 { 540 HDC src_dc; 541 HGDIOBJ orig_src_bitmap; 542 BITMAP bm; 543 HBITMAP dest; 544 545 src_dc = CreateCompatibleDC(NULL); 546 orig_src_bitmap = SelectObject(src_dc, src); 547 GetObjectW(src, sizeof bm, &bm); 548 dest = CreateCompatibleBitmap(src_dc, bm.bmWidth, bm.bmHeight); 549 if (dest) 550 { 551 HDC dest_dc = CreateCompatibleDC(NULL); 552 HGDIOBJ orig_dest_bitmap = SelectObject(dest_dc, dest); 553 BitBlt(dest_dc, 0, 0, bm.bmWidth, bm.bmHeight, src_dc, 0, 0, SRCCOPY); 554 SelectObject(dest_dc, orig_dest_bitmap); 555 DeleteDC(dest_dc); 556 } 557 SelectObject(src_dc, orig_src_bitmap); 558 DeleteDC(src_dc); 559 *pdest = dest; 560 return dest ? S_OK : E_FAIL; 561 } 562 563 /************************************************************ 564 * render_embed_source_hack 565 * 566 * This is clearly a hack and has no place in the clipboard code. 567 * 568 */ 569 static HRESULT render_embed_source_hack(IDataObject *data, LPFORMATETC fmt) 570 { 571 STGMEDIUM std; 572 HGLOBAL hStorage = 0; 573 HRESULT hr = S_OK; 574 ILockBytes *ptrILockBytes; 575 576 memset(&std, 0, sizeof(STGMEDIUM)); 577 std.tymed = fmt->tymed = TYMED_ISTORAGE; 578 579 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); 580 if (hStorage == NULL) return E_OUTOFMEMORY; 581 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); 582 if (FAILED(hr)) 583 { 584 GlobalFree(hStorage); 585 return hr; 586 } 587 588 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); 589 ILockBytes_Release(ptrILockBytes); 590 591 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->src_data, fmt, &std))) 592 { 593 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr); 594 GlobalFree(hStorage); 595 return hr; 596 } 597 598 if (1) /* check whether the presentation data is already -not- present */ 599 { 600 FORMATETC fmt2; 601 STGMEDIUM std2; 602 METAFILEPICT *mfp = 0; 603 604 fmt2.cfFormat = CF_METAFILEPICT; 605 fmt2.ptd = 0; 606 fmt2.dwAspect = DVASPECT_CONTENT; 607 fmt2.lindex = -1; 608 fmt2.tymed = TYMED_MFPICT; 609 610 memset(&std2, 0, sizeof(STGMEDIUM)); 611 std2.tymed = TYMED_MFPICT; 612 613 /* Get the metafile picture out of it */ 614 615 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->src_data, &fmt2, &std2))) 616 { 617 mfp = GlobalLock(std2.u.hGlobal); 618 } 619 620 if (mfp) 621 { 622 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; 623 IStream *pStream = 0; 624 void *mfBits; 625 PresentationDataHeader pdh; 626 INT nSize; 627 CLSID clsID; 628 LPOLESTR strProgID; 629 CHAR strOleTypeName[51]; 630 BYTE OlePresStreamHeader [] = 631 { 632 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 633 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 634 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 635 0x00, 0x00, 0x00, 0x00 636 }; 637 638 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); 639 640 memset(&pdh, 0, sizeof(PresentationDataHeader)); 641 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); 642 643 pdh.dwObjectExtentX = mfp->xExt; 644 pdh.dwObjectExtentY = mfp->yExt; 645 pdh.dwSize = nSize; 646 647 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); 648 649 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); 650 651 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); 652 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); 653 654 hr = IStream_Write(pStream, mfBits, nSize, NULL); 655 656 IStream_Release(pStream); 657 658 HeapFree(GetProcessHeap(), 0, mfBits); 659 660 GlobalUnlock(std2.u.hGlobal); 661 ReleaseStgMedium(&std2); 662 663 ReadClassStg(std.u.pstg, &clsID); 664 ProgIDFromCLSID(&clsID, &strProgID); 665 666 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); 667 STORAGE_CreateOleStream(std.u.pstg, 0); 668 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); 669 CoTaskMemFree(strProgID); 670 } 671 } 672 673 if ( !SetClipboardData( fmt->cfFormat, hStorage ) ) 674 { 675 WARN("() : Failed to set rendered clipboard data into clipboard!\n"); 676 GlobalFree(hStorage); 677 hr = CLIPBRD_E_CANT_SET; 678 } 679 680 ReleaseStgMedium(&std); 681 return hr; 682 } 683 684 /************************************************************************ 685 * find_format_in_list 686 * 687 * Returns the first entry that matches the provided clipboard format. 688 */ 689 static inline ole_priv_data_entry *find_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf) 690 { 691 DWORD i; 692 for(i = 0; i < num; i++) 693 if(entries[i].fmtetc.cfFormat == cf) 694 return &entries[i]; 695 696 return NULL; 697 } 698 699 /*************************************************************************** 700 * get_data_from_storage 701 * 702 * Returns storage data in an HGLOBAL. 703 */ 704 static HRESULT get_data_from_storage(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 705 { 706 HGLOBAL h; 707 IStorage *stg; 708 HRESULT hr; 709 FORMATETC stg_fmt; 710 STGMEDIUM med; 711 ILockBytes *lbs; 712 713 *mem = NULL; 714 715 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); 716 if(!h) return E_OUTOFMEMORY; 717 718 hr = CreateILockBytesOnHGlobal(h, FALSE, &lbs); 719 if(SUCCEEDED(hr)) 720 { 721 hr = StgCreateDocfileOnILockBytes(lbs, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &stg); 722 ILockBytes_Release(lbs); 723 } 724 if(FAILED(hr)) 725 { 726 GlobalFree(h); 727 return hr; 728 } 729 730 stg_fmt = *fmt; 731 med.tymed = stg_fmt.tymed = TYMED_ISTORAGE; 732 med.u.pstg = stg; 733 med.pUnkForRelease = NULL; 734 735 hr = IDataObject_GetDataHere(data, &stg_fmt, &med); 736 if(FAILED(hr)) 737 { 738 memset(&med, 0, sizeof(med)); 739 hr = IDataObject_GetData(data, &stg_fmt, &med); 740 if(FAILED(hr)) goto end; 741 742 hr = IStorage_CopyTo(med.u.pstg, 0, NULL, NULL, stg); 743 ReleaseStgMedium(&med); 744 if(FAILED(hr)) goto end; 745 } 746 *mem = h; 747 748 end: 749 IStorage_Release(stg); 750 if(FAILED(hr)) GlobalFree(h); 751 return hr; 752 } 753 754 /*************************************************************************** 755 * get_data_from_stream 756 * 757 * Returns stream data in an HGLOBAL. 758 */ 759 static HRESULT get_data_from_stream(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 760 { 761 HGLOBAL h; 762 IStream *stm = NULL; 763 HRESULT hr; 764 FORMATETC stm_fmt; 765 STGMEDIUM med; 766 767 *mem = NULL; 768 769 h = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, 0 ); 770 if(!h) return E_OUTOFMEMORY; 771 772 hr = CreateStreamOnHGlobal(h, FALSE, &stm); 773 if(FAILED(hr)) goto error; 774 775 stm_fmt = *fmt; 776 med.tymed = stm_fmt.tymed = TYMED_ISTREAM; 777 med.u.pstm = stm; 778 med.pUnkForRelease = NULL; 779 780 hr = IDataObject_GetDataHere(data, &stm_fmt, &med); 781 if(FAILED(hr)) 782 { 783 LARGE_INTEGER offs; 784 ULARGE_INTEGER pos; 785 786 memset(&med, 0, sizeof(med)); 787 hr = IDataObject_GetData(data, &stm_fmt, &med); 788 if(FAILED(hr)) goto error; 789 790 offs.QuadPart = 0; 791 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_CUR, &pos); 792 IStream_Seek(med.u.pstm, offs, STREAM_SEEK_SET, NULL); 793 hr = IStream_CopyTo(med.u.pstm, stm, pos, NULL, NULL); 794 ReleaseStgMedium(&med); 795 if(FAILED(hr)) goto error; 796 } 797 *mem = h; 798 IStream_Release(stm); 799 return S_OK; 800 801 error: 802 if(stm) IStream_Release(stm); 803 GlobalFree(h); 804 return hr; 805 } 806 807 /*************************************************************************** 808 * get_data_from_global 809 * 810 * Returns global data in an HGLOBAL. 811 */ 812 static HRESULT get_data_from_global(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 813 { 814 HGLOBAL h; 815 HRESULT hr; 816 FORMATETC mem_fmt; 817 STGMEDIUM med; 818 819 *mem = NULL; 820 821 mem_fmt = *fmt; 822 mem_fmt.tymed = TYMED_HGLOBAL; 823 memset(&med, 0, sizeof(med)); 824 825 hr = IDataObject_GetData(data, &mem_fmt, &med); 826 if(FAILED(hr)) return hr; 827 828 hr = dup_global_mem(med.u.hGlobal, GMEM_DDESHARE|GMEM_MOVEABLE, &h); 829 830 if(SUCCEEDED(hr)) *mem = h; 831 832 ReleaseStgMedium(&med); 833 834 return hr; 835 } 836 837 /*************************************************************************** 838 * get_data_from_enhmetafile 839 */ 840 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 841 { 842 HENHMETAFILE copy; 843 HRESULT hr; 844 FORMATETC mem_fmt; 845 STGMEDIUM med; 846 847 *mem = NULL; 848 849 mem_fmt = *fmt; 850 mem_fmt.tymed = TYMED_ENHMF; 851 memset(&med, 0, sizeof(med)); 852 853 hr = IDataObject_GetData(data, &mem_fmt, &med); 854 if(FAILED(hr)) return hr; 855 856 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL); 857 if(copy) *mem = (HGLOBAL)copy; 858 else hr = E_FAIL; 859 860 ReleaseStgMedium(&med); 861 862 return hr; 863 } 864 865 /*************************************************************************** 866 * get_data_from_metafilepict 867 */ 868 static HRESULT get_data_from_metafilepict(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem) 869 { 870 HGLOBAL copy; 871 HRESULT hr; 872 FORMATETC mem_fmt; 873 STGMEDIUM med; 874 875 *mem = NULL; 876 877 mem_fmt = *fmt; 878 mem_fmt.tymed = TYMED_MFPICT; 879 memset(&med, 0, sizeof(med)); 880 881 hr = IDataObject_GetData(data, &mem_fmt, &med); 882 if(FAILED(hr)) return hr; 883 884 hr = dup_metafilepict(med.u.hMetaFilePict, ©); 885 886 if(SUCCEEDED(hr)) *mem = copy; 887 888 ReleaseStgMedium(&med); 889 890 return hr; 891 } 892 893 /*************************************************************************** 894 * get_data_from_bitmap 895 * 896 * Returns bitmap in an HBITMAP. 897 */ 898 static HRESULT get_data_from_bitmap(IDataObject *data, FORMATETC *fmt, HBITMAP *hbm) 899 { 900 HBITMAP copy; 901 HRESULT hr; 902 FORMATETC mem_fmt; 903 STGMEDIUM med; 904 905 *hbm = NULL; 906 907 mem_fmt = *fmt; 908 mem_fmt.tymed = TYMED_GDI; 909 memset(&med, 0, sizeof(med)); 910 911 hr = IDataObject_GetData(data, &mem_fmt, &med); 912 if(FAILED(hr)) return hr; 913 914 hr = dup_bitmap(med.u.hBitmap, ©); 915 916 if(SUCCEEDED(hr)) *hbm = copy; 917 918 ReleaseStgMedium(&med); 919 920 return hr; 921 } 922 923 /*********************************************************************** 924 * render_format 925 * 926 * Render the clipboard data. Note that this call will delegate to the 927 * source data object. 928 */ 929 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt) 930 { 931 HANDLE clip_data = NULL; /* HGLOBAL unless otherwise specified */ 932 HRESULT hr; 933 934 /* Embed source hack */ 935 if(fmt->cfFormat == embed_source_clipboard_format) 936 { 937 return render_embed_source_hack(data, fmt); 938 } 939 940 if(fmt->tymed & TYMED_ISTORAGE) 941 { 942 hr = get_data_from_storage(data, fmt, &clip_data); 943 } 944 else if(fmt->tymed & TYMED_ISTREAM) 945 { 946 hr = get_data_from_stream(data, fmt, &clip_data); 947 } 948 else if(fmt->tymed & TYMED_HGLOBAL) 949 { 950 hr = get_data_from_global(data, fmt, &clip_data); 951 } 952 else if(fmt->tymed & TYMED_ENHMF) 953 { 954 hr = get_data_from_enhmetafile(data, fmt, &clip_data); 955 } 956 else if(fmt->tymed & TYMED_MFPICT) 957 { 958 /* Returns global handle to METAFILEPICT, containing a copied HMETAFILE */ 959 hr = get_data_from_metafilepict(data, fmt, &clip_data); 960 } 961 else if(fmt->tymed & TYMED_GDI) 962 { 963 /* Returns HBITMAP not HGLOBAL */ 964 hr = get_data_from_bitmap(data, fmt, (HBITMAP *)&clip_data); 965 } 966 else 967 { 968 FIXME("Unhandled tymed %x\n", fmt->tymed); 969 hr = DV_E_FORMATETC; 970 } 971 972 if(SUCCEEDED(hr)) 973 { 974 if ( !SetClipboardData(fmt->cfFormat, clip_data) ) 975 { 976 WARN("() : Failed to set rendered clipboard data into clipboard!\n"); 977 if(fmt->tymed & TYMED_MFPICT) 978 free_metafilepict(clip_data); 979 else if(fmt->tymed & TYMED_GDI) 980 DeleteObject(clip_data); 981 else 982 GlobalFree(clip_data); 983 hr = CLIPBRD_E_CANT_SET; 984 } 985 } 986 987 return hr; 988 } 989 990 /*---------------------------------------------------------------------* 991 * Implementation of the internal IDataObject interface exposed by 992 * the OLE clipboard. 993 *---------------------------------------------------------------------*/ 994 995 996 /************************************************************************ 997 * snapshot_QueryInterface 998 */ 999 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface, 1000 REFIID riid, void **ppvObject) 1001 { 1002 snapshot *This = impl_from_IDataObject(iface); 1003 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject); 1004 1005 if ( (This==0) || (ppvObject==0) ) 1006 return E_INVALIDARG; 1007 1008 *ppvObject = 0; 1009 1010 if (IsEqualIID(&IID_IUnknown, riid) || 1011 IsEqualIID(&IID_IDataObject, riid)) 1012 { 1013 *ppvObject = iface; 1014 } 1015 else 1016 { 1017 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); 1018 return E_NOINTERFACE; 1019 } 1020 1021 IUnknown_AddRef((IUnknown*)*ppvObject); 1022 1023 return S_OK; 1024 } 1025 1026 /************************************************************************ 1027 * snapshot_AddRef 1028 */ 1029 static ULONG WINAPI snapshot_AddRef(IDataObject *iface) 1030 { 1031 snapshot *This = impl_from_IDataObject(iface); 1032 1033 TRACE("(%p)->(count=%u)\n", This, This->ref); 1034 1035 return InterlockedIncrement(&This->ref); 1036 } 1037 1038 /************************************************************************ 1039 * snapshot_Release 1040 */ 1041 static ULONG WINAPI snapshot_Release(IDataObject *iface) 1042 { 1043 snapshot *This = impl_from_IDataObject(iface); 1044 ULONG ref; 1045 1046 TRACE("(%p)->(count=%u)\n", This, This->ref); 1047 1048 ref = InterlockedDecrement(&This->ref); 1049 1050 if (ref == 0) 1051 { 1052 EnterCriticalSection(&latest_snapshot_cs); 1053 if (This->ref) 1054 { 1055 LeaveCriticalSection(&latest_snapshot_cs); 1056 return ref; 1057 } 1058 if (theOleClipboard->latest_snapshot == This) 1059 theOleClipboard->latest_snapshot = NULL; 1060 LeaveCriticalSection(&latest_snapshot_cs); 1061 1062 if(This->data) IDataObject_Release(This->data); 1063 HeapFree(GetProcessHeap(), 0, This); 1064 } 1065 1066 return ref; 1067 } 1068 1069 /************************************************************ 1070 * get_current_ole_clip_window 1071 * 1072 * Return the window that owns the ole clipboard. 1073 * 1074 * If the clipboard is flushed or not owned by ole this will 1075 * return NULL. 1076 */ 1077 static HWND get_current_ole_clip_window(void) 1078 { 1079 HGLOBAL h; 1080 HWND *ptr, wnd; 1081 1082 h = GetClipboardData(dataobject_clipboard_format); 1083 if(!h) return NULL; 1084 ptr = GlobalLock(h); 1085 if(!ptr) return NULL; 1086 wnd = *ptr; 1087 GlobalUnlock(h); 1088 return wnd; 1089 } 1090 1091 /************************************************************ 1092 * get_current_dataobject 1093 * 1094 * Return an unmarshalled IDataObject if there is a current 1095 * (ie non-flushed) object on the ole clipboard. 1096 */ 1097 static HRESULT get_current_dataobject(IDataObject **data) 1098 { 1099 HRESULT hr = S_FALSE; 1100 HWND wnd = get_current_ole_clip_window(); 1101 HGLOBAL h; 1102 void *ptr; 1103 IStream *stm; 1104 LARGE_INTEGER pos; 1105 1106 *data = NULL; 1107 if(!wnd) return S_FALSE; 1108 1109 h = GetClipboardData(wine_marshal_clipboard_format); 1110 if(!h) return S_FALSE; 1111 if(GlobalSize(h) <= 1) return S_FALSE; 1112 ptr = GlobalLock(h); 1113 if(!ptr) return S_FALSE; 1114 1115 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm); 1116 if(FAILED(hr)) goto end; 1117 1118 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL); 1119 if(SUCCEEDED(hr)) 1120 { 1121 pos.QuadPart = 0; 1122 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 1123 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data); 1124 } 1125 IStream_Release(stm); 1126 1127 end: 1128 GlobalUnlock(h); 1129 return hr; 1130 } 1131 1132 static DWORD get_tymed_from_nonole_cf(UINT cf) 1133 { 1134 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL; 1135 1136 switch(cf) 1137 { 1138 case CF_TEXT: 1139 case CF_OEMTEXT: 1140 case CF_UNICODETEXT: 1141 return TYMED_ISTREAM | TYMED_HGLOBAL; 1142 case CF_ENHMETAFILE: 1143 return TYMED_ENHMF; 1144 case CF_METAFILEPICT: 1145 return TYMED_MFPICT; 1146 case CF_BITMAP: 1147 return TYMED_GDI; 1148 default: 1149 FIXME("returning TYMED_NULL for cf %04x\n", cf); 1150 return TYMED_NULL; 1151 } 1152 } 1153 1154 /*********************************************************** 1155 * get_priv_data 1156 * 1157 * Returns a copy of the Ole Private Data 1158 */ 1159 static HRESULT get_priv_data(ole_priv_data **data) 1160 { 1161 HGLOBAL handle; 1162 HRESULT hr = S_OK; 1163 ole_priv_data *ret = NULL; 1164 1165 *data = NULL; 1166 1167 handle = GetClipboardData( ole_private_data_clipboard_format ); 1168 if(handle) 1169 { 1170 ole_priv_data *src = GlobalLock(handle); 1171 if(src) 1172 { 1173 DWORD i; 1174 1175 /* FIXME: sanity check on size */ 1176 ret = HeapAlloc(GetProcessHeap(), 0, src->size); 1177 if(!ret) 1178 { 1179 GlobalUnlock(handle); 1180 return E_OUTOFMEMORY; 1181 } 1182 memcpy(ret, src, src->size); 1183 GlobalUnlock(handle); 1184 1185 /* Fixup any target device offsets to ptrs */ 1186 for(i = 0; i < ret->count; i++) 1187 ret->entries[i].fmtetc.ptd = 1188 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd); 1189 } 1190 } 1191 1192 if(!ret) /* Non-ole data */ 1193 { 1194 UINT cf; 1195 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries); 1196 1197 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++) 1198 { 1199 WCHAR buf[256]; 1200 if (GetClipboardFormatNameW(cf, buf, ARRAY_SIZE(buf))) 1201 TRACE("cf %04x %s\n", cf, debugstr_w(buf)); 1202 else 1203 TRACE("cf %04x\n", cf); 1204 } 1205 TRACE("count %d\n", count); 1206 size += count * sizeof(ret->entries[0]); 1207 1208 /* There are holes in fmtetc so zero init */ 1209 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); 1210 if(!ret) return E_OUTOFMEMORY; 1211 ret->size = size; 1212 ret->count = count; 1213 1214 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++) 1215 { 1216 ret->entries[idx].fmtetc.cfFormat = cf; 1217 ret->entries[idx].fmtetc.ptd = NULL; 1218 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT; 1219 ret->entries[idx].fmtetc.lindex = -1; 1220 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf); 1221 ret->entries[idx].first_use = 1; 1222 } 1223 } 1224 1225 *data = ret; 1226 return hr; 1227 } 1228 1229 /************************************************************************ 1230 * get_stgmed_for_global 1231 * 1232 * Returns a stg medium with a copy of the global handle 1233 */ 1234 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med) 1235 { 1236 HRESULT hr; 1237 1238 med->pUnkForRelease = NULL; 1239 med->tymed = TYMED_NULL; 1240 1241 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal); 1242 1243 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL; 1244 1245 return hr; 1246 } 1247 1248 /************************************************************************ 1249 * get_stgmed_for_stream 1250 * 1251 * Returns a stg medium with a stream based on the handle 1252 */ 1253 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med) 1254 { 1255 HRESULT hr; 1256 HGLOBAL dst; 1257 1258 med->pUnkForRelease = NULL; 1259 med->tymed = TYMED_NULL; 1260 1261 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); 1262 if(FAILED(hr)) return hr; 1263 1264 hr = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm); 1265 if(FAILED(hr)) 1266 { 1267 GlobalFree(dst); 1268 return hr; 1269 } 1270 1271 med->tymed = TYMED_ISTREAM; 1272 return hr; 1273 } 1274 1275 /************************************************************************ 1276 * get_stgmed_for_storage 1277 * 1278 * Returns a stg medium with a storage based on the handle 1279 */ 1280 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med) 1281 { 1282 HRESULT hr; 1283 HGLOBAL dst; 1284 ILockBytes *lbs; 1285 1286 med->pUnkForRelease = NULL; 1287 med->tymed = TYMED_NULL; 1288 1289 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst); 1290 if(FAILED(hr)) return hr; 1291 1292 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs); 1293 if(FAILED(hr)) 1294 { 1295 GlobalFree(dst); 1296 return hr; 1297 } 1298 1299 hr = StgIsStorageILockBytes(lbs); 1300 if(hr!=S_OK) 1301 { 1302 ILockBytes_Release(lbs); 1303 GlobalFree(dst); 1304 return SUCCEEDED(hr) ? E_FAIL : hr; 1305 } 1306 1307 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg); 1308 ILockBytes_Release(lbs); 1309 if(FAILED(hr)) 1310 { 1311 GlobalFree(dst); 1312 return hr; 1313 } 1314 1315 med->tymed = TYMED_ISTORAGE; 1316 return hr; 1317 } 1318 1319 /************************************************************************ 1320 * get_stgmed_for_emf 1321 * 1322 * Returns a stg medium with an enhanced metafile based on the handle 1323 */ 1324 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med) 1325 { 1326 med->pUnkForRelease = NULL; 1327 med->tymed = TYMED_NULL; 1328 1329 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL); 1330 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY; 1331 med->tymed = TYMED_ENHMF; 1332 return S_OK; 1333 } 1334 1335 /************************************************************************ 1336 * get_stgmed_for_bitmap 1337 * 1338 * Returns a stg medium with a bitmap based on the handle 1339 */ 1340 static HRESULT get_stgmed_for_bitmap(HBITMAP hbmp, STGMEDIUM *med) 1341 { 1342 HRESULT hr; 1343 1344 med->pUnkForRelease = NULL; 1345 med->tymed = TYMED_NULL; 1346 1347 hr = dup_bitmap(hbmp, &med->u.hBitmap); 1348 1349 if (FAILED(hr)) 1350 return hr; 1351 1352 med->tymed = TYMED_GDI; 1353 return S_OK; 1354 } 1355 1356 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2) 1357 { 1358 const WCHAR *str1, *str2; 1359 1360 if(off1 == 0 && off2 == 0) return TRUE; 1361 if(off1 == 0 || off2 == 0) return FALSE; 1362 1363 str1 = (const WCHAR*)((const char*)t1 + off1); 1364 str2 = (const WCHAR*)((const char*)t2 + off2); 1365 1366 return !wcscmp(str1, str2); 1367 } 1368 1369 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2) 1370 { 1371 if(t1 == NULL && t2 == NULL) return TRUE; 1372 if(t1 == NULL || t2 == NULL) return FALSE; 1373 1374 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset)) 1375 return FALSE; 1376 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset)) 1377 return FALSE; 1378 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset)) 1379 return FALSE; 1380 1381 /* FIXME check devmode? */ 1382 1383 return TRUE; 1384 } 1385 1386 /************************************************************************ 1387 * snapshot_GetData 1388 */ 1389 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt, 1390 STGMEDIUM *med) 1391 { 1392 snapshot *This = impl_from_IDataObject(iface); 1393 HANDLE h; 1394 HRESULT hr; 1395 ole_priv_data *enum_data = NULL; 1396 ole_priv_data_entry *entry; 1397 DWORD mask; 1398 1399 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med); 1400 1401 if ( !fmt || !med ) return E_INVALIDARG; 1402 1403 memset(med, 0, sizeof(*med)); 1404 1405 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN; 1406 1407 if(!This->data) 1408 hr = get_current_dataobject(&This->data); 1409 1410 if(This->data) 1411 { 1412 hr = IDataObject_GetData(This->data, fmt, med); 1413 if(SUCCEEDED(hr)) 1414 { 1415 CloseClipboard(); 1416 return hr; 1417 } 1418 } 1419 if(fmt->lindex != -1) 1420 { 1421 hr = DV_E_FORMATETC; 1422 goto end; 1423 } 1424 1425 if(!IsClipboardFormatAvailable(fmt->cfFormat)) 1426 { 1427 hr = DV_E_FORMATETC; 1428 goto end; 1429 } 1430 1431 hr = get_priv_data(&enum_data); 1432 if(FAILED(hr)) goto end; 1433 1434 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat); 1435 if(entry) 1436 { 1437 if(!td_equal(fmt->ptd, entry->fmtetc.ptd)) 1438 { 1439 hr = DV_E_FORMATETC; 1440 goto end; 1441 } 1442 mask = fmt->tymed & entry->fmtetc.tymed; 1443 if(!mask && (entry->fmtetc.tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE))) 1444 mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL | TYMED_ISTORAGE); 1445 } 1446 else /* non-Ole format */ 1447 mask = fmt->tymed & get_tymed_from_nonole_cf(fmt->cfFormat); 1448 1449 if(!mask) 1450 { 1451 hr = DV_E_TYMED; 1452 goto end; 1453 } 1454 1455 h = GetClipboardData(fmt->cfFormat); 1456 if(!h) 1457 { 1458 hr = DV_E_FORMATETC; 1459 goto end; 1460 } 1461 1462 if(mask & TYMED_HGLOBAL) 1463 hr = get_stgmed_for_global(h, med); 1464 else if(mask & TYMED_ISTREAM) 1465 hr = get_stgmed_for_stream(h, med); 1466 else if(mask & TYMED_ISTORAGE) 1467 hr = get_stgmed_for_storage(h, med); 1468 else if(mask & TYMED_ENHMF) 1469 hr = get_stgmed_for_emf((HENHMETAFILE)h, med); 1470 else if(mask & TYMED_GDI) 1471 hr = get_stgmed_for_bitmap((HBITMAP)h, med); 1472 else 1473 { 1474 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed); 1475 hr = E_FAIL; 1476 goto end; 1477 } 1478 1479 end: 1480 HeapFree(GetProcessHeap(), 0, enum_data); 1481 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 1482 return hr; 1483 } 1484 1485 /************************************************************************ 1486 * snapshot_GetDataHere 1487 */ 1488 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt, 1489 STGMEDIUM *med) 1490 { 1491 snapshot *This = impl_from_IDataObject(iface); 1492 HANDLE h; 1493 HRESULT hr; 1494 ole_priv_data *enum_data = NULL; 1495 ole_priv_data_entry *entry; 1496 TYMED supported; 1497 1498 if ( !fmt || !med ) return E_INVALIDARG; 1499 1500 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed); 1501 1502 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN; 1503 1504 if(!This->data) 1505 hr = get_current_dataobject(&This->data); 1506 1507 if(This->data) 1508 { 1509 hr = IDataObject_GetDataHere(This->data, fmt, med); 1510 if(SUCCEEDED(hr)) 1511 { 1512 CloseClipboard(); 1513 return hr; 1514 } 1515 } 1516 1517 h = GetClipboardData(fmt->cfFormat); 1518 if(!h) 1519 { 1520 hr = DV_E_FORMATETC; 1521 goto end; 1522 } 1523 1524 hr = get_priv_data(&enum_data); 1525 if(FAILED(hr)) goto end; 1526 1527 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat); 1528 if(entry) 1529 { 1530 if(!td_equal(fmt->ptd, entry->fmtetc.ptd)) 1531 { 1532 hr = DV_E_FORMATETC; 1533 goto end; 1534 } 1535 supported = entry->fmtetc.tymed; 1536 } 1537 else /* non-Ole format */ 1538 supported = TYMED_HGLOBAL; 1539 1540 switch(med->tymed) 1541 { 1542 case TYMED_HGLOBAL: 1543 { 1544 DWORD src_size = GlobalSize(h); 1545 DWORD dst_size = GlobalSize(med->u.hGlobal); 1546 hr = E_FAIL; 1547 if(dst_size >= src_size) 1548 { 1549 void *src = GlobalLock(h); 1550 void *dst = GlobalLock(med->u.hGlobal); 1551 1552 memcpy(dst, src, src_size); 1553 GlobalUnlock(med->u.hGlobal); 1554 GlobalUnlock(h); 1555 hr = S_OK; 1556 } 1557 break; 1558 } 1559 case TYMED_ISTREAM: 1560 { 1561 DWORD src_size = GlobalSize(h); 1562 void *src = GlobalLock(h); 1563 hr = IStream_Write(med->u.pstm, src, src_size, NULL); 1564 GlobalUnlock(h); 1565 break; 1566 } 1567 case TYMED_ISTORAGE: 1568 { 1569 STGMEDIUM copy; 1570 if(!(supported & TYMED_ISTORAGE)) 1571 { 1572 hr = E_FAIL; 1573 goto end; 1574 } 1575 hr = get_stgmed_for_storage(h, ©); 1576 if(SUCCEEDED(hr)) 1577 { 1578 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg); 1579 ReleaseStgMedium(©); 1580 } 1581 break; 1582 } 1583 default: 1584 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed); 1585 hr = E_FAIL; 1586 goto end; 1587 } 1588 1589 end: 1590 HeapFree(GetProcessHeap(), 0, enum_data); 1591 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 1592 return hr; 1593 } 1594 1595 /************************************************************************ 1596 * snapshot_QueryGetData 1597 * 1598 * The OLE Clipboard's implementation of this method delegates to 1599 * a data source if there is one or wraps around the windows clipboard 1600 * function IsClipboardFormatAvailable() otherwise. 1601 * 1602 */ 1603 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt) 1604 { 1605 TRACE("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt)); 1606 1607 if (!fmt) return E_INVALIDARG; 1608 1609 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC; 1610 1611 if ( fmt->lindex != -1 ) return DV_E_FORMATETC; 1612 1613 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT; 1614 } 1615 1616 /************************************************************************ 1617 * snapshot_GetCanonicalFormatEtc 1618 */ 1619 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in, 1620 FORMATETC *fmt_out) 1621 { 1622 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out); 1623 1624 if ( !fmt_in || !fmt_out ) return E_INVALIDARG; 1625 1626 *fmt_out = *fmt_in; 1627 return DATA_S_SAMEFORMATETC; 1628 } 1629 1630 /************************************************************************ 1631 * snapshot_SetData 1632 * 1633 * The OLE Clipboard does not implement this method 1634 */ 1635 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt, 1636 STGMEDIUM *med, BOOL release) 1637 { 1638 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release); 1639 return E_NOTIMPL; 1640 } 1641 1642 /************************************************************************ 1643 * snapshot_EnumFormatEtc 1644 * 1645 */ 1646 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir, 1647 IEnumFORMATETC **enum_fmt) 1648 { 1649 HRESULT hr; 1650 ole_priv_data *data = NULL; 1651 1652 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt); 1653 1654 *enum_fmt = NULL; 1655 1656 if ( dir != DATADIR_GET ) return E_NOTIMPL; 1657 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN; 1658 1659 hr = get_priv_data(&data); 1660 1661 if(FAILED(hr)) goto end; 1662 1663 hr = enum_fmtetc_construct( data, 0, enum_fmt ); 1664 1665 end: 1666 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 1667 return hr; 1668 } 1669 1670 /************************************************************************ 1671 * snapshot_DAdvise 1672 * 1673 * The OLE Clipboard does not implement this method 1674 */ 1675 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt, 1676 DWORD flags, IAdviseSink *sink, 1677 DWORD *conn) 1678 { 1679 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn); 1680 return E_NOTIMPL; 1681 } 1682 1683 /************************************************************************ 1684 * snapshot_DUnadvise 1685 * 1686 * The OLE Clipboard does not implement this method 1687 */ 1688 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn) 1689 { 1690 TRACE("(%p, %d): not implemented\n", iface, conn); 1691 return E_NOTIMPL; 1692 } 1693 1694 /************************************************************************ 1695 * snapshot_EnumDAdvise 1696 * 1697 * The OLE Clipboard does not implement this method 1698 */ 1699 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface, 1700 IEnumSTATDATA** enum_advise) 1701 { 1702 TRACE("(%p, %p): not implemented\n", iface, enum_advise); 1703 return E_NOTIMPL; 1704 } 1705 1706 static const IDataObjectVtbl snapshot_vtable = 1707 { 1708 snapshot_QueryInterface, 1709 snapshot_AddRef, 1710 snapshot_Release, 1711 snapshot_GetData, 1712 snapshot_GetDataHere, 1713 snapshot_QueryGetData, 1714 snapshot_GetCanonicalFormatEtc, 1715 snapshot_SetData, 1716 snapshot_EnumFormatEtc, 1717 snapshot_DAdvise, 1718 snapshot_DUnadvise, 1719 snapshot_EnumDAdvise 1720 }; 1721 1722 /*---------------------------------------------------------------------* 1723 * Internal implementation methods for the OLE clipboard 1724 *---------------------------------------------------------------------*/ 1725 1726 static snapshot *snapshot_construct(DWORD seq_no) 1727 { 1728 snapshot *This; 1729 1730 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) ); 1731 if (!This) return NULL; 1732 1733 This->IDataObject_iface.lpVtbl = &snapshot_vtable; 1734 This->ref = 0; 1735 This->seq_no = seq_no; 1736 This->data = NULL; 1737 1738 return This; 1739 } 1740 1741 /********************************************************* 1742 * register_clipboard_formats 1743 */ 1744 static void register_clipboard_formats(void) 1745 { 1746 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0}; 1747 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0}; 1748 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0}; 1749 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0}; 1750 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0}; 1751 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0}; 1752 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0}; 1753 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0}; 1754 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0}; 1755 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ', 1756 'D','e','s','c','r','i','p','t','o','r',0}; 1757 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0}; 1758 1759 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ', 1760 'D','a','t','a','O','b','j','e','c','t',0}; 1761 1762 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink); 1763 filename_clipboard_format = RegisterClipboardFormatW(FileName); 1764 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW); 1765 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject); 1766 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject); 1767 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource); 1768 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource); 1769 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource); 1770 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor); 1771 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor); 1772 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData); 1773 1774 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject); 1775 } 1776 1777 /*********************************************************************** 1778 * OLEClipbrd_Initialize() 1779 * Initializes the OLE clipboard. 1780 */ 1781 void OLEClipbrd_Initialize(void) 1782 { 1783 register_clipboard_formats(); 1784 1785 if ( !theOleClipboard ) 1786 { 1787 ole_clipbrd* clipbrd; 1788 HGLOBAL h; 1789 1790 TRACE("()\n"); 1791 1792 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) ); 1793 if (!clipbrd) return; 1794 1795 clipbrd->latest_snapshot = NULL; 1796 clipbrd->window = NULL; 1797 clipbrd->src_data = NULL; 1798 clipbrd->cached_enum = NULL; 1799 1800 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0); 1801 if(!h) 1802 { 1803 HeapFree(GetProcessHeap(), 0, clipbrd); 1804 return; 1805 } 1806 1807 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data))) 1808 { 1809 GlobalFree(h); 1810 HeapFree(GetProcessHeap(), 0, clipbrd); 1811 return; 1812 } 1813 1814 theOleClipboard = clipbrd; 1815 } 1816 } 1817 1818 /********************************************************************* 1819 * set_clipboard_formats 1820 * 1821 * Enumerate all formats supported by the source and make 1822 * those formats available using delayed rendering using SetClipboardData. 1823 * Cache the enumeration list and make that list visible as the 1824 * 'Ole Private Data' format on the clipboard. 1825 * 1826 */ 1827 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data) 1828 { 1829 HRESULT hr; 1830 FORMATETC fmt; 1831 IEnumFORMATETC *enum_fmt; 1832 HGLOBAL priv_data_handle; 1833 DWORD_PTR target_offset; 1834 ole_priv_data *priv_data; 1835 DWORD count = 0, needed = sizeof(*priv_data), idx; 1836 1837 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt); 1838 if(FAILED(hr)) return hr; 1839 1840 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) 1841 { 1842 count++; 1843 needed += sizeof(priv_data->entries[0]); 1844 if(fmt.ptd) 1845 { 1846 needed += fmt.ptd->tdSize; 1847 CoTaskMemFree(fmt.ptd); 1848 } 1849 } 1850 1851 /* Windows pads the list with two empty ole_priv_data_entries, one 1852 * after the entries array and one after the target device data. 1853 * Allocating with zero init to zero these pads. */ 1854 1855 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */ 1856 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed); 1857 priv_data = GlobalLock(priv_data_handle); 1858 1859 priv_data->unk1 = 0; 1860 priv_data->size = needed; 1861 priv_data->unk2 = 1; 1862 priv_data->count = count; 1863 priv_data->unk3[0] = 0; 1864 priv_data->unk3[1] = 0; 1865 1866 IEnumFORMATETC_Reset(enum_fmt); 1867 1868 idx = 0; 1869 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */ 1870 1871 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK) 1872 { 1873 TRACE("%s\n", dump_fmtetc(&fmt)); 1874 1875 priv_data->entries[idx].fmtetc = fmt; 1876 if(fmt.ptd) 1877 { 1878 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize); 1879 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset; 1880 target_offset += fmt.ptd->tdSize; 1881 CoTaskMemFree(fmt.ptd); 1882 } 1883 1884 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat); 1885 priv_data->entries[idx].unk[0] = 0; 1886 priv_data->entries[idx].unk[1] = 0; 1887 1888 if (priv_data->entries[idx].first_use) 1889 SetClipboardData(fmt.cfFormat, NULL); 1890 1891 idx++; 1892 } 1893 1894 IEnumFORMATETC_Release(enum_fmt); 1895 1896 /* Cache the list and fixup any target device offsets to ptrs */ 1897 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed); 1898 memcpy(clipbrd->cached_enum, priv_data, needed); 1899 for(idx = 0; idx < clipbrd->cached_enum->count; idx++) 1900 clipbrd->cached_enum->entries[idx].fmtetc.ptd = 1901 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd); 1902 1903 GlobalUnlock(priv_data_handle); 1904 if(!SetClipboardData(ole_private_data_clipboard_format, priv_data_handle)) 1905 { 1906 GlobalFree(priv_data_handle); 1907 return CLIPBRD_E_CANT_SET; 1908 } 1909 1910 return S_OK; 1911 } 1912 1913 static HWND create_clipbrd_window(void); 1914 1915 /*********************************************************************** 1916 * get_clipbrd_window 1917 */ 1918 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd) 1919 { 1920 #ifdef __REACTOS__ 1921 /* The clipboard window can get destroyed if the thread that created it dies so we may need to create it again */ 1922 if (!IsWindow(clipbrd->window)) 1923 clipbrd->window = create_clipbrd_window(); 1924 #endif 1925 1926 if ( !clipbrd->window ) 1927 clipbrd->window = create_clipbrd_window(); 1928 1929 *wnd = clipbrd->window; 1930 return *wnd ? S_OK : E_FAIL; 1931 } 1932 1933 1934 /********************************************************************** 1935 * release_marshal_data 1936 * 1937 * Releases the data and sets the stream back to zero size. 1938 */ 1939 static inline void release_marshal_data(IStream *stm) 1940 { 1941 LARGE_INTEGER pos; 1942 ULARGE_INTEGER size; 1943 pos.QuadPart = size.QuadPart = 0; 1944 1945 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 1946 CoReleaseMarshalData(stm); 1947 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL); 1948 IStream_SetSize(stm, size); 1949 } 1950 1951 /*********************************************************************** 1952 * expose_marshalled_dataobject 1953 * 1954 * Sets the marshalled dataobject to the clipboard. In the flushed case 1955 * we set a zero sized HGLOBAL to clear the old marshalled data. 1956 */ 1957 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data) 1958 { 1959 HGLOBAL h; 1960 1961 if(data) 1962 { 1963 HGLOBAL h_stm; 1964 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm); 1965 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h); 1966 } 1967 else /* flushed */ 1968 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 1); 1969 1970 if(!h) return E_OUTOFMEMORY; 1971 1972 if(!SetClipboardData(wine_marshal_clipboard_format, h)) 1973 { 1974 GlobalFree(h); 1975 return CLIPBRD_E_CANT_SET; 1976 } 1977 return S_OK; 1978 } 1979 1980 /*********************************************************************** 1981 * set_src_dataobject 1982 * 1983 * Clears and sets the clipboard's src IDataObject. 1984 * 1985 * To marshal the source dataobject we do something rather different from Windows. 1986 * We set a clipboard format which contains the marshalled data. 1987 * Windows sets two window props one of which is an IID, the other is an endpoint number. 1988 */ 1989 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data) 1990 { 1991 HRESULT hr; 1992 HWND wnd; 1993 1994 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 1995 1996 if(clipbrd->src_data) 1997 { 1998 release_marshal_data(clipbrd->marshal_data); 1999 2000 IDataObject_Release(clipbrd->src_data); 2001 clipbrd->src_data = NULL; 2002 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum); 2003 clipbrd->cached_enum = NULL; 2004 } 2005 2006 if(data) 2007 { 2008 IUnknown *unk; 2009 2010 IDataObject_AddRef(data); 2011 clipbrd->src_data = data; 2012 2013 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk); 2014 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk, 2015 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); 2016 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */ 2017 if(FAILED(hr)) return hr; 2018 hr = set_clipboard_formats(clipbrd, data); 2019 } 2020 return hr; 2021 } 2022 2023 /*********************************************************************** 2024 * OLEClipbrd_UnInitialize() 2025 * Un-Initializes the OLE clipboard 2026 */ 2027 void OLEClipbrd_UnInitialize(void) 2028 { 2029 ole_clipbrd *clipbrd = theOleClipboard; 2030 2031 TRACE("()\n"); 2032 2033 if ( clipbrd ) 2034 { 2035 static const WCHAR ole32W[] = {'o','l','e','3','2',0}; 2036 HINSTANCE hinst = GetModuleHandleW(ole32W); 2037 2038 /* OleUninitialize() does not release the reference to the dataobject, so 2039 take an additional reference here. This reference is then leaked. */ 2040 if (clipbrd->src_data) 2041 { 2042 IDataObject_AddRef(clipbrd->src_data); 2043 set_src_dataobject(clipbrd, NULL); 2044 } 2045 2046 if ( clipbrd->window ) 2047 { 2048 DestroyWindow(clipbrd->window); 2049 UnregisterClassW( clipbrd_wndclass, hinst ); 2050 } 2051 2052 IStream_Release(clipbrd->marshal_data); 2053 HeapFree(GetProcessHeap(), 0, clipbrd); 2054 theOleClipboard = NULL; 2055 } 2056 } 2057 2058 /*********************************************************************** 2059 * clipbrd_wndproc 2060 */ 2061 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 2062 { 2063 ole_clipbrd *clipbrd; 2064 2065 get_ole_clipbrd(&clipbrd); 2066 #ifdef __REACTOS__ 2067 if(clipbrd == NULL) 2068 return DefWindowProcW(hwnd, message, wparam, lparam); 2069 #endif 2070 2071 switch (message) 2072 { 2073 case WM_RENDERFORMAT: 2074 { 2075 #ifdef __REACTOS__ 2076 if (clipbrd->cached_enum) 2077 { 2078 #endif 2079 UINT cf = wparam; 2080 ole_priv_data_entry *entry; 2081 2082 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf); 2083 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf); 2084 2085 if(entry) 2086 render_format(clipbrd->src_data, &entry->fmtetc); 2087 #ifdef __REACTOS__ 2088 } 2089 #endif 2090 break; 2091 } 2092 2093 case WM_RENDERALLFORMATS: 2094 { 2095 DWORD i; 2096 ole_priv_data_entry *entries; 2097 2098 TRACE("(): WM_RENDERALLFORMATS\n"); 2099 2100 if (!clipbrd || !clipbrd->cached_enum) break; 2101 entries = clipbrd->cached_enum->entries; 2102 for(i = 0; i < clipbrd->cached_enum->count; i++) 2103 { 2104 if(entries[i].first_use) 2105 render_format(clipbrd->src_data, &entries[i].fmtetc); 2106 } 2107 break; 2108 } 2109 2110 case WM_DESTROYCLIPBOARD: 2111 { 2112 TRACE("(): WM_DESTROYCLIPBOARD\n"); 2113 2114 set_src_dataobject(clipbrd, NULL); 2115 break; 2116 } 2117 2118 default: 2119 return DefWindowProcW(hwnd, message, wparam, lparam); 2120 } 2121 2122 return 0; 2123 } 2124 2125 2126 /*********************************************************************** 2127 * create_clipbrd_window 2128 */ 2129 static HWND create_clipbrd_window(void) 2130 { 2131 WNDCLASSEXW class; 2132 static const WCHAR ole32W[] = {'o','l','e','3','2',0}; 2133 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0}; 2134 HINSTANCE hinst = GetModuleHandleW(ole32W); 2135 2136 class.cbSize = sizeof(class); 2137 class.style = 0; 2138 class.lpfnWndProc = clipbrd_wndproc; 2139 class.cbClsExtra = 0; 2140 class.cbWndExtra = 0; 2141 class.hInstance = hinst; 2142 class.hIcon = 0; 2143 class.hCursor = 0; 2144 class.hbrBackground = 0; 2145 class.lpszMenuName = NULL; 2146 class.lpszClassName = clipbrd_wndclass; 2147 class.hIconSm = NULL; 2148 2149 RegisterClassExW(&class); 2150 2151 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, 2152 0, 0, 0, 0, HWND_MESSAGE, NULL, hinst, 0); 2153 } 2154 2155 /********************************************************************* 2156 * set_dataobject_format 2157 * 2158 * Windows creates a 'DataObject' clipboard format that contains the 2159 * clipboard window's HWND or NULL if the Ole clipboard has been flushed. 2160 */ 2161 static HRESULT set_dataobject_format(HWND hwnd) 2162 { 2163 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd)); 2164 HWND *data; 2165 2166 if(!h) return E_OUTOFMEMORY; 2167 2168 data = GlobalLock(h); 2169 *data = hwnd; 2170 GlobalUnlock(h); 2171 2172 if(!SetClipboardData(dataobject_clipboard_format, h)) 2173 { 2174 GlobalFree(h); 2175 return CLIPBRD_E_CANT_SET; 2176 } 2177 2178 return S_OK; 2179 } 2180 2181 /*---------------------------------------------------------------------* 2182 * Win32 OLE clipboard API 2183 *---------------------------------------------------------------------*/ 2184 2185 /*********************************************************************** 2186 * OleSetClipboard [OLE32.@] 2187 * Places a pointer to the specified data object onto the clipboard, 2188 * making the data object accessible to the OleGetClipboard function. 2189 * 2190 * RETURNS 2191 * 2192 * S_OK IDataObject pointer placed on the clipboard 2193 * CLIPBRD_E_CANT_OPEN OpenClipboard failed 2194 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed 2195 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed 2196 * CLIPBRD_E_CANT_SET SetClipboard failed 2197 */ 2198 2199 HRESULT WINAPI OleSetClipboard(IDataObject* data) 2200 { 2201 HRESULT hr; 2202 ole_clipbrd *clipbrd; 2203 HWND wnd; 2204 2205 TRACE("(%p)\n", data); 2206 2207 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 2208 2209 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 2210 2211 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN; 2212 2213 if ( !EmptyClipboard() ) 2214 { 2215 hr = CLIPBRD_E_CANT_EMPTY; 2216 goto end; 2217 } 2218 2219 hr = set_src_dataobject(clipbrd, data); 2220 if(FAILED(hr)) goto end; 2221 2222 if(data) 2223 { 2224 hr = expose_marshalled_dataobject(clipbrd, data); 2225 if(FAILED(hr)) goto end; 2226 hr = set_dataobject_format(wnd); 2227 } 2228 2229 end: 2230 2231 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 2232 2233 if ( FAILED(hr) ) 2234 { 2235 expose_marshalled_dataobject(clipbrd, NULL); 2236 set_src_dataobject(clipbrd, NULL); 2237 } 2238 2239 return hr; 2240 } 2241 2242 2243 /*********************************************************************** 2244 * OleGetClipboard [OLE32.@] 2245 * Returns a pointer to our internal IDataObject which represents the conceptual 2246 * state of the Windows clipboard. If the current clipboard already contains 2247 * an IDataObject, our internal IDataObject will delegate to this object. 2248 */ 2249 HRESULT WINAPI OleGetClipboard(IDataObject **obj) 2250 { 2251 HRESULT hr; 2252 ole_clipbrd *clipbrd; 2253 DWORD seq_no; 2254 2255 TRACE("(%p)\n", obj); 2256 2257 if(!obj) return E_INVALIDARG; 2258 *obj = NULL; 2259 2260 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 2261 2262 seq_no = GetClipboardSequenceNumber(); 2263 EnterCriticalSection(&latest_snapshot_cs); 2264 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no) 2265 clipbrd->latest_snapshot = NULL; 2266 2267 if(!clipbrd->latest_snapshot) 2268 { 2269 clipbrd->latest_snapshot = snapshot_construct(seq_no); 2270 if(!clipbrd->latest_snapshot) 2271 { 2272 LeaveCriticalSection(&latest_snapshot_cs); 2273 return E_OUTOFMEMORY; 2274 } 2275 } 2276 2277 *obj = &clipbrd->latest_snapshot->IDataObject_iface; 2278 IDataObject_AddRef(*obj); 2279 LeaveCriticalSection(&latest_snapshot_cs); 2280 2281 return S_OK; 2282 } 2283 2284 /****************************************************************************** 2285 * OleFlushClipboard [OLE32.@] 2286 * Renders the data from the source IDataObject into the windows clipboard 2287 * 2288 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media 2289 * by copying the storage into global memory. Subsequently the default 2290 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL 2291 * back to TYMED_IStorage. 2292 */ 2293 HRESULT WINAPI OleFlushClipboard(void) 2294 { 2295 HRESULT hr; 2296 ole_clipbrd *clipbrd; 2297 HWND wnd; 2298 2299 TRACE("()\n"); 2300 2301 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 2302 2303 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr; 2304 2305 /* 2306 * Already flushed or no source DataObject? Nothing to do. 2307 */ 2308 if (!clipbrd->src_data) return S_OK; 2309 2310 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN; 2311 2312 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0); 2313 2314 hr = set_dataobject_format(NULL); 2315 2316 expose_marshalled_dataobject(clipbrd, NULL); 2317 set_src_dataobject(clipbrd, NULL); 2318 2319 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE; 2320 2321 return hr; 2322 } 2323 2324 2325 /*********************************************************************** 2326 * OleIsCurrentClipboard [OLE32.@] 2327 */ 2328 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data) 2329 { 2330 HRESULT hr; 2331 ole_clipbrd *clipbrd; 2332 TRACE("()\n"); 2333 2334 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr; 2335 2336 if (data == NULL) return S_FALSE; 2337 2338 return (data == clipbrd->src_data) ? S_OK : S_FALSE; 2339 } 2340