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