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