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