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