widl: Move support for stub arguments to typegen.c to make it usable for proxies...
[wine/multimedia.git] / dlls / ole32 / datacache.c
blob249882e85978b88c6bd118024a5652527c33f65e
1 /*
2 * OLE 2 Data cache
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2000 Abey George
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.
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.
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
21 * NOTES:
22 * The OLE2 data cache supports a whole whack of
23 * interfaces including:
24 * IDataObject, IPersistStorage, IViewObject2,
25 * IOleCache2 and IOleCacheControl.
27 * Most of the implementation details are taken from: Inside OLE
28 * second edition by Kraig Brockschmidt,
30 * NOTES
31 * - This implementation of the datacache will let your application
32 * load documents that have embedded OLE objects in them and it will
33 * also retrieve the metafile representation of those objects.
34 * - This implementation of the datacache will also allow your
35 * application to save new documents with OLE objects in them.
36 * - The main thing that it doesn't do is allow you to activate
37 * or modify the OLE objects in any way.
38 * - I haven't found any good documentation on the real usage of
39 * the streams created by the data cache. In particular, How to
40 * determine what the XXX stands for in the stream name
41 * "\002OlePresXXX". It appears to just be a counter.
42 * - Also, I don't know the real content of the presentation stream
43 * header. I was able to figure-out where the extent of the object
44 * was stored and the aspect, but that's about it.
46 #include <stdarg.h>
47 #include <string.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "winerror.h"
58 #include "wine/unicode.h"
59 #include "ole2.h"
60 #include "wine/list.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65 /****************************************************************************
66 * PresentationDataHeader
68 * This structure represents the header of the \002OlePresXXX stream in
69 * the OLE object strorage.
71 typedef struct PresentationDataHeader
73 /* clipformat:
74 * - standard clipformat:
75 * DWORD length = 0xffffffff;
76 * DWORD cfFormat;
77 * - or custom clipformat:
78 * DWORD length;
79 * CHAR format_name[length]; (null-terminated)
81 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
82 DVASPECT dvAspect;
83 DWORD lindex;
84 DWORD tymed;
85 DWORD unknown7; /* 0 */
86 DWORD dwObjectExtentX;
87 DWORD dwObjectExtentY;
88 DWORD dwSize;
89 } PresentationDataHeader;
91 typedef struct DataCacheEntry
93 struct list entry;
94 /* format of this entry */
95 FORMATETC fmtetc;
96 /* the clipboard format of the data */
97 CLIPFORMAT data_cf;
98 /* cached data */
99 STGMEDIUM stgmedium;
101 * This storage pointer is set through a call to
102 * IPersistStorage_Load. This is where the visual
103 * representation of the object is stored.
105 IStorage *storage;
106 /* connection ID */
107 DWORD id;
108 /* dirty flag */
109 BOOL dirty;
110 /* stream number (-1 if not set ) */
111 unsigned short stream_number;
112 } DataCacheEntry;
114 /****************************************************************************
115 * DataCache
117 struct DataCache
120 * List all interface VTables here
122 const IDataObjectVtbl* lpVtbl;
123 const IUnknownVtbl* lpvtblNDIUnknown;
124 const IPersistStorageVtbl* lpvtblIPersistStorage;
125 const IViewObject2Vtbl* lpvtblIViewObject;
126 const IOleCache2Vtbl* lpvtblIOleCache2;
127 const IOleCacheControlVtbl* lpvtblIOleCacheControl;
130 * Reference count of this object
132 LONG ref;
135 * IUnknown implementation of the outer object.
137 IUnknown* outerUnknown;
140 * The user of this object can setup ONE advise sink
141 * connection with the object. These parameters describe
142 * that connection.
144 DWORD sinkAspects;
145 DWORD sinkAdviseFlag;
146 IAdviseSink* sinkInterface;
147 IStorage *presentationStorage;
149 /* list of cache entries */
150 struct list cache_list;
151 /* last id assigned to an entry */
152 DWORD last_cache_id;
153 /* dirty flag */
154 BOOL dirty;
157 typedef struct DataCache DataCache;
160 * Here, I define utility macros to help with the casting of the
161 * "this" parameter.
162 * There is a version to accommodate all of the VTables implemented
163 * by this object.
166 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
168 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpVtbl));
171 static inline DataCache *impl_from_NDIUnknown( IUnknown *iface )
173 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblNDIUnknown));
176 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
178 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIPersistStorage));
181 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
183 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIViewObject));
186 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
188 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCache2));
191 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
193 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCacheControl));
196 static const char * debugstr_formatetc(const FORMATETC *formatetc)
198 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
199 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
200 formatetc->lindex, formatetc->tymed);
204 * Prototypes for the methods of the DataCache class.
206 static DataCache* DataCache_Construct(REFCLSID clsid,
207 LPUNKNOWN pUnkOuter);
208 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *This,
209 IStream **pStm);
211 static void DataCacheEntry_Destroy(DataCacheEntry *This)
213 list_remove(&This->entry);
214 if (This->storage)
215 IStorage_Release(This->storage);
216 HeapFree(GetProcessHeap(), 0, This->fmtetc.ptd);
217 ReleaseStgMedium(&This->stgmedium);
218 HeapFree(GetProcessHeap(), 0, This);
221 static void DataCache_Destroy(
222 DataCache* ptrToDestroy)
224 DataCacheEntry *cache_entry, *next_cache_entry;
226 TRACE("()\n");
228 if (ptrToDestroy->sinkInterface != NULL)
230 IAdviseSink_Release(ptrToDestroy->sinkInterface);
231 ptrToDestroy->sinkInterface = NULL;
234 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
235 DataCacheEntry_Destroy(cache_entry);
238 * Free the datacache pointer.
240 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
243 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
245 DataCacheEntry *cache_entry;
246 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
248 /* FIXME: also compare DVTARGETDEVICEs */
249 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
250 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
251 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
252 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
253 return cache_entry;
255 return NULL;
258 /* checks that the clipformat and tymed are valid and returns an error if they
259 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
260 * DataCache_Draw */
261 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
263 if (!cfFormat || !tymed ||
264 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
265 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
266 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
267 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
268 return S_OK;
269 else if (tymed == TYMED_HGLOBAL)
270 return CACHE_S_FORMATETC_NOTSUPPORTED;
271 else
273 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
274 return DV_E_TYMED;
278 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
280 HRESULT hr;
282 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
283 if (FAILED(hr))
284 return hr;
285 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
286 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
288 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
289 if (!*cache_entry)
290 return E_OUTOFMEMORY;
292 (*cache_entry)->fmtetc = *formatetc;
293 if (formatetc->ptd)
295 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
296 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
298 (*cache_entry)->stgmedium.tymed = TYMED_NULL;
299 (*cache_entry)->stgmedium.pUnkForRelease = NULL;
300 (*cache_entry)->storage = NULL;
301 (*cache_entry)->id = This->last_cache_id++;
302 (*cache_entry)->dirty = TRUE;
303 (*cache_entry)->stream_number = -1;
304 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
305 return hr;
308 /************************************************************************
309 * DataCache_FireOnViewChange
311 * This method will fire an OnViewChange notification to the advise
312 * sink registered with the datacache.
314 * See IAdviseSink::OnViewChange for more details.
316 static void DataCache_FireOnViewChange(
317 DataCache* this,
318 DWORD aspect,
319 LONG lindex)
321 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
324 * The sink supplies a filter when it registers
325 * we make sure we only send the notifications when that
326 * filter matches.
328 if ((this->sinkAspects & aspect) != 0)
330 if (this->sinkInterface != NULL)
332 IAdviseSink_OnViewChange(this->sinkInterface,
333 aspect,
334 lindex);
337 * Some sinks want to be unregistered automatically when
338 * the first notification goes out.
340 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
342 IAdviseSink_Release(this->sinkInterface);
344 this->sinkInterface = NULL;
345 this->sinkAspects = 0;
346 this->sinkAdviseFlag = 0;
352 /* Helper for DataCacheEntry_OpenPresStream */
353 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
355 /* The presentation streams have names of the form "\002OlePresXXX",
356 * where XXX goes from 000 to 999. */
357 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
359 LPCWSTR name = elem->pwcsName;
361 return (elem->type == STGTY_STREAM)
362 && (strlenW(name) == 11)
363 && (strncmpW(name, OlePres, 8) == 0)
364 && (name[8] >= '0') && (name[8] <= '9')
365 && (name[9] >= '0') && (name[9] <= '9')
366 && (name[10] >= '0') && (name[10] <= '9');
369 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
371 DWORD length;
372 HRESULT hr;
373 ULONG read;
375 *clipformat = 0;
377 hr = IStream_Read(stream, &length, sizeof(length), &read);
378 if (hr != S_OK || read != sizeof(length))
379 return DV_E_CLIPFORMAT;
380 if (length == -1)
382 DWORD cf;
383 hr = IStream_Read(stream, &cf, sizeof(cf), 0);
384 if (hr != S_OK || read != sizeof(cf))
385 return DV_E_CLIPFORMAT;
386 *clipformat = cf;
388 else
390 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
391 if (!format_name)
392 return E_OUTOFMEMORY;
393 hr = IStream_Read(stream, format_name, length, &read);
394 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
396 HeapFree(GetProcessHeap(), 0, format_name);
397 return DV_E_CLIPFORMAT;
399 *clipformat = RegisterClipboardFormatA(format_name);
400 HeapFree(GetProcessHeap(), 0, format_name);
402 return S_OK;
405 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
407 DWORD length;
408 HRESULT hr;
410 if (clipformat < 0xc000)
411 length = -1;
412 else
413 length = GetClipboardFormatNameA(clipformat, NULL, 0);
414 hr = IStream_Write(stream, &length, sizeof(length), NULL);
415 if (FAILED(hr))
416 return hr;
417 if (clipformat < 0xc000)
419 DWORD cf = clipformat;
420 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
422 else
424 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
425 if (!format_name)
426 return E_OUTOFMEMORY;
427 GetClipboardFormatNameA(clipformat, format_name, length);
428 hr = IStream_Write(stream, format_name, length, NULL);
429 HeapFree(GetProcessHeap(), 0, format_name);
431 return hr;
434 /************************************************************************
435 * DataCacheEntry_OpenPresStream
437 * This method will find the stream for the given presentation. It makes
438 * no attempt at fallback.
440 * Param:
441 * this - Pointer to the DataCache object
442 * drawAspect - The aspect of the object that we wish to draw.
443 * pStm - A returned stream. It points to the beginning of the
444 * - presentation data, including the header.
446 * Errors:
447 * S_OK The requested stream has been opened.
448 * OLE_E_BLANK The requested stream could not be found.
449 * Quite a few others I'm too lazy to map correctly.
451 * Notes:
452 * Algorithm: Scan the elements of the presentation storage, looking
453 * for presentation streams. For each presentation stream,
454 * load the header and check to see if the aspect matches.
456 * If a fallback is desired, just opening the first presentation stream
457 * is a possibility.
459 static HRESULT DataCacheEntry_OpenPresStream(
460 DataCacheEntry *This,
461 IStream **ppStm)
463 STATSTG elem;
464 IEnumSTATSTG *pEnum;
465 HRESULT hr;
467 if (!ppStm) return E_POINTER;
469 hr = IStorage_EnumElements(This->storage, 0, NULL, 0, &pEnum);
470 if (FAILED(hr)) return hr;
472 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
474 if (DataCache_IsPresentationStream(&elem))
476 IStream *pStm;
478 hr = IStorage_OpenStream(This->storage, elem.pwcsName,
479 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
480 &pStm);
481 if (SUCCEEDED(hr))
483 PresentationDataHeader header;
484 ULONG actual_read;
485 CLIPFORMAT clipformat;
487 hr = read_clipformat(pStm, &clipformat);
489 if (hr == S_OK)
490 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
492 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
493 if (hr == S_OK && actual_read == sizeof(header)
494 && header.dvAspect == This->fmtetc.dwAspect)
496 /* Rewind the stream before returning it. */
497 LARGE_INTEGER offset;
498 offset.u.LowPart = 0;
499 offset.u.HighPart = 0;
500 IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
502 *ppStm = pStm;
504 CoTaskMemFree(elem.pwcsName);
505 IEnumSTATSTG_Release(pEnum);
507 return S_OK;
510 IStream_Release(pStm);
514 CoTaskMemFree(elem.pwcsName);
517 IEnumSTATSTG_Release(pEnum);
519 return (hr == S_FALSE ? OLE_E_BLANK : hr);
522 /************************************************************************
523 * DataCacheEntry_LoadData
525 * This method will read information for the requested presentation
526 * into the given structure.
528 * Param:
529 * This - The entry to load the data from.
531 * Returns:
532 * This method returns a metafile handle if it is successful.
533 * it will return 0 if not.
535 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *This)
537 IStream* presStream = NULL;
538 HRESULT hres;
539 ULARGE_INTEGER current_pos;
540 STATSTG streamInfo;
541 void* metafileBits;
542 METAFILEPICT *mfpict;
543 HGLOBAL hmfpict;
544 PresentationDataHeader header;
545 CLIPFORMAT clipformat;
546 static const LARGE_INTEGER offset_zero;
549 * Open the presentation stream.
551 hres = DataCacheEntry_OpenPresStream(
552 This,
553 &presStream);
555 if (FAILED(hres))
556 return hres;
559 * Get the size of the stream.
561 hres = IStream_Stat(presStream,
562 &streamInfo,
563 STATFLAG_NONAME);
566 * Read the header.
569 hres = read_clipformat(presStream, &clipformat);
570 if (FAILED(hres))
572 IStream_Release(presStream);
573 return hres;
576 hres = IStream_Read(
577 presStream,
578 &header,
579 sizeof(PresentationDataHeader),
580 NULL);
581 if (hres != S_OK)
583 IStream_Release(presStream);
584 return E_FAIL;
587 hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, &current_pos);
589 streamInfo.cbSize.QuadPart -= current_pos.QuadPart;
591 hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
592 if (!hmfpict)
594 IStream_Release(presStream);
595 return E_OUTOFMEMORY;
597 mfpict = GlobalLock(hmfpict);
600 * Allocate a buffer for the metafile bits.
602 metafileBits = HeapAlloc(GetProcessHeap(),
604 streamInfo.cbSize.u.LowPart);
607 * Read the metafile bits.
609 hres = IStream_Read(
610 presStream,
611 metafileBits,
612 streamInfo.cbSize.u.LowPart,
613 NULL);
616 * Create a metafile with those bits.
618 if (SUCCEEDED(hres))
620 /* FIXME: get this from the stream */
621 mfpict->mm = MM_ANISOTROPIC;
622 mfpict->xExt = header.dwObjectExtentX;
623 mfpict->yExt = header.dwObjectExtentY;
624 mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
625 if (!mfpict->hMF)
626 hres = E_FAIL;
629 GlobalUnlock(hmfpict);
630 if (SUCCEEDED(hres))
632 This->data_cf = This->fmtetc.cfFormat;
633 This->stgmedium.tymed = TYMED_MFPICT;
634 This->stgmedium.u.hMetaFilePict = hmfpict;
636 else
637 GlobalFree(hmfpict);
640 * Cleanup.
642 HeapFree(GetProcessHeap(), 0, metafileBits);
643 IStream_Release(presStream);
645 return hres;
648 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This,
649 IStorage *storage, IStream **stream)
651 HRESULT hr;
652 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
653 '0' + (This->stream_number / 100) % 10,
654 '0' + (This->stream_number / 10) % 10,
655 '0' + This->stream_number % 10, 0};
657 /* FIXME: cache the created stream in This? */
658 hr = IStorage_CreateStream(storage, wszName,
659 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
660 0, 0, stream);
661 return hr;
664 static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
665 BOOL same_as_load)
667 PresentationDataHeader header;
668 HRESULT hr;
669 IStream *pres_stream;
670 void *data = NULL;
672 TRACE("stream_number = %d, fmtetc = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc));
674 hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
675 if (FAILED(hr))
676 return hr;
678 hr = write_clipformat(pres_stream, This->data_cf);
679 if (FAILED(hr))
680 return hr;
682 if (This->fmtetc.ptd)
683 FIXME("ptd not serialized\n");
684 header.unknown3 = 4;
685 header.dvAspect = This->fmtetc.dwAspect;
686 header.lindex = This->fmtetc.lindex;
687 header.tymed = This->stgmedium.tymed;
688 header.unknown7 = 0;
689 header.dwObjectExtentX = 0;
690 header.dwObjectExtentY = 0;
691 header.dwSize = 0;
693 /* size the data */
694 switch (This->data_cf)
696 case CF_METAFILEPICT:
698 if (This->stgmedium.tymed != TYMED_NULL)
700 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
701 if (!mfpict)
703 IStream_Release(pres_stream);
704 return DV_E_STGMEDIUM;
706 header.dwObjectExtentX = mfpict->xExt;
707 header.dwObjectExtentY = mfpict->yExt;
708 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
709 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
711 break;
713 default:
714 break;
718 * Write the header.
720 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
721 NULL);
722 if (FAILED(hr))
724 IStream_Release(pres_stream);
725 return hr;
728 /* get the data */
729 switch (This->data_cf)
731 case CF_METAFILEPICT:
733 if (This->stgmedium.tymed != TYMED_NULL)
735 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
736 if (!mfpict)
738 IStream_Release(pres_stream);
739 return DV_E_STGMEDIUM;
741 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
742 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
743 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
745 break;
747 default:
748 break;
751 if (data)
752 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
754 IStream_Release(pres_stream);
755 return hr;
758 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
759 * does no checking of whether src_stgm has a supported tymed, so this should be
760 * done in the caller */
761 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
762 const STGMEDIUM *src_stgm)
764 if (src_stgm->tymed == TYMED_MFPICT)
766 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
767 METAFILEPICT *dest_mfpict;
769 if (!src_mfpict)
770 return DV_E_STGMEDIUM;
771 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
772 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
773 if (!dest_mfpict)
775 GlobalUnlock(src_stgm->u.hMetaFilePict);
776 return E_OUTOFMEMORY;
778 *dest_mfpict = *src_mfpict;
779 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
780 GlobalUnlock(src_stgm->u.hMetaFilePict);
781 GlobalUnlock(dest_stgm->u.hMetaFilePict);
783 else if (src_stgm->tymed != TYMED_NULL)
785 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
786 GMEM_MOVEABLE);
787 if (!dest_stgm->u.hGlobal)
788 return E_OUTOFMEMORY;
790 dest_stgm->tymed = src_stgm->tymed;
791 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
792 if (dest_stgm->pUnkForRelease)
793 IUnknown_AddRef(dest_stgm->pUnkForRelease);
794 return S_OK;
797 static HRESULT DataCacheEntry_SetData(DataCacheEntry *This,
798 const FORMATETC *formatetc,
799 const STGMEDIUM *stgmedium,
800 BOOL fRelease)
802 if ((!This->fmtetc.cfFormat && !formatetc->cfFormat) ||
803 (This->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
804 stgmedium->tymed == TYMED_NULL)
806 WARN("invalid formatetc\n");
807 return DV_E_FORMATETC;
810 This->dirty = TRUE;
811 ReleaseStgMedium(&This->stgmedium);
812 This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat;
813 if (fRelease)
815 This->stgmedium = *stgmedium;
816 return S_OK;
818 else
819 return copy_stg_medium(This->data_cf,
820 &This->stgmedium, stgmedium);
823 static HRESULT DataCacheEntry_GetData(DataCacheEntry *This,
824 STGMEDIUM *stgmedium)
826 if (stgmedium->tymed == TYMED_NULL && This->storage)
828 HRESULT hr = DataCacheEntry_LoadData(This);
829 if (FAILED(hr))
830 return hr;
832 if (stgmedium->tymed == TYMED_NULL)
833 return OLE_E_BLANK;
834 return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium);
837 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
839 ReleaseStgMedium(&This->stgmedium);
840 This->data_cf = This->fmtetc.cfFormat;
841 return S_OK;
844 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This)
846 if (This->storage)
848 IStorage_Release(This->storage);
849 This->storage = NULL;
853 /*********************************************************
854 * Method implementation for the non delegating IUnknown
855 * part of the DataCache class.
858 /************************************************************************
859 * DataCache_NDIUnknown_QueryInterface (IUnknown)
861 * See Windows documentation for more details on IUnknown methods.
863 * This version of QueryInterface will not delegate it's implementation
864 * to the outer unknown.
866 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
867 IUnknown* iface,
868 REFIID riid,
869 void** ppvObject)
871 DataCache *this = impl_from_NDIUnknown(iface);
874 * Perform a sanity check on the parameters.
876 if ( (this==0) || (ppvObject==0) )
877 return E_INVALIDARG;
880 * Initialize the return parameter.
882 *ppvObject = 0;
885 * Compare the riid with the interface IDs implemented by this object.
887 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
889 *ppvObject = iface;
891 else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
893 *ppvObject = (IDataObject*)&(this->lpVtbl);
895 else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) ||
896 (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
898 *ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
900 else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
901 (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
903 *ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
905 else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
906 (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
908 *ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
910 else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
912 *ppvObject = (IOleCacheControl*)&(this->lpvtblIOleCacheControl);
916 * Check that we obtained an interface.
918 if ((*ppvObject)==0)
920 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
921 return E_NOINTERFACE;
925 * Query Interface always increases the reference count by one when it is
926 * successful.
928 IUnknown_AddRef((IUnknown*)*ppvObject);
930 return S_OK;
933 /************************************************************************
934 * DataCache_NDIUnknown_AddRef (IUnknown)
936 * See Windows documentation for more details on IUnknown methods.
938 * This version of QueryInterface will not delegate it's implementation
939 * to the outer unknown.
941 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
942 IUnknown* iface)
944 DataCache *this = impl_from_NDIUnknown(iface);
945 return InterlockedIncrement(&this->ref);
948 /************************************************************************
949 * DataCache_NDIUnknown_Release (IUnknown)
951 * See Windows documentation for more details on IUnknown methods.
953 * This version of QueryInterface will not delegate it's implementation
954 * to the outer unknown.
956 static ULONG WINAPI DataCache_NDIUnknown_Release(
957 IUnknown* iface)
959 DataCache *this = impl_from_NDIUnknown(iface);
960 ULONG ref;
963 * Decrease the reference count on this object.
965 ref = InterlockedDecrement(&this->ref);
968 * If the reference count goes down to 0, perform suicide.
970 if (ref == 0) DataCache_Destroy(this);
972 return ref;
975 /*********************************************************
976 * Method implementation for the IDataObject
977 * part of the DataCache class.
980 /************************************************************************
981 * DataCache_IDataObject_QueryInterface (IUnknown)
983 * See Windows documentation for more details on IUnknown methods.
985 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
986 IDataObject* iface,
987 REFIID riid,
988 void** ppvObject)
990 DataCache *this = impl_from_IDataObject(iface);
992 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
995 /************************************************************************
996 * DataCache_IDataObject_AddRef (IUnknown)
998 * See Windows documentation for more details on IUnknown methods.
1000 static ULONG WINAPI DataCache_IDataObject_AddRef(
1001 IDataObject* iface)
1003 DataCache *this = impl_from_IDataObject(iface);
1005 return IUnknown_AddRef(this->outerUnknown);
1008 /************************************************************************
1009 * DataCache_IDataObject_Release (IUnknown)
1011 * See Windows documentation for more details on IUnknown methods.
1013 static ULONG WINAPI DataCache_IDataObject_Release(
1014 IDataObject* iface)
1016 DataCache *this = impl_from_IDataObject(iface);
1018 return IUnknown_Release(this->outerUnknown);
1021 /************************************************************************
1022 * DataCache_GetData
1024 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1025 * See Windows documentation for more details on GetData.
1027 static HRESULT WINAPI DataCache_GetData(
1028 IDataObject* iface,
1029 LPFORMATETC pformatetcIn,
1030 STGMEDIUM* pmedium)
1032 DataCache *This = impl_from_IDataObject(iface);
1033 DataCacheEntry *cache_entry;
1035 memset(pmedium, 0, sizeof(*pmedium));
1037 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1038 if (!cache_entry)
1039 return OLE_E_BLANK;
1041 return DataCacheEntry_GetData(cache_entry, pmedium);
1044 static HRESULT WINAPI DataCache_GetDataHere(
1045 IDataObject* iface,
1046 LPFORMATETC pformatetc,
1047 STGMEDIUM* pmedium)
1049 FIXME("stub\n");
1050 return E_NOTIMPL;
1053 static HRESULT WINAPI DataCache_QueryGetData(
1054 IDataObject* iface,
1055 LPFORMATETC pformatetc)
1057 FIXME("stub\n");
1058 return E_NOTIMPL;
1061 /************************************************************************
1062 * DataCache_EnumFormatEtc (IDataObject)
1064 * The data cache doesn't implement this method.
1066 * See Windows documentation for more details on IDataObject methods.
1068 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1069 IDataObject* iface,
1070 LPFORMATETC pformatectIn,
1071 LPFORMATETC pformatetcOut)
1073 TRACE("()\n");
1074 return E_NOTIMPL;
1077 /************************************************************************
1078 * DataCache_IDataObject_SetData (IDataObject)
1080 * This method is delegated to the IOleCache2 implementation.
1082 * See Windows documentation for more details on IDataObject methods.
1084 static HRESULT WINAPI DataCache_IDataObject_SetData(
1085 IDataObject* iface,
1086 LPFORMATETC pformatetc,
1087 STGMEDIUM* pmedium,
1088 BOOL fRelease)
1090 IOleCache2* oleCache = NULL;
1091 HRESULT hres;
1093 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1095 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1097 if (FAILED(hres))
1098 return E_UNEXPECTED;
1100 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1102 IOleCache2_Release(oleCache);
1104 return hres;
1107 /************************************************************************
1108 * DataCache_EnumFormatEtc (IDataObject)
1110 * The data cache doesn't implement this method.
1112 * See Windows documentation for more details on IDataObject methods.
1114 static HRESULT WINAPI DataCache_EnumFormatEtc(
1115 IDataObject* iface,
1116 DWORD dwDirection,
1117 IEnumFORMATETC** ppenumFormatEtc)
1119 TRACE("()\n");
1120 return E_NOTIMPL;
1123 /************************************************************************
1124 * DataCache_DAdvise (IDataObject)
1126 * The data cache doesn't support connections.
1128 * See Windows documentation for more details on IDataObject methods.
1130 static HRESULT WINAPI DataCache_DAdvise(
1131 IDataObject* iface,
1132 FORMATETC* pformatetc,
1133 DWORD advf,
1134 IAdviseSink* pAdvSink,
1135 DWORD* pdwConnection)
1137 TRACE("()\n");
1138 return OLE_E_ADVISENOTSUPPORTED;
1141 /************************************************************************
1142 * DataCache_DUnadvise (IDataObject)
1144 * The data cache doesn't support connections.
1146 * See Windows documentation for more details on IDataObject methods.
1148 static HRESULT WINAPI DataCache_DUnadvise(
1149 IDataObject* iface,
1150 DWORD dwConnection)
1152 TRACE("()\n");
1153 return OLE_E_NOCONNECTION;
1156 /************************************************************************
1157 * DataCache_EnumDAdvise (IDataObject)
1159 * The data cache doesn't support connections.
1161 * See Windows documentation for more details on IDataObject methods.
1163 static HRESULT WINAPI DataCache_EnumDAdvise(
1164 IDataObject* iface,
1165 IEnumSTATDATA** ppenumAdvise)
1167 TRACE("()\n");
1168 return OLE_E_ADVISENOTSUPPORTED;
1171 /*********************************************************
1172 * Method implementation for the IDataObject
1173 * part of the DataCache class.
1176 /************************************************************************
1177 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1179 * See Windows documentation for more details on IUnknown methods.
1181 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1182 IPersistStorage* iface,
1183 REFIID riid,
1184 void** ppvObject)
1186 DataCache *this = impl_from_IPersistStorage(iface);
1188 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1191 /************************************************************************
1192 * DataCache_IPersistStorage_AddRef (IUnknown)
1194 * See Windows documentation for more details on IUnknown methods.
1196 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1197 IPersistStorage* iface)
1199 DataCache *this = impl_from_IPersistStorage(iface);
1201 return IUnknown_AddRef(this->outerUnknown);
1204 /************************************************************************
1205 * DataCache_IPersistStorage_Release (IUnknown)
1207 * See Windows documentation for more details on IUnknown methods.
1209 static ULONG WINAPI DataCache_IPersistStorage_Release(
1210 IPersistStorage* iface)
1212 DataCache *this = impl_from_IPersistStorage(iface);
1214 return IUnknown_Release(this->outerUnknown);
1217 /************************************************************************
1218 * DataCache_GetClassID (IPersistStorage)
1220 * The data cache doesn't implement this method.
1222 * See Windows documentation for more details on IPersistStorage methods.
1224 static HRESULT WINAPI DataCache_GetClassID(
1225 IPersistStorage* iface,
1226 CLSID* pClassID)
1228 DataCache *This = impl_from_IPersistStorage(iface);
1229 DataCacheEntry *cache_entry;
1231 TRACE("(%p, %p)\n", iface, pClassID);
1233 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1235 if (cache_entry->storage != NULL)
1237 STATSTG statstg;
1238 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1239 if (SUCCEEDED(hr))
1241 memcpy(pClassID, &statstg.clsid, sizeof(*pClassID));
1242 return S_OK;
1247 memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID));
1249 return S_OK;
1252 /************************************************************************
1253 * DataCache_IsDirty (IPersistStorage)
1255 * See Windows documentation for more details on IPersistStorage methods.
1257 static HRESULT WINAPI DataCache_IsDirty(
1258 IPersistStorage* iface)
1260 DataCache *This = impl_from_IPersistStorage(iface);
1261 DataCacheEntry *cache_entry;
1263 TRACE("(%p)\n", iface);
1265 if (This->dirty)
1266 return S_OK;
1268 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1269 if (cache_entry->dirty)
1270 return S_OK;
1272 return S_FALSE;
1275 /************************************************************************
1276 * DataCache_InitNew (IPersistStorage)
1278 * The data cache implementation of IPersistStorage_InitNew simply stores
1279 * the storage pointer.
1281 * See Windows documentation for more details on IPersistStorage methods.
1283 static HRESULT WINAPI DataCache_InitNew(
1284 IPersistStorage* iface,
1285 IStorage* pStg)
1287 DataCache *This = impl_from_IPersistStorage(iface);
1289 TRACE("(%p, %p)\n", iface, pStg);
1291 if (This->presentationStorage != NULL)
1292 IStorage_Release(This->presentationStorage);
1294 This->presentationStorage = pStg;
1296 IStorage_AddRef(This->presentationStorage);
1297 This->dirty = TRUE;
1299 return S_OK;
1302 /************************************************************************
1303 * DataCache_Load (IPersistStorage)
1305 * The data cache implementation of IPersistStorage_Load doesn't
1306 * actually load anything. Instead, it holds on to the storage pointer
1307 * and it will load the presentation information when the
1308 * IDataObject_GetData or IViewObject2_Draw methods are called.
1310 * See Windows documentation for more details on IPersistStorage methods.
1312 static HRESULT WINAPI DataCache_Load(
1313 IPersistStorage* iface,
1314 IStorage* pStg)
1316 DataCache *This = impl_from_IPersistStorage(iface);
1317 STATSTG elem;
1318 IEnumSTATSTG *pEnum;
1319 HRESULT hr;
1321 TRACE("(%p, %p)\n", iface, pStg);
1323 if (This->presentationStorage != NULL)
1324 IStorage_Release(This->presentationStorage);
1326 This->presentationStorage = pStg;
1328 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1329 if (FAILED(hr)) return hr;
1331 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1333 if (DataCache_IsPresentationStream(&elem))
1335 IStream *pStm;
1337 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1338 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1339 &pStm);
1340 if (SUCCEEDED(hr))
1342 PresentationDataHeader header;
1343 ULONG actual_read;
1344 CLIPFORMAT clipformat;
1346 hr = read_clipformat(pStm, &clipformat);
1348 if (hr == S_OK)
1349 hr = IStream_Read(pStm, &header, sizeof(header),
1350 &actual_read);
1352 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1353 if (hr == S_OK && actual_read == sizeof(header))
1355 DataCacheEntry *cache_entry;
1356 FORMATETC fmtetc;
1358 fmtetc.cfFormat = clipformat;
1359 fmtetc.ptd = NULL; /* FIXME */
1360 fmtetc.dwAspect = header.dvAspect;
1361 fmtetc.lindex = header.lindex;
1362 fmtetc.tymed = header.tymed;
1364 TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1366 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1367 if (!cache_entry)
1368 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1369 if (SUCCEEDED(hr))
1371 DataCacheEntry_DiscardData(cache_entry);
1372 if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1373 cache_entry->storage = pStg;
1374 IStorage_AddRef(pStg);
1375 cache_entry->dirty = FALSE;
1379 IStream_Release(pStm);
1383 CoTaskMemFree(elem.pwcsName);
1386 This->dirty = FALSE;
1388 IEnumSTATSTG_Release(pEnum);
1390 IStorage_AddRef(This->presentationStorage);
1391 return S_OK;
1394 /************************************************************************
1395 * DataCache_Save (IPersistStorage)
1397 * Until we actually connect to a running object and retrieve new
1398 * information to it, we never have to save anything. However, it is
1399 * our responsibility to copy the information when saving to a new
1400 * storage.
1402 * See Windows documentation for more details on IPersistStorage methods.
1404 static HRESULT WINAPI DataCache_Save(
1405 IPersistStorage* iface,
1406 IStorage* pStg,
1407 BOOL fSameAsLoad)
1409 DataCache *This = impl_from_IPersistStorage(iface);
1410 DataCacheEntry *cache_entry;
1411 BOOL dirty = FALSE;
1412 HRESULT hr = S_OK;
1413 unsigned short stream_number = 0;
1415 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1417 dirty = This->dirty;
1418 if (!dirty)
1420 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1422 dirty = cache_entry->dirty;
1423 if (dirty)
1424 break;
1428 /* this is a shortcut if nothing changed */
1429 if (!dirty && !fSameAsLoad && This->presentationStorage)
1431 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1434 /* assign stream numbers to the cache entries */
1435 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1437 if (cache_entry->stream_number != stream_number)
1439 cache_entry->dirty = TRUE; /* needs to be written out again */
1440 cache_entry->stream_number = stream_number;
1442 stream_number++;
1445 /* write out the cache entries */
1446 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1448 if (!fSameAsLoad || cache_entry->dirty)
1450 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1451 if (FAILED(hr))
1452 break;
1454 cache_entry->dirty = FALSE;
1458 This->dirty = FALSE;
1459 return hr;
1462 /************************************************************************
1463 * DataCache_SaveCompleted (IPersistStorage)
1465 * This method is called to tell the cache to release the storage
1466 * pointer it's currently holding.
1468 * See Windows documentation for more details on IPersistStorage methods.
1470 static HRESULT WINAPI DataCache_SaveCompleted(
1471 IPersistStorage* iface,
1472 IStorage* pStgNew)
1474 TRACE("(%p, %p)\n", iface, pStgNew);
1476 if (pStgNew)
1479 * First, make sure we get our hands off any storage we have.
1482 IPersistStorage_HandsOffStorage(iface);
1485 * Then, attach to the new storage.
1488 DataCache_Load(iface, pStgNew);
1491 return S_OK;
1494 /************************************************************************
1495 * DataCache_HandsOffStorage (IPersistStorage)
1497 * This method is called to tell the cache to release the storage
1498 * pointer it's currently holding.
1500 * See Windows documentation for more details on IPersistStorage methods.
1502 static HRESULT WINAPI DataCache_HandsOffStorage(
1503 IPersistStorage* iface)
1505 DataCache *this = impl_from_IPersistStorage(iface);
1506 DataCacheEntry *cache_entry;
1508 TRACE("(%p)\n", iface);
1510 if (this->presentationStorage != NULL)
1512 IStorage_Release(this->presentationStorage);
1513 this->presentationStorage = NULL;
1516 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1517 DataCacheEntry_HandsOffStorage(cache_entry);
1519 return S_OK;
1522 /*********************************************************
1523 * Method implementation for the IViewObject2
1524 * part of the DataCache class.
1527 /************************************************************************
1528 * DataCache_IViewObject2_QueryInterface (IUnknown)
1530 * See Windows documentation for more details on IUnknown methods.
1532 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1533 IViewObject2* iface,
1534 REFIID riid,
1535 void** ppvObject)
1537 DataCache *this = impl_from_IViewObject2(iface);
1539 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1542 /************************************************************************
1543 * DataCache_IViewObject2_AddRef (IUnknown)
1545 * See Windows documentation for more details on IUnknown methods.
1547 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1548 IViewObject2* iface)
1550 DataCache *this = impl_from_IViewObject2(iface);
1552 return IUnknown_AddRef(this->outerUnknown);
1555 /************************************************************************
1556 * DataCache_IViewObject2_Release (IUnknown)
1558 * See Windows documentation for more details on IUnknown methods.
1560 static ULONG WINAPI DataCache_IViewObject2_Release(
1561 IViewObject2* iface)
1563 DataCache *this = impl_from_IViewObject2(iface);
1565 return IUnknown_Release(this->outerUnknown);
1568 /************************************************************************
1569 * DataCache_Draw (IViewObject2)
1571 * This method will draw the cached representation of the object
1572 * to the given device context.
1574 * See Windows documentation for more details on IViewObject2 methods.
1576 static HRESULT WINAPI DataCache_Draw(
1577 IViewObject2* iface,
1578 DWORD dwDrawAspect,
1579 LONG lindex,
1580 void* pvAspect,
1581 DVTARGETDEVICE* ptd,
1582 HDC hdcTargetDev,
1583 HDC hdcDraw,
1584 LPCRECTL lprcBounds,
1585 LPCRECTL lprcWBounds,
1586 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1587 ULONG_PTR dwContinue)
1589 DataCache *This = impl_from_IViewObject2(iface);
1590 HRESULT hres;
1591 DataCacheEntry *cache_entry;
1593 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1594 iface,
1595 dwDrawAspect,
1596 lindex,
1597 pvAspect,
1598 hdcTargetDev,
1599 hdcDraw,
1600 lprcBounds,
1601 lprcWBounds,
1602 pfnContinue,
1603 dwContinue);
1606 * Sanity check
1608 if (lprcBounds==NULL)
1609 return E_INVALIDARG;
1611 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1613 /* FIXME: compare ptd too */
1614 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1615 (cache_entry->fmtetc.lindex != lindex))
1616 continue;
1618 /* if the data hasn't been loaded yet, do it now */
1619 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1621 hres = DataCacheEntry_LoadData(cache_entry);
1622 if (FAILED(hres))
1623 continue;
1626 /* no data */
1627 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1628 continue;
1630 switch (cache_entry->data_cf)
1632 case CF_METAFILEPICT:
1635 * We have to be careful not to modify the state of the
1636 * DC.
1638 INT prevMapMode;
1639 SIZE oldWindowExt;
1640 SIZE oldViewportExt;
1641 POINT oldViewportOrg;
1642 METAFILEPICT *mfpict;
1644 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1645 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1646 continue;
1648 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1650 SetWindowExtEx(hdcDraw,
1651 mfpict->xExt,
1652 mfpict->yExt,
1653 &oldWindowExt);
1655 SetViewportExtEx(hdcDraw,
1656 lprcBounds->right - lprcBounds->left,
1657 lprcBounds->bottom - lprcBounds->top,
1658 &oldViewportExt);
1660 SetViewportOrgEx(hdcDraw,
1661 lprcBounds->left,
1662 lprcBounds->top,
1663 &oldViewportOrg);
1665 PlayMetaFile(hdcDraw, mfpict->hMF);
1667 SetWindowExtEx(hdcDraw,
1668 oldWindowExt.cx,
1669 oldWindowExt.cy,
1670 NULL);
1672 SetViewportExtEx(hdcDraw,
1673 oldViewportExt.cx,
1674 oldViewportExt.cy,
1675 NULL);
1677 SetViewportOrgEx(hdcDraw,
1678 oldViewportOrg.x,
1679 oldViewportOrg.y,
1680 NULL);
1682 SetMapMode(hdcDraw, prevMapMode);
1684 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1686 return S_OK;
1691 WARN("no data could be found to be drawn\n");
1693 return OLE_E_BLANK;
1696 static HRESULT WINAPI DataCache_GetColorSet(
1697 IViewObject2* iface,
1698 DWORD dwDrawAspect,
1699 LONG lindex,
1700 void* pvAspect,
1701 DVTARGETDEVICE* ptd,
1702 HDC hicTargetDevice,
1703 LOGPALETTE** ppColorSet)
1705 FIXME("stub\n");
1706 return E_NOTIMPL;
1709 static HRESULT WINAPI DataCache_Freeze(
1710 IViewObject2* iface,
1711 DWORD dwDrawAspect,
1712 LONG lindex,
1713 void* pvAspect,
1714 DWORD* pdwFreeze)
1716 FIXME("stub\n");
1717 return E_NOTIMPL;
1720 static HRESULT WINAPI DataCache_Unfreeze(
1721 IViewObject2* iface,
1722 DWORD dwFreeze)
1724 FIXME("stub\n");
1725 return E_NOTIMPL;
1728 /************************************************************************
1729 * DataCache_SetAdvise (IViewObject2)
1731 * This sets-up an advisory sink with the data cache. When the object's
1732 * view changes, this sink is called.
1734 * See Windows documentation for more details on IViewObject2 methods.
1736 static HRESULT WINAPI DataCache_SetAdvise(
1737 IViewObject2* iface,
1738 DWORD aspects,
1739 DWORD advf,
1740 IAdviseSink* pAdvSink)
1742 DataCache *this = impl_from_IViewObject2(iface);
1744 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1747 * A call to this function removes the previous sink
1749 if (this->sinkInterface != NULL)
1751 IAdviseSink_Release(this->sinkInterface);
1752 this->sinkInterface = NULL;
1753 this->sinkAspects = 0;
1754 this->sinkAdviseFlag = 0;
1758 * Now, setup the new one.
1760 if (pAdvSink!=NULL)
1762 this->sinkInterface = pAdvSink;
1763 this->sinkAspects = aspects;
1764 this->sinkAdviseFlag = advf;
1766 IAdviseSink_AddRef(this->sinkInterface);
1770 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1771 * sink immediately.
1773 if (advf & ADVF_PRIMEFIRST)
1775 DataCache_FireOnViewChange(this, aspects, -1);
1778 return S_OK;
1781 /************************************************************************
1782 * DataCache_GetAdvise (IViewObject2)
1784 * This method queries the current state of the advise sink
1785 * installed on the data cache.
1787 * See Windows documentation for more details on IViewObject2 methods.
1789 static HRESULT WINAPI DataCache_GetAdvise(
1790 IViewObject2* iface,
1791 DWORD* pAspects,
1792 DWORD* pAdvf,
1793 IAdviseSink** ppAdvSink)
1795 DataCache *this = impl_from_IViewObject2(iface);
1797 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1800 * Just copy all the requested values.
1802 if (pAspects!=NULL)
1803 *pAspects = this->sinkAspects;
1805 if (pAdvf!=NULL)
1806 *pAdvf = this->sinkAdviseFlag;
1808 if (ppAdvSink!=NULL)
1810 if (this->sinkInterface != NULL)
1811 IAdviseSink_QueryInterface(this->sinkInterface,
1812 &IID_IAdviseSink,
1813 (void**)ppAdvSink);
1814 else *ppAdvSink = NULL;
1817 return S_OK;
1820 /************************************************************************
1821 * DataCache_GetExtent (IViewObject2)
1823 * This method retrieves the "natural" size of this cached object.
1825 * See Windows documentation for more details on IViewObject2 methods.
1827 static HRESULT WINAPI DataCache_GetExtent(
1828 IViewObject2* iface,
1829 DWORD dwDrawAspect,
1830 LONG lindex,
1831 DVTARGETDEVICE* ptd,
1832 LPSIZEL lpsizel)
1834 DataCache *This = impl_from_IViewObject2(iface);
1835 HRESULT hres = E_FAIL;
1836 DataCacheEntry *cache_entry;
1838 TRACE("(%p, %x, %d, %p, %p)\n",
1839 iface, dwDrawAspect, lindex, ptd, lpsizel);
1842 * Sanity check
1844 if (lpsizel==NULL)
1845 return E_POINTER;
1848 * Initialize the out parameter.
1850 lpsizel->cx = 0;
1851 lpsizel->cy = 0;
1854 * This flag should be set to -1.
1856 if (lindex!=-1)
1857 FIXME("Unimplemented flag lindex = %d\n", lindex);
1860 * Right now, we support only the callback from
1861 * the default handler.
1863 if (ptd!=NULL)
1864 FIXME("Unimplemented ptd = %p\n", ptd);
1866 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1868 /* FIXME: compare ptd too */
1869 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1870 (cache_entry->fmtetc.lindex != lindex))
1871 continue;
1873 /* if the data hasn't been loaded yet, do it now */
1874 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1876 hres = DataCacheEntry_LoadData(cache_entry);
1877 if (FAILED(hres))
1878 continue;
1881 /* no data */
1882 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1883 continue;
1886 switch (cache_entry->data_cf)
1888 case CF_METAFILEPICT:
1890 METAFILEPICT *mfpict;
1892 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1893 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1894 continue;
1896 lpsizel->cx = mfpict->xExt;
1897 lpsizel->cy = mfpict->yExt;
1899 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1901 return S_OK;
1906 WARN("no data could be found to get the extents from\n");
1909 * This method returns OLE_E_BLANK when it fails.
1911 return OLE_E_BLANK;
1915 /*********************************************************
1916 * Method implementation for the IOleCache2
1917 * part of the DataCache class.
1920 /************************************************************************
1921 * DataCache_IOleCache2_QueryInterface (IUnknown)
1923 * See Windows documentation for more details on IUnknown methods.
1925 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1926 IOleCache2* iface,
1927 REFIID riid,
1928 void** ppvObject)
1930 DataCache *this = impl_from_IOleCache2(iface);
1932 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1935 /************************************************************************
1936 * DataCache_IOleCache2_AddRef (IUnknown)
1938 * See Windows documentation for more details on IUnknown methods.
1940 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1941 IOleCache2* iface)
1943 DataCache *this = impl_from_IOleCache2(iface);
1945 return IUnknown_AddRef(this->outerUnknown);
1948 /************************************************************************
1949 * DataCache_IOleCache2_Release (IUnknown)
1951 * See Windows documentation for more details on IUnknown methods.
1953 static ULONG WINAPI DataCache_IOleCache2_Release(
1954 IOleCache2* iface)
1956 DataCache *this = impl_from_IOleCache2(iface);
1958 return IUnknown_Release(this->outerUnknown);
1961 static HRESULT WINAPI DataCache_Cache(
1962 IOleCache2* iface,
1963 FORMATETC* pformatetc,
1964 DWORD advf,
1965 DWORD* pdwConnection)
1967 DataCache *This = impl_from_IOleCache2(iface);
1968 DataCacheEntry *cache_entry;
1969 HRESULT hr;
1971 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1972 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1974 *pdwConnection = 0;
1976 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1977 if (cache_entry)
1979 TRACE("found an existing cache entry\n");
1980 *pdwConnection = cache_entry->id;
1981 return CACHE_S_SAMECACHE;
1984 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1986 if (SUCCEEDED(hr))
1987 *pdwConnection = cache_entry->id;
1989 return hr;
1992 static HRESULT WINAPI DataCache_Uncache(
1993 IOleCache2* iface,
1994 DWORD dwConnection)
1996 DataCache *This = impl_from_IOleCache2(iface);
1997 DataCacheEntry *cache_entry;
1999 TRACE("(%d)\n", dwConnection);
2001 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2002 if (cache_entry->id == dwConnection)
2004 DataCacheEntry_Destroy(cache_entry);
2005 return S_OK;
2008 WARN("no connection found for %d\n", dwConnection);
2010 return OLE_E_NOCONNECTION;
2013 static HRESULT WINAPI DataCache_EnumCache(
2014 IOleCache2* iface,
2015 IEnumSTATDATA** ppenumSTATDATA)
2017 FIXME("stub\n");
2018 return E_NOTIMPL;
2021 static HRESULT WINAPI DataCache_InitCache(
2022 IOleCache2* iface,
2023 IDataObject* pDataObject)
2025 FIXME("stub\n");
2026 return E_NOTIMPL;
2029 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2030 IOleCache2* iface,
2031 FORMATETC* pformatetc,
2032 STGMEDIUM* pmedium,
2033 BOOL fRelease)
2035 DataCache *This = impl_from_IOleCache2(iface);
2036 DataCacheEntry *cache_entry;
2037 HRESULT hr;
2039 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2040 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2042 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2043 if (cache_entry)
2045 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2047 if (SUCCEEDED(hr))
2048 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2049 cache_entry->fmtetc.lindex);
2051 return hr;
2053 WARN("cache entry not found\n");
2055 return OLE_E_BLANK;
2058 static HRESULT WINAPI DataCache_UpdateCache(
2059 IOleCache2* iface,
2060 LPDATAOBJECT pDataObject,
2061 DWORD grfUpdf,
2062 LPVOID pReserved)
2064 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2065 return E_NOTIMPL;
2068 static HRESULT WINAPI DataCache_DiscardCache(
2069 IOleCache2* iface,
2070 DWORD dwDiscardOptions)
2072 DataCache *This = impl_from_IOleCache2(iface);
2073 DataCacheEntry *cache_entry;
2074 HRESULT hr = S_OK;
2076 TRACE("(%d)\n", dwDiscardOptions);
2078 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2079 hr = DataCache_Save((IPersistStorage *)&This->lpvtblIPersistStorage,
2080 This->presentationStorage, TRUE);
2082 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2084 hr = DataCacheEntry_DiscardData(cache_entry);
2085 if (FAILED(hr))
2086 break;
2089 return hr;
2093 /*********************************************************
2094 * Method implementation for the IOleCacheControl
2095 * part of the DataCache class.
2098 /************************************************************************
2099 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2101 * See Windows documentation for more details on IUnknown methods.
2103 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2104 IOleCacheControl* iface,
2105 REFIID riid,
2106 void** ppvObject)
2108 DataCache *this = impl_from_IOleCacheControl(iface);
2110 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2113 /************************************************************************
2114 * DataCache_IOleCacheControl_AddRef (IUnknown)
2116 * See Windows documentation for more details on IUnknown methods.
2118 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2119 IOleCacheControl* iface)
2121 DataCache *this = impl_from_IOleCacheControl(iface);
2123 return IUnknown_AddRef(this->outerUnknown);
2126 /************************************************************************
2127 * DataCache_IOleCacheControl_Release (IUnknown)
2129 * See Windows documentation for more details on IUnknown methods.
2131 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2132 IOleCacheControl* iface)
2134 DataCache *this = impl_from_IOleCacheControl(iface);
2136 return IUnknown_Release(this->outerUnknown);
2139 static HRESULT WINAPI DataCache_OnRun(
2140 IOleCacheControl* iface,
2141 LPDATAOBJECT pDataObject)
2143 FIXME("stub\n");
2144 return E_NOTIMPL;
2147 static HRESULT WINAPI DataCache_OnStop(
2148 IOleCacheControl* iface)
2150 FIXME("stub\n");
2151 return E_NOTIMPL;
2155 * Virtual function tables for the DataCache class.
2157 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2159 DataCache_NDIUnknown_QueryInterface,
2160 DataCache_NDIUnknown_AddRef,
2161 DataCache_NDIUnknown_Release
2164 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2166 DataCache_IDataObject_QueryInterface,
2167 DataCache_IDataObject_AddRef,
2168 DataCache_IDataObject_Release,
2169 DataCache_GetData,
2170 DataCache_GetDataHere,
2171 DataCache_QueryGetData,
2172 DataCache_GetCanonicalFormatEtc,
2173 DataCache_IDataObject_SetData,
2174 DataCache_EnumFormatEtc,
2175 DataCache_DAdvise,
2176 DataCache_DUnadvise,
2177 DataCache_EnumDAdvise
2180 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2182 DataCache_IPersistStorage_QueryInterface,
2183 DataCache_IPersistStorage_AddRef,
2184 DataCache_IPersistStorage_Release,
2185 DataCache_GetClassID,
2186 DataCache_IsDirty,
2187 DataCache_InitNew,
2188 DataCache_Load,
2189 DataCache_Save,
2190 DataCache_SaveCompleted,
2191 DataCache_HandsOffStorage
2194 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2196 DataCache_IViewObject2_QueryInterface,
2197 DataCache_IViewObject2_AddRef,
2198 DataCache_IViewObject2_Release,
2199 DataCache_Draw,
2200 DataCache_GetColorSet,
2201 DataCache_Freeze,
2202 DataCache_Unfreeze,
2203 DataCache_SetAdvise,
2204 DataCache_GetAdvise,
2205 DataCache_GetExtent
2208 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2210 DataCache_IOleCache2_QueryInterface,
2211 DataCache_IOleCache2_AddRef,
2212 DataCache_IOleCache2_Release,
2213 DataCache_Cache,
2214 DataCache_Uncache,
2215 DataCache_EnumCache,
2216 DataCache_InitCache,
2217 DataCache_IOleCache2_SetData,
2218 DataCache_UpdateCache,
2219 DataCache_DiscardCache
2222 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2224 DataCache_IOleCacheControl_QueryInterface,
2225 DataCache_IOleCacheControl_AddRef,
2226 DataCache_IOleCacheControl_Release,
2227 DataCache_OnRun,
2228 DataCache_OnStop
2231 /******************************************************************************
2232 * CreateDataCache [OLE32.@]
2234 * Creates a data cache to allow an object to render one or more of its views,
2235 * whether running or not.
2237 * PARAMS
2238 * pUnkOuter [I] Outer unknown for the object.
2239 * rclsid [I]
2240 * riid [I] IID of interface to return.
2241 * ppvObj [O] Address where the data cache object will be stored on return.
2243 * RETURNS
2244 * Success: S_OK.
2245 * Failure: HRESULT code.
2247 * NOTES
2248 * The following interfaces are supported by the returned data cache object:
2249 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorae, IDataObject,
2250 * IViewObject and IViewObject2.
2252 HRESULT WINAPI CreateDataCache(
2253 LPUNKNOWN pUnkOuter,
2254 REFCLSID rclsid,
2255 REFIID riid,
2256 LPVOID* ppvObj)
2258 DataCache* newCache = NULL;
2259 HRESULT hr = S_OK;
2261 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2264 * Sanity check
2266 if (ppvObj==0)
2267 return E_POINTER;
2269 *ppvObj = 0;
2272 * If this cache is constructed for aggregation, make sure
2273 * the caller is requesting the IUnknown interface.
2274 * This is necessary because it's the only time the non-delegating
2275 * IUnknown pointer can be returned to the outside.
2277 if ( (pUnkOuter!=NULL) &&
2278 (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
2279 return CLASS_E_NOAGGREGATION;
2282 * Try to construct a new instance of the class.
2284 newCache = DataCache_Construct(rclsid,
2285 pUnkOuter);
2287 if (newCache == 0)
2288 return E_OUTOFMEMORY;
2291 * Make sure it supports the interface required by the caller.
2293 hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
2296 * Release the reference obtained in the constructor. If
2297 * the QueryInterface was unsuccessful, it will free the class.
2299 IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
2301 return hr;
2304 /*********************************************************
2305 * Method implementation for DataCache class.
2307 static DataCache* DataCache_Construct(
2308 REFCLSID clsid,
2309 LPUNKNOWN pUnkOuter)
2311 DataCache* newObject = 0;
2314 * Allocate space for the object.
2316 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2318 if (newObject==0)
2319 return newObject;
2322 * Initialize the virtual function table.
2324 newObject->lpVtbl = &DataCache_IDataObject_VTable;
2325 newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
2326 newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
2327 newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
2328 newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
2329 newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
2332 * Start with one reference count. The caller of this function
2333 * must release the interface pointer when it is done.
2335 newObject->ref = 1;
2338 * Initialize the outer unknown
2339 * We don't keep a reference on the outer unknown since, the way
2340 * aggregation works, our lifetime is at least as large as its
2341 * lifetime.
2343 if (pUnkOuter==NULL)
2344 pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
2346 newObject->outerUnknown = pUnkOuter;
2349 * Initialize the other members of the structure.
2351 newObject->sinkAspects = 0;
2352 newObject->sinkAdviseFlag = 0;
2353 newObject->sinkInterface = 0;
2354 newObject->presentationStorage = NULL;
2355 list_init(&newObject->cache_list);
2356 newObject->last_cache_id = 1;
2357 newObject->dirty = FALSE;
2359 return newObject;