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