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