gdiplus: Implement GdipBeginContainer.
[wine.git] / dlls / ole32 / datacache.c
blob441a8746fc8cd73d498ef560cab603023525ee95
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.
47 #include <stdarg.h>
48 #include <string.h>
50 #define COBJMACROS
51 #define NONAMELESSUNION
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 storage.
71 typedef struct PresentationDataHeader
73 /* clipformat:
74 * - standard clipformat:
75 * DWORD length = 0xffffffff;
76 * DWORD cfFormat;
77 * - or custom clipformat:
78 * DWORD length;
79 * CHAR format_name[length]; (null-terminated)
81 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
82 DVASPECT dvAspect;
83 DWORD lindex;
84 DWORD tymed;
85 DWORD unknown7; /* 0 */
86 DWORD dwObjectExtentX;
87 DWORD dwObjectExtentY;
88 DWORD dwSize;
89 } PresentationDataHeader;
91 enum stream_type
93 no_stream,
94 pres_stream,
95 contents_stream
98 typedef struct DataCacheEntry
100 struct list entry;
101 /* format of this entry */
102 FORMATETC fmtetc;
103 /* the clipboard format of the data */
104 CLIPFORMAT data_cf;
105 /* cached data */
106 STGMEDIUM stgmedium;
108 * This stream pointer is set through a call to
109 * IPersistStorage_Load. This is where the visual
110 * representation of the object is stored.
112 IStream *stream;
113 enum stream_type stream_type;
114 /* connection ID */
115 DWORD id;
116 /* dirty flag */
117 BOOL dirty;
118 /* stream number (-1 if not set ) */
119 unsigned short stream_number;
120 /* sink id set when object is running */
121 DWORD sink_id;
122 /* Advise sink flags */
123 DWORD advise_flags;
124 } DataCacheEntry;
126 /****************************************************************************
127 * DataCache
129 struct DataCache
132 * List all interface here
134 IUnknown IUnknown_inner;
135 IDataObject IDataObject_iface;
136 IPersistStorage IPersistStorage_iface;
137 IViewObject2 IViewObject2_iface;
138 IOleCache2 IOleCache2_iface;
139 IOleCacheControl IOleCacheControl_iface;
141 /* The sink that is connected to a remote object.
142 The other interfaces are not available by QI'ing the sink and vice-versa */
143 IAdviseSink IAdviseSink_iface;
146 * Reference count of this object
148 LONG ref;
151 * IUnknown implementation of the outer object.
153 IUnknown *outer_unk;
156 * The user of this object can setup ONE advise sink
157 * connection with the object. These parameters describe
158 * that connection.
160 DWORD sinkAspects;
161 DWORD sinkAdviseFlag;
162 IAdviseSink* sinkInterface;
163 IStorage *presentationStorage;
165 /* list of cache entries */
166 struct list cache_list;
167 /* last id assigned to an entry */
168 DWORD last_cache_id;
169 /* dirty flag */
170 BOOL dirty;
171 /* running object set by OnRun */
172 IDataObject *running_object;
175 typedef struct DataCache DataCache;
178 * Here, I define utility macros to help with the casting of the
179 * "this" parameter.
180 * There is a version to accommodate all of the VTables implemented
181 * by this object.
184 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
186 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
189 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
191 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
194 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
196 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
199 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
201 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
204 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
206 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
209 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
211 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
214 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
216 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
219 const char *debugstr_formatetc(const FORMATETC *formatetc)
221 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
222 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
223 formatetc->lindex, formatetc->tymed);
226 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
228 list_remove(&cache_entry->entry);
229 if (cache_entry->stream)
230 IStream_Release(cache_entry->stream);
231 HeapFree(GetProcessHeap(), 0, cache_entry->fmtetc.ptd);
232 ReleaseStgMedium(&cache_entry->stgmedium);
233 if(cache_entry->sink_id)
234 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
236 HeapFree(GetProcessHeap(), 0, cache_entry);
239 static void DataCache_Destroy(
240 DataCache* ptrToDestroy)
242 DataCacheEntry *cache_entry, *next_cache_entry;
244 TRACE("()\n");
246 if (ptrToDestroy->sinkInterface != NULL)
248 IAdviseSink_Release(ptrToDestroy->sinkInterface);
249 ptrToDestroy->sinkInterface = NULL;
252 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
253 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
255 if (ptrToDestroy->presentationStorage != NULL)
257 IStorage_Release(ptrToDestroy->presentationStorage);
258 ptrToDestroy->presentationStorage = NULL;
262 * Free the datacache pointer.
264 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
267 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
269 DataCacheEntry *cache_entry;
270 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
272 /* FIXME: also compare DVTARGETDEVICEs */
273 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
274 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
275 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
276 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
277 return cache_entry;
279 return NULL;
282 /* checks that the clipformat and tymed are valid and returns an error if they
283 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
284 * DataCache_Draw */
285 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed, BOOL load)
287 if (!cfFormat || !tymed ||
288 (cfFormat == CF_METAFILEPICT && (tymed == TYMED_MFPICT || load)) ||
289 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
290 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
291 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
292 return S_OK;
293 else if (tymed == TYMED_HGLOBAL)
294 return CACHE_S_FORMATETC_NOTSUPPORTED;
295 else
297 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
298 return DV_E_TYMED;
302 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry, BOOL load)
304 HRESULT hr;
306 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed, load);
307 if (FAILED(hr))
308 return hr;
309 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
310 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
312 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
313 if (!*cache_entry)
314 return E_OUTOFMEMORY;
316 (*cache_entry)->fmtetc = *formatetc;
317 if (formatetc->ptd)
319 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
320 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
322 (*cache_entry)->data_cf = 0;
323 (*cache_entry)->stgmedium.tymed = TYMED_NULL;
324 (*cache_entry)->stgmedium.pUnkForRelease = NULL;
325 (*cache_entry)->stream = NULL;
326 (*cache_entry)->stream_type = no_stream;
327 (*cache_entry)->id = This->last_cache_id++;
328 (*cache_entry)->dirty = TRUE;
329 (*cache_entry)->stream_number = -1;
330 (*cache_entry)->sink_id = 0;
331 (*cache_entry)->advise_flags = 0;
332 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
333 return hr;
336 /************************************************************************
337 * DataCache_FireOnViewChange
339 * This method will fire an OnViewChange notification to the advise
340 * sink registered with the datacache.
342 * See IAdviseSink::OnViewChange for more details.
344 static void DataCache_FireOnViewChange(
345 DataCache* this,
346 DWORD aspect,
347 LONG lindex)
349 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
352 * The sink supplies a filter when it registers
353 * we make sure we only send the notifications when that
354 * filter matches.
356 if ((this->sinkAspects & aspect) != 0)
358 if (this->sinkInterface != NULL)
360 IAdviseSink_OnViewChange(this->sinkInterface,
361 aspect,
362 lindex);
365 * Some sinks want to be unregistered automatically when
366 * the first notification goes out.
368 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
370 IAdviseSink_Release(this->sinkInterface);
372 this->sinkInterface = NULL;
373 this->sinkAspects = 0;
374 this->sinkAdviseFlag = 0;
380 /* Helper for DataCacheEntry_OpenPresStream */
381 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
383 /* The presentation streams have names of the form "\002OlePresXXX",
384 * where XXX goes from 000 to 999. */
385 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
387 LPCWSTR name = elem->pwcsName;
389 return (elem->type == STGTY_STREAM)
390 && (strlenW(name) == 11)
391 && (strncmpW(name, OlePres, 8) == 0)
392 && (name[8] >= '0') && (name[8] <= '9')
393 && (name[9] >= '0') && (name[9] <= '9')
394 && (name[10] >= '0') && (name[10] <= '9');
397 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
399 DWORD length;
400 HRESULT hr;
401 ULONG read;
403 *clipformat = 0;
405 hr = IStream_Read(stream, &length, sizeof(length), &read);
406 if (hr != S_OK || read != sizeof(length))
407 return DV_E_CLIPFORMAT;
408 if (length == -1)
410 DWORD cf;
411 hr = IStream_Read(stream, &cf, sizeof(cf), &read);
412 if (hr != S_OK || read != sizeof(cf))
413 return DV_E_CLIPFORMAT;
414 *clipformat = cf;
416 else
418 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
419 if (!format_name)
420 return E_OUTOFMEMORY;
421 hr = IStream_Read(stream, format_name, length, &read);
422 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
424 HeapFree(GetProcessHeap(), 0, format_name);
425 return DV_E_CLIPFORMAT;
427 *clipformat = RegisterClipboardFormatA(format_name);
428 HeapFree(GetProcessHeap(), 0, format_name);
430 return S_OK;
433 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
435 DWORD length;
436 HRESULT hr;
438 if (clipformat < 0xc000)
439 length = -1;
440 else
441 length = GetClipboardFormatNameA(clipformat, NULL, 0);
442 hr = IStream_Write(stream, &length, sizeof(length), NULL);
443 if (FAILED(hr))
444 return hr;
445 if (clipformat < 0xc000)
447 DWORD cf = clipformat;
448 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
450 else
452 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
453 if (!format_name)
454 return E_OUTOFMEMORY;
455 GetClipboardFormatNameA(clipformat, format_name, length);
456 hr = IStream_Write(stream, format_name, length, NULL);
457 HeapFree(GetProcessHeap(), 0, format_name);
459 return hr;
462 /************************************************************************
463 * DataCacheEntry_OpenPresStream
465 * This method will find the stream for the given presentation. It makes
466 * no attempt at fallback.
468 * Param:
469 * this - Pointer to the DataCache object
470 * drawAspect - The aspect of the object that we wish to draw.
471 * pStm - A returned stream. It points to the beginning of the
472 * - presentation data, including the header.
474 * Errors:
475 * S_OK The requested stream has been opened.
476 * OLE_E_BLANK The requested stream could not be found.
477 * Quite a few others I'm too lazy to map correctly.
479 * Notes:
480 * Algorithm: Scan the elements of the presentation storage, looking
481 * for presentation streams. For each presentation stream,
482 * load the header and check to see if the aspect matches.
484 * If a fallback is desired, just opening the first presentation stream
485 * is a possibility.
487 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
489 HRESULT hr;
490 LARGE_INTEGER offset;
492 if (cache_entry->stream)
494 /* Rewind the stream before returning it. */
495 offset.QuadPart = 0;
497 hr = IStream_Seek( cache_entry->stream, offset, STREAM_SEEK_SET, NULL );
498 if (SUCCEEDED( hr ))
500 *ppStm = cache_entry->stream;
501 IStream_AddRef( cache_entry->stream );
504 else
505 hr = OLE_E_BLANK;
507 return hr;
511 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
513 HRESULT hr;
514 STATSTG stat;
515 ULARGE_INTEGER current_pos;
516 void *bits;
517 METAFILEPICT *mfpict;
518 HGLOBAL hmfpict;
519 PresentationDataHeader header;
520 CLIPFORMAT clipformat;
521 static const LARGE_INTEGER offset_zero;
522 ULONG read;
524 if (cache_entry->stream_type != pres_stream)
526 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
527 return E_FAIL;
530 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
531 if (FAILED( hr )) return hr;
533 hr = read_clipformat( stm, &clipformat );
534 if (FAILED( hr )) return hr;
536 hr = IStream_Read( stm, &header, sizeof(header), &read );
537 if (hr != S_OK || read != sizeof(header)) return E_FAIL;
539 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
540 if (FAILED( hr )) return hr;
542 stat.cbSize.QuadPart -= current_pos.QuadPart;
544 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
545 if (!hmfpict) return E_OUTOFMEMORY;
546 mfpict = GlobalLock( hmfpict );
548 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
549 if (!bits)
551 GlobalFree( hmfpict );
552 return E_OUTOFMEMORY;
555 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
556 if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL;
558 if (SUCCEEDED( hr ))
560 /* FIXME: get this from the stream */
561 mfpict->mm = MM_ANISOTROPIC;
562 mfpict->xExt = header.dwObjectExtentX;
563 mfpict->yExt = header.dwObjectExtentY;
564 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
565 if (!mfpict->hMF)
566 hr = E_FAIL;
569 GlobalUnlock( hmfpict );
570 if (SUCCEEDED( hr ))
572 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
573 cache_entry->stgmedium.tymed = TYMED_MFPICT;
574 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
576 else
577 GlobalFree( hmfpict );
579 HeapFree( GetProcessHeap(), 0, bits );
581 return hr;
584 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
586 HRESULT hr;
587 STATSTG stat;
588 void *dib;
589 HGLOBAL hglobal;
590 ULONG read;
592 if (cache_entry->stream_type != contents_stream)
594 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
595 return E_FAIL;
598 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
599 if (FAILED( hr )) return hr;
601 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
602 if (!hglobal) return E_OUTOFMEMORY;
603 dib = GlobalLock( hglobal );
605 hr = IStream_Read( stm, dib, stat.cbSize.u.LowPart, &read );
606 GlobalUnlock( hglobal );
608 if (hr != S_OK || read != stat.cbSize.u.LowPart)
610 GlobalFree( hglobal );
611 return E_FAIL;
614 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
615 cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
616 cache_entry->stgmedium.u.hGlobal = hglobal;
618 return S_OK;
621 /************************************************************************
622 * DataCacheEntry_LoadData
624 * This method will read information for the requested presentation
625 * into the given structure.
627 * Param:
628 * This - The entry to load the data from.
630 * Returns:
631 * This method returns a metafile handle if it is successful.
632 * it will return 0 if not.
634 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
636 HRESULT hr;
637 IStream *stm;
639 hr = DataCacheEntry_OpenPresStream( cache_entry, &stm );
640 if (FAILED(hr)) return hr;
642 switch (cache_entry->fmtetc.cfFormat)
644 case CF_METAFILEPICT:
645 hr = load_mf_pict( cache_entry, stm );
646 break;
648 case CF_DIB:
649 hr = load_dib( cache_entry, stm );
650 break;
652 default:
653 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
654 hr = E_NOTIMPL;
657 IStream_Release( stm );
658 return hr;
661 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
662 IStorage *storage, IStream **stream)
664 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
665 '0' + (cache_entry->stream_number / 100) % 10,
666 '0' + (cache_entry->stream_number / 10) % 10,
667 '0' + cache_entry->stream_number % 10, 0};
669 /* FIXME: cache the created stream in This? */
670 return IStorage_CreateStream(storage, wszName,
671 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
672 0, 0, stream);
675 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
676 BOOL same_as_load)
678 PresentationDataHeader header;
679 HRESULT hr;
680 IStream *pres_stream;
681 void *data = NULL;
683 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
685 hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
686 if (FAILED(hr))
687 return hr;
689 hr = write_clipformat(pres_stream, cache_entry->data_cf);
690 if (FAILED(hr))
691 return hr;
693 if (cache_entry->fmtetc.ptd)
694 FIXME("ptd not serialized\n");
695 header.unknown3 = 4;
696 header.dvAspect = cache_entry->fmtetc.dwAspect;
697 header.lindex = cache_entry->fmtetc.lindex;
698 header.tymed = cache_entry->stgmedium.tymed;
699 header.unknown7 = 0;
700 header.dwObjectExtentX = 0;
701 header.dwObjectExtentY = 0;
702 header.dwSize = 0;
704 /* size the data */
705 switch (cache_entry->data_cf)
707 case CF_METAFILEPICT:
709 if (cache_entry->stgmedium.tymed != TYMED_NULL)
711 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
712 if (!mfpict)
714 IStream_Release(pres_stream);
715 return DV_E_STGMEDIUM;
717 header.dwObjectExtentX = mfpict->xExt;
718 header.dwObjectExtentY = mfpict->yExt;
719 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
720 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
722 break;
724 default:
725 break;
729 * Write the header.
731 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
732 NULL);
733 if (FAILED(hr))
735 IStream_Release(pres_stream);
736 return hr;
739 /* get the data */
740 switch (cache_entry->data_cf)
742 case CF_METAFILEPICT:
744 if (cache_entry->stgmedium.tymed != TYMED_NULL)
746 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
747 if (!mfpict)
749 IStream_Release(pres_stream);
750 return DV_E_STGMEDIUM;
752 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
753 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
754 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
756 break;
758 default:
759 break;
762 if (data)
763 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
764 HeapFree(GetProcessHeap(), 0, data);
766 IStream_Release(pres_stream);
767 return hr;
770 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
771 * does no checking of whether src_stgm has a supported tymed, so this should be
772 * done in the caller */
773 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
774 const STGMEDIUM *src_stgm)
776 if (src_stgm->tymed == TYMED_MFPICT)
778 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
779 METAFILEPICT *dest_mfpict;
781 if (!src_mfpict)
782 return DV_E_STGMEDIUM;
783 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
784 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
785 if (!dest_mfpict)
787 GlobalUnlock(src_stgm->u.hMetaFilePict);
788 return E_OUTOFMEMORY;
790 *dest_mfpict = *src_mfpict;
791 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
792 GlobalUnlock(src_stgm->u.hMetaFilePict);
793 GlobalUnlock(dest_stgm->u.hMetaFilePict);
795 else if (src_stgm->tymed != TYMED_NULL)
797 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
798 GMEM_MOVEABLE);
799 if (!dest_stgm->u.hGlobal)
800 return E_OUTOFMEMORY;
802 dest_stgm->tymed = src_stgm->tymed;
803 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
804 if (dest_stgm->pUnkForRelease)
805 IUnknown_AddRef(dest_stgm->pUnkForRelease);
806 return S_OK;
809 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
810 const FORMATETC *formatetc,
811 const STGMEDIUM *stgmedium,
812 BOOL fRelease)
814 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
815 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
816 stgmedium->tymed == TYMED_NULL)
818 WARN("invalid formatetc\n");
819 return DV_E_FORMATETC;
822 cache_entry->dirty = TRUE;
823 ReleaseStgMedium(&cache_entry->stgmedium);
824 cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
825 if (fRelease)
827 cache_entry->stgmedium = *stgmedium;
828 return S_OK;
830 else
831 return copy_stg_medium(cache_entry->data_cf,
832 &cache_entry->stgmedium, stgmedium);
835 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
837 if (stgmedium->tymed == TYMED_NULL && cache_entry->stream)
839 HRESULT hr = DataCacheEntry_LoadData(cache_entry);
840 if (FAILED(hr))
841 return hr;
843 if (cache_entry->stgmedium.tymed == TYMED_NULL)
844 return OLE_E_BLANK;
845 return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
848 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
850 ReleaseStgMedium(&cache_entry->stgmedium);
851 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
852 return S_OK;
855 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
857 if (cache_entry->stream)
859 IStream_Release(cache_entry->stream);
860 cache_entry->stream = NULL;
864 /*********************************************************
865 * Method implementation for the non delegating IUnknown
866 * part of the DataCache class.
869 /************************************************************************
870 * DataCache_NDIUnknown_QueryInterface (IUnknown)
872 * This version of QueryInterface will not delegate its implementation
873 * to the outer unknown.
875 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
876 IUnknown* iface,
877 REFIID riid,
878 void** ppvObject)
880 DataCache *this = impl_from_IUnknown(iface);
882 if ( ppvObject==0 )
883 return E_INVALIDARG;
885 *ppvObject = 0;
887 if (IsEqualIID(&IID_IUnknown, riid))
889 *ppvObject = iface;
891 else if (IsEqualIID(&IID_IDataObject, riid))
893 *ppvObject = &this->IDataObject_iface;
895 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
896 IsEqualIID(&IID_IPersist, riid) )
898 *ppvObject = &this->IPersistStorage_iface;
900 else if ( IsEqualIID(&IID_IViewObject, riid) ||
901 IsEqualIID(&IID_IViewObject2, riid) )
903 *ppvObject = &this->IViewObject2_iface;
905 else if ( IsEqualIID(&IID_IOleCache, riid) ||
906 IsEqualIID(&IID_IOleCache2, riid) )
908 *ppvObject = &this->IOleCache2_iface;
910 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
912 *ppvObject = &this->IOleCacheControl_iface;
915 if ((*ppvObject)==0)
917 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
918 return E_NOINTERFACE;
921 IUnknown_AddRef((IUnknown*)*ppvObject);
923 return S_OK;
926 /************************************************************************
927 * DataCache_NDIUnknown_AddRef (IUnknown)
929 * This version of QueryInterface will not delegate its implementation
930 * to the outer unknown.
932 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
933 IUnknown* iface)
935 DataCache *this = impl_from_IUnknown(iface);
936 return InterlockedIncrement(&this->ref);
939 /************************************************************************
940 * DataCache_NDIUnknown_Release (IUnknown)
942 * This version of QueryInterface will not delegate its implementation
943 * to the outer unknown.
945 static ULONG WINAPI DataCache_NDIUnknown_Release(
946 IUnknown* iface)
948 DataCache *this = impl_from_IUnknown(iface);
949 ULONG ref;
951 ref = InterlockedDecrement(&this->ref);
953 if (ref == 0) DataCache_Destroy(this);
955 return ref;
958 /*********************************************************
959 * Method implementation for the IDataObject
960 * part of the DataCache class.
963 /************************************************************************
964 * DataCache_IDataObject_QueryInterface (IUnknown)
966 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
967 IDataObject* iface,
968 REFIID riid,
969 void** ppvObject)
971 DataCache *this = impl_from_IDataObject(iface);
973 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
976 /************************************************************************
977 * DataCache_IDataObject_AddRef (IUnknown)
979 static ULONG WINAPI DataCache_IDataObject_AddRef(
980 IDataObject* iface)
982 DataCache *this = impl_from_IDataObject(iface);
984 return IUnknown_AddRef(this->outer_unk);
987 /************************************************************************
988 * DataCache_IDataObject_Release (IUnknown)
990 static ULONG WINAPI DataCache_IDataObject_Release(
991 IDataObject* iface)
993 DataCache *this = impl_from_IDataObject(iface);
995 return IUnknown_Release(this->outer_unk);
998 /************************************************************************
999 * DataCache_GetData
1001 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1003 static HRESULT WINAPI DataCache_GetData(
1004 IDataObject* iface,
1005 LPFORMATETC pformatetcIn,
1006 STGMEDIUM* pmedium)
1008 DataCache *This = impl_from_IDataObject(iface);
1009 DataCacheEntry *cache_entry;
1011 memset(pmedium, 0, sizeof(*pmedium));
1013 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1014 if (!cache_entry)
1015 return OLE_E_BLANK;
1017 return DataCacheEntry_GetData(cache_entry, pmedium);
1020 static HRESULT WINAPI DataCache_GetDataHere(
1021 IDataObject* iface,
1022 LPFORMATETC pformatetc,
1023 STGMEDIUM* pmedium)
1025 FIXME("stub\n");
1026 return E_NOTIMPL;
1029 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1031 DataCache *This = impl_from_IDataObject( iface );
1032 DataCacheEntry *cache_entry;
1034 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1035 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1037 return cache_entry ? S_OK : S_FALSE;
1040 /************************************************************************
1041 * DataCache_EnumFormatEtc (IDataObject)
1043 * The data cache doesn't implement this method.
1045 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1046 IDataObject* iface,
1047 LPFORMATETC pformatectIn,
1048 LPFORMATETC pformatetcOut)
1050 TRACE("()\n");
1051 return E_NOTIMPL;
1054 /************************************************************************
1055 * DataCache_IDataObject_SetData (IDataObject)
1057 * This method is delegated to the IOleCache2 implementation.
1059 static HRESULT WINAPI DataCache_IDataObject_SetData(
1060 IDataObject* iface,
1061 LPFORMATETC pformatetc,
1062 STGMEDIUM* pmedium,
1063 BOOL fRelease)
1065 IOleCache2* oleCache = NULL;
1066 HRESULT hres;
1068 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1070 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1072 if (FAILED(hres))
1073 return E_UNEXPECTED;
1075 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1077 IOleCache2_Release(oleCache);
1079 return hres;
1082 /************************************************************************
1083 * DataCache_EnumFormatEtc (IDataObject)
1085 * The data cache doesn't implement this method.
1087 static HRESULT WINAPI DataCache_EnumFormatEtc(
1088 IDataObject* iface,
1089 DWORD dwDirection,
1090 IEnumFORMATETC** ppenumFormatEtc)
1092 TRACE("()\n");
1093 return E_NOTIMPL;
1096 /************************************************************************
1097 * DataCache_DAdvise (IDataObject)
1099 * The data cache doesn't support connections.
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 static HRESULT WINAPI DataCache_DUnadvise(
1118 IDataObject* iface,
1119 DWORD dwConnection)
1121 TRACE("()\n");
1122 return OLE_E_NOCONNECTION;
1125 /************************************************************************
1126 * DataCache_EnumDAdvise (IDataObject)
1128 * The data cache doesn't support connections.
1130 static HRESULT WINAPI DataCache_EnumDAdvise(
1131 IDataObject* iface,
1132 IEnumSTATDATA** ppenumAdvise)
1134 TRACE("()\n");
1135 return OLE_E_ADVISENOTSUPPORTED;
1138 /*********************************************************
1139 * Method implementation for the IDataObject
1140 * part of the DataCache class.
1143 /************************************************************************
1144 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1146 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1147 IPersistStorage* iface,
1148 REFIID riid,
1149 void** ppvObject)
1151 DataCache *this = impl_from_IPersistStorage(iface);
1153 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1156 /************************************************************************
1157 * DataCache_IPersistStorage_AddRef (IUnknown)
1159 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1160 IPersistStorage* iface)
1162 DataCache *this = impl_from_IPersistStorage(iface);
1164 return IUnknown_AddRef(this->outer_unk);
1167 /************************************************************************
1168 * DataCache_IPersistStorage_Release (IUnknown)
1170 static ULONG WINAPI DataCache_IPersistStorage_Release(
1171 IPersistStorage* iface)
1173 DataCache *this = impl_from_IPersistStorage(iface);
1175 return IUnknown_Release(this->outer_unk);
1178 /************************************************************************
1179 * DataCache_GetClassID (IPersistStorage)
1182 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1184 DataCache *This = impl_from_IPersistStorage( iface );
1185 HRESULT hr;
1186 STATSTG statstg;
1188 TRACE( "(%p, %p)\n", iface, clsid );
1190 if (This->presentationStorage)
1192 hr = IStorage_Stat( This->presentationStorage, &statstg, STATFLAG_NONAME );
1193 if (SUCCEEDED(hr))
1195 *clsid = statstg.clsid;
1196 return S_OK;
1200 *clsid = CLSID_NULL;
1202 return S_OK;
1205 /************************************************************************
1206 * DataCache_IsDirty (IPersistStorage)
1208 static HRESULT WINAPI DataCache_IsDirty(
1209 IPersistStorage* iface)
1211 DataCache *This = impl_from_IPersistStorage(iface);
1212 DataCacheEntry *cache_entry;
1214 TRACE("(%p)\n", iface);
1216 if (This->dirty)
1217 return S_OK;
1219 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1220 if (cache_entry->dirty)
1221 return S_OK;
1223 return S_FALSE;
1226 /************************************************************************
1227 * DataCache_InitNew (IPersistStorage)
1229 * The data cache implementation of IPersistStorage_InitNew simply stores
1230 * the storage pointer.
1232 static HRESULT WINAPI DataCache_InitNew(
1233 IPersistStorage* iface,
1234 IStorage* pStg)
1236 DataCache *This = impl_from_IPersistStorage(iface);
1238 TRACE("(%p, %p)\n", iface, pStg);
1240 if (This->presentationStorage != NULL)
1241 IStorage_Release(This->presentationStorage);
1243 This->presentationStorage = pStg;
1245 IStorage_AddRef(This->presentationStorage);
1246 This->dirty = TRUE;
1248 return S_OK;
1252 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, IStream *stm,
1253 enum stream_type type )
1255 DataCacheEntry *cache_entry;
1256 HRESULT hr = S_OK;
1258 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1260 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1261 if (!cache_entry)
1262 hr = DataCache_CreateEntry( This, fmt, &cache_entry, TRUE );
1263 if (SUCCEEDED( hr ))
1265 DataCacheEntry_DiscardData( cache_entry );
1266 if (cache_entry->stream) IStream_Release( cache_entry->stream );
1267 cache_entry->stream = stm;
1268 IStream_AddRef( stm );
1269 cache_entry->stream_type = type;
1270 cache_entry->dirty = FALSE;
1272 return hr;
1275 static HRESULT parse_pres_streams( DataCache *This, IStorage *stg )
1277 HRESULT hr;
1278 IEnumSTATSTG *stat_enum;
1279 STATSTG stat;
1280 IStream *stm;
1281 PresentationDataHeader header;
1282 ULONG actual_read;
1283 CLIPFORMAT clipformat;
1284 FORMATETC fmtetc;
1286 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stat_enum );
1287 if (FAILED( hr )) return hr;
1289 while ((hr = IEnumSTATSTG_Next( stat_enum, 1, &stat, NULL )) == S_OK)
1291 if (DataCache_IsPresentationStream( &stat ))
1293 hr = IStorage_OpenStream( stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1294 0, &stm );
1295 if (SUCCEEDED( hr ))
1297 hr = read_clipformat( stm, &clipformat );
1299 if (hr == S_OK)
1300 hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1302 if (hr == S_OK && actual_read == sizeof(header))
1304 fmtetc.cfFormat = clipformat;
1305 fmtetc.ptd = NULL; /* FIXME */
1306 fmtetc.dwAspect = header.dvAspect;
1307 fmtetc.lindex = header.lindex;
1308 fmtetc.tymed = header.tymed;
1310 add_cache_entry( This, &fmtetc, stm, pres_stream );
1312 IStream_Release( stm );
1315 CoTaskMemFree( stat.pwcsName );
1317 IEnumSTATSTG_Release( stat_enum );
1319 return S_OK;
1322 static const FORMATETC static_dib_fmt = { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
1324 static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *stm )
1326 HRESULT hr;
1327 STATSTG stat;
1328 const FORMATETC *fmt;
1330 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
1331 if (FAILED( hr )) return hr;
1333 if (IsEqualCLSID( &stat.clsid, &CLSID_Picture_Dib ))
1334 fmt = &static_dib_fmt;
1335 else
1337 FIXME("unsupported format %s\n", debugstr_guid( &stat.clsid ));
1338 return E_FAIL;
1341 return add_cache_entry( This, fmt, stm, contents_stream );
1344 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1346 /************************************************************************
1347 * DataCache_Load (IPersistStorage)
1349 * The data cache implementation of IPersistStorage_Load doesn't
1350 * actually load anything. Instead, it holds on to the storage pointer
1351 * and it will load the presentation information when the
1352 * IDataObject_GetData or IViewObject2_Draw methods are called.
1354 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1356 DataCache *This = impl_from_IPersistStorage(iface);
1357 HRESULT hr;
1358 IStream *stm;
1360 TRACE("(%p, %p)\n", iface, pStg);
1362 IPersistStorage_HandsOffStorage( iface );
1364 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1365 0, &stm );
1366 if (SUCCEEDED( hr ))
1368 hr = parse_contents_stream( This, pStg, stm );
1369 IStream_Release( stm );
1372 if (FAILED(hr))
1373 hr = parse_pres_streams( This, pStg );
1375 if (SUCCEEDED( hr ))
1377 This->dirty = FALSE;
1378 This->presentationStorage = pStg;
1379 IStorage_AddRef( This->presentationStorage );
1382 return hr;
1385 /************************************************************************
1386 * DataCache_Save (IPersistStorage)
1388 * Until we actually connect to a running object and retrieve new
1389 * information to it, we never have to save anything. However, it is
1390 * our responsibility to copy the information when saving to a new
1391 * storage.
1393 static HRESULT WINAPI DataCache_Save(
1394 IPersistStorage* iface,
1395 IStorage* pStg,
1396 BOOL fSameAsLoad)
1398 DataCache *This = impl_from_IPersistStorage(iface);
1399 DataCacheEntry *cache_entry;
1400 BOOL dirty = FALSE;
1401 HRESULT hr = S_OK;
1402 unsigned short stream_number = 0;
1404 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1406 dirty = This->dirty;
1407 if (!dirty)
1409 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1411 dirty = cache_entry->dirty;
1412 if (dirty)
1413 break;
1417 /* this is a shortcut if nothing changed */
1418 if (!dirty && !fSameAsLoad && This->presentationStorage)
1420 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1423 /* assign stream numbers to the cache entries */
1424 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1426 if (cache_entry->stream_number != stream_number)
1428 cache_entry->dirty = TRUE; /* needs to be written out again */
1429 cache_entry->stream_number = stream_number;
1431 stream_number++;
1434 /* write out the cache entries */
1435 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1437 if (!fSameAsLoad || cache_entry->dirty)
1439 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1440 if (FAILED(hr))
1441 break;
1443 cache_entry->dirty = FALSE;
1447 This->dirty = FALSE;
1448 return hr;
1451 /************************************************************************
1452 * DataCache_SaveCompleted (IPersistStorage)
1454 * This method is called to tell the cache to release the storage
1455 * pointer it's currently holding.
1457 static HRESULT WINAPI DataCache_SaveCompleted(
1458 IPersistStorage* iface,
1459 IStorage* pStgNew)
1461 TRACE("(%p, %p)\n", iface, pStgNew);
1463 if (pStgNew)
1465 IPersistStorage_HandsOffStorage(iface);
1467 DataCache_Load(iface, pStgNew);
1470 return S_OK;
1473 /************************************************************************
1474 * DataCache_HandsOffStorage (IPersistStorage)
1476 * This method is called to tell the cache to release the storage
1477 * pointer it's currently holding.
1479 static HRESULT WINAPI DataCache_HandsOffStorage(
1480 IPersistStorage* iface)
1482 DataCache *this = impl_from_IPersistStorage(iface);
1483 DataCacheEntry *cache_entry;
1485 TRACE("(%p)\n", iface);
1487 if (this->presentationStorage != NULL)
1489 IStorage_Release(this->presentationStorage);
1490 this->presentationStorage = NULL;
1493 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1494 DataCacheEntry_HandsOffStorage(cache_entry);
1496 return S_OK;
1499 /*********************************************************
1500 * Method implementation for the IViewObject2
1501 * part of the DataCache class.
1504 /************************************************************************
1505 * DataCache_IViewObject2_QueryInterface (IUnknown)
1507 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1508 IViewObject2* iface,
1509 REFIID riid,
1510 void** ppvObject)
1512 DataCache *this = impl_from_IViewObject2(iface);
1514 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1517 /************************************************************************
1518 * DataCache_IViewObject2_AddRef (IUnknown)
1520 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1521 IViewObject2* iface)
1523 DataCache *this = impl_from_IViewObject2(iface);
1525 return IUnknown_AddRef(this->outer_unk);
1528 /************************************************************************
1529 * DataCache_IViewObject2_Release (IUnknown)
1531 static ULONG WINAPI DataCache_IViewObject2_Release(
1532 IViewObject2* iface)
1534 DataCache *this = impl_from_IViewObject2(iface);
1536 return IUnknown_Release(this->outer_unk);
1539 /************************************************************************
1540 * DataCache_Draw (IViewObject2)
1542 * This method will draw the cached representation of the object
1543 * to the given device context.
1545 static HRESULT WINAPI DataCache_Draw(
1546 IViewObject2* iface,
1547 DWORD dwDrawAspect,
1548 LONG lindex,
1549 void* pvAspect,
1550 DVTARGETDEVICE* ptd,
1551 HDC hdcTargetDev,
1552 HDC hdcDraw,
1553 LPCRECTL lprcBounds,
1554 LPCRECTL lprcWBounds,
1555 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1556 ULONG_PTR dwContinue)
1558 DataCache *This = impl_from_IViewObject2(iface);
1559 HRESULT hres;
1560 DataCacheEntry *cache_entry;
1562 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1563 iface,
1564 dwDrawAspect,
1565 lindex,
1566 pvAspect,
1567 hdcTargetDev,
1568 hdcDraw,
1569 lprcBounds,
1570 lprcWBounds,
1571 pfnContinue,
1572 dwContinue);
1574 if (lprcBounds==NULL)
1575 return E_INVALIDARG;
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))
1582 continue;
1584 /* if the data hasn't been loaded yet, do it now */
1585 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1587 hres = DataCacheEntry_LoadData(cache_entry);
1588 if (FAILED(hres))
1589 continue;
1592 /* no data */
1593 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1594 continue;
1596 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1598 switch (cache_entry->data_cf)
1600 case CF_METAFILEPICT:
1603 * We have to be careful not to modify the state of the
1604 * DC.
1606 INT prevMapMode;
1607 SIZE oldWindowExt;
1608 SIZE oldViewportExt;
1609 POINT oldViewportOrg;
1610 METAFILEPICT *mfpict;
1612 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1613 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1614 continue;
1616 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1618 SetWindowExtEx(hdcDraw,
1619 mfpict->xExt,
1620 mfpict->yExt,
1621 &oldWindowExt);
1623 SetViewportExtEx(hdcDraw,
1624 lprcBounds->right - lprcBounds->left,
1625 lprcBounds->bottom - lprcBounds->top,
1626 &oldViewportExt);
1628 SetViewportOrgEx(hdcDraw,
1629 lprcBounds->left,
1630 lprcBounds->top,
1631 &oldViewportOrg);
1633 PlayMetaFile(hdcDraw, mfpict->hMF);
1635 SetWindowExtEx(hdcDraw,
1636 oldWindowExt.cx,
1637 oldWindowExt.cy,
1638 NULL);
1640 SetViewportExtEx(hdcDraw,
1641 oldViewportExt.cx,
1642 oldViewportExt.cy,
1643 NULL);
1645 SetViewportOrgEx(hdcDraw,
1646 oldViewportOrg.x,
1647 oldViewportOrg.y,
1648 NULL);
1650 SetMapMode(hdcDraw, prevMapMode);
1652 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1654 return S_OK;
1656 case CF_DIB:
1658 BITMAPFILEHEADER *file_head;
1659 BITMAPINFO *info;
1660 BYTE *bits;
1662 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1663 !((file_head = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1664 continue;
1666 info = (BITMAPINFO *)(file_head + 1);
1667 bits = (BYTE *) file_head + file_head->bfOffBits;
1668 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1669 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1670 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1671 bits, info, DIB_RGB_COLORS, SRCCOPY );
1673 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1674 return S_OK;
1679 WARN("no data could be found to be drawn\n");
1681 return OLE_E_BLANK;
1684 static HRESULT WINAPI DataCache_GetColorSet(
1685 IViewObject2* iface,
1686 DWORD dwDrawAspect,
1687 LONG lindex,
1688 void* pvAspect,
1689 DVTARGETDEVICE* ptd,
1690 HDC hicTargetDevice,
1691 LOGPALETTE** ppColorSet)
1693 FIXME("stub\n");
1694 return E_NOTIMPL;
1697 static HRESULT WINAPI DataCache_Freeze(
1698 IViewObject2* iface,
1699 DWORD dwDrawAspect,
1700 LONG lindex,
1701 void* pvAspect,
1702 DWORD* pdwFreeze)
1704 FIXME("stub\n");
1705 return E_NOTIMPL;
1708 static HRESULT WINAPI DataCache_Unfreeze(
1709 IViewObject2* iface,
1710 DWORD dwFreeze)
1712 FIXME("stub\n");
1713 return E_NOTIMPL;
1716 /************************************************************************
1717 * DataCache_SetAdvise (IViewObject2)
1719 * This sets-up an advisory sink with the data cache. When the object's
1720 * view changes, this sink is called.
1722 static HRESULT WINAPI DataCache_SetAdvise(
1723 IViewObject2* iface,
1724 DWORD aspects,
1725 DWORD advf,
1726 IAdviseSink* pAdvSink)
1728 DataCache *this = impl_from_IViewObject2(iface);
1730 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1733 * A call to this function removes the previous sink
1735 if (this->sinkInterface != NULL)
1737 IAdviseSink_Release(this->sinkInterface);
1738 this->sinkInterface = NULL;
1739 this->sinkAspects = 0;
1740 this->sinkAdviseFlag = 0;
1744 * Now, setup the new one.
1746 if (pAdvSink!=NULL)
1748 this->sinkInterface = pAdvSink;
1749 this->sinkAspects = aspects;
1750 this->sinkAdviseFlag = advf;
1752 IAdviseSink_AddRef(this->sinkInterface);
1756 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1757 * sink immediately.
1759 if (advf & ADVF_PRIMEFIRST)
1761 DataCache_FireOnViewChange(this, aspects, -1);
1764 return S_OK;
1767 /************************************************************************
1768 * DataCache_GetAdvise (IViewObject2)
1770 * This method queries the current state of the advise sink
1771 * installed on the data cache.
1773 static HRESULT WINAPI DataCache_GetAdvise(
1774 IViewObject2* iface,
1775 DWORD* pAspects,
1776 DWORD* pAdvf,
1777 IAdviseSink** ppAdvSink)
1779 DataCache *this = impl_from_IViewObject2(iface);
1781 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1784 * Just copy all the requested values.
1786 if (pAspects!=NULL)
1787 *pAspects = this->sinkAspects;
1789 if (pAdvf!=NULL)
1790 *pAdvf = this->sinkAdviseFlag;
1792 if (ppAdvSink!=NULL)
1794 if (this->sinkInterface != NULL)
1795 IAdviseSink_QueryInterface(this->sinkInterface,
1796 &IID_IAdviseSink,
1797 (void**)ppAdvSink);
1798 else *ppAdvSink = NULL;
1801 return S_OK;
1804 /************************************************************************
1805 * DataCache_GetExtent (IViewObject2)
1807 * This method retrieves the "natural" size of this cached object.
1809 static HRESULT WINAPI DataCache_GetExtent(
1810 IViewObject2* iface,
1811 DWORD dwDrawAspect,
1812 LONG lindex,
1813 DVTARGETDEVICE* ptd,
1814 LPSIZEL lpsizel)
1816 DataCache *This = impl_from_IViewObject2(iface);
1817 HRESULT hres = E_FAIL;
1818 DataCacheEntry *cache_entry;
1820 TRACE("(%p, %x, %d, %p, %p)\n",
1821 iface, dwDrawAspect, lindex, ptd, lpsizel);
1823 if (lpsizel==NULL)
1824 return E_POINTER;
1826 lpsizel->cx = 0;
1827 lpsizel->cy = 0;
1829 if (lindex!=-1)
1830 FIXME("Unimplemented flag lindex = %d\n", lindex);
1833 * Right now, we support only the callback from
1834 * the default handler.
1836 if (ptd!=NULL)
1837 FIXME("Unimplemented ptd = %p\n", ptd);
1839 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1841 /* FIXME: compare ptd too */
1842 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1843 (cache_entry->fmtetc.lindex != lindex))
1844 continue;
1846 /* if the data hasn't been loaded yet, do it now */
1847 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1849 hres = DataCacheEntry_LoadData(cache_entry);
1850 if (FAILED(hres))
1851 continue;
1854 /* no data */
1855 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1856 continue;
1859 switch (cache_entry->data_cf)
1861 case CF_METAFILEPICT:
1863 METAFILEPICT *mfpict;
1865 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1866 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1867 continue;
1869 lpsizel->cx = mfpict->xExt;
1870 lpsizel->cy = mfpict->yExt;
1872 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1874 return S_OK;
1876 case CF_DIB:
1878 BITMAPFILEHEADER *file_head;
1879 BITMAPINFOHEADER *info;
1880 LONG x_pels_m, y_pels_m;
1883 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1884 !((file_head = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1885 continue;
1887 info = (BITMAPINFOHEADER *)(file_head + 1);
1889 x_pels_m = info->biXPelsPerMeter;
1890 y_pels_m = info->biYPelsPerMeter;
1892 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
1893 if (x_pels_m != 0 && y_pels_m != 0)
1895 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
1896 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
1898 else
1900 HDC hdc = GetDC( 0 );
1901 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
1902 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
1904 ReleaseDC( 0, hdc );
1907 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1909 return S_OK;
1914 WARN("no data could be found to get the extents from\n");
1917 * This method returns OLE_E_BLANK when it fails.
1919 return OLE_E_BLANK;
1923 /*********************************************************
1924 * Method implementation for the IOleCache2
1925 * part of the DataCache class.
1928 /************************************************************************
1929 * DataCache_IOleCache2_QueryInterface (IUnknown)
1931 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1932 IOleCache2* iface,
1933 REFIID riid,
1934 void** ppvObject)
1936 DataCache *this = impl_from_IOleCache2(iface);
1938 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1941 /************************************************************************
1942 * DataCache_IOleCache2_AddRef (IUnknown)
1944 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1945 IOleCache2* iface)
1947 DataCache *this = impl_from_IOleCache2(iface);
1949 return IUnknown_AddRef(this->outer_unk);
1952 /************************************************************************
1953 * DataCache_IOleCache2_Release (IUnknown)
1955 static ULONG WINAPI DataCache_IOleCache2_Release(
1956 IOleCache2* iface)
1958 DataCache *this = impl_from_IOleCache2(iface);
1960 return IUnknown_Release(this->outer_unk);
1963 /*****************************************************************************
1964 * setup_sink
1966 * Set up the sink connection to the running object.
1968 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
1970 HRESULT hr = S_FALSE;
1971 DWORD flags;
1973 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
1974 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
1976 if(This->running_object)
1977 if(!(flags & ADVF_NODATA))
1978 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
1979 &This->IAdviseSink_iface, &cache_entry->sink_id);
1980 return hr;
1983 static HRESULT WINAPI DataCache_Cache(
1984 IOleCache2* iface,
1985 FORMATETC* pformatetc,
1986 DWORD advf,
1987 DWORD* pdwConnection)
1989 DataCache *This = impl_from_IOleCache2(iface);
1990 DataCacheEntry *cache_entry;
1991 HRESULT hr;
1993 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1995 if (!pformatetc || !pdwConnection)
1996 return E_INVALIDARG;
1998 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2000 *pdwConnection = 0;
2002 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2003 if (cache_entry)
2005 TRACE("found an existing cache entry\n");
2006 *pdwConnection = cache_entry->id;
2007 return CACHE_S_SAMECACHE;
2010 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry, FALSE);
2012 if (SUCCEEDED(hr))
2014 *pdwConnection = cache_entry->id;
2015 cache_entry->advise_flags = advf;
2016 setup_sink(This, cache_entry);
2019 return hr;
2022 static HRESULT WINAPI DataCache_Uncache(
2023 IOleCache2* iface,
2024 DWORD dwConnection)
2026 DataCache *This = impl_from_IOleCache2(iface);
2027 DataCacheEntry *cache_entry;
2029 TRACE("(%d)\n", dwConnection);
2031 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2032 if (cache_entry->id == dwConnection)
2034 DataCacheEntry_Destroy(This, cache_entry);
2035 return S_OK;
2038 WARN("no connection found for %d\n", dwConnection);
2040 return OLE_E_NOCONNECTION;
2043 static HRESULT WINAPI DataCache_EnumCache(
2044 IOleCache2* iface,
2045 IEnumSTATDATA** ppenumSTATDATA)
2047 FIXME("stub\n");
2048 return E_NOTIMPL;
2051 static HRESULT WINAPI DataCache_InitCache(
2052 IOleCache2* iface,
2053 IDataObject* pDataObject)
2055 FIXME("stub\n");
2056 return E_NOTIMPL;
2059 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2060 IOleCache2* iface,
2061 FORMATETC* pformatetc,
2062 STGMEDIUM* pmedium,
2063 BOOL fRelease)
2065 DataCache *This = impl_from_IOleCache2(iface);
2066 DataCacheEntry *cache_entry;
2067 HRESULT hr;
2069 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2070 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2072 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2073 if (cache_entry)
2075 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2077 if (SUCCEEDED(hr))
2078 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2079 cache_entry->fmtetc.lindex);
2081 return hr;
2083 WARN("cache entry not found\n");
2085 return OLE_E_BLANK;
2088 static HRESULT WINAPI DataCache_UpdateCache(
2089 IOleCache2* iface,
2090 LPDATAOBJECT pDataObject,
2091 DWORD grfUpdf,
2092 LPVOID pReserved)
2094 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2095 return E_NOTIMPL;
2098 static HRESULT WINAPI DataCache_DiscardCache(
2099 IOleCache2* iface,
2100 DWORD dwDiscardOptions)
2102 DataCache *This = impl_from_IOleCache2(iface);
2103 DataCacheEntry *cache_entry;
2104 HRESULT hr = S_OK;
2106 TRACE("(%d)\n", dwDiscardOptions);
2108 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2109 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2111 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2113 hr = DataCacheEntry_DiscardData(cache_entry);
2114 if (FAILED(hr))
2115 break;
2118 return hr;
2122 /*********************************************************
2123 * Method implementation for the IOleCacheControl
2124 * part of the DataCache class.
2127 /************************************************************************
2128 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2130 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2131 IOleCacheControl* iface,
2132 REFIID riid,
2133 void** ppvObject)
2135 DataCache *this = impl_from_IOleCacheControl(iface);
2137 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2140 /************************************************************************
2141 * DataCache_IOleCacheControl_AddRef (IUnknown)
2143 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2144 IOleCacheControl* iface)
2146 DataCache *this = impl_from_IOleCacheControl(iface);
2148 return IUnknown_AddRef(this->outer_unk);
2151 /************************************************************************
2152 * DataCache_IOleCacheControl_Release (IUnknown)
2154 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2155 IOleCacheControl* iface)
2157 DataCache *this = impl_from_IOleCacheControl(iface);
2159 return IUnknown_Release(this->outer_unk);
2162 /************************************************************************
2163 * DataCache_OnRun (IOleCacheControl)
2165 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2167 DataCache *This = impl_from_IOleCacheControl(iface);
2168 DataCacheEntry *cache_entry;
2170 TRACE("(%p)->(%p)\n", iface, data_obj);
2172 if(This->running_object) return S_OK;
2174 /* No reference is taken on the data object */
2175 This->running_object = data_obj;
2177 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2179 setup_sink(This, cache_entry);
2182 return S_OK;
2185 /************************************************************************
2186 * DataCache_OnStop (IOleCacheControl)
2188 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2190 DataCache *This = impl_from_IOleCacheControl(iface);
2191 DataCacheEntry *cache_entry;
2193 TRACE("(%p)\n", iface);
2195 if(!This->running_object) return S_OK;
2197 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2199 if(cache_entry->sink_id)
2201 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2202 cache_entry->sink_id = 0;
2206 /* No ref taken in OnRun, so no Release call here */
2207 This->running_object = NULL;
2208 return S_OK;
2211 /************************************************************************
2212 * IAdviseSink methods.
2213 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2214 * give access to the cache's other interfaces. We don't maintain a ref count,
2215 * the object exists as long as the cache is around.
2217 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2219 *obj = NULL;
2220 if (IsEqualIID(&IID_IUnknown, iid) ||
2221 IsEqualIID(&IID_IAdviseSink, iid))
2223 *obj = iface;
2226 if(*obj)
2228 IAdviseSink_AddRef(iface);
2229 return S_OK;
2231 return E_NOINTERFACE;
2234 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2236 return 2;
2239 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2241 return 1;
2244 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2246 DataCache *This = impl_from_IAdviseSink(iface);
2247 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2248 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2251 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2253 FIXME("stub\n");
2256 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2258 FIXME("stub\n");
2261 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2263 FIXME("stub\n");
2266 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2268 FIXME("stub\n");
2272 * Virtual function tables for the DataCache class.
2274 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2276 DataCache_NDIUnknown_QueryInterface,
2277 DataCache_NDIUnknown_AddRef,
2278 DataCache_NDIUnknown_Release
2281 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2283 DataCache_IDataObject_QueryInterface,
2284 DataCache_IDataObject_AddRef,
2285 DataCache_IDataObject_Release,
2286 DataCache_GetData,
2287 DataCache_GetDataHere,
2288 DataCache_QueryGetData,
2289 DataCache_GetCanonicalFormatEtc,
2290 DataCache_IDataObject_SetData,
2291 DataCache_EnumFormatEtc,
2292 DataCache_DAdvise,
2293 DataCache_DUnadvise,
2294 DataCache_EnumDAdvise
2297 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2299 DataCache_IPersistStorage_QueryInterface,
2300 DataCache_IPersistStorage_AddRef,
2301 DataCache_IPersistStorage_Release,
2302 DataCache_GetClassID,
2303 DataCache_IsDirty,
2304 DataCache_InitNew,
2305 DataCache_Load,
2306 DataCache_Save,
2307 DataCache_SaveCompleted,
2308 DataCache_HandsOffStorage
2311 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2313 DataCache_IViewObject2_QueryInterface,
2314 DataCache_IViewObject2_AddRef,
2315 DataCache_IViewObject2_Release,
2316 DataCache_Draw,
2317 DataCache_GetColorSet,
2318 DataCache_Freeze,
2319 DataCache_Unfreeze,
2320 DataCache_SetAdvise,
2321 DataCache_GetAdvise,
2322 DataCache_GetExtent
2325 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2327 DataCache_IOleCache2_QueryInterface,
2328 DataCache_IOleCache2_AddRef,
2329 DataCache_IOleCache2_Release,
2330 DataCache_Cache,
2331 DataCache_Uncache,
2332 DataCache_EnumCache,
2333 DataCache_InitCache,
2334 DataCache_IOleCache2_SetData,
2335 DataCache_UpdateCache,
2336 DataCache_DiscardCache
2339 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2341 DataCache_IOleCacheControl_QueryInterface,
2342 DataCache_IOleCacheControl_AddRef,
2343 DataCache_IOleCacheControl_Release,
2344 DataCache_OnRun,
2345 DataCache_OnStop
2348 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2350 DataCache_IAdviseSink_QueryInterface,
2351 DataCache_IAdviseSink_AddRef,
2352 DataCache_IAdviseSink_Release,
2353 DataCache_OnDataChange,
2354 DataCache_OnViewChange,
2355 DataCache_OnRename,
2356 DataCache_OnSave,
2357 DataCache_OnClose
2360 /*********************************************************
2361 * Method implementation for DataCache class.
2363 static DataCache* DataCache_Construct(
2364 REFCLSID clsid,
2365 LPUNKNOWN pUnkOuter)
2367 DataCache* newObject = 0;
2370 * Allocate space for the object.
2372 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2374 if (newObject==0)
2375 return newObject;
2378 * Initialize the virtual function table.
2380 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2381 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2382 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2383 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2384 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2385 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2386 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2387 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2388 newObject->ref = 1;
2391 * Initialize the other members of the structure.
2393 newObject->sinkAspects = 0;
2394 newObject->sinkAdviseFlag = 0;
2395 newObject->sinkInterface = 0;
2396 newObject->presentationStorage = NULL;
2397 list_init(&newObject->cache_list);
2398 newObject->last_cache_id = 1;
2399 newObject->dirty = FALSE;
2400 newObject->running_object = NULL;
2402 return newObject;
2405 /******************************************************************************
2406 * CreateDataCache [OLE32.@]
2408 * Creates a data cache to allow an object to render one or more of its views,
2409 * whether running or not.
2411 * PARAMS
2412 * pUnkOuter [I] Outer unknown for the object.
2413 * rclsid [I]
2414 * riid [I] IID of interface to return.
2415 * ppvObj [O] Address where the data cache object will be stored on return.
2417 * RETURNS
2418 * Success: S_OK.
2419 * Failure: HRESULT code.
2421 * NOTES
2422 * The following interfaces are supported by the returned data cache object:
2423 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2424 * IViewObject and IViewObject2.
2426 HRESULT WINAPI CreateDataCache(
2427 LPUNKNOWN pUnkOuter,
2428 REFCLSID rclsid,
2429 REFIID riid,
2430 LPVOID* ppvObj)
2432 DataCache* newCache = NULL;
2433 HRESULT hr = S_OK;
2435 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2438 * Sanity check
2440 if (ppvObj==0)
2441 return E_POINTER;
2443 *ppvObj = 0;
2446 * If this cache is constructed for aggregation, make sure
2447 * the caller is requesting the IUnknown interface.
2448 * This is necessary because it's the only time the non-delegating
2449 * IUnknown pointer can be returned to the outside.
2451 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2452 return E_INVALIDARG;
2455 * Try to construct a new instance of the class.
2457 newCache = DataCache_Construct(rclsid,
2458 pUnkOuter);
2460 if (newCache == 0)
2461 return E_OUTOFMEMORY;
2463 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
2464 IUnknown_Release(&newCache->IUnknown_inner);
2466 return hr;