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 static HRESULT get_data_from_enhmetafile(IDataObject *data, FORMATETC *fmt, HGLOBAL *mem)
748 {
749 HENHMETAFILE copy;
750 HRESULT hr;
751 FORMATETC mem_fmt;
752 STGMEDIUM med;
753
754 *mem = NULL;
755
756 mem_fmt = *fmt;
757 mem_fmt.tymed = TYMED_ENHMF;
758
759 hr = IDataObject_GetData(data, &mem_fmt, &med);
760 if(FAILED(hr)) return hr;
761
762 copy = CopyEnhMetaFileW(med.u.hEnhMetaFile, NULL);
763 if(copy) *mem = (HGLOBAL)copy;
764 else hr = E_FAIL;
765
766 ReleaseStgMedium(&med);
767
768 return hr;
769 }
770
771 /***********************************************************************
772 * render_format
773 *
774 * Render the clipboard data. Note that this call will delegate to the
775 * source data object.
776 */
777 static HRESULT render_format(IDataObject *data, LPFORMATETC fmt)
778 {
779 HGLOBAL clip_data = NULL;
780 HRESULT hr;
781
782 /* Embed source hack */
783 if(fmt->cfFormat == embed_source_clipboard_format)
784 {
785 return render_embed_source_hack(data, fmt);
786 }
787
788 if(fmt->tymed & TYMED_ISTORAGE)
789 {
790 hr = get_data_from_storage(data, fmt, &clip_data);
791 }
792 else if(fmt->tymed & TYMED_ISTREAM)
793 {
794 hr = get_data_from_stream(data, fmt, &clip_data);
795 }
796 else if(fmt->tymed & TYMED_HGLOBAL)
797 {
798 hr = get_data_from_global(data, fmt, &clip_data);
799 }
800 else if(fmt->tymed & TYMED_ENHMF)
801 {
802 hr = get_data_from_enhmetafile(data, fmt, &clip_data);
803 }
804 else
805 {
806 FIXME("Unhandled tymed %x\n", fmt->tymed);
807 hr = DV_E_FORMATETC;
808 }
809
810 if(SUCCEEDED(hr))
811 {
812 if ( !SetClipboardData(fmt->cfFormat, clip_data) )
813 {
814 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
815 GlobalFree(clip_data);
816 hr = CLIPBRD_E_CANT_SET;
817 }
818 }
819
820 return hr;
821 }
822
823 /*---------------------------------------------------------------------*
824 * Implementation of the internal IDataObject interface exposed by
825 * the OLE clipboard.
826 *---------------------------------------------------------------------*/
827
828
829 /************************************************************************
830 * snapshot_QueryInterface
831 */
832 static HRESULT WINAPI snapshot_QueryInterface(IDataObject *iface,
833 REFIID riid, void **ppvObject)
834 {
835 snapshot *This = impl_from_IDataObject(iface);
836 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
837
838 if ( (This==0) || (ppvObject==0) )
839 return E_INVALIDARG;
840
841 *ppvObject = 0;
842
843 if (IsEqualIID(&IID_IUnknown, riid) ||
844 IsEqualIID(&IID_IDataObject, riid))
845 {
846 *ppvObject = iface;
847 }
848 else
849 {
850 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
851 return E_NOINTERFACE;
852 }
853
854 IUnknown_AddRef((IUnknown*)*ppvObject);
855
856 return S_OK;
857 }
858
859 /************************************************************************
860 * snapshot_AddRef
861 */
862 static ULONG WINAPI snapshot_AddRef(IDataObject *iface)
863 {
864 snapshot *This = impl_from_IDataObject(iface);
865
866 TRACE("(%p)->(count=%u)\n", This, This->ref);
867
868 return InterlockedIncrement(&This->ref);
869 }
870
871 /************************************************************************
872 * snapshot_Release
873 */
874 static ULONG WINAPI snapshot_Release(IDataObject *iface)
875 {
876 snapshot *This = impl_from_IDataObject(iface);
877 ULONG ref;
878
879 TRACE("(%p)->(count=%u)\n", This, This->ref);
880
881 ref = InterlockedDecrement(&This->ref);
882
883 if (ref == 0)
884 {
885 ole_clipbrd *clipbrd;
886 HRESULT hr = get_ole_clipbrd(&clipbrd);
887
888 if(This->data) IDataObject_Release(This->data);
889
890 if(SUCCEEDED(hr) && clipbrd->latest_snapshot == This)
891 clipbrd->latest_snapshot = NULL;
892 HeapFree(GetProcessHeap(), 0, This);
893 }
894
895 return ref;
896 }
897
898 /************************************************************
899 * get_current_ole_clip_window
900 *
901 * Return the window that owns the ole clipboard.
902 *
903 * If the clipboard is flushed or not owned by ole this will
904 * return NULL.
905 */
906 static HWND get_current_ole_clip_window(void)
907 {
908 HGLOBAL h;
909 HWND *ptr, wnd;
910
911 h = GetClipboardData(dataobject_clipboard_format);
912 if(!h) return NULL;
913 ptr = GlobalLock(h);
914 if(!ptr) return NULL;
915 wnd = *ptr;
916 GlobalUnlock(h);
917 return wnd;
918 }
919
920 /************************************************************
921 * get_current_dataobject
922 *
923 * Return an unmarshalled IDataObject if there is a current
924 * (ie non-flushed) object on the ole clipboard.
925 */
926 static HRESULT get_current_dataobject(IDataObject **data)
927 {
928 HRESULT hr = S_FALSE;
929 HWND wnd = get_current_ole_clip_window();
930 HGLOBAL h;
931 void *ptr;
932 IStream *stm;
933 LARGE_INTEGER pos;
934
935 *data = NULL;
936 if(!wnd) return S_FALSE;
937
938 h = GetClipboardData(wine_marshal_clipboard_format);
939 if(!h) return S_FALSE;
940 if(GlobalSize(h) == 0) return S_FALSE;
941 ptr = GlobalLock(h);
942 if(!ptr) return S_FALSE;
943
944 hr = CreateStreamOnHGlobal(NULL, TRUE, &stm);
945 if(FAILED(hr)) goto end;
946
947 hr = IStream_Write(stm, ptr, GlobalSize(h), NULL);
948 if(SUCCEEDED(hr))
949 {
950 pos.QuadPart = 0;
951 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
952 hr = CoUnmarshalInterface(stm, &IID_IDataObject, (void**)data);
953 }
954 IStream_Release(stm);
955
956 end:
957 GlobalUnlock(h);
958 return hr;
959 }
960
961 static DWORD get_tymed_from_nonole_cf(UINT cf)
962 {
963 if(cf >= 0xc000) return TYMED_ISTREAM | TYMED_HGLOBAL;
964
965 switch(cf)
966 {
967 case CF_TEXT:
968 case CF_OEMTEXT:
969 case CF_UNICODETEXT:
970 return TYMED_ISTREAM | TYMED_HGLOBAL;
971 case CF_ENHMETAFILE:
972 return TYMED_ENHMF;
973 case CF_METAFILEPICT:
974 return TYMED_MFPICT;
975 default:
976 FIXME("returning TYMED_NULL for cf %04x\n", cf);
977 return TYMED_NULL;
978 }
979 }
980
981 /***********************************************************
982 * get_priv_data
983 *
984 * Returns a copy of the Ole Private Data
985 */
986 static HRESULT get_priv_data(ole_priv_data **data)
987 {
988 HGLOBAL handle;
989 HRESULT hr = S_OK;
990 ole_priv_data *ret = NULL;
991
992 *data = NULL;
993
994 handle = GetClipboardData( ole_private_data_clipboard_format );
995 if(handle)
996 {
997 ole_priv_data *src = GlobalLock(handle);
998 if(src)
999 {
1000 DWORD i;
1001
1002 /* FIXME: sanity check on size */
1003 ret = HeapAlloc(GetProcessHeap(), 0, src->size);
1004 if(!ret)
1005 {
1006 GlobalUnlock(handle);
1007 return E_OUTOFMEMORY;
1008 }
1009 memcpy(ret, src, src->size);
1010 GlobalUnlock(handle);
1011
1012 /* Fixup any target device offsets to ptrs */
1013 for(i = 0; i < ret->count; i++)
1014 ret->entries[i].fmtetc.ptd =
1015 td_offs_to_ptr(ret, (DWORD_PTR) ret->entries[i].fmtetc.ptd);
1016 }
1017 }
1018
1019 if(!ret) /* Non-ole data */
1020 {
1021 UINT cf;
1022 DWORD count = 0, idx, size = FIELD_OFFSET(ole_priv_data, entries);
1023
1024 for(cf = 0; (cf = EnumClipboardFormats(cf)) != 0; count++)
1025 {
1026 char buf[100];
1027 GetClipboardFormatNameA(cf, buf, sizeof(buf));
1028 TRACE("cf %04x %s\n", cf, buf);
1029 }
1030 TRACE("count %d\n", count);
1031 size += count * sizeof(ret->entries[0]);
1032
1033 /* There are holes in fmtetc so zero init */
1034 ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
1035 if(!ret) return E_OUTOFMEMORY;
1036 ret->size = size;
1037 ret->count = count;
1038
1039 for(cf = 0, idx = 0; (cf = EnumClipboardFormats(cf)) != 0; idx++)
1040 {
1041 ret->entries[idx].fmtetc.cfFormat = cf;
1042 ret->entries[idx].fmtetc.ptd = NULL;
1043 ret->entries[idx].fmtetc.dwAspect = DVASPECT_CONTENT;
1044 ret->entries[idx].fmtetc.lindex = -1;
1045 ret->entries[idx].fmtetc.tymed = get_tymed_from_nonole_cf(cf);
1046 ret->entries[idx].first_use = 1;
1047 }
1048 }
1049
1050 *data = ret;
1051 return hr;
1052 }
1053
1054 /************************************************************************
1055 * get_stgmed_for_global
1056 *
1057 * Returns a stg medium with a copy of the global handle
1058 */
1059 static HRESULT get_stgmed_for_global(HGLOBAL h, STGMEDIUM *med)
1060 {
1061 HRESULT hr;
1062
1063 med->pUnkForRelease = NULL;
1064 med->tymed = TYMED_NULL;
1065
1066 hr = dup_global_mem(h, GMEM_MOVEABLE, &med->u.hGlobal);
1067
1068 if(SUCCEEDED(hr)) med->tymed = TYMED_HGLOBAL;
1069
1070 return hr;
1071 }
1072
1073 /************************************************************************
1074 * get_stgmed_for_stream
1075 *
1076 * Returns a stg medium with a stream based on the handle
1077 */
1078 static HRESULT get_stgmed_for_stream(HGLOBAL h, STGMEDIUM *med)
1079 {
1080 HRESULT hr;
1081 HGLOBAL dst;
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 = CreateStreamOnHGlobal(dst, TRUE, &med->u.pstm);
1090 if(FAILED(hr))
1091 {
1092 GlobalFree(dst);
1093 return hr;
1094 }
1095
1096 med->tymed = TYMED_ISTREAM;
1097 return hr;
1098 }
1099
1100 /************************************************************************
1101 * get_stgmed_for_storage
1102 *
1103 * Returns a stg medium with a storage based on the handle
1104 */
1105 static HRESULT get_stgmed_for_storage(HGLOBAL h, STGMEDIUM *med)
1106 {
1107 HRESULT hr;
1108 HGLOBAL dst;
1109 ILockBytes *lbs;
1110
1111 med->pUnkForRelease = NULL;
1112 med->tymed = TYMED_NULL;
1113
1114 hr = dup_global_mem(h, GMEM_MOVEABLE, &dst);
1115 if(FAILED(hr)) return hr;
1116
1117 hr = CreateILockBytesOnHGlobal(dst, TRUE, &lbs);
1118 if(FAILED(hr))
1119 {
1120 GlobalFree(dst);
1121 return hr;
1122 }
1123
1124 hr = StgOpenStorageOnILockBytes(lbs, NULL, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, NULL, 0, &med->u.pstg);
1125 ILockBytes_Release(lbs);
1126 if(FAILED(hr))
1127 {
1128 GlobalFree(dst);
1129 return hr;
1130 }
1131
1132 med->tymed = TYMED_ISTORAGE;
1133 return hr;
1134 }
1135
1136 /************************************************************************
1137 * get_stgmed_for_emf
1138 *
1139 * Returns a stg medium with an enhanced metafile based on the handle
1140 */
1141 static HRESULT get_stgmed_for_emf(HENHMETAFILE hemf, STGMEDIUM *med)
1142 {
1143 med->pUnkForRelease = NULL;
1144 med->tymed = TYMED_NULL;
1145
1146 med->u.hEnhMetaFile = CopyEnhMetaFileW(hemf, NULL);
1147 if(!med->u.hEnhMetaFile) return E_OUTOFMEMORY;
1148 med->tymed = TYMED_ENHMF;
1149 return S_OK;
1150 }
1151
1152 static inline BOOL string_off_equal(const DVTARGETDEVICE *t1, WORD off1, const DVTARGETDEVICE *t2, WORD off2)
1153 {
1154 const WCHAR *str1, *str2;
1155
1156 if(off1 == 0 && off2 == 0) return TRUE;
1157 if(off1 == 0 || off2 == 0) return FALSE;
1158
1159 str1 = (const WCHAR*)((const char*)t1 + off1);
1160 str2 = (const WCHAR*)((const char*)t2 + off2);
1161
1162 return !lstrcmpW(str1, str2);
1163 }
1164
1165 static inline BOOL td_equal(const DVTARGETDEVICE *t1, const DVTARGETDEVICE *t2)
1166 {
1167 if(t1 == NULL && t2 == NULL) return TRUE;
1168 if(t1 == NULL || t2 == NULL) return FALSE;
1169
1170 if(!string_off_equal(t1, t1->tdDriverNameOffset, t2, t2->tdDriverNameOffset))
1171 return FALSE;
1172 if(!string_off_equal(t1, t1->tdDeviceNameOffset, t2, t2->tdDeviceNameOffset))
1173 return FALSE;
1174 if(!string_off_equal(t1, t1->tdPortNameOffset, t2, t2->tdPortNameOffset))
1175 return FALSE;
1176
1177 /* FIXME check devmode? */
1178
1179 return TRUE;
1180 }
1181
1182 /************************************************************************
1183 * snapshot_GetData
1184 */
1185 static HRESULT WINAPI snapshot_GetData(IDataObject *iface, FORMATETC *fmt,
1186 STGMEDIUM *med)
1187 {
1188 snapshot *This = impl_from_IDataObject(iface);
1189 HANDLE h;
1190 HRESULT hr;
1191 ole_priv_data *enum_data = NULL;
1192 ole_priv_data_entry *entry;
1193 DWORD mask;
1194
1195 TRACE("(%p, %p {%s}, %p)\n", iface, fmt, dump_fmtetc(fmt), med);
1196
1197 if ( !fmt || !med ) return E_INVALIDARG;
1198
1199 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1200
1201 if(!This->data)
1202 hr = get_current_dataobject(&This->data);
1203
1204 if(This->data)
1205 {
1206 hr = IDataObject_GetData(This->data, fmt, med);
1207 CloseClipboard();
1208 return hr;
1209 }
1210
1211 h = GetClipboardData(fmt->cfFormat);
1212 if(!h)
1213 {
1214 hr = DV_E_FORMATETC;
1215 goto end;
1216 }
1217
1218 hr = get_priv_data(&enum_data);
1219 if(FAILED(hr)) goto end;
1220
1221 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1222 if(entry)
1223 {
1224 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1225 {
1226 hr = DV_E_FORMATETC;
1227 goto end;
1228 }
1229 mask = fmt->tymed & entry->fmtetc.tymed;
1230 if(!mask) mask = fmt->tymed & (TYMED_ISTREAM | TYMED_HGLOBAL);
1231 }
1232 else /* non-Ole format */
1233 mask = fmt->tymed & TYMED_HGLOBAL;
1234
1235 if(mask & TYMED_ISTORAGE)
1236 hr = get_stgmed_for_storage(h, med);
1237 else if(mask & TYMED_HGLOBAL)
1238 hr = get_stgmed_for_global(h, med);
1239 else if(mask & TYMED_ISTREAM)
1240 hr = get_stgmed_for_stream(h, med);
1241 else if(mask & TYMED_ENHMF)
1242 hr = get_stgmed_for_emf((HENHMETAFILE)h, med);
1243 else
1244 {
1245 FIXME("Unhandled tymed - mask %x req tymed %x\n", mask, fmt->tymed);
1246 hr = E_FAIL;
1247 goto end;
1248 }
1249
1250 end:
1251 HeapFree(GetProcessHeap(), 0, enum_data);
1252 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1253 return hr;
1254 }
1255
1256 /************************************************************************
1257 * snapshot_GetDataHere
1258 */
1259 static HRESULT WINAPI snapshot_GetDataHere(IDataObject *iface, FORMATETC *fmt,
1260 STGMEDIUM *med)
1261 {
1262 snapshot *This = impl_from_IDataObject(iface);
1263 HANDLE h;
1264 HRESULT hr;
1265 ole_priv_data *enum_data = NULL;
1266 ole_priv_data_entry *entry;
1267 TYMED supported;
1268
1269 TRACE("(%p, %p {%s}, %p (tymed %x)\n", iface, fmt, dump_fmtetc(fmt), med, med->tymed);
1270
1271 if ( !fmt || !med ) return E_INVALIDARG;
1272
1273 if ( !OpenClipboard(NULL)) return CLIPBRD_E_CANT_OPEN;
1274
1275 if(!This->data)
1276 hr = get_current_dataobject(&This->data);
1277
1278 if(This->data)
1279 {
1280 hr = IDataObject_GetDataHere(This->data, fmt, med);
1281 if(SUCCEEDED(hr))
1282 {
1283 CloseClipboard();
1284 return hr;
1285 }
1286 }
1287
1288 h = GetClipboardData(fmt->cfFormat);
1289 if(!h)
1290 {
1291 hr = DV_E_FORMATETC;
1292 goto end;
1293 }
1294
1295 hr = get_priv_data(&enum_data);
1296 if(FAILED(hr)) goto end;
1297
1298 entry = find_format_in_list(enum_data->entries, enum_data->count, fmt->cfFormat);
1299 if(entry)
1300 {
1301 if(!td_equal(fmt->ptd, entry->fmtetc.ptd))
1302 {
1303 hr = DV_E_FORMATETC;
1304 goto end;
1305 }
1306 supported = entry->fmtetc.tymed;
1307 }
1308 else /* non-Ole format */
1309 supported = TYMED_HGLOBAL;
1310
1311 switch(med->tymed)
1312 {
1313 case TYMED_HGLOBAL:
1314 {
1315 DWORD src_size = GlobalSize(h);
1316 DWORD dst_size = GlobalSize(med->u.hGlobal);
1317 hr = E_FAIL;
1318 if(dst_size >= src_size)
1319 {
1320 void *src = GlobalLock(h);
1321 void *dst = GlobalLock(med->u.hGlobal);
1322
1323 memcpy(dst, src, src_size);
1324 GlobalUnlock(med->u.hGlobal);
1325 GlobalUnlock(h);
1326 hr = S_OK;
1327 }
1328 break;
1329 }
1330 case TYMED_ISTREAM:
1331 {
1332 DWORD src_size = GlobalSize(h);
1333 void *src = GlobalLock(h);
1334 hr = IStream_Write(med->u.pstm, src, src_size, NULL);
1335 GlobalUnlock(h);
1336 break;
1337 }
1338 case TYMED_ISTORAGE:
1339 {
1340 STGMEDIUM copy;
1341 if(!(supported & TYMED_ISTORAGE))
1342 {
1343 hr = E_FAIL;
1344 goto end;
1345 }
1346 hr = get_stgmed_for_storage(h, ©);
1347 if(SUCCEEDED(hr))
1348 {
1349 hr = IStorage_CopyTo(copy.u.pstg, 0, NULL, NULL, med->u.pstg);
1350 ReleaseStgMedium(©);
1351 }
1352 break;
1353 }
1354 default:
1355 FIXME("Unhandled tymed - supported %x req tymed %x\n", supported, med->tymed);
1356 hr = E_FAIL;
1357 goto end;
1358 }
1359
1360 end:
1361 HeapFree(GetProcessHeap(), 0, enum_data);
1362 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1363 return hr;
1364 }
1365
1366 /************************************************************************
1367 * snapshot_QueryGetData
1368 *
1369 * The OLE Clipboard's implementation of this method delegates to
1370 * a data source if there is one or wraps around the windows clipboard
1371 * function IsClipboardFormatAvailable() otherwise.
1372 *
1373 */
1374 static HRESULT WINAPI snapshot_QueryGetData(IDataObject *iface, FORMATETC *fmt)
1375 {
1376 FIXME("(%p, %p {%s})\n", iface, fmt, dump_fmtetc(fmt));
1377
1378 if (!fmt) return E_INVALIDARG;
1379
1380 if ( fmt->dwAspect != DVASPECT_CONTENT ) return DV_E_FORMATETC;
1381
1382 if ( fmt->lindex != -1 ) return DV_E_FORMATETC;
1383
1384 return (IsClipboardFormatAvailable(fmt->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1385 }
1386
1387 /************************************************************************
1388 * snapshot_GetCanonicalFormatEtc
1389 */
1390 static HRESULT WINAPI snapshot_GetCanonicalFormatEtc(IDataObject *iface, FORMATETC *fmt_in,
1391 FORMATETC *fmt_out)
1392 {
1393 TRACE("(%p, %p, %p)\n", iface, fmt_in, fmt_out);
1394
1395 if ( !fmt_in || !fmt_out ) return E_INVALIDARG;
1396
1397 *fmt_out = *fmt_in;
1398 return DATA_S_SAMEFORMATETC;
1399 }
1400
1401 /************************************************************************
1402 * snapshot_SetData
1403 *
1404 * The OLE Clipboard does not implement this method
1405 */
1406 static HRESULT WINAPI snapshot_SetData(IDataObject *iface, FORMATETC *fmt,
1407 STGMEDIUM *med, BOOL release)
1408 {
1409 TRACE("(%p, %p, %p, %d): not implemented\n", iface, fmt, med, release);
1410 return E_NOTIMPL;
1411 }
1412
1413 /************************************************************************
1414 * snapshot_EnumFormatEtc
1415 *
1416 */
1417 static HRESULT WINAPI snapshot_EnumFormatEtc(IDataObject *iface, DWORD dir,
1418 IEnumFORMATETC **enum_fmt)
1419 {
1420 HRESULT hr;
1421 ole_priv_data *data = NULL;
1422
1423 TRACE("(%p, %x, %p)\n", iface, dir, enum_fmt);
1424
1425 *enum_fmt = NULL;
1426
1427 if ( dir != DATADIR_GET ) return E_NOTIMPL;
1428 if ( !OpenClipboard(NULL) ) return CLIPBRD_E_CANT_OPEN;
1429
1430 hr = get_priv_data(&data);
1431
1432 if(FAILED(hr)) goto end;
1433
1434 hr = enum_fmtetc_construct( data, 0, enum_fmt );
1435
1436 end:
1437 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1438 return hr;
1439 }
1440
1441 /************************************************************************
1442 * snapshot_DAdvise
1443 *
1444 * The OLE Clipboard does not implement this method
1445 */
1446 static HRESULT WINAPI snapshot_DAdvise(IDataObject *iface, FORMATETC *fmt,
1447 DWORD flags, IAdviseSink *sink,
1448 DWORD *conn)
1449 {
1450 TRACE("(%p, %p, %x, %p, %p): not implemented\n", iface, fmt, flags, sink, conn);
1451 return E_NOTIMPL;
1452 }
1453
1454 /************************************************************************
1455 * snapshot_DUnadvise
1456 *
1457 * The OLE Clipboard does not implement this method
1458 */
1459 static HRESULT WINAPI snapshot_DUnadvise(IDataObject* iface, DWORD conn)
1460 {
1461 TRACE("(%p, %d): not implemented\n", iface, conn);
1462 return E_NOTIMPL;
1463 }
1464
1465 /************************************************************************
1466 * snapshot_EnumDAdvise
1467 *
1468 * The OLE Clipboard does not implement this method
1469 */
1470 static HRESULT WINAPI snapshot_EnumDAdvise(IDataObject* iface,
1471 IEnumSTATDATA** enum_advise)
1472 {
1473 TRACE("(%p, %p): not implemented\n", iface, enum_advise);
1474 return E_NOTIMPL;
1475 }
1476
1477 static const IDataObjectVtbl snapshot_vtable =
1478 {
1479 snapshot_QueryInterface,
1480 snapshot_AddRef,
1481 snapshot_Release,
1482 snapshot_GetData,
1483 snapshot_GetDataHere,
1484 snapshot_QueryGetData,
1485 snapshot_GetCanonicalFormatEtc,
1486 snapshot_SetData,
1487 snapshot_EnumFormatEtc,
1488 snapshot_DAdvise,
1489 snapshot_DUnadvise,
1490 snapshot_EnumDAdvise
1491 };
1492
1493 /*---------------------------------------------------------------------*
1494 * Internal implementation methods for the OLE clipboard
1495 *---------------------------------------------------------------------*/
1496
1497 static snapshot *snapshot_construct(DWORD seq_no)
1498 {
1499 snapshot *This;
1500
1501 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1502 if (!This) return NULL;
1503
1504 This->lpVtbl = &snapshot_vtable;
1505 This->ref = 0;
1506 This->seq_no = seq_no;
1507 This->data = NULL;
1508
1509 return This;
1510 }
1511
1512 /*********************************************************
1513 * register_clipboard_formats
1514 */
1515 static void register_clipboard_formats(void)
1516 {
1517 static const WCHAR OwnerLink[] = {'O','w','n','e','r','L','i','n','k',0};
1518 static const WCHAR FileName[] = {'F','i','l','e','N','a','m','e',0};
1519 static const WCHAR FileNameW[] = {'F','i','l','e','N','a','m','e','W',0};
1520 static const WCHAR DataObject[] = {'D','a','t','a','O','b','j','e','c','t',0};
1521 static const WCHAR EmbeddedObject[] = {'E','m','b','e','d','d','e','d',' ','O','b','j','e','c','t',0};
1522 static const WCHAR EmbedSource[] = {'E','m','b','e','d',' ','S','o','u','r','c','e',0};
1523 static const WCHAR CustomLinkSource[] = {'C','u','s','t','o','m',' ','L','i','n','k',' ','S','o','u','r','c','e',0};
1524 static const WCHAR LinkSource[] = {'L','i','n','k',' ','S','o','u','r','c','e',0};
1525 static const WCHAR ObjectDescriptor[] = {'O','b','j','e','c','t',' ','D','e','s','c','r','i','p','t','o','r',0};
1526 static const WCHAR LinkSourceDescriptor[] = {'L','i','n','k',' ','S','o','u','r','c','e',' ',
1527 'D','e','s','c','r','i','p','t','o','r',0};
1528 static const WCHAR OlePrivateData[] = {'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0};
1529
1530 static const WCHAR WineMarshalledDataObject[] = {'W','i','n','e',' ','M','a','r','s','h','a','l','l','e','d',' ',
1531 'D','a','t','a','O','b','j','e','c','t',0};
1532
1533 ownerlink_clipboard_format = RegisterClipboardFormatW(OwnerLink);
1534 filename_clipboard_format = RegisterClipboardFormatW(FileName);
1535 filenameW_clipboard_format = RegisterClipboardFormatW(FileNameW);
1536 dataobject_clipboard_format = RegisterClipboardFormatW(DataObject);
1537 embedded_object_clipboard_format = RegisterClipboardFormatW(EmbeddedObject);
1538 embed_source_clipboard_format = RegisterClipboardFormatW(EmbedSource);
1539 custom_link_source_clipboard_format = RegisterClipboardFormatW(CustomLinkSource);
1540 link_source_clipboard_format = RegisterClipboardFormatW(LinkSource);
1541 object_descriptor_clipboard_format = RegisterClipboardFormatW(ObjectDescriptor);
1542 link_source_descriptor_clipboard_format = RegisterClipboardFormatW(LinkSourceDescriptor);
1543 ole_private_data_clipboard_format = RegisterClipboardFormatW(OlePrivateData);
1544
1545 wine_marshal_clipboard_format = RegisterClipboardFormatW(WineMarshalledDataObject);
1546 }
1547
1548 /***********************************************************************
1549 * OLEClipbrd_Initialize()
1550 * Initializes the OLE clipboard.
1551 */
1552 void OLEClipbrd_Initialize(void)
1553 {
1554 register_clipboard_formats();
1555
1556 if ( !theOleClipboard )
1557 {
1558 ole_clipbrd* clipbrd;
1559 HGLOBAL h;
1560
1561 TRACE("()\n");
1562
1563 clipbrd = HeapAlloc( GetProcessHeap(), 0, sizeof(*clipbrd) );
1564 if (!clipbrd) return;
1565
1566 clipbrd->latest_snapshot = NULL;
1567 clipbrd->window = NULL;
1568 clipbrd->src_data = NULL;
1569 clipbrd->cached_enum = NULL;
1570
1571 h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 0);
1572 if(!h)
1573 {
1574 HeapFree(GetProcessHeap(), 0, clipbrd);
1575 return;
1576 }
1577
1578 if(FAILED(CreateStreamOnHGlobal(h, TRUE, &clipbrd->marshal_data)))
1579 {
1580 GlobalFree(h);
1581 HeapFree(GetProcessHeap(), 0, clipbrd);
1582 return;
1583 }
1584
1585 theOleClipboard = clipbrd;
1586 }
1587 }
1588
1589 /***********************************************************************
1590 * OLEClipbrd_UnInitialize()
1591 * Un-Initializes the OLE clipboard
1592 */
1593 void OLEClipbrd_UnInitialize(void)
1594 {
1595 ole_clipbrd *clipbrd = theOleClipboard;
1596
1597 TRACE("()\n");
1598
1599 if ( clipbrd )
1600 {
1601 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1602 HINSTANCE hinst = GetModuleHandleW(ole32W);
1603
1604 if ( clipbrd->window )
1605 {
1606 DestroyWindow(clipbrd->window);
1607 UnregisterClassW( clipbrd_wndclass, hinst );
1608 }
1609
1610 IStream_Release(clipbrd->marshal_data);
1611 HeapFree(GetProcessHeap(), 0, clipbrd);
1612 theOleClipboard = NULL;
1613 }
1614 }
1615
1616 /*********************************************************************
1617 * set_clipboard_formats
1618 *
1619 * Enumerate all formats supported by the source and make
1620 * those formats available using delayed rendering using SetClipboardData.
1621 * Cache the enumeration list and make that list visibile as the
1622 * 'Ole Private Data' format on the clipboard.
1623 *
1624 */
1625 static HRESULT set_clipboard_formats(ole_clipbrd *clipbrd, IDataObject *data)
1626 {
1627 HRESULT hr;
1628 FORMATETC fmt;
1629 IEnumFORMATETC *enum_fmt;
1630 HGLOBAL priv_data_handle;
1631 DWORD_PTR target_offset;
1632 ole_priv_data *priv_data;
1633 DWORD count = 0, needed = sizeof(*priv_data), idx;
1634
1635 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1636 if(FAILED(hr)) return hr;
1637
1638 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1639 {
1640 count++;
1641 needed += sizeof(priv_data->entries[0]);
1642 if(fmt.ptd)
1643 {
1644 needed += fmt.ptd->tdSize;
1645 CoTaskMemFree(fmt.ptd);
1646 }
1647 }
1648
1649 /* Windows pads the list with two empty ole_priv_data_entries, one
1650 * after the entries array and one after the target device data.
1651 * Allocating with zero init to zero these pads. */
1652
1653 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1654 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1655 priv_data = GlobalLock(priv_data_handle);
1656
1657 priv_data->unk1 = 0;
1658 priv_data->size = needed;
1659 priv_data->unk2 = 1;
1660 priv_data->count = count;
1661 priv_data->unk3[0] = 0;
1662 priv_data->unk3[1] = 0;
1663
1664 IEnumFORMATETC_Reset(enum_fmt);
1665
1666 idx = 0;
1667 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1668
1669 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1670 {
1671 TRACE("%s\n", dump_fmtetc(&fmt));
1672
1673 priv_data->entries[idx].fmtetc = fmt;
1674 if(fmt.ptd)
1675 {
1676 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1677 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1678 target_offset += fmt.ptd->tdSize;
1679 CoTaskMemFree(fmt.ptd);
1680 }
1681
1682 priv_data->entries[idx].first_use = !find_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1683 priv_data->entries[idx].unk[0] = 0;
1684 priv_data->entries[idx].unk[1] = 0;
1685
1686 if (priv_data->entries[idx].first_use)
1687 SetClipboardData(fmt.cfFormat, NULL);
1688
1689 idx++;
1690 }
1691
1692 IEnumFORMATETC_Release(enum_fmt);
1693
1694 /* Cache the list and fixup any target device offsets to ptrs */
1695 clipbrd->cached_enum = HeapAlloc(GetProcessHeap(), 0, needed);
1696 memcpy(clipbrd->cached_enum, priv_data, needed);
1697 for(idx = 0; idx < clipbrd->cached_enum->count; idx++)
1698 clipbrd->cached_enum->entries[idx].fmtetc.ptd =
1699 td_offs_to_ptr(clipbrd->cached_enum, (DWORD_PTR)clipbrd->cached_enum->entries[idx].fmtetc.ptd);
1700
1701 GlobalUnlock(priv_data_handle);
1702 SetClipboardData(ole_private_data_clipboard_format, priv_data_handle);
1703
1704 return S_OK;
1705 }
1706
1707 static HWND create_clipbrd_window(void);
1708
1709 /***********************************************************************
1710 * get_clipbrd_window
1711 */
1712 static inline HRESULT get_clipbrd_window(ole_clipbrd *clipbrd, HWND *wnd)
1713 {
1714 if ( !clipbrd->window )
1715 clipbrd->window = create_clipbrd_window();
1716
1717 *wnd = clipbrd->window;
1718 return *wnd ? S_OK : E_FAIL;
1719 }
1720
1721
1722 /**********************************************************************
1723 * release_marshal_data
1724 *
1725 * Releases the data and sets the stream back to zero size.
1726 */
1727 static inline void release_marshal_data(IStream *stm)
1728 {
1729 LARGE_INTEGER pos;
1730 ULARGE_INTEGER size;
1731 pos.QuadPart = size.QuadPart = 0;
1732
1733 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1734 CoReleaseMarshalData(stm);
1735 IStream_Seek(stm, pos, STREAM_SEEK_SET, NULL);
1736 IStream_SetSize(stm, size);
1737 }
1738
1739 /***********************************************************************
1740 * expose_marshalled_dataobject
1741 *
1742 * Sets the marshalled dataobject to the clipboard. In the flushed case
1743 * we set a zero sized HGLOBAL to clear the old marshalled data.
1744 */
1745 static HRESULT expose_marshalled_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1746 {
1747 HGLOBAL h;
1748
1749 if(data)
1750 {
1751 HGLOBAL h_stm;
1752 GetHGlobalFromStream(clipbrd->marshal_data, &h_stm);
1753 dup_global_mem(h_stm, GMEM_DDESHARE|GMEM_MOVEABLE, &h);
1754 }
1755 else /* flushed */
1756 h = GlobalAlloc(GMEM_DDESHARE|GMEM_MOVEABLE, 0);
1757
1758 if(!h) return E_OUTOFMEMORY;
1759
1760 SetClipboardData(wine_marshal_clipboard_format, h);
1761 return S_OK;
1762 }
1763
1764 /***********************************************************************
1765 * set_src_dataobject
1766 *
1767 * Clears and sets the clipboard's src IDataObject.
1768 *
1769 * To marshal the source dataobject we do something rather different from Windows.
1770 * We set a clipboard format which contains the marshalled data.
1771 * Windows sets two window props one of which is an IID, the other is an endpoint number.
1772 */
1773 static HRESULT set_src_dataobject(ole_clipbrd *clipbrd, IDataObject *data)
1774 {
1775 HRESULT hr;
1776 HWND wnd;
1777
1778 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1779
1780 if(clipbrd->src_data)
1781 {
1782 release_marshal_data(clipbrd->marshal_data);
1783
1784 IDataObject_Release(clipbrd->src_data);
1785 clipbrd->src_data = NULL;
1786 HeapFree(GetProcessHeap(), 0, clipbrd->cached_enum);
1787 clipbrd->cached_enum = NULL;
1788 }
1789
1790 if(data)
1791 {
1792 IUnknown *unk;
1793
1794 IDataObject_AddRef(data);
1795 clipbrd->src_data = data;
1796
1797 IDataObject_QueryInterface(data, &IID_IUnknown, (void**)&unk);
1798 hr = CoMarshalInterface(clipbrd->marshal_data, &IID_IDataObject, unk,
1799 MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG);
1800 IUnknown_Release(unk); /* Don't hold a ref on IUnknown, we have one on IDataObject. */
1801 if(FAILED(hr)) return hr;
1802 hr = set_clipboard_formats(clipbrd, data);
1803 }
1804 return hr;
1805 }
1806
1807 /***********************************************************************
1808 * clipbrd_wndproc
1809 */
1810 static LRESULT CALLBACK clipbrd_wndproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
1811 {
1812 ole_clipbrd *clipbrd;
1813
1814 get_ole_clipbrd(&clipbrd);
1815
1816 switch (message)
1817 {
1818 case WM_RENDERFORMAT:
1819 {
1820 UINT cf = wparam;
1821 ole_priv_data_entry *entry;
1822
1823 TRACE("(): WM_RENDERFORMAT(cfFormat=%x)\n", cf);
1824 entry = find_format_in_list(clipbrd->cached_enum->entries, clipbrd->cached_enum->count, cf);
1825
1826 if(entry)
1827 render_format(clipbrd->src_data, &entry->fmtetc);
1828
1829 break;
1830 }
1831
1832 case WM_RENDERALLFORMATS:
1833 {
1834 DWORD i;
1835 ole_priv_data_entry *entries = clipbrd->cached_enum->entries;
1836
1837 TRACE("(): WM_RENDERALLFORMATS\n");
1838
1839 for(i = 0; i < clipbrd->cached_enum->count; i++)
1840 {
1841 if(entries[i].first_use)
1842 render_format(clipbrd->src_data, &entries[i].fmtetc);
1843 }
1844 break;
1845 }
1846
1847 case WM_DESTROYCLIPBOARD:
1848 {
1849 TRACE("(): WM_DESTROYCLIPBOARD\n");
1850
1851 set_src_dataobject(clipbrd, NULL);
1852 break;
1853 }
1854
1855 default:
1856 return DefWindowProcW(hwnd, message, wparam, lparam);
1857 }
1858
1859 return 0;
1860 }
1861
1862
1863 /***********************************************************************
1864 * create_clipbrd_window
1865 */
1866 static HWND create_clipbrd_window(void)
1867 {
1868 WNDCLASSEXW class;
1869 static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1870 static const WCHAR title[] = {'C','l','i','p','b','o','a','r','d','W','i','n','d','o','w',0};
1871 HINSTANCE hinst = GetModuleHandleW(ole32W);
1872
1873 class.cbSize = sizeof(class);
1874 class.style = 0;
1875 class.lpfnWndProc = clipbrd_wndproc;
1876 class.cbClsExtra = 0;
1877 class.cbWndExtra = 0;
1878 class.hInstance = hinst;
1879 class.hIcon = 0;
1880 class.hCursor = 0;
1881 class.hbrBackground = 0;
1882 class.lpszMenuName = NULL;
1883 class.lpszClassName = clipbrd_wndclass;
1884 class.hIconSm = NULL;
1885
1886 RegisterClassExW(&class);
1887
1888 return CreateWindowW(clipbrd_wndclass, title, WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1889 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1890 NULL, NULL, hinst, 0);
1891 }
1892
1893 /*********************************************************************
1894 * set_dataobject_format
1895 *
1896 * Windows creates a 'DataObject' clipboard format that contains the
1897 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1898 */
1899 static HRESULT set_dataobject_format(HWND hwnd)
1900 {
1901 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1902 HWND *data;
1903
1904 if(!h) return E_OUTOFMEMORY;
1905
1906 data = GlobalLock(h);
1907 *data = hwnd;
1908 GlobalUnlock(h);
1909
1910 if(!SetClipboardData(dataobject_clipboard_format, h))
1911 {
1912 GlobalFree(h);
1913 return CLIPBRD_E_CANT_SET;
1914 }
1915
1916 return S_OK;
1917 }
1918
1919 /*---------------------------------------------------------------------*
1920 * Win32 OLE clipboard API
1921 *---------------------------------------------------------------------*/
1922
1923 /***********************************************************************
1924 * OleSetClipboard [OLE32.@]
1925 * Places a pointer to the specified data object onto the clipboard,
1926 * making the data object accessible to the OleGetClipboard function.
1927 *
1928 * RETURNS
1929 *
1930 * S_OK IDataObject pointer placed on the clipboard
1931 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1932 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1933 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1934 * CLIPBRD_E_CANT_SET SetClipboard failed
1935 */
1936
1937 HRESULT WINAPI OleSetClipboard(IDataObject* data)
1938 {
1939 HRESULT hr;
1940 ole_clipbrd *clipbrd;
1941 HWND wnd;
1942
1943 TRACE("(%p)\n", data);
1944
1945 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1946
1947 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
1948
1949 if ( !OpenClipboard(wnd) ) return CLIPBRD_E_CANT_OPEN;
1950
1951 if ( !EmptyClipboard() )
1952 {
1953 hr = CLIPBRD_E_CANT_EMPTY;
1954 goto end;
1955 }
1956
1957 hr = set_src_dataobject(clipbrd, data);
1958 if(FAILED(hr)) goto end;
1959
1960 if(data)
1961 {
1962 hr = expose_marshalled_dataobject(clipbrd, data);
1963 if(FAILED(hr)) goto end;
1964 hr = set_dataobject_format(wnd);
1965 }
1966
1967 end:
1968
1969 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
1970
1971 if ( FAILED(hr) )
1972 {
1973 expose_marshalled_dataobject(clipbrd, NULL);
1974 set_src_dataobject(clipbrd, NULL);
1975 }
1976
1977 return hr;
1978 }
1979
1980
1981 /***********************************************************************
1982 * OleGetClipboard [OLE32.@]
1983 * Returns a pointer to our internal IDataObject which represents the conceptual
1984 * state of the Windows clipboard. If the current clipboard already contains
1985 * an IDataObject, our internal IDataObject will delegate to this object.
1986 */
1987 HRESULT WINAPI OleGetClipboard(IDataObject **obj)
1988 {
1989 HRESULT hr;
1990 ole_clipbrd *clipbrd;
1991 DWORD seq_no;
1992
1993 TRACE("(%p)\n", obj);
1994
1995 if(!obj) return E_INVALIDARG;
1996
1997 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
1998
1999 seq_no = GetClipboardSequenceNumber();
2000 if(clipbrd->latest_snapshot && clipbrd->latest_snapshot->seq_no != seq_no)
2001 clipbrd->latest_snapshot = NULL;
2002
2003 if(!clipbrd->latest_snapshot)
2004 {
2005 clipbrd->latest_snapshot = snapshot_construct(seq_no);
2006 if(!clipbrd->latest_snapshot) return E_OUTOFMEMORY;
2007 }
2008
2009 *obj = (IDataObject*)&clipbrd->latest_snapshot->lpVtbl;
2010 IDataObject_AddRef(*obj);
2011
2012 return S_OK;
2013 }
2014
2015 /******************************************************************************
2016 * OleFlushClipboard [OLE32.@]
2017 * Renders the data from the source IDataObject into the windows clipboard
2018 *
2019 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
2020 * by copying the storage into global memory. Subsequently the default
2021 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
2022 * back to TYMED_IStorage.
2023 */
2024 HRESULT WINAPI OleFlushClipboard(void)
2025 {
2026 HRESULT hr;
2027 ole_clipbrd *clipbrd;
2028 HWND wnd;
2029
2030 TRACE("()\n");
2031
2032 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2033
2034 if(FAILED(hr = get_clipbrd_window(clipbrd, &wnd))) return hr;
2035
2036 /*
2037 * Already flushed or no source DataObject? Nothing to do.
2038 */
2039 if (!clipbrd->src_data) return S_OK;
2040
2041 if (!OpenClipboard(wnd)) return CLIPBRD_E_CANT_OPEN;
2042
2043 SendMessageW(wnd, WM_RENDERALLFORMATS, 0, 0);
2044
2045 hr = set_dataobject_format(NULL);
2046
2047 expose_marshalled_dataobject(clipbrd, NULL);
2048 set_src_dataobject(clipbrd, NULL);
2049
2050 if ( !CloseClipboard() ) hr = CLIPBRD_E_CANT_CLOSE;
2051
2052 return hr;
2053 }
2054
2055
2056 /***********************************************************************
2057 * OleIsCurrentClipboard [OLE32.@]
2058 */
2059 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *data)
2060 {
2061 HRESULT hr;
2062 ole_clipbrd *clipbrd;
2063 TRACE("()\n");
2064
2065 if(FAILED(hr = get_ole_clipbrd(&clipbrd))) return hr;
2066
2067 if (data == NULL) return S_FALSE;
2068
2069 return (data == clipbrd->src_data) ? S_OK : S_FALSE;
2070 }
2071
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.