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