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