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