ole32: Implement Revert for transacted storage objects.
[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     HRESULT hr;
659     WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
660         '0' + (This->stream_number / 100) % 10,
661         '0' + (This->stream_number / 10) % 10,
662         '0' + This->stream_number % 10, 0};
663
664     /* FIXME: cache the created stream in This? */
665     hr = IStorage_CreateStream(storage, wszName,
666                                STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
667                                0, 0, stream);
668     return hr;
669 }
670
671 static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
672                                    BOOL same_as_load)
673 {
674     PresentationDataHeader header;
675     HRESULT hr;
676     IStream *pres_stream;
677     void *data = NULL;
678
679     TRACE("stream_number = %d, fmtetc = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc));
680
681     hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
682     if (FAILED(hr))
683         return hr;
684
685     hr = write_clipformat(pres_stream, This->data_cf);
686     if (FAILED(hr))
687         return hr;
688
689     if (This->fmtetc.ptd)
690         FIXME("ptd not serialized\n");
691     header.unknown3 = 4;
692     header.dvAspect = This->fmtetc.dwAspect;
693     header.lindex = This->fmtetc.lindex;
694     header.tymed = This->stgmedium.tymed;
695     header.unknown7 = 0;
696     header.dwObjectExtentX = 0;
697     header.dwObjectExtentY = 0;
698     header.dwSize = 0;
699
700     /* size the data */
701     switch (This->data_cf)
702     {
703         case CF_METAFILEPICT:
704         {
705             if (This->stgmedium.tymed != TYMED_NULL)
706             {
707                 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
708                 if (!mfpict)
709                 {
710                     IStream_Release(pres_stream);
711                     return DV_E_STGMEDIUM;
712                 }
713                 header.dwObjectExtentX = mfpict->xExt;
714                 header.dwObjectExtentY = mfpict->yExt;
715                 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
716                 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
717             }
718             break;
719         }
720         default:
721             break;
722     }
723
724     /*
725      * Write the header.
726      */
727     hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
728                        NULL);
729     if (FAILED(hr))
730     {
731         IStream_Release(pres_stream);
732         return hr;
733     }
734
735     /* get the data */
736     switch (This->data_cf)
737     {
738         case CF_METAFILEPICT:
739         {
740             if (This->stgmedium.tymed != TYMED_NULL)
741             {
742                 const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
743                 if (!mfpict)
744                 {
745                     IStream_Release(pres_stream);
746                     return DV_E_STGMEDIUM;
747                 }
748                 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
749                 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
750                 GlobalUnlock(This->stgmedium.u.hMetaFilePict);
751             }
752             break;
753         }
754         default:
755             break;
756     }
757
758     if (data)
759         hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
760     HeapFree(GetProcessHeap(), 0, data);
761
762     IStream_Release(pres_stream);
763     return hr;
764 }
765
766 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
767 * does no checking of whether src_stgm has a supported tymed, so this should be
768 * done in the caller */
769 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
770                                const STGMEDIUM *src_stgm)
771 {
772     if (src_stgm->tymed == TYMED_MFPICT)
773     {
774         const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
775         METAFILEPICT *dest_mfpict;
776
777         if (!src_mfpict)
778             return DV_E_STGMEDIUM;
779         dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
780         dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
781         if (!dest_mfpict)
782         {
783             GlobalUnlock(src_stgm->u.hMetaFilePict);
784             return E_OUTOFMEMORY;
785         }
786         *dest_mfpict = *src_mfpict;
787         dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
788         GlobalUnlock(src_stgm->u.hMetaFilePict);
789         GlobalUnlock(dest_stgm->u.hMetaFilePict);
790     }
791     else if (src_stgm->tymed != TYMED_NULL)
792     {
793         dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
794                                                 GMEM_MOVEABLE);
795         if (!dest_stgm->u.hGlobal)
796             return E_OUTOFMEMORY;
797     }
798     dest_stgm->tymed = src_stgm->tymed;
799     dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
800     if (dest_stgm->pUnkForRelease)
801         IUnknown_AddRef(dest_stgm->pUnkForRelease);
802     return S_OK;
803 }
804
805 static HRESULT DataCacheEntry_SetData(DataCacheEntry *This,
806                                       const FORMATETC *formatetc,
807                                       const STGMEDIUM *stgmedium,
808                                       BOOL fRelease)
809 {
810     if ((!This->fmtetc.cfFormat && !formatetc->cfFormat) ||
811         (This->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
812         stgmedium->tymed == TYMED_NULL)
813     {
814         WARN("invalid formatetc\n");
815         return DV_E_FORMATETC;
816     }
817
818     This->dirty = TRUE;
819     ReleaseStgMedium(&This->stgmedium);
820     This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat;
821     if (fRelease)
822     {
823         This->stgmedium = *stgmedium;
824         return S_OK;
825     }
826     else
827         return copy_stg_medium(This->data_cf,
828                                &This->stgmedium, stgmedium);
829 }
830
831 static HRESULT DataCacheEntry_GetData(DataCacheEntry *This,
832                                       STGMEDIUM *stgmedium)
833 {
834     if (stgmedium->tymed == TYMED_NULL && This->storage)
835     {
836         HRESULT hr = DataCacheEntry_LoadData(This);
837         if (FAILED(hr))
838             return hr;
839     }
840     if (This->stgmedium.tymed == TYMED_NULL)
841         return OLE_E_BLANK;
842     return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium);
843 }
844
845 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
846 {
847     ReleaseStgMedium(&This->stgmedium);
848     This->data_cf = This->fmtetc.cfFormat;
849     return S_OK;
850 }
851
852 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This)
853 {
854     if (This->storage)
855     {
856         IStorage_Release(This->storage);
857         This->storage = NULL;
858     }
859 }
860
861 /*********************************************************
862  * Method implementation for the  non delegating IUnknown
863  * part of the DataCache class.
864  */
865
866 /************************************************************************
867  * DataCache_NDIUnknown_QueryInterface (IUnknown)
868  *
869  * See Windows documentation for more details on IUnknown methods.
870  *
871  * This version of QueryInterface will not delegate it's implementation
872  * to the outer unknown.
873  */
874 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
875             IUnknown*      iface,
876             REFIID         riid,
877             void**         ppvObject)
878 {
879   DataCache *this = impl_from_NDIUnknown(iface);
880
881   /*
882    * Perform a sanity check on the parameters.
883    */
884   if ( (this==0) || (ppvObject==0) )
885     return E_INVALIDARG;
886
887   /*
888    * Initialize the return parameter.
889    */
890   *ppvObject = 0;
891
892   /*
893    * Compare the riid with the interface IDs implemented by this object.
894    */
895   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
896   {
897     *ppvObject = iface;
898   }
899   else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
900   {
901     *ppvObject = &this->lpVtbl;
902   }
903   else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0)  ||
904             (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
905   {
906     *ppvObject = &this->lpvtblIPersistStorage;
907   }
908   else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
909             (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
910   {
911     *ppvObject = &this->lpvtblIViewObject;
912   }
913   else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
914             (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
915   {
916     *ppvObject = &this->lpvtblIOleCache2;
917   }
918   else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
919   {
920     *ppvObject = &this->lpvtblIOleCacheControl;
921   }
922
923   /*
924    * Check that we obtained an interface.
925    */
926   if ((*ppvObject)==0)
927   {
928     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
929     return E_NOINTERFACE;
930   }
931
932   /*
933    * Query Interface always increases the reference count by one when it is
934    * successful.
935    */
936   IUnknown_AddRef((IUnknown*)*ppvObject);
937
938   return S_OK;
939 }
940
941 /************************************************************************
942  * DataCache_NDIUnknown_AddRef (IUnknown)
943  *
944  * See Windows documentation for more details on IUnknown methods.
945  *
946  * This version of QueryInterface will not delegate it's implementation
947  * to the outer unknown.
948  */
949 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
950             IUnknown*      iface)
951 {
952   DataCache *this = impl_from_NDIUnknown(iface);
953   return InterlockedIncrement(&this->ref);
954 }
955
956 /************************************************************************
957  * DataCache_NDIUnknown_Release (IUnknown)
958  *
959  * See Windows documentation for more details on IUnknown methods.
960  *
961  * This version of QueryInterface will not delegate it's implementation
962  * to the outer unknown.
963  */
964 static ULONG WINAPI DataCache_NDIUnknown_Release(
965             IUnknown*      iface)
966 {
967   DataCache *this = impl_from_NDIUnknown(iface);
968   ULONG ref;
969
970   /*
971    * Decrease the reference count on this object.
972    */
973   ref = InterlockedDecrement(&this->ref);
974
975   /*
976    * If the reference count goes down to 0, perform suicide.
977    */
978   if (ref == 0) DataCache_Destroy(this);
979
980   return ref;
981 }
982
983 /*********************************************************
984  * Method implementation for the IDataObject
985  * part of the DataCache class.
986  */
987
988 /************************************************************************
989  * DataCache_IDataObject_QueryInterface (IUnknown)
990  *
991  * See Windows documentation for more details on IUnknown methods.
992  */
993 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
994             IDataObject*     iface,
995             REFIID           riid,
996             void**           ppvObject)
997 {
998   DataCache *this = impl_from_IDataObject(iface);
999
1000   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1001 }
1002
1003 /************************************************************************
1004  * DataCache_IDataObject_AddRef (IUnknown)
1005  *
1006  * See Windows documentation for more details on IUnknown methods.
1007  */
1008 static ULONG WINAPI DataCache_IDataObject_AddRef(
1009             IDataObject*     iface)
1010 {
1011   DataCache *this = impl_from_IDataObject(iface);
1012
1013   return IUnknown_AddRef(this->outerUnknown);
1014 }
1015
1016 /************************************************************************
1017  * DataCache_IDataObject_Release (IUnknown)
1018  *
1019  * See Windows documentation for more details on IUnknown methods.
1020  */
1021 static ULONG WINAPI DataCache_IDataObject_Release(
1022             IDataObject*     iface)
1023 {
1024   DataCache *this = impl_from_IDataObject(iface);
1025
1026   return IUnknown_Release(this->outerUnknown);
1027 }
1028
1029 /************************************************************************
1030  * DataCache_GetData
1031  *
1032  * Get Data from a source dataobject using format pformatetcIn->cfFormat
1033  * See Windows documentation for more details on GetData.
1034  */
1035 static HRESULT WINAPI DataCache_GetData(
1036             IDataObject*     iface,
1037             LPFORMATETC      pformatetcIn,
1038             STGMEDIUM*       pmedium)
1039 {
1040     DataCache *This = impl_from_IDataObject(iface);
1041     DataCacheEntry *cache_entry;
1042
1043     memset(pmedium, 0, sizeof(*pmedium));
1044
1045     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1046     if (!cache_entry)
1047         return OLE_E_BLANK;
1048
1049     return DataCacheEntry_GetData(cache_entry, pmedium);
1050 }
1051
1052 static HRESULT WINAPI DataCache_GetDataHere(
1053             IDataObject*     iface,
1054             LPFORMATETC      pformatetc,
1055             STGMEDIUM*       pmedium)
1056 {
1057   FIXME("stub\n");
1058   return E_NOTIMPL;
1059 }
1060
1061 static HRESULT WINAPI DataCache_QueryGetData(
1062             IDataObject*     iface,
1063             LPFORMATETC      pformatetc)
1064 {
1065   FIXME("stub\n");
1066   return E_NOTIMPL;
1067 }
1068
1069 /************************************************************************
1070  * DataCache_EnumFormatEtc (IDataObject)
1071  *
1072  * The data cache doesn't implement this method.
1073  *
1074  * See Windows documentation for more details on IDataObject methods.
1075  */
1076 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1077             IDataObject*     iface,
1078             LPFORMATETC      pformatectIn,
1079             LPFORMATETC      pformatetcOut)
1080 {
1081   TRACE("()\n");
1082   return E_NOTIMPL;
1083 }
1084
1085 /************************************************************************
1086  * DataCache_IDataObject_SetData (IDataObject)
1087  *
1088  * This method is delegated to the IOleCache2 implementation.
1089  *
1090  * See Windows documentation for more details on IDataObject methods.
1091  */
1092 static HRESULT WINAPI DataCache_IDataObject_SetData(
1093             IDataObject*     iface,
1094             LPFORMATETC      pformatetc,
1095             STGMEDIUM*       pmedium,
1096             BOOL             fRelease)
1097 {
1098   IOleCache2* oleCache = NULL;
1099   HRESULT     hres;
1100
1101   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1102
1103   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1104
1105   if (FAILED(hres))
1106     return E_UNEXPECTED;
1107
1108   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1109
1110   IOleCache2_Release(oleCache);
1111
1112   return hres;
1113 }
1114
1115 /************************************************************************
1116  * DataCache_EnumFormatEtc (IDataObject)
1117  *
1118  * The data cache doesn't implement this method.
1119  *
1120  * See Windows documentation for more details on IDataObject methods.
1121  */
1122 static HRESULT WINAPI DataCache_EnumFormatEtc(
1123             IDataObject*     iface,
1124             DWORD            dwDirection,
1125             IEnumFORMATETC** ppenumFormatEtc)
1126 {
1127   TRACE("()\n");
1128   return E_NOTIMPL;
1129 }
1130
1131 /************************************************************************
1132  * DataCache_DAdvise (IDataObject)
1133  *
1134  * The data cache doesn't support connections.
1135  *
1136  * See Windows documentation for more details on IDataObject methods.
1137  */
1138 static HRESULT WINAPI DataCache_DAdvise(
1139             IDataObject*     iface,
1140             FORMATETC*       pformatetc,
1141             DWORD            advf,
1142             IAdviseSink*     pAdvSink,
1143             DWORD*           pdwConnection)
1144 {
1145   TRACE("()\n");
1146   return OLE_E_ADVISENOTSUPPORTED;
1147 }
1148
1149 /************************************************************************
1150  * DataCache_DUnadvise (IDataObject)
1151  *
1152  * The data cache doesn't support connections.
1153  *
1154  * See Windows documentation for more details on IDataObject methods.
1155  */
1156 static HRESULT WINAPI DataCache_DUnadvise(
1157             IDataObject*     iface,
1158             DWORD            dwConnection)
1159 {
1160   TRACE("()\n");
1161   return OLE_E_NOCONNECTION;
1162 }
1163
1164 /************************************************************************
1165  * DataCache_EnumDAdvise (IDataObject)
1166  *
1167  * The data cache doesn't support connections.
1168  *
1169  * See Windows documentation for more details on IDataObject methods.
1170  */
1171 static HRESULT WINAPI DataCache_EnumDAdvise(
1172             IDataObject*     iface,
1173             IEnumSTATDATA**  ppenumAdvise)
1174 {
1175   TRACE("()\n");
1176   return OLE_E_ADVISENOTSUPPORTED;
1177 }
1178
1179 /*********************************************************
1180  * Method implementation for the IDataObject
1181  * part of the DataCache class.
1182  */
1183
1184 /************************************************************************
1185  * DataCache_IPersistStorage_QueryInterface (IUnknown)
1186  *
1187  * See Windows documentation for more details on IUnknown methods.
1188  */
1189 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1190             IPersistStorage* iface,
1191             REFIID           riid,
1192             void**           ppvObject)
1193 {
1194   DataCache *this = impl_from_IPersistStorage(iface);
1195
1196   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1197 }
1198
1199 /************************************************************************
1200  * DataCache_IPersistStorage_AddRef (IUnknown)
1201  *
1202  * See Windows documentation for more details on IUnknown methods.
1203  */
1204 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1205             IPersistStorage* iface)
1206 {
1207   DataCache *this = impl_from_IPersistStorage(iface);
1208
1209   return IUnknown_AddRef(this->outerUnknown);
1210 }
1211
1212 /************************************************************************
1213  * DataCache_IPersistStorage_Release (IUnknown)
1214  *
1215  * See Windows documentation for more details on IUnknown methods.
1216  */
1217 static ULONG WINAPI DataCache_IPersistStorage_Release(
1218             IPersistStorage* iface)
1219 {
1220   DataCache *this = impl_from_IPersistStorage(iface);
1221
1222   return IUnknown_Release(this->outerUnknown);
1223 }
1224
1225 /************************************************************************
1226  * DataCache_GetClassID (IPersistStorage)
1227  *
1228  * The data cache doesn't implement this method.
1229  *
1230  * See Windows documentation for more details on IPersistStorage methods.
1231  */
1232 static HRESULT WINAPI DataCache_GetClassID(
1233             IPersistStorage* iface,
1234             CLSID*           pClassID)
1235 {
1236   DataCache *This = impl_from_IPersistStorage(iface);
1237   DataCacheEntry *cache_entry;
1238
1239   TRACE("(%p, %p)\n", iface, pClassID);
1240
1241   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1242   {
1243     if (cache_entry->storage != NULL)
1244     {
1245       STATSTG statstg;
1246       HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1247       if (SUCCEEDED(hr))
1248       {
1249         *pClassID = statstg.clsid;
1250         return S_OK;
1251       }
1252     }
1253   }
1254
1255   *pClassID = CLSID_NULL;
1256
1257   return S_OK;
1258 }
1259
1260 /************************************************************************
1261  * DataCache_IsDirty (IPersistStorage)
1262  *
1263  * See Windows documentation for more details on IPersistStorage methods.
1264  */
1265 static HRESULT WINAPI DataCache_IsDirty(
1266             IPersistStorage* iface)
1267 {
1268     DataCache *This = impl_from_IPersistStorage(iface);
1269     DataCacheEntry *cache_entry;
1270
1271     TRACE("(%p)\n", iface);
1272
1273     if (This->dirty)
1274         return S_OK;
1275
1276     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1277         if (cache_entry->dirty)
1278             return S_OK;
1279
1280     return S_FALSE;
1281 }
1282
1283 /************************************************************************
1284  * DataCache_InitNew (IPersistStorage)
1285  *
1286  * The data cache implementation of IPersistStorage_InitNew simply stores
1287  * the storage pointer.
1288  *
1289  * See Windows documentation for more details on IPersistStorage methods.
1290  */
1291 static HRESULT WINAPI DataCache_InitNew(
1292             IPersistStorage* iface,
1293             IStorage*        pStg)
1294 {
1295     DataCache *This = impl_from_IPersistStorage(iface);
1296
1297     TRACE("(%p, %p)\n", iface, pStg);
1298
1299     if (This->presentationStorage != NULL)
1300         IStorage_Release(This->presentationStorage);
1301
1302     This->presentationStorage = pStg;
1303
1304     IStorage_AddRef(This->presentationStorage);
1305     This->dirty = TRUE;
1306
1307     return S_OK;
1308 }
1309
1310 /************************************************************************
1311  * DataCache_Load (IPersistStorage)
1312  *
1313  * The data cache implementation of IPersistStorage_Load doesn't
1314  * actually load anything. Instead, it holds on to the storage pointer
1315  * and it will load the presentation information when the
1316  * IDataObject_GetData or IViewObject2_Draw methods are called.
1317  *
1318  * See Windows documentation for more details on IPersistStorage methods.
1319  */
1320 static HRESULT WINAPI DataCache_Load(
1321             IPersistStorage* iface,
1322             IStorage*        pStg)
1323 {
1324     DataCache *This = impl_from_IPersistStorage(iface);
1325     STATSTG elem;
1326     IEnumSTATSTG *pEnum;
1327     HRESULT hr;
1328
1329     TRACE("(%p, %p)\n", iface, pStg);
1330
1331     if (This->presentationStorage != NULL)
1332       IStorage_Release(This->presentationStorage);
1333
1334     This->presentationStorage = pStg;
1335
1336     hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1337     if (FAILED(hr)) return hr;
1338
1339     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1340     {
1341         if (DataCache_IsPresentationStream(&elem))
1342         {
1343             IStream *pStm;
1344
1345             hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1346                                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1347                                      &pStm);
1348             if (SUCCEEDED(hr))
1349             {
1350                 PresentationDataHeader header;
1351                 ULONG actual_read;
1352                 CLIPFORMAT clipformat;
1353
1354                 hr = read_clipformat(pStm, &clipformat);
1355
1356                 if (hr == S_OK)
1357                     hr = IStream_Read(pStm, &header, sizeof(header),
1358                                       &actual_read);
1359
1360                 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1361                 if (hr == S_OK && actual_read == sizeof(header))
1362                 {
1363                     DataCacheEntry *cache_entry;
1364                     FORMATETC fmtetc;
1365
1366                     fmtetc.cfFormat = clipformat;
1367                     fmtetc.ptd = NULL; /* FIXME */
1368                     fmtetc.dwAspect = header.dvAspect;
1369                     fmtetc.lindex = header.lindex;
1370                     fmtetc.tymed = header.tymed;
1371
1372                     TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1373
1374                     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1375                     if (!cache_entry)
1376                         hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1377                     if (SUCCEEDED(hr))
1378                     {
1379                         DataCacheEntry_DiscardData(cache_entry);
1380                         if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1381                         cache_entry->storage = pStg;
1382                         IStorage_AddRef(pStg);
1383                         cache_entry->dirty = FALSE;
1384                     }
1385                 }
1386
1387                 IStream_Release(pStm);
1388             }
1389         }
1390
1391         CoTaskMemFree(elem.pwcsName);
1392     }
1393
1394     This->dirty = FALSE;
1395
1396     IEnumSTATSTG_Release(pEnum);
1397
1398     IStorage_AddRef(This->presentationStorage);
1399     return S_OK;
1400 }
1401
1402 /************************************************************************
1403  * DataCache_Save (IPersistStorage)
1404  *
1405  * Until we actually connect to a running object and retrieve new
1406  * information to it, we never have to save anything. However, it is
1407  * our responsibility to copy the information when saving to a new
1408  * storage.
1409  *
1410  * See Windows documentation for more details on IPersistStorage methods.
1411  */
1412 static HRESULT WINAPI DataCache_Save(
1413             IPersistStorage* iface,
1414             IStorage*        pStg,
1415             BOOL             fSameAsLoad)
1416 {
1417     DataCache *This = impl_from_IPersistStorage(iface);
1418     DataCacheEntry *cache_entry;
1419     BOOL dirty = FALSE;
1420     HRESULT hr = S_OK;
1421     unsigned short stream_number = 0;
1422
1423     TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1424
1425     dirty = This->dirty;
1426     if (!dirty)
1427     {
1428         LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1429         {
1430             dirty = cache_entry->dirty;
1431             if (dirty)
1432                 break;
1433         }
1434     }
1435
1436     /* this is a shortcut if nothing changed */
1437     if (!dirty && !fSameAsLoad && This->presentationStorage)
1438     {
1439         return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1440     }
1441
1442     /* assign stream numbers to the cache entries */
1443     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1444     {
1445         if (cache_entry->stream_number != stream_number)
1446         {
1447             cache_entry->dirty = TRUE; /* needs to be written out again */
1448             cache_entry->stream_number = stream_number;
1449         }
1450         stream_number++;
1451     }
1452
1453     /* write out the cache entries */
1454     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1455     {
1456         if (!fSameAsLoad || cache_entry->dirty)
1457         {
1458             hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1459             if (FAILED(hr))
1460                 break;
1461
1462             cache_entry->dirty = FALSE;
1463         }
1464     }
1465
1466     This->dirty = FALSE;
1467     return hr;
1468 }
1469
1470 /************************************************************************
1471  * DataCache_SaveCompleted (IPersistStorage)
1472  *
1473  * This method is called to tell the cache to release the storage
1474  * pointer it's currently holding.
1475  *
1476  * See Windows documentation for more details on IPersistStorage methods.
1477  */
1478 static HRESULT WINAPI DataCache_SaveCompleted(
1479             IPersistStorage* iface,
1480             IStorage*        pStgNew)
1481 {
1482   TRACE("(%p, %p)\n", iface, pStgNew);
1483
1484   if (pStgNew)
1485   {
1486   /*
1487    * First, make sure we get our hands off any storage we have.
1488    */
1489
1490   IPersistStorage_HandsOffStorage(iface);
1491
1492   /*
1493    * Then, attach to the new storage.
1494    */
1495
1496   DataCache_Load(iface, pStgNew);
1497   }
1498
1499   return S_OK;
1500 }
1501
1502 /************************************************************************
1503  * DataCache_HandsOffStorage (IPersistStorage)
1504  *
1505  * This method is called to tell the cache to release the storage
1506  * pointer it's currently holding.
1507  *
1508  * See Windows documentation for more details on IPersistStorage methods.
1509  */
1510 static HRESULT WINAPI DataCache_HandsOffStorage(
1511             IPersistStorage* iface)
1512 {
1513   DataCache *this = impl_from_IPersistStorage(iface);
1514   DataCacheEntry *cache_entry;
1515
1516   TRACE("(%p)\n", iface);
1517
1518   if (this->presentationStorage != NULL)
1519   {
1520     IStorage_Release(this->presentationStorage);
1521     this->presentationStorage = NULL;
1522   }
1523
1524   LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1525     DataCacheEntry_HandsOffStorage(cache_entry);
1526
1527   return S_OK;
1528 }
1529
1530 /*********************************************************
1531  * Method implementation for the IViewObject2
1532  * part of the DataCache class.
1533  */
1534
1535 /************************************************************************
1536  * DataCache_IViewObject2_QueryInterface (IUnknown)
1537  *
1538  * See Windows documentation for more details on IUnknown methods.
1539  */
1540 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1541             IViewObject2* iface,
1542             REFIID           riid,
1543             void**           ppvObject)
1544 {
1545   DataCache *this = impl_from_IViewObject2(iface);
1546
1547   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1548 }
1549
1550 /************************************************************************
1551  * DataCache_IViewObject2_AddRef (IUnknown)
1552  *
1553  * See Windows documentation for more details on IUnknown methods.
1554  */
1555 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1556             IViewObject2* iface)
1557 {
1558   DataCache *this = impl_from_IViewObject2(iface);
1559
1560   return IUnknown_AddRef(this->outerUnknown);
1561 }
1562
1563 /************************************************************************
1564  * DataCache_IViewObject2_Release (IUnknown)
1565  *
1566  * See Windows documentation for more details on IUnknown methods.
1567  */
1568 static ULONG WINAPI DataCache_IViewObject2_Release(
1569             IViewObject2* iface)
1570 {
1571   DataCache *this = impl_from_IViewObject2(iface);
1572
1573   return IUnknown_Release(this->outerUnknown);
1574 }
1575
1576 /************************************************************************
1577  * DataCache_Draw (IViewObject2)
1578  *
1579  * This method will draw the cached representation of the object
1580  * to the given device context.
1581  *
1582  * See Windows documentation for more details on IViewObject2 methods.
1583  */
1584 static HRESULT WINAPI DataCache_Draw(
1585             IViewObject2*    iface,
1586             DWORD            dwDrawAspect,
1587             LONG             lindex,
1588             void*            pvAspect,
1589             DVTARGETDEVICE*  ptd,
1590             HDC              hdcTargetDev,
1591             HDC              hdcDraw,
1592             LPCRECTL         lprcBounds,
1593             LPCRECTL         lprcWBounds,
1594             BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1595             ULONG_PTR        dwContinue)
1596 {
1597   DataCache *This = impl_from_IViewObject2(iface);
1598   HRESULT                hres;
1599   DataCacheEntry        *cache_entry;
1600
1601   TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1602         iface,
1603         dwDrawAspect,
1604         lindex,
1605         pvAspect,
1606         hdcTargetDev,
1607         hdcDraw,
1608         lprcBounds,
1609         lprcWBounds,
1610         pfnContinue,
1611         dwContinue);
1612
1613   /*
1614    * Sanity check
1615    */
1616   if (lprcBounds==NULL)
1617     return E_INVALIDARG;
1618
1619   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1620   {
1621     /* FIXME: compare ptd too */
1622     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1623         (cache_entry->fmtetc.lindex != lindex))
1624       continue;
1625
1626     /* if the data hasn't been loaded yet, do it now */
1627     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1628     {
1629       hres = DataCacheEntry_LoadData(cache_entry);
1630       if (FAILED(hres))
1631         continue;
1632     }
1633
1634     /* no data */
1635     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1636       continue;
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!=NULL) &&
2290        (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
2291     return CLASS_E_NOAGGREGATION;
2292
2293   /*
2294    * Try to construct a new instance of the class.
2295    */
2296   newCache = DataCache_Construct(rclsid,
2297                                  pUnkOuter);
2298
2299   if (newCache == 0)
2300     return E_OUTOFMEMORY;
2301
2302   /*
2303    * Make sure it supports the interface required by the caller.
2304    */
2305   hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
2306
2307   /*
2308    * Release the reference obtained in the constructor. If
2309    * the QueryInterface was unsuccessful, it will free the class.
2310    */
2311   IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
2312
2313   return hr;
2314 }
2315
2316 /*********************************************************
2317  * Method implementation for DataCache class.
2318  */
2319 static DataCache* DataCache_Construct(
2320   REFCLSID  clsid,
2321   LPUNKNOWN pUnkOuter)
2322 {
2323   DataCache* newObject = 0;
2324
2325   /*
2326    * Allocate space for the object.
2327    */
2328   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2329
2330   if (newObject==0)
2331     return newObject;
2332
2333   /*
2334    * Initialize the virtual function table.
2335    */
2336   newObject->lpVtbl = &DataCache_IDataObject_VTable;
2337   newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
2338   newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
2339   newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
2340   newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
2341   newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
2342
2343   /*
2344    * Start with one reference count. The caller of this function
2345    * must release the interface pointer when it is done.
2346    */
2347   newObject->ref = 1;
2348
2349   /*
2350    * Initialize the outer unknown
2351    * We don't keep a reference on the outer unknown since, the way
2352    * aggregation works, our lifetime is at least as large as its
2353    * lifetime.
2354    */
2355   if (pUnkOuter==NULL)
2356     pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
2357
2358   newObject->outerUnknown = pUnkOuter;
2359
2360   /*
2361    * Initialize the other members of the structure.
2362    */
2363   newObject->sinkAspects = 0;
2364   newObject->sinkAdviseFlag = 0;
2365   newObject->sinkInterface = 0;
2366   newObject->presentationStorage = NULL;
2367   list_init(&newObject->cache_list);
2368   newObject->last_cache_id = 1;
2369   newObject->dirty = FALSE;
2370
2371   return newObject;
2372 }