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 */
76 DWORD unknown2; /* 3, possibly CF_METAFILEPICT */
77 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
79 DWORD unknown5; /* -1 */
82 DWORD unknown7; /* 0 */
83 DWORD dwObjectExtentX;
84 DWORD dwObjectExtentY;
86 } PresentationDataHeader;
88 typedef struct DataCacheEntry
92 /* format of this entry */
96 * This storage pointer is set through a call to
97 * IPersistStorage_Load. This is where the visual
98 * representation of the object is stored.
105 /****************************************************************************
111 * List all interface VTables here
113 const IDataObjectVtbl* lpVtbl;
114 const IUnknownVtbl* lpvtblNDIUnknown;
115 const IPersistStorageVtbl* lpvtblIPersistStorage;
116 const IViewObject2Vtbl* lpvtblIViewObject;
117 const IOleCache2Vtbl* lpvtblIOleCache2;
118 const IOleCacheControlVtbl* lpvtblIOleCacheControl;
121 * Reference count of this object
126 * IUnknown implementation of the outer object.
128 IUnknown* outerUnknown;
131 * The user of this object can setup ONE advise sink
132 * connection with the object. These parameters describe
136 DWORD sinkAdviseFlag;
137 IAdviseSink* sinkInterface;
138 IStorage *presentationStorage;
140 struct list cache_list;
142 /* last id assigned to an object */
146 typedef struct DataCache DataCache;
149 * Here, I define utility macros to help with the casting of the
151 * There is a version to accommodate all of the VTables implemented
155 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
157 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpVtbl));
160 static inline DataCache *impl_from_NDIUnknown( IUnknown *iface )
162 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblNDIUnknown));
165 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
167 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIPersistStorage));
170 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
172 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIViewObject));
175 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
177 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCache2));
180 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
182 return (DataCache *)((char*)iface - FIELD_OFFSET(DataCache, lpvtblIOleCacheControl));
187 * Prototypes for the methods of the DataCache class.
189 static DataCache* DataCache_Construct(REFCLSID clsid,
190 LPUNKNOWN pUnkOuter);
191 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *This,
194 static void DataCacheEntry_Destroy(DataCacheEntry *This)
196 list_remove(&This->entry);
198 IStorage_Release(This->storage);
199 HeapFree(GetProcessHeap(), 0, This->fmtetc.ptd);
200 HeapFree(GetProcessHeap(), 0, This);
203 static void DataCache_Destroy(
204 DataCache* ptrToDestroy)
206 DataCacheEntry *cache_entry, *next_cache_entry;
210 if (ptrToDestroy->sinkInterface != NULL)
212 IAdviseSink_Release(ptrToDestroy->sinkInterface);
213 ptrToDestroy->sinkInterface = NULL;
216 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
217 DataCacheEntry_Destroy(cache_entry);
220 * Free the datacache pointer.
222 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
225 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
227 DataCacheEntry *cache_entry;
228 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
230 /* FIXME: also compare DVTARGETDEVICEs */
231 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
232 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
233 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
234 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
240 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
242 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
243 (*cache_entry)->fmtetc = *formatetc;
246 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
247 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
249 (*cache_entry)->storage = NULL;
250 (*cache_entry)->id = This->last_cache_id++;
251 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
255 /************************************************************************
256 * DataCache_ReadPresentationData
258 * This method will read information for the requested presentation
259 * into the given structure.
262 * this - Pointer to the DataCache object
263 * cache_entry - The entry that we wish to draw.
264 * header - The structure containing information about this
265 * aspect of the object.
267 static HRESULT DataCache_ReadPresentationData(
269 DataCacheEntry* cache_entry,
270 PresentationDataHeader* header)
272 IStream* presStream = NULL;
276 * Open the presentation stream.
278 hres = DataCacheEntry_OpenPresStream(
292 sizeof(PresentationDataHeader),
298 IStream_Release(presStream);
301 * We don't want to propagate any other error
302 * code than a failure.
310 /************************************************************************
311 * DataCache_FireOnViewChange
313 * This method will fire an OnViewChange notification to the advise
314 * sink registered with the datacache.
316 * See IAdviseSink::OnViewChange for more details.
318 static void DataCache_FireOnViewChange(
323 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
326 * The sink supplies a filter when it registers
327 * we make sure we only send the notifications when that
330 if ((this->sinkAspects & aspect) != 0)
332 if (this->sinkInterface != NULL)
334 IAdviseSink_OnViewChange(this->sinkInterface,
339 * Some sinks want to be unregistered automatically when
340 * the first notification goes out.
342 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
344 IAdviseSink_Release(this->sinkInterface);
346 this->sinkInterface = NULL;
347 this->sinkAspects = 0;
348 this->sinkAdviseFlag = 0;
354 /* Helper for DataCacheEntry_OpenPresStream */
355 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
357 /* The presentation streams have names of the form "\002OlePresXXX",
358 * where XXX goes from 000 to 999. */
359 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
361 LPCWSTR name = elem->pwcsName;
363 return (elem->type == STGTY_STREAM)
364 && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader))
365 && (strlenW(name) == 11)
366 && (strncmpW(name, OlePres, 8) == 0)
367 && (name[8] >= '0') && (name[8] <= '9')
368 && (name[9] >= '0') && (name[9] <= '9')
369 && (name[10] >= '0') && (name[10] <= '9');
372 /************************************************************************
373 * DataCacheEntry_OpenPresStream
375 * This method will find the stream for the given presentation. It makes
376 * no attempt at fallback.
379 * this - Pointer to the DataCache object
380 * drawAspect - The aspect of the object that we wish to draw.
381 * pStm - A returned stream. It points to the beginning of the
382 * - presentation data, including the header.
385 * S_OK The requested stream has been opened.
386 * OLE_E_BLANK The requested stream could not be found.
387 * Quite a few others I'm too lazy to map correctly.
390 * Algorithm: Scan the elements of the presentation storage, looking
391 * for presentation streams. For each presentation stream,
392 * load the header and check to see if the aspect matches.
394 * If a fallback is desired, just opening the first presentation stream
397 static HRESULT DataCacheEntry_OpenPresStream(
398 DataCacheEntry *This,
405 if (!ppStm) return E_POINTER;
407 hr = IStorage_EnumElements(This->storage, 0, NULL, 0, &pEnum);
408 if (FAILED(hr)) return hr;
410 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
412 if (DataCache_IsPresentationStream(&elem))
416 hr = IStorage_OpenStream(This->storage, elem.pwcsName,
417 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
421 PresentationDataHeader header;
424 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
426 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
427 if (hr == S_OK && actual_read == sizeof(header)
428 && header.dvAspect == This->fmtetc.dwAspect)
430 /* Rewind the stream before returning it. */
431 LARGE_INTEGER offset;
432 offset.u.LowPart = 0;
433 offset.u.HighPart = 0;
434 IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
438 CoTaskMemFree(elem.pwcsName);
439 IEnumSTATSTG_Release(pEnum);
444 IStream_Release(pStm);
448 CoTaskMemFree(elem.pwcsName);
451 IEnumSTATSTG_Release(pEnum);
453 return (hr == S_FALSE ? OLE_E_BLANK : hr);
456 /************************************************************************
457 * DataCache_ReadPresMetafile
459 * This method will read information for the requested presentation
460 * into the given structure.
463 * this - Pointer to the DataCache object
464 * cache_entry - The entry that we wish to draw.
467 * This method returns a metafile handle if it is successful.
468 * it will return 0 if not.
470 static HMETAFILE DataCache_ReadPresMetafile(
472 DataCacheEntry *cache_entry)
474 LARGE_INTEGER offset;
475 IStream* presStream = NULL;
479 HMETAFILE newMetafile = 0;
482 * Open the presentation stream.
484 hres = DataCacheEntry_OpenPresStream(
489 return (HMETAFILE)hres;
492 * Get the size of the stream.
494 hres = IStream_Stat(presStream,
501 offset.u.HighPart = 0;
502 offset.u.LowPart = sizeof(PresentationDataHeader);
510 streamInfo.cbSize.u.LowPart -= offset.u.LowPart;
513 * Allocate a buffer for the metafile bits.
515 metafileBits = HeapAlloc(GetProcessHeap(),
517 streamInfo.cbSize.u.LowPart);
520 * Read the metafile bits.
525 streamInfo.cbSize.u.LowPart,
529 * Create a metafile with those bits.
533 newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
539 HeapFree(GetProcessHeap(), 0, metafileBits);
540 IStream_Release(presStream);
548 /*********************************************************
549 * Method implementation for the non delegating IUnknown
550 * part of the DataCache class.
553 /************************************************************************
554 * DataCache_NDIUnknown_QueryInterface (IUnknown)
556 * See Windows documentation for more details on IUnknown methods.
558 * This version of QueryInterface will not delegate it's implementation
559 * to the outer unknown.
561 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
566 DataCache *this = impl_from_NDIUnknown(iface);
569 * Perform a sanity check on the parameters.
571 if ( (this==0) || (ppvObject==0) )
575 * Initialize the return parameter.
580 * Compare the riid with the interface IDs implemented by this object.
582 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
586 else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
588 *ppvObject = (IDataObject*)&(this->lpVtbl);
590 else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) ||
591 (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
593 *ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
595 else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
596 (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
598 *ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
600 else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
601 (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
603 *ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
605 else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
607 *ppvObject = (IOleCacheControl*)&(this->lpvtblIOleCacheControl);
611 * Check that we obtained an interface.
615 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
616 return E_NOINTERFACE;
620 * Query Interface always increases the reference count by one when it is
623 IUnknown_AddRef((IUnknown*)*ppvObject);
628 /************************************************************************
629 * DataCache_NDIUnknown_AddRef (IUnknown)
631 * See Windows documentation for more details on IUnknown methods.
633 * This version of QueryInterface will not delegate it's implementation
634 * to the outer unknown.
636 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
639 DataCache *this = impl_from_NDIUnknown(iface);
640 return InterlockedIncrement(&this->ref);
643 /************************************************************************
644 * DataCache_NDIUnknown_Release (IUnknown)
646 * See Windows documentation for more details on IUnknown methods.
648 * This version of QueryInterface will not delegate it's implementation
649 * to the outer unknown.
651 static ULONG WINAPI DataCache_NDIUnknown_Release(
654 DataCache *this = impl_from_NDIUnknown(iface);
658 * Decrease the reference count on this object.
660 ref = InterlockedDecrement(&this->ref);
663 * If the reference count goes down to 0, perform suicide.
665 if (ref == 0) DataCache_Destroy(this);
670 /*********************************************************
671 * Method implementation for the IDataObject
672 * part of the DataCache class.
675 /************************************************************************
676 * DataCache_IDataObject_QueryInterface (IUnknown)
678 * See Windows documentation for more details on IUnknown methods.
680 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
685 DataCache *this = impl_from_IDataObject(iface);
687 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
690 /************************************************************************
691 * DataCache_IDataObject_AddRef (IUnknown)
693 * See Windows documentation for more details on IUnknown methods.
695 static ULONG WINAPI DataCache_IDataObject_AddRef(
698 DataCache *this = impl_from_IDataObject(iface);
700 return IUnknown_AddRef(this->outerUnknown);
703 /************************************************************************
704 * DataCache_IDataObject_Release (IUnknown)
706 * See Windows documentation for more details on IUnknown methods.
708 static ULONG WINAPI DataCache_IDataObject_Release(
711 DataCache *this = impl_from_IDataObject(iface);
713 return IUnknown_Release(this->outerUnknown);
716 /************************************************************************
719 * Get Data from a source dataobject using format pformatetcIn->cfFormat
720 * See Windows documentation for more details on GetData.
721 * TODO: Currently only CF_METAFILEPICT is implemented
723 static HRESULT WINAPI DataCache_GetData(
725 LPFORMATETC pformatetcIn,
729 HRESULT hrRet = E_UNEXPECTED;
730 IPersistStorage *pPersistStorage = 0;
731 IStorage *pStorage = 0;
732 IStream *pStream = 0;
733 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
734 HGLOBAL hGlobalMF = 0;
736 PresentationDataHeader pdh;
737 METAFILEPICT *mfPict;
738 HMETAFILE hMetaFile = 0;
740 if (pformatetcIn->cfFormat == CF_METAFILEPICT)
742 /* Get the Persist Storage */
744 hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage);
749 /* Create a doc file to copy the doc to a storage */
751 hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage);
756 /* Save it to storage */
758 hr = OleSave(pPersistStorage, pStorage, FALSE);
763 /* Open the Presentation data srteam */
765 hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream);
770 /* Read the presentation header */
772 hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
777 mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize);
779 /* Read the Metafile bits */
781 hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL);
786 /* Create the metafile and place it in the STGMEDIUM structure */
788 hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits);
790 hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT));
791 mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF);
792 mfPict->hMF = hMetaFile;
794 GlobalUnlock(hGlobalMF);
796 pmedium->u.hGlobal = hGlobalMF;
797 pmedium->tymed = TYMED_MFPICT;
802 HeapFree(GetProcessHeap(), 0, mfBits);
805 IStream_Release(pStream);
808 IStorage_Release(pStorage);
811 IPersistStorage_Release(pPersistStorage);
816 /* TODO: Other formats are not implemented */
821 static HRESULT WINAPI DataCache_GetDataHere(
823 LPFORMATETC pformatetc,
830 static HRESULT WINAPI DataCache_QueryGetData(
832 LPFORMATETC pformatetc)
838 /************************************************************************
839 * DataCache_EnumFormatEtc (IDataObject)
841 * The data cache doesn't implement this method.
843 * See Windows documentation for more details on IDataObject methods.
845 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
847 LPFORMATETC pformatectIn,
848 LPFORMATETC pformatetcOut)
854 /************************************************************************
855 * DataCache_IDataObject_SetData (IDataObject)
857 * This method is delegated to the IOleCache2 implementation.
859 * See Windows documentation for more details on IDataObject methods.
861 static HRESULT WINAPI DataCache_IDataObject_SetData(
863 LPFORMATETC pformatetc,
867 IOleCache2* oleCache = NULL;
870 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
872 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
877 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
879 IOleCache2_Release(oleCache);
884 /************************************************************************
885 * DataCache_EnumFormatEtc (IDataObject)
887 * The data cache doesn't implement this method.
889 * See Windows documentation for more details on IDataObject methods.
891 static HRESULT WINAPI DataCache_EnumFormatEtc(
894 IEnumFORMATETC** ppenumFormatEtc)
900 /************************************************************************
901 * DataCache_DAdvise (IDataObject)
903 * The data cache doesn't support connections.
905 * See Windows documentation for more details on IDataObject methods.
907 static HRESULT WINAPI DataCache_DAdvise(
909 FORMATETC* pformatetc,
911 IAdviseSink* pAdvSink,
912 DWORD* pdwConnection)
915 return OLE_E_ADVISENOTSUPPORTED;
918 /************************************************************************
919 * DataCache_DUnadvise (IDataObject)
921 * The data cache doesn't support connections.
923 * See Windows documentation for more details on IDataObject methods.
925 static HRESULT WINAPI DataCache_DUnadvise(
930 return OLE_E_NOCONNECTION;
933 /************************************************************************
934 * DataCache_EnumDAdvise (IDataObject)
936 * The data cache doesn't support connections.
938 * See Windows documentation for more details on IDataObject methods.
940 static HRESULT WINAPI DataCache_EnumDAdvise(
942 IEnumSTATDATA** ppenumAdvise)
945 return OLE_E_ADVISENOTSUPPORTED;
948 /*********************************************************
949 * Method implementation for the IDataObject
950 * part of the DataCache class.
953 /************************************************************************
954 * DataCache_IPersistStorage_QueryInterface (IUnknown)
956 * See Windows documentation for more details on IUnknown methods.
958 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
959 IPersistStorage* iface,
963 DataCache *this = impl_from_IPersistStorage(iface);
965 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
968 /************************************************************************
969 * DataCache_IPersistStorage_AddRef (IUnknown)
971 * See Windows documentation for more details on IUnknown methods.
973 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
974 IPersistStorage* iface)
976 DataCache *this = impl_from_IPersistStorage(iface);
978 return IUnknown_AddRef(this->outerUnknown);
981 /************************************************************************
982 * DataCache_IPersistStorage_Release (IUnknown)
984 * See Windows documentation for more details on IUnknown methods.
986 static ULONG WINAPI DataCache_IPersistStorage_Release(
987 IPersistStorage* iface)
989 DataCache *this = impl_from_IPersistStorage(iface);
991 return IUnknown_Release(this->outerUnknown);
994 /************************************************************************
995 * DataCache_GetClassID (IPersistStorage)
997 * The data cache doesn't implement this method.
999 * See Windows documentation for more details on IPersistStorage methods.
1001 static HRESULT WINAPI DataCache_GetClassID(
1002 IPersistStorage* iface,
1005 DataCache *This = impl_from_IPersistStorage(iface);
1006 DataCacheEntry *cache_entry;
1008 TRACE("(%p, %p)\n", iface, pClassID);
1010 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1012 if (cache_entry->storage != NULL)
1015 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1018 memcpy(pClassID, &statstg.clsid, sizeof(*pClassID));
1024 memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID));
1029 /************************************************************************
1030 * DataCache_IsDirty (IPersistStorage)
1032 * Until we actually connect to a running object and retrieve new
1033 * information to it, we never get dirty.
1035 * See Windows documentation for more details on IPersistStorage methods.
1037 static HRESULT WINAPI DataCache_IsDirty(
1038 IPersistStorage* iface)
1040 TRACE("(%p)\n", iface);
1045 /************************************************************************
1046 * DataCache_InitNew (IPersistStorage)
1048 * The data cache implementation of IPersistStorage_InitNew simply stores
1049 * the storage pointer.
1051 * See Windows documentation for more details on IPersistStorage methods.
1053 static HRESULT WINAPI DataCache_InitNew(
1054 IPersistStorage* iface,
1057 TRACE("(%p, %p)\n", iface, pStg);
1059 return IPersistStorage_Load(iface, pStg);
1062 /************************************************************************
1063 * DataCache_Load (IPersistStorage)
1065 * The data cache implementation of IPersistStorage_Load doesn't
1066 * actually load anything. Instead, it holds on to the storage pointer
1067 * and it will load the presentation information when the
1068 * IDataObject_GetData or IViewObject2_Draw methods are called.
1070 * See Windows documentation for more details on IPersistStorage methods.
1072 static HRESULT WINAPI DataCache_Load(
1073 IPersistStorage* iface,
1076 DataCache *This = impl_from_IPersistStorage(iface);
1078 IEnumSTATSTG *pEnum;
1081 TRACE("(%p, %p)\n", iface, pStg);
1083 if (This->presentationStorage != NULL)
1084 IStorage_Release(This->presentationStorage);
1086 This->presentationStorage = pStg;
1088 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1089 if (FAILED(hr)) return hr;
1091 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1093 if (DataCache_IsPresentationStream(&elem))
1097 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1098 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1102 PresentationDataHeader header;
1105 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
1107 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1108 if (hr == S_OK && actual_read == sizeof(header))
1110 DataCacheEntry *cache_entry;
1113 fmtetc.cfFormat = header.unknown2;
1114 fmtetc.ptd = NULL; /* FIXME */
1115 fmtetc.dwAspect = header.dvAspect;
1116 fmtetc.lindex = header.unknown5;
1117 fmtetc.tymed = header.unknown6;
1119 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1121 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1124 if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1125 cache_entry->storage = pStg;
1126 IStorage_AddRef(pStg);
1130 IStream_Release(pStm);
1134 CoTaskMemFree(elem.pwcsName);
1137 IEnumSTATSTG_Release(pEnum);
1139 IStorage_AddRef(This->presentationStorage);
1143 /************************************************************************
1144 * DataCache_Save (IPersistStorage)
1146 * Until we actually connect to a running object and retrieve new
1147 * information to it, we never have to save anything. However, it is
1148 * our responsibility to copy the information when saving to a new
1151 * See Windows documentation for more details on IPersistStorage methods.
1153 static HRESULT WINAPI DataCache_Save(
1154 IPersistStorage* iface,
1158 DataCache *this = impl_from_IPersistStorage(iface);
1160 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1162 if ( (!fSameAsLoad) &&
1163 (this->presentationStorage!=NULL) )
1165 return IStorage_CopyTo(this->presentationStorage,
1175 /************************************************************************
1176 * DataCache_SaveCompleted (IPersistStorage)
1178 * This method is called to tell the cache to release the storage
1179 * pointer it's currently holding.
1181 * See Windows documentation for more details on IPersistStorage methods.
1183 static HRESULT WINAPI DataCache_SaveCompleted(
1184 IPersistStorage* iface,
1187 TRACE("(%p, %p)\n", iface, pStgNew);
1192 * First, make sure we get our hands off any storage we have.
1195 IPersistStorage_HandsOffStorage(iface);
1198 * Then, attach to the new storage.
1201 DataCache_Load(iface, pStgNew);
1207 /************************************************************************
1208 * DataCache_HandsOffStorage (IPersistStorage)
1210 * This method is called to tell the cache to release the storage
1211 * pointer it's currently holding.
1213 * See Windows documentation for more details on IPersistStorage methods.
1215 static HRESULT WINAPI DataCache_HandsOffStorage(
1216 IPersistStorage* iface)
1218 DataCache *this = impl_from_IPersistStorage(iface);
1220 TRACE("(%p)\n", iface);
1222 if (this->presentationStorage != NULL)
1224 IStorage_Release(this->presentationStorage);
1225 this->presentationStorage = NULL;
1231 /*********************************************************
1232 * Method implementation for the IViewObject2
1233 * part of the DataCache class.
1236 /************************************************************************
1237 * DataCache_IViewObject2_QueryInterface (IUnknown)
1239 * See Windows documentation for more details on IUnknown methods.
1241 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1242 IViewObject2* iface,
1246 DataCache *this = impl_from_IViewObject2(iface);
1248 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1251 /************************************************************************
1252 * DataCache_IViewObject2_AddRef (IUnknown)
1254 * See Windows documentation for more details on IUnknown methods.
1256 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1257 IViewObject2* iface)
1259 DataCache *this = impl_from_IViewObject2(iface);
1261 return IUnknown_AddRef(this->outerUnknown);
1264 /************************************************************************
1265 * DataCache_IViewObject2_Release (IUnknown)
1267 * See Windows documentation for more details on IUnknown methods.
1269 static ULONG WINAPI DataCache_IViewObject2_Release(
1270 IViewObject2* iface)
1272 DataCache *this = impl_from_IViewObject2(iface);
1274 return IUnknown_Release(this->outerUnknown);
1277 /************************************************************************
1278 * DataCache_Draw (IViewObject2)
1280 * This method will draw the cached representation of the object
1281 * to the given device context.
1283 * See Windows documentation for more details on IViewObject2 methods.
1285 static HRESULT WINAPI DataCache_Draw(
1286 IViewObject2* iface,
1290 DVTARGETDEVICE* ptd,
1293 LPCRECTL lprcBounds,
1294 LPCRECTL lprcWBounds,
1295 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1296 ULONG_PTR dwContinue)
1298 DataCache *This = impl_from_IViewObject2(iface);
1299 PresentationDataHeader presData;
1300 HMETAFILE presMetafile = 0;
1302 DataCacheEntry *cache_entry;
1304 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1319 if (lprcBounds==NULL)
1320 return E_INVALIDARG;
1322 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1324 /* FIXME: compare ptd too */
1325 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1326 (cache_entry->fmtetc.lindex != lindex))
1330 * First, we need to retrieve the dimensions of the
1331 * image in the metafile.
1333 hres = DataCache_ReadPresentationData(This,
1341 * Then, we can extract the metafile itself from the cached
1344 * FIXME Unless it isn't a metafile. I think it could be any CF_XXX type,
1345 * particularly CF_DIB.
1347 presMetafile = DataCache_ReadPresMetafile(This,
1351 * If we have a metafile, just draw baby...
1352 * We have to be careful not to modify the state of the
1355 if (presMetafile!=0)
1357 INT prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC);
1359 SIZE oldViewportExt;
1360 POINT oldViewportOrg;
1362 SetWindowExtEx(hdcDraw,
1363 presData.dwObjectExtentX,
1364 presData.dwObjectExtentY,
1367 SetViewportExtEx(hdcDraw,
1368 lprcBounds->right - lprcBounds->left,
1369 lprcBounds->bottom - lprcBounds->top,
1372 SetViewportOrgEx(hdcDraw,
1377 PlayMetaFile(hdcDraw, presMetafile);
1379 SetWindowExtEx(hdcDraw,
1384 SetViewportExtEx(hdcDraw,
1389 SetViewportOrgEx(hdcDraw,
1394 SetMapMode(hdcDraw, prevMapMode);
1396 DeleteMetaFile(presMetafile);
1404 static HRESULT WINAPI DataCache_GetColorSet(
1405 IViewObject2* iface,
1409 DVTARGETDEVICE* ptd,
1410 HDC hicTargetDevice,
1411 LOGPALETTE** ppColorSet)
1417 static HRESULT WINAPI DataCache_Freeze(
1418 IViewObject2* iface,
1428 static HRESULT WINAPI DataCache_Unfreeze(
1429 IViewObject2* iface,
1436 /************************************************************************
1437 * DataCache_SetAdvise (IViewObject2)
1439 * This sets-up an advisory sink with the data cache. When the object's
1440 * view changes, this sink is called.
1442 * See Windows documentation for more details on IViewObject2 methods.
1444 static HRESULT WINAPI DataCache_SetAdvise(
1445 IViewObject2* iface,
1448 IAdviseSink* pAdvSink)
1450 DataCache *this = impl_from_IViewObject2(iface);
1452 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1455 * A call to this function removes the previous sink
1457 if (this->sinkInterface != NULL)
1459 IAdviseSink_Release(this->sinkInterface);
1460 this->sinkInterface = NULL;
1461 this->sinkAspects = 0;
1462 this->sinkAdviseFlag = 0;
1466 * Now, setup the new one.
1470 this->sinkInterface = pAdvSink;
1471 this->sinkAspects = aspects;
1472 this->sinkAdviseFlag = advf;
1474 IAdviseSink_AddRef(this->sinkInterface);
1478 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1481 if (advf & ADVF_PRIMEFIRST)
1483 DataCache_FireOnViewChange(this,
1491 /************************************************************************
1492 * DataCache_GetAdvise (IViewObject2)
1494 * This method queries the current state of the advise sink
1495 * installed on the data cache.
1497 * See Windows documentation for more details on IViewObject2 methods.
1499 static HRESULT WINAPI DataCache_GetAdvise(
1500 IViewObject2* iface,
1503 IAdviseSink** ppAdvSink)
1505 DataCache *this = impl_from_IViewObject2(iface);
1507 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1510 * Just copy all the requested values.
1513 *pAspects = this->sinkAspects;
1516 *pAdvf = this->sinkAdviseFlag;
1518 if (ppAdvSink!=NULL)
1520 if (this->sinkInterface != NULL)
1521 IAdviseSink_QueryInterface(this->sinkInterface,
1524 else *ppAdvSink = NULL;
1530 /************************************************************************
1531 * DataCache_GetExtent (IViewObject2)
1533 * This method retrieves the "natural" size of this cached object.
1535 * See Windows documentation for more details on IViewObject2 methods.
1537 static HRESULT WINAPI DataCache_GetExtent(
1538 IViewObject2* iface,
1541 DVTARGETDEVICE* ptd,
1544 DataCache *This = impl_from_IViewObject2(iface);
1545 PresentationDataHeader presData;
1546 HRESULT hres = E_FAIL;
1547 DataCacheEntry *cache_entry;
1549 TRACE("(%p, %x, %d, %p, %p)\n",
1550 iface, dwDrawAspect, lindex, ptd, lpsizel);
1559 * Initialize the out parameter.
1565 * This flag should be set to -1.
1568 FIXME("Unimplemented flag lindex = %d\n", lindex);
1571 * Right now, we support only the callback from
1572 * the default handler.
1575 FIXME("Unimplemented ptd = %p\n", ptd);
1577 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1579 /* FIXME: compare ptd too */
1580 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1581 (cache_entry->fmtetc.lindex != lindex))
1585 * Get the presentation information from the
1588 hres = DataCache_ReadPresentationData(This,
1592 if (SUCCEEDED(hres))
1594 lpsizel->cx = presData.dwObjectExtentX;
1595 lpsizel->cy = presData.dwObjectExtentY;
1602 * This method returns OLE_E_BLANK when it fails.
1608 /*********************************************************
1609 * Method implementation for the IOleCache2
1610 * part of the DataCache class.
1613 /************************************************************************
1614 * DataCache_IOleCache2_QueryInterface (IUnknown)
1616 * See Windows documentation for more details on IUnknown methods.
1618 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1623 DataCache *this = impl_from_IOleCache2(iface);
1625 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1628 /************************************************************************
1629 * DataCache_IOleCache2_AddRef (IUnknown)
1631 * See Windows documentation for more details on IUnknown methods.
1633 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1636 DataCache *this = impl_from_IOleCache2(iface);
1638 return IUnknown_AddRef(this->outerUnknown);
1641 /************************************************************************
1642 * DataCache_IOleCache2_Release (IUnknown)
1644 * See Windows documentation for more details on IUnknown methods.
1646 static ULONG WINAPI DataCache_IOleCache2_Release(
1649 DataCache *this = impl_from_IOleCache2(iface);
1651 return IUnknown_Release(this->outerUnknown);
1654 static HRESULT WINAPI DataCache_Cache(
1656 FORMATETC* pformatetc,
1658 DWORD* pdwConnection)
1660 DataCache *This = impl_from_IOleCache2(iface);
1661 DataCacheEntry *cache_entry;
1664 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1668 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1671 *pdwConnection = cache_entry->id;
1672 return CACHE_S_SAMECACHE;
1675 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1678 *pdwConnection = cache_entry->id;
1683 static HRESULT WINAPI DataCache_Uncache(
1687 DataCache *This = impl_from_IOleCache2(iface);
1688 DataCacheEntry *cache_entry;
1690 TRACE("(%d)\n", dwConnection);
1692 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1693 if (cache_entry->id == dwConnection)
1695 DataCacheEntry_Destroy(cache_entry);
1699 return OLE_E_NOCONNECTION;
1702 static HRESULT WINAPI DataCache_EnumCache(
1704 IEnumSTATDATA** ppenumSTATDATA)
1710 static HRESULT WINAPI DataCache_InitCache(
1712 IDataObject* pDataObject)
1718 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1720 FORMATETC* pformatetc,
1728 static HRESULT WINAPI DataCache_UpdateCache(
1730 LPDATAOBJECT pDataObject,
1738 static HRESULT WINAPI DataCache_DiscardCache(
1740 DWORD dwDiscardOptions)
1747 /*********************************************************
1748 * Method implementation for the IOleCacheControl
1749 * part of the DataCache class.
1752 /************************************************************************
1753 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
1755 * See Windows documentation for more details on IUnknown methods.
1757 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
1758 IOleCacheControl* iface,
1762 DataCache *this = impl_from_IOleCacheControl(iface);
1764 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1767 /************************************************************************
1768 * DataCache_IOleCacheControl_AddRef (IUnknown)
1770 * See Windows documentation for more details on IUnknown methods.
1772 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
1773 IOleCacheControl* iface)
1775 DataCache *this = impl_from_IOleCacheControl(iface);
1777 return IUnknown_AddRef(this->outerUnknown);
1780 /************************************************************************
1781 * DataCache_IOleCacheControl_Release (IUnknown)
1783 * See Windows documentation for more details on IUnknown methods.
1785 static ULONG WINAPI DataCache_IOleCacheControl_Release(
1786 IOleCacheControl* iface)
1788 DataCache *this = impl_from_IOleCacheControl(iface);
1790 return IUnknown_Release(this->outerUnknown);
1793 static HRESULT WINAPI DataCache_OnRun(
1794 IOleCacheControl* iface,
1795 LPDATAOBJECT pDataObject)
1801 static HRESULT WINAPI DataCache_OnStop(
1802 IOleCacheControl* iface)
1809 * Virtual function tables for the DataCache class.
1811 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
1813 DataCache_NDIUnknown_QueryInterface,
1814 DataCache_NDIUnknown_AddRef,
1815 DataCache_NDIUnknown_Release
1818 static const IDataObjectVtbl DataCache_IDataObject_VTable =
1820 DataCache_IDataObject_QueryInterface,
1821 DataCache_IDataObject_AddRef,
1822 DataCache_IDataObject_Release,
1824 DataCache_GetDataHere,
1825 DataCache_QueryGetData,
1826 DataCache_GetCanonicalFormatEtc,
1827 DataCache_IDataObject_SetData,
1828 DataCache_EnumFormatEtc,
1830 DataCache_DUnadvise,
1831 DataCache_EnumDAdvise
1834 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
1836 DataCache_IPersistStorage_QueryInterface,
1837 DataCache_IPersistStorage_AddRef,
1838 DataCache_IPersistStorage_Release,
1839 DataCache_GetClassID,
1844 DataCache_SaveCompleted,
1845 DataCache_HandsOffStorage
1848 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
1850 DataCache_IViewObject2_QueryInterface,
1851 DataCache_IViewObject2_AddRef,
1852 DataCache_IViewObject2_Release,
1854 DataCache_GetColorSet,
1857 DataCache_SetAdvise,
1858 DataCache_GetAdvise,
1862 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
1864 DataCache_IOleCache2_QueryInterface,
1865 DataCache_IOleCache2_AddRef,
1866 DataCache_IOleCache2_Release,
1869 DataCache_EnumCache,
1870 DataCache_InitCache,
1871 DataCache_IOleCache2_SetData,
1872 DataCache_UpdateCache,
1873 DataCache_DiscardCache
1876 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
1878 DataCache_IOleCacheControl_QueryInterface,
1879 DataCache_IOleCacheControl_AddRef,
1880 DataCache_IOleCacheControl_Release,
1885 /******************************************************************************
1886 * CreateDataCache [OLE32.@]
1888 HRESULT WINAPI CreateDataCache(
1889 LPUNKNOWN pUnkOuter,
1894 DataCache* newCache = NULL;
1897 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
1908 * If this cache is constructed for aggregation, make sure
1909 * the caller is requesting the IUnknown interface.
1910 * This is necessary because it's the only time the non-delegating
1911 * IUnknown pointer can be returned to the outside.
1913 if ( (pUnkOuter!=NULL) &&
1914 (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
1915 return CLASS_E_NOAGGREGATION;
1918 * Try to construct a new instance of the class.
1920 newCache = DataCache_Construct(rclsid,
1924 return E_OUTOFMEMORY;
1927 * Make sure it supports the interface required by the caller.
1929 hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
1932 * Release the reference obtained in the constructor. If
1933 * the QueryInterface was unsuccessful, it will free the class.
1935 IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
1940 /*********************************************************
1941 * Method implementation for DataCache class.
1943 static DataCache* DataCache_Construct(
1945 LPUNKNOWN pUnkOuter)
1947 DataCache* newObject = 0;
1950 * Allocate space for the object.
1952 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
1958 * Initialize the virtual function table.
1960 newObject->lpVtbl = &DataCache_IDataObject_VTable;
1961 newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
1962 newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
1963 newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
1964 newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
1965 newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
1968 * Start with one reference count. The caller of this function
1969 * must release the interface pointer when it is done.
1974 * Initialize the outer unknown
1975 * We don't keep a reference on the outer unknown since, the way
1976 * aggregation works, our lifetime is at least as large as its
1979 if (pUnkOuter==NULL)
1980 pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
1982 newObject->outerUnknown = pUnkOuter;
1985 * Initialize the other members of the structure.
1987 newObject->sinkAspects = 0;
1988 newObject->sinkAdviseFlag = 0;
1989 newObject->sinkInterface = 0;
1990 newObject->presentationStorage = NULL;
1991 list_init(&newObject->cache_list);