ws2_32/tests: Add UDP select() test for unbound socket.
[wine/multimedia.git] / dlls / ole32 / datacache.c
blob1076a37d4a54512e6c29e0e1079468be603f9cc0
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 IDataObject IDataObject_iface;
135 IUnknown IUnknown_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* outerUnknown;
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_iface);
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 static 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)
287 if (!cfFormat || !tymed ||
288 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
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)
304 HRESULT hr;
306 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
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), 0);
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->outerUnknown, 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->outerUnknown);
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->outerUnknown);
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->outerUnknown, 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->outerUnknown);
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->outerUnknown);
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 );
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
1336 return E_FAIL;
1338 return add_cache_entry( This, fmt, stm, contents_stream );
1341 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1343 /************************************************************************
1344 * DataCache_Load (IPersistStorage)
1346 * The data cache implementation of IPersistStorage_Load doesn't
1347 * actually load anything. Instead, it holds on to the storage pointer
1348 * and it will load the presentation information when the
1349 * IDataObject_GetData or IViewObject2_Draw methods are called.
1351 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1353 DataCache *This = impl_from_IPersistStorage(iface);
1354 HRESULT hr;
1355 IStream *stm;
1357 TRACE("(%p, %p)\n", iface, pStg);
1359 IPersistStorage_HandsOffStorage( iface );
1361 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1362 0, &stm );
1363 if (SUCCEEDED( hr ))
1365 hr = parse_contents_stream( This, pStg, stm );
1366 IStream_Release( stm );
1368 else
1369 hr = parse_pres_streams( This, pStg );
1371 if (SUCCEEDED( hr ))
1373 This->dirty = FALSE;
1374 This->presentationStorage = pStg;
1375 IStorage_AddRef( This->presentationStorage );
1378 return hr;
1381 /************************************************************************
1382 * DataCache_Save (IPersistStorage)
1384 * Until we actually connect to a running object and retrieve new
1385 * information to it, we never have to save anything. However, it is
1386 * our responsibility to copy the information when saving to a new
1387 * storage.
1389 static HRESULT WINAPI DataCache_Save(
1390 IPersistStorage* iface,
1391 IStorage* pStg,
1392 BOOL fSameAsLoad)
1394 DataCache *This = impl_from_IPersistStorage(iface);
1395 DataCacheEntry *cache_entry;
1396 BOOL dirty = FALSE;
1397 HRESULT hr = S_OK;
1398 unsigned short stream_number = 0;
1400 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1402 dirty = This->dirty;
1403 if (!dirty)
1405 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1407 dirty = cache_entry->dirty;
1408 if (dirty)
1409 break;
1413 /* this is a shortcut if nothing changed */
1414 if (!dirty && !fSameAsLoad && This->presentationStorage)
1416 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1419 /* assign stream numbers to the cache entries */
1420 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1422 if (cache_entry->stream_number != stream_number)
1424 cache_entry->dirty = TRUE; /* needs to be written out again */
1425 cache_entry->stream_number = stream_number;
1427 stream_number++;
1430 /* write out the cache entries */
1431 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1433 if (!fSameAsLoad || cache_entry->dirty)
1435 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1436 if (FAILED(hr))
1437 break;
1439 cache_entry->dirty = FALSE;
1443 This->dirty = FALSE;
1444 return hr;
1447 /************************************************************************
1448 * DataCache_SaveCompleted (IPersistStorage)
1450 * This method is called to tell the cache to release the storage
1451 * pointer it's currently holding.
1453 static HRESULT WINAPI DataCache_SaveCompleted(
1454 IPersistStorage* iface,
1455 IStorage* pStgNew)
1457 TRACE("(%p, %p)\n", iface, pStgNew);
1459 if (pStgNew)
1461 IPersistStorage_HandsOffStorage(iface);
1463 DataCache_Load(iface, pStgNew);
1466 return S_OK;
1469 /************************************************************************
1470 * DataCache_HandsOffStorage (IPersistStorage)
1472 * This method is called to tell the cache to release the storage
1473 * pointer it's currently holding.
1475 static HRESULT WINAPI DataCache_HandsOffStorage(
1476 IPersistStorage* iface)
1478 DataCache *this = impl_from_IPersistStorage(iface);
1479 DataCacheEntry *cache_entry;
1481 TRACE("(%p)\n", iface);
1483 if (this->presentationStorage != NULL)
1485 IStorage_Release(this->presentationStorage);
1486 this->presentationStorage = NULL;
1489 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1490 DataCacheEntry_HandsOffStorage(cache_entry);
1492 return S_OK;
1495 /*********************************************************
1496 * Method implementation for the IViewObject2
1497 * part of the DataCache class.
1500 /************************************************************************
1501 * DataCache_IViewObject2_QueryInterface (IUnknown)
1503 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1504 IViewObject2* iface,
1505 REFIID riid,
1506 void** ppvObject)
1508 DataCache *this = impl_from_IViewObject2(iface);
1510 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1513 /************************************************************************
1514 * DataCache_IViewObject2_AddRef (IUnknown)
1516 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1517 IViewObject2* iface)
1519 DataCache *this = impl_from_IViewObject2(iface);
1521 return IUnknown_AddRef(this->outerUnknown);
1524 /************************************************************************
1525 * DataCache_IViewObject2_Release (IUnknown)
1527 static ULONG WINAPI DataCache_IViewObject2_Release(
1528 IViewObject2* iface)
1530 DataCache *this = impl_from_IViewObject2(iface);
1532 return IUnknown_Release(this->outerUnknown);
1535 /************************************************************************
1536 * DataCache_Draw (IViewObject2)
1538 * This method will draw the cached representation of the object
1539 * to the given device context.
1541 static HRESULT WINAPI DataCache_Draw(
1542 IViewObject2* iface,
1543 DWORD dwDrawAspect,
1544 LONG lindex,
1545 void* pvAspect,
1546 DVTARGETDEVICE* ptd,
1547 HDC hdcTargetDev,
1548 HDC hdcDraw,
1549 LPCRECTL lprcBounds,
1550 LPCRECTL lprcWBounds,
1551 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1552 ULONG_PTR dwContinue)
1554 DataCache *This = impl_from_IViewObject2(iface);
1555 HRESULT hres;
1556 DataCacheEntry *cache_entry;
1558 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1559 iface,
1560 dwDrawAspect,
1561 lindex,
1562 pvAspect,
1563 hdcTargetDev,
1564 hdcDraw,
1565 lprcBounds,
1566 lprcWBounds,
1567 pfnContinue,
1568 dwContinue);
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->stream)
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 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1594 switch (cache_entry->data_cf)
1596 case CF_METAFILEPICT:
1599 * We have to be careful not to modify the state of the
1600 * DC.
1602 INT prevMapMode;
1603 SIZE oldWindowExt;
1604 SIZE oldViewportExt;
1605 POINT oldViewportOrg;
1606 METAFILEPICT *mfpict;
1608 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1609 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1610 continue;
1612 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1614 SetWindowExtEx(hdcDraw,
1615 mfpict->xExt,
1616 mfpict->yExt,
1617 &oldWindowExt);
1619 SetViewportExtEx(hdcDraw,
1620 lprcBounds->right - lprcBounds->left,
1621 lprcBounds->bottom - lprcBounds->top,
1622 &oldViewportExt);
1624 SetViewportOrgEx(hdcDraw,
1625 lprcBounds->left,
1626 lprcBounds->top,
1627 &oldViewportOrg);
1629 PlayMetaFile(hdcDraw, mfpict->hMF);
1631 SetWindowExtEx(hdcDraw,
1632 oldWindowExt.cx,
1633 oldWindowExt.cy,
1634 NULL);
1636 SetViewportExtEx(hdcDraw,
1637 oldViewportExt.cx,
1638 oldViewportExt.cy,
1639 NULL);
1641 SetViewportOrgEx(hdcDraw,
1642 oldViewportOrg.x,
1643 oldViewportOrg.y,
1644 NULL);
1646 SetMapMode(hdcDraw, prevMapMode);
1648 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1650 return S_OK;
1652 case CF_DIB:
1654 BITMAPFILEHEADER *file_head;
1655 BITMAPINFO *info;
1656 BYTE *bits;
1658 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1659 !((file_head = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1660 continue;
1662 info = (BITMAPINFO *)(file_head + 1);
1663 bits = (BYTE *) file_head + file_head->bfOffBits;
1664 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1665 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1666 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1667 bits, info, DIB_RGB_COLORS, SRCCOPY );
1669 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1670 return S_OK;
1675 WARN("no data could be found to be drawn\n");
1677 return OLE_E_BLANK;
1680 static HRESULT WINAPI DataCache_GetColorSet(
1681 IViewObject2* iface,
1682 DWORD dwDrawAspect,
1683 LONG lindex,
1684 void* pvAspect,
1685 DVTARGETDEVICE* ptd,
1686 HDC hicTargetDevice,
1687 LOGPALETTE** ppColorSet)
1689 FIXME("stub\n");
1690 return E_NOTIMPL;
1693 static HRESULT WINAPI DataCache_Freeze(
1694 IViewObject2* iface,
1695 DWORD dwDrawAspect,
1696 LONG lindex,
1697 void* pvAspect,
1698 DWORD* pdwFreeze)
1700 FIXME("stub\n");
1701 return E_NOTIMPL;
1704 static HRESULT WINAPI DataCache_Unfreeze(
1705 IViewObject2* iface,
1706 DWORD dwFreeze)
1708 FIXME("stub\n");
1709 return E_NOTIMPL;
1712 /************************************************************************
1713 * DataCache_SetAdvise (IViewObject2)
1715 * This sets-up an advisory sink with the data cache. When the object's
1716 * view changes, this sink is called.
1718 static HRESULT WINAPI DataCache_SetAdvise(
1719 IViewObject2* iface,
1720 DWORD aspects,
1721 DWORD advf,
1722 IAdviseSink* pAdvSink)
1724 DataCache *this = impl_from_IViewObject2(iface);
1726 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1729 * A call to this function removes the previous sink
1731 if (this->sinkInterface != NULL)
1733 IAdviseSink_Release(this->sinkInterface);
1734 this->sinkInterface = NULL;
1735 this->sinkAspects = 0;
1736 this->sinkAdviseFlag = 0;
1740 * Now, setup the new one.
1742 if (pAdvSink!=NULL)
1744 this->sinkInterface = pAdvSink;
1745 this->sinkAspects = aspects;
1746 this->sinkAdviseFlag = advf;
1748 IAdviseSink_AddRef(this->sinkInterface);
1752 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1753 * sink immediately.
1755 if (advf & ADVF_PRIMEFIRST)
1757 DataCache_FireOnViewChange(this, aspects, -1);
1760 return S_OK;
1763 /************************************************************************
1764 * DataCache_GetAdvise (IViewObject2)
1766 * This method queries the current state of the advise sink
1767 * installed on the data cache.
1769 static HRESULT WINAPI DataCache_GetAdvise(
1770 IViewObject2* iface,
1771 DWORD* pAspects,
1772 DWORD* pAdvf,
1773 IAdviseSink** ppAdvSink)
1775 DataCache *this = impl_from_IViewObject2(iface);
1777 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1780 * Just copy all the requested values.
1782 if (pAspects!=NULL)
1783 *pAspects = this->sinkAspects;
1785 if (pAdvf!=NULL)
1786 *pAdvf = this->sinkAdviseFlag;
1788 if (ppAdvSink!=NULL)
1790 if (this->sinkInterface != NULL)
1791 IAdviseSink_QueryInterface(this->sinkInterface,
1792 &IID_IAdviseSink,
1793 (void**)ppAdvSink);
1794 else *ppAdvSink = NULL;
1797 return S_OK;
1800 /************************************************************************
1801 * DataCache_GetExtent (IViewObject2)
1803 * This method retrieves the "natural" size of this cached object.
1805 static HRESULT WINAPI DataCache_GetExtent(
1806 IViewObject2* iface,
1807 DWORD dwDrawAspect,
1808 LONG lindex,
1809 DVTARGETDEVICE* ptd,
1810 LPSIZEL lpsizel)
1812 DataCache *This = impl_from_IViewObject2(iface);
1813 HRESULT hres = E_FAIL;
1814 DataCacheEntry *cache_entry;
1816 TRACE("(%p, %x, %d, %p, %p)\n",
1817 iface, dwDrawAspect, lindex, ptd, lpsizel);
1819 if (lpsizel==NULL)
1820 return E_POINTER;
1822 lpsizel->cx = 0;
1823 lpsizel->cy = 0;
1825 if (lindex!=-1)
1826 FIXME("Unimplemented flag lindex = %d\n", lindex);
1829 * Right now, we support only the callback from
1830 * the default handler.
1832 if (ptd!=NULL)
1833 FIXME("Unimplemented ptd = %p\n", ptd);
1835 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1837 /* FIXME: compare ptd too */
1838 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1839 (cache_entry->fmtetc.lindex != lindex))
1840 continue;
1842 /* if the data hasn't been loaded yet, do it now */
1843 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1845 hres = DataCacheEntry_LoadData(cache_entry);
1846 if (FAILED(hres))
1847 continue;
1850 /* no data */
1851 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1852 continue;
1855 switch (cache_entry->data_cf)
1857 case CF_METAFILEPICT:
1859 METAFILEPICT *mfpict;
1861 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1862 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1863 continue;
1865 lpsizel->cx = mfpict->xExt;
1866 lpsizel->cy = mfpict->yExt;
1868 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1870 return S_OK;
1872 case CF_DIB:
1874 BITMAPFILEHEADER *file_head;
1875 BITMAPINFOHEADER *info;
1876 LONG x_pels_m, y_pels_m;
1879 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1880 !((file_head = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1881 continue;
1883 info = (BITMAPINFOHEADER *)(file_head + 1);
1885 x_pels_m = info->biXPelsPerMeter;
1886 y_pels_m = info->biYPelsPerMeter;
1888 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
1889 if (x_pels_m != 0 && y_pels_m != 0)
1891 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
1892 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
1894 else
1896 HDC hdc = GetDC( 0 );
1897 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
1898 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
1900 ReleaseDC( 0, hdc );
1903 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1905 return S_OK;
1910 WARN("no data could be found to get the extents from\n");
1913 * This method returns OLE_E_BLANK when it fails.
1915 return OLE_E_BLANK;
1919 /*********************************************************
1920 * Method implementation for the IOleCache2
1921 * part of the DataCache class.
1924 /************************************************************************
1925 * DataCache_IOleCache2_QueryInterface (IUnknown)
1927 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1928 IOleCache2* iface,
1929 REFIID riid,
1930 void** ppvObject)
1932 DataCache *this = impl_from_IOleCache2(iface);
1934 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1937 /************************************************************************
1938 * DataCache_IOleCache2_AddRef (IUnknown)
1940 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1941 IOleCache2* iface)
1943 DataCache *this = impl_from_IOleCache2(iface);
1945 return IUnknown_AddRef(this->outerUnknown);
1948 /************************************************************************
1949 * DataCache_IOleCache2_Release (IUnknown)
1951 static ULONG WINAPI DataCache_IOleCache2_Release(
1952 IOleCache2* iface)
1954 DataCache *this = impl_from_IOleCache2(iface);
1956 return IUnknown_Release(this->outerUnknown);
1959 /*****************************************************************************
1960 * setup_sink
1962 * Set up the sink connection to the running object.
1964 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
1966 HRESULT hr = S_FALSE;
1967 DWORD flags;
1969 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
1970 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
1972 if(This->running_object)
1973 if(!(flags & ADVF_NODATA))
1974 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
1975 &This->IAdviseSink_iface, &cache_entry->sink_id);
1976 return hr;
1979 static HRESULT WINAPI DataCache_Cache(
1980 IOleCache2* iface,
1981 FORMATETC* pformatetc,
1982 DWORD advf,
1983 DWORD* pdwConnection)
1985 DataCache *This = impl_from_IOleCache2(iface);
1986 DataCacheEntry *cache_entry;
1987 HRESULT hr;
1989 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1991 if (!pformatetc || !pdwConnection)
1992 return E_INVALIDARG;
1994 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1996 *pdwConnection = 0;
1998 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1999 if (cache_entry)
2001 TRACE("found an existing cache entry\n");
2002 *pdwConnection = cache_entry->id;
2003 return CACHE_S_SAMECACHE;
2006 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
2008 if (SUCCEEDED(hr))
2010 *pdwConnection = cache_entry->id;
2011 cache_entry->advise_flags = advf;
2012 setup_sink(This, cache_entry);
2015 return hr;
2018 static HRESULT WINAPI DataCache_Uncache(
2019 IOleCache2* iface,
2020 DWORD dwConnection)
2022 DataCache *This = impl_from_IOleCache2(iface);
2023 DataCacheEntry *cache_entry;
2025 TRACE("(%d)\n", dwConnection);
2027 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2028 if (cache_entry->id == dwConnection)
2030 DataCacheEntry_Destroy(This, cache_entry);
2031 return S_OK;
2034 WARN("no connection found for %d\n", dwConnection);
2036 return OLE_E_NOCONNECTION;
2039 static HRESULT WINAPI DataCache_EnumCache(
2040 IOleCache2* iface,
2041 IEnumSTATDATA** ppenumSTATDATA)
2043 FIXME("stub\n");
2044 return E_NOTIMPL;
2047 static HRESULT WINAPI DataCache_InitCache(
2048 IOleCache2* iface,
2049 IDataObject* pDataObject)
2051 FIXME("stub\n");
2052 return E_NOTIMPL;
2055 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2056 IOleCache2* iface,
2057 FORMATETC* pformatetc,
2058 STGMEDIUM* pmedium,
2059 BOOL fRelease)
2061 DataCache *This = impl_from_IOleCache2(iface);
2062 DataCacheEntry *cache_entry;
2063 HRESULT hr;
2065 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2066 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2068 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2069 if (cache_entry)
2071 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2073 if (SUCCEEDED(hr))
2074 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2075 cache_entry->fmtetc.lindex);
2077 return hr;
2079 WARN("cache entry not found\n");
2081 return OLE_E_BLANK;
2084 static HRESULT WINAPI DataCache_UpdateCache(
2085 IOleCache2* iface,
2086 LPDATAOBJECT pDataObject,
2087 DWORD grfUpdf,
2088 LPVOID pReserved)
2090 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2091 return E_NOTIMPL;
2094 static HRESULT WINAPI DataCache_DiscardCache(
2095 IOleCache2* iface,
2096 DWORD dwDiscardOptions)
2098 DataCache *This = impl_from_IOleCache2(iface);
2099 DataCacheEntry *cache_entry;
2100 HRESULT hr = S_OK;
2102 TRACE("(%d)\n", dwDiscardOptions);
2104 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2105 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2107 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2109 hr = DataCacheEntry_DiscardData(cache_entry);
2110 if (FAILED(hr))
2111 break;
2114 return hr;
2118 /*********************************************************
2119 * Method implementation for the IOleCacheControl
2120 * part of the DataCache class.
2123 /************************************************************************
2124 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2126 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2127 IOleCacheControl* iface,
2128 REFIID riid,
2129 void** ppvObject)
2131 DataCache *this = impl_from_IOleCacheControl(iface);
2133 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2136 /************************************************************************
2137 * DataCache_IOleCacheControl_AddRef (IUnknown)
2139 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2140 IOleCacheControl* iface)
2142 DataCache *this = impl_from_IOleCacheControl(iface);
2144 return IUnknown_AddRef(this->outerUnknown);
2147 /************************************************************************
2148 * DataCache_IOleCacheControl_Release (IUnknown)
2150 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2151 IOleCacheControl* iface)
2153 DataCache *this = impl_from_IOleCacheControl(iface);
2155 return IUnknown_Release(this->outerUnknown);
2158 /************************************************************************
2159 * DataCache_OnRun (IOleCacheControl)
2161 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2163 DataCache *This = impl_from_IOleCacheControl(iface);
2164 DataCacheEntry *cache_entry;
2166 TRACE("(%p)->(%p)\n", iface, data_obj);
2168 if(This->running_object) return S_OK;
2170 /* No reference is taken on the data object */
2171 This->running_object = data_obj;
2173 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2175 setup_sink(This, cache_entry);
2178 return S_OK;
2181 /************************************************************************
2182 * DataCache_OnStop (IOleCacheControl)
2184 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2186 DataCache *This = impl_from_IOleCacheControl(iface);
2187 DataCacheEntry *cache_entry;
2189 TRACE("(%p)\n", iface);
2191 if(!This->running_object) return S_OK;
2193 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2195 if(cache_entry->sink_id)
2197 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2198 cache_entry->sink_id = 0;
2202 /* No ref taken in OnRun, so no Release call here */
2203 This->running_object = NULL;
2204 return S_OK;
2207 /************************************************************************
2208 * IAdviseSink methods.
2209 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2210 * give access to the cache's other interfaces. We don't maintain a ref count,
2211 * the object exists as long as the cache is around.
2213 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2215 *obj = NULL;
2216 if (IsEqualIID(&IID_IUnknown, iid) ||
2217 IsEqualIID(&IID_IAdviseSink, iid))
2219 *obj = iface;
2222 if(*obj)
2224 IAdviseSink_AddRef(iface);
2225 return S_OK;
2227 return E_NOINTERFACE;
2230 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2232 return 2;
2235 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2237 return 1;
2240 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2242 DataCache *This = impl_from_IAdviseSink(iface);
2243 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2244 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2247 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2249 FIXME("stub\n");
2252 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2254 FIXME("stub\n");
2257 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2259 FIXME("stub\n");
2262 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2264 FIXME("stub\n");
2268 * Virtual function tables for the DataCache class.
2270 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2272 DataCache_NDIUnknown_QueryInterface,
2273 DataCache_NDIUnknown_AddRef,
2274 DataCache_NDIUnknown_Release
2277 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2279 DataCache_IDataObject_QueryInterface,
2280 DataCache_IDataObject_AddRef,
2281 DataCache_IDataObject_Release,
2282 DataCache_GetData,
2283 DataCache_GetDataHere,
2284 DataCache_QueryGetData,
2285 DataCache_GetCanonicalFormatEtc,
2286 DataCache_IDataObject_SetData,
2287 DataCache_EnumFormatEtc,
2288 DataCache_DAdvise,
2289 DataCache_DUnadvise,
2290 DataCache_EnumDAdvise
2293 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2295 DataCache_IPersistStorage_QueryInterface,
2296 DataCache_IPersistStorage_AddRef,
2297 DataCache_IPersistStorage_Release,
2298 DataCache_GetClassID,
2299 DataCache_IsDirty,
2300 DataCache_InitNew,
2301 DataCache_Load,
2302 DataCache_Save,
2303 DataCache_SaveCompleted,
2304 DataCache_HandsOffStorage
2307 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2309 DataCache_IViewObject2_QueryInterface,
2310 DataCache_IViewObject2_AddRef,
2311 DataCache_IViewObject2_Release,
2312 DataCache_Draw,
2313 DataCache_GetColorSet,
2314 DataCache_Freeze,
2315 DataCache_Unfreeze,
2316 DataCache_SetAdvise,
2317 DataCache_GetAdvise,
2318 DataCache_GetExtent
2321 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2323 DataCache_IOleCache2_QueryInterface,
2324 DataCache_IOleCache2_AddRef,
2325 DataCache_IOleCache2_Release,
2326 DataCache_Cache,
2327 DataCache_Uncache,
2328 DataCache_EnumCache,
2329 DataCache_InitCache,
2330 DataCache_IOleCache2_SetData,
2331 DataCache_UpdateCache,
2332 DataCache_DiscardCache
2335 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2337 DataCache_IOleCacheControl_QueryInterface,
2338 DataCache_IOleCacheControl_AddRef,
2339 DataCache_IOleCacheControl_Release,
2340 DataCache_OnRun,
2341 DataCache_OnStop
2344 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2346 DataCache_IAdviseSink_QueryInterface,
2347 DataCache_IAdviseSink_AddRef,
2348 DataCache_IAdviseSink_Release,
2349 DataCache_OnDataChange,
2350 DataCache_OnViewChange,
2351 DataCache_OnRename,
2352 DataCache_OnSave,
2353 DataCache_OnClose
2356 /*********************************************************
2357 * Method implementation for DataCache class.
2359 static DataCache* DataCache_Construct(
2360 REFCLSID clsid,
2361 LPUNKNOWN pUnkOuter)
2363 DataCache* newObject = 0;
2366 * Allocate space for the object.
2368 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2370 if (newObject==0)
2371 return newObject;
2374 * Initialize the virtual function table.
2376 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2377 newObject->IUnknown_iface.lpVtbl = &DataCache_NDIUnknown_VTable;
2378 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2379 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2380 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2381 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2382 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2385 * Start with one reference count. The caller of this function
2386 * must release the interface pointer when it is done.
2388 newObject->ref = 1;
2391 * Initialize the outer unknown
2392 * We don't keep a reference on the outer unknown since, the way
2393 * aggregation works, our lifetime is at least as large as its
2394 * lifetime.
2396 if (pUnkOuter==NULL)
2397 pUnkOuter = &newObject->IUnknown_iface;
2399 newObject->outerUnknown = pUnkOuter;
2402 * Initialize the other members of the structure.
2404 newObject->sinkAspects = 0;
2405 newObject->sinkAdviseFlag = 0;
2406 newObject->sinkInterface = 0;
2407 newObject->presentationStorage = NULL;
2408 list_init(&newObject->cache_list);
2409 newObject->last_cache_id = 1;
2410 newObject->dirty = FALSE;
2411 newObject->running_object = NULL;
2413 return newObject;
2416 /******************************************************************************
2417 * CreateDataCache [OLE32.@]
2419 * Creates a data cache to allow an object to render one or more of its views,
2420 * whether running or not.
2422 * PARAMS
2423 * pUnkOuter [I] Outer unknown for the object.
2424 * rclsid [I]
2425 * riid [I] IID of interface to return.
2426 * ppvObj [O] Address where the data cache object will be stored on return.
2428 * RETURNS
2429 * Success: S_OK.
2430 * Failure: HRESULT code.
2432 * NOTES
2433 * The following interfaces are supported by the returned data cache object:
2434 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2435 * IViewObject and IViewObject2.
2437 HRESULT WINAPI CreateDataCache(
2438 LPUNKNOWN pUnkOuter,
2439 REFCLSID rclsid,
2440 REFIID riid,
2441 LPVOID* ppvObj)
2443 DataCache* newCache = NULL;
2444 HRESULT hr = S_OK;
2446 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2449 * Sanity check
2451 if (ppvObj==0)
2452 return E_POINTER;
2454 *ppvObj = 0;
2457 * If this cache is constructed for aggregation, make sure
2458 * the caller is requesting the IUnknown interface.
2459 * This is necessary because it's the only time the non-delegating
2460 * IUnknown pointer can be returned to the outside.
2462 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2463 return CLASS_E_NOAGGREGATION;
2466 * Try to construct a new instance of the class.
2468 newCache = DataCache_Construct(rclsid,
2469 pUnkOuter);
2471 if (newCache == 0)
2472 return E_OUTOFMEMORY;
2475 * Make sure it supports the interface required by the caller.
2477 hr = IUnknown_QueryInterface(&newCache->IUnknown_iface, riid, ppvObj);
2480 * Release the reference obtained in the constructor. If
2481 * the QueryInterface was unsuccessful, it will free the class.
2483 IUnknown_Release(&newCache->IUnknown_iface);
2485 return hr;