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