wined3d: Handle hull shader control point outputs.
[wine.git] / dlls / ole32 / datacache.c
blob40d4ab8c2300986cb9a604410506175dc71ba8b2
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 "ole2.h"
59 #include "compobj_private.h"
60 #include "wine/unicode.h"
61 #include "wine/list.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
66 /****************************************************************************
67 * PresentationDataHeader
69 * This structure represents the header of the \002OlePresXXX stream in
70 * the OLE object storage.
72 typedef struct PresentationDataHeader
74 /* clipformat:
75 * - standard clipformat:
76 * DWORD length = 0xffffffff;
77 * DWORD cfFormat;
78 * - or custom clipformat:
79 * DWORD length;
80 * CHAR format_name[length]; (null-terminated)
82 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
83 DVASPECT dvAspect;
84 DWORD lindex;
85 DWORD tymed;
86 DWORD unknown7; /* 0 */
87 DWORD dwObjectExtentX;
88 DWORD dwObjectExtentY;
89 DWORD dwSize;
90 } PresentationDataHeader;
92 enum stream_type
94 no_stream,
95 pres_stream,
96 contents_stream
99 typedef struct DataCacheEntry
101 struct list entry;
102 /* format of this entry */
103 FORMATETC fmtetc;
104 /* the clipboard format of the data */
105 CLIPFORMAT data_cf;
106 /* cached data */
107 STGMEDIUM stgmedium;
109 * This stream pointer is set through a call to
110 * IPersistStorage_Load. This is where the visual
111 * representation of the object is stored.
113 IStream *stream;
114 enum stream_type stream_type;
115 /* connection ID */
116 DWORD id;
117 /* dirty flag */
118 BOOL dirty;
119 /* stream number (-1 if not set ) */
120 unsigned short stream_number;
121 /* sink id set when object is running */
122 DWORD sink_id;
123 /* Advise sink flags */
124 DWORD advise_flags;
125 } DataCacheEntry;
127 /****************************************************************************
128 * DataCache
130 struct DataCache
133 * List all interface here
135 IUnknown IUnknown_inner;
136 IDataObject IDataObject_iface;
137 IPersistStorage IPersistStorage_iface;
138 IViewObject2 IViewObject2_iface;
139 IOleCache2 IOleCache2_iface;
140 IOleCacheControl IOleCacheControl_iface;
142 /* The sink that is connected to a remote object.
143 The other interfaces are not available by QI'ing the sink and vice-versa */
144 IAdviseSink IAdviseSink_iface;
147 * Reference count of this object
149 LONG ref;
152 * IUnknown implementation of the outer object.
154 IUnknown *outer_unk;
157 * The user of this object can setup ONE advise sink
158 * connection with the object. These parameters describe
159 * that connection.
161 DWORD sinkAspects;
162 DWORD sinkAdviseFlag;
163 IAdviseSink* sinkInterface;
164 IStorage *presentationStorage;
166 /* list of cache entries */
167 struct list cache_list;
168 /* last id assigned to an entry */
169 DWORD last_cache_id;
170 /* dirty flag */
171 BOOL dirty;
172 /* running object set by OnRun */
173 IDataObject *running_object;
176 typedef struct DataCache DataCache;
179 * Here, I define utility macros to help with the casting of the
180 * "this" parameter.
181 * There is a version to accommodate all of the VTables implemented
182 * by this object.
185 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
187 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
190 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
192 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
195 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
197 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
200 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
202 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
205 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
207 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
210 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
212 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
215 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
217 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
220 const char *debugstr_formatetc(const FORMATETC *formatetc)
222 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
223 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
224 formatetc->lindex, formatetc->tymed);
227 /***********************************************************************
228 * bitmap_info_size
230 * Return the size of the bitmap info structure including color table.
232 int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
234 unsigned int colors, size, masks = 0;
236 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
238 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
239 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
240 return sizeof(BITMAPCOREHEADER) + colors *
241 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
243 else /* assume BITMAPINFOHEADER */
245 colors = info->bmiHeader.biClrUsed;
246 if (colors > 256) /* buffer overflow otherwise */
247 colors = 256;
248 if (!colors && (info->bmiHeader.biBitCount <= 8))
249 colors = 1 << info->bmiHeader.biBitCount;
250 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
251 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
252 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
256 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
258 list_remove(&cache_entry->entry);
259 if (cache_entry->stream)
260 IStream_Release(cache_entry->stream);
261 CoTaskMemFree(cache_entry->fmtetc.ptd);
262 ReleaseStgMedium(&cache_entry->stgmedium);
263 if(cache_entry->sink_id)
264 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
266 HeapFree(GetProcessHeap(), 0, cache_entry);
269 static void DataCache_Destroy(
270 DataCache* ptrToDestroy)
272 DataCacheEntry *cache_entry, *next_cache_entry;
274 TRACE("()\n");
276 if (ptrToDestroy->sinkInterface != NULL)
278 IAdviseSink_Release(ptrToDestroy->sinkInterface);
279 ptrToDestroy->sinkInterface = NULL;
282 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
283 DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
285 if (ptrToDestroy->presentationStorage != NULL)
287 IStorage_Release(ptrToDestroy->presentationStorage);
288 ptrToDestroy->presentationStorage = NULL;
292 * Free the datacache pointer.
294 HeapFree(GetProcessHeap(), 0, ptrToDestroy);
297 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
299 DataCacheEntry *cache_entry;
300 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
302 /* FIXME: also compare DVTARGETDEVICEs */
303 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
304 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
305 (formatetc->lindex == cache_entry->fmtetc.lindex) &&
306 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
307 return cache_entry;
309 return NULL;
312 /* checks that the clipformat and tymed are valid and returns an error if they
313 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
314 * DataCache_Draw */
315 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed, BOOL load)
317 if (!cfFormat || !tymed ||
318 (cfFormat == CF_METAFILEPICT && (tymed == TYMED_MFPICT || load)) ||
319 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
320 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
321 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
322 return S_OK;
323 else if (tymed == TYMED_HGLOBAL)
324 return CACHE_S_FORMATETC_NOTSUPPORTED;
325 else
327 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
328 return DV_E_TYMED;
332 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf,
333 DWORD id)
335 HRESULT hr;
337 hr = copy_formatetc(&entry->fmtetc, fmt);
338 if (FAILED(hr)) return FALSE;
340 entry->data_cf = 0;
341 entry->stgmedium.tymed = TYMED_NULL;
342 entry->stgmedium.pUnkForRelease = NULL;
343 entry->stream = NULL;
344 entry->stream_type = no_stream;
345 entry->id = id;
346 entry->dirty = TRUE;
347 entry->stream_number = -1;
348 entry->sink_id = 0;
349 entry->advise_flags = advf;
351 return TRUE;
354 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf,
355 DataCacheEntry **cache_entry, BOOL load)
357 HRESULT hr;
359 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed, load);
360 if (FAILED(hr))
361 return hr;
362 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
363 TRACE("creating unsupported format %d\n", formatetc->cfFormat);
365 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
366 if (!*cache_entry)
367 return E_OUTOFMEMORY;
369 if (!init_cache_entry(*cache_entry, formatetc, advf, This->last_cache_id))
370 goto fail;
372 list_add_tail(&This->cache_list, &(*cache_entry)->entry);
373 This->last_cache_id++;
375 return hr;
377 fail:
378 HeapFree(GetProcessHeap(), 0, *cache_entry);
379 return E_OUTOFMEMORY;
382 /************************************************************************
383 * DataCache_FireOnViewChange
385 * This method will fire an OnViewChange notification to the advise
386 * sink registered with the datacache.
388 * See IAdviseSink::OnViewChange for more details.
390 static void DataCache_FireOnViewChange(
391 DataCache* this,
392 DWORD aspect,
393 LONG lindex)
395 TRACE("(%p, %x, %d)\n", this, aspect, lindex);
398 * The sink supplies a filter when it registers
399 * we make sure we only send the notifications when that
400 * filter matches.
402 if ((this->sinkAspects & aspect) != 0)
404 if (this->sinkInterface != NULL)
406 IAdviseSink_OnViewChange(this->sinkInterface,
407 aspect,
408 lindex);
411 * Some sinks want to be unregistered automatically when
412 * the first notification goes out.
414 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
416 IAdviseSink_Release(this->sinkInterface);
418 this->sinkInterface = NULL;
419 this->sinkAspects = 0;
420 this->sinkAdviseFlag = 0;
426 /* Helper for DataCacheEntry_OpenPresStream */
427 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
429 /* The presentation streams have names of the form "\002OlePresXXX",
430 * where XXX goes from 000 to 999. */
431 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
433 LPCWSTR name = elem->pwcsName;
435 return (elem->type == STGTY_STREAM)
436 && (strlenW(name) == 11)
437 && (strncmpW(name, OlePres, 8) == 0)
438 && (name[8] >= '0') && (name[8] <= '9')
439 && (name[9] >= '0') && (name[9] <= '9')
440 && (name[10] >= '0') && (name[10] <= '9');
443 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
445 DWORD length;
446 HRESULT hr;
447 ULONG read;
449 *clipformat = 0;
451 hr = IStream_Read(stream, &length, sizeof(length), &read);
452 if (hr != S_OK || read != sizeof(length))
453 return DV_E_CLIPFORMAT;
454 if (length == -1)
456 DWORD cf;
457 hr = IStream_Read(stream, &cf, sizeof(cf), &read);
458 if (hr != S_OK || read != sizeof(cf))
459 return DV_E_CLIPFORMAT;
460 *clipformat = cf;
462 else
464 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
465 if (!format_name)
466 return E_OUTOFMEMORY;
467 hr = IStream_Read(stream, format_name, length, &read);
468 if (hr != S_OK || read != length || format_name[length - 1] != '\0')
470 HeapFree(GetProcessHeap(), 0, format_name);
471 return DV_E_CLIPFORMAT;
473 *clipformat = RegisterClipboardFormatA(format_name);
474 HeapFree(GetProcessHeap(), 0, format_name);
476 return S_OK;
479 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
481 DWORD length;
482 HRESULT hr;
484 if (clipformat < 0xc000)
485 length = -1;
486 else
487 length = GetClipboardFormatNameA(clipformat, NULL, 0);
488 hr = IStream_Write(stream, &length, sizeof(length), NULL);
489 if (FAILED(hr))
490 return hr;
491 if (clipformat < 0xc000)
493 DWORD cf = clipformat;
494 hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
496 else
498 char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
499 if (!format_name)
500 return E_OUTOFMEMORY;
501 GetClipboardFormatNameA(clipformat, format_name, length);
502 hr = IStream_Write(stream, format_name, length, NULL);
503 HeapFree(GetProcessHeap(), 0, format_name);
505 return hr;
508 /************************************************************************
509 * DataCacheEntry_OpenPresStream
511 * This method will find the stream for the given presentation. It makes
512 * no attempt at fallback.
514 * Param:
515 * this - Pointer to the DataCache object
516 * drawAspect - The aspect of the object that we wish to draw.
517 * pStm - A returned stream. It points to the beginning of the
518 * - presentation data, including the header.
520 * Errors:
521 * S_OK The requested stream has been opened.
522 * OLE_E_BLANK The requested stream could not be found.
523 * Quite a few others I'm too lazy to map correctly.
525 * Notes:
526 * Algorithm: Scan the elements of the presentation storage, looking
527 * for presentation streams. For each presentation stream,
528 * load the header and check to see if the aspect matches.
530 * If a fallback is desired, just opening the first presentation stream
531 * is a possibility.
533 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
535 HRESULT hr;
536 LARGE_INTEGER offset;
538 if (cache_entry->stream)
540 /* Rewind the stream before returning it. */
541 offset.QuadPart = 0;
543 hr = IStream_Seek( cache_entry->stream, offset, STREAM_SEEK_SET, NULL );
544 if (SUCCEEDED( hr ))
546 *ppStm = cache_entry->stream;
547 IStream_AddRef( cache_entry->stream );
550 else
551 hr = OLE_E_BLANK;
553 return hr;
557 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
559 HRESULT hr;
560 STATSTG stat;
561 ULARGE_INTEGER current_pos;
562 void *bits;
563 METAFILEPICT *mfpict;
564 HGLOBAL hmfpict;
565 PresentationDataHeader header;
566 CLIPFORMAT clipformat;
567 static const LARGE_INTEGER offset_zero;
568 ULONG read;
570 if (cache_entry->stream_type != pres_stream)
572 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
573 return E_FAIL;
576 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
577 if (FAILED( hr )) return hr;
579 hr = read_clipformat( stm, &clipformat );
580 if (FAILED( hr )) return hr;
582 hr = IStream_Read( stm, &header, sizeof(header), &read );
583 if (hr != S_OK || read != sizeof(header)) return E_FAIL;
585 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
586 if (FAILED( hr )) return hr;
588 stat.cbSize.QuadPart -= current_pos.QuadPart;
590 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
591 if (!hmfpict) return E_OUTOFMEMORY;
592 mfpict = GlobalLock( hmfpict );
594 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
595 if (!bits)
597 GlobalFree( hmfpict );
598 return E_OUTOFMEMORY;
601 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
602 if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL;
604 if (SUCCEEDED( hr ))
606 /* FIXME: get this from the stream */
607 mfpict->mm = MM_ANISOTROPIC;
608 mfpict->xExt = header.dwObjectExtentX;
609 mfpict->yExt = header.dwObjectExtentY;
610 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
611 if (!mfpict->hMF)
612 hr = E_FAIL;
615 GlobalUnlock( hmfpict );
616 if (SUCCEEDED( hr ))
618 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
619 cache_entry->stgmedium.tymed = TYMED_MFPICT;
620 cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
622 else
623 GlobalFree( hmfpict );
625 HeapFree( GetProcessHeap(), 0, bits );
627 return hr;
630 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
632 HRESULT hr;
633 STATSTG stat;
634 void *dib;
635 HGLOBAL hglobal;
636 ULONG read, info_size, bi_size;
637 BITMAPFILEHEADER file;
638 BITMAPINFOHEADER *info;
640 if (cache_entry->stream_type != contents_stream)
642 FIXME( "Unimplemented for stream type %d\n", cache_entry->stream_type );
643 return E_FAIL;
646 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
647 if (FAILED( hr )) return hr;
649 if (stat.cbSize.QuadPart < sizeof(file) + sizeof(DWORD)) return E_FAIL;
650 hr = IStream_Read( stm, &file, sizeof(file), &read );
651 if (hr != S_OK || read != sizeof(file)) return E_FAIL;
652 stat.cbSize.QuadPart -= sizeof(file);
654 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
655 if (!hglobal) return E_OUTOFMEMORY;
656 dib = GlobalLock( hglobal );
658 hr = IStream_Read( stm, dib, sizeof(DWORD), &read );
659 if (hr != S_OK || read != sizeof(DWORD)) goto fail;
660 bi_size = *(DWORD *)dib;
661 if (stat.cbSize.QuadPart < bi_size) goto fail;
663 hr = IStream_Read( stm, (char *)dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read );
664 if (hr != S_OK || read != bi_size - sizeof(DWORD)) goto fail;
666 info_size = bitmap_info_size( dib, DIB_RGB_COLORS );
667 if (stat.cbSize.QuadPart < info_size) goto fail;
668 if (info_size > bi_size)
670 hr = IStream_Read( stm, (char *)dib + bi_size, info_size - bi_size, &read );
671 if (hr != S_OK || read != info_size - bi_size) goto fail;
673 stat.cbSize.QuadPart -= info_size;
675 if (file.bfOffBits)
677 LARGE_INTEGER skip;
679 skip.QuadPart = file.bfOffBits - sizeof(file) - info_size;
680 if (stat.cbSize.QuadPart < skip.QuadPart) goto fail;
681 hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL );
682 if (hr != S_OK) goto fail;
683 stat.cbSize.QuadPart -= skip.QuadPart;
686 hr = IStream_Read( stm, (char *)dib + info_size, stat.cbSize.u.LowPart, &read );
687 if (hr != S_OK || read != stat.cbSize.QuadPart) goto fail;
689 if (bi_size >= sizeof(*info))
691 info = (BITMAPINFOHEADER *)dib;
692 if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0)
694 HDC hdc = GetDC( 0 );
695 info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 );
696 info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 );
697 ReleaseDC( 0, hdc );
701 GlobalUnlock( hglobal );
703 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
704 cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
705 cache_entry->stgmedium.u.hGlobal = hglobal;
707 return S_OK;
709 fail:
710 GlobalUnlock( hglobal );
711 GlobalFree( hglobal );
712 return E_FAIL;
716 /************************************************************************
717 * DataCacheEntry_LoadData
719 * This method will read information for the requested presentation
720 * into the given structure.
722 * Param:
723 * This - The entry to load the data from.
725 * Returns:
726 * This method returns a metafile handle if it is successful.
727 * it will return 0 if not.
729 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
731 HRESULT hr;
732 IStream *stm;
734 hr = DataCacheEntry_OpenPresStream( cache_entry, &stm );
735 if (FAILED(hr)) return hr;
737 switch (cache_entry->fmtetc.cfFormat)
739 case CF_METAFILEPICT:
740 hr = load_mf_pict( cache_entry, stm );
741 break;
743 case CF_DIB:
744 hr = load_dib( cache_entry, stm );
745 break;
747 default:
748 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
749 hr = E_NOTIMPL;
752 IStream_Release( stm );
753 return hr;
756 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
757 IStorage *storage, IStream **stream)
759 WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
760 '0' + (cache_entry->stream_number / 100) % 10,
761 '0' + (cache_entry->stream_number / 10) % 10,
762 '0' + cache_entry->stream_number % 10, 0};
764 /* FIXME: cache the created stream in This? */
765 return IStorage_CreateStream(storage, wszName,
766 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
767 0, 0, stream);
770 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
771 BOOL same_as_load)
773 PresentationDataHeader header;
774 HRESULT hr;
775 IStream *pres_stream;
776 void *data = NULL;
778 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
780 hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
781 if (FAILED(hr))
782 return hr;
784 hr = write_clipformat(pres_stream, cache_entry->data_cf);
785 if (FAILED(hr))
786 return hr;
788 if (cache_entry->fmtetc.ptd)
789 FIXME("ptd not serialized\n");
790 header.unknown3 = 4;
791 header.dvAspect = cache_entry->fmtetc.dwAspect;
792 header.lindex = cache_entry->fmtetc.lindex;
793 header.tymed = cache_entry->stgmedium.tymed;
794 header.unknown7 = 0;
795 header.dwObjectExtentX = 0;
796 header.dwObjectExtentY = 0;
797 header.dwSize = 0;
799 /* size the data */
800 switch (cache_entry->data_cf)
802 case CF_METAFILEPICT:
804 if (cache_entry->stgmedium.tymed != TYMED_NULL)
806 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
807 if (!mfpict)
809 IStream_Release(pres_stream);
810 return DV_E_STGMEDIUM;
812 header.dwObjectExtentX = mfpict->xExt;
813 header.dwObjectExtentY = mfpict->yExt;
814 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
815 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
817 break;
819 default:
820 break;
824 * Write the header.
826 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
827 NULL);
828 if (FAILED(hr))
830 IStream_Release(pres_stream);
831 return hr;
834 /* get the data */
835 switch (cache_entry->data_cf)
837 case CF_METAFILEPICT:
839 if (cache_entry->stgmedium.tymed != TYMED_NULL)
841 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
842 if (!mfpict)
844 IStream_Release(pres_stream);
845 return DV_E_STGMEDIUM;
847 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
848 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
849 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
851 break;
853 default:
854 break;
857 if (data)
858 hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
859 HeapFree(GetProcessHeap(), 0, data);
861 IStream_Release(pres_stream);
862 return hr;
865 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
866 * does no checking of whether src_stgm has a supported tymed, so this should be
867 * done in the caller */
868 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
869 const STGMEDIUM *src_stgm)
871 if (src_stgm->tymed == TYMED_MFPICT)
873 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
874 METAFILEPICT *dest_mfpict;
876 if (!src_mfpict)
877 return DV_E_STGMEDIUM;
878 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
879 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
880 if (!dest_mfpict)
882 GlobalUnlock(src_stgm->u.hMetaFilePict);
883 return E_OUTOFMEMORY;
885 *dest_mfpict = *src_mfpict;
886 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
887 GlobalUnlock(src_stgm->u.hMetaFilePict);
888 GlobalUnlock(dest_stgm->u.hMetaFilePict);
890 else if (src_stgm->tymed != TYMED_NULL)
892 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
893 GMEM_MOVEABLE);
894 if (!dest_stgm->u.hGlobal)
895 return E_OUTOFMEMORY;
897 dest_stgm->tymed = src_stgm->tymed;
898 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
899 if (dest_stgm->pUnkForRelease)
900 IUnknown_AddRef(dest_stgm->pUnkForRelease);
901 return S_OK;
904 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
905 const FORMATETC *formatetc,
906 const STGMEDIUM *stgmedium,
907 BOOL fRelease)
909 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
910 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
911 stgmedium->tymed == TYMED_NULL)
913 WARN("invalid formatetc\n");
914 return DV_E_FORMATETC;
917 cache_entry->dirty = TRUE;
918 ReleaseStgMedium(&cache_entry->stgmedium);
919 cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
920 if (fRelease)
922 cache_entry->stgmedium = *stgmedium;
923 return S_OK;
925 else
926 return copy_stg_medium(cache_entry->data_cf,
927 &cache_entry->stgmedium, stgmedium);
930 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
932 if (stgmedium->tymed == TYMED_NULL && cache_entry->stream)
934 HRESULT hr = DataCacheEntry_LoadData(cache_entry);
935 if (FAILED(hr))
936 return hr;
938 if (cache_entry->stgmedium.tymed == TYMED_NULL)
939 return OLE_E_BLANK;
940 return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
943 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
945 ReleaseStgMedium(&cache_entry->stgmedium);
946 cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
947 return S_OK;
950 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
952 if (cache_entry->stream)
954 IStream_Release(cache_entry->stream);
955 cache_entry->stream = NULL;
959 /*********************************************************
960 * Method implementation for the non delegating IUnknown
961 * part of the DataCache class.
964 /************************************************************************
965 * DataCache_NDIUnknown_QueryInterface (IUnknown)
967 * This version of QueryInterface will not delegate its implementation
968 * to the outer unknown.
970 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
971 IUnknown* iface,
972 REFIID riid,
973 void** ppvObject)
975 DataCache *this = impl_from_IUnknown(iface);
977 if ( ppvObject==0 )
978 return E_INVALIDARG;
980 *ppvObject = 0;
982 if (IsEqualIID(&IID_IUnknown, riid))
984 *ppvObject = iface;
986 else if (IsEqualIID(&IID_IDataObject, riid))
988 *ppvObject = &this->IDataObject_iface;
990 else if ( IsEqualIID(&IID_IPersistStorage, riid) ||
991 IsEqualIID(&IID_IPersist, riid) )
993 *ppvObject = &this->IPersistStorage_iface;
995 else if ( IsEqualIID(&IID_IViewObject, riid) ||
996 IsEqualIID(&IID_IViewObject2, riid) )
998 *ppvObject = &this->IViewObject2_iface;
1000 else if ( IsEqualIID(&IID_IOleCache, riid) ||
1001 IsEqualIID(&IID_IOleCache2, riid) )
1003 *ppvObject = &this->IOleCache2_iface;
1005 else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1007 *ppvObject = &this->IOleCacheControl_iface;
1010 if ((*ppvObject)==0)
1012 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1013 return E_NOINTERFACE;
1016 IUnknown_AddRef((IUnknown*)*ppvObject);
1018 return S_OK;
1021 /************************************************************************
1022 * DataCache_NDIUnknown_AddRef (IUnknown)
1024 * This version of QueryInterface will not delegate its implementation
1025 * to the outer unknown.
1027 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1028 IUnknown* iface)
1030 DataCache *this = impl_from_IUnknown(iface);
1031 return InterlockedIncrement(&this->ref);
1034 /************************************************************************
1035 * DataCache_NDIUnknown_Release (IUnknown)
1037 * This version of QueryInterface will not delegate its implementation
1038 * to the outer unknown.
1040 static ULONG WINAPI DataCache_NDIUnknown_Release(
1041 IUnknown* iface)
1043 DataCache *this = impl_from_IUnknown(iface);
1044 ULONG ref;
1046 ref = InterlockedDecrement(&this->ref);
1048 if (ref == 0) DataCache_Destroy(this);
1050 return ref;
1053 /*********************************************************
1054 * Method implementation for the IDataObject
1055 * part of the DataCache class.
1058 /************************************************************************
1059 * DataCache_IDataObject_QueryInterface (IUnknown)
1061 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1062 IDataObject* iface,
1063 REFIID riid,
1064 void** ppvObject)
1066 DataCache *this = impl_from_IDataObject(iface);
1068 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1071 /************************************************************************
1072 * DataCache_IDataObject_AddRef (IUnknown)
1074 static ULONG WINAPI DataCache_IDataObject_AddRef(
1075 IDataObject* iface)
1077 DataCache *this = impl_from_IDataObject(iface);
1079 return IUnknown_AddRef(this->outer_unk);
1082 /************************************************************************
1083 * DataCache_IDataObject_Release (IUnknown)
1085 static ULONG WINAPI DataCache_IDataObject_Release(
1086 IDataObject* iface)
1088 DataCache *this = impl_from_IDataObject(iface);
1090 return IUnknown_Release(this->outer_unk);
1093 /************************************************************************
1094 * DataCache_GetData
1096 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1098 static HRESULT WINAPI DataCache_GetData(
1099 IDataObject* iface,
1100 LPFORMATETC pformatetcIn,
1101 STGMEDIUM* pmedium)
1103 DataCache *This = impl_from_IDataObject(iface);
1104 DataCacheEntry *cache_entry;
1106 memset(pmedium, 0, sizeof(*pmedium));
1108 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1109 if (!cache_entry)
1110 return OLE_E_BLANK;
1112 return DataCacheEntry_GetData(cache_entry, pmedium);
1115 static HRESULT WINAPI DataCache_GetDataHere(
1116 IDataObject* iface,
1117 LPFORMATETC pformatetc,
1118 STGMEDIUM* pmedium)
1120 FIXME("stub\n");
1121 return E_NOTIMPL;
1124 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1126 DataCache *This = impl_from_IDataObject( iface );
1127 DataCacheEntry *cache_entry;
1129 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1130 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1132 return cache_entry ? S_OK : S_FALSE;
1135 /************************************************************************
1136 * DataCache_EnumFormatEtc (IDataObject)
1138 * The data cache doesn't implement this method.
1140 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1141 IDataObject* iface,
1142 LPFORMATETC pformatectIn,
1143 LPFORMATETC pformatetcOut)
1145 TRACE("()\n");
1146 return E_NOTIMPL;
1149 /************************************************************************
1150 * DataCache_IDataObject_SetData (IDataObject)
1152 * This method is delegated to the IOleCache2 implementation.
1154 static HRESULT WINAPI DataCache_IDataObject_SetData(
1155 IDataObject* iface,
1156 LPFORMATETC pformatetc,
1157 STGMEDIUM* pmedium,
1158 BOOL fRelease)
1160 IOleCache2* oleCache = NULL;
1161 HRESULT hres;
1163 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1165 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1167 if (FAILED(hres))
1168 return E_UNEXPECTED;
1170 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1172 IOleCache2_Release(oleCache);
1174 return hres;
1177 /************************************************************************
1178 * DataCache_EnumFormatEtc (IDataObject)
1180 * The data cache doesn't implement this method.
1182 static HRESULT WINAPI DataCache_EnumFormatEtc(
1183 IDataObject* iface,
1184 DWORD dwDirection,
1185 IEnumFORMATETC** ppenumFormatEtc)
1187 TRACE("()\n");
1188 return E_NOTIMPL;
1191 /************************************************************************
1192 * DataCache_DAdvise (IDataObject)
1194 * The data cache doesn't support connections.
1196 static HRESULT WINAPI DataCache_DAdvise(
1197 IDataObject* iface,
1198 FORMATETC* pformatetc,
1199 DWORD advf,
1200 IAdviseSink* pAdvSink,
1201 DWORD* pdwConnection)
1203 TRACE("()\n");
1204 return OLE_E_ADVISENOTSUPPORTED;
1207 /************************************************************************
1208 * DataCache_DUnadvise (IDataObject)
1210 * The data cache doesn't support connections.
1212 static HRESULT WINAPI DataCache_DUnadvise(
1213 IDataObject* iface,
1214 DWORD dwConnection)
1216 TRACE("()\n");
1217 return OLE_E_NOCONNECTION;
1220 /************************************************************************
1221 * DataCache_EnumDAdvise (IDataObject)
1223 * The data cache doesn't support connections.
1225 static HRESULT WINAPI DataCache_EnumDAdvise(
1226 IDataObject* iface,
1227 IEnumSTATDATA** ppenumAdvise)
1229 TRACE("()\n");
1230 return OLE_E_ADVISENOTSUPPORTED;
1233 /*********************************************************
1234 * Method implementation for the IDataObject
1235 * part of the DataCache class.
1238 /************************************************************************
1239 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1241 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1242 IPersistStorage* iface,
1243 REFIID riid,
1244 void** ppvObject)
1246 DataCache *this = impl_from_IPersistStorage(iface);
1248 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1251 /************************************************************************
1252 * DataCache_IPersistStorage_AddRef (IUnknown)
1254 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1255 IPersistStorage* iface)
1257 DataCache *this = impl_from_IPersistStorage(iface);
1259 return IUnknown_AddRef(this->outer_unk);
1262 /************************************************************************
1263 * DataCache_IPersistStorage_Release (IUnknown)
1265 static ULONG WINAPI DataCache_IPersistStorage_Release(
1266 IPersistStorage* iface)
1268 DataCache *this = impl_from_IPersistStorage(iface);
1270 return IUnknown_Release(this->outer_unk);
1273 /************************************************************************
1274 * DataCache_GetClassID (IPersistStorage)
1277 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1279 DataCache *This = impl_from_IPersistStorage( iface );
1280 HRESULT hr;
1281 STATSTG statstg;
1283 TRACE( "(%p, %p)\n", iface, clsid );
1285 if (This->presentationStorage)
1287 hr = IStorage_Stat( This->presentationStorage, &statstg, STATFLAG_NONAME );
1288 if (SUCCEEDED(hr))
1290 *clsid = statstg.clsid;
1291 return S_OK;
1295 *clsid = CLSID_NULL;
1297 return S_OK;
1300 /************************************************************************
1301 * DataCache_IsDirty (IPersistStorage)
1303 static HRESULT WINAPI DataCache_IsDirty(
1304 IPersistStorage* iface)
1306 DataCache *This = impl_from_IPersistStorage(iface);
1307 DataCacheEntry *cache_entry;
1309 TRACE("(%p)\n", iface);
1311 if (This->dirty)
1312 return S_OK;
1314 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1315 if (cache_entry->dirty)
1316 return S_OK;
1318 return S_FALSE;
1321 /************************************************************************
1322 * DataCache_InitNew (IPersistStorage)
1324 * The data cache implementation of IPersistStorage_InitNew simply stores
1325 * the storage pointer.
1327 static HRESULT WINAPI DataCache_InitNew(
1328 IPersistStorage* iface,
1329 IStorage* pStg)
1331 DataCache *This = impl_from_IPersistStorage(iface);
1333 TRACE("(%p, %p)\n", iface, pStg);
1335 if (This->presentationStorage != NULL)
1336 IStorage_Release(This->presentationStorage);
1338 This->presentationStorage = pStg;
1340 IStorage_AddRef(This->presentationStorage);
1341 This->dirty = TRUE;
1343 return S_OK;
1347 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, IStream *stm,
1348 enum stream_type type )
1350 DataCacheEntry *cache_entry;
1351 HRESULT hr = S_OK;
1353 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1355 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1356 if (!cache_entry)
1357 hr = DataCache_CreateEntry( This, fmt, 0, &cache_entry, TRUE );
1358 if (SUCCEEDED( hr ))
1360 DataCacheEntry_DiscardData( cache_entry );
1361 if (cache_entry->stream) IStream_Release( cache_entry->stream );
1362 cache_entry->stream = stm;
1363 IStream_AddRef( stm );
1364 cache_entry->stream_type = type;
1365 cache_entry->dirty = FALSE;
1367 return hr;
1370 static HRESULT parse_pres_streams( DataCache *This, IStorage *stg )
1372 HRESULT hr;
1373 IEnumSTATSTG *stat_enum;
1374 STATSTG stat;
1375 IStream *stm;
1376 PresentationDataHeader header;
1377 ULONG actual_read;
1378 CLIPFORMAT clipformat;
1379 FORMATETC fmtetc;
1381 hr = IStorage_EnumElements( stg, 0, NULL, 0, &stat_enum );
1382 if (FAILED( hr )) return hr;
1384 while ((hr = IEnumSTATSTG_Next( stat_enum, 1, &stat, NULL )) == S_OK)
1386 if (DataCache_IsPresentationStream( &stat ))
1388 hr = IStorage_OpenStream( stg, stat.pwcsName, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1389 0, &stm );
1390 if (SUCCEEDED( hr ))
1392 hr = read_clipformat( stm, &clipformat );
1394 if (hr == S_OK)
1395 hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1397 if (hr == S_OK && actual_read == sizeof(header))
1399 fmtetc.cfFormat = clipformat;
1400 fmtetc.ptd = NULL; /* FIXME */
1401 fmtetc.dwAspect = header.dvAspect;
1402 fmtetc.lindex = header.lindex;
1403 fmtetc.tymed = header.tymed;
1405 add_cache_entry( This, &fmtetc, stm, pres_stream );
1407 IStream_Release( stm );
1410 CoTaskMemFree( stat.pwcsName );
1412 IEnumSTATSTG_Release( stat_enum );
1414 return S_OK;
1417 static const FORMATETC static_dib_fmt = { CF_DIB, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
1419 static HRESULT parse_contents_stream( DataCache *This, IStorage *stg, IStream *stm )
1421 HRESULT hr;
1422 STATSTG stat;
1423 const FORMATETC *fmt;
1425 hr = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
1426 if (FAILED( hr )) return hr;
1428 if (IsEqualCLSID( &stat.clsid, &CLSID_Picture_Dib ))
1429 fmt = &static_dib_fmt;
1430 else
1432 FIXME("unsupported format %s\n", debugstr_guid( &stat.clsid ));
1433 return E_FAIL;
1436 return add_cache_entry( This, fmt, stm, contents_stream );
1439 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
1441 /************************************************************************
1442 * DataCache_Load (IPersistStorage)
1444 * The data cache implementation of IPersistStorage_Load doesn't
1445 * actually load anything. Instead, it holds on to the storage pointer
1446 * and it will load the presentation information when the
1447 * IDataObject_GetData or IViewObject2_Draw methods are called.
1449 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *pStg )
1451 DataCache *This = impl_from_IPersistStorage(iface);
1452 HRESULT hr;
1453 IStream *stm;
1455 TRACE("(%p, %p)\n", iface, pStg);
1457 IPersistStorage_HandsOffStorage( iface );
1459 hr = IStorage_OpenStream( pStg, CONTENTS, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE,
1460 0, &stm );
1461 if (SUCCEEDED( hr ))
1463 hr = parse_contents_stream( This, pStg, stm );
1464 IStream_Release( stm );
1467 if (FAILED(hr))
1468 hr = parse_pres_streams( This, pStg );
1470 if (SUCCEEDED( hr ))
1472 This->dirty = FALSE;
1473 This->presentationStorage = pStg;
1474 IStorage_AddRef( This->presentationStorage );
1477 return hr;
1480 /************************************************************************
1481 * DataCache_Save (IPersistStorage)
1483 * Until we actually connect to a running object and retrieve new
1484 * information to it, we never have to save anything. However, it is
1485 * our responsibility to copy the information when saving to a new
1486 * storage.
1488 static HRESULT WINAPI DataCache_Save(
1489 IPersistStorage* iface,
1490 IStorage* pStg,
1491 BOOL fSameAsLoad)
1493 DataCache *This = impl_from_IPersistStorage(iface);
1494 DataCacheEntry *cache_entry;
1495 BOOL dirty = FALSE;
1496 HRESULT hr = S_OK;
1497 unsigned short stream_number = 0;
1499 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1501 dirty = This->dirty;
1502 if (!dirty)
1504 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1506 dirty = cache_entry->dirty;
1507 if (dirty)
1508 break;
1512 /* this is a shortcut if nothing changed */
1513 if (!dirty && !fSameAsLoad && This->presentationStorage)
1515 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1518 /* assign stream numbers to the cache entries */
1519 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1521 if (cache_entry->stream_number != stream_number)
1523 cache_entry->dirty = TRUE; /* needs to be written out again */
1524 cache_entry->stream_number = stream_number;
1526 stream_number++;
1529 /* write out the cache entries */
1530 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1532 if (!fSameAsLoad || cache_entry->dirty)
1534 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1535 if (FAILED(hr))
1536 break;
1538 cache_entry->dirty = FALSE;
1542 This->dirty = FALSE;
1543 return hr;
1546 /************************************************************************
1547 * DataCache_SaveCompleted (IPersistStorage)
1549 * This method is called to tell the cache to release the storage
1550 * pointer it's currently holding.
1552 static HRESULT WINAPI DataCache_SaveCompleted(
1553 IPersistStorage* iface,
1554 IStorage* pStgNew)
1556 TRACE("(%p, %p)\n", iface, pStgNew);
1558 if (pStgNew)
1560 IPersistStorage_HandsOffStorage(iface);
1562 DataCache_Load(iface, pStgNew);
1565 return S_OK;
1568 /************************************************************************
1569 * DataCache_HandsOffStorage (IPersistStorage)
1571 * This method is called to tell the cache to release the storage
1572 * pointer it's currently holding.
1574 static HRESULT WINAPI DataCache_HandsOffStorage(
1575 IPersistStorage* iface)
1577 DataCache *this = impl_from_IPersistStorage(iface);
1578 DataCacheEntry *cache_entry;
1580 TRACE("(%p)\n", iface);
1582 if (this->presentationStorage != NULL)
1584 IStorage_Release(this->presentationStorage);
1585 this->presentationStorage = NULL;
1588 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1589 DataCacheEntry_HandsOffStorage(cache_entry);
1591 return S_OK;
1594 /*********************************************************
1595 * Method implementation for the IViewObject2
1596 * part of the DataCache class.
1599 /************************************************************************
1600 * DataCache_IViewObject2_QueryInterface (IUnknown)
1602 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1603 IViewObject2* iface,
1604 REFIID riid,
1605 void** ppvObject)
1607 DataCache *this = impl_from_IViewObject2(iface);
1609 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1612 /************************************************************************
1613 * DataCache_IViewObject2_AddRef (IUnknown)
1615 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1616 IViewObject2* iface)
1618 DataCache *this = impl_from_IViewObject2(iface);
1620 return IUnknown_AddRef(this->outer_unk);
1623 /************************************************************************
1624 * DataCache_IViewObject2_Release (IUnknown)
1626 static ULONG WINAPI DataCache_IViewObject2_Release(
1627 IViewObject2* iface)
1629 DataCache *this = impl_from_IViewObject2(iface);
1631 return IUnknown_Release(this->outer_unk);
1634 /************************************************************************
1635 * DataCache_Draw (IViewObject2)
1637 * This method will draw the cached representation of the object
1638 * to the given device context.
1640 static HRESULT WINAPI DataCache_Draw(
1641 IViewObject2* iface,
1642 DWORD dwDrawAspect,
1643 LONG lindex,
1644 void* pvAspect,
1645 DVTARGETDEVICE* ptd,
1646 HDC hdcTargetDev,
1647 HDC hdcDraw,
1648 LPCRECTL lprcBounds,
1649 LPCRECTL lprcWBounds,
1650 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1651 ULONG_PTR dwContinue)
1653 DataCache *This = impl_from_IViewObject2(iface);
1654 HRESULT hres;
1655 DataCacheEntry *cache_entry;
1657 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1658 iface,
1659 dwDrawAspect,
1660 lindex,
1661 pvAspect,
1662 hdcTargetDev,
1663 hdcDraw,
1664 lprcBounds,
1665 lprcWBounds,
1666 pfnContinue,
1667 dwContinue);
1669 if (lprcBounds==NULL)
1670 return E_INVALIDARG;
1672 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1674 /* FIXME: compare ptd too */
1675 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1676 (cache_entry->fmtetc.lindex != lindex))
1677 continue;
1679 /* if the data hasn't been loaded yet, do it now */
1680 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1682 hres = DataCacheEntry_LoadData(cache_entry);
1683 if (FAILED(hres))
1684 continue;
1687 /* no data */
1688 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1689 continue;
1691 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1693 switch (cache_entry->data_cf)
1695 case CF_METAFILEPICT:
1698 * We have to be careful not to modify the state of the
1699 * DC.
1701 INT prevMapMode;
1702 SIZE oldWindowExt;
1703 SIZE oldViewportExt;
1704 POINT oldViewportOrg;
1705 METAFILEPICT *mfpict;
1707 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1708 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1709 continue;
1711 prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1713 SetWindowExtEx(hdcDraw,
1714 mfpict->xExt,
1715 mfpict->yExt,
1716 &oldWindowExt);
1718 SetViewportExtEx(hdcDraw,
1719 lprcBounds->right - lprcBounds->left,
1720 lprcBounds->bottom - lprcBounds->top,
1721 &oldViewportExt);
1723 SetViewportOrgEx(hdcDraw,
1724 lprcBounds->left,
1725 lprcBounds->top,
1726 &oldViewportOrg);
1728 PlayMetaFile(hdcDraw, mfpict->hMF);
1730 SetWindowExtEx(hdcDraw,
1731 oldWindowExt.cx,
1732 oldWindowExt.cy,
1733 NULL);
1735 SetViewportExtEx(hdcDraw,
1736 oldViewportExt.cx,
1737 oldViewportExt.cy,
1738 NULL);
1740 SetViewportOrgEx(hdcDraw,
1741 oldViewportOrg.x,
1742 oldViewportOrg.y,
1743 NULL);
1745 SetMapMode(hdcDraw, prevMapMode);
1747 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1749 return S_OK;
1751 case CF_DIB:
1753 BITMAPINFO *info;
1754 BYTE *bits;
1756 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1757 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1758 continue;
1760 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
1761 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
1762 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
1763 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
1764 bits, info, DIB_RGB_COLORS, SRCCOPY );
1766 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1767 return S_OK;
1772 WARN("no data could be found to be drawn\n");
1774 return OLE_E_BLANK;
1777 static HRESULT WINAPI DataCache_GetColorSet(
1778 IViewObject2* iface,
1779 DWORD dwDrawAspect,
1780 LONG lindex,
1781 void* pvAspect,
1782 DVTARGETDEVICE* ptd,
1783 HDC hicTargetDevice,
1784 LOGPALETTE** ppColorSet)
1786 FIXME("stub\n");
1787 return E_NOTIMPL;
1790 static HRESULT WINAPI DataCache_Freeze(
1791 IViewObject2* iface,
1792 DWORD dwDrawAspect,
1793 LONG lindex,
1794 void* pvAspect,
1795 DWORD* pdwFreeze)
1797 FIXME("stub\n");
1798 return E_NOTIMPL;
1801 static HRESULT WINAPI DataCache_Unfreeze(
1802 IViewObject2* iface,
1803 DWORD dwFreeze)
1805 FIXME("stub\n");
1806 return E_NOTIMPL;
1809 /************************************************************************
1810 * DataCache_SetAdvise (IViewObject2)
1812 * This sets-up an advisory sink with the data cache. When the object's
1813 * view changes, this sink is called.
1815 static HRESULT WINAPI DataCache_SetAdvise(
1816 IViewObject2* iface,
1817 DWORD aspects,
1818 DWORD advf,
1819 IAdviseSink* pAdvSink)
1821 DataCache *this = impl_from_IViewObject2(iface);
1823 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1826 * A call to this function removes the previous sink
1828 if (this->sinkInterface != NULL)
1830 IAdviseSink_Release(this->sinkInterface);
1831 this->sinkInterface = NULL;
1832 this->sinkAspects = 0;
1833 this->sinkAdviseFlag = 0;
1837 * Now, setup the new one.
1839 if (pAdvSink!=NULL)
1841 this->sinkInterface = pAdvSink;
1842 this->sinkAspects = aspects;
1843 this->sinkAdviseFlag = advf;
1845 IAdviseSink_AddRef(this->sinkInterface);
1849 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1850 * sink immediately.
1852 if (advf & ADVF_PRIMEFIRST)
1854 DataCache_FireOnViewChange(this, aspects, -1);
1857 return S_OK;
1860 /************************************************************************
1861 * DataCache_GetAdvise (IViewObject2)
1863 * This method queries the current state of the advise sink
1864 * installed on the data cache.
1866 static HRESULT WINAPI DataCache_GetAdvise(
1867 IViewObject2* iface,
1868 DWORD* pAspects,
1869 DWORD* pAdvf,
1870 IAdviseSink** ppAdvSink)
1872 DataCache *this = impl_from_IViewObject2(iface);
1874 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1877 * Just copy all the requested values.
1879 if (pAspects!=NULL)
1880 *pAspects = this->sinkAspects;
1882 if (pAdvf!=NULL)
1883 *pAdvf = this->sinkAdviseFlag;
1885 if (ppAdvSink!=NULL)
1887 if (this->sinkInterface != NULL)
1888 IAdviseSink_QueryInterface(this->sinkInterface,
1889 &IID_IAdviseSink,
1890 (void**)ppAdvSink);
1891 else *ppAdvSink = NULL;
1894 return S_OK;
1897 /************************************************************************
1898 * DataCache_GetExtent (IViewObject2)
1900 * This method retrieves the "natural" size of this cached object.
1902 static HRESULT WINAPI DataCache_GetExtent(
1903 IViewObject2* iface,
1904 DWORD dwDrawAspect,
1905 LONG lindex,
1906 DVTARGETDEVICE* ptd,
1907 LPSIZEL lpsizel)
1909 DataCache *This = impl_from_IViewObject2(iface);
1910 HRESULT hres = E_FAIL;
1911 DataCacheEntry *cache_entry;
1913 TRACE("(%p, %x, %d, %p, %p)\n",
1914 iface, dwDrawAspect, lindex, ptd, lpsizel);
1916 if (lpsizel==NULL)
1917 return E_POINTER;
1919 lpsizel->cx = 0;
1920 lpsizel->cy = 0;
1922 if (lindex!=-1)
1923 FIXME("Unimplemented flag lindex = %d\n", lindex);
1926 * Right now, we support only the callback from
1927 * the default handler.
1929 if (ptd!=NULL)
1930 FIXME("Unimplemented ptd = %p\n", ptd);
1932 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1934 /* FIXME: compare ptd too */
1935 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1936 (cache_entry->fmtetc.lindex != lindex))
1937 continue;
1939 /* if the data hasn't been loaded yet, do it now */
1940 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->stream)
1942 hres = DataCacheEntry_LoadData(cache_entry);
1943 if (FAILED(hres))
1944 continue;
1947 /* no data */
1948 if (cache_entry->stgmedium.tymed == TYMED_NULL)
1949 continue;
1952 switch (cache_entry->data_cf)
1954 case CF_METAFILEPICT:
1956 METAFILEPICT *mfpict;
1958 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1959 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1960 continue;
1962 lpsizel->cx = mfpict->xExt;
1963 lpsizel->cy = mfpict->yExt;
1965 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1967 return S_OK;
1969 case CF_DIB:
1971 BITMAPINFOHEADER *info;
1972 LONG x_pels_m, y_pels_m;
1975 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
1976 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
1977 continue;
1979 x_pels_m = info->biXPelsPerMeter;
1980 y_pels_m = info->biYPelsPerMeter;
1982 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
1983 if (x_pels_m != 0 && y_pels_m != 0)
1985 lpsizel->cx = info->biWidth * 100000 / x_pels_m;
1986 lpsizel->cy = info->biHeight * 100000 / y_pels_m;
1988 else
1990 HDC hdc = GetDC( 0 );
1991 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
1992 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
1994 ReleaseDC( 0, hdc );
1997 GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
1999 return S_OK;
2004 WARN("no data could be found to get the extents from\n");
2007 * This method returns OLE_E_BLANK when it fails.
2009 return OLE_E_BLANK;
2013 /*********************************************************
2014 * Method implementation for the IOleCache2
2015 * part of the DataCache class.
2018 /************************************************************************
2019 * DataCache_IOleCache2_QueryInterface (IUnknown)
2021 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2022 IOleCache2* iface,
2023 REFIID riid,
2024 void** ppvObject)
2026 DataCache *this = impl_from_IOleCache2(iface);
2028 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2031 /************************************************************************
2032 * DataCache_IOleCache2_AddRef (IUnknown)
2034 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2035 IOleCache2* iface)
2037 DataCache *this = impl_from_IOleCache2(iface);
2039 return IUnknown_AddRef(this->outer_unk);
2042 /************************************************************************
2043 * DataCache_IOleCache2_Release (IUnknown)
2045 static ULONG WINAPI DataCache_IOleCache2_Release(
2046 IOleCache2* iface)
2048 DataCache *this = impl_from_IOleCache2(iface);
2050 return IUnknown_Release(this->outer_unk);
2053 /*****************************************************************************
2054 * setup_sink
2056 * Set up the sink connection to the running object.
2058 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2060 HRESULT hr = S_FALSE;
2061 DWORD flags;
2063 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2064 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2066 if(This->running_object)
2067 if(!(flags & ADVF_NODATA))
2068 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2069 &This->IAdviseSink_iface, &cache_entry->sink_id);
2070 return hr;
2073 static HRESULT WINAPI DataCache_Cache(
2074 IOleCache2* iface,
2075 FORMATETC* pformatetc,
2076 DWORD advf,
2077 DWORD* pdwConnection)
2079 DataCache *This = impl_from_IOleCache2(iface);
2080 DataCacheEntry *cache_entry;
2081 HRESULT hr;
2083 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2085 if (!pformatetc || !pdwConnection)
2086 return E_INVALIDARG;
2088 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2090 *pdwConnection = 0;
2092 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2093 if (cache_entry)
2095 TRACE("found an existing cache entry\n");
2096 *pdwConnection = cache_entry->id;
2097 return CACHE_S_SAMECACHE;
2100 hr = DataCache_CreateEntry(This, pformatetc, advf, &cache_entry, FALSE);
2102 if (SUCCEEDED(hr))
2104 *pdwConnection = cache_entry->id;
2105 setup_sink(This, cache_entry);
2108 return hr;
2111 static HRESULT WINAPI DataCache_Uncache(
2112 IOleCache2* iface,
2113 DWORD dwConnection)
2115 DataCache *This = impl_from_IOleCache2(iface);
2116 DataCacheEntry *cache_entry;
2118 TRACE("(%d)\n", dwConnection);
2120 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2121 if (cache_entry->id == dwConnection)
2123 DataCacheEntry_Destroy(This, cache_entry);
2124 return S_OK;
2127 WARN("no connection found for %d\n", dwConnection);
2129 return OLE_E_NOCONNECTION;
2132 static HRESULT WINAPI DataCache_EnumCache(
2133 IOleCache2* iface,
2134 IEnumSTATDATA** ppenumSTATDATA)
2136 FIXME("stub\n");
2137 return E_NOTIMPL;
2140 static HRESULT WINAPI DataCache_InitCache(
2141 IOleCache2* iface,
2142 IDataObject* pDataObject)
2144 FIXME("stub\n");
2145 return E_NOTIMPL;
2148 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2149 IOleCache2* iface,
2150 FORMATETC* pformatetc,
2151 STGMEDIUM* pmedium,
2152 BOOL fRelease)
2154 DataCache *This = impl_from_IOleCache2(iface);
2155 DataCacheEntry *cache_entry;
2156 HRESULT hr;
2158 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2159 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2161 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2162 if (cache_entry)
2164 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2166 if (SUCCEEDED(hr))
2167 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2168 cache_entry->fmtetc.lindex);
2170 return hr;
2172 WARN("cache entry not found\n");
2174 return OLE_E_BLANK;
2177 static HRESULT WINAPI DataCache_UpdateCache(
2178 IOleCache2* iface,
2179 LPDATAOBJECT pDataObject,
2180 DWORD grfUpdf,
2181 LPVOID pReserved)
2183 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2184 return E_NOTIMPL;
2187 static HRESULT WINAPI DataCache_DiscardCache(
2188 IOleCache2* iface,
2189 DWORD dwDiscardOptions)
2191 DataCache *This = impl_from_IOleCache2(iface);
2192 DataCacheEntry *cache_entry;
2193 HRESULT hr = S_OK;
2195 TRACE("(%d)\n", dwDiscardOptions);
2197 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2198 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2200 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2202 hr = DataCacheEntry_DiscardData(cache_entry);
2203 if (FAILED(hr))
2204 break;
2207 return hr;
2211 /*********************************************************
2212 * Method implementation for the IOleCacheControl
2213 * part of the DataCache class.
2216 /************************************************************************
2217 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2219 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2220 IOleCacheControl* iface,
2221 REFIID riid,
2222 void** ppvObject)
2224 DataCache *this = impl_from_IOleCacheControl(iface);
2226 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2229 /************************************************************************
2230 * DataCache_IOleCacheControl_AddRef (IUnknown)
2232 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2233 IOleCacheControl* iface)
2235 DataCache *this = impl_from_IOleCacheControl(iface);
2237 return IUnknown_AddRef(this->outer_unk);
2240 /************************************************************************
2241 * DataCache_IOleCacheControl_Release (IUnknown)
2243 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2244 IOleCacheControl* iface)
2246 DataCache *this = impl_from_IOleCacheControl(iface);
2248 return IUnknown_Release(this->outer_unk);
2251 /************************************************************************
2252 * DataCache_OnRun (IOleCacheControl)
2254 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2256 DataCache *This = impl_from_IOleCacheControl(iface);
2257 DataCacheEntry *cache_entry;
2259 TRACE("(%p)->(%p)\n", iface, data_obj);
2261 if(This->running_object) return S_OK;
2263 /* No reference is taken on the data object */
2264 This->running_object = data_obj;
2266 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2268 setup_sink(This, cache_entry);
2271 return S_OK;
2274 /************************************************************************
2275 * DataCache_OnStop (IOleCacheControl)
2277 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2279 DataCache *This = impl_from_IOleCacheControl(iface);
2280 DataCacheEntry *cache_entry;
2282 TRACE("(%p)\n", iface);
2284 if(!This->running_object) return S_OK;
2286 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2288 if(cache_entry->sink_id)
2290 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2291 cache_entry->sink_id = 0;
2295 /* No ref taken in OnRun, so no Release call here */
2296 This->running_object = NULL;
2297 return S_OK;
2300 /************************************************************************
2301 * IAdviseSink methods.
2302 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2303 * give access to the cache's other interfaces. We don't maintain a ref count,
2304 * the object exists as long as the cache is around.
2306 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2308 *obj = NULL;
2309 if (IsEqualIID(&IID_IUnknown, iid) ||
2310 IsEqualIID(&IID_IAdviseSink, iid))
2312 *obj = iface;
2315 if(*obj)
2317 IAdviseSink_AddRef(iface);
2318 return S_OK;
2320 return E_NOINTERFACE;
2323 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2325 return 2;
2328 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2330 return 1;
2333 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2335 DataCache *This = impl_from_IAdviseSink(iface);
2336 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2337 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2340 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2342 FIXME("stub\n");
2345 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2347 FIXME("stub\n");
2350 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2352 FIXME("stub\n");
2355 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2357 FIXME("stub\n");
2361 * Virtual function tables for the DataCache class.
2363 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2365 DataCache_NDIUnknown_QueryInterface,
2366 DataCache_NDIUnknown_AddRef,
2367 DataCache_NDIUnknown_Release
2370 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2372 DataCache_IDataObject_QueryInterface,
2373 DataCache_IDataObject_AddRef,
2374 DataCache_IDataObject_Release,
2375 DataCache_GetData,
2376 DataCache_GetDataHere,
2377 DataCache_QueryGetData,
2378 DataCache_GetCanonicalFormatEtc,
2379 DataCache_IDataObject_SetData,
2380 DataCache_EnumFormatEtc,
2381 DataCache_DAdvise,
2382 DataCache_DUnadvise,
2383 DataCache_EnumDAdvise
2386 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2388 DataCache_IPersistStorage_QueryInterface,
2389 DataCache_IPersistStorage_AddRef,
2390 DataCache_IPersistStorage_Release,
2391 DataCache_GetClassID,
2392 DataCache_IsDirty,
2393 DataCache_InitNew,
2394 DataCache_Load,
2395 DataCache_Save,
2396 DataCache_SaveCompleted,
2397 DataCache_HandsOffStorage
2400 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2402 DataCache_IViewObject2_QueryInterface,
2403 DataCache_IViewObject2_AddRef,
2404 DataCache_IViewObject2_Release,
2405 DataCache_Draw,
2406 DataCache_GetColorSet,
2407 DataCache_Freeze,
2408 DataCache_Unfreeze,
2409 DataCache_SetAdvise,
2410 DataCache_GetAdvise,
2411 DataCache_GetExtent
2414 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2416 DataCache_IOleCache2_QueryInterface,
2417 DataCache_IOleCache2_AddRef,
2418 DataCache_IOleCache2_Release,
2419 DataCache_Cache,
2420 DataCache_Uncache,
2421 DataCache_EnumCache,
2422 DataCache_InitCache,
2423 DataCache_IOleCache2_SetData,
2424 DataCache_UpdateCache,
2425 DataCache_DiscardCache
2428 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2430 DataCache_IOleCacheControl_QueryInterface,
2431 DataCache_IOleCacheControl_AddRef,
2432 DataCache_IOleCacheControl_Release,
2433 DataCache_OnRun,
2434 DataCache_OnStop
2437 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2439 DataCache_IAdviseSink_QueryInterface,
2440 DataCache_IAdviseSink_AddRef,
2441 DataCache_IAdviseSink_Release,
2442 DataCache_OnDataChange,
2443 DataCache_OnViewChange,
2444 DataCache_OnRename,
2445 DataCache_OnSave,
2446 DataCache_OnClose
2449 /*********************************************************
2450 * Method implementation for DataCache class.
2452 static DataCache* DataCache_Construct(
2453 REFCLSID clsid,
2454 LPUNKNOWN pUnkOuter)
2456 DataCache* newObject = 0;
2459 * Allocate space for the object.
2461 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2463 if (newObject==0)
2464 return newObject;
2467 * Initialize the virtual function table.
2469 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2470 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2471 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2472 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2473 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2474 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2475 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2476 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2477 newObject->ref = 1;
2480 * Initialize the other members of the structure.
2482 newObject->sinkAspects = 0;
2483 newObject->sinkAdviseFlag = 0;
2484 newObject->sinkInterface = 0;
2485 newObject->presentationStorage = NULL;
2486 list_init(&newObject->cache_list);
2487 newObject->last_cache_id = 1;
2488 newObject->dirty = FALSE;
2489 newObject->running_object = NULL;
2491 return newObject;
2494 /******************************************************************************
2495 * CreateDataCache [OLE32.@]
2497 * Creates a data cache to allow an object to render one or more of its views,
2498 * whether running or not.
2500 * PARAMS
2501 * pUnkOuter [I] Outer unknown for the object.
2502 * rclsid [I]
2503 * riid [I] IID of interface to return.
2504 * ppvObj [O] Address where the data cache object will be stored on return.
2506 * RETURNS
2507 * Success: S_OK.
2508 * Failure: HRESULT code.
2510 * NOTES
2511 * The following interfaces are supported by the returned data cache object:
2512 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2513 * IViewObject and IViewObject2.
2515 HRESULT WINAPI CreateDataCache(
2516 LPUNKNOWN pUnkOuter,
2517 REFCLSID rclsid,
2518 REFIID riid,
2519 LPVOID* ppvObj)
2521 DataCache* newCache = NULL;
2522 HRESULT hr = S_OK;
2524 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2527 * Sanity check
2529 if (ppvObj==0)
2530 return E_POINTER;
2532 *ppvObj = 0;
2535 * If this cache is constructed for aggregation, make sure
2536 * the caller is requesting the IUnknown interface.
2537 * This is necessary because it's the only time the non-delegating
2538 * IUnknown pointer can be returned to the outside.
2540 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2541 return E_INVALIDARG;
2544 * Try to construct a new instance of the class.
2546 newCache = DataCache_Construct(rclsid,
2547 pUnkOuter);
2549 if (newCache == 0)
2550 return E_OUTOFMEMORY;
2552 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
2553 IUnknown_Release(&newCache->IUnknown_inner);
2555 return hr;