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