hhctrl.ocx: Make AppendFullPathURL() static.
[wine] / dlls / ole32 / datacache.c
1 /*
2  *      OLE 2 Data cache
3  *
4  *      Copyright 1999  Francis Beaudet
5  *      Copyright 2000  Abey George
6  *
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.
11  *
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.
16  *
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
20  *
21  * NOTES:
22  *    The OLE2 data cache supports a whole whack of
23  *    interfaces including:
24  *       IDataObject, IPersistStorage, IViewObject2,
25  *       IOleCache2 and IOleCacheControl.
26  *
27  *    Most of the implementation details are taken from: Inside OLE
28  *    second edition by Kraig Brockschmidt,
29  *
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.
45  */
46 #include <stdarg.h>
47 #include <string.h>
48
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
52
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"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(ole);
64
65 /****************************************************************************
66  * PresentationDataHeader
67  *
68  * This structure represents the header of the \002OlePresXXX stream in
69  * the OLE object storage.
70  */
71 typedef struct PresentationDataHeader
72 {
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)
80    */
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;
90
91 typedef struct DataCacheEntry
92 {
93   struct list entry;
94   /* format of this entry */
95   FORMATETC fmtetc;
96   /* the clipboard format of the data */
97   CLIPFORMAT data_cf;
98   /* cached data */
99   STGMEDIUM stgmedium;
100   /*
101    * This storage pointer is set through a call to
102    * IPersistStorage_Load. This is where the visual
103    * representation of the object is stored.
104    */
105   IStorage *storage;
106   /* connection ID */
107   DWORD id;
108   /* dirty flag */
109   BOOL dirty;
110   /* stream number (-1 if not set ) */
111   unsigned short stream_number;
112   /* sink id set when object is running */
113   DWORD sink_id;
114   /* Advise sink flags */
115   DWORD advise_flags;
116 } DataCacheEntry;
117
118 /****************************************************************************
119  * DataCache
120  */
121 struct DataCache
122 {
123   /*
124    * List all interface here
125    */
126   IDataObject       IDataObject_iface;
127   IUnknown          IUnknown_iface;
128   IPersistStorage   IPersistStorage_iface;
129   IViewObject2      IViewObject2_iface;
130   IOleCache2        IOleCache2_iface;
131   IOleCacheControl  IOleCacheControl_iface;
132
133   /* The sink that is connected to a remote object.
134      The other interfaces are not available by QI'ing the sink and vice-versa */
135   IAdviseSink       IAdviseSink_iface;
136
137   /*
138    * Reference count of this object
139    */
140   LONG ref;
141
142   /*
143    * IUnknown implementation of the outer object.
144    */
145   IUnknown* outerUnknown;
146
147   /*
148    * The user of this object can setup ONE advise sink
149    * connection with the object. These parameters describe
150    * that connection.
151    */
152   DWORD        sinkAspects;
153   DWORD        sinkAdviseFlag;
154   IAdviseSink* sinkInterface;
155   IStorage *presentationStorage;
156
157   /* list of cache entries */
158   struct list cache_list;
159   /* last id assigned to an entry */
160   DWORD last_cache_id;
161   /* dirty flag */
162   BOOL dirty;
163   /* running object set by OnRun */
164   IDataObject *running_object;
165 };
166
167 typedef struct DataCache DataCache;
168
169 /*
170  * Here, I define utility macros to help with the casting of the
171  * "this" parameter.
172  * There is a version to accommodate all of the VTables implemented
173  * by this object.
174  */
175
176 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
177 {
178     return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
179 }
180
181 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
182 {
183     return CONTAINING_RECORD(iface, DataCache, IUnknown_iface);
184 }
185
186 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
187 {
188     return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
189 }
190
191 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
192 {
193     return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
194 }
195
196 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
197 {
198     return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
199 }
200
201 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
202 {
203     return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
204 }
205
206 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
207 {
208     return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
209 }
210
211 static const char * debugstr_formatetc(const FORMATETC *formatetc)
212 {
213     return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
214         formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
215         formatetc->lindex, formatetc->tymed);
216 }
217
218 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
219 {
220     list_remove(&cache_entry->entry);
221     if (cache_entry->storage)
222         IStorage_Release(cache_entry->storage);
223     HeapFree(GetProcessHeap(), 0, cache_entry->fmtetc.ptd);
224     ReleaseStgMedium(&cache_entry->stgmedium);
225     if(cache_entry->sink_id)
226         IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
227
228     HeapFree(GetProcessHeap(), 0, cache_entry);
229 }
230
231 static void DataCache_Destroy(
232   DataCache* ptrToDestroy)
233 {
234   DataCacheEntry *cache_entry, *next_cache_entry;
235
236   TRACE("()\n");
237
238   if (ptrToDestroy->sinkInterface != NULL)
239   {
240     IAdviseSink_Release(ptrToDestroy->sinkInterface);
241     ptrToDestroy->sinkInterface = NULL;
242   }
243
244   LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
245     DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
246
247   if (ptrToDestroy->presentationStorage != NULL)
248   {
249     IStorage_Release(ptrToDestroy->presentationStorage);
250     ptrToDestroy->presentationStorage = NULL;
251   }
252
253   /*
254    * Free the datacache pointer.
255    */
256   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
257 }
258
259 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
260 {
261     DataCacheEntry *cache_entry;
262     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
263     {
264         /* FIXME: also compare DVTARGETDEVICEs */
265         if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
266             (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
267             (formatetc->lindex == cache_entry->fmtetc.lindex) &&
268             (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
269             return cache_entry;
270     }
271     return NULL;
272 }
273
274 /* checks that the clipformat and tymed are valid and returns an error if they
275 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
276 * DataCache_Draw */
277 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
278 {
279     if (!cfFormat || !tymed ||
280         (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
281         (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
282         (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
283         (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
284         return S_OK;
285     else if (tymed == TYMED_HGLOBAL)
286         return CACHE_S_FORMATETC_NOTSUPPORTED;
287     else
288     {
289         WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
290         return DV_E_TYMED;
291     }
292 }
293
294 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
295 {
296     HRESULT hr;
297
298     hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
299     if (FAILED(hr))
300         return hr;
301     if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
302         TRACE("creating unsupported format %d\n", formatetc->cfFormat);
303
304     *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
305     if (!*cache_entry)
306         return E_OUTOFMEMORY;
307
308     (*cache_entry)->fmtetc = *formatetc;
309     if (formatetc->ptd)
310     {
311         (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
312         memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
313     }
314     (*cache_entry)->data_cf = 0;
315     (*cache_entry)->stgmedium.tymed = TYMED_NULL;
316     (*cache_entry)->stgmedium.pUnkForRelease = NULL;
317     (*cache_entry)->storage = NULL;
318     (*cache_entry)->id = This->last_cache_id++;
319     (*cache_entry)->dirty = TRUE;
320     (*cache_entry)->stream_number = -1;
321     (*cache_entry)->sink_id = 0;
322     (*cache_entry)->advise_flags = 0;
323     list_add_tail(&This->cache_list, &(*cache_entry)->entry);
324     return hr;
325 }
326
327 /************************************************************************
328  * DataCache_FireOnViewChange
329  *
330  * This method will fire an OnViewChange notification to the advise
331  * sink registered with the datacache.
332  *
333  * See IAdviseSink::OnViewChange for more details.
334  */
335 static void DataCache_FireOnViewChange(
336   DataCache* this,
337   DWORD      aspect,
338   LONG       lindex)
339 {
340   TRACE("(%p, %x, %d)\n", this, aspect, lindex);
341
342   /*
343    * The sink supplies a filter when it registers
344    * we make sure we only send the notifications when that
345    * filter matches.
346    */
347   if ((this->sinkAspects & aspect) != 0)
348   {
349     if (this->sinkInterface != NULL)
350     {
351       IAdviseSink_OnViewChange(this->sinkInterface,
352                                aspect,
353                                lindex);
354
355       /*
356        * Some sinks want to be unregistered automatically when
357        * the first notification goes out.
358        */
359       if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
360       {
361         IAdviseSink_Release(this->sinkInterface);
362
363         this->sinkInterface  = NULL;
364         this->sinkAspects    = 0;
365         this->sinkAdviseFlag = 0;
366       }
367     }
368   }
369 }
370
371 /* Helper for DataCacheEntry_OpenPresStream */
372 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
373 {
374     /* The presentation streams have names of the form "\002OlePresXXX",
375      * where XXX goes from 000 to 999. */
376     static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
377
378     LPCWSTR name = elem->pwcsName;
379
380     return (elem->type == STGTY_STREAM)
381         && (strlenW(name) == 11)
382         && (strncmpW(name, OlePres, 8) == 0)
383         && (name[8] >= '0') && (name[8] <= '9')
384         && (name[9] >= '0') && (name[9] <= '9')
385         && (name[10] >= '0') && (name[10] <= '9');
386 }
387
388 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
389 {
390     DWORD length;
391     HRESULT hr;
392     ULONG read;
393
394     *clipformat = 0;
395
396     hr = IStream_Read(stream, &length, sizeof(length), &read);
397     if (hr != S_OK || read != sizeof(length))
398         return DV_E_CLIPFORMAT;
399     if (length == -1)
400     {
401         DWORD cf;
402         hr = IStream_Read(stream, &cf, sizeof(cf), 0);
403         if (hr != S_OK || read != sizeof(cf))
404             return DV_E_CLIPFORMAT;
405         *clipformat = cf;
406     }
407     else
408     {
409         char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
410         if (!format_name)
411             return E_OUTOFMEMORY;
412         hr = IStream_Read(stream, format_name, length, &read);
413         if (hr != S_OK || read != length || format_name[length - 1] != '\0')
414         {
415             HeapFree(GetProcessHeap(), 0, format_name);
416             return DV_E_CLIPFORMAT;
417         }
418         *clipformat = RegisterClipboardFormatA(format_name);
419         HeapFree(GetProcessHeap(), 0, format_name);
420     }
421     return S_OK;
422 }
423
424 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
425 {
426     DWORD length;
427     HRESULT hr;
428
429     if (clipformat < 0xc000)
430         length = -1;
431     else
432         length = GetClipboardFormatNameA(clipformat, NULL, 0);
433     hr = IStream_Write(stream, &length, sizeof(length), NULL);
434     if (FAILED(hr))
435         return hr;
436     if (clipformat < 0xc000)
437     {
438         DWORD cf = clipformat;
439         hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
440     }
441     else
442     {
443         char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
444         if (!format_name)
445             return E_OUTOFMEMORY;
446         GetClipboardFormatNameA(clipformat, format_name, length);
447         hr = IStream_Write(stream, format_name, length, NULL);
448         HeapFree(GetProcessHeap(), 0, format_name);
449     }
450     return hr;
451 }
452
453 /************************************************************************
454  * DataCacheEntry_OpenPresStream
455  *
456  * This method will find the stream for the given presentation. It makes
457  * no attempt at fallback.
458  *
459  * Param:
460  *   this       - Pointer to the DataCache object
461  *   drawAspect - The aspect of the object that we wish to draw.
462  *   pStm       - A returned stream. It points to the beginning of the
463  *              - presentation data, including the header.
464  *
465  * Errors:
466  *   S_OK               The requested stream has been opened.
467  *   OLE_E_BLANK        The requested stream could not be found.
468  *   Quite a few others I'm too lazy to map correctly.
469  *
470  * Notes:
471  *   Algorithm: Scan the elements of the presentation storage, looking
472  *              for presentation streams. For each presentation stream,
473  *              load the header and check to see if the aspect matches.
474  *
475  *   If a fallback is desired, just opening the first presentation stream
476  *   is a possibility.
477  */
478 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
479 {
480     STATSTG elem;
481     IEnumSTATSTG *pEnum;
482     HRESULT hr;
483
484     if (!ppStm) return E_POINTER;
485
486     hr = IStorage_EnumElements(cache_entry->storage, 0, NULL, 0, &pEnum);
487     if (FAILED(hr)) return hr;
488
489     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
490     {
491         if (DataCache_IsPresentationStream(&elem))
492         {
493             IStream *pStm;
494
495             hr = IStorage_OpenStream(cache_entry->storage, elem.pwcsName,
496                                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
497                                      &pStm);
498             if (SUCCEEDED(hr))
499             {
500                 PresentationDataHeader header;
501                 ULONG actual_read;
502                 CLIPFORMAT clipformat;
503
504                 hr = read_clipformat(pStm, &clipformat);
505
506                 if (hr == S_OK)
507                     hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
508
509                 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
510                 if (hr == S_OK && actual_read == sizeof(header)
511                     && header.dvAspect == cache_entry->fmtetc.dwAspect)
512                 {
513                     /* Rewind the stream before returning it. */
514                     LARGE_INTEGER offset;
515                     offset.u.LowPart = 0;
516                     offset.u.HighPart = 0;
517                     IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
518
519                     *ppStm = pStm;
520
521                     CoTaskMemFree(elem.pwcsName);
522                     IEnumSTATSTG_Release(pEnum);
523
524                     return S_OK;
525                 }
526
527                 IStream_Release(pStm);
528             }
529         }
530
531         CoTaskMemFree(elem.pwcsName);
532     }
533
534     IEnumSTATSTG_Release(pEnum);
535
536     return (hr == S_FALSE ? OLE_E_BLANK : hr);
537 }
538
539 /************************************************************************
540  * DataCacheEntry_LoadData
541  *
542  * This method will read information for the requested presentation
543  * into the given structure.
544  *
545  * Param:
546  *   This - The entry to load the data from.
547  *
548  * Returns:
549  *   This method returns a metafile handle if it is successful.
550  *   it will return 0 if not.
551  */
552 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
553 {
554   IStream*      presStream = NULL;
555   HRESULT       hres;
556   ULARGE_INTEGER current_pos;
557   STATSTG       streamInfo;
558   void*         metafileBits;
559   METAFILEPICT *mfpict;
560   HGLOBAL       hmfpict;
561   PresentationDataHeader header;
562   CLIPFORMAT    clipformat;
563   static const LARGE_INTEGER offset_zero;
564
565   /*
566    * Open the presentation stream.
567    */
568   hres = DataCacheEntry_OpenPresStream(cache_entry, &presStream);
569
570   if (FAILED(hres))
571     return hres;
572
573   /*
574    * Get the size of the stream.
575    */
576   hres = IStream_Stat(presStream,
577                       &streamInfo,
578                       STATFLAG_NONAME);
579
580   /*
581    * Read the header.
582    */
583
584   hres = read_clipformat(presStream, &clipformat);
585   if (FAILED(hres))
586   {
587       IStream_Release(presStream);
588       return hres;
589   }
590
591   hres = IStream_Read(
592                       presStream,
593                       &header,
594                       sizeof(PresentationDataHeader),
595                       NULL);
596   if (hres != S_OK)
597   {
598       IStream_Release(presStream);
599       return E_FAIL;
600   }
601
602   hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, &current_pos);
603
604   streamInfo.cbSize.QuadPart -= current_pos.QuadPart;
605
606   hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
607   if (!hmfpict)
608   {
609       IStream_Release(presStream);
610       return E_OUTOFMEMORY;
611   }
612   mfpict = GlobalLock(hmfpict);
613
614   /*
615    * Allocate a buffer for the metafile bits.
616    */
617   metafileBits = HeapAlloc(GetProcessHeap(),
618                            0,
619                            streamInfo.cbSize.u.LowPart);
620
621   /*
622    * Read the metafile bits.
623    */
624   hres = IStream_Read(
625            presStream,
626            metafileBits,
627            streamInfo.cbSize.u.LowPart,
628            NULL);
629
630   /*
631    * Create a metafile with those bits.
632    */
633   if (SUCCEEDED(hres))
634   {
635     /* FIXME: get this from the stream */
636     mfpict->mm = MM_ANISOTROPIC;
637     mfpict->xExt = header.dwObjectExtentX;
638     mfpict->yExt = header.dwObjectExtentY;
639     mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
640     if (!mfpict->hMF)
641       hres = E_FAIL;
642   }
643
644   GlobalUnlock(hmfpict);
645   if (SUCCEEDED(hres))
646   {
647     cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
648     cache_entry->stgmedium.tymed = TYMED_MFPICT;
649     cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
650   }
651   else
652     GlobalFree(hmfpict);
653
654   /*
655    * Cleanup.
656    */
657   HeapFree(GetProcessHeap(), 0, metafileBits);
658   IStream_Release(presStream);
659
660   return hres;
661 }
662
663 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
664                                            IStorage *storage, IStream **stream)
665 {
666     WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
667         '0' + (cache_entry->stream_number / 100) % 10,
668         '0' + (cache_entry->stream_number / 10) % 10,
669         '0' + cache_entry->stream_number % 10, 0};
670
671     /* FIXME: cache the created stream in This? */
672     return IStorage_CreateStream(storage, wszName,
673                                  STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
674                                  0, 0, stream);
675 }
676
677 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
678                                    BOOL same_as_load)
679 {
680     PresentationDataHeader header;
681     HRESULT hr;
682     IStream *pres_stream;
683     void *data = NULL;
684
685     TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
686
687     hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
688     if (FAILED(hr))
689         return hr;
690
691     hr = write_clipformat(pres_stream, cache_entry->data_cf);
692     if (FAILED(hr))
693         return hr;
694
695     if (cache_entry->fmtetc.ptd)
696         FIXME("ptd not serialized\n");
697     header.unknown3 = 4;
698     header.dvAspect = cache_entry->fmtetc.dwAspect;
699     header.lindex = cache_entry->fmtetc.lindex;
700     header.tymed = cache_entry->stgmedium.tymed;
701     header.unknown7 = 0;
702     header.dwObjectExtentX = 0;
703     header.dwObjectExtentY = 0;
704     header.dwSize = 0;
705
706     /* size the data */
707     switch (cache_entry->data_cf)
708     {
709         case CF_METAFILEPICT:
710         {
711             if (cache_entry->stgmedium.tymed != TYMED_NULL)
712             {
713                 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
714                 if (!mfpict)
715                 {
716                     IStream_Release(pres_stream);
717                     return DV_E_STGMEDIUM;
718                 }
719                 header.dwObjectExtentX = mfpict->xExt;
720                 header.dwObjectExtentY = mfpict->yExt;
721                 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
722                 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
723             }
724             break;
725         }
726         default:
727             break;
728     }
729
730     /*
731      * Write the header.
732      */
733     hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
734                        NULL);
735     if (FAILED(hr))
736     {
737         IStream_Release(pres_stream);
738         return hr;
739     }
740
741     /* get the data */
742     switch (cache_entry->data_cf)
743     {
744         case CF_METAFILEPICT:
745         {
746             if (cache_entry->stgmedium.tymed != TYMED_NULL)
747             {
748                 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
749                 if (!mfpict)
750                 {
751                     IStream_Release(pres_stream);
752                     return DV_E_STGMEDIUM;
753                 }
754                 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
755                 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
756                 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
757             }
758             break;
759         }
760         default:
761             break;
762     }
763
764     if (data)
765         hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
766     HeapFree(GetProcessHeap(), 0, data);
767
768     IStream_Release(pres_stream);
769     return hr;
770 }
771
772 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
773 * does no checking of whether src_stgm has a supported tymed, so this should be
774 * done in the caller */
775 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
776                                const STGMEDIUM *src_stgm)
777 {
778     if (src_stgm->tymed == TYMED_MFPICT)
779     {
780         const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
781         METAFILEPICT *dest_mfpict;
782
783         if (!src_mfpict)
784             return DV_E_STGMEDIUM;
785         dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
786         dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
787         if (!dest_mfpict)
788         {
789             GlobalUnlock(src_stgm->u.hMetaFilePict);
790             return E_OUTOFMEMORY;
791         }
792         *dest_mfpict = *src_mfpict;
793         dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
794         GlobalUnlock(src_stgm->u.hMetaFilePict);
795         GlobalUnlock(dest_stgm->u.hMetaFilePict);
796     }
797     else if (src_stgm->tymed != TYMED_NULL)
798     {
799         dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
800                                                 GMEM_MOVEABLE);
801         if (!dest_stgm->u.hGlobal)
802             return E_OUTOFMEMORY;
803     }
804     dest_stgm->tymed = src_stgm->tymed;
805     dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
806     if (dest_stgm->pUnkForRelease)
807         IUnknown_AddRef(dest_stgm->pUnkForRelease);
808     return S_OK;
809 }
810
811 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
812                                       const FORMATETC *formatetc,
813                                       const STGMEDIUM *stgmedium,
814                                       BOOL fRelease)
815 {
816     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
817         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
818         stgmedium->tymed == TYMED_NULL)
819     {
820         WARN("invalid formatetc\n");
821         return DV_E_FORMATETC;
822     }
823
824     cache_entry->dirty = TRUE;
825     ReleaseStgMedium(&cache_entry->stgmedium);
826     cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
827     if (fRelease)
828     {
829         cache_entry->stgmedium = *stgmedium;
830         return S_OK;
831     }
832     else
833         return copy_stg_medium(cache_entry->data_cf,
834                                &cache_entry->stgmedium, stgmedium);
835 }
836
837 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
838 {
839     if (stgmedium->tymed == TYMED_NULL && cache_entry->storage)
840     {
841         HRESULT hr = DataCacheEntry_LoadData(cache_entry);
842         if (FAILED(hr))
843             return hr;
844     }
845     if (cache_entry->stgmedium.tymed == TYMED_NULL)
846         return OLE_E_BLANK;
847     return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
848 }
849
850 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
851 {
852     ReleaseStgMedium(&cache_entry->stgmedium);
853     cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
854     return S_OK;
855 }
856
857 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
858 {
859     if (cache_entry->storage)
860     {
861         IStorage_Release(cache_entry->storage);
862         cache_entry->storage = NULL;
863     }
864 }
865
866 /*********************************************************
867  * Method implementation for the  non delegating IUnknown
868  * part of the DataCache class.
869  */
870
871 /************************************************************************
872  * DataCache_NDIUnknown_QueryInterface (IUnknown)
873  *
874  * This version of QueryInterface will not delegate its implementation
875  * to the outer unknown.
876  */
877 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
878             IUnknown*      iface,
879             REFIID         riid,
880             void**         ppvObject)
881 {
882   DataCache *this = impl_from_IUnknown(iface);
883
884   if ( ppvObject==0 )
885     return E_INVALIDARG;
886
887   *ppvObject = 0;
888
889   if (IsEqualIID(&IID_IUnknown, riid))
890   {
891     *ppvObject = iface;
892   }
893   else if (IsEqualIID(&IID_IDataObject, riid))
894   {
895     *ppvObject = &this->IDataObject_iface;
896   }
897   else if ( IsEqualIID(&IID_IPersistStorage, riid)  ||
898             IsEqualIID(&IID_IPersist, riid) )
899   {
900     *ppvObject = &this->IPersistStorage_iface;
901   }
902   else if ( IsEqualIID(&IID_IViewObject, riid) ||
903             IsEqualIID(&IID_IViewObject2, riid) )
904   {
905     *ppvObject = &this->IViewObject2_iface;
906   }
907   else if ( IsEqualIID(&IID_IOleCache, riid) ||
908             IsEqualIID(&IID_IOleCache2, riid) )
909   {
910     *ppvObject = &this->IOleCache2_iface;
911   }
912   else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
913   {
914     *ppvObject = &this->IOleCacheControl_iface;
915   }
916
917   if ((*ppvObject)==0)
918   {
919     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
920     return E_NOINTERFACE;
921   }
922
923   IUnknown_AddRef((IUnknown*)*ppvObject);
924
925   return S_OK;
926 }
927
928 /************************************************************************
929  * DataCache_NDIUnknown_AddRef (IUnknown)
930  *
931  * This version of QueryInterface will not delegate its implementation
932  * to the outer unknown.
933  */
934 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
935             IUnknown*      iface)
936 {
937   DataCache *this = impl_from_IUnknown(iface);
938   return InterlockedIncrement(&this->ref);
939 }
940
941 /************************************************************************
942  * DataCache_NDIUnknown_Release (IUnknown)
943  *
944  * This version of QueryInterface will not delegate its implementation
945  * to the outer unknown.
946  */
947 static ULONG WINAPI DataCache_NDIUnknown_Release(
948             IUnknown*      iface)
949 {
950   DataCache *this = impl_from_IUnknown(iface);
951   ULONG ref;
952
953   ref = InterlockedDecrement(&this->ref);
954
955   if (ref == 0) DataCache_Destroy(this);
956
957   return ref;
958 }
959
960 /*********************************************************
961  * Method implementation for the IDataObject
962  * part of the DataCache class.
963  */
964
965 /************************************************************************
966  * DataCache_IDataObject_QueryInterface (IUnknown)
967  */
968 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
969             IDataObject*     iface,
970             REFIID           riid,
971             void**           ppvObject)
972 {
973   DataCache *this = impl_from_IDataObject(iface);
974
975   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
976 }
977
978 /************************************************************************
979  * DataCache_IDataObject_AddRef (IUnknown)
980  */
981 static ULONG WINAPI DataCache_IDataObject_AddRef(
982             IDataObject*     iface)
983 {
984   DataCache *this = impl_from_IDataObject(iface);
985
986   return IUnknown_AddRef(this->outerUnknown);
987 }
988
989 /************************************************************************
990  * DataCache_IDataObject_Release (IUnknown)
991  */
992 static ULONG WINAPI DataCache_IDataObject_Release(
993             IDataObject*     iface)
994 {
995   DataCache *this = impl_from_IDataObject(iface);
996
997   return IUnknown_Release(this->outerUnknown);
998 }
999
1000 /************************************************************************
1001  * DataCache_GetData
1002  *
1003  * Get Data from a source dataobject using format pformatetcIn->cfFormat
1004  */
1005 static HRESULT WINAPI DataCache_GetData(
1006             IDataObject*     iface,
1007             LPFORMATETC      pformatetcIn,
1008             STGMEDIUM*       pmedium)
1009 {
1010     DataCache *This = impl_from_IDataObject(iface);
1011     DataCacheEntry *cache_entry;
1012
1013     memset(pmedium, 0, sizeof(*pmedium));
1014
1015     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1016     if (!cache_entry)
1017         return OLE_E_BLANK;
1018
1019     return DataCacheEntry_GetData(cache_entry, pmedium);
1020 }
1021
1022 static HRESULT WINAPI DataCache_GetDataHere(
1023             IDataObject*     iface,
1024             LPFORMATETC      pformatetc,
1025             STGMEDIUM*       pmedium)
1026 {
1027   FIXME("stub\n");
1028   return E_NOTIMPL;
1029 }
1030
1031 static HRESULT WINAPI DataCache_QueryGetData(
1032             IDataObject*     iface,
1033             LPFORMATETC      pformatetc)
1034 {
1035   FIXME("stub\n");
1036   return E_NOTIMPL;
1037 }
1038
1039 /************************************************************************
1040  * DataCache_EnumFormatEtc (IDataObject)
1041  *
1042  * The data cache doesn't implement this method.
1043  */
1044 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1045             IDataObject*     iface,
1046             LPFORMATETC      pformatectIn,
1047             LPFORMATETC      pformatetcOut)
1048 {
1049   TRACE("()\n");
1050   return E_NOTIMPL;
1051 }
1052
1053 /************************************************************************
1054  * DataCache_IDataObject_SetData (IDataObject)
1055  *
1056  * This method is delegated to the IOleCache2 implementation.
1057  */
1058 static HRESULT WINAPI DataCache_IDataObject_SetData(
1059             IDataObject*     iface,
1060             LPFORMATETC      pformatetc,
1061             STGMEDIUM*       pmedium,
1062             BOOL             fRelease)
1063 {
1064   IOleCache2* oleCache = NULL;
1065   HRESULT     hres;
1066
1067   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1068
1069   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1070
1071   if (FAILED(hres))
1072     return E_UNEXPECTED;
1073
1074   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1075
1076   IOleCache2_Release(oleCache);
1077
1078   return hres;
1079 }
1080
1081 /************************************************************************
1082  * DataCache_EnumFormatEtc (IDataObject)
1083  *
1084  * The data cache doesn't implement this method.
1085  */
1086 static HRESULT WINAPI DataCache_EnumFormatEtc(
1087             IDataObject*     iface,
1088             DWORD            dwDirection,
1089             IEnumFORMATETC** ppenumFormatEtc)
1090 {
1091   TRACE("()\n");
1092   return E_NOTIMPL;
1093 }
1094
1095 /************************************************************************
1096  * DataCache_DAdvise (IDataObject)
1097  *
1098  * The data cache doesn't support connections.
1099  */
1100 static HRESULT WINAPI DataCache_DAdvise(
1101             IDataObject*     iface,
1102             FORMATETC*       pformatetc,
1103             DWORD            advf,
1104             IAdviseSink*     pAdvSink,
1105             DWORD*           pdwConnection)
1106 {
1107   TRACE("()\n");
1108   return OLE_E_ADVISENOTSUPPORTED;
1109 }
1110
1111 /************************************************************************
1112  * DataCache_DUnadvise (IDataObject)
1113  *
1114  * The data cache doesn't support connections.
1115  */
1116 static HRESULT WINAPI DataCache_DUnadvise(
1117             IDataObject*     iface,
1118             DWORD            dwConnection)
1119 {
1120   TRACE("()\n");
1121   return OLE_E_NOCONNECTION;
1122 }
1123
1124 /************************************************************************
1125  * DataCache_EnumDAdvise (IDataObject)
1126  *
1127  * The data cache doesn't support connections.
1128  */
1129 static HRESULT WINAPI DataCache_EnumDAdvise(
1130             IDataObject*     iface,
1131             IEnumSTATDATA**  ppenumAdvise)
1132 {
1133   TRACE("()\n");
1134   return OLE_E_ADVISENOTSUPPORTED;
1135 }
1136
1137 /*********************************************************
1138  * Method implementation for the IDataObject
1139  * part of the DataCache class.
1140  */
1141
1142 /************************************************************************
1143  * DataCache_IPersistStorage_QueryInterface (IUnknown)
1144  */
1145 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1146             IPersistStorage* iface,
1147             REFIID           riid,
1148             void**           ppvObject)
1149 {
1150   DataCache *this = impl_from_IPersistStorage(iface);
1151
1152   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1153 }
1154
1155 /************************************************************************
1156  * DataCache_IPersistStorage_AddRef (IUnknown)
1157  */
1158 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1159             IPersistStorage* iface)
1160 {
1161   DataCache *this = impl_from_IPersistStorage(iface);
1162
1163   return IUnknown_AddRef(this->outerUnknown);
1164 }
1165
1166 /************************************************************************
1167  * DataCache_IPersistStorage_Release (IUnknown)
1168  */
1169 static ULONG WINAPI DataCache_IPersistStorage_Release(
1170             IPersistStorage* iface)
1171 {
1172   DataCache *this = impl_from_IPersistStorage(iface);
1173
1174   return IUnknown_Release(this->outerUnknown);
1175 }
1176
1177 /************************************************************************
1178  * DataCache_GetClassID (IPersistStorage)
1179  *
1180  * The data cache doesn't implement this method.
1181  */
1182 static HRESULT WINAPI DataCache_GetClassID(
1183             IPersistStorage* iface,
1184             CLSID*           pClassID)
1185 {
1186   DataCache *This = impl_from_IPersistStorage(iface);
1187   DataCacheEntry *cache_entry;
1188
1189   TRACE("(%p, %p)\n", iface, pClassID);
1190
1191   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1192   {
1193     if (cache_entry->storage != NULL)
1194     {
1195       STATSTG statstg;
1196       HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1197       if (SUCCEEDED(hr))
1198       {
1199         *pClassID = statstg.clsid;
1200         return S_OK;
1201       }
1202     }
1203   }
1204
1205   *pClassID = CLSID_NULL;
1206
1207   return S_OK;
1208 }
1209
1210 /************************************************************************
1211  * DataCache_IsDirty (IPersistStorage)
1212  */
1213 static HRESULT WINAPI DataCache_IsDirty(
1214             IPersistStorage* iface)
1215 {
1216     DataCache *This = impl_from_IPersistStorage(iface);
1217     DataCacheEntry *cache_entry;
1218
1219     TRACE("(%p)\n", iface);
1220
1221     if (This->dirty)
1222         return S_OK;
1223
1224     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1225         if (cache_entry->dirty)
1226             return S_OK;
1227
1228     return S_FALSE;
1229 }
1230
1231 /************************************************************************
1232  * DataCache_InitNew (IPersistStorage)
1233  *
1234  * The data cache implementation of IPersistStorage_InitNew simply stores
1235  * the storage pointer.
1236  */
1237 static HRESULT WINAPI DataCache_InitNew(
1238             IPersistStorage* iface,
1239             IStorage*        pStg)
1240 {
1241     DataCache *This = impl_from_IPersistStorage(iface);
1242
1243     TRACE("(%p, %p)\n", iface, pStg);
1244
1245     if (This->presentationStorage != NULL)
1246         IStorage_Release(This->presentationStorage);
1247
1248     This->presentationStorage = pStg;
1249
1250     IStorage_AddRef(This->presentationStorage);
1251     This->dirty = TRUE;
1252
1253     return S_OK;
1254 }
1255
1256 /************************************************************************
1257  * DataCache_Load (IPersistStorage)
1258  *
1259  * The data cache implementation of IPersistStorage_Load doesn't
1260  * actually load anything. Instead, it holds on to the storage pointer
1261  * and it will load the presentation information when the
1262  * IDataObject_GetData or IViewObject2_Draw methods are called.
1263  */
1264 static HRESULT WINAPI DataCache_Load(
1265             IPersistStorage* iface,
1266             IStorage*        pStg)
1267 {
1268     DataCache *This = impl_from_IPersistStorage(iface);
1269     STATSTG elem;
1270     IEnumSTATSTG *pEnum;
1271     HRESULT hr;
1272
1273     TRACE("(%p, %p)\n", iface, pStg);
1274
1275     if (This->presentationStorage != NULL)
1276       IStorage_Release(This->presentationStorage);
1277
1278     This->presentationStorage = pStg;
1279
1280     hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1281     if (FAILED(hr)) return hr;
1282
1283     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1284     {
1285         if (DataCache_IsPresentationStream(&elem))
1286         {
1287             IStream *pStm;
1288
1289             hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1290                                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1291                                      &pStm);
1292             if (SUCCEEDED(hr))
1293             {
1294                 PresentationDataHeader header;
1295                 ULONG actual_read;
1296                 CLIPFORMAT clipformat;
1297
1298                 hr = read_clipformat(pStm, &clipformat);
1299
1300                 if (hr == S_OK)
1301                     hr = IStream_Read(pStm, &header, sizeof(header),
1302                                       &actual_read);
1303
1304                 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1305                 if (hr == S_OK && actual_read == sizeof(header))
1306                 {
1307                     DataCacheEntry *cache_entry;
1308                     FORMATETC fmtetc;
1309
1310                     fmtetc.cfFormat = clipformat;
1311                     fmtetc.ptd = NULL; /* FIXME */
1312                     fmtetc.dwAspect = header.dvAspect;
1313                     fmtetc.lindex = header.lindex;
1314                     fmtetc.tymed = header.tymed;
1315
1316                     TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1317
1318                     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1319                     if (!cache_entry)
1320                         hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1321                     if (SUCCEEDED(hr))
1322                     {
1323                         DataCacheEntry_DiscardData(cache_entry);
1324                         if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1325                         cache_entry->storage = pStg;
1326                         IStorage_AddRef(pStg);
1327                         cache_entry->dirty = FALSE;
1328                     }
1329                 }
1330
1331                 IStream_Release(pStm);
1332             }
1333         }
1334
1335         CoTaskMemFree(elem.pwcsName);
1336     }
1337
1338     This->dirty = FALSE;
1339
1340     IEnumSTATSTG_Release(pEnum);
1341
1342     IStorage_AddRef(This->presentationStorage);
1343     return S_OK;
1344 }
1345
1346 /************************************************************************
1347  * DataCache_Save (IPersistStorage)
1348  *
1349  * Until we actually connect to a running object and retrieve new
1350  * information to it, we never have to save anything. However, it is
1351  * our responsibility to copy the information when saving to a new
1352  * storage.
1353  */
1354 static HRESULT WINAPI DataCache_Save(
1355             IPersistStorage* iface,
1356             IStorage*        pStg,
1357             BOOL             fSameAsLoad)
1358 {
1359     DataCache *This = impl_from_IPersistStorage(iface);
1360     DataCacheEntry *cache_entry;
1361     BOOL dirty = FALSE;
1362     HRESULT hr = S_OK;
1363     unsigned short stream_number = 0;
1364
1365     TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1366
1367     dirty = This->dirty;
1368     if (!dirty)
1369     {
1370         LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1371         {
1372             dirty = cache_entry->dirty;
1373             if (dirty)
1374                 break;
1375         }
1376     }
1377
1378     /* this is a shortcut if nothing changed */
1379     if (!dirty && !fSameAsLoad && This->presentationStorage)
1380     {
1381         return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1382     }
1383
1384     /* assign stream numbers to the cache entries */
1385     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1386     {
1387         if (cache_entry->stream_number != stream_number)
1388         {
1389             cache_entry->dirty = TRUE; /* needs to be written out again */
1390             cache_entry->stream_number = stream_number;
1391         }
1392         stream_number++;
1393     }
1394
1395     /* write out the cache entries */
1396     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1397     {
1398         if (!fSameAsLoad || cache_entry->dirty)
1399         {
1400             hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1401             if (FAILED(hr))
1402                 break;
1403
1404             cache_entry->dirty = FALSE;
1405         }
1406     }
1407
1408     This->dirty = FALSE;
1409     return hr;
1410 }
1411
1412 /************************************************************************
1413  * DataCache_SaveCompleted (IPersistStorage)
1414  *
1415  * This method is called to tell the cache to release the storage
1416  * pointer it's currently holding.
1417  */
1418 static HRESULT WINAPI DataCache_SaveCompleted(
1419             IPersistStorage* iface,
1420             IStorage*        pStgNew)
1421 {
1422   TRACE("(%p, %p)\n", iface, pStgNew);
1423
1424   if (pStgNew)
1425   {
1426     IPersistStorage_HandsOffStorage(iface);
1427
1428     DataCache_Load(iface, pStgNew);
1429   }
1430
1431   return S_OK;
1432 }
1433
1434 /************************************************************************
1435  * DataCache_HandsOffStorage (IPersistStorage)
1436  *
1437  * This method is called to tell the cache to release the storage
1438  * pointer it's currently holding.
1439  */
1440 static HRESULT WINAPI DataCache_HandsOffStorage(
1441             IPersistStorage* iface)
1442 {
1443   DataCache *this = impl_from_IPersistStorage(iface);
1444   DataCacheEntry *cache_entry;
1445
1446   TRACE("(%p)\n", iface);
1447
1448   if (this->presentationStorage != NULL)
1449   {
1450     IStorage_Release(this->presentationStorage);
1451     this->presentationStorage = NULL;
1452   }
1453
1454   LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1455     DataCacheEntry_HandsOffStorage(cache_entry);
1456
1457   return S_OK;
1458 }
1459
1460 /*********************************************************
1461  * Method implementation for the IViewObject2
1462  * part of the DataCache class.
1463  */
1464
1465 /************************************************************************
1466  * DataCache_IViewObject2_QueryInterface (IUnknown)
1467  */
1468 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1469             IViewObject2* iface,
1470             REFIID           riid,
1471             void**           ppvObject)
1472 {
1473   DataCache *this = impl_from_IViewObject2(iface);
1474
1475   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1476 }
1477
1478 /************************************************************************
1479  * DataCache_IViewObject2_AddRef (IUnknown)
1480  */
1481 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1482             IViewObject2* iface)
1483 {
1484   DataCache *this = impl_from_IViewObject2(iface);
1485
1486   return IUnknown_AddRef(this->outerUnknown);
1487 }
1488
1489 /************************************************************************
1490  * DataCache_IViewObject2_Release (IUnknown)
1491  */
1492 static ULONG WINAPI DataCache_IViewObject2_Release(
1493             IViewObject2* iface)
1494 {
1495   DataCache *this = impl_from_IViewObject2(iface);
1496
1497   return IUnknown_Release(this->outerUnknown);
1498 }
1499
1500 /************************************************************************
1501  * DataCache_Draw (IViewObject2)
1502  *
1503  * This method will draw the cached representation of the object
1504  * to the given device context.
1505  */
1506 static HRESULT WINAPI DataCache_Draw(
1507             IViewObject2*    iface,
1508             DWORD            dwDrawAspect,
1509             LONG             lindex,
1510             void*            pvAspect,
1511             DVTARGETDEVICE*  ptd,
1512             HDC              hdcTargetDev,
1513             HDC              hdcDraw,
1514             LPCRECTL         lprcBounds,
1515             LPCRECTL         lprcWBounds,
1516             BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1517             ULONG_PTR        dwContinue)
1518 {
1519   DataCache *This = impl_from_IViewObject2(iface);
1520   HRESULT                hres;
1521   DataCacheEntry        *cache_entry;
1522
1523   TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1524         iface,
1525         dwDrawAspect,
1526         lindex,
1527         pvAspect,
1528         hdcTargetDev,
1529         hdcDraw,
1530         lprcBounds,
1531         lprcWBounds,
1532         pfnContinue,
1533         dwContinue);
1534
1535   if (lprcBounds==NULL)
1536     return E_INVALIDARG;
1537
1538   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1539   {
1540     /* FIXME: compare ptd too */
1541     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1542         (cache_entry->fmtetc.lindex != lindex))
1543       continue;
1544
1545     /* if the data hasn't been loaded yet, do it now */
1546     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1547     {
1548       hres = DataCacheEntry_LoadData(cache_entry);
1549       if (FAILED(hres))
1550         continue;
1551     }
1552
1553     /* no data */
1554     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1555       continue;
1556
1557     if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
1558
1559     switch (cache_entry->data_cf)
1560     {
1561       case CF_METAFILEPICT:
1562       {
1563         /*
1564          * We have to be careful not to modify the state of the
1565          * DC.
1566          */
1567         INT   prevMapMode;
1568         SIZE  oldWindowExt;
1569         SIZE  oldViewportExt;
1570         POINT oldViewportOrg;
1571         METAFILEPICT *mfpict;
1572
1573         if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1574             !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1575           continue;
1576
1577         prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1578
1579         SetWindowExtEx(hdcDraw,
1580                        mfpict->xExt,
1581                        mfpict->yExt,
1582                        &oldWindowExt);
1583
1584         SetViewportExtEx(hdcDraw,
1585                          lprcBounds->right - lprcBounds->left,
1586                          lprcBounds->bottom - lprcBounds->top,
1587                          &oldViewportExt);
1588
1589         SetViewportOrgEx(hdcDraw,
1590                          lprcBounds->left,
1591                          lprcBounds->top,
1592                          &oldViewportOrg);
1593
1594         PlayMetaFile(hdcDraw, mfpict->hMF);
1595
1596         SetWindowExtEx(hdcDraw,
1597                        oldWindowExt.cx,
1598                        oldWindowExt.cy,
1599                        NULL);
1600
1601         SetViewportExtEx(hdcDraw,
1602                          oldViewportExt.cx,
1603                          oldViewportExt.cy,
1604                          NULL);
1605
1606         SetViewportOrgEx(hdcDraw,
1607                          oldViewportOrg.x,
1608                          oldViewportOrg.y,
1609                          NULL);
1610
1611         SetMapMode(hdcDraw, prevMapMode);
1612
1613         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1614
1615         return S_OK;
1616       }
1617     }
1618   }
1619
1620   WARN("no data could be found to be drawn\n");
1621
1622   return OLE_E_BLANK;
1623 }
1624
1625 static HRESULT WINAPI DataCache_GetColorSet(
1626             IViewObject2*   iface,
1627             DWORD           dwDrawAspect,
1628             LONG            lindex,
1629             void*           pvAspect,
1630             DVTARGETDEVICE* ptd,
1631             HDC             hicTargetDevice,
1632             LOGPALETTE**    ppColorSet)
1633 {
1634   FIXME("stub\n");
1635   return E_NOTIMPL;
1636 }
1637
1638 static HRESULT WINAPI DataCache_Freeze(
1639             IViewObject2*   iface,
1640             DWORD           dwDrawAspect,
1641             LONG            lindex,
1642             void*           pvAspect,
1643             DWORD*          pdwFreeze)
1644 {
1645   FIXME("stub\n");
1646   return E_NOTIMPL;
1647 }
1648
1649 static HRESULT WINAPI DataCache_Unfreeze(
1650             IViewObject2*   iface,
1651             DWORD           dwFreeze)
1652 {
1653   FIXME("stub\n");
1654   return E_NOTIMPL;
1655 }
1656
1657 /************************************************************************
1658  * DataCache_SetAdvise (IViewObject2)
1659  *
1660  * This sets-up an advisory sink with the data cache. When the object's
1661  * view changes, this sink is called.
1662  */
1663 static HRESULT WINAPI DataCache_SetAdvise(
1664             IViewObject2*   iface,
1665             DWORD           aspects,
1666             DWORD           advf,
1667             IAdviseSink*    pAdvSink)
1668 {
1669   DataCache *this = impl_from_IViewObject2(iface);
1670
1671   TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1672
1673   /*
1674    * A call to this function removes the previous sink
1675    */
1676   if (this->sinkInterface != NULL)
1677   {
1678     IAdviseSink_Release(this->sinkInterface);
1679     this->sinkInterface  = NULL;
1680     this->sinkAspects    = 0;
1681     this->sinkAdviseFlag = 0;
1682   }
1683
1684   /*
1685    * Now, setup the new one.
1686    */
1687   if (pAdvSink!=NULL)
1688   {
1689     this->sinkInterface  = pAdvSink;
1690     this->sinkAspects    = aspects;
1691     this->sinkAdviseFlag = advf;
1692
1693     IAdviseSink_AddRef(this->sinkInterface);
1694   }
1695
1696   /*
1697    * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1698    * sink immediately.
1699    */
1700   if (advf & ADVF_PRIMEFIRST)
1701   {
1702     DataCache_FireOnViewChange(this, aspects, -1);
1703   }
1704
1705   return S_OK;
1706 }
1707
1708 /************************************************************************
1709  * DataCache_GetAdvise (IViewObject2)
1710  *
1711  * This method queries the current state of the advise sink
1712  * installed on the data cache.
1713  */
1714 static HRESULT WINAPI DataCache_GetAdvise(
1715             IViewObject2*   iface,
1716             DWORD*          pAspects,
1717             DWORD*          pAdvf,
1718             IAdviseSink**   ppAdvSink)
1719 {
1720   DataCache *this = impl_from_IViewObject2(iface);
1721
1722   TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1723
1724   /*
1725    * Just copy all the requested values.
1726    */
1727   if (pAspects!=NULL)
1728     *pAspects = this->sinkAspects;
1729
1730   if (pAdvf!=NULL)
1731     *pAdvf = this->sinkAdviseFlag;
1732
1733   if (ppAdvSink!=NULL)
1734   {
1735     if (this->sinkInterface != NULL)
1736         IAdviseSink_QueryInterface(this->sinkInterface,
1737                                &IID_IAdviseSink,
1738                                (void**)ppAdvSink);
1739     else *ppAdvSink = NULL;
1740   }
1741
1742   return S_OK;
1743 }
1744
1745 /************************************************************************
1746  * DataCache_GetExtent (IViewObject2)
1747  *
1748  * This method retrieves the "natural" size of this cached object.
1749  */
1750 static HRESULT WINAPI DataCache_GetExtent(
1751             IViewObject2*   iface,
1752             DWORD           dwDrawAspect,
1753             LONG            lindex,
1754             DVTARGETDEVICE* ptd,
1755             LPSIZEL         lpsizel)
1756 {
1757   DataCache *This = impl_from_IViewObject2(iface);
1758   HRESULT                hres = E_FAIL;
1759   DataCacheEntry        *cache_entry;
1760
1761   TRACE("(%p, %x, %d, %p, %p)\n",
1762         iface, dwDrawAspect, lindex, ptd, lpsizel);
1763
1764   if (lpsizel==NULL)
1765     return E_POINTER;
1766
1767   lpsizel->cx = 0;
1768   lpsizel->cy = 0;
1769
1770   if (lindex!=-1)
1771     FIXME("Unimplemented flag lindex = %d\n", lindex);
1772
1773   /*
1774    * Right now, we support only the callback from
1775    * the default handler.
1776    */
1777   if (ptd!=NULL)
1778     FIXME("Unimplemented ptd = %p\n", ptd);
1779
1780   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1781   {
1782     /* FIXME: compare ptd too */
1783     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1784         (cache_entry->fmtetc.lindex != lindex))
1785       continue;
1786
1787     /* if the data hasn't been loaded yet, do it now */
1788     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1789     {
1790       hres = DataCacheEntry_LoadData(cache_entry);
1791       if (FAILED(hres))
1792         continue;
1793     }
1794
1795     /* no data */
1796     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1797       continue;
1798
1799
1800     switch (cache_entry->data_cf)
1801     {
1802       case CF_METAFILEPICT:
1803       {
1804           METAFILEPICT *mfpict;
1805
1806           if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1807               !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1808             continue;
1809
1810         lpsizel->cx = mfpict->xExt;
1811         lpsizel->cy = mfpict->yExt;
1812
1813         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1814
1815         return S_OK;
1816       }
1817     }
1818   }
1819
1820   WARN("no data could be found to get the extents from\n");
1821
1822   /*
1823    * This method returns OLE_E_BLANK when it fails.
1824    */
1825   return OLE_E_BLANK;
1826 }
1827
1828
1829 /*********************************************************
1830  * Method implementation for the IOleCache2
1831  * part of the DataCache class.
1832  */
1833
1834 /************************************************************************
1835  * DataCache_IOleCache2_QueryInterface (IUnknown)
1836  */
1837 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1838             IOleCache2*     iface,
1839             REFIID          riid,
1840             void**          ppvObject)
1841 {
1842   DataCache *this = impl_from_IOleCache2(iface);
1843
1844   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1845 }
1846
1847 /************************************************************************
1848  * DataCache_IOleCache2_AddRef (IUnknown)
1849  */
1850 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1851             IOleCache2*     iface)
1852 {
1853   DataCache *this = impl_from_IOleCache2(iface);
1854
1855   return IUnknown_AddRef(this->outerUnknown);
1856 }
1857
1858 /************************************************************************
1859  * DataCache_IOleCache2_Release (IUnknown)
1860  */
1861 static ULONG WINAPI DataCache_IOleCache2_Release(
1862             IOleCache2*     iface)
1863 {
1864   DataCache *this = impl_from_IOleCache2(iface);
1865
1866   return IUnknown_Release(this->outerUnknown);
1867 }
1868
1869 /*****************************************************************************
1870  * setup_sink
1871  *
1872  * Set up the sink connection to the running object.
1873  */
1874 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
1875 {
1876     HRESULT hr = S_FALSE;
1877     DWORD flags;
1878
1879     /* Clear the ADVFCACHE_* bits.  Native also sets the two highest bits for some reason. */
1880     flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
1881
1882     if(This->running_object)
1883         if(!(flags & ADVF_NODATA))
1884             hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
1885                                      &This->IAdviseSink_iface, &cache_entry->sink_id);
1886     return hr;
1887 }
1888
1889 static HRESULT WINAPI DataCache_Cache(
1890             IOleCache2*     iface,
1891             FORMATETC*      pformatetc,
1892             DWORD           advf,
1893             DWORD*          pdwConnection)
1894 {
1895     DataCache *This = impl_from_IOleCache2(iface);
1896     DataCacheEntry *cache_entry;
1897     HRESULT hr;
1898
1899     TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1900
1901     if (!pformatetc || !pdwConnection)
1902         return E_INVALIDARG;
1903
1904     TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1905
1906     *pdwConnection = 0;
1907
1908     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1909     if (cache_entry)
1910     {
1911         TRACE("found an existing cache entry\n");
1912         *pdwConnection = cache_entry->id;
1913         return CACHE_S_SAMECACHE;
1914     }
1915
1916     hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1917
1918     if (SUCCEEDED(hr))
1919     {
1920         *pdwConnection = cache_entry->id;
1921         cache_entry->advise_flags = advf;
1922         setup_sink(This, cache_entry);
1923     }
1924
1925     return hr;
1926 }
1927
1928 static HRESULT WINAPI DataCache_Uncache(
1929             IOleCache2*     iface,
1930             DWORD           dwConnection)
1931 {
1932     DataCache *This = impl_from_IOleCache2(iface);
1933     DataCacheEntry *cache_entry;
1934
1935     TRACE("(%d)\n", dwConnection);
1936
1937     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1938         if (cache_entry->id == dwConnection)
1939         {
1940             DataCacheEntry_Destroy(This, cache_entry);
1941             return S_OK;
1942         }
1943
1944     WARN("no connection found for %d\n", dwConnection);
1945
1946     return OLE_E_NOCONNECTION;
1947 }
1948
1949 static HRESULT WINAPI DataCache_EnumCache(
1950             IOleCache2*     iface,
1951             IEnumSTATDATA** ppenumSTATDATA)
1952 {
1953   FIXME("stub\n");
1954   return E_NOTIMPL;
1955 }
1956
1957 static HRESULT WINAPI DataCache_InitCache(
1958             IOleCache2*     iface,
1959             IDataObject*    pDataObject)
1960 {
1961   FIXME("stub\n");
1962   return E_NOTIMPL;
1963 }
1964
1965 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1966             IOleCache2*     iface,
1967             FORMATETC*      pformatetc,
1968             STGMEDIUM*      pmedium,
1969             BOOL            fRelease)
1970 {
1971     DataCache *This = impl_from_IOleCache2(iface);
1972     DataCacheEntry *cache_entry;
1973     HRESULT hr;
1974
1975     TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
1976     TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
1977
1978     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1979     if (cache_entry)
1980     {
1981         hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
1982
1983         if (SUCCEEDED(hr))
1984             DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
1985                                        cache_entry->fmtetc.lindex);
1986
1987         return hr;
1988     }
1989     WARN("cache entry not found\n");
1990
1991     return OLE_E_BLANK;
1992 }
1993
1994 static HRESULT WINAPI DataCache_UpdateCache(
1995             IOleCache2*     iface,
1996             LPDATAOBJECT    pDataObject,
1997             DWORD           grfUpdf,
1998             LPVOID          pReserved)
1999 {
2000   FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
2001   return E_NOTIMPL;
2002 }
2003
2004 static HRESULT WINAPI DataCache_DiscardCache(
2005             IOleCache2*     iface,
2006             DWORD           dwDiscardOptions)
2007 {
2008     DataCache *This = impl_from_IOleCache2(iface);
2009     DataCacheEntry *cache_entry;
2010     HRESULT hr = S_OK;
2011
2012     TRACE("(%d)\n", dwDiscardOptions);
2013
2014     if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2015         hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2016
2017     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2018     {
2019         hr = DataCacheEntry_DiscardData(cache_entry);
2020         if (FAILED(hr))
2021             break;
2022     }
2023
2024     return hr;
2025 }
2026
2027
2028 /*********************************************************
2029  * Method implementation for the IOleCacheControl
2030  * part of the DataCache class.
2031  */
2032
2033 /************************************************************************
2034  * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2035  */
2036 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2037             IOleCacheControl* iface,
2038             REFIID            riid,
2039             void**            ppvObject)
2040 {
2041   DataCache *this = impl_from_IOleCacheControl(iface);
2042
2043   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2044 }
2045
2046 /************************************************************************
2047  * DataCache_IOleCacheControl_AddRef (IUnknown)
2048  */
2049 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2050             IOleCacheControl* iface)
2051 {
2052   DataCache *this = impl_from_IOleCacheControl(iface);
2053
2054   return IUnknown_AddRef(this->outerUnknown);
2055 }
2056
2057 /************************************************************************
2058  * DataCache_IOleCacheControl_Release (IUnknown)
2059  */
2060 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2061             IOleCacheControl* iface)
2062 {
2063   DataCache *this = impl_from_IOleCacheControl(iface);
2064
2065   return IUnknown_Release(this->outerUnknown);
2066 }
2067
2068 /************************************************************************
2069  * DataCache_OnRun (IOleCacheControl)
2070  */
2071 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2072 {
2073     DataCache *This = impl_from_IOleCacheControl(iface);
2074     DataCacheEntry *cache_entry;
2075
2076     TRACE("(%p)->(%p)\n", iface, data_obj);
2077
2078     if(This->running_object) return S_OK;
2079
2080     /* No reference is taken on the data object */
2081     This->running_object = data_obj;
2082
2083     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2084     {
2085         setup_sink(This, cache_entry);
2086     }
2087
2088     return S_OK;
2089 }
2090
2091 /************************************************************************
2092  * DataCache_OnStop (IOleCacheControl)
2093  */
2094 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2095 {
2096     DataCache *This = impl_from_IOleCacheControl(iface);
2097     DataCacheEntry *cache_entry;
2098
2099     TRACE("(%p)\n", iface);
2100
2101     if(!This->running_object) return S_OK;
2102
2103     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2104     {
2105         if(cache_entry->sink_id)
2106         {
2107             IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2108             cache_entry->sink_id = 0;
2109         }
2110     }
2111
2112     /* No ref taken in OnRun, so no Release call here */
2113     This->running_object = NULL;
2114     return S_OK;
2115 }
2116
2117 /************************************************************************
2118  *              IAdviseSink methods.
2119  * This behaves as an internal object to the data cache.  QI'ing its ptr doesn't
2120  * give access to the cache's other interfaces.  We don't maintain a ref count,
2121  * the object exists as long as the cache is around.
2122  */
2123 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2124 {
2125     *obj = NULL;
2126     if (IsEqualIID(&IID_IUnknown, iid) ||
2127         IsEqualIID(&IID_IAdviseSink, iid))
2128     {
2129         *obj = iface;
2130     }
2131
2132     if(*obj)
2133     {
2134         IAdviseSink_AddRef(iface);
2135         return S_OK;
2136     }
2137     return E_NOINTERFACE;
2138 }
2139
2140 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2141 {
2142     return 2;
2143 }
2144
2145 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2146 {
2147     return 1;
2148 }
2149
2150 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2151 {
2152     DataCache *This = impl_from_IAdviseSink(iface);
2153     TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2154     IOleCache_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2155 }
2156
2157 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2158 {
2159     FIXME("stub\n");
2160 }
2161
2162 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2163 {
2164     FIXME("stub\n");
2165 }
2166
2167 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2168 {
2169     FIXME("stub\n");
2170 }
2171
2172 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2173 {
2174     FIXME("stub\n");
2175 }
2176
2177 /*
2178  * Virtual function tables for the DataCache class.
2179  */
2180 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2181 {
2182   DataCache_NDIUnknown_QueryInterface,
2183   DataCache_NDIUnknown_AddRef,
2184   DataCache_NDIUnknown_Release
2185 };
2186
2187 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2188 {
2189   DataCache_IDataObject_QueryInterface,
2190   DataCache_IDataObject_AddRef,
2191   DataCache_IDataObject_Release,
2192   DataCache_GetData,
2193   DataCache_GetDataHere,
2194   DataCache_QueryGetData,
2195   DataCache_GetCanonicalFormatEtc,
2196   DataCache_IDataObject_SetData,
2197   DataCache_EnumFormatEtc,
2198   DataCache_DAdvise,
2199   DataCache_DUnadvise,
2200   DataCache_EnumDAdvise
2201 };
2202
2203 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2204 {
2205   DataCache_IPersistStorage_QueryInterface,
2206   DataCache_IPersistStorage_AddRef,
2207   DataCache_IPersistStorage_Release,
2208   DataCache_GetClassID,
2209   DataCache_IsDirty,
2210   DataCache_InitNew,
2211   DataCache_Load,
2212   DataCache_Save,
2213   DataCache_SaveCompleted,
2214   DataCache_HandsOffStorage
2215 };
2216
2217 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2218 {
2219   DataCache_IViewObject2_QueryInterface,
2220   DataCache_IViewObject2_AddRef,
2221   DataCache_IViewObject2_Release,
2222   DataCache_Draw,
2223   DataCache_GetColorSet,
2224   DataCache_Freeze,
2225   DataCache_Unfreeze,
2226   DataCache_SetAdvise,
2227   DataCache_GetAdvise,
2228   DataCache_GetExtent
2229 };
2230
2231 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2232 {
2233   DataCache_IOleCache2_QueryInterface,
2234   DataCache_IOleCache2_AddRef,
2235   DataCache_IOleCache2_Release,
2236   DataCache_Cache,
2237   DataCache_Uncache,
2238   DataCache_EnumCache,
2239   DataCache_InitCache,
2240   DataCache_IOleCache2_SetData,
2241   DataCache_UpdateCache,
2242   DataCache_DiscardCache
2243 };
2244
2245 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2246 {
2247   DataCache_IOleCacheControl_QueryInterface,
2248   DataCache_IOleCacheControl_AddRef,
2249   DataCache_IOleCacheControl_Release,
2250   DataCache_OnRun,
2251   DataCache_OnStop
2252 };
2253
2254 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2255 {
2256     DataCache_IAdviseSink_QueryInterface,
2257     DataCache_IAdviseSink_AddRef,
2258     DataCache_IAdviseSink_Release,
2259     DataCache_OnDataChange,
2260     DataCache_OnViewChange,
2261     DataCache_OnRename,
2262     DataCache_OnSave,
2263     DataCache_OnClose
2264 };
2265
2266 /*********************************************************
2267  * Method implementation for DataCache class.
2268  */
2269 static DataCache* DataCache_Construct(
2270   REFCLSID  clsid,
2271   LPUNKNOWN pUnkOuter)
2272 {
2273   DataCache* newObject = 0;
2274
2275   /*
2276    * Allocate space for the object.
2277    */
2278   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2279
2280   if (newObject==0)
2281     return newObject;
2282
2283   /*
2284    * Initialize the virtual function table.
2285    */
2286   newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2287   newObject->IUnknown_iface.lpVtbl = &DataCache_NDIUnknown_VTable;
2288   newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2289   newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2290   newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2291   newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2292   newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2293
2294   /*
2295    * Start with one reference count. The caller of this function
2296    * must release the interface pointer when it is done.
2297    */
2298   newObject->ref = 1;
2299
2300   /*
2301    * Initialize the outer unknown
2302    * We don't keep a reference on the outer unknown since, the way
2303    * aggregation works, our lifetime is at least as large as its
2304    * lifetime.
2305    */
2306   if (pUnkOuter==NULL)
2307     pUnkOuter = &newObject->IUnknown_iface;
2308
2309   newObject->outerUnknown = pUnkOuter;
2310
2311   /*
2312    * Initialize the other members of the structure.
2313    */
2314   newObject->sinkAspects = 0;
2315   newObject->sinkAdviseFlag = 0;
2316   newObject->sinkInterface = 0;
2317   newObject->presentationStorage = NULL;
2318   list_init(&newObject->cache_list);
2319   newObject->last_cache_id = 1;
2320   newObject->dirty = FALSE;
2321   newObject->running_object = NULL;
2322
2323   return newObject;
2324 }
2325
2326 /******************************************************************************
2327  *              CreateDataCache        [OLE32.@]
2328  *
2329  * Creates a data cache to allow an object to render one or more of its views,
2330  * whether running or not.
2331  *
2332  * PARAMS
2333  *  pUnkOuter [I] Outer unknown for the object.
2334  *  rclsid    [I]
2335  *  riid      [I] IID of interface to return.
2336  *  ppvObj    [O] Address where the data cache object will be stored on return.
2337  *
2338  * RETURNS
2339  *  Success: S_OK.
2340  *  Failure: HRESULT code.
2341  *
2342  * NOTES
2343  *  The following interfaces are supported by the returned data cache object:
2344  *  IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
2345  *  IViewObject and IViewObject2.
2346  */
2347 HRESULT WINAPI CreateDataCache(
2348   LPUNKNOWN pUnkOuter,
2349   REFCLSID  rclsid,
2350   REFIID    riid,
2351   LPVOID*   ppvObj)
2352 {
2353   DataCache* newCache = NULL;
2354   HRESULT    hr       = S_OK;
2355
2356   TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2357
2358   /*
2359    * Sanity check
2360    */
2361   if (ppvObj==0)
2362     return E_POINTER;
2363
2364   *ppvObj = 0;
2365
2366   /*
2367    * If this cache is constructed for aggregation, make sure
2368    * the caller is requesting the IUnknown interface.
2369    * This is necessary because it's the only time the non-delegating
2370    * IUnknown pointer can be returned to the outside.
2371    */
2372   if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
2373     return CLASS_E_NOAGGREGATION;
2374
2375   /*
2376    * Try to construct a new instance of the class.
2377    */
2378   newCache = DataCache_Construct(rclsid,
2379                                  pUnkOuter);
2380
2381   if (newCache == 0)
2382     return E_OUTOFMEMORY;
2383
2384   /*
2385    * Make sure it supports the interface required by the caller.
2386    */
2387   hr = IUnknown_QueryInterface(&newCache->IUnknown_iface, riid, ppvObj);
2388
2389   /*
2390    * Release the reference obtained in the constructor. If
2391    * the QueryInterface was unsuccessful, it will free the class.
2392    */
2393   IUnknown_Release(&newCache->IUnknown_iface);
2394
2395   return hr;
2396 }