1 /*
2 * OLE 2 clipboard support
3 *
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * NOTES:
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
29 *
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
36 *
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
39 *
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
43 *
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
45 *
46 * TODO:
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
58 *
59 */
60
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64
65 #define COBJMACROS
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "winnls.h"
75 #include "ole2.h"
76 #include "wine/debug.h"
77 #include "olestd.h"
78
79 #include "storage32.h"
80
81 #include "compobj_private.h"
82
83 WINE_DEFAULT_DEBUG_CHANNEL(ole);
84
85 #define HANDLE_ERROR(err) do { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; } while (0)
86
87
88 /****************************************************************************
89 * ole_clipbrd
90 */
91 struct ole_clipbrd
92 {
93 const IDataObjectVtbl* lpvtbl; /* Exposed IDataObject vtable */
94
95 LONG ref;
96
97 HWND hWndClipboard; /* Hidden clipboard window */
98 IDataObject* pIDataObjectSrc; /* Source object passed to OleSetClipboard */
99 };
100
101 typedef struct ole_clipbrd ole_clipbrd;
102
103 static inline ole_clipbrd *impl_from_IDataObject(IDataObject *iface)
104 {
105 return (ole_clipbrd*)((char*)iface - FIELD_OFFSET(ole_clipbrd, lpvtbl));
106 }
107
108 /****************************************************************************
109 * IEnumFORMATETC implementation
110 * DO NOT add any members before the VTables declaration!
111 */
112 typedef struct
113 {
114 /* IEnumFORMATETC VTable */
115 const IEnumFORMATETCVtbl *lpVtbl;
116
117 /* IEnumFORMATETC fields */
118 UINT posFmt; /* current enumerator position */
119 UINT countFmt; /* number of EnumFORMATETC's in array */
120 LPFORMATETC pFmt; /* array of EnumFORMATETC's */
121
122 /*
123 * Reference count of this object
124 */
125 LONG ref;
126
127 /*
128 * IUnknown implementation of the parent data object.
129 */
130 IUnknown* pUnkDataObj;
131
132 } IEnumFORMATETCImpl;
133
134 typedef struct PresentationDataHeader
135 {
136 BYTE unknown1[28];
137 DWORD dwObjectExtentX;
138 DWORD dwObjectExtentY;
139 DWORD dwSize;
140 } PresentationDataHeader;
141
142 /*
143 * The one and only ole_clipbrd object which is created by OLEClipbrd_Initialize()
144 */
145 static ole_clipbrd* theOleClipboard;
146
147
148 /*
149 * Name of our registered OLE clipboard window class
150 */
151 static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
152
153 static UINT dataobject_clipboard_format;
154 static UINT ole_priv_data_clipboard_format;
155
156 /* Structure of 'Ole Private Data' clipboard format */
157 typedef struct
158 {
159 FORMATETC fmtetc;
160 DWORD first_use; /* Has this cf been added to the list already */
161 DWORD unk[2];
162 } ole_priv_data_entry;
163
164 typedef struct
165 {
166 DWORD unk1;
167 DWORD size; /* in bytes of the entire structure */
168 DWORD unk2;
169 DWORD count; /* no. of format entries */
170 DWORD unk3[2];
171 ole_priv_data_entry entries[1]; /* array of size count */
172 /* then follows any DVTARGETDEVICE structures referenced in the FORMATETCs */
173 } ole_priv_data;
174
175 /*---------------------------------------------------------------------*
176 * Implementation of the internal IEnumFORMATETC interface returned by
177 * the OLE clipboard's IDataObject.
178 *---------------------------------------------------------------------*/
179
180 /************************************************************************
181 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
182 *
183 * See Windows documentation for more details on IUnknown methods.
184 */
185 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
186 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
187 {
188 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
189
190 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
191
192 /*
193 * Since enumerators are separate objects from the parent data object
194 * we only need to support the IUnknown and IEnumFORMATETC interfaces
195 */
196
197 *ppvObj = NULL;
198
199 if(IsEqualIID(riid, &IID_IUnknown) ||
200 IsEqualIID(riid, &IID_IEnumFORMATETC))
201 {
202 *ppvObj = This;
203 }
204
205 if(*ppvObj)
206 {
207 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
208 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
209 return S_OK;
210 }
211
212 TRACE("-- Interface: E_NOINTERFACE\n");
213 return E_NOINTERFACE;
214 }
215
216 /************************************************************************
217 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
218 *
219 * Since enumerating formats only makes sense when our data object is around,
220 * we insure that it stays as long as we stay by calling our parents IUnknown
221 * for AddRef and Release. But since we are not controlled by the lifetime of
222 * the outer object, we still keep our own reference count in order to
223 * free ourselves.
224 */
225 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
226 {
227 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
228 TRACE("(%p)->(count=%u)\n",This, This->ref);
229
230 if (This->pUnkDataObj)
231 IUnknown_AddRef(This->pUnkDataObj);
232
233 return InterlockedIncrement(&This->ref);
234 }
235
236 /************************************************************************
237 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
238 *
239 * See Windows documentation for more details on IUnknown methods.
240 */
241 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
242 {
243 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
244 ULONG ref;
245
246 TRACE("(%p)->(count=%u)\n",This, This->ref);
247
248 if (This->pUnkDataObj)
249 IUnknown_Release(This->pUnkDataObj); /* Release parent data object */
250
251 ref = InterlockedDecrement(&This->ref);
252 if (!ref)
253 {
254 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
255 HeapFree(GetProcessHeap(), 0, This->pFmt);
256 HeapFree(GetProcessHeap(),0,This);
257 }
258 return ref;
259 }
260
261 /************************************************************************
262 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
263 *
264 * Standard enumerator members for IEnumFORMATETC
265 */
266 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
267 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
268 {
269 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
270 UINT cfetch;
271 HRESULT hres = S_FALSE;
272
273 TRACE("(%p)->(pos=%u)\n", This, This->posFmt);
274
275 if (This->posFmt < This->countFmt)
276 {
277 cfetch = This->countFmt - This->posFmt;
278 if (cfetch >= celt)
279 {
280 cfetch = celt;
281 hres = S_OK;
282 }
283
284 memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
285 This->posFmt += cfetch;
286 }
287 else
288 {
289 cfetch = 0;
290 }
291
292 if (pceltFethed)
293 {
294 *pceltFethed = cfetch;
295 }
296
297 return hres;
298 }
299
300 /************************************************************************
301 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
302 *
303 * Standard enumerator members for IEnumFORMATETC
304 */
305 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
306 {
307 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
308 TRACE("(%p)->(num=%u)\n", This, celt);
309
310 This->posFmt += celt;
311 if (This->posFmt > This->countFmt)
312 {
313 This->posFmt = This->countFmt;
314 return S_FALSE;
315 }
316 return S_OK;
317 }
318
319 /************************************************************************
320 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
321 *
322 * Standard enumerator members for IEnumFORMATETC
323 */
324 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
325 {
326 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
327 TRACE("(%p)->()\n", This);
328
329 This->posFmt = 0;
330 return S_OK;
331 }
332
333 static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
334 LPUNKNOWN pUnkDataObj);
335
336 /************************************************************************
337 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
338 *
339 * Standard enumerator members for IEnumFORMATETC
340 */
341 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
342 (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
343 {
344 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
345 HRESULT hr = S_OK;
346
347 TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
348
349 if ( !ppenum )
350 return E_INVALIDARG;
351
352 *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,
353 This->pFmt,
354 This->pUnkDataObj);
355
356 if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))
357 return ( hr );
358
359 return (*ppenum) ? S_OK : E_OUTOFMEMORY;
360 }
361
362 static const IEnumFORMATETCVtbl efvt =
363 {
364 OLEClipbrd_IEnumFORMATETC_QueryInterface,
365 OLEClipbrd_IEnumFORMATETC_AddRef,
366 OLEClipbrd_IEnumFORMATETC_Release,
367 OLEClipbrd_IEnumFORMATETC_Next,
368 OLEClipbrd_IEnumFORMATETC_Skip,
369 OLEClipbrd_IEnumFORMATETC_Reset,
370 OLEClipbrd_IEnumFORMATETC_Clone
371 };
372
373 /************************************************************************
374 * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)
375 *
376 * Creates an IEnumFORMATETC enumerator from an array of FORMATETC
377 * Structures. pUnkOuter is the outer unknown for reference counting only.
378 * NOTE: this does not AddRef the interface.
379 */
380
381 static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
382 LPUNKNOWN pUnkDataObj)
383 {
384 IEnumFORMATETCImpl* ef;
385 DWORD size=cfmt * sizeof(FORMATETC);
386
387 ef = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumFORMATETCImpl));
388 if (!ef)
389 return NULL;
390
391 ef->ref = 0;
392 ef->lpVtbl = &efvt;
393 ef->pUnkDataObj = pUnkDataObj;
394
395 ef->posFmt = 0;
396 ef->countFmt = cfmt;
397 ef->pFmt = HeapAlloc(GetProcessHeap(), 0, size);
398 if (ef->pFmt)
399 memcpy(ef->pFmt, afmt, size);
400 else
401 {
402 HeapFree(GetProcessHeap(), 0, ef);
403 return NULL;
404 }
405
406 TRACE("(%p)->()\n",ef);
407 return (LPENUMFORMATETC)ef;
408 }
409
410 /***********************************************************************
411 * OLEClipbrd_GlobalDupMem( HGLOBAL )
412 * Helper method to duplicate an HGLOBAL chunk of memory
413 */
414 static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )
415 {
416 HGLOBAL hGlobalDest;
417 PVOID pGlobalSrc, pGlobalDest;
418 DWORD cBytes;
419
420 if ( !hGlobalSrc )
421 return 0;
422
423 cBytes = GlobalSize(hGlobalSrc);
424 if ( 0 == cBytes )
425 return 0;
426
427 hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,
428 cBytes );
429 if ( !hGlobalDest )
430 return 0;
431
432 pGlobalSrc = GlobalLock(hGlobalSrc);
433 pGlobalDest = GlobalLock(hGlobalDest);
434 if ( !pGlobalSrc || !pGlobalDest )
435 {
436 GlobalFree(hGlobalDest);
437 return 0;
438 }
439
440 memcpy(pGlobalDest, pGlobalSrc, cBytes);
441
442 GlobalUnlock(hGlobalSrc);
443 GlobalUnlock(hGlobalDest);
444
445 return hGlobalDest;
446 }
447
448 #define MAX_CLIPFORMAT_NAME 80
449
450 /***********************************************************************
451 * OLEClipbrd_RenderFormat(LPFORMATETC)
452 * Render the clipboard data. Note that this call will delegate to the
453 * source data object.
454 * Note: This function assumes it is passed an HGLOBAL format to render.
455 */
456 static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc)
457 {
458 STGMEDIUM std;
459 HGLOBAL hDup;
460 HRESULT hr = S_OK;
461 char szFmtName[MAX_CLIPFORMAT_NAME];
462 ILockBytes *ptrILockBytes = 0;
463 HGLOBAL hStorage = 0;
464
465 if (!GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME))
466 szFmtName[0] = '\0';
467
468 /* If embed source */
469 if (!strcmp(szFmtName, CF_EMBEDSOURCE))
470 {
471 memset(&std, 0, sizeof(STGMEDIUM));
472 std.tymed = pFormatetc->tymed = TYMED_ISTORAGE;
473
474 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
475 if (hStorage == NULL)
476 HANDLE_ERROR( E_OUTOFMEMORY );
477 hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes);
478 hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg);
479
480 if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std)))
481 {
482 WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%x)\n", hr);
483 GlobalFree(hStorage);
484 return hr;
485 }
486
487 if (1) /* check whether the presentation data is already -not- present */
488 {
489 FORMATETC fmt2;
490 STGMEDIUM std2;
491 METAFILEPICT *mfp = 0;
492
493 fmt2.cfFormat = CF_METAFILEPICT;
494 fmt2.ptd = 0;
495 fmt2.dwAspect = DVASPECT_CONTENT;
496 fmt2.lindex = -1;
497 fmt2.tymed = TYMED_MFPICT;
498
499 memset(&std2, 0, sizeof(STGMEDIUM));
500 std2.tymed = TYMED_MFPICT;
501
502 /* Get the metafile picture out of it */
503
504 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
505 {
506 mfp = GlobalLock(std2.u.hGlobal);
507 }
508
509 if (mfp)
510 {
511 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '', '', '', 0};
512 IStream *pStream = 0;
513 void *mfBits;
514 PresentationDataHeader pdh;
515 INT nSize;
516 CLSID clsID;
517 LPOLESTR strProgID;
518 CHAR strOleTypeName[51];
519 BYTE OlePresStreamHeader [] =
520 {
521 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
522 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
523 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
524 0x00, 0x00, 0x00, 0x00
525 };
526
527 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
528
529 memset(&pdh, 0, sizeof(PresentationDataHeader));
530 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
531
532 pdh.dwObjectExtentX = mfp->xExt;
533 pdh.dwObjectExtentY = mfp->yExt;
534 pdh.dwSize = nSize;
535
536 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
537
538 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
539
540 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
541 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
542
543 hr = IStream_Write(pStream, mfBits, nSize, NULL);
544
545 IStream_Release(pStream);
546
547 HeapFree(GetProcessHeap(), 0, mfBits);
548
549 GlobalUnlock(std2.u.hGlobal);
550
551 ReadClassStg(std.u.pstg, &clsID);
552 ProgIDFromCLSID(&clsID, &strProgID);
553
554 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
555 OLECONVERT_CreateOleStream(std.u.pstg);
556 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
557 }
558 }
559 }
560 else
561 {
562 if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std)))
563 {
564 WARN("() : IDataObject_GetData failed to render clipboard data! (%x)\n", hr);
565 GlobalFree(hStorage);
566 return hr;
567 }
568
569 /* To put a copy back on the clipboard */
570
571 hStorage = std.u.hGlobal;
572 }
573
574 /*
575 * Put a copy of the rendered data back on the clipboard
576 */
577
578 if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) )
579 HANDLE_ERROR( E_OUTOFMEMORY );
580
581 if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )
582 {
583 GlobalFree(hDup);
584 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
585 }
586
587 CLEANUP:
588
589 ReleaseStgMedium(&std);
590
591 return hr;
592 }
593
594
595 /***********************************************************************
596 * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG)
597 * Processes messages sent to the OLE clipboard window.
598 * Note that we will intercept messages in our WndProc only when data
599 * has been placed in the clipboard via OleSetClipboard().
600 * i.e. Only when OLE owns the windows clipboard.
601 */
602 static LRESULT CALLBACK OLEClipbrd_WndProc
603 (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
604 {
605 switch (message)
606 {
607 /*
608 * WM_RENDERFORMAT
609 * We receive this message to allow us to handle delayed rendering of
610 * a specific clipboard format when an application requests data in
611 * that format by calling GetClipboardData.
612 * (Recall that in OleSetClipboard, we used SetClipboardData to
613 * make all HGLOBAL formats supported by the source IDataObject
614 * available using delayed rendering)
615 * On receiving this message we must actually render the data in the
616 * specified format and place it on the clipboard by calling the
617 * SetClipboardData function.
618 */
619 case WM_RENDERFORMAT:
620 {
621 FORMATETC rgelt;
622
623 ZeroMemory( &rgelt, sizeof(FORMATETC));
624
625 /*
626 * Initialize FORMATETC to a Windows clipboard friendly format
627 */
628 rgelt.cfFormat = (UINT) wParam;
629 rgelt.dwAspect = DVASPECT_CONTENT;
630 rgelt.lindex = -1;
631 rgelt.tymed = TYMED_HGLOBAL;
632
633 TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat);
634
635 /*
636 * Render the clipboard data.
637 * (We must have a source data object or we wouldn't be in this WndProc)
638 */
639 OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl), &rgelt );
640
641 break;
642 }
643
644 /*
645 * WM_RENDERALLFORMATS
646 * Sent before the clipboard owner window is destroyed.
647 * We should receive this message only when OleUninitialize is called
648 * while we have an IDataObject in the clipboard.
649 * For the content of the clipboard to remain available to other
650 * applications, we must render data in all the formats the source IDataObject
651 * is capable of generating, and place the data on the clipboard by calling
652 * SetClipboardData.
653 */
654 case WM_RENDERALLFORMATS:
655 {
656 IEnumFORMATETC* penumFormatetc = NULL;
657 FORMATETC rgelt;
658
659 TRACE("(): WM_RENDERALLFORMATS\n");
660
661 /*
662 * Render all HGLOBAL formats supported by the source into
663 * the windows clipboard.
664 */
665 if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl),
666 DATADIR_GET, &penumFormatetc) ) )
667 {
668 WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n");
669 return 0;
670 }
671
672 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
673 {
674 if ( rgelt.tymed == TYMED_HGLOBAL )
675 {
676 /*
677 * Render the clipboard data.
678 */
679 if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl), &rgelt )) )
680 continue;
681
682 TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat);
683 }
684 }
685
686 IEnumFORMATETC_Release(penumFormatetc);
687
688 break;
689 }
690
691 /*
692 * WM_DESTROYCLIPBOARD
693 * This is sent by EmptyClipboard before the clipboard is emptied.
694 * We should release any IDataObject we are holding onto when we receive
695 * this message, since it indicates that the OLE clipboard should be empty
696 * from this point on.
697 */
698 case WM_DESTROYCLIPBOARD:
699 {
700 TRACE("(): WM_DESTROYCLIPBOARD\n");
701 /*
702 * Release the data object we are holding on to
703 */
704 if ( theOleClipboard->pIDataObjectSrc )
705 {
706 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
707 theOleClipboard->pIDataObjectSrc = NULL;
708 }
709 break;
710 }
711
712 /*
713 case WM_ASKCBFORMATNAME:
714 case WM_CHANGECBCHAIN:
715 case WM_DRAWCLIPBOARD:
716 case WM_SIZECLIPBOARD:
717 case WM_HSCROLLCLIPBOARD:
718 case WM_VSCROLLCLIPBOARD:
719 case WM_PAINTCLIPBOARD:
720 */
721 default:
722 return DefWindowProcA(hWnd, message, wParam, lParam);
723 }
724
725 return 0;
726 }
727
728
729 /*---------------------------------------------------------------------*
730 * Implementation of the internal IDataObject interface exposed by
731 * the OLE clipboard.
732 *---------------------------------------------------------------------*/
733
734
735 /************************************************************************
736 * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
737 *
738 * See Windows documentation for more details on IUnknown methods.
739 */
740 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
741 IDataObject* iface,
742 REFIID riid,
743 void** ppvObject)
744 {
745 ole_clipbrd *This = impl_from_IDataObject(iface);
746 TRACE("(%p)->(IID:%s, %p)\n", This, debugstr_guid(riid), ppvObject);
747
748 if ( (This==0) || (ppvObject==0) )
749 return E_INVALIDARG;
750
751 *ppvObject = 0;
752
753 if (IsEqualIID(&IID_IUnknown, riid) ||
754 IsEqualIID(&IID_IDataObject, riid))
755 {
756 *ppvObject = iface;
757 }
758 else
759 {
760 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
761 return E_NOINTERFACE;
762 }
763
764 IUnknown_AddRef((IUnknown*)*ppvObject);
765
766 return S_OK;
767 }
768
769 /************************************************************************
770 * OLEClipbrd_IDataObject_AddRef (IUnknown)
771 *
772 * See Windows documentation for more details on IUnknown methods.
773 */
774 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
775 IDataObject* iface)
776 {
777 ole_clipbrd *This = impl_from_IDataObject(iface);
778
779 TRACE("(%p)->(count=%u)\n",This, This->ref);
780
781 return InterlockedIncrement(&This->ref);
782 }
783
784 /***********************************************************************
785 * OLEClipbrd_DestroyWindow(HWND)
786 * Destroy the clipboard window and unregister its class
787 */
788 static void OLEClipbrd_DestroyWindow(HWND hwnd)
789 {
790 DestroyWindow(hwnd);
791 UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
792 }
793
794 static void OLEClipbrd_Destroy(ole_clipbrd* This)
795 {
796 TRACE("()\n");
797
798 if (!This) return;
799
800 theOleClipboard = NULL;
801
802 if ( This->hWndClipboard )
803 OLEClipbrd_DestroyWindow(This->hWndClipboard);
804
805 HeapFree(GetProcessHeap(), 0, This);
806 }
807
808 /************************************************************************
809 * OLEClipbrd_IDataObject_Release (IUnknown)
810 *
811 * See Windows documentation for more details on IUnknown methods.
812 */
813 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
814 IDataObject* iface)
815 {
816 ole_clipbrd *This = impl_from_IDataObject(iface);
817 ULONG ref;
818
819 TRACE("(%p)->(count=%u)\n",This, This->ref);
820
821 ref = InterlockedDecrement(&This->ref);
822
823 if (ref == 0)
824 {
825 OLEClipbrd_Destroy(This);
826 }
827
828 return ref;
829 }
830
831
832 /************************************************************************
833 * OLEClipbrd_IDataObject_GetData (IDataObject)
834 *
835 * The OLE Clipboard's implementation of this method delegates to
836 * a data source if there is one or wraps around the windows clipboard
837 *
838 * See Windows documentation for more details on IDataObject methods.
839 */
840 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
841 IDataObject* iface,
842 LPFORMATETC pformatetcIn,
843 STGMEDIUM* pmedium)
844 {
845 HANDLE hData = 0;
846 BOOL bClipboardOpen = FALSE;
847 HRESULT hr = S_OK;
848 LPVOID src;
849 ole_clipbrd *This = impl_from_IDataObject(iface);
850
851 TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
852
853 if ( !pformatetcIn || !pmedium )
854 return E_INVALIDARG;
855
856 /*
857 * If we have a data source placed on the clipboard (via OleSetClipboard)
858 * simply delegate to the source object's QueryGetData
859 * NOTE: This code assumes that the IDataObject is in the same address space!
860 * We will need to add marshalling support when Wine handles multiple processes.
861 */
862 if ( This->pIDataObjectSrc )
863 {
864 return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
865 }
866
867 if ( pformatetcIn->lindex != -1 )
868 return DV_E_FORMATETC;
869
870 if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
871 return DV_E_TYMED;
872 /*
873 if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
874 return DV_E_DVASPECT;
875 */
876
877 /*
878 * Otherwise, get the data from the windows clipboard using GetClipboardData
879 */
880 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
881 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
882
883 hData = GetClipboardData(pformatetcIn->cfFormat);
884
885 /* Must make a copy of global handle returned by GetClipboardData; it
886 * is not valid after we call CloseClipboard
887 * Application is responsible for freeing the memory (Forte Agent does this)
888 */
889 src = GlobalLock(hData);
890 if(src) {
891 LPVOID dest;
892 ULONG size;
893 HANDLE hDest;
894
895 size = GlobalSize(hData);
896 hDest = GlobalAlloc(GHND, size);
897 dest = GlobalLock(hDest);
898 memcpy(dest, src, size);
899 GlobalUnlock(hDest);
900 GlobalUnlock(hData);
901 hData = hDest;
902 }
903
904 /*
905 * Return the clipboard data in the storage medium structure
906 */
907 pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
908 pmedium->u.hGlobal = hData;
909 pmedium->pUnkForRelease = NULL;
910
911 hr = S_OK;
912
913 CLEANUP:
914 /*
915 * Close Windows clipboard
916 */
917 if ( bClipboardOpen && !CloseClipboard() )
918 hr = CLIPBRD_E_CANT_CLOSE;
919
920 if ( FAILED(hr) )
921 return hr;
922 return (hData == 0) ? DV_E_FORMATETC : S_OK;
923 }
924
925 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
926 IDataObject* iface,
927 LPFORMATETC pformatetc,
928 STGMEDIUM* pmedium)
929 {
930 FIXME(": Stub\n");
931 return E_NOTIMPL;
932 }
933
934 /************************************************************************
935 * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
936 *
937 * The OLE Clipboard's implementation of this method delegates to
938 * a data source if there is one or wraps around the windows clipboard
939 * function IsClipboardFormatAvailable() otherwise.
940 *
941 * See Windows documentation for more details on IDataObject methods.
942 */
943 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
944 IDataObject* iface,
945 LPFORMATETC pformatetc)
946 {
947 TRACE("(%p, %p)\n", iface, pformatetc);
948
949 if (!pformatetc)
950 return E_INVALIDARG;
951
952 if ( pformatetc->dwAspect != DVASPECT_CONTENT )
953 return DV_E_FORMATETC;
954
955 if ( pformatetc->lindex != -1 )
956 return DV_E_FORMATETC;
957
958 /*
959 * Delegate to the Windows clipboard function IsClipboardFormatAvailable
960 */
961 return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
962 }
963
964 /************************************************************************
965 * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
966 *
967 * See Windows documentation for more details on IDataObject methods.
968 */
969 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
970 IDataObject* iface,
971 LPFORMATETC pformatectIn,
972 LPFORMATETC pformatetcOut)
973 {
974 TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
975
976 if ( !pformatectIn || !pformatetcOut )
977 return E_INVALIDARG;
978
979 *pformatetcOut = *pformatectIn;
980 return DATA_S_SAMEFORMATETC;
981 }
982
983 /************************************************************************
984 * OLEClipbrd_IDataObject_SetData (IDataObject)
985 *
986 * The OLE Clipboard's does not implement this method
987 *
988 * See Windows documentation for more details on IDataObject methods.
989 */
990 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
991 IDataObject* iface,
992 LPFORMATETC pformatetc,
993 STGMEDIUM* pmedium,
994 BOOL fRelease)
995 {
996 TRACE("\n");
997 return E_NOTIMPL;
998 }
999
1000 /************************************************************************
1001 * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
1002 *
1003 * See Windows documentation for more details on IDataObject methods.
1004 */
1005 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
1006 IDataObject* iface,
1007 DWORD dwDirection,
1008 IEnumFORMATETC** ppenumFormatEtc)
1009 {
1010 HRESULT hr = S_OK;
1011 FORMATETC *afmt = NULL;
1012 int cfmt, i;
1013 UINT format;
1014 BOOL bClipboardOpen;
1015 ole_clipbrd *This = impl_from_IDataObject(iface);
1016
1017 TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc);
1018
1019 /*
1020 * If we have a data source placed on the clipboard (via OleSetClipboard)
1021 * simply delegate to the source object's EnumFormatEtc
1022 */
1023 if ( This->pIDataObjectSrc )
1024 {
1025 return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,
1026 dwDirection, ppenumFormatEtc);
1027 }
1028
1029 /*
1030 * Otherwise we must provide our own enumerator which wraps around the
1031 * Windows clipboard function EnumClipboardFormats
1032 */
1033 if ( !ppenumFormatEtc )
1034 return E_INVALIDARG;
1035
1036 if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */
1037 return E_NOTIMPL;
1038
1039 /*
1040 * Store all current clipboard formats in an array of FORMATETC's,
1041 * and create an IEnumFORMATETC enumerator from this list.
1042 */
1043 cfmt = CountClipboardFormats();
1044 afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1045 sizeof(FORMATETC) * cfmt);
1046 /*
1047 * Open the Windows clipboard, associating it with our hidden window
1048 */
1049 if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )
1050 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1051
1052 /*
1053 * Store all current clipboard formats in an array of FORMATETC's
1054 * TODO: Handle TYMED_IStorage media which were put on the clipboard
1055 * by copying the storage into global memory. We must convert this
1056 * TYMED_HGLOBAL back to TYMED_IStorage.
1057 */
1058 for (i = 0, format = 0; i < cfmt; i++)
1059 {
1060 format = EnumClipboardFormats(format);
1061 if (!format) /* Failed! */
1062 {
1063 ERR("EnumClipboardFormats failed to return format!\n");
1064 HANDLE_ERROR( E_FAIL );
1065 }
1066
1067 /* Init the FORMATETC struct */
1068 afmt[i].cfFormat = format;
1069 afmt[i].ptd = NULL;
1070 afmt[i].dwAspect = DVASPECT_CONTENT;
1071 afmt[i].lindex = -1;
1072 afmt[i].tymed = TYMED_HGLOBAL;
1073 }
1074
1075 /*
1076 * Create an EnumFORMATETC enumerator and return an
1077 * EnumFORMATETC after bumping up its ref count
1078 */
1079 *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);
1080 if (!(*ppenumFormatEtc))
1081 HANDLE_ERROR( E_OUTOFMEMORY );
1082
1083 if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))
1084 HANDLE_ERROR( hr );
1085
1086 hr = S_OK;
1087
1088 CLEANUP:
1089 /*
1090 * Free the array of FORMATETC's
1091 */
1092 HeapFree(GetProcessHeap(), 0, afmt);
1093
1094 /*
1095 * Close Windows clipboard
1096 */
1097 if ( bClipboardOpen && !CloseClipboard() )
1098 hr = CLIPBRD_E_CANT_CLOSE;
1099
1100 return hr;
1101 }
1102
1103 /************************************************************************
1104 * OLEClipbrd_IDataObject_DAdvise (IDataObject)
1105 *
1106 * The OLE Clipboard's does not implement this method
1107 *
1108 * See Windows documentation for more details on IDataObject methods.
1109 */
1110 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
1111 IDataObject* iface,
1112 FORMATETC* pformatetc,
1113 DWORD advf,
1114 IAdviseSink* pAdvSink,
1115 DWORD* pdwConnection)
1116 {
1117 TRACE("\n");
1118 return E_NOTIMPL;
1119 }
1120
1121 /************************************************************************
1122 * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
1123 *
1124 * The OLE Clipboard's does not implement this method
1125 *
1126 * See Windows documentation for more details on IDataObject methods.
1127 */
1128 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
1129 IDataObject* iface,
1130 DWORD dwConnection)
1131 {
1132 TRACE("\n");
1133 return E_NOTIMPL;
1134 }
1135
1136 /************************************************************************
1137 * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1138 *
1139 * The OLE Clipboard does not implement this method
1140 *
1141 * See Windows documentation for more details on IDataObject methods.
1142 */
1143 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1144 IDataObject* iface,
1145 IEnumSTATDATA** ppenumAdvise)
1146 {
1147 TRACE("\n");
1148 return E_NOTIMPL;
1149 }
1150
1151 static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
1152 {
1153 OLEClipbrd_IDataObject_QueryInterface,
1154 OLEClipbrd_IDataObject_AddRef,
1155 OLEClipbrd_IDataObject_Release,
1156 OLEClipbrd_IDataObject_GetData,
1157 OLEClipbrd_IDataObject_GetDataHere,
1158 OLEClipbrd_IDataObject_QueryGetData,
1159 OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
1160 OLEClipbrd_IDataObject_SetData,
1161 OLEClipbrd_IDataObject_EnumFormatEtc,
1162 OLEClipbrd_IDataObject_DAdvise,
1163 OLEClipbrd_IDataObject_DUnadvise,
1164 OLEClipbrd_IDataObject_EnumDAdvise
1165 };
1166
1167 /*---------------------------------------------------------------------*
1168 * Internal implementation methods for the OLE clipboard
1169 *---------------------------------------------------------------------*/
1170
1171 /*********************************************************
1172 * Construct the OLEClipbrd class.
1173 */
1174 static ole_clipbrd* OLEClipbrd_Construct(void)
1175 {
1176 ole_clipbrd* This;
1177
1178 This = HeapAlloc( GetProcessHeap(), 0, sizeof(*This) );
1179 if (!This) return NULL;
1180
1181 This->lpvtbl = &OLEClipbrd_IDataObject_VTable;
1182 This->ref = 1;
1183
1184 This->hWndClipboard = NULL;
1185 This->pIDataObjectSrc = NULL;
1186
1187 theOleClipboard = This;
1188 return This;
1189 }
1190
1191 static void register_clipboard_formats(void)
1192 {
1193 static const WCHAR DataObjectW[] = { 'D','a','t','a','O','b','j','e','c','t',0 };
1194 static const WCHAR OlePrivateDataW[] = { 'O','l','e',' ','P','r','i','v','a','t','e',' ','D','a','t','a',0 };
1195
1196 if(!dataobject_clipboard_format)
1197 dataobject_clipboard_format = RegisterClipboardFormatW(DataObjectW);
1198 if(!ole_priv_data_clipboard_format)
1199 ole_priv_data_clipboard_format = RegisterClipboardFormatW(OlePrivateDataW);
1200 }
1201
1202 /***********************************************************************
1203 * OLEClipbrd_Initialize()
1204 * Initializes the OLE clipboard.
1205 */
1206 void OLEClipbrd_Initialize(void)
1207 {
1208 register_clipboard_formats();
1209
1210 if ( !theOleClipboard )
1211 {
1212 TRACE("()\n");
1213 theOleClipboard = OLEClipbrd_Construct();
1214 }
1215 }
1216
1217
1218 /***********************************************************************
1219 * OLEClipbrd_UnInitialize()
1220 * Un-Initializes the OLE clipboard
1221 */
1222 void OLEClipbrd_UnInitialize(void)
1223 {
1224 TRACE("()\n");
1225 /*
1226 * Destroy the clipboard if no one holds a reference to us.
1227 * Note that the clipboard was created with a reference count of 1.
1228 */
1229 if ( theOleClipboard && (theOleClipboard->ref <= 1) )
1230 {
1231 OLEClipbrd_Destroy( theOleClipboard );
1232 }
1233 else
1234 {
1235 WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n");
1236 }
1237 }
1238
1239 /***********************************************************************
1240 * OLEClipbrd_CreateWindow()
1241 * Create the clipboard window
1242 */
1243 static HWND OLEClipbrd_CreateWindow(void)
1244 {
1245 HWND hwnd = 0;
1246 WNDCLASSEXA wcex;
1247
1248 /*
1249 * Register the clipboard window class if necessary
1250 */
1251 ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
1252
1253 wcex.cbSize = sizeof(WNDCLASSEXA);
1254 /* Windows creates this class with a style mask of 0
1255 * We don't bother doing this since the FindClassByAtom code
1256 * would have to be changed to deal with this idiosyncrasy. */
1257 wcex.style = CS_GLOBALCLASS;
1258 wcex.lpfnWndProc = OLEClipbrd_WndProc;
1259 wcex.hInstance = 0;
1260 wcex.lpszClassName = OLEClipbrd_WNDCLASS;
1261
1262 RegisterClassExA(&wcex);
1263
1264 /*
1265 * Create a hidden window to receive OLE clipboard messages
1266 */
1267
1268 /*
1269 * If we need to store state info we can store it here.
1270 * For now we don't need this functionality.
1271 * ClipboardWindowInfo clipboardInfo;
1272 * ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
1273 */
1274
1275 hwnd = CreateWindowA(OLEClipbrd_WNDCLASS,
1276 "ClipboardWindow",
1277 WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
1278 CW_USEDEFAULT, CW_USEDEFAULT,
1279 CW_USEDEFAULT, CW_USEDEFAULT,
1280 0,
1281 0,
1282 0,
1283 0 /*(LPVOID)&clipboardInfo */);
1284
1285 return hwnd;
1286 }
1287
1288 static inline BOOL is_format_in_list(ole_priv_data_entry *entries, DWORD num, UINT cf)
1289 {
1290 DWORD i;
1291 for(i = 0; i < num; i++)
1292 if(entries[i].fmtetc.cfFormat == cf)
1293 return TRUE;
1294
1295 return FALSE;
1296 }
1297
1298 /*********************************************************************
1299 * set_clipboard_formats
1300 *
1301 * Enumerate all HGLOBAL formats supported by the source and make
1302 * those formats available using delayed rendering using SetClipboardData.
1303 *
1304 * TODO: We need to additionally handle TYMED_IStorage and
1305 * TYMED_IStream data by copying into global memory.
1306 */
1307 static HRESULT set_clipboard_formats(IDataObject *data)
1308 {
1309 HRESULT hr;
1310 FORMATETC fmt;
1311 IEnumFORMATETC *enum_fmt;
1312 HGLOBAL priv_data_handle;
1313 DWORD target_offset;
1314 ole_priv_data *priv_data;
1315 DWORD count = 0, needed = sizeof(*priv_data), idx;
1316
1317 hr = IDataObject_EnumFormatEtc(data, DATADIR_GET, &enum_fmt);
1318 if(FAILED(hr)) return hr;
1319
1320 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1321 {
1322 count++;
1323 needed += sizeof(priv_data->entries[0]);
1324 if(fmt.ptd)
1325 {
1326 needed += fmt.ptd->tdSize;
1327 CoTaskMemFree(fmt.ptd);
1328 }
1329 }
1330
1331 /* Windows pads the list with two empty ole_priv_data_entries, one
1332 * after the entries array and one after the target device data.
1333 * Allocating with zero init to zero these pads. */
1334
1335 needed += sizeof(priv_data->entries[0]); /* initialisation of needed includes one of these. */
1336 priv_data_handle = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT, needed);
1337 priv_data = GlobalLock(priv_data_handle);
1338
1339 priv_data->unk1 = 0;
1340 priv_data->size = needed;
1341 priv_data->unk2 = 1;
1342 priv_data->count = count;
1343 priv_data->unk3[0] = 0;
1344 priv_data->unk3[1] = 0;
1345
1346 IEnumFORMATETC_Reset(enum_fmt);
1347
1348 idx = 0;
1349 target_offset = FIELD_OFFSET(ole_priv_data, entries[count + 1]); /* count entries + one pad. */
1350
1351 while(IEnumFORMATETC_Next(enum_fmt, 1, &fmt, NULL) == S_OK)
1352 {
1353 if (fmt.tymed == TYMED_HGLOBAL)
1354 {
1355 char fmt_name[80];
1356 TRACE("(cfFormat=%d:%s)\n", fmt.cfFormat,
1357 GetClipboardFormatNameA(fmt.cfFormat, fmt_name, sizeof(fmt_name)-1) ? fmt_name : "");
1358
1359 SetClipboardData(fmt.cfFormat, NULL);
1360 }
1361
1362 priv_data->entries[idx].fmtetc = fmt;
1363 if(fmt.ptd)
1364 {
1365 memcpy((char*)priv_data + target_offset, fmt.ptd, fmt.ptd->tdSize);
1366 priv_data->entries[idx].fmtetc.ptd = (DVTARGETDEVICE*)target_offset;
1367 target_offset += fmt.ptd->tdSize;
1368 CoTaskMemFree(fmt.ptd);
1369 }
1370
1371 priv_data->entries[idx].first_use = !is_format_in_list(priv_data->entries, idx, fmt.cfFormat);
1372 priv_data->entries[idx].unk[0] = 0;
1373 priv_data->entries[idx].unk[1] = 0;
1374
1375 idx++;
1376 }
1377
1378 IEnumFORMATETC_Release(enum_fmt);
1379
1380 GlobalUnlock(priv_data_handle);
1381 SetClipboardData(ole_priv_data_clipboard_format, priv_data_handle);
1382
1383 return S_OK;
1384 }
1385
1386 /*********************************************************************
1387 * set_dataobject_format
1388 *
1389 * Windows creates a 'DataObject' clipboard format that contains the
1390 * clipboard window's HWND or NULL if the Ole clipboard has been flushed.
1391 */
1392 static HRESULT set_dataobject_format(HWND hwnd)
1393 {
1394 HGLOBAL h = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, sizeof(hwnd));
1395 HWND *data;
1396
1397 if(!h) return E_OUTOFMEMORY;
1398
1399 data = GlobalLock(h);
1400 *data = hwnd;
1401 GlobalUnlock(h);
1402
1403 if(!SetClipboardData(dataobject_clipboard_format, h))
1404 {
1405 GlobalFree(h);
1406 return CLIPBRD_E_CANT_SET;
1407 }
1408
1409 return S_OK;
1410 }
1411
1412 /*---------------------------------------------------------------------*
1413 * Win32 OLE clipboard API
1414 *---------------------------------------------------------------------*/
1415
1416 /***********************************************************************
1417 * OleSetClipboard [OLE32.@]
1418 * Places a pointer to the specified data object onto the clipboard,
1419 * making the data object accessible to the OleGetClipboard function.
1420 *
1421 * RETURNS
1422 *
1423 * S_OK IDataObject pointer placed on the clipboard
1424 * CLIPBRD_E_CANT_OPEN OpenClipboard failed
1425 * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed
1426 * CLIPBRD_E_CANT_CLOSE CloseClipboard failed
1427 * CLIPBRD_E_CANT_SET SetClipboard failed
1428 */
1429
1430 HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj)
1431 {
1432 HRESULT hr = S_OK;
1433 BOOL bClipboardOpen = FALSE;
1434 struct oletls *info = COM_CurrentInfo();
1435
1436 TRACE("(%p)\n", pDataObj);
1437
1438 if(!info)
1439 WARN("Could not allocate tls\n");
1440 else
1441 if(!info->ole_inits)
1442 return CO_E_NOTINITIALIZED;
1443
1444 /*
1445 * Make sure we have a clipboard object
1446 */
1447 OLEClipbrd_Initialize();
1448
1449 /*
1450 * If the Ole clipboard window hasn't been created yet, create it now.
1451 */
1452 if ( !theOleClipboard->hWndClipboard )
1453 theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
1454
1455 if ( !theOleClipboard->hWndClipboard ) /* sanity check */
1456 HANDLE_ERROR( E_FAIL );
1457
1458 /*
1459 * Open the Windows clipboard, associating it with our hidden window
1460 */
1461 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
1462 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1463
1464 /*
1465 * Empty the current clipboard and make our window the clipboard owner
1466 * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
1467 */
1468 if ( !EmptyClipboard() )
1469 HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
1470
1471 /*
1472 * If we are already holding on to an IDataObject first release that.
1473 */
1474 if ( theOleClipboard->pIDataObjectSrc )
1475 {
1476 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1477 theOleClipboard->pIDataObjectSrc = NULL;
1478 }
1479
1480 /* A NULL value indicates that the clipboard should be emptied. */
1481 theOleClipboard->pIDataObjectSrc = pDataObj;
1482 if ( pDataObj )
1483 {
1484 IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
1485 hr = set_clipboard_formats(pDataObj);
1486 if(FAILED(hr)) goto CLEANUP;
1487 }
1488
1489 hr = set_dataobject_format(theOleClipboard->hWndClipboard);
1490
1491 CLEANUP:
1492
1493 /*
1494 * Close Windows clipboard (It remains associated with our window)
1495 */
1496 if ( bClipboardOpen && !CloseClipboard() )
1497 hr = CLIPBRD_E_CANT_CLOSE;
1498
1499 /*
1500 * Release the source IDataObject if something failed
1501 */
1502 if ( FAILED(hr) )
1503 {
1504 if (theOleClipboard->pIDataObjectSrc)
1505 {
1506 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1507 theOleClipboard->pIDataObjectSrc = NULL;
1508 }
1509 }
1510
1511 return hr;
1512 }
1513
1514
1515 /***********************************************************************
1516 * OleGetClipboard [OLE32.@]
1517 * Returns a pointer to our internal IDataObject which represents the conceptual
1518 * state of the Windows clipboard. If the current clipboard already contains
1519 * an IDataObject, our internal IDataObject will delegate to this object.
1520 */
1521 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
1522 {
1523 HRESULT hr = S_OK;
1524 TRACE("()\n");
1525
1526 /*
1527 * Make sure we have a clipboard object
1528 */
1529 OLEClipbrd_Initialize();
1530
1531 if (!theOleClipboard)
1532 return E_OUTOFMEMORY;
1533
1534 /* Return a reference counted IDataObject */
1535 hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl),
1536 &IID_IDataObject, (void**)ppDataObj);
1537 return hr;
1538 }
1539
1540 /******************************************************************************
1541 * OleFlushClipboard [OLE32.@]
1542 * Renders the data from the source IDataObject into the windows clipboard
1543 *
1544 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
1545 * by copying the storage into global memory. Subsequently the default
1546 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
1547 * back to TYMED_IStorage.
1548 */
1549 HRESULT WINAPI OleFlushClipboard(void)
1550 {
1551 IEnumFORMATETC* penumFormatetc = NULL;
1552 FORMATETC rgelt;
1553 HRESULT hr = S_OK;
1554 BOOL bClipboardOpen = FALSE;
1555
1556 TRACE("()\n");
1557
1558 OLEClipbrd_Initialize();
1559
1560 /*
1561 * Already flushed or no source DataObject? Nothing to do.
1562 */
1563 if (!theOleClipboard->pIDataObjectSrc)
1564 return S_OK;
1565
1566 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
1567 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1568
1569 /*
1570 * Render all HGLOBAL formats supported by the source into
1571 * the windows clipboard.
1572 */
1573 if ( FAILED( hr = IDataObject_EnumFormatEtc( theOleClipboard->pIDataObjectSrc,
1574 DATADIR_GET,
1575 &penumFormatetc) ))
1576 {
1577 HANDLE_ERROR( hr );
1578 }
1579
1580 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
1581 {
1582 if ( rgelt.tymed == TYMED_HGLOBAL )
1583 {
1584 CHAR szFmtName[80];
1585 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
1586 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
1587 ? szFmtName : "");
1588
1589 if ( FAILED(OLEClipbrd_RenderFormat( theOleClipboard->pIDataObjectSrc, &rgelt )) )
1590 continue;
1591 }
1592 }
1593
1594 IEnumFORMATETC_Release(penumFormatetc);
1595
1596 hr = set_dataobject_format(NULL);
1597
1598 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
1599 theOleClipboard->pIDataObjectSrc = NULL;
1600
1601 CLEANUP:
1602
1603 if ( bClipboardOpen && !CloseClipboard() )
1604 hr = CLIPBRD_E_CANT_CLOSE;
1605
1606 return hr;
1607 }
1608
1609
1610 /***********************************************************************
1611 * OleIsCurrentClipboard [OLE32.@]
1612 */
1613 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject)
1614 {
1615 TRACE("()\n");
1616 /*
1617 * Make sure we have a clipboard object
1618 */
1619 OLEClipbrd_Initialize();
1620
1621 if (!theOleClipboard)
1622 return E_OUTOFMEMORY;
1623
1624 if (pDataObject == NULL)
1625 return S_FALSE;
1626
1627 return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
1628 }
1629
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.