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

Last change on this file since 7788 was 7788, checked in by sandervl, 24 years ago

update

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