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