opengl32: Avoid generating a wrapper for internal functions when we can call the...
[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 const char * debugstr_formatetc(const FORMATETC *formatetc)
193 {
194     return wine_dbg_sprintf("{ 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 = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc));
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 static HRESULT DataCacheEntry_GetData(DataCacheEntry *This,
736                                       STGMEDIUM *stgmedium)
737 {
738     if (stgmedium->tymed == TYMED_NULL && This->storage)
739     {
740         HRESULT hr = DataCacheEntry_LoadData(This);
741         if (FAILED(hr))
742             return hr;
743     }
744     if (stgmedium->tymed == TYMED_NULL)
745         return OLE_E_BLANK;
746     return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium);
747 }
748
749 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
750 {
751     ReleaseStgMedium(&This->stgmedium);
752     This->data_cf = This->fmtetc.cfFormat;
753     return S_OK;
754 }
755
756 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This)
757 {
758     if (This->storage)
759     {
760         IStorage_Release(This->storage);
761         This->storage = NULL;
762     }
763 }
764
765 /*********************************************************
766  * Method implementation for the  non delegating IUnknown
767  * part of the DataCache class.
768  */
769
770 /************************************************************************
771  * DataCache_NDIUnknown_QueryInterface (IUnknown)
772  *
773  * See Windows documentation for more details on IUnknown methods.
774  *
775  * This version of QueryInterface will not delegate it's implementation
776  * to the outer unknown.
777  */
778 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
779             IUnknown*      iface,
780             REFIID         riid,
781             void**         ppvObject)
782 {
783   DataCache *this = impl_from_NDIUnknown(iface);
784
785   /*
786    * Perform a sanity check on the parameters.
787    */
788   if ( (this==0) || (ppvObject==0) )
789     return E_INVALIDARG;
790
791   /*
792    * Initialize the return parameter.
793    */
794   *ppvObject = 0;
795
796   /*
797    * Compare the riid with the interface IDs implemented by this object.
798    */
799   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
800   {
801     *ppvObject = iface;
802   }
803   else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
804   {
805     *ppvObject = (IDataObject*)&(this->lpVtbl);
806   }
807   else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0)  ||
808             (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
809   {
810     *ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
811   }
812   else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
813             (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
814   {
815     *ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
816   }
817   else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
818             (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
819   {
820     *ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
821   }
822   else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
823   {
824     *ppvObject = (IOleCacheControl*)&(this->lpvtblIOleCacheControl);
825   }
826
827   /*
828    * Check that we obtained an interface.
829    */
830   if ((*ppvObject)==0)
831   {
832     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
833     return E_NOINTERFACE;
834   }
835
836   /*
837    * Query Interface always increases the reference count by one when it is
838    * successful.
839    */
840   IUnknown_AddRef((IUnknown*)*ppvObject);
841
842   return S_OK;
843 }
844
845 /************************************************************************
846  * DataCache_NDIUnknown_AddRef (IUnknown)
847  *
848  * See Windows documentation for more details on IUnknown methods.
849  *
850  * This version of QueryInterface will not delegate it's implementation
851  * to the outer unknown.
852  */
853 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
854             IUnknown*      iface)
855 {
856   DataCache *this = impl_from_NDIUnknown(iface);
857   return InterlockedIncrement(&this->ref);
858 }
859
860 /************************************************************************
861  * DataCache_NDIUnknown_Release (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 ULONG WINAPI DataCache_NDIUnknown_Release(
869             IUnknown*      iface)
870 {
871   DataCache *this = impl_from_NDIUnknown(iface);
872   ULONG ref;
873
874   /*
875    * Decrease the reference count on this object.
876    */
877   ref = InterlockedDecrement(&this->ref);
878
879   /*
880    * If the reference count goes down to 0, perform suicide.
881    */
882   if (ref == 0) DataCache_Destroy(this);
883
884   return ref;
885 }
886
887 /*********************************************************
888  * Method implementation for the IDataObject
889  * part of the DataCache class.
890  */
891
892 /************************************************************************
893  * DataCache_IDataObject_QueryInterface (IUnknown)
894  *
895  * See Windows documentation for more details on IUnknown methods.
896  */
897 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
898             IDataObject*     iface,
899             REFIID           riid,
900             void**           ppvObject)
901 {
902   DataCache *this = impl_from_IDataObject(iface);
903
904   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
905 }
906
907 /************************************************************************
908  * DataCache_IDataObject_AddRef (IUnknown)
909  *
910  * See Windows documentation for more details on IUnknown methods.
911  */
912 static ULONG WINAPI DataCache_IDataObject_AddRef(
913             IDataObject*     iface)
914 {
915   DataCache *this = impl_from_IDataObject(iface);
916
917   return IUnknown_AddRef(this->outerUnknown);
918 }
919
920 /************************************************************************
921  * DataCache_IDataObject_Release (IUnknown)
922  *
923  * See Windows documentation for more details on IUnknown methods.
924  */
925 static ULONG WINAPI DataCache_IDataObject_Release(
926             IDataObject*     iface)
927 {
928   DataCache *this = impl_from_IDataObject(iface);
929
930   return IUnknown_Release(this->outerUnknown);
931 }
932
933 /************************************************************************
934  * DataCache_GetData
935  *
936  * Get Data from a source dataobject using format pformatetcIn->cfFormat
937  * See Windows documentation for more details on GetData.
938  */
939 static HRESULT WINAPI DataCache_GetData(
940             IDataObject*     iface,
941             LPFORMATETC      pformatetcIn,
942             STGMEDIUM*       pmedium)
943 {
944     DataCache *This = impl_from_IDataObject(iface);
945     DataCacheEntry *cache_entry;
946
947     memset(pmedium, 0, sizeof(*pmedium));
948
949     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
950     if (!cache_entry)
951         return OLE_E_BLANK;
952
953     return DataCacheEntry_GetData(cache_entry, pmedium);
954 }
955
956 static HRESULT WINAPI DataCache_GetDataHere(
957             IDataObject*     iface,
958             LPFORMATETC      pformatetc,
959             STGMEDIUM*       pmedium)
960 {
961   FIXME("stub\n");
962   return E_NOTIMPL;
963 }
964
965 static HRESULT WINAPI DataCache_QueryGetData(
966             IDataObject*     iface,
967             LPFORMATETC      pformatetc)
968 {
969   FIXME("stub\n");
970   return E_NOTIMPL;
971 }
972
973 /************************************************************************
974  * DataCache_EnumFormatEtc (IDataObject)
975  *
976  * The data cache doesn't implement this method.
977  *
978  * See Windows documentation for more details on IDataObject methods.
979  */
980 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
981             IDataObject*     iface,
982             LPFORMATETC      pformatectIn,
983             LPFORMATETC      pformatetcOut)
984 {
985   TRACE("()\n");
986   return E_NOTIMPL;
987 }
988
989 /************************************************************************
990  * DataCache_IDataObject_SetData (IDataObject)
991  *
992  * This method is delegated to the IOleCache2 implementation.
993  *
994  * See Windows documentation for more details on IDataObject methods.
995  */
996 static HRESULT WINAPI DataCache_IDataObject_SetData(
997             IDataObject*     iface,
998             LPFORMATETC      pformatetc,
999             STGMEDIUM*       pmedium,
1000             BOOL             fRelease)
1001 {
1002   IOleCache2* oleCache = NULL;
1003   HRESULT     hres;
1004
1005   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1006
1007   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1008
1009   if (FAILED(hres))
1010     return E_UNEXPECTED;
1011
1012   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1013
1014   IOleCache2_Release(oleCache);
1015
1016   return hres;
1017 }
1018
1019 /************************************************************************
1020  * DataCache_EnumFormatEtc (IDataObject)
1021  *
1022  * The data cache doesn't implement this method.
1023  *
1024  * See Windows documentation for more details on IDataObject methods.
1025  */
1026 static HRESULT WINAPI DataCache_EnumFormatEtc(
1027             IDataObject*     iface,
1028             DWORD            dwDirection,
1029             IEnumFORMATETC** ppenumFormatEtc)
1030 {
1031   TRACE("()\n");
1032   return E_NOTIMPL;
1033 }
1034
1035 /************************************************************************
1036  * DataCache_DAdvise (IDataObject)
1037  *
1038  * The data cache doesn't support connections.
1039  *
1040  * See Windows documentation for more details on IDataObject methods.
1041  */
1042 static HRESULT WINAPI DataCache_DAdvise(
1043             IDataObject*     iface,
1044             FORMATETC*       pformatetc,
1045             DWORD            advf,
1046             IAdviseSink*     pAdvSink,
1047             DWORD*           pdwConnection)
1048 {
1049   TRACE("()\n");
1050   return OLE_E_ADVISENOTSUPPORTED;
1051 }
1052
1053 /************************************************************************
1054  * DataCache_DUnadvise (IDataObject)
1055  *
1056  * The data cache doesn't support connections.
1057  *
1058  * See Windows documentation for more details on IDataObject methods.
1059  */
1060 static HRESULT WINAPI DataCache_DUnadvise(
1061             IDataObject*     iface,
1062             DWORD            dwConnection)
1063 {
1064   TRACE("()\n");
1065   return OLE_E_NOCONNECTION;
1066 }
1067
1068 /************************************************************************
1069  * DataCache_EnumDAdvise (IDataObject)
1070  *
1071  * The data cache doesn't support connections.
1072  *
1073  * See Windows documentation for more details on IDataObject methods.
1074  */
1075 static HRESULT WINAPI DataCache_EnumDAdvise(
1076             IDataObject*     iface,
1077             IEnumSTATDATA**  ppenumAdvise)
1078 {
1079   TRACE("()\n");
1080   return OLE_E_ADVISENOTSUPPORTED;
1081 }
1082
1083 /*********************************************************
1084  * Method implementation for the IDataObject
1085  * part of the DataCache class.
1086  */
1087
1088 /************************************************************************
1089  * DataCache_IPersistStorage_QueryInterface (IUnknown)
1090  *
1091  * See Windows documentation for more details on IUnknown methods.
1092  */
1093 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1094             IPersistStorage* iface,
1095             REFIID           riid,
1096             void**           ppvObject)
1097 {
1098   DataCache *this = impl_from_IPersistStorage(iface);
1099
1100   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1101 }
1102
1103 /************************************************************************
1104  * DataCache_IPersistStorage_AddRef (IUnknown)
1105  *
1106  * See Windows documentation for more details on IUnknown methods.
1107  */
1108 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1109             IPersistStorage* iface)
1110 {
1111   DataCache *this = impl_from_IPersistStorage(iface);
1112
1113   return IUnknown_AddRef(this->outerUnknown);
1114 }
1115
1116 /************************************************************************
1117  * DataCache_IPersistStorage_Release (IUnknown)
1118  *
1119  * See Windows documentation for more details on IUnknown methods.
1120  */
1121 static ULONG WINAPI DataCache_IPersistStorage_Release(
1122             IPersistStorage* iface)
1123 {
1124   DataCache *this = impl_from_IPersistStorage(iface);
1125
1126   return IUnknown_Release(this->outerUnknown);
1127 }
1128
1129 /************************************************************************
1130  * DataCache_GetClassID (IPersistStorage)
1131  *
1132  * The data cache doesn't implement this method.
1133  *
1134  * See Windows documentation for more details on IPersistStorage methods.
1135  */
1136 static HRESULT WINAPI DataCache_GetClassID(
1137             IPersistStorage* iface,
1138             CLSID*           pClassID)
1139 {
1140   DataCache *This = impl_from_IPersistStorage(iface);
1141   DataCacheEntry *cache_entry;
1142
1143   TRACE("(%p, %p)\n", iface, pClassID);
1144
1145   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1146   {
1147     if (cache_entry->storage != NULL)
1148     {
1149       STATSTG statstg;
1150       HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
1151       if (SUCCEEDED(hr))
1152       {
1153         memcpy(pClassID, &statstg.clsid, sizeof(*pClassID));
1154         return S_OK;
1155       }
1156     }
1157   }
1158
1159   memcpy(pClassID, &CLSID_NULL, sizeof(*pClassID));
1160
1161   return S_OK;
1162 }
1163
1164 /************************************************************************
1165  * DataCache_IsDirty (IPersistStorage)
1166  *
1167  * See Windows documentation for more details on IPersistStorage methods.
1168  */
1169 static HRESULT WINAPI DataCache_IsDirty(
1170             IPersistStorage* iface)
1171 {
1172     DataCache *This = impl_from_IPersistStorage(iface);
1173     DataCacheEntry *cache_entry;
1174
1175     TRACE("(%p)\n", iface);
1176
1177     if (This->dirty)
1178         return S_OK;
1179
1180     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1181         if (cache_entry->dirty)
1182             return S_OK;
1183
1184     return S_FALSE;
1185 }
1186
1187 /************************************************************************
1188  * DataCache_InitNew (IPersistStorage)
1189  *
1190  * The data cache implementation of IPersistStorage_InitNew simply stores
1191  * the storage pointer.
1192  *
1193  * See Windows documentation for more details on IPersistStorage methods.
1194  */
1195 static HRESULT WINAPI DataCache_InitNew(
1196             IPersistStorage* iface,
1197             IStorage*        pStg)
1198 {
1199     DataCache *This = impl_from_IPersistStorage(iface);
1200
1201     TRACE("(%p, %p)\n", iface, pStg);
1202
1203     if (This->presentationStorage != NULL)
1204         IStorage_Release(This->presentationStorage);
1205
1206     This->presentationStorage = pStg;
1207
1208     IStorage_AddRef(This->presentationStorage);
1209     This->dirty = TRUE;
1210
1211     return S_OK;
1212 }
1213
1214 /************************************************************************
1215  * DataCache_Load (IPersistStorage)
1216  *
1217  * The data cache implementation of IPersistStorage_Load doesn't
1218  * actually load anything. Instead, it holds on to the storage pointer
1219  * and it will load the presentation information when the
1220  * IDataObject_GetData or IViewObject2_Draw methods are called.
1221  *
1222  * See Windows documentation for more details on IPersistStorage methods.
1223  */
1224 static HRESULT WINAPI DataCache_Load(
1225             IPersistStorage* iface,
1226             IStorage*        pStg)
1227 {
1228     DataCache *This = impl_from_IPersistStorage(iface);
1229     STATSTG elem;
1230     IEnumSTATSTG *pEnum;
1231     HRESULT hr;
1232
1233     TRACE("(%p, %p)\n", iface, pStg);
1234
1235     if (This->presentationStorage != NULL)
1236       IStorage_Release(This->presentationStorage);
1237
1238     This->presentationStorage = pStg;
1239
1240     hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
1241     if (FAILED(hr)) return hr;
1242
1243     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
1244     {
1245         if (DataCache_IsPresentationStream(&elem))
1246         {
1247             IStream *pStm;
1248
1249             hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
1250                                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
1251                                      &pStm);
1252             if (SUCCEEDED(hr))
1253             {
1254                 PresentationDataHeader header;
1255                 ULONG actual_read;
1256
1257                 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
1258
1259                 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
1260                 if (hr == S_OK && actual_read == sizeof(header))
1261                 {
1262                     DataCacheEntry *cache_entry;
1263                     FORMATETC fmtetc;
1264
1265                     fmtetc.cfFormat = header.clipformat;
1266                     fmtetc.ptd = NULL; /* FIXME */
1267                     fmtetc.dwAspect = header.dvAspect;
1268                     fmtetc.lindex = header.lindex;
1269                     fmtetc.tymed = header.tymed;
1270
1271                     TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
1272
1273                     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
1274                     if (!cache_entry)
1275                         hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
1276                     if (SUCCEEDED(hr))
1277                     {
1278                         DataCacheEntry_DiscardData(cache_entry);
1279                         if (cache_entry->storage) IStorage_Release(cache_entry->storage);
1280                         cache_entry->storage = pStg;
1281                         IStorage_AddRef(pStg);
1282                         cache_entry->dirty = FALSE;
1283                     }
1284                 }
1285
1286                 IStream_Release(pStm);
1287             }
1288         }
1289
1290         CoTaskMemFree(elem.pwcsName);
1291     }
1292
1293     This->dirty = FALSE;
1294
1295     IEnumSTATSTG_Release(pEnum);
1296
1297     IStorage_AddRef(This->presentationStorage);
1298     return S_OK;
1299 }
1300
1301 /************************************************************************
1302  * DataCache_Save (IPersistStorage)
1303  *
1304  * Until we actually connect to a running object and retrieve new
1305  * information to it, we never have to save anything. However, it is
1306  * our responsibility to copy the information when saving to a new
1307  * storage.
1308  *
1309  * See Windows documentation for more details on IPersistStorage methods.
1310  */
1311 static HRESULT WINAPI DataCache_Save(
1312             IPersistStorage* iface,
1313             IStorage*        pStg,
1314             BOOL             fSameAsLoad)
1315 {
1316     DataCache *This = impl_from_IPersistStorage(iface);
1317     DataCacheEntry *cache_entry;
1318     BOOL dirty = FALSE;
1319     HRESULT hr = S_OK;
1320     unsigned short stream_number = 0;
1321
1322     TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1323
1324     dirty = This->dirty;
1325     if (!dirty)
1326     {
1327         LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1328         {
1329             dirty = cache_entry->dirty;
1330             if (dirty)
1331                 break;
1332         }
1333     }
1334
1335     /* this is a shortcut if nothing changed */
1336     if (!dirty && !fSameAsLoad && This->presentationStorage)
1337     {
1338         return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
1339     }
1340
1341     /* assign stream numbers to the cache entries */
1342     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1343     {
1344         if (cache_entry->stream_number != stream_number)
1345         {
1346             cache_entry->dirty = TRUE; /* needs to be written out again */
1347             cache_entry->stream_number = stream_number;
1348         }
1349         stream_number++;
1350     }
1351
1352     /* write out the cache entries */
1353     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1354     {
1355         if (!fSameAsLoad || cache_entry->dirty)
1356         {
1357             hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
1358             if (FAILED(hr))
1359                 break;
1360
1361             cache_entry->dirty = FALSE;
1362         }
1363     }
1364
1365     This->dirty = FALSE;
1366     return hr;
1367 }
1368
1369 /************************************************************************
1370  * DataCache_SaveCompleted (IPersistStorage)
1371  *
1372  * This method is called to tell the cache to release the storage
1373  * pointer it's currently holding.
1374  *
1375  * See Windows documentation for more details on IPersistStorage methods.
1376  */
1377 static HRESULT WINAPI DataCache_SaveCompleted(
1378             IPersistStorage* iface,
1379             IStorage*        pStgNew)
1380 {
1381   TRACE("(%p, %p)\n", iface, pStgNew);
1382
1383   if (pStgNew)
1384   {
1385   /*
1386    * First, make sure we get our hands off any storage we have.
1387    */
1388
1389   IPersistStorage_HandsOffStorage(iface);
1390
1391   /*
1392    * Then, attach to the new storage.
1393    */
1394
1395   DataCache_Load(iface, pStgNew);
1396   }
1397
1398   return S_OK;
1399 }
1400
1401 /************************************************************************
1402  * DataCache_HandsOffStorage (IPersistStorage)
1403  *
1404  * This method is called to tell the cache to release the storage
1405  * pointer it's currently holding.
1406  *
1407  * See Windows documentation for more details on IPersistStorage methods.
1408  */
1409 static HRESULT WINAPI DataCache_HandsOffStorage(
1410             IPersistStorage* iface)
1411 {
1412   DataCache *this = impl_from_IPersistStorage(iface);
1413   DataCacheEntry *cache_entry;
1414
1415   TRACE("(%p)\n", iface);
1416
1417   if (this->presentationStorage != NULL)
1418   {
1419     IStorage_Release(this->presentationStorage);
1420     this->presentationStorage = NULL;
1421   }
1422
1423   LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
1424     DataCacheEntry_HandsOffStorage(cache_entry);
1425
1426   return S_OK;
1427 }
1428
1429 /*********************************************************
1430  * Method implementation for the IViewObject2
1431  * part of the DataCache class.
1432  */
1433
1434 /************************************************************************
1435  * DataCache_IViewObject2_QueryInterface (IUnknown)
1436  *
1437  * See Windows documentation for more details on IUnknown methods.
1438  */
1439 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1440             IViewObject2* iface,
1441             REFIID           riid,
1442             void**           ppvObject)
1443 {
1444   DataCache *this = impl_from_IViewObject2(iface);
1445
1446   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1447 }
1448
1449 /************************************************************************
1450  * DataCache_IViewObject2_AddRef (IUnknown)
1451  *
1452  * See Windows documentation for more details on IUnknown methods.
1453  */
1454 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1455             IViewObject2* iface)
1456 {
1457   DataCache *this = impl_from_IViewObject2(iface);
1458
1459   return IUnknown_AddRef(this->outerUnknown);
1460 }
1461
1462 /************************************************************************
1463  * DataCache_IViewObject2_Release (IUnknown)
1464  *
1465  * See Windows documentation for more details on IUnknown methods.
1466  */
1467 static ULONG WINAPI DataCache_IViewObject2_Release(
1468             IViewObject2* iface)
1469 {
1470   DataCache *this = impl_from_IViewObject2(iface);
1471
1472   return IUnknown_Release(this->outerUnknown);
1473 }
1474
1475 /************************************************************************
1476  * DataCache_Draw (IViewObject2)
1477  *
1478  * This method will draw the cached representation of the object
1479  * to the given device context.
1480  *
1481  * See Windows documentation for more details on IViewObject2 methods.
1482  */
1483 static HRESULT WINAPI DataCache_Draw(
1484             IViewObject2*    iface,
1485             DWORD            dwDrawAspect,
1486             LONG             lindex,
1487             void*            pvAspect,
1488             DVTARGETDEVICE*  ptd,
1489             HDC              hdcTargetDev,
1490             HDC              hdcDraw,
1491             LPCRECTL         lprcBounds,
1492             LPCRECTL         lprcWBounds,
1493             BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
1494             ULONG_PTR        dwContinue)
1495 {
1496   DataCache *This = impl_from_IViewObject2(iface);
1497   HRESULT                hres;
1498   DataCacheEntry        *cache_entry;
1499
1500   TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
1501         iface,
1502         dwDrawAspect,
1503         lindex,
1504         pvAspect,
1505         hdcTargetDev,
1506         hdcDraw,
1507         lprcBounds,
1508         lprcWBounds,
1509         pfnContinue,
1510         dwContinue);
1511
1512   /*
1513    * Sanity check
1514    */
1515   if (lprcBounds==NULL)
1516     return E_INVALIDARG;
1517
1518   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1519   {
1520     /* FIXME: compare ptd too */
1521     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1522         (cache_entry->fmtetc.lindex != lindex))
1523       continue;
1524
1525     /* if the data hasn't been loaded yet, do it now */
1526     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1527     {
1528       hres = DataCacheEntry_LoadData(cache_entry);
1529       if (FAILED(hres))
1530         continue;
1531     }
1532
1533     /* no data */
1534     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1535       continue;
1536
1537     switch (cache_entry->data_cf)
1538     {
1539       case CF_METAFILEPICT:
1540       {
1541         /*
1542          * We have to be careful not to modify the state of the
1543          * DC.
1544          */
1545         INT   prevMapMode;
1546         SIZE  oldWindowExt;
1547         SIZE  oldViewportExt;
1548         POINT oldViewportOrg;
1549         METAFILEPICT *mfpict;
1550
1551         if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1552             !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1553           continue;
1554
1555         prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
1556
1557         SetWindowExtEx(hdcDraw,
1558                        mfpict->xExt,
1559                        mfpict->yExt,
1560                        &oldWindowExt);
1561
1562         SetViewportExtEx(hdcDraw,
1563                          lprcBounds->right - lprcBounds->left,
1564                          lprcBounds->bottom - lprcBounds->top,
1565                          &oldViewportExt);
1566
1567         SetViewportOrgEx(hdcDraw,
1568                          lprcBounds->left,
1569                          lprcBounds->top,
1570                          &oldViewportOrg);
1571
1572         PlayMetaFile(hdcDraw, mfpict->hMF);
1573
1574         SetWindowExtEx(hdcDraw,
1575                        oldWindowExt.cx,
1576                        oldWindowExt.cy,
1577                        NULL);
1578
1579         SetViewportExtEx(hdcDraw,
1580                          oldViewportExt.cx,
1581                          oldViewportExt.cy,
1582                          NULL);
1583
1584         SetViewportOrgEx(hdcDraw,
1585                          oldViewportOrg.x,
1586                          oldViewportOrg.y,
1587                          NULL);
1588
1589         SetMapMode(hdcDraw, prevMapMode);
1590
1591         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1592
1593         return S_OK;
1594       }
1595     }
1596   }
1597
1598   WARN("no data could be found to be drawn\n");
1599
1600   return OLE_E_BLANK;
1601 }
1602
1603 static HRESULT WINAPI DataCache_GetColorSet(
1604             IViewObject2*   iface,
1605             DWORD           dwDrawAspect,
1606             LONG            lindex,
1607             void*           pvAspect,
1608             DVTARGETDEVICE* ptd,
1609             HDC             hicTargetDevice,
1610             LOGPALETTE**    ppColorSet)
1611 {
1612   FIXME("stub\n");
1613   return E_NOTIMPL;
1614 }
1615
1616 static HRESULT WINAPI DataCache_Freeze(
1617             IViewObject2*   iface,
1618             DWORD           dwDrawAspect,
1619             LONG            lindex,
1620             void*           pvAspect,
1621             DWORD*          pdwFreeze)
1622 {
1623   FIXME("stub\n");
1624   return E_NOTIMPL;
1625 }
1626
1627 static HRESULT WINAPI DataCache_Unfreeze(
1628             IViewObject2*   iface,
1629             DWORD           dwFreeze)
1630 {
1631   FIXME("stub\n");
1632   return E_NOTIMPL;
1633 }
1634
1635 /************************************************************************
1636  * DataCache_SetAdvise (IViewObject2)
1637  *
1638  * This sets-up an advisory sink with the data cache. When the object's
1639  * view changes, this sink is called.
1640  *
1641  * See Windows documentation for more details on IViewObject2 methods.
1642  */
1643 static HRESULT WINAPI DataCache_SetAdvise(
1644             IViewObject2*   iface,
1645             DWORD           aspects,
1646             DWORD           advf,
1647             IAdviseSink*    pAdvSink)
1648 {
1649   DataCache *this = impl_from_IViewObject2(iface);
1650
1651   TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
1652
1653   /*
1654    * A call to this function removes the previous sink
1655    */
1656   if (this->sinkInterface != NULL)
1657   {
1658     IAdviseSink_Release(this->sinkInterface);
1659     this->sinkInterface  = NULL;
1660     this->sinkAspects    = 0;
1661     this->sinkAdviseFlag = 0;
1662   }
1663
1664   /*
1665    * Now, setup the new one.
1666    */
1667   if (pAdvSink!=NULL)
1668   {
1669     this->sinkInterface  = pAdvSink;
1670     this->sinkAspects    = aspects;
1671     this->sinkAdviseFlag = advf;
1672
1673     IAdviseSink_AddRef(this->sinkInterface);
1674   }
1675
1676   /*
1677    * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1678    * sink immediately.
1679    */
1680   if (advf & ADVF_PRIMEFIRST)
1681   {
1682     DataCache_FireOnViewChange(this, aspects, -1);
1683   }
1684
1685   return S_OK;
1686 }
1687
1688 /************************************************************************
1689  * DataCache_GetAdvise (IViewObject2)
1690  *
1691  * This method queries the current state of the advise sink
1692  * installed on the data cache.
1693  *
1694  * See Windows documentation for more details on IViewObject2 methods.
1695  */
1696 static HRESULT WINAPI DataCache_GetAdvise(
1697             IViewObject2*   iface,
1698             DWORD*          pAspects,
1699             DWORD*          pAdvf,
1700             IAdviseSink**   ppAdvSink)
1701 {
1702   DataCache *this = impl_from_IViewObject2(iface);
1703
1704   TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1705
1706   /*
1707    * Just copy all the requested values.
1708    */
1709   if (pAspects!=NULL)
1710     *pAspects = this->sinkAspects;
1711
1712   if (pAdvf!=NULL)
1713     *pAdvf = this->sinkAdviseFlag;
1714
1715   if (ppAdvSink!=NULL)
1716   {
1717     if (this->sinkInterface != NULL)
1718         IAdviseSink_QueryInterface(this->sinkInterface,
1719                                &IID_IAdviseSink,
1720                                (void**)ppAdvSink);
1721     else *ppAdvSink = NULL;
1722   }
1723
1724   return S_OK;
1725 }
1726
1727 /************************************************************************
1728  * DataCache_GetExtent (IViewObject2)
1729  *
1730  * This method retrieves the "natural" size of this cached object.
1731  *
1732  * See Windows documentation for more details on IViewObject2 methods.
1733  */
1734 static HRESULT WINAPI DataCache_GetExtent(
1735             IViewObject2*   iface,
1736             DWORD           dwDrawAspect,
1737             LONG            lindex,
1738             DVTARGETDEVICE* ptd,
1739             LPSIZEL         lpsizel)
1740 {
1741   DataCache *This = impl_from_IViewObject2(iface);
1742   HRESULT                hres = E_FAIL;
1743   DataCacheEntry        *cache_entry;
1744
1745   TRACE("(%p, %x, %d, %p, %p)\n",
1746         iface, dwDrawAspect, lindex, ptd, lpsizel);
1747
1748   /*
1749    * Sanity check
1750    */
1751   if (lpsizel==NULL)
1752     return E_POINTER;
1753
1754   /*
1755    * Initialize the out parameter.
1756    */
1757   lpsizel->cx = 0;
1758   lpsizel->cy = 0;
1759
1760   /*
1761    * This flag should be set to -1.
1762    */
1763   if (lindex!=-1)
1764     FIXME("Unimplemented flag lindex = %d\n", lindex);
1765
1766   /*
1767    * Right now, we support only the callback from
1768    * the default handler.
1769    */
1770   if (ptd!=NULL)
1771     FIXME("Unimplemented ptd = %p\n", ptd);
1772
1773   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1774   {
1775     /* FIXME: compare ptd too */
1776     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
1777         (cache_entry->fmtetc.lindex != lindex))
1778       continue;
1779
1780     /* if the data hasn't been loaded yet, do it now */
1781     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
1782     {
1783       hres = DataCacheEntry_LoadData(cache_entry);
1784       if (FAILED(hres))
1785         continue;
1786     }
1787
1788     /* no data */
1789     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1790       continue;
1791
1792
1793     switch (cache_entry->data_cf)
1794     {
1795       case CF_METAFILEPICT:
1796       {
1797           METAFILEPICT *mfpict;
1798
1799           if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
1800               !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
1801             continue;
1802
1803         lpsizel->cx = mfpict->xExt;
1804         lpsizel->cy = mfpict->yExt;
1805
1806         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
1807
1808         return S_OK;
1809       }
1810     }
1811   }
1812
1813   WARN("no data could be found to get the extents from\n");
1814
1815   /*
1816    * This method returns OLE_E_BLANK when it fails.
1817    */
1818   return OLE_E_BLANK;
1819 }
1820
1821
1822 /*********************************************************
1823  * Method implementation for the IOleCache2
1824  * part of the DataCache class.
1825  */
1826
1827 /************************************************************************
1828  * DataCache_IOleCache2_QueryInterface (IUnknown)
1829  *
1830  * See Windows documentation for more details on IUnknown methods.
1831  */
1832 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1833             IOleCache2*     iface,
1834             REFIID          riid,
1835             void**          ppvObject)
1836 {
1837   DataCache *this = impl_from_IOleCache2(iface);
1838
1839   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
1840 }
1841
1842 /************************************************************************
1843  * DataCache_IOleCache2_AddRef (IUnknown)
1844  *
1845  * See Windows documentation for more details on IUnknown methods.
1846  */
1847 static ULONG WINAPI DataCache_IOleCache2_AddRef(
1848             IOleCache2*     iface)
1849 {
1850   DataCache *this = impl_from_IOleCache2(iface);
1851
1852   return IUnknown_AddRef(this->outerUnknown);
1853 }
1854
1855 /************************************************************************
1856  * DataCache_IOleCache2_Release (IUnknown)
1857  *
1858  * See Windows documentation for more details on IUnknown methods.
1859  */
1860 static ULONG WINAPI DataCache_IOleCache2_Release(
1861             IOleCache2*     iface)
1862 {
1863   DataCache *this = impl_from_IOleCache2(iface);
1864
1865   return IUnknown_Release(this->outerUnknown);
1866 }
1867
1868 static HRESULT WINAPI DataCache_Cache(
1869             IOleCache2*     iface,
1870             FORMATETC*      pformatetc,
1871             DWORD           advf,
1872             DWORD*          pdwConnection)
1873 {
1874     DataCache *This = impl_from_IOleCache2(iface);
1875     DataCacheEntry *cache_entry;
1876     HRESULT hr;
1877
1878     TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
1879     TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
1880
1881     *pdwConnection = 0;
1882
1883     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1884     if (cache_entry)
1885     {
1886         TRACE("found an existing cache entry\n");
1887         *pdwConnection = cache_entry->id;
1888         return CACHE_S_SAMECACHE;
1889     }
1890
1891     hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
1892
1893     if (SUCCEEDED(hr))
1894         *pdwConnection = cache_entry->id;
1895
1896     return hr;
1897 }
1898
1899 static HRESULT WINAPI DataCache_Uncache(
1900             IOleCache2*     iface,
1901             DWORD           dwConnection)
1902 {
1903     DataCache *This = impl_from_IOleCache2(iface);
1904     DataCacheEntry *cache_entry;
1905
1906     TRACE("(%d)\n", dwConnection);
1907
1908     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1909         if (cache_entry->id == dwConnection)
1910         {
1911             DataCacheEntry_Destroy(cache_entry);
1912             return S_OK;
1913         }
1914
1915     WARN("no connection found for %d\n", dwConnection);
1916
1917     return OLE_E_NOCONNECTION;
1918 }
1919
1920 static HRESULT WINAPI DataCache_EnumCache(
1921             IOleCache2*     iface,
1922             IEnumSTATDATA** ppenumSTATDATA)
1923 {
1924   FIXME("stub\n");
1925   return E_NOTIMPL;
1926 }
1927
1928 static HRESULT WINAPI DataCache_InitCache(
1929             IOleCache2*     iface,
1930             IDataObject*    pDataObject)
1931 {
1932   FIXME("stub\n");
1933   return E_NOTIMPL;
1934 }
1935
1936 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1937             IOleCache2*     iface,
1938             FORMATETC*      pformatetc,
1939             STGMEDIUM*      pmedium,
1940             BOOL            fRelease)
1941 {
1942     DataCache *This = impl_from_IOleCache2(iface);
1943     DataCacheEntry *cache_entry;
1944     HRESULT hr;
1945
1946     TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
1947     TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
1948
1949     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
1950     if (cache_entry)
1951     {
1952         hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
1953
1954         if (SUCCEEDED(hr))
1955             DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
1956                                        cache_entry->fmtetc.lindex);
1957
1958         return hr;
1959     }
1960     WARN("cache entry not found\n");
1961
1962     return OLE_E_BLANK;
1963 }
1964
1965 static HRESULT WINAPI DataCache_UpdateCache(
1966             IOleCache2*     iface,
1967             LPDATAOBJECT    pDataObject,
1968             DWORD           grfUpdf,
1969             LPVOID          pReserved)
1970 {
1971   FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
1972   return E_NOTIMPL;
1973 }
1974
1975 static HRESULT WINAPI DataCache_DiscardCache(
1976             IOleCache2*     iface,
1977             DWORD           dwDiscardOptions)
1978 {
1979     DataCache *This = impl_from_IOleCache2(iface);
1980     DataCacheEntry *cache_entry;
1981     HRESULT hr = S_OK;
1982
1983     TRACE("(%d)\n", dwDiscardOptions);
1984
1985     if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
1986         hr = DataCache_Save((IPersistStorage *)&This->lpvtblIPersistStorage,
1987                             This->presentationStorage, TRUE);
1988
1989     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1990     {
1991         hr = DataCacheEntry_DiscardData(cache_entry);
1992         if (FAILED(hr))
1993             break;
1994     }
1995
1996     return hr;
1997 }
1998
1999
2000 /*********************************************************
2001  * Method implementation for the IOleCacheControl
2002  * part of the DataCache class.
2003  */
2004
2005 /************************************************************************
2006  * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2007  *
2008  * See Windows documentation for more details on IUnknown methods.
2009  */
2010 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2011             IOleCacheControl* iface,
2012             REFIID            riid,
2013             void**            ppvObject)
2014 {
2015   DataCache *this = impl_from_IOleCacheControl(iface);
2016
2017   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
2018 }
2019
2020 /************************************************************************
2021  * DataCache_IOleCacheControl_AddRef (IUnknown)
2022  *
2023  * See Windows documentation for more details on IUnknown methods.
2024  */
2025 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2026             IOleCacheControl* iface)
2027 {
2028   DataCache *this = impl_from_IOleCacheControl(iface);
2029
2030   return IUnknown_AddRef(this->outerUnknown);
2031 }
2032
2033 /************************************************************************
2034  * DataCache_IOleCacheControl_Release (IUnknown)
2035  *
2036  * See Windows documentation for more details on IUnknown methods.
2037  */
2038 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2039             IOleCacheControl* iface)
2040 {
2041   DataCache *this = impl_from_IOleCacheControl(iface);
2042
2043   return IUnknown_Release(this->outerUnknown);
2044 }
2045
2046 static HRESULT WINAPI DataCache_OnRun(
2047             IOleCacheControl* iface,
2048             LPDATAOBJECT      pDataObject)
2049 {
2050   FIXME("stub\n");
2051   return E_NOTIMPL;
2052 }
2053
2054 static HRESULT WINAPI DataCache_OnStop(
2055             IOleCacheControl* iface)
2056 {
2057   FIXME("stub\n");
2058   return E_NOTIMPL;
2059 }
2060
2061 /*
2062  * Virtual function tables for the DataCache class.
2063  */
2064 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2065 {
2066   DataCache_NDIUnknown_QueryInterface,
2067   DataCache_NDIUnknown_AddRef,
2068   DataCache_NDIUnknown_Release
2069 };
2070
2071 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2072 {
2073   DataCache_IDataObject_QueryInterface,
2074   DataCache_IDataObject_AddRef,
2075   DataCache_IDataObject_Release,
2076   DataCache_GetData,
2077   DataCache_GetDataHere,
2078   DataCache_QueryGetData,
2079   DataCache_GetCanonicalFormatEtc,
2080   DataCache_IDataObject_SetData,
2081   DataCache_EnumFormatEtc,
2082   DataCache_DAdvise,
2083   DataCache_DUnadvise,
2084   DataCache_EnumDAdvise
2085 };
2086
2087 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2088 {
2089   DataCache_IPersistStorage_QueryInterface,
2090   DataCache_IPersistStorage_AddRef,
2091   DataCache_IPersistStorage_Release,
2092   DataCache_GetClassID,
2093   DataCache_IsDirty,
2094   DataCache_InitNew,
2095   DataCache_Load,
2096   DataCache_Save,
2097   DataCache_SaveCompleted,
2098   DataCache_HandsOffStorage
2099 };
2100
2101 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2102 {
2103   DataCache_IViewObject2_QueryInterface,
2104   DataCache_IViewObject2_AddRef,
2105   DataCache_IViewObject2_Release,
2106   DataCache_Draw,
2107   DataCache_GetColorSet,
2108   DataCache_Freeze,
2109   DataCache_Unfreeze,
2110   DataCache_SetAdvise,
2111   DataCache_GetAdvise,
2112   DataCache_GetExtent
2113 };
2114
2115 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2116 {
2117   DataCache_IOleCache2_QueryInterface,
2118   DataCache_IOleCache2_AddRef,
2119   DataCache_IOleCache2_Release,
2120   DataCache_Cache,
2121   DataCache_Uncache,
2122   DataCache_EnumCache,
2123   DataCache_InitCache,
2124   DataCache_IOleCache2_SetData,
2125   DataCache_UpdateCache,
2126   DataCache_DiscardCache
2127 };
2128
2129 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2130 {
2131   DataCache_IOleCacheControl_QueryInterface,
2132   DataCache_IOleCacheControl_AddRef,
2133   DataCache_IOleCacheControl_Release,
2134   DataCache_OnRun,
2135   DataCache_OnStop
2136 };
2137
2138 /******************************************************************************
2139  *              CreateDataCache        [OLE32.@]
2140  *
2141  * Creates a data cache to allow an object to render one or more of its views,
2142  * whether running or not.
2143  *
2144  * PARAMS
2145  *  pUnkOuter [I] Outer unknown for the object.
2146  *  rclsid    [I]
2147  *  riid      [I] IID of interface to return.
2148  *  ppvObj    [O] Address where the data cache object will be stored on return.
2149  *
2150  * RETURNS
2151  *  Success: S_OK.
2152  *  Failure: HRESULT code.
2153  *
2154  * NOTES
2155  *  The following interfaces are supported by the returned data cache object:
2156  *  IOleCache, IOleCache2, IOleCacheControl, IPersistStorae, IDataObject,
2157  *  IViewObject and IViewObject2.
2158  */
2159 HRESULT WINAPI CreateDataCache(
2160   LPUNKNOWN pUnkOuter,
2161   REFCLSID  rclsid,
2162   REFIID    riid,
2163   LPVOID*   ppvObj)
2164 {
2165   DataCache* newCache = NULL;
2166   HRESULT    hr       = S_OK;
2167
2168   TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
2169
2170   /*
2171    * Sanity check
2172    */
2173   if (ppvObj==0)
2174     return E_POINTER;
2175
2176   *ppvObj = 0;
2177
2178   /*
2179    * If this cache is constructed for aggregation, make sure
2180    * the caller is requesting the IUnknown interface.
2181    * This is necessary because it's the only time the non-delegating
2182    * IUnknown pointer can be returned to the outside.
2183    */
2184   if ( (pUnkOuter!=NULL) &&
2185        (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
2186     return CLASS_E_NOAGGREGATION;
2187
2188   /*
2189    * Try to construct a new instance of the class.
2190    */
2191   newCache = DataCache_Construct(rclsid,
2192                                  pUnkOuter);
2193
2194   if (newCache == 0)
2195     return E_OUTOFMEMORY;
2196
2197   /*
2198    * Make sure it supports the interface required by the caller.
2199    */
2200   hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtblNDIUnknown), riid, ppvObj);
2201
2202   /*
2203    * Release the reference obtained in the constructor. If
2204    * the QueryInterface was unsuccessful, it will free the class.
2205    */
2206   IUnknown_Release((IUnknown*)&(newCache->lpvtblNDIUnknown));
2207
2208   return hr;
2209 }
2210
2211 /*********************************************************
2212  * Method implementation for DataCache class.
2213  */
2214 static DataCache* DataCache_Construct(
2215   REFCLSID  clsid,
2216   LPUNKNOWN pUnkOuter)
2217 {
2218   DataCache* newObject = 0;
2219
2220   /*
2221    * Allocate space for the object.
2222    */
2223   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2224
2225   if (newObject==0)
2226     return newObject;
2227
2228   /*
2229    * Initialize the virtual function table.
2230    */
2231   newObject->lpVtbl = &DataCache_IDataObject_VTable;
2232   newObject->lpvtblNDIUnknown = &DataCache_NDIUnknown_VTable;
2233   newObject->lpvtblIPersistStorage = &DataCache_IPersistStorage_VTable;
2234   newObject->lpvtblIViewObject = &DataCache_IViewObject2_VTable;
2235   newObject->lpvtblIOleCache2 = &DataCache_IOleCache2_VTable;
2236   newObject->lpvtblIOleCacheControl = &DataCache_IOleCacheControl_VTable;
2237
2238   /*
2239    * Start with one reference count. The caller of this function
2240    * must release the interface pointer when it is done.
2241    */
2242   newObject->ref = 1;
2243
2244   /*
2245    * Initialize the outer unknown
2246    * We don't keep a reference on the outer unknown since, the way
2247    * aggregation works, our lifetime is at least as large as its
2248    * lifetime.
2249    */
2250   if (pUnkOuter==NULL)
2251     pUnkOuter = (IUnknown*)&(newObject->lpvtblNDIUnknown);
2252
2253   newObject->outerUnknown = pUnkOuter;
2254
2255   /*
2256    * Initialize the other members of the structure.
2257    */
2258   newObject->sinkAspects = 0;
2259   newObject->sinkAdviseFlag = 0;
2260   newObject->sinkInterface = 0;
2261   newObject->presentationStorage = NULL;
2262   list_init(&newObject->cache_list);
2263   newObject->last_cache_id = 1;
2264   newObject->dirty = FALSE;
2265
2266   return newObject;
2267 }