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