ole32: Implement the DiscardCache function in the data cache.
[wine/wine64.git] / dlls / ole32 / datacache.c
blob54d25ea8c08f3fc4939cbca7fba53cfd7ba600d5
1 /*
2 * OLE 2 Data cache
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2000 Abey George
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * NOTES:
22 * The OLE2 data cache supports a whole whack of
23 * interfaces including:
24 * IDataObject, IPersistStorage, IViewObject2,
25 * IOleCache2 and IOleCacheControl.
27 * Most of the implementation details are taken from: Inside OLE
28 * second edition by Kraig Brockschmidt,
30 * NOTES
31 * - This implementation of the datacache will let your application
32 * load documents that have embedded OLE objects in them and it will
33 * also retrieve the metafile representation of those objects.
34 * - This implementation of the datacache will also allow your
35 * application to save new documents with OLE objects in them.
36 * - The main thing that it doesn't do is allow you to activate
37 * or modify the OLE objects in any way.
38 * - I haven't found any good documentation on the real usage of
39 * the streams created by the data cache. In particular, How to
40 * determine what the XXX stands for in the stream name
41 * "\002OlePresXXX". It appears to just be a counter.
42 * - Also, I don't know the real content of the presentation stream
43 * header. I was able to figure-out where the extent of the object
44 * was stored and the aspect, but that's about it.
46 #include <stdarg.h>
47 #include <string.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "winerror.h"
58 #include "wine/unicode.h"
59 #include "ole2.h"
60 #include "wine/list.h"
61 #include "wine/debug.h"
63 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65 /****************************************************************************
66 * PresentationDataHeader
68 * This structure represents the header of the \002OlePresXXX stream in
69 * the OLE object strorage.
71 * Most fields are still unknown.
73 typedef struct PresentationDataHeader
75 DWORD unknown1; /* -1 */
76 DWORD clipformat;
77 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
78 DVASPECT dvAspect;
79 DWORD lindex;
80 DWORD tymed;
81 DWORD unknown7; /* 0 */
82 DWORD dwObjectExtentX;
83 DWORD dwObjectExtentY;
84 DWORD dwSize;
85 } PresentationDataHeader;
87 typedef struct DataCacheEntry
89 struct list entry;
90 /* format of this entry */
91 FORMATETC fmtetc;
92 /* the clipboard format of the data */
93 CLIPFORMAT data_cf;
94 /* cached data */
95 STGMEDIUM stgmedium;
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.
101 IStorage *storage;
102 /* connection ID */
103 DWORD id;
104 /* dirty flag */
105 BOOL dirty;
106 /* stream number (-1 if not set ) */
107 unsigned short stream_number;
108 } DataCacheEntry;
110 /****************************************************************************
111 * DataCache
113 struct DataCache
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
128 LONG ref;
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
138 * that connection.
140 DWORD sinkAspects;
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 */
148 DWORD last_cache_id;
149 /* dirty flag */
150 BOOL dirty;
153 typedef struct DataCache DataCache;
156 * Here, I define utility macros to help with the casting of the
157 * "this" parameter.
158 * There is a version to accommodate all of the VTables implemented
159 * by this object.
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 void dump_FORMATETC(const FORMATETC *formatetc)
194 TRACE("{ 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,
205 IStream **pStm);
207 static void DataCacheEntry_Destroy(DataCacheEntry *This)
209 list_remove(&This->entry);
210 if (This->storage)
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;
222 TRACE("()\n");
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)))
249 return cache_entry;
251 return NULL;
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
256 * DataCache_Draw */
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))
264 return S_OK;
265 else if (tymed == TYMED_HGLOBAL)
266 return CACHE_S_FORMATETC_NOTSUPPORTED;
267 else
269 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
270 return DV_E_TYMED;
274 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
276 HRESULT hr;
278 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
279 if (FAILED(hr))
280 return hr;
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));
285 if (!*cache_entry)
286 return E_OUTOFMEMORY;
288 (*cache_entry)->fmtetc = *formatetc;
289 if (formatetc->ptd)
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);
301 return hr;
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(
313 DataCache* this,
314 DWORD aspect,
315 LONG lindex)
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
322 * filter matches.
324 if ((this->sinkAspects & aspect) != 0)
326 if (this->sinkInterface != NULL)
328 IAdviseSink_OnViewChange(this->sinkInterface,
329 aspect,
330 lindex);
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.
372 * Param:
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.
378 * Errors:
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.
383 * Notes:
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
389 * is a possibility.
391 static HRESULT DataCacheEntry_OpenPresStream(
392 DataCacheEntry *This,
393 IStream **ppStm)
395 STATSTG elem;
396 IEnumSTATSTG *pEnum;
397 HRESULT hr;
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))
408 IStream *pStm;
410 hr = IStorage_OpenStream(This->storage, elem.pwcsName,
411 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
412 &pStm);
413 if (SUCCEEDED(hr))
415 PresentationDataHeader header;
416 ULONG actual_read;
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);
430 *ppStm = pStm;
432 CoTaskMemFree(elem.pwcsName);
433 IEnumSTATSTG_Release(pEnum);
435 return S_OK;
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.
456 * Param:
457 * This - The entry to load the data from.
459 * Returns:
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;
466 HRESULT hres;
467 STATSTG streamInfo;
468 void* metafileBits;
469 METAFILEPICT *mfpict;
470 HGLOBAL hmfpict;
471 PresentationDataHeader header;
474 * Open the presentation stream.
476 hres = DataCacheEntry_OpenPresStream(
477 This,
478 &presStream);
480 if (FAILED(hres))
481 return hres;
484 * Get the size of the stream.
486 hres = IStream_Stat(presStream,
487 &streamInfo,
488 STATFLAG_NONAME);
491 * Read the header.
494 hres = IStream_Read(
495 presStream,
496 &header,
497 sizeof(PresentationDataHeader),
498 NULL);
500 streamInfo.cbSize.QuadPart -= sizeof(PresentationDataHeader);
502 hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
503 if (!hmfpict)
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.
520 hres = IStream_Read(
521 presStream,
522 metafileBits,
523 streamInfo.cbSize.u.LowPart,
524 NULL);
527 * Create a metafile with those bits.
529 if (SUCCEEDED(hres))
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);
536 if (!mfpict->hMF)
537 hres = E_FAIL;
540 GlobalUnlock(hmfpict);
541 if (SUCCEEDED(hres))
543 This->data_cf = This->fmtetc.cfFormat;
544 This->stgmedium.tymed = TYMED_MFPICT;
545 This->stgmedium.u.hMetaFilePict = hmfpict;
547 else
548 GlobalFree(hmfpict);
551 * Cleanup.
553 HeapFree(GetProcessHeap(), 0, metafileBits);
554 IStream_Release(presStream);
556 return hres;
559 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This,
560 IStorage *storage, IStream **stream)
562 HRESULT hr;
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,
571 0, 0, stream);
572 return hr;
575 static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
576 BOOL same_as_load)
578 PresentationDataHeader header;
579 HRESULT hr;
580 IStream *pres_stream;
581 void *data = NULL;
583 TRACE("stream_number = %d, fmtetc = ", This->stream_number); dump_FORMATETC(&This->fmtetc); TRACE("\n");
585 hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
586 if (FAILED(hr))
587 return hr;
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");
596 header.unknown3 = 4;
597 header.dvAspect = This->fmtetc.dwAspect;
598 header.lindex = This->fmtetc.lindex;
599 header.tymed = This->stgmedium.tymed;
600 header.unknown7 = 0;
601 header.dwObjectExtentX = 0;
602 header.dwObjectExtentY = 0;
603 header.dwSize = 0;
605 /* size the data */
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);
613 if (!mfpict)
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);
623 break;
625 default:
626 break;
630 * Write the header.
632 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
633 NULL);
634 if (FAILED(hr))
636 IStream_Release(pres_stream);
637 return hr;
640 /* get the data */
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);
648 if (!mfpict)
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);
657 break;
659 default:
660 break;
663 if (data)
664 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
666 IStream_Release(pres_stream);
667 return hr;
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;
681 if (!src_mfpict)
682 return DV_E_STGMEDIUM;
683 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
684 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
685 if (!dest_mfpict)
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,
698 GMEM_MOVEABLE);
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);
706 return S_OK;
709 static HRESULT DataCacheEntry_SetData(DataCacheEntry *This,
710 const FORMATETC *formatetc,
711 const STGMEDIUM *stgmedium,
712 BOOL fRelease)
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;
722 This->dirty = TRUE;
723 ReleaseStgMedium(&This->stgmedium);
724 This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat;
725 if (fRelease)
727 This->stgmedium = *stgmedium;
728 return S_OK;
730 else
731 return copy_stg_medium(This->data_cf,
732 &This->stgmedium, stgmedium);
735 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
737 ReleaseStgMedium(&This->stgmedium);
738 This->data_cf = This->fmtetc.cfFormat;
739 return S_OK;
742 /*********************************************************
743 * Method implementation for the non delegating IUnknown
744 * part of the DataCache class.
747 /************************************************************************
748 * DataCache_NDIUnknown_QueryInterface (IUnknown)
750 * See Windows documentation for more details on IUnknown methods.
752 * This version of QueryInterface will not delegate it's implementation
753 * to the outer unknown.
755 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
756 IUnknown* iface,
757 REFIID riid,
758 void** ppvObject)
760 DataCache *this = impl_from_NDIUnknown(iface);
763 * Perform a sanity check on the parameters.
765 if ( (this==0) || (ppvObject==0) )
766 return E_INVALIDARG;
769 * Initialize the return parameter.
771 *ppvObject = 0;
774 * Compare the riid with the interface IDs implemented by this object.
776 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
778 *ppvObject = iface;
780 else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
782 *ppvObject = (IDataObject*)&(this->lpVtbl);
784 else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) ||
785 (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
787 *ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
789 else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
790 (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
792 *ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
794 else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
795 (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
797 *ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
799 else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
801 *ppvObject = (IOleCacheControl*)&(this->lpvtblIOleCacheControl);
805 * Check that we obtained an interface.
807 if ((*ppvObject)==0)
809 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
810 return E_NOINTERFACE;
814 * Query Interface always increases the reference count by one when it is
815 * successful.
817 IUnknown_AddRef((IUnknown*)*ppvObject);
819 return S_OK;
822 /************************************************************************
823 * DataCache_NDIUnknown_AddRef (IUnknown)
825 * See Windows documentation for more details on IUnknown methods.
827 * This version of QueryInterface will not delegate it's implementation
828 * to the outer unknown.
830 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
831 IUnknown* iface)
833 DataCache *this = impl_from_NDIUnknown(iface);
834 return InterlockedIncrement(&this->ref);
837 /************************************************************************
838 * DataCache_NDIUnknown_Release (IUnknown)
840 * See Windows documentation for more details on IUnknown methods.
842 * This version of QueryInterface will not delegate it's implementation
843 * to the outer unknown.
845 static ULONG WINAPI DataCache_NDIUnknown_Release(
846 IUnknown* iface)
848 DataCache *this = impl_from_NDIUnknown(iface);
849 ULONG ref;
852 * Decrease the reference count on this object.
854 ref = InterlockedDecrement(&this->ref);
857 * If the reference count goes down to 0, perform suicide.
859 if (ref == 0) DataCache_Destroy(this);
861 return ref;
864 /*********************************************************
865 * Method implementation for the IDataObject
866 * part of the DataCache class.
869 /************************************************************************
870 * DataCache_IDataObject_QueryInterface (IUnknown)
872 * See Windows documentation for more details on IUnknown methods.
874 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
875 IDataObject* iface,
876 REFIID riid,
877 void** ppvObject)
879 DataCache *this = impl_from_IDataObject(iface);
881 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
884 /************************************************************************
885 * DataCache_IDataObject_AddRef (IUnknown)
887 * See Windows documentation for more details on IUnknown methods.
889 static ULONG WINAPI DataCache_IDataObject_AddRef(
890 IDataObject* iface)
892 DataCache *this = impl_from_IDataObject(iface);
894 return IUnknown_AddRef(this->outerUnknown);
897 /************************************************************************
898 * DataCache_IDataObject_Release (IUnknown)
900 * See Windows documentation for more details on IUnknown methods.
902 static ULONG WINAPI DataCache_IDataObject_Release(
903 IDataObject* iface)
905 DataCache *this = impl_from_IDataObject(iface);
907 return IUnknown_Release(this->outerUnknown);
910 /************************************************************************
911 * DataCache_GetData
913 * Get Data from a source dataobject using format pformatetcIn->cfFormat
914 * See Windows documentation for more details on GetData.
915 * TODO: Currently only CF_METAFILEPICT is implemented
917 static HRESULT WINAPI DataCache_GetData(
918 IDataObject* iface,
919 LPFORMATETC pformatetcIn,
920 STGMEDIUM* pmedium)
922 HRESULT hr = 0;
923 HRESULT hrRet = E_UNEXPECTED;
924 IPersistStorage *pPersistStorage = 0;
925 IStorage *pStorage = 0;
926 IStream *pStream = 0;
927 OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
928 HGLOBAL hGlobalMF = 0;
929 void *mfBits = 0;
930 PresentationDataHeader pdh;
931 METAFILEPICT *mfPict;
932 HMETAFILE hMetaFile = 0;
934 if (pformatetcIn->cfFormat == CF_METAFILEPICT)
936 /* Get the Persist Storage */
938 hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage);
940 if (hr != S_OK)
941 goto cleanup;
943 /* Create a doc file to copy the doc to a storage */
945 hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage);
947 if (hr != S_OK)
948 goto cleanup;
950 /* Save it to storage */
952 hr = OleSave(pPersistStorage, pStorage, FALSE);
954 if (hr != S_OK)
955 goto cleanup;
957 /* Open the Presentation data srteam */
959 hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream);
961 if (hr != S_OK)
962 goto cleanup;
964 /* Read the presentation header */
966 hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL);
968 if (hr != S_OK)
969 goto cleanup;
971 mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize);
973 /* Read the Metafile bits */
975 hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL);
977 if (hr != S_OK)
978 goto cleanup;
980 /* Create the metafile and place it in the STGMEDIUM structure */
982 hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits);
984 hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT));
985 mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF);
986 mfPict->hMF = hMetaFile;
988 GlobalUnlock(hGlobalMF);
990 pmedium->u.hGlobal = hGlobalMF;
991 pmedium->tymed = TYMED_MFPICT;
992 hrRet = S_OK;
994 cleanup:
996 HeapFree(GetProcessHeap(), 0, mfBits);
998 if (pStream)
999 IStream_Release(pStream);
1001 if (pStorage)
1002 IStorage_Release(pStorage);
1004 if (pPersistStorage)
1005 IPersistStorage_Release(pPersistStorage);
1007 return hrRet;
1010 /* TODO: Other formats are not implemented */
1012 return E_NOTIMPL;
1015 static HRESULT WINAPI DataCache_GetDataHere(
1016 IDataObject* iface,
1017 LPFORMATETC pformatetc,
1018 STGMEDIUM* pmedium)
1020 FIXME("stub\n");
1021 return E_NOTIMPL;
1024 static HRESULT WINAPI DataCache_QueryGetData(
1025 IDataObject* iface,
1026 LPFORMATETC pformatetc)
1028 FIXME("stub\n");
1029 return E_NOTIMPL;
1032 /************************************************************************
1033 * DataCache_EnumFormatEtc (IDataObject)
1035 * The data cache doesn't implement this method.
1037 * See Windows documentation for more details on IDataObject methods.
1039 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1040 IDataObject* iface,
1041 LPFORMATETC pformatectIn,
1042 LPFORMATETC pformatetcOut)
1044 TRACE("()\n");
1045 return E_NOTIMPL;
1048 /************************************************************************
1049 * DataCache_IDataObject_SetData (IDataObject)
1051 * This method is delegated to the IOleCache2 implementation.
1053 * See Windows documentation for more details on IDataObject methods.
1055 static HRESULT WINAPI DataCache_IDataObject_SetData(
1056 IDataObject* iface,
1057 LPFORMATETC pformatetc,
1058 STGMEDIUM* pmedium,
1059 BOOL fRelease)
1061 IOleCache2* oleCache = NULL;
1062 HRESULT hres;
1064 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1066 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1068 if (FAILED(hres))
1069 return E_UNEXPECTED;
1071 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1073 IOleCache2_Release(oleCache);
1075 return hres;
1078 /************************************************************************
1079 * DataCache_EnumFormatEtc (IDataObject)
1081 * The data cache doesn't implement this method.
1083 * See Windows documentation for more details on IDataObject methods.
1085 static HRESULT WINAPI DataCache_EnumFormatEtc(
1086 IDataObject* iface,
1087 DWORD dwDirection,
1088 IEnumFORMATETC** ppenumFormatEtc)
1090 TRACE("()\n");
1091 return E_NOTIMPL;
1094 /************************************************************************
1095 * DataCache_DAdvise (IDataObject)
1097 * The data cache doesn't support connections.
1099 * See Windows documentation for more details on IDataObject methods.
1101 static HRESULT WINAPI DataCache_DAdvise(
1102 IDataObject* iface,
1103 FORMATETC* pformatetc,
1104 DWORD advf,
1105 IAdviseSink* pAdvSink,
1106 DWORD* pdwConnection)
1108 TRACE("()\n");
1109 return OLE_E_ADVISENOTSUPPORTED;
1112 /************************************************************************
1113 * DataCache_DUnadvise (IDataObject)
1115 * The data cache doesn't support connections.
1117 * See Windows documentation for more details on IDataObject methods.
1119 static HRESULT WINAPI DataCache_DUnadvise(
1120 IDataObject* iface,
1121 DWORD dwConnection)
1123 TRACE("()\n");
1124 return OLE_E_NOCONNECTION;
1127 /************************************************************************
1128 * DataCache_EnumDAdvise (IDataObject)
1130 * The data cache doesn't support connections.
1132 * See Windows documentation for more details on IDataObject methods.
1134 static HRESULT WINAPI DataCache_EnumDAdvise(
1135 IDataObject* iface,
1136 IEnumSTATDATA** ppenumAdvise)
1138 TRACE("()\n");
1139 return OLE_E_ADVISENOTSUPPORTED;
1142 /*********************************************************
1143 * Method implementation for the IDataObject
1144 * part of the DataCache class.
1147 /************************************************************************
1148 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1150 * See Windows documentation for more details on IUnknown methods.
1152 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1153 IPersistStorage* iface,
1154 REFIID riid,
1155 void** ppvObject)
1157 DataCache *this = impl_from_IPersistStorage(iface);
1159 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1162 /************************************************************************
1163 * DataCache_IPersistStorage_AddRef (IUnknown)
1165 * See Windows documentation for more details on IUnknown methods.
1167 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1168 IPersistStorage* iface)
1170 DataCache *this = impl_from_IPersistStorage(iface);
1172 return IUnknown_AddRef(this->outerUnknown);
1175 /************************************************************************
1176 * DataCache_IPersistStorage_Release (IUnknown)
1178 * See Windows documentation for more details on IUnknown methods.
1180 static ULONG WINAPI DataCache_IPersistStorage_Release(
1181 IPersistStorage* iface)
1183 DataCache *this = impl_from_IPersistStorage(iface);
1185 return IUnknown_Release(this->outerUnknown);
1188 /************************************************************************
1189 * DataCache_GetClassID (IPersistStorage)
1191 * The data cache doesn't implement this method.
1193 * See Windows documentation for more details on IPersistStorage methods.
1195 static HRESULT WINAPI DataCache_GetClassID(
1196 IPersistStorage* iface,
1197 CLSID* pClassID)
1199 DataCache *This = impl_from_IPersistStorage(iface);
1200 DataCacheEntry *cache_entry;
1202 TRACE("(%p, %p)\n", iface, pClassID);
1204 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1206 if (cache_entry->storage != NULL)
1208 STATSTG statstg;
1209 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1210 if (SUCCEEDED(hr))
1212 memcpy(pClassID, &statstg.clsid, sizeof(*pClassID));
1213 return S_OK;
1218 memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID));
1220 return S_OK;
1223 /************************************************************************
1224 * DataCache_IsDirty (IPersistStorage)
1226 * See Windows documentation for more details on IPersistStorage methods.
1228 static HRESULT WINAPI DataCache_IsDirty(
1229 IPersistStorage* iface)
1231 DataCache *This = impl_from_IPersistStorage(iface);
1232 DataCacheEntry *cache_entry;
1234 TRACE("(%p)\n", iface);
1236 if (This->dirty)
1237 return S_OK;
1239 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1240 if (cache_entry->dirty)
1241 return S_OK;
1243 return S_FALSE;
1246 /************************************************************************
1247 * DataCache_InitNew (IPersistStorage)
1249 * The data cache implementation of IPersistStorage_InitNew simply stores
1250 * the storage pointer.
1252 * See Windows documentation for more details on IPersistStorage methods.
1254 static HRESULT WINAPI DataCache_InitNew(
1255 IPersistStorage* iface,
1256 IStorage* pStg)
1258 DataCache *This = impl_from_IPersistStorage(iface);
1260 TRACE("(%p, %p)\n", iface, pStg);
1262 if (This->presentationStorage != NULL)
1263 IStorage_Release(This->presentationStorage);
1265 This->presentationStorage = pStg;
1267 IStorage_AddRef(This->presentationStorage);
1268 This->dirty = TRUE;
1270 return S_OK;
1273 /************************************************************************
1274 * DataCache_Load (IPersistStorage)
1276 * The data cache implementation of IPersistStorage_Load doesn't
1277 * actually load anything. Instead, it holds on to the storage pointer
1278 * and it will load the presentation information when the
1279 * IDataObject_GetData or IViewObject2_Draw methods are called.
1281 * See Windows documentation for more details on IPersistStorage methods.
1283 static HRESULT WINAPI DataCache_Load(
1284 IPersistStorage* iface,
1285 IStorage* pStg)
1287 DataCache *This = impl_from_IPersistStorage(iface);
1288 STATSTG elem;
1289 IEnumSTATSTG *pEnum;
1290 HRESULT hr;
1292 TRACE("(%p, %p)\n", iface, pStg);
1294 if (This->presentationStorage != NULL)
1295 IStorage_Release(This->presentationStorage);
1297 This->presentationStorage = pStg;
1299 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1300 if (FAILED(hr)) return hr;
1302 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1304 if (DataCache_IsPresentationStream(&elem))
1306 IStream *pStm;
1308 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1309 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1310 &pStm);
1311 if (SUCCEEDED(hr))
1313 PresentationDataHeader header;
1314 ULONG actual_read;
1316 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
1318 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1319 if (hr == S_OK && actual_read == sizeof(header))
1321 DataCacheEntry *cache_entry;
1322 FORMATETC fmtetc;
1324 fmtetc.cfFormat = header.clipformat;
1325 fmtetc.ptd = NULL; /* FIXME */
1326 fmtetc.dwAspect = header.dvAspect;
1327 fmtetc.lindex = header.lindex;
1328 fmtetc.tymed = header.tymed;
1330 TRACE("loading entry with formatetc: "); dump_FORMATETC(&fmtetc); TRACE("\n");
1332 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1333 if (!cache_entry)
1334 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1335 if (SUCCEEDED(hr))
1337 DataCacheEntry_DiscardData(cache_entry);
1338 if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1339 cache_entry->storage = pStg;
1340 IStorage_AddRef(pStg);
1341 cache_entry->dirty = FALSE;
1345 IStream_Release(pStm);
1349 CoTaskMemFree(elem.pwcsName);
1352 This->dirty = FALSE;
1354 IEnumSTATSTG_Release(pEnum);
1356 IStorage_AddRef(This->presentationStorage);
1357 return S_OK;
1360 /************************************************************************
1361 * DataCache_Save (IPersistStorage)
1363 * Until we actually connect to a running object and retrieve new
1364 * information to it, we never have to save anything. However, it is
1365 * our responsibility to copy the information when saving to a new
1366 * storage.
1368 * See Windows documentation for more details on IPersistStorage methods.
1370 static HRESULT WINAPI DataCache_Save(
1371 IPersistStorage* iface,
1372 IStorage* pStg,
1373 BOOL fSameAsLoad)
1375 DataCache *This = impl_from_IPersistStorage(iface);
1376 DataCacheEntry *cache_entry;
1377 BOOL dirty = FALSE;
1378 HRESULT hr = S_OK;
1379 unsigned short stream_number = 0;
1381 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1383 dirty = This->dirty;
1384 if (!dirty)
1386 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1388 dirty = cache_entry->dirty;
1389 if (dirty)
1390 break;
1394 /* this is a shortcut if nothing changed */
1395 if (!dirty && !fSameAsLoad && This->presentationStorage)
1397 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1400 /* assign stream numbers to the cache entries */
1401 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1403 if (cache_entry->stream_number != stream_number)
1405 cache_entry->dirty = TRUE; /* needs to be written out again */
1406 cache_entry->stream_number = stream_number;
1408 stream_number++;
1411 /* write out the cache entries */
1412 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1414 if (!fSameAsLoad || cache_entry->dirty)
1416 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1417 if (FAILED(hr))
1418 break;
1420 cache_entry->dirty = FALSE;
1424 This->dirty = FALSE;
1425 return hr;
1428 /************************************************************************
1429 * DataCache_SaveCompleted (IPersistStorage)
1431 * This method is called to tell the cache to release the storage
1432 * pointer it's currently holding.
1434 * See Windows documentation for more details on IPersistStorage methods.
1436 static HRESULT WINAPI DataCache_SaveCompleted(
1437 IPersistStorage* iface,
1438 IStorage* pStgNew)
1440 TRACE("(%p, %p)\n", iface, pStgNew);
1442 if (pStgNew)
1445 * First, make sure we get our hands off any storage we have.
1448 IPersistStorage_HandsOffStorage(iface);
1451 * Then, attach to the new storage.
1454 DataCache_Load(iface, pStgNew);
1457 return S_OK;
1460 /************************************************************************
1461 * DataCache_HandsOffStorage (IPersistStorage)
1463 * This method is called to tell the cache to release the storage
1464 * pointer it's currently holding.
1466 * See Windows documentation for more details on IPersistStorage methods.
1468 static HRESULT WINAPI DataCache_HandsOffStorage(
1469 IPersistStorage* iface)
1471 DataCache *this = impl_from_IPersistStorage(iface);
1473 TRACE("(%p)\n", iface);
1475 if (this->presentationStorage != NULL)
1477 IStorage_Release(this->presentationStorage);
1478 this->presentationStorage = NULL;
1481 return S_OK;
1484 /*********************************************************
1485 * Method implementation for the IViewObject2
1486 * part of the DataCache class.
1489 /************************************************************************
1490 * DataCache_IViewObject2_QueryInterface (IUnknown)
1492 * See Windows documentation for more details on IUnknown methods.
1494 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1495 IViewObject2* iface,
1496 REFIID riid,
1497 void** ppvObject)
1499 DataCache *this = impl_from_IViewObject2(iface);
1501 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1504 /************************************************************************
1505 * DataCache_IViewObject2_AddRef (IUnknown)
1507 * See Windows documentation for more details on IUnknown methods.
1509 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1510 IViewObject2* iface)
1512 DataCache *this = impl_from_IViewObject2(iface);
1514 return IUnknown_AddRef(this->outerUnknown);
1517 /************************************************************************
1518 * DataCache_IViewObject2_Release (IUnknown)
1520 * See Windows documentation for more details on IUnknown methods.
1522 static ULONG WINAPI DataCache_IViewObject2_Release(
1523 IViewObject2* iface)
1525 DataCache *this = impl_from_IViewObject2(iface);
1527 return IUnknown_Release(this->outerUnknown);
1530 /************************************************************************
1531 * DataCache_Draw (IViewObject2)
1533 * This method will draw the cached representation of the object
1534 * to the given device context.
1536 * See Windows documentation for more details on IViewObject2 methods.
1538 static HRESULT WINAPI DataCache_Draw(
1539 IViewObject2* iface,
1540 DWORD dwDrawAspect,
1541 LONG lindex,
1542 void* pvAspect,
1543 DVTARGETDEVICE* ptd,
1544 HDC hdcTargetDev,
1545 HDC hdcDraw,
1546 LPCRECTL lprcBounds,
1547 LPCRECTL lprcWBounds,
1548 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1549 ULONG_PTR dwContinue)
1551 DataCache *This = impl_from_IViewObject2(iface);
1552 HRESULT hres;
1553 DataCacheEntry *cache_entry;
1555 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1556 iface,
1557 dwDrawAspect,
1558 lindex,
1559 pvAspect,
1560 hdcTargetDev,
1561 hdcDraw,
1562 lprcBounds,
1563 lprcWBounds,
1564 pfnContinue,
1565 dwContinue);
1568 * Sanity check
1570 if (lprcBounds==NULL)
1571 return E_INVALIDARG;
1573 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1575 /* FIXME: compare ptd too */
1576 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1577 (cache_entry->fmtetc.lindex != lindex))
1578 continue;
1580 /* if the data hasn't been loaded yet, do it now */
1581 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1583 hres = DataCacheEntry_LoadData(cache_entry);
1584 if (FAILED(hres))
1585 continue;
1588 /* no data */
1589 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1590 continue;
1592 switch (cache_entry->data_cf)
1594 case CF_METAFILEPICT:
1597 * We have to be careful not to modify the state of the
1598 * DC.
1600 INT prevMapMode;
1601 SIZE oldWindowExt;
1602 SIZE oldViewportExt;
1603 POINT oldViewportOrg;
1604 METAFILEPICT *mfpict;
1606 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1607 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1608 continue;
1610 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1612 SetWindowExtEx(hdcDraw,
1613 mfpict->xExt,
1614 mfpict->yExt,
1615 &oldWindowExt);
1617 SetViewportExtEx(hdcDraw,
1618 lprcBounds->right - lprcBounds->left,
1619 lprcBounds->bottom - lprcBounds->top,
1620 &oldViewportExt);
1622 SetViewportOrgEx(hdcDraw,
1623 lprcBounds->left,
1624 lprcBounds->top,
1625 &oldViewportOrg);
1627 PlayMetaFile(hdcDraw, mfpict->hMF);
1629 SetWindowExtEx(hdcDraw,
1630 oldWindowExt.cx,
1631 oldWindowExt.cy,
1632 NULL);
1634 SetViewportExtEx(hdcDraw,
1635 oldViewportExt.cx,
1636 oldViewportExt.cy,
1637 NULL);
1639 SetViewportOrgEx(hdcDraw,
1640 oldViewportOrg.x,
1641 oldViewportOrg.y,
1642 NULL);
1644 SetMapMode(hdcDraw, prevMapMode);
1646 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1648 return S_OK;
1653 WARN("no data could be found to be drawn\n");
1655 return OLE_E_BLANK;
1658 static HRESULT WINAPI DataCache_GetColorSet(
1659 IViewObject2* iface,
1660 DWORD dwDrawAspect,
1661 LONG lindex,
1662 void* pvAspect,
1663 DVTARGETDEVICE* ptd,
1664 HDC hicTargetDevice,
1665 LOGPALETTE** ppColorSet)
1667 FIXME("stub\n");
1668 return E_NOTIMPL;
1671 static HRESULT WINAPI DataCache_Freeze(
1672 IViewObject2* iface,
1673 DWORD dwDrawAspect,
1674 LONG lindex,
1675 void* pvAspect,
1676 DWORD* pdwFreeze)
1678 FIXME("stub\n");
1679 return E_NOTIMPL;
1682 static HRESULT WINAPI DataCache_Unfreeze(
1683 IViewObject2* iface,
1684 DWORD dwFreeze)
1686 FIXME("stub\n");
1687 return E_NOTIMPL;
1690 /************************************************************************
1691 * DataCache_SetAdvise (IViewObject2)
1693 * This sets-up an advisory sink with the data cache. When the object's
1694 * view changes, this sink is called.
1696 * See Windows documentation for more details on IViewObject2 methods.
1698 static HRESULT WINAPI DataCache_SetAdvise(
1699 IViewObject2* iface,
1700 DWORD aspects,
1701 DWORD advf,
1702 IAdviseSink* pAdvSink)
1704 DataCache *this = impl_from_IViewObject2(iface);
1706 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1709 * A call to this function removes the previous sink
1711 if (this->sinkInterface != NULL)
1713 IAdviseSink_Release(this->sinkInterface);
1714 this->sinkInterface = NULL;
1715 this->sinkAspects = 0;
1716 this->sinkAdviseFlag = 0;
1720 * Now, setup the new one.
1722 if (pAdvSink!=NULL)
1724 this->sinkInterface = pAdvSink;
1725 this->sinkAspects = aspects;
1726 this->sinkAdviseFlag = advf;
1728 IAdviseSink_AddRef(this->sinkInterface);
1732 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1733 * sink immediately.
1735 if (advf & ADVF_PRIMEFIRST)
1737 DataCache_FireOnViewChange(this, aspects, -1);
1740 return S_OK;
1743 /************************************************************************
1744 * DataCache_GetAdvise (IViewObject2)
1746 * This method queries the current state of the advise sink
1747 * installed on the data cache.
1749 * See Windows documentation for more details on IViewObject2 methods.
1751 static HRESULT WINAPI DataCache_GetAdvise(
1752 IViewObject2* iface,
1753 DWORD* pAspects,
1754 DWORD* pAdvf,
1755 IAdviseSink** ppAdvSink)
1757 DataCache *this = impl_from_IViewObject2(iface);
1759 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1762 * Just copy all the requested values.
1764 if (pAspects!=NULL)
1765 *pAspects = this->sinkAspects;
1767 if (pAdvf!=NULL)
1768 *pAdvf = this->sinkAdviseFlag;
1770 if (ppAdvSink!=NULL)
1772 if (this->sinkInterface != NULL)
1773 IAdviseSink_QueryInterface(this->sinkInterface,
1774 &IID_IAdviseSink,
1775 (void**)ppAdvSink);
1776 else *ppAdvSink = NULL;
1779 return S_OK;
1782 /************************************************************************
1783 * DataCache_GetExtent (IViewObject2)
1785 * This method retrieves the "natural" size of this cached object.
1787 * See Windows documentation for more details on IViewObject2 methods.
1789 static HRESULT WINAPI DataCache_GetExtent(
1790 IViewObject2* iface,
1791 DWORD dwDrawAspect,
1792 LONG lindex,
1793 DVTARGETDEVICE* ptd,
1794 LPSIZEL lpsizel)
1796 DataCache *This = impl_from_IViewObject2(iface);
1797 HRESULT hres = E_FAIL;
1798 DataCacheEntry *cache_entry;
1800 TRACE("(%p, %x, %d, %p, %p)\n",
1801 iface, dwDrawAspect, lindex, ptd, lpsizel);
1804 * Sanity check
1806 if (lpsizel==NULL)
1807 return E_POINTER;
1810 * Initialize the out parameter.
1812 lpsizel->cx = 0;
1813 lpsizel->cy = 0;
1816 * This flag should be set to -1.
1818 if (lindex!=-1)
1819 FIXME("Unimplemented flag lindex = %d\n", lindex);
1822 * Right now, we support only the callback from
1823 * the default handler.
1825 if (ptd!=NULL)
1826 FIXME("Unimplemented ptd = %p\n", ptd);
1828 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1830 /* FIXME: compare ptd too */
1831 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1832 (cache_entry->fmtetc.lindex != lindex))
1833 continue;
1835 /* if the data hasn't been loaded yet, do it now */
1836 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1838 hres = DataCacheEntry_LoadData(cache_entry);
1839 if (FAILED(hres))
1840 continue;
1843 /* no data */
1844 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1845 continue;
1848 switch (cache_entry->data_cf)
1850 case CF_METAFILEPICT:
1852 METAFILEPICT *mfpict;
1854 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1855 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1856 continue;
1858 lpsizel->cx = mfpict->xExt;
1859 lpsizel->cy = mfpict->yExt;
1861 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1863 return S_OK;
1868 WARN("no data could be found to get the extents from\n");
1871 * This method returns OLE_E_BLANK when it fails.
1873 return OLE_E_BLANK;
1877 /*********************************************************
1878 * Method implementation for the IOleCache2
1879 * part of the DataCache class.
1882 /************************************************************************
1883 * DataCache_IOleCache2_QueryInterface (IUnknown)
1885 * See Windows documentation for more details on IUnknown methods.
1887 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1888 IOleCache2* iface,
1889 REFIID riid,
1890 void** ppvObject)
1892 DataCache *this = impl_from_IOleCache2(iface);
1894 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1897 /************************************************************************
1898 * DataCache_IOleCache2_AddRef (IUnknown)
1900 * See Windows documentation for more details on IUnknown methods.
1902 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1903 IOleCache2* iface)
1905 DataCache *this = impl_from_IOleCache2(iface);
1907 return IUnknown_AddRef(this->outerUnknown);
1910 /************************************************************************
1911 * DataCache_IOleCache2_Release (IUnknown)
1913 * See Windows documentation for more details on IUnknown methods.
1915 static ULONG WINAPI DataCache_IOleCache2_Release(
1916 IOleCache2* iface)
1918 DataCache *this = impl_from_IOleCache2(iface);
1920 return IUnknown_Release(this->outerUnknown);
1923 static HRESULT WINAPI DataCache_Cache(
1924 IOleCache2* iface,
1925 FORMATETC* pformatetc,
1926 DWORD advf,
1927 DWORD* pdwConnection)
1929 DataCache *This = impl_from_IOleCache2(iface);
1930 DataCacheEntry *cache_entry;
1931 HRESULT hr;
1933 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1934 TRACE("pformatetc = "); dump_FORMATETC(pformatetc); TRACE("\n");
1936 *pdwConnection = 0;
1938 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1939 if (cache_entry)
1941 TRACE("found an existing cache entry\n");
1942 *pdwConnection = cache_entry->id;
1943 return CACHE_S_SAMECACHE;
1946 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1948 if (SUCCEEDED(hr))
1949 *pdwConnection = cache_entry->id;
1951 return hr;
1954 static HRESULT WINAPI DataCache_Uncache(
1955 IOleCache2* iface,
1956 DWORD dwConnection)
1958 DataCache *This = impl_from_IOleCache2(iface);
1959 DataCacheEntry *cache_entry;
1961 TRACE("(%d)\n", dwConnection);
1963 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1964 if (cache_entry->id == dwConnection)
1966 DataCacheEntry_Destroy(cache_entry);
1967 return S_OK;
1970 WARN("no connection found for %d\n", dwConnection);
1972 return OLE_E_NOCONNECTION;
1975 static HRESULT WINAPI DataCache_EnumCache(
1976 IOleCache2* iface,
1977 IEnumSTATDATA** ppenumSTATDATA)
1979 FIXME("stub\n");
1980 return E_NOTIMPL;
1983 static HRESULT WINAPI DataCache_InitCache(
1984 IOleCache2* iface,
1985 IDataObject* pDataObject)
1987 FIXME("stub\n");
1988 return E_NOTIMPL;
1991 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1992 IOleCache2* iface,
1993 FORMATETC* pformatetc,
1994 STGMEDIUM* pmedium,
1995 BOOL fRelease)
1997 DataCache *This = impl_from_IOleCache2(iface);
1998 DataCacheEntry *cache_entry;
1999 HRESULT hr;
2001 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2002 TRACE("formatetc = "); dump_FORMATETC(pformatetc); TRACE("\n");
2004 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2005 if (cache_entry)
2007 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2009 if (SUCCEEDED(hr))
2010 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2011 cache_entry->fmtetc.lindex);
2013 return hr;
2015 WARN("cache entry not found\n");
2017 return OLE_E_BLANK;
2020 static HRESULT WINAPI DataCache_UpdateCache(
2021 IOleCache2* iface,
2022 LPDATAOBJECT pDataObject,
2023 DWORD grfUpdf,
2024 LPVOID pReserved)
2026 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2027 return E_NOTIMPL;
2030 static HRESULT WINAPI DataCache_DiscardCache(
2031 IOleCache2* iface,
2032 DWORD dwDiscardOptions)
2034 DataCache *This = impl_from_IOleCache2(iface);
2035 DataCacheEntry *cache_entry;
2036 HRESULT hr = S_OK;
2038 TRACE("(%d)\n", dwDiscardOptions);
2040 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2041 hr = DataCache_Save((IPersistStorage *)&This->lpvtblIPersistStorage,
2042 This->presentationStorage, TRUE);
2044 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2046 hr = DataCacheEntry_DiscardData(cache_entry);
2047 if (FAILED(hr))
2048 break;
2051 return hr;
2055 /*********************************************************
2056 * Method implementation for the IOleCacheControl
2057 * part of the DataCache class.
2060 /************************************************************************
2061 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2063 * See Windows documentation for more details on IUnknown methods.
2065 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2066 IOleCacheControl* iface,
2067 REFIID riid,
2068 void** ppvObject)
2070 DataCache *this = impl_from_IOleCacheControl(iface);
2072 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2075 /************************************************************************
2076 * DataCache_IOleCacheControl_AddRef (IUnknown)
2078 * See Windows documentation for more details on IUnknown methods.
2080 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2081 IOleCacheControl* iface)
2083 DataCache *this = impl_from_IOleCacheControl(iface);
2085 return IUnknown_AddRef(this->outerUnknown);
2088 /************************************************************************
2089 * DataCache_IOleCacheControl_Release (IUnknown)
2091 * See Windows documentation for more details on IUnknown methods.
2093 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2094 IOleCacheControl* iface)
2096 DataCache *this = impl_from_IOleCacheControl(iface);
2098 return IUnknown_Release(this->outerUnknown);
2101 static HRESULT WINAPI DataCache_OnRun(
2102 IOleCacheControl* iface,
2103 LPDATAOBJECT pDataObject)
2105 FIXME("stub\n");
2106 return E_NOTIMPL;
2109 static HRESULT WINAPI DataCache_OnStop(
2110 IOleCacheControl* iface)
2112 FIXME("stub\n");
2113 return E_NOTIMPL;
2117 * Virtual function tables for the DataCache class.
2119 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2121 DataCache_NDIUnknown_QueryInterface,
2122 DataCache_NDIUnknown_AddRef,
2123 DataCache_NDIUnknown_Release
2126 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2128 DataCache_IDataObject_QueryInterface,
2129 DataCache_IDataObject_AddRef,
2130 DataCache_IDataObject_Release,
2131 DataCache_GetData,
2132 DataCache_GetDataHere,
2133 DataCache_QueryGetData,
2134 DataCache_GetCanonicalFormatEtc,
2135 DataCache_IDataObject_SetData,
2136 DataCache_EnumFormatEtc,
2137 DataCache_DAdvise,
2138 DataCache_DUnadvise,
2139 DataCache_EnumDAdvise
2142 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2144 DataCache_IPersistStorage_QueryInterface,
2145 DataCache_IPersistStorage_AddRef,
2146 DataCache_IPersistStorage_Release,
2147 DataCache_GetClassID,
2148 DataCache_IsDirty,
2149 DataCache_InitNew,
2150 DataCache_Load,
2151 DataCache_Save,
2152 DataCache_SaveCompleted,
2153 DataCache_HandsOffStorage
2156 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2158 DataCache_IViewObject2_QueryInterface,
2159 DataCache_IViewObject2_AddRef,
2160 DataCache_IViewObject2_Release,
2161 DataCache_Draw,
2162 DataCache_GetColorSet,
2163 DataCache_Freeze,
2164 DataCache_Unfreeze,
2165 DataCache_SetAdvise,
2166 DataCache_GetAdvise,
2167 DataCache_GetExtent
2170 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2172 DataCache_IOleCache2_QueryInterface,
2173 DataCache_IOleCache2_AddRef,
2174 DataCache_IOleCache2_Release,
2175 DataCache_Cache,
2176 DataCache_Uncache,
2177 DataCache_EnumCache,
2178 DataCache_InitCache,
2179 DataCache_IOleCache2_SetData,
2180 DataCache_UpdateCache,
2181 DataCache_DiscardCache
2184 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2186 DataCache_IOleCacheControl_QueryInterface,
2187 DataCache_IOleCacheControl_AddRef,
2188 DataCache_IOleCacheControl_Release,
2189 DataCache_OnRun,
2190 DataCache_OnStop
2193 /******************************************************************************
2194 * CreateDataCache [OLE32.@]
2196 * Creates a data cache to allow an object to render one or more of its views,
2197 * whether running or not.
2199 * PARAMS
2200 * pUnkOuter [I] Outer unknown for the object.
2201 * rclsid [I]
2202 * riid [I] IID of interface to return.
2203 * ppvObj [O] Address where the data cache object will be stored on return.
2205 * RETURNS
2206 * Success: S_OK.
2207 * Failure: HRESULT code.
2209 * NOTES
2210 * The following interfaces are supported by the returned data cache object:
2211 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorae, IDataObject,
2212 * IViewObject and IViewObject2.
2214 HRESULT WINAPI CreateDataCache(
2215 LPUNKNOWN pUnkOuter,
2216 REFCLSID rclsid,
2217 REFIID riid,
2218 LPVOID* ppvObj)
2220 DataCache* newCache = NULL;
2221 HRESULT hr = S_OK;
2223 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2226 * Sanity check
2228 if (ppvObj==0)
2229 return E_POINTER;
2231 *ppvObj = 0;
2234 * If this cache is constructed for aggregation, make sure
2235 * the caller is requesting the IUnknown interface.
2236 * This is necessary because it's the only time the non-delegating
2237 * IUnknown pointer can be returned to the outside.
2239 if ( (pUnkOuter!=NULL) &&
2240 (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
2241 return CLASS_E_NOAGGREGATION;
2244 * Try to construct a new instance of the class.
2246 newCache = DataCache_Construct(rclsid,
2247 pUnkOuter);
2249 if (newCache == 0)
2250 return E_OUTOFMEMORY;
2253 * Make sure it supports the interface required by the caller.
2255 hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
2258 * Release the reference obtained in the constructor. If
2259 * the QueryInterface was unsuccessful, it will free the class.
2261 IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
2263 return hr;
2266 /*********************************************************
2267 * Method implementation for DataCache class.
2269 static DataCache* DataCache_Construct(
2270 REFCLSID clsid,
2271 LPUNKNOWN pUnkOuter)
2273 DataCache* newObject = 0;
2276 * Allocate space for the object.
2278 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2280 if (newObject==0)
2281 return newObject;
2284 * Initialize the virtual function table.
2286 newObject->lpVtbl = &DataCache_IDataObject_VTable;
2287 newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
2288 newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
2289 newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
2290 newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
2291 newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
2294 * Start with one reference count. The caller of this function
2295 * must release the interface pointer when it is done.
2297 newObject->ref = 1;
2300 * Initialize the outer unknown
2301 * We don't keep a reference on the outer unknown since, the way
2302 * aggregation works, our lifetime is at least as large as its
2303 * lifetime.
2305 if (pUnkOuter==NULL)
2306 pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
2308 newObject->outerUnknown = pUnkOuter;
2311 * Initialize the other members of the structure.
2313 newObject->sinkAspects = 0;
2314 newObject->sinkAdviseFlag = 0;
2315 newObject->sinkInterface = 0;
2316 newObject->presentationStorage = NULL;
2317 list_init(&newObject->cache_list);
2318 newObject->last_cache_id = 1;
2319 newObject->dirty = FALSE;
2321 return newObject;