ole32: Set the 'Ole Private Data' clipboard format.
[wine] / dlls / ole32 / clipboard.c
1 /*
2  *  OLE 2 clipboard support
3  *
4  *      Copyright 1999  Noel Borthwick <noel@macadamian.com>
5  *      Copyright 2000  Abey George <abey@macadamian.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES:
22  *    This file contains the implementation for the OLE Clipboard and its
23  *    internal interfaces. The OLE clipboard interacts with an IDataObject
24  *    interface via the OleSetClipboard, OleGetClipboard and
25  *    OleIsCurrentClipboard API's. An internal IDataObject delegates
26  *    to a client supplied IDataObject or the WIN32 clipboard API depending
27  *    on whether OleSetClipboard has been invoked.
28  *    Here are some operating scenarios:
29  *
30  *    1. OleSetClipboard called: In this case the internal IDataObject
31  *       delegates to the client supplied IDataObject. Additionally OLE takes
32  *       ownership of the Windows clipboard and any HGLOCBAL IDataObject
33  *       items are placed on the Windows clipboard. This allows non OLE aware
34  *       applications to access these. A local WinProc fields WM_RENDERFORMAT
35  *       and WM_RENDERALLFORMATS messages in this case.
36  *
37  *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38  *       IDataObject functionality wraps around the WIN32 clipboard API.
39  *
40  *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41  *       IDataObject delegates to the source IDataObjects functionality directly,
42  *       thereby bypassing the Windows clipboard.
43  *
44  *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
45  *
46  * TODO:
47  *    - Support for pasting between different processes. OLE clipboard support
48  *      currently works only for in process copy and paste. Since we internally
49  *      store a pointer to the source's IDataObject and delegate to that, this
50  *      will fail if the IDataObject client belongs to a different process.
51  *    - IDataObject::GetDataHere is not implemented
52  *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53  *      by copying the storage into global memory. Subsequently the default
54  *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55  *      back to TYMED_IStorage.
56  *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57  *      clipboard in OleSetClipboard.
58  *
59  */
60
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64
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', '0', '0', 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 }