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
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,
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.
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
58 #include "wine/unicode.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 * Most fields are still unknown.
73 typedef struct PresentationDataHeader
75 DWORD unknown1; /* -1 */
77 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
81 DWORD unknown7; /* 0 */
82 DWORD dwObjectExtentX;
83 DWORD dwObjectExtentY;
85 } PresentationDataHeader;
87 typedef struct DataCacheEntry
90 /* format of this entry */
92 /* the clipboard format of the data */
97 * This storage pointer is set through a call to
98 * IPersistStorage_Load. This is where the visual
99 * representation of the object is stored.
106 /* stream number (-1 if not set ) */
107 unsigned short stream_number;
110 /****************************************************************************
116 * List all interface VTables here
118 const IDataObjectVtbl* lpVtbl;
119 const IUnknownVtbl* lpvtblNDIUnknown;
120 const IPersistStorageVtbl* lpvtblIPersistStorage;
121 const IViewObject2Vtbl* lpvtblIViewObject;
122 const IOleCache2Vtbl* lpvtblIOleCache2;
123 const IOleCacheControlVtbl* lpvtblIOleCacheControl;
126 * Reference count of this object
131 * IUnknown implementation of the outer object.
133 IUnknown* outerUnknown;
136 * The user of this object can setup ONE advise sink
137 * connection with the object. These parameters describe
141 DWORD sinkAdviseFlag;
142 IAdviseSink* sinkInterface;
143 IStorage *presentationStorage;
145 /* list of cache entries */
146 struct list cache_list;
147 /* last id assigned to an entry */
153 typedef struct DataCache DataCache;
156 * Here, I define utility macros to help with the casting of the
158 * There is a version to accommodate all of the VTables implemented
162 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
164 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpVtbl));
167 static inline DataCache *impl_from_NDIUnknown( IUnknown *iface )
169 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblNDIUnknown));
172 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
174 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIPersistStorage));
177 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
179 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIViewObject));
182 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
184 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCache2));
187 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
189 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCacheControl));
192 static const char * debugstr_formatetc(const FORMATETC *formatetc)
194 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
195 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
196 formatetc->lindex, formatetc->tymed);
200 * Prototypes for the methods of the DataCache class.
202 static DataCache* DataCache_Construct(REFCLSID clsid,
203 LPUNKNOWN pUnkOuter);
204 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *This,
207 static void DataCacheEntry_Destroy(DataCacheEntry *This)
209 list_remove(&This->entry);
211 IStorage_Release(This->storage);
212 HeapFree(GetProcessHeap(), 0, This->fmtetc.ptd);
213 ReleaseStgMedium(&This->stgmedium);
214 HeapFree(GetProcessHeap(), 0, This);
217 static void DataCache_Destroy(
218 DataCache* ptrToDestroy)
220 DataCacheEntry *cache_entry, *next_cache_entry;
224 if (ptrToDestroy->sinkInterface != NULL)
226 IAdviseSink_Release(ptrToDestroy->sinkInterface);
227 ptrToDestroy->sinkInterface = NULL;
230 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
231 DataCacheEntry_Destroy(cache_entry);
234 * Free the datacache pointer.
236 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
239 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
241 DataCacheEntry *cache_entry;
242 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
244 /* FIXME: also compare DVTARGETDEVICEs */
245 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
246 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
247 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
248 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
254 /* checks that the clipformat and tymed are valid and returns an error if they
255 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
257 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
259 if (!cfFormat || !tymed ||
260 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
261 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
262 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
263 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
265 else if (tymed == TYMED_HGLOBAL)
266 return CACHE_S_FORMATETC_NOTSUPPORTED;
269 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
274 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
278 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
281 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
282 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
284 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
286 return E_OUTOFMEMORY;
288 (*cache_entry)->fmtetc = *formatetc;
291 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
292 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
294 (*cache_entry)->stgmedium.tymed = TYMED_NULL;
295 (*cache_entry)->stgmedium.pUnkForRelease = NULL;
296 (*cache_entry)->storage = NULL;
297 (*cache_entry)->id = This->last_cache_id++;
298 (*cache_entry)->dirty = TRUE;
299 (*cache_entry)->stream_number = -1;
300 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
304 /************************************************************************
305 * DataCache_FireOnViewChange
307 * This method will fire an OnViewChange notification to the advise
308 * sink registered with the datacache.
310 * See IAdviseSink::OnViewChange for more details.
312 static void DataCache_FireOnViewChange(
317 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
320 * The sink supplies a filter when it registers
321 * we make sure we only send the notifications when that
324 if ((this->sinkAspects & aspect) != 0)
326 if (this->sinkInterface != NULL)
328 IAdviseSink_OnViewChange(this->sinkInterface,
333 * Some sinks want to be unregistered automatically when
334 * the first notification goes out.
336 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
338 IAdviseSink_Release(this->sinkInterface);
340 this->sinkInterface = NULL;
341 this->sinkAspects = 0;
342 this->sinkAdviseFlag = 0;
348 /* Helper for DataCacheEntry_OpenPresStream */
349 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
351 /* The presentation streams have names of the form "\002OlePresXXX",
352 * where XXX goes from 000 to 999. */
353 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
355 LPCWSTR name = elem->pwcsName;
357 return (elem->type == STGTY_STREAM)
358 && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader))
359 && (strlenW(name) == 11)
360 && (strncmpW(name, OlePres, 8) == 0)
361 && (name[8] >= '0') && (name[8] <= '9')
362 && (name[9] >= '0') && (name[9] <= '9')
363 && (name[10] >= '0') && (name[10] <= '9');
366 /************************************************************************
367 * DataCacheEntry_OpenPresStream
369 * This method will find the stream for the given presentation. It makes
370 * no attempt at fallback.
373 * this - Pointer to the DataCache object
374 * drawAspect - The aspect of the object that we wish to draw.
375 * pStm - A returned stream. It points to the beginning of the
376 * - presentation data, including the header.
379 * S_OK The requested stream has been opened.
380 * OLE_E_BLANK The requested stream could not be found.
381 * Quite a few others I'm too lazy to map correctly.
384 * Algorithm: Scan the elements of the presentation storage, looking
385 * for presentation streams. For each presentation stream,
386 * load the header and check to see if the aspect matches.
388 * If a fallback is desired, just opening the first presentation stream
391 static HRESULT DataCacheEntry_OpenPresStream(
392 DataCacheEntry *This,
399 if (!ppStm) return E_POINTER;
401 hr = IStorage_EnumElements(This->storage, 0, NULL, 0, &pEnum);
402 if (FAILED(hr)) return hr;
404 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
406 if (DataCache_IsPresentationStream(&elem))
410 hr = IStorage_OpenStream(This->storage, elem.pwcsName,
411 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
415 PresentationDataHeader header;
418 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
420 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
421 if (hr == S_OK && actual_read == sizeof(header)
422 && header.dvAspect == This->fmtetc.dwAspect)
424 /* Rewind the stream before returning it. */
425 LARGE_INTEGER offset;
426 offset.u.LowPart = 0;
427 offset.u.HighPart = 0;
428 IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
432 CoTaskMemFree(elem.pwcsName);
433 IEnumSTATSTG_Release(pEnum);
438 IStream_Release(pStm);
442 CoTaskMemFree(elem.pwcsName);
445 IEnumSTATSTG_Release(pEnum);
447 return (hr == S_FALSE ? OLE_E_BLANK : hr);
450 /************************************************************************
451 * DataCacheEntry_LoadData
453 * This method will read information for the requested presentation
454 * into the given structure.
457 * This - The entry to load the data from.
460 * This method returns a metafile handle if it is successful.
461 * it will return 0 if not.
463 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *This)
465 IStream* presStream = NULL;
469 METAFILEPICT *mfpict;
471 PresentationDataHeader header;
474 * Open the presentation stream.
476 hres = DataCacheEntry_OpenPresStream(
484 * Get the size of the stream.
486 hres = IStream_Stat(presStream,
497 sizeof(PresentationDataHeader),
500 streamInfo.cbSize.QuadPart -= sizeof(PresentationDataHeader);
502 hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
505 IStream_Release(presStream);
506 return E_OUTOFMEMORY;
508 mfpict = GlobalLock(hmfpict);
511 * Allocate a buffer for the metafile bits.
513 metafileBits = HeapAlloc(GetProcessHeap(),
515 streamInfo.cbSize.u.LowPart);
518 * Read the metafile bits.
523 streamInfo.cbSize.u.LowPart,
527 * Create a metafile with those bits.
531 /* FIXME: get this from the stream */
532 mfpict->mm = MM_ANISOTROPIC;
533 mfpict->xExt = header.dwObjectExtentX;
534 mfpict->yExt = header.dwObjectExtentY;
535 mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
540 GlobalUnlock(hmfpict);
543 This->data_cf = This->fmtetc.cfFormat;
544 This->stgmedium.tymed = TYMED_MFPICT;
545 This->stgmedium.u.hMetaFilePict = hmfpict;
553 HeapFree(GetProcessHeap(), 0, metafileBits);
554 IStream_Release(presStream);
559 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This,
560 IStorage *storage, IStream **stream)
563 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
564 '0' + (This->stream_number / 100) % 10,
565 '0' + (This->stream_number / 10) % 10,
566 '0' + This->stream_number % 10, 0};
568 /* FIXME: cache the created stream in This? */
569 hr = IStorage_CreateStream(storage, wszName,
570 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
575 static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
578 PresentationDataHeader header;
580 IStream *pres_stream;
583 TRACE("stream_number = %d, fmtetc = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc));
585 hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
589 /* custom clipformat */
590 if (This->data_cf >= 0xc000)
591 FIXME("custom clipboard format not serialized properly\n");
592 header.unknown1 = -1;
593 header.clipformat = This->data_cf;
594 if (This->fmtetc.ptd)
595 FIXME("ptd not serialized\n");
597 header.dvAspect = This->fmtetc.dwAspect;
598 header.lindex = This->fmtetc.lindex;
599 header.tymed = This->stgmedium.tymed;
601 header.dwObjectExtentX = 0;
602 header.dwObjectExtentY = 0;
606 switch (This->data_cf)
608 case CF_METAFILEPICT:
610 if (This->stgmedium.tymed != TYMED_NULL)
612 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
615 IStream_Release(pres_stream);
616 return DV_E_STGMEDIUM;
618 header.dwObjectExtentX = mfpict->xExt;
619 header.dwObjectExtentY = mfpict->yExt;
620 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
621 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
632 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
636 IStream_Release(pres_stream);
641 switch (This->data_cf)
643 case CF_METAFILEPICT:
645 if (This->stgmedium.tymed != TYMED_NULL)
647 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
650 IStream_Release(pres_stream);
651 return DV_E_STGMEDIUM;
653 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
654 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
655 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
664 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
666 IStream_Release(pres_stream);
670 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
671 * does no checking of whether src_stgm has a supported tymed, so this should be
672 * done in the caller */
673 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
674 const STGMEDIUM *src_stgm)
676 if (src_stgm->tymed == TYMED_MFPICT)
678 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
679 METAFILEPICT *dest_mfpict;
682 return DV_E_STGMEDIUM;
683 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
684 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
687 GlobalUnlock(src_stgm->u.hMetaFilePict);
688 return E_OUTOFMEMORY;
690 *dest_mfpict = *src_mfpict;
691 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
692 GlobalUnlock(src_stgm->u.hMetaFilePict);
693 GlobalUnlock(dest_stgm->u.hMetaFilePict);
695 else if (src_stgm->tymed != TYMED_NULL)
697 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
699 if (!dest_stgm->u.hGlobal)
700 return E_OUTOFMEMORY;
702 dest_stgm->tymed = src_stgm->tymed;
703 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
704 if (dest_stgm->pUnkForRelease)
705 IUnknown_AddRef(dest_stgm->pUnkForRelease);
709 static HRESULT DataCacheEntry_SetData(DataCacheEntry *This,
710 const FORMATETC *formatetc,
711 const STGMEDIUM *stgmedium,
714 if ((!This->fmtetc.cfFormat && !formatetc->cfFormat) ||
715 (This->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
716 stgmedium->tymed == TYMED_NULL)
718 WARN("invalid formatetc\n");
719 return DV_E_FORMATETC;
723 ReleaseStgMedium(&This->stgmedium);
724 This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat;
727 This->stgmedium = *stgmedium;
731 return copy_stg_medium(This->data_cf,
732 &This->stgmedium, stgmedium);
735 static HRESULT DataCacheEntry_GetData(DataCacheEntry *This,
736 STGMEDIUM *stgmedium)
738 if (stgmedium->tymed == TYMED_NULL && This->storage)
740 HRESULT hr = DataCacheEntry_LoadData(This);
744 if (stgmedium->tymed == TYMED_NULL)
746 return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium);
749 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
751 ReleaseStgMedium(&This->stgmedium);
752 This->data_cf = This->fmtetc.cfFormat;
756 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This)
760 IStorage_Release(This->storage);
761 This->storage = NULL;
765 /*********************************************************
766 * Method implementation for the non delegating IUnknown
767 * part of the DataCache class.
770 /************************************************************************
771 * DataCache_NDIUnknown_QueryInterface (IUnknown)
773 * See Windows documentation for more details on IUnknown methods.
775 * This version of QueryInterface will not delegate it's implementation
776 * to the outer unknown.
778 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
783 DataCache *this = impl_from_NDIUnknown(iface);
786 * Perform a sanity check on the parameters.
788 if ( (this==0) || (ppvObject==0) )
792 * Initialize the return parameter.
797 * Compare the riid with the interface IDs implemented by this object.
799 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
803 else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
805 *ppvObject = (IDataObject*)&(this->lpVtbl);
807 else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) ||
808 (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
810 *ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
812 else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
813 (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
815 *ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
817 else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
818 (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
820 *ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
822 else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
824 *ppvObject = (IOleCacheControl*)&(this->lpvtblIOleCacheControl);
828 * Check that we obtained an interface.
832 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
833 return E_NOINTERFACE;
837 * Query Interface always increases the reference count by one when it is
840 IUnknown_AddRef((IUnknown*)*ppvObject);
845 /************************************************************************
846 * DataCache_NDIUnknown_AddRef (IUnknown)
848 * See Windows documentation for more details on IUnknown methods.
850 * This version of QueryInterface will not delegate it's implementation
851 * to the outer unknown.
853 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
856 DataCache *this = impl_from_NDIUnknown(iface);
857 return InterlockedIncrement(&this->ref);
860 /************************************************************************
861 * DataCache_NDIUnknown_Release (IUnknown)
863 * See Windows documentation for more details on IUnknown methods.
865 * This version of QueryInterface will not delegate it's implementation
866 * to the outer unknown.
868 static ULONG WINAPI DataCache_NDIUnknown_Release(
871 DataCache *this = impl_from_NDIUnknown(iface);
875 * Decrease the reference count on this object.
877 ref = InterlockedDecrement(&this->ref);
880 * If the reference count goes down to 0, perform suicide.
882 if (ref == 0) DataCache_Destroy(this);
887 /*********************************************************
888 * Method implementation for the IDataObject
889 * part of the DataCache class.
892 /************************************************************************
893 * DataCache_IDataObject_QueryInterface (IUnknown)
895 * See Windows documentation for more details on IUnknown methods.
897 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
902 DataCache *this = impl_from_IDataObject(iface);
904 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
907 /************************************************************************
908 * DataCache_IDataObject_AddRef (IUnknown)
910 * See Windows documentation for more details on IUnknown methods.
912 static ULONG WINAPI DataCache_IDataObject_AddRef(
915 DataCache *this = impl_from_IDataObject(iface);
917 return IUnknown_AddRef(this->outerUnknown);
920 /************************************************************************
921 * DataCache_IDataObject_Release (IUnknown)
923 * See Windows documentation for more details on IUnknown methods.
925 static ULONG WINAPI DataCache_IDataObject_Release(
928 DataCache *this = impl_from_IDataObject(iface);
930 return IUnknown_Release(this->outerUnknown);
933 /************************************************************************
936 * Get Data from a source dataobject using format pformatetcIn->cfFormat
937 * See Windows documentation for more details on GetData.
939 static HRESULT WINAPI DataCache_GetData(
941 LPFORMATETC pformatetcIn,
944 DataCache *This = impl_from_IDataObject(iface);
945 DataCacheEntry *cache_entry;
947 memset(pmedium, 0, sizeof(*pmedium));
949 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
953 return DataCacheEntry_GetData(cache_entry, pmedium);
956 static HRESULT WINAPI DataCache_GetDataHere(
958 LPFORMATETC pformatetc,
965 static HRESULT WINAPI DataCache_QueryGetData(
967 LPFORMATETC pformatetc)
973 /************************************************************************
974 * DataCache_EnumFormatEtc (IDataObject)
976 * The data cache doesn't implement this method.
978 * See Windows documentation for more details on IDataObject methods.
980 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
982 LPFORMATETC pformatectIn,
983 LPFORMATETC pformatetcOut)
989 /************************************************************************
990 * DataCache_IDataObject_SetData (IDataObject)
992 * This method is delegated to the IOleCache2 implementation.
994 * See Windows documentation for more details on IDataObject methods.
996 static HRESULT WINAPI DataCache_IDataObject_SetData(
998 LPFORMATETC pformatetc,
1002 IOleCache2* oleCache = NULL;
1005 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1007 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1010 return E_UNEXPECTED;
1012 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1014 IOleCache2_Release(oleCache);
1019 /************************************************************************
1020 * DataCache_EnumFormatEtc (IDataObject)
1022 * The data cache doesn't implement this method.
1024 * See Windows documentation for more details on IDataObject methods.
1026 static HRESULT WINAPI DataCache_EnumFormatEtc(
1029 IEnumFORMATETC** ppenumFormatEtc)
1035 /************************************************************************
1036 * DataCache_DAdvise (IDataObject)
1038 * The data cache doesn't support connections.
1040 * See Windows documentation for more details on IDataObject methods.
1042 static HRESULT WINAPI DataCache_DAdvise(
1044 FORMATETC* pformatetc,
1046 IAdviseSink* pAdvSink,
1047 DWORD* pdwConnection)
1050 return OLE_E_ADVISENOTSUPPORTED;
1053 /************************************************************************
1054 * DataCache_DUnadvise (IDataObject)
1056 * The data cache doesn't support connections.
1058 * See Windows documentation for more details on IDataObject methods.
1060 static HRESULT WINAPI DataCache_DUnadvise(
1065 return OLE_E_NOCONNECTION;
1068 /************************************************************************
1069 * DataCache_EnumDAdvise (IDataObject)
1071 * The data cache doesn't support connections.
1073 * See Windows documentation for more details on IDataObject methods.
1075 static HRESULT WINAPI DataCache_EnumDAdvise(
1077 IEnumSTATDATA** ppenumAdvise)
1080 return OLE_E_ADVISENOTSUPPORTED;
1083 /*********************************************************
1084 * Method implementation for the IDataObject
1085 * part of the DataCache class.
1088 /************************************************************************
1089 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1091 * See Windows documentation for more details on IUnknown methods.
1093 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1094 IPersistStorage* iface,
1098 DataCache *this = impl_from_IPersistStorage(iface);
1100 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1103 /************************************************************************
1104 * DataCache_IPersistStorage_AddRef (IUnknown)
1106 * See Windows documentation for more details on IUnknown methods.
1108 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1109 IPersistStorage* iface)
1111 DataCache *this = impl_from_IPersistStorage(iface);
1113 return IUnknown_AddRef(this->outerUnknown);
1116 /************************************************************************
1117 * DataCache_IPersistStorage_Release (IUnknown)
1119 * See Windows documentation for more details on IUnknown methods.
1121 static ULONG WINAPI DataCache_IPersistStorage_Release(
1122 IPersistStorage* iface)
1124 DataCache *this = impl_from_IPersistStorage(iface);
1126 return IUnknown_Release(this->outerUnknown);
1129 /************************************************************************
1130 * DataCache_GetClassID (IPersistStorage)
1132 * The data cache doesn't implement this method.
1134 * See Windows documentation for more details on IPersistStorage methods.
1136 static HRESULT WINAPI DataCache_GetClassID(
1137 IPersistStorage* iface,
1140 DataCache *This = impl_from_IPersistStorage(iface);
1141 DataCacheEntry *cache_entry;
1143 TRACE("(%p, %p)\n", iface, pClassID);
1145 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1147 if (cache_entry->storage != NULL)
1150 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1153 memcpy(pClassID, &statstg.clsid, sizeof(*pClassID));
1159 memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID));
1164 /************************************************************************
1165 * DataCache_IsDirty (IPersistStorage)
1167 * See Windows documentation for more details on IPersistStorage methods.
1169 static HRESULT WINAPI DataCache_IsDirty(
1170 IPersistStorage* iface)
1172 DataCache *This = impl_from_IPersistStorage(iface);
1173 DataCacheEntry *cache_entry;
1175 TRACE("(%p)\n", iface);
1180 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1181 if (cache_entry->dirty)
1187 /************************************************************************
1188 * DataCache_InitNew (IPersistStorage)
1190 * The data cache implementation of IPersistStorage_InitNew simply stores
1191 * the storage pointer.
1193 * See Windows documentation for more details on IPersistStorage methods.
1195 static HRESULT WINAPI DataCache_InitNew(
1196 IPersistStorage* iface,
1199 DataCache *This = impl_from_IPersistStorage(iface);
1201 TRACE("(%p, %p)\n", iface, pStg);
1203 if (This->presentationStorage != NULL)
1204 IStorage_Release(This->presentationStorage);
1206 This->presentationStorage = pStg;
1208 IStorage_AddRef(This->presentationStorage);
1214 /************************************************************************
1215 * DataCache_Load (IPersistStorage)
1217 * The data cache implementation of IPersistStorage_Load doesn't
1218 * actually load anything. Instead, it holds on to the storage pointer
1219 * and it will load the presentation information when the
1220 * IDataObject_GetData or IViewObject2_Draw methods are called.
1222 * See Windows documentation for more details on IPersistStorage methods.
1224 static HRESULT WINAPI DataCache_Load(
1225 IPersistStorage* iface,
1228 DataCache *This = impl_from_IPersistStorage(iface);
1230 IEnumSTATSTG *pEnum;
1233 TRACE("(%p, %p)\n", iface, pStg);
1235 if (This->presentationStorage != NULL)
1236 IStorage_Release(This->presentationStorage);
1238 This->presentationStorage = pStg;
1240 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1241 if (FAILED(hr)) return hr;
1243 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1245 if (DataCache_IsPresentationStream(&elem))
1249 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1250 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1254 PresentationDataHeader header;
1257 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
1259 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1260 if (hr == S_OK && actual_read == sizeof(header))
1262 DataCacheEntry *cache_entry;
1265 fmtetc.cfFormat = header.clipformat;
1266 fmtetc.ptd = NULL; /* FIXME */
1267 fmtetc.dwAspect = header.dvAspect;
1268 fmtetc.lindex = header.lindex;
1269 fmtetc.tymed = header.tymed;
1271 TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1273 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1275 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1278 DataCacheEntry_DiscardData(cache_entry);
1279 if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1280 cache_entry->storage = pStg;
1281 IStorage_AddRef(pStg);
1282 cache_entry->dirty = FALSE;
1286 IStream_Release(pStm);
1290 CoTaskMemFree(elem.pwcsName);
1293 This->dirty = FALSE;
1295 IEnumSTATSTG_Release(pEnum);
1297 IStorage_AddRef(This->presentationStorage);
1301 /************************************************************************
1302 * DataCache_Save (IPersistStorage)
1304 * Until we actually connect to a running object and retrieve new
1305 * information to it, we never have to save anything. However, it is
1306 * our responsibility to copy the information when saving to a new
1309 * See Windows documentation for more details on IPersistStorage methods.
1311 static HRESULT WINAPI DataCache_Save(
1312 IPersistStorage* iface,
1316 DataCache *This = impl_from_IPersistStorage(iface);
1317 DataCacheEntry *cache_entry;
1320 unsigned short stream_number = 0;
1322 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1324 dirty = This->dirty;
1327 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1329 dirty = cache_entry->dirty;
1335 /* this is a shortcut if nothing changed */
1336 if (!dirty && !fSameAsLoad && This->presentationStorage)
1338 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1341 /* assign stream numbers to the cache entries */
1342 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1344 if (cache_entry->stream_number != stream_number)
1346 cache_entry->dirty = TRUE; /* needs to be written out again */
1347 cache_entry->stream_number = stream_number;
1352 /* write out the cache entries */
1353 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1355 if (!fSameAsLoad || cache_entry->dirty)
1357 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1361 cache_entry->dirty = FALSE;
1365 This->dirty = FALSE;
1369 /************************************************************************
1370 * DataCache_SaveCompleted (IPersistStorage)
1372 * This method is called to tell the cache to release the storage
1373 * pointer it's currently holding.
1375 * See Windows documentation for more details on IPersistStorage methods.
1377 static HRESULT WINAPI DataCache_SaveCompleted(
1378 IPersistStorage* iface,
1381 TRACE("(%p, %p)\n", iface, pStgNew);
1386 * First, make sure we get our hands off any storage we have.
1389 IPersistStorage_HandsOffStorage(iface);
1392 * Then, attach to the new storage.
1395 DataCache_Load(iface, pStgNew);
1401 /************************************************************************
1402 * DataCache_HandsOffStorage (IPersistStorage)
1404 * This method is called to tell the cache to release the storage
1405 * pointer it's currently holding.
1407 * See Windows documentation for more details on IPersistStorage methods.
1409 static HRESULT WINAPI DataCache_HandsOffStorage(
1410 IPersistStorage* iface)
1412 DataCache *this = impl_from_IPersistStorage(iface);
1413 DataCacheEntry *cache_entry;
1415 TRACE("(%p)\n", iface);
1417 if (this->presentationStorage != NULL)
1419 IStorage_Release(this->presentationStorage);
1420 this->presentationStorage = NULL;
1423 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1424 DataCacheEntry_HandsOffStorage(cache_entry);
1429 /*********************************************************
1430 * Method implementation for the IViewObject2
1431 * part of the DataCache class.
1434 /************************************************************************
1435 * DataCache_IViewObject2_QueryInterface (IUnknown)
1437 * See Windows documentation for more details on IUnknown methods.
1439 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1440 IViewObject2* iface,
1444 DataCache *this = impl_from_IViewObject2(iface);
1446 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1449 /************************************************************************
1450 * DataCache_IViewObject2_AddRef (IUnknown)
1452 * See Windows documentation for more details on IUnknown methods.
1454 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1455 IViewObject2* iface)
1457 DataCache *this = impl_from_IViewObject2(iface);
1459 return IUnknown_AddRef(this->outerUnknown);
1462 /************************************************************************
1463 * DataCache_IViewObject2_Release (IUnknown)
1465 * See Windows documentation for more details on IUnknown methods.
1467 static ULONG WINAPI DataCache_IViewObject2_Release(
1468 IViewObject2* iface)
1470 DataCache *this = impl_from_IViewObject2(iface);
1472 return IUnknown_Release(this->outerUnknown);
1475 /************************************************************************
1476 * DataCache_Draw (IViewObject2)
1478 * This method will draw the cached representation of the object
1479 * to the given device context.
1481 * See Windows documentation for more details on IViewObject2 methods.
1483 static HRESULT WINAPI DataCache_Draw(
1484 IViewObject2* iface,
1488 DVTARGETDEVICE* ptd,
1491 LPCRECTL lprcBounds,
1492 LPCRECTL lprcWBounds,
1493 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1494 ULONG_PTR dwContinue)
1496 DataCache *This = impl_from_IViewObject2(iface);
1498 DataCacheEntry *cache_entry;
1500 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1515 if (lprcBounds==NULL)
1516 return E_INVALIDARG;
1518 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1520 /* FIXME: compare ptd too */
1521 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1522 (cache_entry->fmtetc.lindex != lindex))
1525 /* if the data hasn't been loaded yet, do it now */
1526 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1528 hres = DataCacheEntry_LoadData(cache_entry);
1534 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1537 switch (cache_entry->data_cf)
1539 case CF_METAFILEPICT:
1542 * We have to be careful not to modify the state of the
1547 SIZE oldViewportExt;
1548 POINT oldViewportOrg;
1549 METAFILEPICT *mfpict;
1551 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1552 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1555 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1557 SetWindowExtEx(hdcDraw,
1562 SetViewportExtEx(hdcDraw,
1563 lprcBounds->right - lprcBounds->left,
1564 lprcBounds->bottom - lprcBounds->top,
1567 SetViewportOrgEx(hdcDraw,
1572 PlayMetaFile(hdcDraw, mfpict->hMF);
1574 SetWindowExtEx(hdcDraw,
1579 SetViewportExtEx(hdcDraw,
1584 SetViewportOrgEx(hdcDraw,
1589 SetMapMode(hdcDraw, prevMapMode);
1591 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1598 WARN("no data could be found to be drawn\n");
1603 static HRESULT WINAPI DataCache_GetColorSet(
1604 IViewObject2* iface,
1608 DVTARGETDEVICE* ptd,
1609 HDC hicTargetDevice,
1610 LOGPALETTE** ppColorSet)
1616 static HRESULT WINAPI DataCache_Freeze(
1617 IViewObject2* iface,
1627 static HRESULT WINAPI DataCache_Unfreeze(
1628 IViewObject2* iface,
1635 /************************************************************************
1636 * DataCache_SetAdvise (IViewObject2)
1638 * This sets-up an advisory sink with the data cache. When the object's
1639 * view changes, this sink is called.
1641 * See Windows documentation for more details on IViewObject2 methods.
1643 static HRESULT WINAPI DataCache_SetAdvise(
1644 IViewObject2* iface,
1647 IAdviseSink* pAdvSink)
1649 DataCache *this = impl_from_IViewObject2(iface);
1651 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1654 * A call to this function removes the previous sink
1656 if (this->sinkInterface != NULL)
1658 IAdviseSink_Release(this->sinkInterface);
1659 this->sinkInterface = NULL;
1660 this->sinkAspects = 0;
1661 this->sinkAdviseFlag = 0;
1665 * Now, setup the new one.
1669 this->sinkInterface = pAdvSink;
1670 this->sinkAspects = aspects;
1671 this->sinkAdviseFlag = advf;
1673 IAdviseSink_AddRef(this->sinkInterface);
1677 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1680 if (advf & ADVF_PRIMEFIRST)
1682 DataCache_FireOnViewChange(this, aspects, -1);
1688 /************************************************************************
1689 * DataCache_GetAdvise (IViewObject2)
1691 * This method queries the current state of the advise sink
1692 * installed on the data cache.
1694 * See Windows documentation for more details on IViewObject2 methods.
1696 static HRESULT WINAPI DataCache_GetAdvise(
1697 IViewObject2* iface,
1700 IAdviseSink** ppAdvSink)
1702 DataCache *this = impl_from_IViewObject2(iface);
1704 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1707 * Just copy all the requested values.
1710 *pAspects = this->sinkAspects;
1713 *pAdvf = this->sinkAdviseFlag;
1715 if (ppAdvSink!=NULL)
1717 if (this->sinkInterface != NULL)
1718 IAdviseSink_QueryInterface(this->sinkInterface,
1721 else *ppAdvSink = NULL;
1727 /************************************************************************
1728 * DataCache_GetExtent (IViewObject2)
1730 * This method retrieves the "natural" size of this cached object.
1732 * See Windows documentation for more details on IViewObject2 methods.
1734 static HRESULT WINAPI DataCache_GetExtent(
1735 IViewObject2* iface,
1738 DVTARGETDEVICE* ptd,
1741 DataCache *This = impl_from_IViewObject2(iface);
1742 HRESULT hres = E_FAIL;
1743 DataCacheEntry *cache_entry;
1745 TRACE("(%p, %x, %d, %p, %p)\n",
1746 iface, dwDrawAspect, lindex, ptd, lpsizel);
1755 * Initialize the out parameter.
1761 * This flag should be set to -1.
1764 FIXME("Unimplemented flag lindex = %d\n", lindex);
1767 * Right now, we support only the callback from
1768 * the default handler.
1771 FIXME("Unimplemented ptd = %p\n", ptd);
1773 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1775 /* FIXME: compare ptd too */
1776 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1777 (cache_entry->fmtetc.lindex != lindex))
1780 /* if the data hasn't been loaded yet, do it now */
1781 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1783 hres = DataCacheEntry_LoadData(cache_entry);
1789 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1793 switch (cache_entry->data_cf)
1795 case CF_METAFILEPICT:
1797 METAFILEPICT *mfpict;
1799 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1800 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1803 lpsizel->cx = mfpict->xExt;
1804 lpsizel->cy = mfpict->yExt;
1806 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1813 WARN("no data could be found to get the extents from\n");
1816 * This method returns OLE_E_BLANK when it fails.
1822 /*********************************************************
1823 * Method implementation for the IOleCache2
1824 * part of the DataCache class.
1827 /************************************************************************
1828 * DataCache_IOleCache2_QueryInterface (IUnknown)
1830 * See Windows documentation for more details on IUnknown methods.
1832 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1837 DataCache *this = impl_from_IOleCache2(iface);
1839 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1842 /************************************************************************
1843 * DataCache_IOleCache2_AddRef (IUnknown)
1845 * See Windows documentation for more details on IUnknown methods.
1847 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1850 DataCache *this = impl_from_IOleCache2(iface);
1852 return IUnknown_AddRef(this->outerUnknown);
1855 /************************************************************************
1856 * DataCache_IOleCache2_Release (IUnknown)
1858 * See Windows documentation for more details on IUnknown methods.
1860 static ULONG WINAPI DataCache_IOleCache2_Release(
1863 DataCache *this = impl_from_IOleCache2(iface);
1865 return IUnknown_Release(this->outerUnknown);
1868 static HRESULT WINAPI DataCache_Cache(
1870 FORMATETC* pformatetc,
1872 DWORD* pdwConnection)
1874 DataCache *This = impl_from_IOleCache2(iface);
1875 DataCacheEntry *cache_entry;
1878 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1879 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1883 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1886 TRACE("found an existing cache entry\n");
1887 *pdwConnection = cache_entry->id;
1888 return CACHE_S_SAMECACHE;
1891 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1894 *pdwConnection = cache_entry->id;
1899 static HRESULT WINAPI DataCache_Uncache(
1903 DataCache *This = impl_from_IOleCache2(iface);
1904 DataCacheEntry *cache_entry;
1906 TRACE("(%d)\n", dwConnection);
1908 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1909 if (cache_entry->id == dwConnection)
1911 DataCacheEntry_Destroy(cache_entry);
1915 WARN("no connection found for %d\n", dwConnection);
1917 return OLE_E_NOCONNECTION;
1920 static HRESULT WINAPI DataCache_EnumCache(
1922 IEnumSTATDATA** ppenumSTATDATA)
1928 static HRESULT WINAPI DataCache_InitCache(
1930 IDataObject* pDataObject)
1936 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1938 FORMATETC* pformatetc,
1942 DataCache *This = impl_from_IOleCache2(iface);
1943 DataCacheEntry *cache_entry;
1946 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
1947 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
1949 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1952 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
1955 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
1956 cache_entry->fmtetc.lindex);
1960 WARN("cache entry not found\n");
1965 static HRESULT WINAPI DataCache_UpdateCache(
1967 LPDATAOBJECT pDataObject,
1971 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
1975 static HRESULT WINAPI DataCache_DiscardCache(
1977 DWORD dwDiscardOptions)
1979 DataCache *This = impl_from_IOleCache2(iface);
1980 DataCacheEntry *cache_entry;
1983 TRACE("(%d)\n", dwDiscardOptions);
1985 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
1986 hr = DataCache_Save((IPersistStorage *)&This->lpvtblIPersistStorage,
1987 This->presentationStorage, TRUE);
1989 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1991 hr = DataCacheEntry_DiscardData(cache_entry);
2000 /*********************************************************
2001 * Method implementation for the IOleCacheControl
2002 * part of the DataCache class.
2005 /************************************************************************
2006 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2008 * See Windows documentation for more details on IUnknown methods.
2010 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2011 IOleCacheControl* iface,
2015 DataCache *this = impl_from_IOleCacheControl(iface);
2017 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2020 /************************************************************************
2021 * DataCache_IOleCacheControl_AddRef (IUnknown)
2023 * See Windows documentation for more details on IUnknown methods.
2025 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2026 IOleCacheControl* iface)
2028 DataCache *this = impl_from_IOleCacheControl(iface);
2030 return IUnknown_AddRef(this->outerUnknown);
2033 /************************************************************************
2034 * DataCache_IOleCacheControl_Release (IUnknown)
2036 * See Windows documentation for more details on IUnknown methods.
2038 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2039 IOleCacheControl* iface)
2041 DataCache *this = impl_from_IOleCacheControl(iface);
2043 return IUnknown_Release(this->outerUnknown);
2046 static HRESULT WINAPI DataCache_OnRun(
2047 IOleCacheControl* iface,
2048 LPDATAOBJECT pDataObject)
2054 static HRESULT WINAPI DataCache_OnStop(
2055 IOleCacheControl* iface)
2062 * Virtual function tables for the DataCache class.
2064 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2066 DataCache_NDIUnknown_QueryInterface,
2067 DataCache_NDIUnknown_AddRef,
2068 DataCache_NDIUnknown_Release
2071 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2073 DataCache_IDataObject_QueryInterface,
2074 DataCache_IDataObject_AddRef,
2075 DataCache_IDataObject_Release,
2077 DataCache_GetDataHere,
2078 DataCache_QueryGetData,
2079 DataCache_GetCanonicalFormatEtc,
2080 DataCache_IDataObject_SetData,
2081 DataCache_EnumFormatEtc,
2083 DataCache_DUnadvise,
2084 DataCache_EnumDAdvise
2087 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2089 DataCache_IPersistStorage_QueryInterface,
2090 DataCache_IPersistStorage_AddRef,
2091 DataCache_IPersistStorage_Release,
2092 DataCache_GetClassID,
2097 DataCache_SaveCompleted,
2098 DataCache_HandsOffStorage
2101 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2103 DataCache_IViewObject2_QueryInterface,
2104 DataCache_IViewObject2_AddRef,
2105 DataCache_IViewObject2_Release,
2107 DataCache_GetColorSet,
2110 DataCache_SetAdvise,
2111 DataCache_GetAdvise,
2115 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2117 DataCache_IOleCache2_QueryInterface,
2118 DataCache_IOleCache2_AddRef,
2119 DataCache_IOleCache2_Release,
2122 DataCache_EnumCache,
2123 DataCache_InitCache,
2124 DataCache_IOleCache2_SetData,
2125 DataCache_UpdateCache,
2126 DataCache_DiscardCache
2129 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2131 DataCache_IOleCacheControl_QueryInterface,
2132 DataCache_IOleCacheControl_AddRef,
2133 DataCache_IOleCacheControl_Release,
2138 /******************************************************************************
2139 * CreateDataCache [OLE32.@]
2141 * Creates a data cache to allow an object to render one or more of its views,
2142 * whether running or not.
2145 * pUnkOuter [I] Outer unknown for the object.
2147 * riid [I] IID of interface to return.
2148 * ppvObj [O] Address where the data cache object will be stored on return.
2152 * Failure: HRESULT code.
2155 * The following interfaces are supported by the returned data cache object:
2156 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorae, IDataObject,
2157 * IViewObject and IViewObject2.
2159 HRESULT WINAPI CreateDataCache(
2160 LPUNKNOWN pUnkOuter,
2165 DataCache* newCache = NULL;
2168 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2179 * If this cache is constructed for aggregation, make sure
2180 * the caller is requesting the IUnknown interface.
2181 * This is necessary because it's the only time the non-delegating
2182 * IUnknown pointer can be returned to the outside.
2184 if ( (pUnkOuter!=NULL) &&
2185 (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
2186 return CLASS_E_NOAGGREGATION;
2189 * Try to construct a new instance of the class.
2191 newCache = DataCache_Construct(rclsid,
2195 return E_OUTOFMEMORY;
2198 * Make sure it supports the interface required by the caller.
2200 hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
2203 * Release the reference obtained in the constructor. If
2204 * the QueryInterface was unsuccessful, it will free the class.
2206 IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
2211 /*********************************************************
2212 * Method implementation for DataCache class.
2214 static DataCache* DataCache_Construct(
2216 LPUNKNOWN pUnkOuter)
2218 DataCache* newObject = 0;
2221 * Allocate space for the object.
2223 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2229 * Initialize the virtual function table.
2231 newObject->lpVtbl = &DataCache_IDataObject_VTable;
2232 newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
2233 newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
2234 newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
2235 newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
2236 newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
2239 * Start with one reference count. The caller of this function
2240 * must release the interface pointer when it is done.
2245 * Initialize the outer unknown
2246 * We don't keep a reference on the outer unknown since, the way
2247 * aggregation works, our lifetime is at least as large as its
2250 if (pUnkOuter==NULL)
2251 pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
2253 newObject->outerUnknown = pUnkOuter;
2256 * Initialize the other members of the structure.
2258 newObject->sinkAspects = 0;
2259 newObject->sinkAdviseFlag = 0;
2260 newObject->sinkInterface = 0;
2261 newObject->presentationStorage = NULL;
2262 list_init(&newObject->cache_list);
2263 newObject->last_cache_id = 1;
2264 newObject->dirty = FALSE;