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