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