source: trunk/src/ole32/clipboard.c@ 7955

Last change on this file since 7955 was 7955, checked in by phaller, 24 years ago

Fixed dbgwrap for new defined prototypes

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