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