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

Last change on this file since 6648 was 6648, checked in by bird, 24 years ago

Added $Id:$ keyword.

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