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