1 /*
2 * OLE 2 clipboard support
3 *
4 * Copyright 1999 Noel Borthwick <noel@macadamian.com>
5 * Copyright 2000 Abey George <abey@macadamian.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 *
21 * NOTES:
22 * This file contains the implementation for the OLE Clipboard and its
23 * internal interfaces. The OLE clipboard interacts with an IDataObject
24 * interface via the OleSetClipboard, OleGetClipboard and
25 * OleIsCurrentClipboard API's. An internal IDataObject delegates
26 * to a client supplied IDataObject or the WIN32 clipboard API depending
27 * on whether OleSetClipboard has been invoked.
28 * Here are some operating scenarios:
29 *
30 * 1. OleSetClipboard called: In this case the internal IDataObject
31 * delegates to the client supplied IDataObject. Additionally OLE takes
32 * ownership of the Windows clipboard and any HGLOCBAL IDataObject
33 * items are placed on the Windows clipboard. This allows non OLE aware
34 * applications to access these. A local WinProc fields WM_RENDERFORMAT
35 * and WM_RENDERALLFORMATS messages in this case.
36 *
37 * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal
38 * IDataObject functionality wraps around the WIN32 clipboard API.
39 *
40 * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal
41 * IDataObject delegates to the source IDataObjects functionality directly,
42 * thereby bypassing the Windows clipboard.
43 *
44 * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt
45 *
46 * TODO:
47 * - Support for pasting between different processes. OLE clipboard support
48 * currently works only for in process copy and paste. Since we internally
49 * store a pointer to the source's IDataObject and delegate to that, this
50 * will fail if the IDataObject client belongs to a different process.
51 * - IDataObject::GetDataHere is not implemented
52 * - OleFlushClipboard needs to additionally handle TYMED_IStorage media
53 * by copying the storage into global memory. Subsequently the default
54 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
55 * back to TYMED_IStorage.
56 * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
57 * clipboard in OleSetClipboard.
58 *
59 */
60
61 #include <assert.h>
62 #include <stdarg.h>
63 #include <string.h>
64
65 #define COBJMACROS
66 #define NONAMELESSUNION
67 #define NONAMELESSSTRUCT
68
69 #include "windef.h"
70 #include "winbase.h"
71 #include "wingdi.h"
72 #include "winuser.h"
73 #include "winerror.h"
74 #include "winnls.h"
75 #include "ole2.h"
76 #include "wine/debug.h"
77 #include "olestd.h"
78
79 #include "storage32.h"
80
81 #include "compobj_private.h"
82
83 #define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%x)\n", (HRESULT)err); goto CLEANUP; }
84
85 WINE_DEFAULT_DEBUG_CHANNEL(ole);
86
87 /****************************************************************************
88 * OLEClipbrd
89 * DO NOT add any members before the VTables declaration!
90 */
91 struct OLEClipbrd
92 {
93 /*
94 * List all interface VTables here
95 */
96 const IDataObjectVtbl* lpvtbl1; /* IDataObject VTable */
97
98 /*
99 * The hidden OLE clipboard window. This window is used as the bridge between the
100 * the OLE and windows clipboard API. (Windows creates one such window per process)
101 */
102 HWND hWndClipboard;
103
104 /*
105 * Pointer to the source data object (via OleSetClipboard)
106 */
107 IDataObject* pIDataObjectSrc;
108
109 /*
110 * The registered DataObject clipboard format
111 */
112 UINT cfDataObj;
113
114 /*
115 * The handle to ourself
116 */
117 HGLOBAL hSelf;
118
119 /*
120 * Reference count of this object
121 */
122 LONG ref;
123 };
124
125 typedef struct OLEClipbrd OLEClipbrd;
126
127
128 /****************************************************************************
129 * IEnumFORMATETC implementation
130 * DO NOT add any members before the VTables declaration!
131 */
132 typedef struct
133 {
134 /* IEnumFORMATETC VTable */
135 const IEnumFORMATETCVtbl *lpVtbl;
136
137 /* IEnumFORMATETC fields */
138 UINT posFmt; /* current enumerator position */
139 UINT countFmt; /* number of EnumFORMATETC's in array */
140 LPFORMATETC pFmt; /* array of EnumFORMATETC's */
141
142 /*
143 * Reference count of this object
144 */
145 LONG ref;
146
147 /*
148 * IUnknown implementation of the parent data object.
149 */
150 IUnknown* pUnkDataObj;
151
152 } IEnumFORMATETCImpl;
153
154 typedef struct PresentationDataHeader
155 {
156 BYTE unknown1[28];
157 DWORD dwObjectExtentX;
158 DWORD dwObjectExtentY;
159 DWORD dwSize;
160 } PresentationDataHeader;
161
162 /*
163 * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()
164 */
165 static HGLOBAL hTheOleClipboard = 0;
166 static OLEClipbrd* theOleClipboard = NULL;
167
168
169 /*
170 * Prototypes for the methods of the OLEClipboard class.
171 */
172 void OLEClipbrd_Initialize(void);
173 void OLEClipbrd_UnInitialize(void);
174 static OLEClipbrd* OLEClipbrd_Construct(void);
175 static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
176 static HWND OLEClipbrd_CreateWindow(void);
177 static void OLEClipbrd_DestroyWindow(HWND hwnd);
178 static LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
179 static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc );
180 static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );
181
182 /*
183 * Prototypes for the methods of the OLEClipboard class
184 * that implement IDataObject methods.
185 */
186 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
187 IDataObject* iface,
188 REFIID riid,
189 void** ppvObject);
190 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
191 IDataObject* iface);
192 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
193 IDataObject* iface);
194 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
195 IDataObject* iface,
196 LPFORMATETC pformatetcIn,
197 STGMEDIUM* pmedium);
198 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
199 IDataObject* iface,
200 LPFORMATETC pformatetc,
201 STGMEDIUM* pmedium);
202 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
203 IDataObject* iface,
204 LPFORMATETC pformatetc);
205 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
206 IDataObject* iface,
207 LPFORMATETC pformatectIn,
208 LPFORMATETC pformatetcOut);
209 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
210 IDataObject* iface,
211 LPFORMATETC pformatetc,
212 STGMEDIUM* pmedium,
213 BOOL fRelease);
214 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
215 IDataObject* iface,
216 DWORD dwDirection,
217 IEnumFORMATETC** ppenumFormatEtc);
218 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
219 IDataObject* iface,
220 FORMATETC* pformatetc,
221 DWORD advf,
222 IAdviseSink* pAdvSink,
223 DWORD* pdwConnection);
224 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
225 IDataObject* iface,
226 DWORD dwConnection);
227 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
228 IDataObject* iface,
229 IEnumSTATDATA** ppenumAdvise);
230
231 /*
232 * Prototypes for the IEnumFORMATETC methods.
233 */
234 static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
235 LPUNKNOWN pUnkDataObj);
236 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid,
237 LPVOID* ppvObj);
238 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface);
239 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface);
240 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt,
241 FORMATETC* rgelt, ULONG* pceltFethed);
242 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt);
243 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface);
244 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
245
246
247 /*
248 * Virtual function table for the OLEClipbrd's exposed IDataObject interface
249 */
250 static const IDataObjectVtbl OLEClipbrd_IDataObject_VTable =
251 {
252 OLEClipbrd_IDataObject_QueryInterface,
253 OLEClipbrd_IDataObject_AddRef,
254 OLEClipbrd_IDataObject_Release,
255 OLEClipbrd_IDataObject_GetData,
256 OLEClipbrd_IDataObject_GetDataHere,
257 OLEClipbrd_IDataObject_QueryGetData,
258 OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
259 OLEClipbrd_IDataObject_SetData,
260 OLEClipbrd_IDataObject_EnumFormatEtc,
261 OLEClipbrd_IDataObject_DAdvise,
262 OLEClipbrd_IDataObject_DUnadvise,
263 OLEClipbrd_IDataObject_EnumDAdvise
264 };
265
266 /*
267 * Virtual function table for IEnumFORMATETC interface
268 */
269 static const IEnumFORMATETCVtbl efvt =
270 {
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 static const CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
284
285 /*
286 * If we need to store state info we can store it here.
287 * For now we don't 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.@]
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 struct oletls *info = COM_CurrentInfo();
319 /*
320 HGLOBAL hDataObject = 0;
321 OLEClipbrd **ppDataObject;
322 */
323
324 TRACE("(%p)\n", pDataObj);
325
326 if(!info)
327 WARN("Could not allocate tls\n");
328 else
329 if(!info->ole_inits)
330 return CO_E_NOTINITIALIZED;
331
332 /*
333 * Make sure we have a clipboard object
334 */
335 OLEClipbrd_Initialize();
336
337 /*
338 * If the Ole clipboard window hasn't been created yet, create it now.
339 */
340 if ( !theOleClipboard->hWndClipboard )
341 theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
342
343 if ( !theOleClipboard->hWndClipboard ) /* sanity check */
344 HANDLE_ERROR( E_FAIL );
345
346 /*
347 * Open the Windows clipboard, associating it with our hidden window
348 */
349 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
350 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
351
352 /*
353 * Empty the current clipboard and make our window the clipboard owner
354 * NOTE: This will trigger a WM_DESTROYCLIPBOARD message
355 */
356 if ( !EmptyClipboard() )
357 HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
358
359 /*
360 * If we are already holding on to an IDataObject first release that.
361 */
362 if ( theOleClipboard->pIDataObjectSrc )
363 {
364 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
365 theOleClipboard->pIDataObjectSrc = NULL;
366 }
367
368 /*
369 * AddRef the data object passed in and save its pointer.
370 * A NULL value indicates that the clipboard should be emptied.
371 */
372 theOleClipboard->pIDataObjectSrc = pDataObj;
373 if ( pDataObj )
374 {
375 IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
376 }
377
378 /*
379 * Enumerate all HGLOBAL formats supported by the source and make
380 * those formats available using delayed rendering using SetClipboardData.
381 * Only global memory based data items may be made available to non-OLE
382 * applications via the standard Windows clipboard API. Data based on other
383 * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.
384 *
385 * TODO: Do we need to additionally handle TYMED_IStorage media by copying
386 * the storage into global memory?
387 */
388 if ( pDataObj )
389 {
390 if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,
391 DATADIR_GET,
392 &penumFormatetc )))
393 {
394 HANDLE_ERROR( hr );
395 }
396
397 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
398 {
399 if ( rgelt.tymed == TYMED_HGLOBAL )
400 {
401 CHAR szFmtName[80];
402 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
403 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
404 ? szFmtName : "");
405
406 SetClipboardData( rgelt.cfFormat, NULL);
407 }
408 }
409 IEnumFORMATETC_Release(penumFormatetc);
410 }
411
412 /*
413 * Windows additionally creates a new "DataObject" clipboard format
414 * and stores in on the clipboard. We could possibly store a pointer
415 * to our internal IDataObject interface on the clipboard. I'm not
416 * sure what the use of this is though.
417 * Enable the code below for this functionality.
418 */
419 /*
420 theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");
421 hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
422 sizeof(OLEClipbrd *));
423 if (hDataObject==0)
424 HANDLE_ERROR( E_OUTOFMEMORY );
425
426 ppDataObject = GlobalLock(hDataObject);
427 *ppDataObject = theOleClipboard;
428 GlobalUnlock(hDataObject);
429
430 if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )
431 HANDLE_ERROR( CLIPBRD_E_CANT_SET );
432 */
433
434 hr = S_OK;
435
436 CLEANUP:
437
438 /*
439 * Close Windows clipboard (It remains associated with our window)
440 */
441 if ( bClipboardOpen && !CloseClipboard() )
442 hr = CLIPBRD_E_CANT_CLOSE;
443
444 /*
445 * Release the source IDataObject if something failed
446 */
447 if ( FAILED(hr) )
448 {
449 if (theOleClipboard->pIDataObjectSrc)
450 {
451 IDataObject_Release(theOleClipboard->pIDataObjectSrc);
452 theOleClipboard->pIDataObjectSrc = NULL;
453 }
454 }
455
456 return hr;
457 }
458
459
460 /***********************************************************************
461 * OleGetClipboard [OLE32.@]
462 * Returns a pointer to our internal IDataObject which represents the conceptual
463 * state of the Windows clipboard. If the current clipboard already contains
464 * an IDataObject, our internal IDataObject will delegate to this object.
465 */
466 HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj)
467 {
468 HRESULT hr = S_OK;
469 TRACE("()\n");
470
471 /*
472 * Make sure we have a clipboard object
473 */
474 OLEClipbrd_Initialize();
475
476 if (!theOleClipboard)
477 return E_OUTOFMEMORY;
478
479 /* Return a reference counted IDataObject */
480 hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),
481 &IID_IDataObject, (void**)ppDataObj);
482 return hr;
483 }
484
485 /******************************************************************************
486 * OleFlushClipboard [OLE32.@]
487 * Renders the data from the source IDataObject into the windows clipboard
488 *
489 * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
490 * by copying the storage into global memory. Subsequently the default
491 * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
492 * back to TYMED_IStorage.
493 */
494 HRESULT WINAPI OleFlushClipboard(void)
495 {
496 IEnumFORMATETC* penumFormatetc = NULL;
497 FORMATETC rgelt;
498 HRESULT hr = S_OK;
499 BOOL bClipboardOpen = FALSE;
500 IDataObject* pIDataObjectSrc = NULL;
501
502 TRACE("()\n");
503
504 /*
505 * Make sure we have a clipboard object
506 */
507 OLEClipbrd_Initialize();
508
509 /*
510 * Already flushed or no source DataObject? Nothing to do.
511 */
512 if (!theOleClipboard->pIDataObjectSrc)
513 return S_OK;
514
515 /*
516 * Addref and save the source data object we are holding on to temporarily,
517 * since it will be released when we empty the clipboard.
518 */
519 pIDataObjectSrc = theOleClipboard->pIDataObjectSrc;
520 IDataObject_AddRef(pIDataObjectSrc);
521
522 /*
523 * Open the Windows clipboard
524 */
525 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
526 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
527
528 /*
529 * Empty the current clipboard
530 */
531 if ( !EmptyClipboard() )
532 HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
533
534 /*
535 * Render all HGLOBAL formats supported by the source into
536 * the windows clipboard.
537 */
538 if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc,
539 DATADIR_GET,
540 &penumFormatetc) ))
541 {
542 HANDLE_ERROR( hr );
543 }
544
545 while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
546 {
547 if ( rgelt.tymed == TYMED_HGLOBAL )
548 {
549 CHAR szFmtName[80];
550 TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat,
551 GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
552 ? szFmtName : "");
553
554 /*
555 * Render the clipboard data
556 */
557 if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) )
558 continue;
559 }
560 }
561
562 IEnumFORMATETC_Release(penumFormatetc);
563
564 /*
565 * Release the source data object we are holding on to
566 */
567 IDataObject_Release(pIDataObjectSrc);
568
569 CLEANUP:
570
571 /*
572 * Close Windows clipboard (It remains associated with our window)
573 */
574 if ( bClipboardOpen && !CloseClipboard() )
575 hr = CLIPBRD_E_CANT_CLOSE;
576
577 return hr;
578 }
579
580
581 /***********************************************************************
582 * OleIsCurrentClipboard [OLE32.@]
583 */
584 HRESULT WINAPI OleIsCurrentClipboard(IDataObject *pDataObject)
585 {
586 TRACE("()\n");
587 /*
588 * Make sure we have a clipboard object
589 */
590 OLEClipbrd_Initialize();
591
592 if (!theOleClipboard)
593 return E_OUTOFMEMORY;
594
595 if (pDataObject == NULL)
596 return S_FALSE;
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(void)
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(void)
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(void)
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(void)
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 don't bother doing this since the FindClassByAtom code
734 * would have to be changed to deal with this idiosyncrasy. */
735 wcex.style = CS_GLOBALCLASS;
736 wcex.lpfnWndProc = 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 don't 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 static 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 message 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 if (!GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME))
930 szFmtName[0] = '\0';
931
932 /* If embed source */
933 if (!strcmp(szFmtName, CF_EMBEDSOURCE))
934 {
935 memset(&std, 0, sizeof(STGMEDIUM));
936 std.tymed = pFormatetc->tymed = TYMED_ISTORAGE;
937
938 hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0);
939 if (hStorage == NULL)
940 HANDLE_ERROR( E_OUTOFMEMORY );
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! (%x)\n", hr);
947 GlobalFree(hStorage);
948 return hr;
949 }
950
951 if (1) /* check whether the presentation data is already -not- present */
952 {
953 FORMATETC fmt2;
954 STGMEDIUM std2;
955 METAFILEPICT *mfp = 0;
956
957 fmt2.cfFormat = CF_METAFILEPICT;
958 fmt2.ptd = 0;
959 fmt2.dwAspect = DVASPECT_CONTENT;
960 fmt2.lindex = -1;
961 fmt2.tymed = TYMED_MFPICT;
962
963 memset(&std2, 0, sizeof(STGMEDIUM));
964 std2.tymed = TYMED_MFPICT;
965
966 /* Get the metafile picture out of it */
967
968 if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
969 {
970 mfp = GlobalLock(std2.u.hGlobal);
971 }
972
973 if (mfp)
974 {
975 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '', '', '', 0};
976 IStream *pStream = 0;
977 void *mfBits;
978 PresentationDataHeader pdh;
979 INT nSize;
980 CLSID clsID;
981 LPOLESTR strProgID;
982 CHAR strOleTypeName[51];
983 BYTE OlePresStreamHeader [] =
984 {
985 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00,
986 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
987 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
988 0x00, 0x00, 0x00, 0x00
989 };
990
991 nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL);
992
993 memset(&pdh, 0, sizeof(PresentationDataHeader));
994 memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader));
995
996 pdh.dwObjectExtentX = mfp->xExt;
997 pdh.dwObjectExtentY = mfp->yExt;
998 pdh.dwSize = nSize;
999
1000 hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream);
1001
1002 hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
1003
1004 mfBits = HeapAlloc(GetProcessHeap(), 0, nSize);
1005 nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits);
1006
1007 hr = IStream_Write(pStream, mfBits, nSize, NULL);
1008
1009 IStream_Release(pStream);
1010
1011 HeapFree(GetProcessHeap(), 0, mfBits);
1012
1013 GlobalUnlock(std2.u.hGlobal);
1014
1015 ReadClassStg(std.u.pstg, &clsID);
1016 ProgIDFromCLSID(&clsID, &strProgID);
1017
1018 WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL );
1019 OLECONVERT_CreateOleStream(std.u.pstg);
1020 OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName);
1021 }
1022 }
1023 }
1024 else
1025 {
1026 if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std)))
1027 {
1028 WARN("() : IDataObject_GetData failed to render clipboard data! (%x)\n", hr);
1029 GlobalFree(hStorage);
1030 return hr;
1031 }
1032
1033 /* To put a copy back on the clipboard */
1034
1035 hStorage = std.u.hGlobal;
1036 }
1037
1038 /*
1039 * Put a copy of the rendered data back on the clipboard
1040 */
1041
1042 if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) )
1043 HANDLE_ERROR( E_OUTOFMEMORY );
1044
1045 if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )
1046 {
1047 GlobalFree(hDup);
1048 WARN("() : Failed to set rendered clipboard data into clipboard!\n");
1049 }
1050
1051 CLEANUP:
1052
1053 ReleaseStgMedium(&std);
1054
1055 return hr;
1056 }
1057
1058
1059 /***********************************************************************
1060 * OLEClipbrd_GlobalDupMem( HGLOBAL )
1061 * Helper method to duplicate an HGLOBAL chunk of memory
1062 */
1063 static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )
1064 {
1065 HGLOBAL hGlobalDest;
1066 PVOID pGlobalSrc, pGlobalDest;
1067 DWORD cBytes;
1068
1069 if ( !hGlobalSrc )
1070 return 0;
1071
1072 cBytes = GlobalSize(hGlobalSrc);
1073 if ( 0 == cBytes )
1074 return 0;
1075
1076 hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,
1077 cBytes );
1078 if ( !hGlobalDest )
1079 return 0;
1080
1081 pGlobalSrc = GlobalLock(hGlobalSrc);
1082 pGlobalDest = GlobalLock(hGlobalDest);
1083 if ( !pGlobalSrc || !pGlobalDest )
1084 {
1085 GlobalFree(hGlobalDest);
1086 return 0;
1087 }
1088
1089 memcpy(pGlobalDest, pGlobalSrc, cBytes);
1090
1091 GlobalUnlock(hGlobalSrc);
1092 GlobalUnlock(hGlobalDest);
1093
1094 return hGlobalDest;
1095 }
1096
1097
1098 /*---------------------------------------------------------------------*
1099 * Implementation of the internal IDataObject interface exposed by
1100 * the OLE clipboard.
1101 *---------------------------------------------------------------------*/
1102
1103
1104 /************************************************************************
1105 * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
1106 *
1107 * See Windows documentation for more details on IUnknown methods.
1108 */
1109 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface(
1110 IDataObject* iface,
1111 REFIID riid,
1112 void** ppvObject)
1113 {
1114 /*
1115 * Declare "This" pointer
1116 */
1117 OLEClipbrd *This = (OLEClipbrd *)iface;
1118 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1119
1120 /*
1121 * Perform a sanity check on the parameters.
1122 */
1123 if ( (This==0) || (ppvObject==0) )
1124 return E_INVALIDARG;
1125
1126 /*
1127 * Initialize the return parameter.
1128 */
1129 *ppvObject = 0;
1130
1131 /*
1132 * Compare the riid with the interface IDs implemented by this object.
1133 */
1134 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
1135 {
1136 *ppvObject = iface;
1137 }
1138 else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
1139 {
1140 *ppvObject = (IDataObject*)&(This->lpvtbl1);
1141 }
1142 else /* We only support IUnknown and IDataObject */
1143 {
1144 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1145 return E_NOINTERFACE;
1146 }
1147
1148 /*
1149 * Query Interface always increases the reference count by one when it is
1150 * successful.
1151 */
1152 IUnknown_AddRef((IUnknown*)*ppvObject);
1153
1154 return S_OK;
1155 }
1156
1157 /************************************************************************
1158 * OLEClipbrd_IDataObject_AddRef (IUnknown)
1159 *
1160 * See Windows documentation for more details on IUnknown methods.
1161 */
1162 static ULONG WINAPI OLEClipbrd_IDataObject_AddRef(
1163 IDataObject* iface)
1164 {
1165 /*
1166 * Declare "This" pointer
1167 */
1168 OLEClipbrd *This = (OLEClipbrd *)iface;
1169
1170 TRACE("(%p)->(count=%u)\n",This, This->ref);
1171
1172 return InterlockedIncrement(&This->ref);
1173
1174 }
1175
1176 /************************************************************************
1177 * OLEClipbrd_IDataObject_Release (IUnknown)
1178 *
1179 * See Windows documentation for more details on IUnknown methods.
1180 */
1181 static ULONG WINAPI OLEClipbrd_IDataObject_Release(
1182 IDataObject* iface)
1183 {
1184 /*
1185 * Declare "This" pointer
1186 */
1187 OLEClipbrd *This = (OLEClipbrd *)iface;
1188 ULONG ref;
1189
1190 TRACE("(%p)->(count=%u)\n",This, This->ref);
1191
1192 /*
1193 * Decrease the reference count on this object.
1194 */
1195 ref = InterlockedDecrement(&This->ref);
1196
1197 /*
1198 * If the reference count goes down to 0, perform suicide.
1199 */
1200 if (ref == 0)
1201 {
1202 OLEClipbrd_Destroy(This);
1203 }
1204
1205 return ref;
1206 }
1207
1208
1209 /************************************************************************
1210 * OLEClipbrd_IDataObject_GetData (IDataObject)
1211 *
1212 * The OLE Clipboard's implementation of this method delegates to
1213 * a data source if there is one or wraps around the windows clipboard
1214 *
1215 * See Windows documentation for more details on IDataObject methods.
1216 */
1217 static HRESULT WINAPI OLEClipbrd_IDataObject_GetData(
1218 IDataObject* iface,
1219 LPFORMATETC pformatetcIn,
1220 STGMEDIUM* pmedium)
1221 {
1222 HANDLE hData = 0;
1223 BOOL bClipboardOpen = FALSE;
1224 HRESULT hr = S_OK;
1225 LPVOID src;
1226
1227 /*
1228 * Declare "This" pointer
1229 */
1230 OLEClipbrd *This = (OLEClipbrd *)iface;
1231
1232 TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium);
1233
1234 if ( !pformatetcIn || !pmedium )
1235 return E_INVALIDARG;
1236
1237 /*
1238 * If we have a data source placed on the clipboard (via OleSetClipboard)
1239 * simply delegate to the source object's QueryGetData
1240 * NOTE: This code assumes that the IDataObject is in the same address space!
1241 * We will need to add marshalling support when Wine handles multiple processes.
1242 */
1243 if ( This->pIDataObjectSrc )
1244 {
1245 return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
1246 }
1247
1248 if ( pformatetcIn->lindex != -1 )
1249 return DV_E_LINDEX;
1250 if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
1251 return DV_E_TYMED;
1252 /*
1253 if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
1254 return DV_E_DVASPECT;
1255 */
1256
1257 /*
1258 * Otherwise, get the data from the windows clipboard using GetClipboardData
1259 */
1260 if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
1261 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1262
1263 hData = GetClipboardData(pformatetcIn->cfFormat);
1264
1265 /* Must make a copy of global handle returned by GetClipboardData; it
1266 * is not valid after we call CloseClipboard
1267 * Application is responsible for freeing the memory (Forte Agent does this)
1268 */
1269 src = GlobalLock(hData);
1270 if(src) {
1271 LPVOID dest;
1272 ULONG size;
1273 HANDLE hDest;
1274
1275 size = GlobalSize(hData);
1276 hDest = GlobalAlloc(GHND, size);
1277 dest = GlobalLock(hDest);
1278 memcpy(dest, src, size);
1279 GlobalUnlock(hDest);
1280 GlobalUnlock(hData);
1281 hData = hDest;
1282 }
1283
1284 /*
1285 * Return the clipboard data in the storage medium structure
1286 */
1287 pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
1288 pmedium->u.hGlobal = hData;
1289 pmedium->pUnkForRelease = NULL;
1290
1291 hr = S_OK;
1292
1293 CLEANUP:
1294 /*
1295 * Close Windows clipboard
1296 */
1297 if ( bClipboardOpen && !CloseClipboard() )
1298 hr = CLIPBRD_E_CANT_CLOSE;
1299
1300 if ( FAILED(hr) )
1301 return hr;
1302 return (hData == 0) ? DV_E_FORMATETC : S_OK;
1303 }
1304
1305 static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere(
1306 IDataObject* iface,
1307 LPFORMATETC pformatetc,
1308 STGMEDIUM* pmedium)
1309 {
1310 FIXME(": Stub\n");
1311 return E_NOTIMPL;
1312 }
1313
1314 /************************************************************************
1315 * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
1316 *
1317 * The OLE Clipboard's implementation of this method delegates to
1318 * a data source if there is one or wraps around the windows clipboard
1319 * function IsClipboardFormatAvailable() otherwise.
1320 *
1321 * See Windows documentation for more details on IDataObject methods.
1322 */
1323 static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData(
1324 IDataObject* iface,
1325 LPFORMATETC pformatetc)
1326 {
1327 TRACE("(%p, %p)\n", iface, pformatetc);
1328
1329 if (!pformatetc)
1330 return E_INVALIDARG;
1331
1332 if ( pformatetc->dwAspect != DVASPECT_CONTENT )
1333 return DV_E_FORMATETC;
1334
1335 if ( pformatetc->lindex != -1 )
1336 return DV_E_FORMATETC;
1337
1338 /*
1339 * Delegate to the Windows clipboard function IsClipboardFormatAvailable
1340 */
1341 return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_CLIPFORMAT;
1342 }
1343
1344 /************************************************************************
1345 * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
1346 *
1347 * See Windows documentation for more details on IDataObject methods.
1348 */
1349 static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
1350 IDataObject* iface,
1351 LPFORMATETC pformatectIn,
1352 LPFORMATETC pformatetcOut)
1353 {
1354 TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
1355
1356 if ( !pformatectIn || !pformatetcOut )
1357 return E_INVALIDARG;
1358
1359 *pformatetcOut = *pformatectIn;
1360 return DATA_S_SAMEFORMATETC;
1361 }
1362
1363 /************************************************************************
1364 * OLEClipbrd_IDataObject_SetData (IDataObject)
1365 *
1366 * The OLE Clipboard's does not implement this method
1367 *
1368 * See Windows documentation for more details on IDataObject methods.
1369 */
1370 static HRESULT WINAPI OLEClipbrd_IDataObject_SetData(
1371 IDataObject* iface,
1372 LPFORMATETC pformatetc,
1373 STGMEDIUM* pmedium,
1374 BOOL fRelease)
1375 {
1376 TRACE("\n");
1377 return E_NOTIMPL;
1378 }
1379
1380 /************************************************************************
1381 * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
1382 *
1383 * See Windows documentation for more details on IDataObject methods.
1384 */
1385 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc(
1386 IDataObject* iface,
1387 DWORD dwDirection,
1388 IEnumFORMATETC** ppenumFormatEtc)
1389 {
1390 HRESULT hr = S_OK;
1391 FORMATETC *afmt = NULL;
1392 int cfmt, i;
1393 UINT format;
1394 BOOL bClipboardOpen;
1395
1396 /*
1397 * Declare "This" pointer
1398 */
1399 OLEClipbrd *This = (OLEClipbrd *)iface;
1400
1401 TRACE("(%p, %x, %p)\n", iface, dwDirection, ppenumFormatEtc);
1402
1403 /*
1404 * If we have a data source placed on the clipboard (via OleSetClipboard)
1405 * simply delegate to the source object's EnumFormatEtc
1406 */
1407 if ( This->pIDataObjectSrc )
1408 {
1409 return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,
1410 dwDirection, ppenumFormatEtc);
1411 }
1412
1413 /*
1414 * Otherwise we must provide our own enumerator which wraps around the
1415 * Windows clipboard function EnumClipboardFormats
1416 */
1417 if ( !ppenumFormatEtc )
1418 return E_INVALIDARG;
1419
1420 if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */
1421 return E_NOTIMPL;
1422
1423 /*
1424 * Store all current clipboard formats in an array of FORMATETC's,
1425 * and create an IEnumFORMATETC enumerator from this list.
1426 */
1427 cfmt = CountClipboardFormats();
1428 afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1429 sizeof(FORMATETC) * cfmt);
1430 /*
1431 * Open the Windows clipboard, associating it with our hidden window
1432 */
1433 if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )
1434 HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
1435
1436 /*
1437 * Store all current clipboard formats in an array of FORMATETC's
1438 * TODO: Handle TYMED_IStorage media which were put on the clipboard
1439 * by copying the storage into global memory. We must convert this
1440 * TYMED_HGLOBAL back to TYMED_IStorage.
1441 */
1442 for (i = 0, format = 0; i < cfmt; i++)
1443 {
1444 format = EnumClipboardFormats(format);
1445 if (!format) /* Failed! */
1446 {
1447 ERR("EnumClipboardFormats failed to return format!\n");
1448 HANDLE_ERROR( E_FAIL );
1449 }
1450
1451 /* Init the FORMATETC struct */
1452 afmt[i].cfFormat = format;
1453 afmt[i].ptd = NULL;
1454 afmt[i].dwAspect = DVASPECT_CONTENT;
1455 afmt[i].lindex = -1;
1456 afmt[i].tymed = TYMED_HGLOBAL;
1457 }
1458
1459 /*
1460 * Create an EnumFORMATETC enumerator and return an
1461 * EnumFORMATETC after bumping up its ref count
1462 */
1463 *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);
1464 if (!(*ppenumFormatEtc))
1465 HANDLE_ERROR( E_OUTOFMEMORY );
1466
1467 if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))
1468 HANDLE_ERROR( hr );
1469
1470 hr = S_OK;
1471
1472 CLEANUP:
1473 /*
1474 * Free the array of FORMATETC's
1475 */
1476 HeapFree(GetProcessHeap(), 0, afmt);
1477
1478 /*
1479 * Close Windows clipboard
1480 */
1481 if ( bClipboardOpen && !CloseClipboard() )
1482 hr = CLIPBRD_E_CANT_CLOSE;
1483
1484 return hr;
1485 }
1486
1487 /************************************************************************
1488 * OLEClipbrd_IDataObject_DAdvise (IDataObject)
1489 *
1490 * The OLE Clipboard's does not implement this method
1491 *
1492 * See Windows documentation for more details on IDataObject methods.
1493 */
1494 static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise(
1495 IDataObject* iface,
1496 FORMATETC* pformatetc,
1497 DWORD advf,
1498 IAdviseSink* pAdvSink,
1499 DWORD* pdwConnection)
1500 {
1501 TRACE("\n");
1502 return E_NOTIMPL;
1503 }
1504
1505 /************************************************************************
1506 * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
1507 *
1508 * The OLE Clipboard's does not implement this method
1509 *
1510 * See Windows documentation for more details on IDataObject methods.
1511 */
1512 static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise(
1513 IDataObject* iface,
1514 DWORD dwConnection)
1515 {
1516 TRACE("\n");
1517 return E_NOTIMPL;
1518 }
1519
1520 /************************************************************************
1521 * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
1522 *
1523 * The OLE Clipboard does not implement this method
1524 *
1525 * See Windows documentation for more details on IDataObject methods.
1526 */
1527 static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise(
1528 IDataObject* iface,
1529 IEnumSTATDATA** ppenumAdvise)
1530 {
1531 TRACE("\n");
1532 return E_NOTIMPL;
1533 }
1534
1535
1536 /*---------------------------------------------------------------------*
1537 * Implementation of the internal IEnumFORMATETC interface returned by
1538 * the OLE clipboard's IDataObject.
1539 *---------------------------------------------------------------------*/
1540
1541 /************************************************************************
1542 * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)
1543 *
1544 * Creates an IEnumFORMATETC enumerator from an array of FORMATETC
1545 * Structures. pUnkOuter is the outer unknown for reference counting only.
1546 * NOTE: this does not AddRef the interface.
1547 */
1548
1549 static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
1550 LPUNKNOWN pUnkDataObj)
1551 {
1552 IEnumFORMATETCImpl* ef;
1553 DWORD size=cfmt * sizeof(FORMATETC);
1554 LPMALLOC pIMalloc;
1555
1556 ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl));
1557 if (!ef)
1558 return NULL;
1559
1560 ef->ref = 0;
1561 ef->lpVtbl = &efvt;
1562 ef->pUnkDataObj = pUnkDataObj;
1563
1564 ef->posFmt = 0;
1565 ef->countFmt = cfmt;
1566 if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) {
1567 HeapFree(GetProcessHeap(), 0, ef);
1568 return NULL;
1569 }
1570 ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size);
1571 IMalloc_Release(pIMalloc);
1572
1573 if (ef->pFmt)
1574 memcpy(ef->pFmt, afmt, size);
1575
1576 TRACE("(%p)->()\n",ef);
1577 return (LPENUMFORMATETC)ef;
1578 }
1579
1580
1581 /************************************************************************
1582 * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
1583 *
1584 * See Windows documentation for more details on IUnknown methods.
1585 */
1586 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface
1587 (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
1588 {
1589 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1590
1591 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj);
1592
1593 /*
1594 * Since enumerators are separate objects from the parent data object
1595 * we only need to support the IUnknown and IEnumFORMATETC interfaces
1596 */
1597
1598 *ppvObj = NULL;
1599
1600 if(IsEqualIID(riid, &IID_IUnknown))
1601 {
1602 *ppvObj = This;
1603 }
1604 else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
1605 {
1606 *ppvObj = (IDataObject*)This;
1607 }
1608
1609 if(*ppvObj)
1610 {
1611 IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
1612 TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj);
1613 return S_OK;
1614 }
1615
1616 TRACE("-- Interface: E_NOINTERFACE\n");
1617 return E_NOINTERFACE;
1618 }
1619
1620 /************************************************************************
1621 * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
1622 *
1623 * Since enumerating formats only makes sense when our data object is around,
1624 * we insure that it stays as long as we stay by calling our parents IUnknown
1625 * for AddRef and Release. But since we are not controlled by the lifetime of
1626 * the outer object, we still keep our own reference count in order to
1627 * free ourselves.
1628 */
1629 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
1630 {
1631 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1632 TRACE("(%p)->(count=%u)\n",This, This->ref);
1633
1634 if (This->pUnkDataObj)
1635 IUnknown_AddRef(This->pUnkDataObj);
1636
1637 return InterlockedIncrement(&This->ref);
1638 }
1639
1640 /************************************************************************
1641 * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
1642 *
1643 * See Windows documentation for more details on IUnknown methods.
1644 */
1645 static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
1646 {
1647 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1648 LPMALLOC pIMalloc;
1649 ULONG ref;
1650
1651 TRACE("(%p)->(count=%u)\n",This, This->ref);
1652
1653 if (This->pUnkDataObj)
1654 IUnknown_Release(This->pUnkDataObj); /* Release parent data object */
1655
1656 ref = InterlockedDecrement(&This->ref);
1657 if (!ref)
1658 {
1659 TRACE("() - destroying IEnumFORMATETC(%p)\n",This);
1660 if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
1661 {
1662 IMalloc_Free(pIMalloc, This->pFmt);
1663 IMalloc_Release(pIMalloc);
1664 }
1665
1666 HeapFree(GetProcessHeap(),0,This);
1667 }
1668 return ref;
1669 }
1670
1671 /************************************************************************
1672 * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
1673 *
1674 * Standard enumerator members for IEnumFORMATETC
1675 */
1676 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next
1677 (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
1678 {
1679 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1680 UINT cfetch;
1681 HRESULT hres = S_FALSE;
1682
1683 TRACE("(%p)->(pos=%u)\n", This, This->posFmt);
1684
1685 if (This->posFmt < This->countFmt)
1686 {
1687 cfetch = This->countFmt - This->posFmt;
1688 if (cfetch >= celt)
1689 {
1690 cfetch = celt;
1691 hres = S_OK;
1692 }
1693
1694 memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
1695 This->posFmt += cfetch;
1696 }
1697 else
1698 {
1699 cfetch = 0;
1700 }
1701
1702 if (pceltFethed)
1703 {
1704 *pceltFethed = cfetch;
1705 }
1706
1707 return hres;
1708 }
1709
1710 /************************************************************************
1711 * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
1712 *
1713 * Standard enumerator members for IEnumFORMATETC
1714 */
1715 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
1716 {
1717 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1718 TRACE("(%p)->(num=%u)\n", This, celt);
1719
1720 This->posFmt += celt;
1721 if (This->posFmt > This->countFmt)
1722 {
1723 This->posFmt = This->countFmt;
1724 return S_FALSE;
1725 }
1726 return S_OK;
1727 }
1728
1729 /************************************************************************
1730 * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
1731 *
1732 * Standard enumerator members for IEnumFORMATETC
1733 */
1734 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
1735 {
1736 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1737 TRACE("(%p)->()\n", This);
1738
1739 This->posFmt = 0;
1740 return S_OK;
1741 }
1742
1743 /************************************************************************
1744 * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
1745 *
1746 * Standard enumerator members for IEnumFORMATETC
1747 */
1748 static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone
1749 (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
1750 {
1751 IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface;
1752 HRESULT hr = S_OK;
1753
1754 TRACE("(%p)->(ppenum=%p)\n", This, ppenum);
1755
1756 if ( !ppenum )
1757 return E_INVALIDARG;
1758
1759 *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,
1760 This->pFmt,
1761 This->pUnkDataObj);
1762
1763 if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))
1764 return ( hr );
1765
1766 return (*ppenum) ? S_OK : E_OUTOFMEMORY;
1767 }
1768
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.