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