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