xref: /reactos/dll/win32/ole32/datacache.c (revision d5399189)
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 
47 #include <stdarg.h>
48 #include <string.h>
49 
50 #define COBJMACROS
51 #define NONAMELESSUNION
52 
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "winerror.h"
58 #include "ole2.h"
59 #include "compobj_private.h"
60 #include "wine/unicode.h"
61 #include "wine/list.h"
62 #include "wine/debug.h"
63 
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65 
66 /****************************************************************************
67  * PresentationDataHeader
68  *
69  * This structure represents the header of the \002OlePresXXX stream in
70  * the OLE object storage.
71  */
72 typedef struct PresentationDataHeader
73 {
74   /* clipformat:
75    *  - standard clipformat:
76    *  DWORD length = 0xffffffff;
77    *  DWORD cfFormat;
78    *  - or custom clipformat:
79    *  DWORD length;
80    *  CHAR format_name[length]; (null-terminated)
81    */
82   DWORD tdSize; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD)
83                    then there are tdSize - sizeof(DWORD) more bytes before dvAspect */
84   DVASPECT dvAspect;
85   DWORD lindex;
86   DWORD advf;
87   DWORD unknown7;	/* 0 */
88   DWORD dwObjectExtentX;
89   DWORD dwObjectExtentY;
90   DWORD dwSize;
91 } PresentationDataHeader;
92 
93 #define STREAM_NUMBER_NOT_SET -2
94 #define STREAM_NUMBER_CONTENTS -1 /* CONTENTS stream */
95 
96 typedef struct DataCacheEntry
97 {
98   struct list entry;
99   /* format of this entry */
100   FORMATETC fmtetc;
101   /* cached data */
102   STGMEDIUM stgmedium;
103   /* connection ID */
104   DWORD id;
105   /* dirty flag */
106   BOOL dirty;
107   /* stream number that the entry was loaded from.
108      This is used to defer loading until the data is actually needed. */
109   int load_stream_num;
110   /* stream number that the entry will be saved to.
111      This may differ from above if cache entries have been Uncache()d for example. */
112   int save_stream_num;
113   /* sink id set when object is running */
114   DWORD sink_id;
115   /* Advise sink flags */
116   DWORD advise_flags;
117 } DataCacheEntry;
118 
119 /****************************************************************************
120  * DataCache
121  */
122 struct DataCache
123 {
124   /*
125    * List all interface here
126    */
127   IUnknown          IUnknown_inner;
128   IDataObject       IDataObject_iface;
129   IPersistStorage   IPersistStorage_iface;
130   IViewObject2      IViewObject2_iface;
131   IOleCache2        IOleCache2_iface;
132   IOleCacheControl  IOleCacheControl_iface;
133 
134   /* The sink that is connected to a remote object.
135      The other interfaces are not available by QI'ing the sink and vice-versa */
136   IAdviseSink       IAdviseSink_iface;
137 
138   /*
139    * Reference count of this object
140    */
141   LONG ref;
142 
143   /*
144    * IUnknown implementation of the outer object.
145    */
146   IUnknown *outer_unk;
147 
148   /*
149    * The user of this object can setup ONE advise sink
150    * connection with the object. These parameters describe
151    * that connection.
152    */
153   DWORD        sinkAspects;
154   DWORD        sinkAdviseFlag;
155   IAdviseSink *sinkInterface;
156 
157   CLSID clsid;
158   /* Is the clsid one of the CLSID_Picture classes */
159   BOOL clsid_static;
160 
161   IStorage *presentationStorage;
162 
163   /* list of cache entries */
164   struct list cache_list;
165   /* last id assigned to an entry */
166   DWORD last_cache_id;
167   /* dirty flag */
168   BOOL dirty;
169   /* running object set by OnRun */
170   IDataObject *running_object;
171 };
172 
173 typedef struct DataCache DataCache;
174 
175 /*
176  * Here, I define utility macros to help with the casting of the
177  * "this" parameter.
178  * There is a version to accommodate all of the VTables implemented
179  * by this object.
180  */
181 
182 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
183 {
184     return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
185 }
186 
187 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
188 {
189     return CONTAINING_RECORD(iface, DataCache, IUnknown_inner);
190 }
191 
192 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
193 {
194     return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
195 }
196 
197 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
198 {
199     return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
200 }
201 
202 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
203 {
204     return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
205 }
206 
207 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
208 {
209     return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
210 }
211 
212 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
213 {
214     return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
215 }
216 
217 const char *debugstr_formatetc(const FORMATETC *formatetc)
218 {
219     return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
220         formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
221         formatetc->lindex, formatetc->tymed);
222 }
223 
224 /***********************************************************************
225  *           bitmap_info_size
226  *
227  * Return the size of the bitmap info structure including color table.
228  */
229 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
230 {
231     unsigned int colors, size, masks = 0;
232 
233     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
234     {
235         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
236         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
237         return sizeof(BITMAPCOREHEADER) + colors *
238             ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
239     }
240     else  /* assume BITMAPINFOHEADER */
241     {
242         colors = info->bmiHeader.biClrUsed;
243         if (colors > 256) /* buffer overflow otherwise */
244             colors = 256;
245         if (!colors && (info->bmiHeader.biBitCount <= 8))
246             colors = 1 << info->bmiHeader.biBitCount;
247         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
248         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
249         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
250     }
251 }
252 
253 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
254 {
255     list_remove(&cache_entry->entry);
256     CoTaskMemFree(cache_entry->fmtetc.ptd);
257     ReleaseStgMedium(&cache_entry->stgmedium);
258     if(cache_entry->sink_id)
259         IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
260 
261     HeapFree(GetProcessHeap(), 0, cache_entry);
262 }
263 
264 static void DataCache_Destroy(
265   DataCache* ptrToDestroy)
266 {
267   DataCacheEntry *cache_entry, *next_cache_entry;
268 
269   TRACE("()\n");
270 
271   if (ptrToDestroy->sinkInterface != NULL)
272   {
273     IAdviseSink_Release(ptrToDestroy->sinkInterface);
274     ptrToDestroy->sinkInterface = NULL;
275   }
276 
277   LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
278     DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
279 
280   if (ptrToDestroy->presentationStorage != NULL)
281   {
282     IStorage_Release(ptrToDestroy->presentationStorage);
283     ptrToDestroy->presentationStorage = NULL;
284   }
285 
286   /*
287    * Free the datacache pointer.
288    */
289   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
290 }
291 
292 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
293 {
294     DataCacheEntry *cache_entry;
295     FORMATETC fmt = *formatetc;
296 
297     if (fmt.cfFormat == CF_BITMAP)
298     {
299         fmt.cfFormat = CF_DIB;
300         fmt.tymed = TYMED_HGLOBAL;
301     }
302 
303     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
304     {
305         /* FIXME: also compare DVTARGETDEVICEs */
306         if ((fmt.cfFormat == cache_entry->fmtetc.cfFormat) &&
307             (fmt.dwAspect == cache_entry->fmtetc.dwAspect) &&
308             (fmt.lindex == cache_entry->fmtetc.lindex) &&
309             ((fmt.tymed == cache_entry->fmtetc.tymed) || !cache_entry->fmtetc.cfFormat)) /* tymed is ignored for view caching */
310             return cache_entry;
311     }
312     return NULL;
313 }
314 
315 /* Returns the cache entry associated with a static CLSID.
316    This will be first in the list with connection id == 1 */
317 static HRESULT get_static_entry( DataCache *cache, DataCacheEntry **cache_entry )
318 {
319     DataCacheEntry *entry;
320     struct list *head = list_head( &cache->cache_list );
321     HRESULT hr = E_FAIL;
322 
323     *cache_entry = NULL;
324 
325     if (head)
326     {
327         entry = LIST_ENTRY( head, DataCacheEntry, entry );
328         if (entry->id == 1)
329         {
330             *cache_entry = entry;
331             hr = S_OK;
332         }
333     }
334 
335     return hr;
336 }
337 
338 /* checks that the clipformat and tymed are valid and returns an error if they
339 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
340 * DataCache_Draw */
341 static HRESULT check_valid_formatetc( const FORMATETC *fmt )
342 {
343     /* DVASPECT_ICON must be CF_METAFILEPICT */
344     if (fmt->dwAspect == DVASPECT_ICON && fmt->cfFormat != CF_METAFILEPICT)
345         return DV_E_FORMATETC;
346 
347     if (!fmt->cfFormat ||
348         (fmt->cfFormat == CF_METAFILEPICT && fmt->tymed == TYMED_MFPICT) ||
349         (fmt->cfFormat == CF_BITMAP && fmt->tymed == TYMED_GDI) ||
350         (fmt->cfFormat == CF_DIB && fmt->tymed == TYMED_HGLOBAL) ||
351         (fmt->cfFormat == CF_ENHMETAFILE && fmt->tymed == TYMED_ENHMF))
352         return S_OK;
353     else if (fmt->tymed == TYMED_HGLOBAL)
354         return CACHE_S_FORMATETC_NOTSUPPORTED;
355     else
356     {
357         WARN("invalid clipformat/tymed combination: %d/%d\n", fmt->cfFormat, fmt->tymed);
358         return DV_E_TYMED;
359     }
360 }
361 
362 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf,
363                              DWORD id)
364 {
365     HRESULT hr;
366 
367     hr = copy_formatetc(&entry->fmtetc, fmt);
368     if (FAILED(hr)) return FALSE;
369 
370     entry->stgmedium.tymed = TYMED_NULL;
371     entry->stgmedium.pUnkForRelease = NULL;
372     entry->id = id;
373     entry->dirty = TRUE;
374     entry->load_stream_num = STREAM_NUMBER_NOT_SET;
375     entry->save_stream_num = STREAM_NUMBER_NOT_SET;
376     entry->sink_id = 0;
377     entry->advise_flags = advf;
378 
379     return TRUE;
380 }
381 
382 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf,
383                                      BOOL automatic, DataCacheEntry **cache_entry)
384 {
385     HRESULT hr;
386     DWORD id = automatic ? 1 : This->last_cache_id;
387     DataCacheEntry *entry;
388 
389     hr = check_valid_formatetc( formatetc );
390     if (FAILED(hr))
391         return hr;
392     if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
393         TRACE("creating unsupported format %d\n", formatetc->cfFormat);
394 
395     entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
396     if (!entry)
397         return E_OUTOFMEMORY;
398 
399     if (!init_cache_entry(entry, formatetc, advf, id))
400         goto fail;
401 
402     if (automatic)
403         list_add_head(&This->cache_list, &entry->entry);
404     else
405     {
406         list_add_tail(&This->cache_list, &entry->entry);
407         This->last_cache_id++;
408     }
409 
410     if (cache_entry) *cache_entry = entry;
411     return hr;
412 
413 fail:
414     HeapFree(GetProcessHeap(), 0, entry);
415     return E_OUTOFMEMORY;
416 }
417 
418 /************************************************************************
419  * DataCache_FireOnViewChange
420  *
421  * This method will fire an OnViewChange notification to the advise
422  * sink registered with the datacache.
423  *
424  * See IAdviseSink::OnViewChange for more details.
425  */
426 static void DataCache_FireOnViewChange(
427   DataCache* this,
428   DWORD      aspect,
429   LONG       lindex)
430 {
431   TRACE("(%p, %x, %d)\n", this, aspect, lindex);
432 
433   /*
434    * The sink supplies a filter when it registers
435    * we make sure we only send the notifications when that
436    * filter matches.
437    */
438   if ((this->sinkAspects & aspect) != 0)
439   {
440     if (this->sinkInterface != NULL)
441     {
442       IAdviseSink_OnViewChange(this->sinkInterface,
443 			       aspect,
444 			       lindex);
445 
446       /*
447        * Some sinks want to be unregistered automatically when
448        * the first notification goes out.
449        */
450       if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
451       {
452 	IAdviseSink_Release(this->sinkInterface);
453 
454 	this->sinkInterface  = NULL;
455 	this->sinkAspects    = 0;
456 	this->sinkAdviseFlag = 0;
457       }
458     }
459   }
460 }
461 
462 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
463 {
464     DWORD length;
465     HRESULT hr;
466     ULONG read;
467 
468     *clipformat = 0;
469 
470     hr = IStream_Read(stream, &length, sizeof(length), &read);
471     if (hr != S_OK || read != sizeof(length))
472         return DV_E_CLIPFORMAT;
473     if (!length) {
474         /* No clipboard format present */
475         return S_OK;
476     }
477     if (length == -1)
478     {
479         DWORD cf;
480         hr = IStream_Read(stream, &cf, sizeof(cf), &read);
481         if (hr != S_OK || read != sizeof(cf))
482             return DV_E_CLIPFORMAT;
483         *clipformat = cf;
484     }
485     else
486     {
487         char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
488         if (!format_name)
489             return E_OUTOFMEMORY;
490         hr = IStream_Read(stream, format_name, length, &read);
491         if (hr != S_OK || read != length || format_name[length - 1] != '\0')
492         {
493             HeapFree(GetProcessHeap(), 0, format_name);
494             return DV_E_CLIPFORMAT;
495         }
496         *clipformat = RegisterClipboardFormatA(format_name);
497         HeapFree(GetProcessHeap(), 0, format_name);
498     }
499     return S_OK;
500 }
501 
502 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
503 {
504     DWORD length;
505     HRESULT hr;
506     char format_name[256];
507 
508     if (clipformat == 0)
509         length = 0;
510     else if (clipformat < 0xc000)
511         length = -1;
512     else
513     {
514         length = GetClipboardFormatNameA(clipformat, format_name, sizeof(format_name));
515         /* If there is a clipboard format name, we need to include its terminating \0 */
516         if (length) length++;
517     }
518     hr = IStream_Write(stream, &length, sizeof(length), NULL);
519     if (FAILED(hr) || clipformat == 0)
520         return hr;
521 
522     if (clipformat < 0xc000)
523     {
524         DWORD cf = clipformat;
525         hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
526     }
527     else
528     {
529         hr = IStream_Write(stream, format_name, length, NULL);
530     }
531     return hr;
532 }
533 
534 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0};
535 
536 static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm )
537 {
538     WCHAR pres[] = {2,'O','l','e','P','r','e','s',
539                     '0' + (stream_number / 100) % 10,
540                     '0' + (stream_number / 10) % 10,
541                     '0' + stream_number % 10, 0};
542     const WCHAR *name = pres;
543 
544     if (stream_number == STREAM_NUMBER_NOT_SET) return E_FAIL;
545     if (stream_number == STREAM_NUMBER_CONTENTS) name = CONTENTS;
546 
547     return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
548 }
549 
550 static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med )
551 {
552     METAFILEPICT *pict;
553     HRESULT hr = E_FAIL;
554     UINT size;
555     void *bits;
556 
557     if (!(pict = GlobalLock( data ))) return hr;
558 
559     size = GetMetaFileBitsEx( pict->hMF, 0, NULL );
560     if ((bits = HeapAlloc( GetProcessHeap(), 0, size )))
561     {
562         GetMetaFileBitsEx( pict->hMF, size, bits );
563         med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict );
564         HeapFree( GetProcessHeap(), 0, bits );
565         med->tymed = TYMED_ENHMF;
566         med->pUnkForRelease = NULL;
567         hr = S_OK;
568     }
569 
570     GlobalUnlock( data );
571     return hr;
572 }
573 #include <pshpack2.h>
574 struct meta_placeable
575 {
576     DWORD key;
577     WORD hwmf;
578     WORD bounding_box[4];
579     WORD inch;
580     DWORD reserved;
581     WORD checksum;
582 };
583 #include <poppack.h>
584 
585 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm )
586 {
587     HRESULT hr;
588     STATSTG stat;
589     ULARGE_INTEGER current_pos;
590     void *bits;
591     METAFILEPICT *mfpict;
592     HGLOBAL hmfpict;
593     PresentationDataHeader header;
594     CLIPFORMAT clipformat;
595     static const LARGE_INTEGER offset_zero;
596     ULONG read;
597     struct meta_placeable mf_place;
598 
599     hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
600     if (FAILED( hr )) return hr;
601 
602     if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
603     {
604         hr = read_clipformat( stm, &clipformat );
605         if (hr != S_OK) return hr;
606         hr = IStream_Read( stm, &header, sizeof(header), &read );
607         if (hr != S_OK) return hr;
608     }
609     else
610     {
611         hr = IStream_Read( stm, &mf_place, sizeof(mf_place), &read );
612         if (hr != S_OK) return hr;
613     }
614 
615     hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
616     if (FAILED( hr )) return hr;
617     stat.cbSize.QuadPart -= current_pos.QuadPart;
618 
619     hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) );
620     if (!hmfpict) return E_OUTOFMEMORY;
621     mfpict = GlobalLock( hmfpict );
622 
623     bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart);
624     if (!bits)
625     {
626         GlobalFree( hmfpict );
627         return E_OUTOFMEMORY;
628     }
629 
630     hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read );
631 
632     if (SUCCEEDED( hr ))
633     {
634         mfpict->mm = MM_ANISOTROPIC;
635         /* FIXME: get this from the stream */
636         if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
637         {
638             mfpict->xExt = header.dwObjectExtentX;
639             mfpict->yExt = header.dwObjectExtentY;
640         }
641         else
642         {
643             mfpict->xExt = ((mf_place.bounding_box[2] - mf_place.bounding_box[0])
644                             * 2540) / mf_place.inch;
645             mfpict->yExt = ((mf_place.bounding_box[3] - mf_place.bounding_box[1])
646                             * 2540) / mf_place.inch;
647         }
648         mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits );
649         if (!mfpict->hMF)
650             hr = E_FAIL;
651     }
652 
653     GlobalUnlock( hmfpict );
654     if (SUCCEEDED( hr ))
655     {
656         cache_entry->stgmedium.tymed = TYMED_MFPICT;
657         cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
658     }
659     else
660         GlobalFree( hmfpict );
661 
662     HeapFree( GetProcessHeap(), 0, bits );
663 
664     return hr;
665 }
666 
667 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm )
668 {
669     HRESULT hr;
670     STATSTG stat;
671     BYTE *dib;
672     HGLOBAL hglobal;
673     ULONG read, info_size, bi_size;
674     BITMAPFILEHEADER file;
675     BITMAPINFOHEADER *info;
676     CLIPFORMAT cf;
677     PresentationDataHeader pres;
678     ULARGE_INTEGER current_pos;
679     static const LARGE_INTEGER offset_zero;
680 
681     hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
682     if (FAILED( hr )) return hr;
683 
684     if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
685     {
686         hr = read_clipformat( stm, &cf );
687         if (hr != S_OK) return hr;
688         hr = IStream_Read( stm, &pres, sizeof(pres), &read );
689         if (hr != S_OK) return hr;
690     }
691     else
692     {
693         hr = IStream_Read( stm, &file, sizeof(BITMAPFILEHEADER), &read );
694         if (hr != S_OK) return hr;
695     }
696 
697     hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, &current_pos );
698     if (FAILED( hr )) return hr;
699     stat.cbSize.QuadPart -= current_pos.QuadPart;
700 
701     hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart );
702     if (!hglobal) return E_OUTOFMEMORY;
703     dib = GlobalLock( hglobal );
704 
705     /* read first DWORD of BITMAPINFOHEADER */
706     hr = IStream_Read( stm, dib, sizeof(DWORD), &read );
707     if (hr != S_OK) goto fail;
708     bi_size = *(DWORD *)dib;
709     if (stat.cbSize.QuadPart < bi_size) goto fail;
710 
711     /* read rest of BITMAPINFOHEADER */
712     hr = IStream_Read( stm, dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read );
713     if (hr != S_OK) goto fail;
714 
715     info_size = bitmap_info_size( (BITMAPINFO *)dib, DIB_RGB_COLORS );
716     if (stat.cbSize.QuadPart < info_size) goto fail;
717     if (info_size > bi_size)
718     {
719         hr = IStream_Read( stm, dib + bi_size, info_size - bi_size, &read );
720         if (hr != S_OK) goto fail;
721     }
722     stat.cbSize.QuadPart -= info_size;
723 
724     /* set Stream pointer to beginning of bitmap bits */
725     if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS && file.bfOffBits)
726     {
727         LARGE_INTEGER skip;
728 
729         skip.QuadPart = file.bfOffBits - sizeof(file) - info_size;
730         if (stat.cbSize.QuadPart < skip.QuadPart) goto fail;
731         hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL );
732         if (hr != S_OK) goto fail;
733         stat.cbSize.QuadPart -= skip.QuadPart;
734     }
735 
736     hr = IStream_Read( stm, dib + info_size, stat.cbSize.u.LowPart, &read );
737     if (hr != S_OK) goto fail;
738 
739     if (bi_size >= sizeof(*info))
740     {
741         info = (BITMAPINFOHEADER *)dib;
742         if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0)
743         {
744             HDC hdc = GetDC( 0 );
745             info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 );
746             info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 );
747             ReleaseDC( 0, hdc );
748         }
749     }
750 
751     GlobalUnlock( hglobal );
752 
753     cache_entry->stgmedium.tymed = TYMED_HGLOBAL;
754     cache_entry->stgmedium.u.hGlobal = hglobal;
755 
756     return hr;
757 
758 fail:
759     GlobalUnlock( hglobal );
760     GlobalFree( hglobal );
761     return hr;
762 
763 }
764 
765 static HRESULT load_emf( DataCacheEntry *cache_entry, IStream *stm )
766 {
767     HRESULT hr;
768 
769     if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS)
770     {
771         STGMEDIUM stgmed;
772 
773         hr = load_mf_pict( cache_entry, stm );
774         if (SUCCEEDED( hr ))
775         {
776             hr = synthesize_emf( cache_entry->stgmedium.u.hMetaFilePict, &stgmed );
777             ReleaseStgMedium( &cache_entry->stgmedium );
778         }
779         if (SUCCEEDED( hr ))
780             cache_entry->stgmedium = stgmed;
781     }
782     else
783     {
784         STATSTG stat;
785         BYTE *data;
786         ULONG read, size_bits;
787 
788         hr = IStream_Stat( stm, &stat, STATFLAG_NONAME );
789 
790         if (SUCCEEDED( hr ))
791         {
792             data = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart );
793             if (!data) return E_OUTOFMEMORY;
794 
795             hr = IStream_Read( stm, data, stat.cbSize.u.LowPart, &read );
796             if (hr != S_OK)
797             {
798                 HeapFree( GetProcessHeap(), 0, data );
799                 return hr;
800             }
801 
802             if (read <= sizeof(DWORD) + sizeof(ENHMETAHEADER))
803             {
804                 HeapFree( GetProcessHeap(), 0, data );
805                 return E_FAIL;
806             }
807             size_bits = read - sizeof(DWORD) - sizeof(ENHMETAHEADER);
808             cache_entry->stgmedium.u.hEnhMetaFile = SetEnhMetaFileBits( size_bits, data + (read - size_bits) );
809             cache_entry->stgmedium.tymed = TYMED_ENHMF;
810             cache_entry->stgmedium.pUnkForRelease = NULL;
811 
812             HeapFree( GetProcessHeap(), 0, data );
813         }
814     }
815 
816     return hr;
817 }
818 
819 /************************************************************************
820  * DataCacheEntry_LoadData
821  *
822  * This method will read information for the requested presentation
823  * into the given structure.
824  *
825  * Param:
826  *   This - The entry to load the data from.
827  *
828  * Returns:
829  *   This method returns a metafile handle if it is successful.
830  *   it will return 0 if not.
831  */
832 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *stg)
833 {
834     HRESULT hr;
835     IStream *stm;
836 
837     if (!stg) return OLE_E_BLANK;
838     hr = open_pres_stream( stg, cache_entry->load_stream_num, &stm );
839     if (FAILED(hr)) return hr;
840 
841     switch (cache_entry->fmtetc.cfFormat)
842     {
843     case CF_METAFILEPICT:
844         hr = load_mf_pict( cache_entry, stm );
845         break;
846 
847     case CF_DIB:
848         hr = load_dib( cache_entry, stm );
849         break;
850 
851     case CF_ENHMETAFILE:
852         hr = load_emf( cache_entry, stm );
853         break;
854 
855     default:
856         FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat );
857         hr = E_NOTIMPL;
858     }
859 
860     IStream_Release( stm );
861     return hr;
862 }
863 
864 static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header)
865 {
866     if (entry->fmtetc.ptd)
867         FIXME("ptd not serialized\n");
868     header->tdSize = sizeof(header->tdSize);
869     header->dvAspect = entry->fmtetc.dwAspect;
870     header->lindex = entry->fmtetc.lindex;
871     header->advf = entry->advise_flags;
872     header->unknown7 = 0;
873     header->dwObjectExtentX = 0;
874     header->dwObjectExtentY = 0;
875     header->dwSize = 0;
876 }
877 
878 static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream)
879 {
880     HRESULT hr = S_OK;
881     int data_size = 0;
882     BITMAPINFO *bmi = NULL;
883 
884     if (entry->stgmedium.tymed != TYMED_NULL)
885     {
886         data_size = GlobalSize(entry->stgmedium.u.hGlobal);
887         bmi = GlobalLock(entry->stgmedium.u.hGlobal);
888     }
889 
890     if (!contents)
891     {
892         PresentationDataHeader header;
893 
894         init_stream_header(entry, &header);
895         hr = write_clipformat(stream, entry->fmtetc.cfFormat);
896         if (FAILED(hr)) goto end;
897         if (data_size)
898         {
899             header.dwSize = data_size;
900             /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
901             if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0)
902             {
903                 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter);
904                 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter);
905             }
906             else
907             {
908                 HDC hdc = GetDC(0);
909                 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
910                 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
911                 ReleaseDC(0, hdc);
912             }
913         }
914         hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
915         if (hr == S_OK && data_size)
916             hr = IStream_Write(stream, bmi, data_size, NULL);
917     }
918     else if(data_size)
919     {
920         BITMAPFILEHEADER bmp_fhdr;
921 
922         bmp_fhdr.bfType = 0x4d42;
923         bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER);
924         bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0;
925         bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER);
926         hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL);
927         if (hr == S_OK)
928             hr = IStream_Write(stream, bmi, data_size, NULL);
929     }
930 
931 end:
932     if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal);
933     return hr;
934 }
935 
936 static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream)
937 {
938     HRESULT hr = S_OK;
939     int data_size = 0;
940     void *data = NULL;
941     METAFILEPICT *mfpict = NULL;
942 
943     if (!contents)
944     {
945         PresentationDataHeader header;
946 
947         init_stream_header(entry, &header);
948         hr = write_clipformat(stream, entry->fmtetc.cfFormat);
949         if (FAILED(hr)) return hr;
950         if (entry->stgmedium.tymed != TYMED_NULL)
951         {
952             mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
953             if (!mfpict)
954                 return DV_E_STGMEDIUM;
955             data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
956             header.dwObjectExtentX = mfpict->xExt;
957             header.dwObjectExtentY = mfpict->yExt;
958             header.dwSize = data_size;
959             data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
960             if (!data)
961             {
962                 GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
963                 return E_OUTOFMEMORY;
964             }
965             GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
966             GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
967         }
968         hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
969         if (hr == S_OK && data_size)
970             hr = IStream_Write(stream, data, data_size, NULL);
971         HeapFree(GetProcessHeap(), 0, data);
972     }
973     else if (entry->stgmedium.tymed != TYMED_NULL)
974     {
975         struct meta_placeable meta_place_rec;
976         WORD *check;
977 
978         mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict);
979         if (!mfpict)
980             return DV_E_STGMEDIUM;
981         data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
982         data = HeapAlloc(GetProcessHeap(), 0, data_size);
983         if (!data)
984         {
985             GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
986             return E_OUTOFMEMORY;
987         }
988         GetMetaFileBitsEx(mfpict->hMF, data_size, data);
989 
990         /* units are in 1/8th of a point (1 point is 1/72th of an inch) */
991         meta_place_rec.key = 0x9ac6cdd7;
992         meta_place_rec.hwmf = 0;
993         meta_place_rec.inch = 576;
994         meta_place_rec.bounding_box[0] = 0;
995         meta_place_rec.bounding_box[1] = 0;
996         meta_place_rec.bounding_box[2] = 0;
997         meta_place_rec.bounding_box[3] = 0;
998         meta_place_rec.checksum = 0;
999         meta_place_rec.reserved = 0;
1000 
1001         /* These values are rounded down so MulDiv won't do the right thing */
1002         meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540;
1003         meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540;
1004         GlobalUnlock(entry->stgmedium.u.hMetaFilePict);
1005 
1006         for (check = (WORD *)&meta_place_rec; check != (WORD *)&meta_place_rec.checksum; check++)
1007             meta_place_rec.checksum ^= *check;
1008         hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL);
1009         if (hr == S_OK && data_size)
1010             hr = IStream_Write(stream, data, data_size, NULL);
1011         HeapFree(GetProcessHeap(), 0, data);
1012     }
1013 
1014     return hr;
1015 }
1016 
1017 static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream)
1018 {
1019     HRESULT hr = S_OK;
1020     int data_size = 0;
1021     BYTE *data;
1022 
1023     if (!contents)
1024     {
1025         PresentationDataHeader header;
1026         METAFILEPICT *mfpict;
1027         HDC hdc = GetDC(0);
1028 
1029         init_stream_header(entry, &header);
1030         hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1031         if (FAILED(hr))
1032         {
1033             ReleaseDC(0, hdc);
1034             return hr;
1035         }
1036         data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc);
1037         header.dwSize = data_size;
1038         data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
1039         if (!data)
1040         {
1041             ReleaseDC(0, hdc);
1042             return E_OUTOFMEMORY;
1043         }
1044         GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc);
1045         ReleaseDC(0, hdc);
1046         mfpict = (METAFILEPICT *)data;
1047         header.dwObjectExtentX = mfpict->xExt;
1048         header.dwObjectExtentY = mfpict->yExt;
1049         hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL);
1050         if (hr == S_OK && data_size)
1051             hr = IStream_Write(stream, data, data_size, NULL);
1052         HeapFree(GetProcessHeap(), 0, data);
1053     }
1054     else if (entry->stgmedium.tymed != TYMED_NULL)
1055     {
1056         data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL);
1057         data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size);
1058         if (!data) return E_OUTOFMEMORY;
1059         *((DWORD *)data) = sizeof(ENHMETAHEADER);
1060         GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER));
1061         memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER));
1062         data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER);
1063         hr = IStream_Write(stream, data, data_size, NULL);
1064         HeapFree(GetProcessHeap(), 0, data);
1065     }
1066 
1067     return hr;
1068 }
1069 
1070 static HRESULT save_view_cache(DataCacheEntry *entry, IStream *stream)
1071 {
1072     HRESULT hr;
1073     PresentationDataHeader header;
1074 
1075     init_stream_header(entry, &header);
1076     hr = write_clipformat(stream, entry->fmtetc.cfFormat);
1077     if (SUCCEEDED(hr))
1078         hr = IStream_Write(stream, &header, FIELD_OFFSET(PresentationDataHeader, unknown7), NULL);
1079 
1080     return hr;
1081 }
1082 
1083 static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage,
1084                              BOOL contents, IStream **stream)
1085 {
1086     WCHAR pres[] = {2,'O','l','e','P','r','e','s',
1087         '0' + (cache_entry->save_stream_num / 100) % 10,
1088         '0' + (cache_entry->save_stream_num / 10) % 10,
1089         '0' + cache_entry->save_stream_num % 10, 0};
1090     const WCHAR *name;
1091 
1092     if (contents)
1093         name = CONTENTS;
1094     else
1095         name = pres;
1096 
1097     return IStorage_CreateStream(storage, name,
1098                                  STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
1099                                  0, 0, stream);
1100 }
1101 
1102 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
1103                                    BOOL same_as_load)
1104 {
1105     HRESULT hr;
1106     IStream *stream;
1107     BOOL contents = (cache_entry->id == 1);
1108 
1109     TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->save_stream_num, debugstr_formatetc(&cache_entry->fmtetc));
1110 
1111     hr = create_stream(cache_entry, storage, contents, &stream);
1112     if (FAILED(hr))
1113         return hr;
1114 
1115     switch (cache_entry->fmtetc.cfFormat)
1116     {
1117     case CF_DIB:
1118         hr = save_dib(cache_entry, contents, stream);
1119         break;
1120     case CF_METAFILEPICT:
1121         hr = save_mfpict(cache_entry, contents, stream);
1122         break;
1123     case CF_ENHMETAFILE:
1124         hr = save_emf(cache_entry, contents, stream);
1125         break;
1126     case 0:
1127         hr = save_view_cache(cache_entry, stream);
1128         break;
1129     default:
1130         FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat);
1131     }
1132 
1133     IStream_Release(stream);
1134     return hr;
1135 }
1136 
1137 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
1138 * does no checking of whether src_stgm has a supported tymed, so this should be
1139 * done in the caller */
1140 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
1141                                const STGMEDIUM *src_stgm)
1142 {
1143     if (src_stgm->tymed == TYMED_MFPICT)
1144     {
1145         const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
1146         METAFILEPICT *dest_mfpict;
1147 
1148         if (!src_mfpict)
1149             return DV_E_STGMEDIUM;
1150         dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
1151         dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
1152         if (!dest_mfpict)
1153         {
1154             GlobalUnlock(src_stgm->u.hMetaFilePict);
1155             return E_OUTOFMEMORY;
1156         }
1157         *dest_mfpict = *src_mfpict;
1158         dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
1159         GlobalUnlock(src_stgm->u.hMetaFilePict);
1160         GlobalUnlock(dest_stgm->u.hMetaFilePict);
1161     }
1162     else if (src_stgm->tymed != TYMED_NULL)
1163     {
1164         dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
1165                                                 GMEM_MOVEABLE);
1166         if (!dest_stgm->u.hGlobal)
1167             return E_OUTOFMEMORY;
1168     }
1169     dest_stgm->tymed = src_stgm->tymed;
1170     dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
1171     if (dest_stgm->pUnkForRelease)
1172         IUnknown_AddRef(dest_stgm->pUnkForRelease);
1173     return S_OK;
1174 }
1175 
1176 static HRESULT synthesize_dib( HBITMAP bm, STGMEDIUM *med )
1177 {
1178     HDC hdc = GetDC( 0 );
1179     BITMAPINFOHEADER header;
1180     BITMAPINFO *bmi;
1181     HRESULT hr = E_FAIL;
1182     DWORD header_size;
1183 
1184     memset( &header, 0, sizeof(header) );
1185     header.biSize = sizeof(header);
1186     if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done;
1187 
1188     header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS );
1189     if (!(med->u.hGlobal = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done;
1190     bmi = GlobalLock( med->u.hGlobal );
1191     memset( bmi, 0, header_size );
1192     memcpy( bmi, &header, header.biSize );
1193     GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS );
1194     GlobalUnlock( med->u.hGlobal );
1195     med->tymed = TYMED_HGLOBAL;
1196     med->pUnkForRelease = NULL;
1197     hr = S_OK;
1198 
1199 done:
1200     ReleaseDC( 0, hdc );
1201     return hr;
1202 }
1203 
1204 static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med )
1205 {
1206     HRESULT hr = E_FAIL;
1207     BITMAPINFO *bmi;
1208     HDC hdc = GetDC( 0 );
1209 
1210     if ((bmi = GlobalLock( dib )))
1211     {
1212         /* FIXME: validate data size */
1213         med->u.hBitmap = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT,
1214                                          (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ),
1215                                          bmi, DIB_RGB_COLORS );
1216         GlobalUnlock( dib );
1217         med->tymed = TYMED_GDI;
1218         med->pUnkForRelease = NULL;
1219         hr = S_OK;
1220     }
1221     ReleaseDC( 0, hdc );
1222     return hr;
1223 }
1224 
1225 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
1226                                       const FORMATETC *formatetc,
1227                                       STGMEDIUM *stgmedium,
1228                                       BOOL fRelease)
1229 {
1230     STGMEDIUM copy;
1231     HRESULT hr;
1232 
1233     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
1234         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
1235         stgmedium->tymed == TYMED_NULL)
1236     {
1237         WARN("invalid formatetc\n");
1238         return DV_E_FORMATETC;
1239     }
1240 
1241     cache_entry->dirty = TRUE;
1242     ReleaseStgMedium(&cache_entry->stgmedium);
1243 
1244     if (formatetc->cfFormat == CF_BITMAP)
1245     {
1246         hr = synthesize_dib( stgmedium->u.hBitmap, &copy );
1247         if (FAILED(hr)) return hr;
1248         if (fRelease) ReleaseStgMedium(stgmedium);
1249         stgmedium = &copy;
1250         fRelease = TRUE;
1251     }
1252     else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE)
1253     {
1254         hr = synthesize_emf( stgmedium->u.hMetaFilePict, &copy );
1255         if (FAILED(hr)) return hr;
1256         if (fRelease) ReleaseStgMedium(stgmedium);
1257         stgmedium = &copy;
1258         fRelease = TRUE;
1259     }
1260 
1261     if (fRelease)
1262     {
1263         cache_entry->stgmedium = *stgmedium;
1264         return S_OK;
1265     }
1266     else
1267         return copy_stg_medium(cache_entry->fmtetc.cfFormat, &cache_entry->stgmedium, stgmedium);
1268 }
1269 
1270 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, IStorage *stg, FORMATETC *fmt, STGMEDIUM *stgmedium)
1271 {
1272     if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET)
1273     {
1274         HRESULT hr = DataCacheEntry_LoadData(cache_entry, stg);
1275         if (FAILED(hr))
1276             return hr;
1277     }
1278     if (cache_entry->stgmedium.tymed == TYMED_NULL)
1279         return OLE_E_BLANK;
1280 
1281     if (fmt->cfFormat == CF_BITMAP)
1282         return synthesize_bitmap( cache_entry->stgmedium.u.hGlobal, stgmedium );
1283 
1284     return copy_stg_medium(cache_entry->fmtetc.cfFormat, stgmedium, &cache_entry->stgmedium);
1285 }
1286 
1287 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
1288 {
1289     ReleaseStgMedium(&cache_entry->stgmedium);
1290     return S_OK;
1291 }
1292 
1293 static inline DWORD tymed_from_cf( DWORD cf )
1294 {
1295     switch( cf )
1296     {
1297     case CF_BITMAP:       return TYMED_GDI;
1298     case CF_METAFILEPICT: return TYMED_MFPICT;
1299     case CF_ENHMETAFILE:  return TYMED_ENHMF;
1300     case CF_DIB:
1301     default:              return TYMED_HGLOBAL;
1302     }
1303 }
1304 
1305 /****************************************************************
1306  *  create_automatic_entry
1307  *
1308  * Creates an appropriate cache entry for one of the CLSID_Picture_
1309  * classes.  The connection id of the entry is one.  Any pre-existing
1310  * automatic entry is re-assigned a new connection id, and moved to
1311  * the end of the list.
1312  */
1313 static HRESULT create_automatic_entry(DataCache *cache, const CLSID *clsid)
1314 {
1315     static const struct data
1316     {
1317         const CLSID *clsid;
1318         FORMATETC fmt;
1319     } data[] =
1320     {
1321         { &CLSID_Picture_Dib,         { CF_DIB,          0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } },
1322         { &CLSID_Picture_Metafile,    { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT } },
1323         { &CLSID_Picture_EnhMetafile, { CF_ENHMETAFILE,  0, DVASPECT_CONTENT, -1, TYMED_ENHMF } },
1324         { NULL }
1325     };
1326     const struct data *ptr = data;
1327     struct list *head;
1328     DataCacheEntry *entry;
1329 
1330     if (IsEqualCLSID( &cache->clsid, clsid )) return S_OK;
1331 
1332     /* move and reassign any pre-existing automatic entry */
1333     if ((head = list_head( &cache->cache_list )))
1334     {
1335         entry = LIST_ENTRY( head, DataCacheEntry, entry );
1336         if (entry->id == 1)
1337         {
1338             list_remove( &entry->entry );
1339             entry->id = cache->last_cache_id++;
1340             list_add_tail( &cache->cache_list, &entry->entry );
1341         }
1342     }
1343 
1344     while (ptr->clsid)
1345     {
1346         if (IsEqualCLSID( clsid, ptr->clsid ))
1347         {
1348             cache->clsid_static = TRUE;
1349             return DataCache_CreateEntry( cache, &ptr->fmt, 0, TRUE, NULL );
1350         }
1351         ptr++;
1352     }
1353     cache->clsid_static = FALSE;
1354     return S_OK;
1355 }
1356 
1357 /*********************************************************
1358  * Method implementation for the  non delegating IUnknown
1359  * part of the DataCache class.
1360  */
1361 
1362 /************************************************************************
1363  * DataCache_NDIUnknown_QueryInterface (IUnknown)
1364  *
1365  * This version of QueryInterface will not delegate its implementation
1366  * to the outer unknown.
1367  */
1368 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
1369             IUnknown*      iface,
1370             REFIID         riid,
1371             void**         ppvObject)
1372 {
1373   DataCache *this = impl_from_IUnknown(iface);
1374 
1375   if ( ppvObject==0 )
1376     return E_INVALIDARG;
1377 
1378   *ppvObject = 0;
1379 
1380   if (IsEqualIID(&IID_IUnknown, riid))
1381   {
1382     if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */
1383       *ppvObject = &this->IOleCache2_iface;
1384     else
1385       *ppvObject = iface;
1386   }
1387   else if (IsEqualIID(&IID_IDataObject, riid))
1388   {
1389     *ppvObject = &this->IDataObject_iface;
1390   }
1391   else if ( IsEqualIID(&IID_IPersistStorage, riid)  ||
1392             IsEqualIID(&IID_IPersist, riid) )
1393   {
1394     *ppvObject = &this->IPersistStorage_iface;
1395   }
1396   else if ( IsEqualIID(&IID_IViewObject, riid) ||
1397             IsEqualIID(&IID_IViewObject2, riid) )
1398   {
1399     *ppvObject = &this->IViewObject2_iface;
1400   }
1401   else if ( IsEqualIID(&IID_IOleCache, riid) ||
1402             IsEqualIID(&IID_IOleCache2, riid) )
1403   {
1404     *ppvObject = &this->IOleCache2_iface;
1405   }
1406   else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
1407   {
1408     *ppvObject = &this->IOleCacheControl_iface;
1409   }
1410 
1411   if ((*ppvObject)==0)
1412   {
1413     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
1414     return E_NOINTERFACE;
1415   }
1416 
1417   IUnknown_AddRef((IUnknown*)*ppvObject);
1418 
1419   return S_OK;
1420 }
1421 
1422 /************************************************************************
1423  * DataCache_NDIUnknown_AddRef (IUnknown)
1424  *
1425  * This version of QueryInterface will not delegate its implementation
1426  * to the outer unknown.
1427  */
1428 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
1429             IUnknown*      iface)
1430 {
1431   DataCache *this = impl_from_IUnknown(iface);
1432   return InterlockedIncrement(&this->ref);
1433 }
1434 
1435 /************************************************************************
1436  * DataCache_NDIUnknown_Release (IUnknown)
1437  *
1438  * This version of QueryInterface will not delegate its implementation
1439  * to the outer unknown.
1440  */
1441 static ULONG WINAPI DataCache_NDIUnknown_Release(
1442             IUnknown*      iface)
1443 {
1444   DataCache *this = impl_from_IUnknown(iface);
1445   ULONG ref;
1446 
1447   ref = InterlockedDecrement(&this->ref);
1448 
1449   if (ref == 0) DataCache_Destroy(this);
1450 
1451   return ref;
1452 }
1453 
1454 /*********************************************************
1455  * Method implementation for the IDataObject
1456  * part of the DataCache class.
1457  */
1458 
1459 /************************************************************************
1460  * DataCache_IDataObject_QueryInterface (IUnknown)
1461  */
1462 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
1463             IDataObject*     iface,
1464             REFIID           riid,
1465             void**           ppvObject)
1466 {
1467   DataCache *this = impl_from_IDataObject(iface);
1468 
1469   return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1470 }
1471 
1472 /************************************************************************
1473  * DataCache_IDataObject_AddRef (IUnknown)
1474  */
1475 static ULONG WINAPI DataCache_IDataObject_AddRef(
1476             IDataObject*     iface)
1477 {
1478   DataCache *this = impl_from_IDataObject(iface);
1479 
1480   return IUnknown_AddRef(this->outer_unk);
1481 }
1482 
1483 /************************************************************************
1484  * DataCache_IDataObject_Release (IUnknown)
1485  */
1486 static ULONG WINAPI DataCache_IDataObject_Release(
1487             IDataObject*     iface)
1488 {
1489   DataCache *this = impl_from_IDataObject(iface);
1490 
1491   return IUnknown_Release(this->outer_unk);
1492 }
1493 
1494 /************************************************************************
1495  * DataCache_GetData
1496  *
1497  * Get Data from a source dataobject using format pformatetcIn->cfFormat
1498  */
1499 static HRESULT WINAPI DataCache_GetData(
1500 	    IDataObject*     iface,
1501 	    LPFORMATETC      pformatetcIn,
1502 	    STGMEDIUM*       pmedium)
1503 {
1504     DataCache *This = impl_from_IDataObject(iface);
1505     DataCacheEntry *cache_entry;
1506 
1507     TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium);
1508 
1509     memset(pmedium, 0, sizeof(*pmedium));
1510 
1511     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
1512     if (!cache_entry)
1513         return OLE_E_BLANK;
1514 
1515     return DataCacheEntry_GetData(cache_entry, This->presentationStorage, pformatetcIn, pmedium);
1516 }
1517 
1518 static HRESULT WINAPI DataCache_GetDataHere(
1519 	    IDataObject*     iface,
1520 	    LPFORMATETC      pformatetc,
1521 	    STGMEDIUM*       pmedium)
1522 {
1523   FIXME("stub\n");
1524   return E_NOTIMPL;
1525 }
1526 
1527 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt )
1528 {
1529     DataCache *This = impl_from_IDataObject( iface );
1530     DataCacheEntry *cache_entry;
1531 
1532     TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) );
1533     cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1534 
1535     return cache_entry ? S_OK : S_FALSE;
1536 }
1537 
1538 /************************************************************************
1539  * DataCache_EnumFormatEtc (IDataObject)
1540  *
1541  * The data cache doesn't implement this method.
1542  */
1543 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1544 	    IDataObject*     iface,
1545 	    LPFORMATETC      pformatectIn,
1546 	    LPFORMATETC      pformatetcOut)
1547 {
1548   TRACE("()\n");
1549   return E_NOTIMPL;
1550 }
1551 
1552 /************************************************************************
1553  * DataCache_IDataObject_SetData (IDataObject)
1554  *
1555  * This method is delegated to the IOleCache2 implementation.
1556  */
1557 static HRESULT WINAPI DataCache_IDataObject_SetData(
1558 	    IDataObject*     iface,
1559 	    LPFORMATETC      pformatetc,
1560 	    STGMEDIUM*       pmedium,
1561 	    BOOL             fRelease)
1562 {
1563   IOleCache2* oleCache = NULL;
1564   HRESULT     hres;
1565 
1566   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1567 
1568   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1569 
1570   if (FAILED(hres))
1571     return E_UNEXPECTED;
1572 
1573   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1574 
1575   IOleCache2_Release(oleCache);
1576 
1577   return hres;
1578 }
1579 
1580 /************************************************************************
1581  * DataCache_EnumFormatEtc (IDataObject)
1582  *
1583  * The data cache doesn't implement this method.
1584  */
1585 static HRESULT WINAPI DataCache_EnumFormatEtc(
1586 	    IDataObject*     iface,
1587 	    DWORD            dwDirection,
1588 	    IEnumFORMATETC** ppenumFormatEtc)
1589 {
1590   TRACE("()\n");
1591   return E_NOTIMPL;
1592 }
1593 
1594 /************************************************************************
1595  * DataCache_DAdvise (IDataObject)
1596  *
1597  * The data cache doesn't support connections.
1598  */
1599 static HRESULT WINAPI DataCache_DAdvise(
1600 	    IDataObject*     iface,
1601 	    FORMATETC*       pformatetc,
1602 	    DWORD            advf,
1603 	    IAdviseSink*     pAdvSink,
1604 	    DWORD*           pdwConnection)
1605 {
1606   TRACE("()\n");
1607   return OLE_E_ADVISENOTSUPPORTED;
1608 }
1609 
1610 /************************************************************************
1611  * DataCache_DUnadvise (IDataObject)
1612  *
1613  * The data cache doesn't support connections.
1614  */
1615 static HRESULT WINAPI DataCache_DUnadvise(
1616 	    IDataObject*     iface,
1617 	    DWORD            dwConnection)
1618 {
1619   TRACE("()\n");
1620   return OLE_E_NOCONNECTION;
1621 }
1622 
1623 /************************************************************************
1624  * DataCache_EnumDAdvise (IDataObject)
1625  *
1626  * The data cache doesn't support connections.
1627  */
1628 static HRESULT WINAPI DataCache_EnumDAdvise(
1629 	    IDataObject*     iface,
1630 	    IEnumSTATDATA**  ppenumAdvise)
1631 {
1632   TRACE("()\n");
1633   return OLE_E_ADVISENOTSUPPORTED;
1634 }
1635 
1636 /*********************************************************
1637  * Method implementation for the IDataObject
1638  * part of the DataCache class.
1639  */
1640 
1641 /************************************************************************
1642  * DataCache_IPersistStorage_QueryInterface (IUnknown)
1643  */
1644 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1645             IPersistStorage* iface,
1646             REFIID           riid,
1647             void**           ppvObject)
1648 {
1649   DataCache *this = impl_from_IPersistStorage(iface);
1650 
1651   return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1652 }
1653 
1654 /************************************************************************
1655  * DataCache_IPersistStorage_AddRef (IUnknown)
1656  */
1657 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
1658             IPersistStorage* iface)
1659 {
1660   DataCache *this = impl_from_IPersistStorage(iface);
1661 
1662   return IUnknown_AddRef(this->outer_unk);
1663 }
1664 
1665 /************************************************************************
1666  * DataCache_IPersistStorage_Release (IUnknown)
1667  */
1668 static ULONG WINAPI DataCache_IPersistStorage_Release(
1669             IPersistStorage* iface)
1670 {
1671   DataCache *this = impl_from_IPersistStorage(iface);
1672 
1673   return IUnknown_Release(this->outer_unk);
1674 }
1675 
1676 /************************************************************************
1677  * DataCache_GetClassID (IPersistStorage)
1678  *
1679  */
1680 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid)
1681 {
1682     DataCache *This = impl_from_IPersistStorage( iface );
1683 
1684     TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) );
1685     *clsid = This->clsid;
1686 
1687     return S_OK;
1688 }
1689 
1690 /************************************************************************
1691  * DataCache_IsDirty (IPersistStorage)
1692  */
1693 static HRESULT WINAPI DataCache_IsDirty(
1694             IPersistStorage* iface)
1695 {
1696     DataCache *This = impl_from_IPersistStorage(iface);
1697     DataCacheEntry *cache_entry;
1698 
1699     TRACE("(%p)\n", iface);
1700 
1701     if (This->dirty)
1702         return S_OK;
1703 
1704     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1705         if (cache_entry->dirty)
1706             return S_OK;
1707 
1708     return S_FALSE;
1709 }
1710 
1711 /************************************************************************
1712  * DataCache_InitNew (IPersistStorage)
1713  *
1714  * The data cache implementation of IPersistStorage_InitNew simply stores
1715  * the storage pointer.
1716  */
1717 static HRESULT WINAPI DataCache_InitNew(
1718             IPersistStorage* iface,
1719 	    IStorage*        pStg)
1720 {
1721     DataCache *This = impl_from_IPersistStorage(iface);
1722     CLSID clsid;
1723     HRESULT hr;
1724 
1725     TRACE("(%p, %p)\n", iface, pStg);
1726 
1727     if (This->presentationStorage != NULL)
1728         return CO_E_ALREADYINITIALIZED;
1729 
1730     This->presentationStorage = pStg;
1731 
1732     IStorage_AddRef(This->presentationStorage);
1733     This->dirty = TRUE;
1734     ReadClassStg( pStg, &clsid );
1735     hr = create_automatic_entry( This, &clsid );
1736     if (FAILED(hr))
1737     {
1738         IStorage_Release( pStg );
1739         This->presentationStorage = NULL;
1740         return hr;
1741     }
1742     This->clsid = clsid;
1743 
1744     return S_OK;
1745 }
1746 
1747 
1748 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, int stream_number )
1749 {
1750     DataCacheEntry *cache_entry;
1751     HRESULT hr = S_OK;
1752 
1753     TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) );
1754 
1755     cache_entry = DataCache_GetEntryForFormatEtc( This, fmt );
1756     if (!cache_entry)
1757         hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry );
1758     if (SUCCEEDED( hr ))
1759     {
1760         DataCacheEntry_DiscardData( cache_entry );
1761         cache_entry->load_stream_num = stream_number;
1762         cache_entry->save_stream_num = stream_number;
1763         cache_entry->dirty = FALSE;
1764     }
1765     return hr;
1766 }
1767 
1768 static HRESULT parse_pres_streams( DataCache *cache, IStorage *stg )
1769 {
1770     HRESULT hr;
1771     IStream *stm;
1772     PresentationDataHeader header;
1773     ULONG actual_read;
1774     CLIPFORMAT clipformat;
1775     FORMATETC fmtetc;
1776     int stream_number = 0;
1777 
1778     do
1779     {
1780         hr = open_pres_stream( stg, stream_number, &stm );
1781         if (FAILED(hr)) break;
1782 
1783         hr = read_clipformat( stm, &clipformat );
1784 
1785         if (hr == S_OK) hr = IStream_Read( stm, &header, sizeof(header), &actual_read );
1786 
1787         if (hr == S_OK && actual_read == sizeof(header))
1788         {
1789             fmtetc.cfFormat = clipformat;
1790             fmtetc.ptd = NULL; /* FIXME */
1791             fmtetc.dwAspect = header.dvAspect;
1792             fmtetc.lindex = header.lindex;
1793             fmtetc.tymed = tymed_from_cf( clipformat );
1794 
1795             add_cache_entry( cache, &fmtetc, header.advf, stream_number );
1796         }
1797         IStream_Release( stm );
1798         stream_number++;
1799     } while (hr == S_OK);
1800 
1801     return S_OK;
1802 }
1803 
1804 static HRESULT parse_contents_stream( DataCache *cache, IStorage *stg )
1805 {
1806     HRESULT hr;
1807     IStream *stm;
1808     DataCacheEntry *cache_entry;
1809 
1810     hr = open_pres_stream( stg, STREAM_NUMBER_CONTENTS, &stm );
1811     if (FAILED( hr )) return hr;
1812 
1813     hr = get_static_entry( cache, &cache_entry );
1814     if (hr == S_OK)
1815     {
1816         cache_entry->load_stream_num = STREAM_NUMBER_CONTENTS;
1817         cache_entry->save_stream_num = STREAM_NUMBER_CONTENTS;
1818         cache_entry->dirty = FALSE;
1819     }
1820 
1821     IStream_Release( stm );
1822     return hr;
1823 }
1824 
1825 /************************************************************************
1826  * DataCache_Load (IPersistStorage)
1827  *
1828  * The data cache implementation of IPersistStorage_Load doesn't
1829  * actually load anything. Instead, it holds on to the storage pointer
1830  * and it will load the presentation information when the
1831  * IDataObject_GetData or IViewObject2_Draw methods are called.
1832  */
1833 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg )
1834 {
1835     DataCache *This = impl_from_IPersistStorage(iface);
1836     HRESULT hr;
1837     CLSID clsid;
1838     DataCacheEntry *entry, *cursor2;
1839 
1840     TRACE("(%p, %p)\n", iface, stg);
1841 
1842     IPersistStorage_HandsOffStorage( iface );
1843 
1844     LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry )
1845         DataCacheEntry_Destroy( This, entry );
1846     This->clsid = CLSID_NULL;
1847 
1848     ReadClassStg( stg, &clsid );
1849     hr = create_automatic_entry( This, &clsid );
1850     if (FAILED( hr )) return hr;
1851 
1852     This->clsid = clsid;
1853 
1854     if (This->clsid_static)
1855     {
1856         hr = parse_contents_stream( This, stg );
1857         if (FAILED(hr)) hr = parse_pres_streams( This, stg );
1858     }
1859     else
1860         hr = parse_pres_streams( This, stg );
1861 
1862     if (SUCCEEDED( hr ))
1863     {
1864         This->dirty = FALSE;
1865         This->presentationStorage = stg;
1866         IStorage_AddRef( This->presentationStorage );
1867     }
1868 
1869     return hr;
1870 }
1871 
1872 /************************************************************************
1873  * DataCache_Save (IPersistStorage)
1874  *
1875  * Until we actually connect to a running object and retrieve new
1876  * information to it, we never have to save anything. However, it is
1877  * our responsibility to copy the information when saving to a new
1878  * storage.
1879  */
1880 static HRESULT WINAPI DataCache_Save(IPersistStorage* iface, IStorage *stg, BOOL same_as_load)
1881 {
1882     DataCache *This = impl_from_IPersistStorage(iface);
1883     DataCacheEntry *cache_entry;
1884     HRESULT hr = S_OK;
1885     int stream_number = 0;
1886 
1887     TRACE("(%p, %p, %d)\n", iface, stg, same_as_load);
1888 
1889     /* assign stream numbers to the cache entries */
1890     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1891     {
1892         if (cache_entry->save_stream_num != stream_number)
1893         {
1894             cache_entry->dirty = TRUE; /* needs to be written out again */
1895             cache_entry->save_stream_num = stream_number;
1896         }
1897         stream_number++;
1898     }
1899 
1900     /* write out the cache entries */
1901     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
1902     {
1903         if (!same_as_load || cache_entry->dirty)
1904         {
1905             hr = DataCacheEntry_Save(cache_entry, stg, same_as_load);
1906             if (FAILED(hr))
1907                 break;
1908 
1909             if (same_as_load) cache_entry->dirty = FALSE;
1910         }
1911     }
1912 
1913     if (same_as_load) This->dirty = FALSE;
1914     return hr;
1915 }
1916 
1917 /************************************************************************
1918  * DataCache_SaveCompleted (IPersistStorage)
1919  *
1920  * This method is called to tell the cache to release the storage
1921  * pointer it's currently holding.
1922  */
1923 static HRESULT WINAPI DataCache_SaveCompleted(
1924             IPersistStorage* iface,
1925 	    IStorage*        pStgNew)
1926 {
1927   TRACE("(%p, %p)\n", iface, pStgNew);
1928 
1929   if (pStgNew)
1930   {
1931     IPersistStorage_HandsOffStorage(iface);
1932 
1933     DataCache_Load(iface, pStgNew);
1934   }
1935 
1936   return S_OK;
1937 }
1938 
1939 /************************************************************************
1940  * DataCache_HandsOffStorage (IPersistStorage)
1941  *
1942  * This method is called to tell the cache to release the storage
1943  * pointer it's currently holding.
1944  */
1945 static HRESULT WINAPI DataCache_HandsOffStorage(
1946             IPersistStorage* iface)
1947 {
1948   DataCache *this = impl_from_IPersistStorage(iface);
1949 
1950   TRACE("(%p)\n", iface);
1951 
1952   if (this->presentationStorage != NULL)
1953   {
1954     IStorage_Release(this->presentationStorage);
1955     this->presentationStorage = NULL;
1956   }
1957 
1958   return S_OK;
1959 }
1960 
1961 /*********************************************************
1962  * Method implementation for the IViewObject2
1963  * part of the DataCache class.
1964  */
1965 
1966 /************************************************************************
1967  * DataCache_IViewObject2_QueryInterface (IUnknown)
1968  */
1969 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1970             IViewObject2* iface,
1971             REFIID           riid,
1972             void**           ppvObject)
1973 {
1974   DataCache *this = impl_from_IViewObject2(iface);
1975 
1976   return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
1977 }
1978 
1979 /************************************************************************
1980  * DataCache_IViewObject2_AddRef (IUnknown)
1981  */
1982 static ULONG WINAPI DataCache_IViewObject2_AddRef(
1983             IViewObject2* iface)
1984 {
1985   DataCache *this = impl_from_IViewObject2(iface);
1986 
1987   return IUnknown_AddRef(this->outer_unk);
1988 }
1989 
1990 /************************************************************************
1991  * DataCache_IViewObject2_Release (IUnknown)
1992  */
1993 static ULONG WINAPI DataCache_IViewObject2_Release(
1994             IViewObject2* iface)
1995 {
1996   DataCache *this = impl_from_IViewObject2(iface);
1997 
1998   return IUnknown_Release(this->outer_unk);
1999 }
2000 
2001 /************************************************************************
2002  * DataCache_Draw (IViewObject2)
2003  *
2004  * This method will draw the cached representation of the object
2005  * to the given device context.
2006  */
2007 static HRESULT WINAPI DataCache_Draw(
2008             IViewObject2*    iface,
2009 	    DWORD            dwDrawAspect,
2010 	    LONG             lindex,
2011 	    void*            pvAspect,
2012 	    DVTARGETDEVICE*  ptd,
2013 	    HDC              hdcTargetDev,
2014 	    HDC              hdcDraw,
2015 	    LPCRECTL         lprcBounds,
2016 	    LPCRECTL         lprcWBounds,
2017 	    BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
2018 	    ULONG_PTR        dwContinue)
2019 {
2020   DataCache *This = impl_from_IViewObject2(iface);
2021   HRESULT                hres;
2022   DataCacheEntry        *cache_entry;
2023 
2024   TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
2025 	iface,
2026 	dwDrawAspect,
2027 	lindex,
2028 	pvAspect,
2029 	hdcTargetDev,
2030 	hdcDraw,
2031 	lprcBounds,
2032 	lprcWBounds,
2033 	pfnContinue,
2034 	dwContinue);
2035 
2036   if (lprcBounds==NULL)
2037     return E_INVALIDARG;
2038 
2039   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2040   {
2041     /* FIXME: compare ptd too */
2042     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2043         (cache_entry->fmtetc.lindex != lindex))
2044       continue;
2045 
2046     /* if the data hasn't been loaded yet, do it now */
2047     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2048     {
2049       hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2050       if (FAILED(hres))
2051         continue;
2052     }
2053 
2054     /* no data */
2055     if (cache_entry->stgmedium.tymed == TYMED_NULL)
2056       continue;
2057 
2058     if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
2059 
2060     switch (cache_entry->fmtetc.cfFormat)
2061     {
2062       case CF_METAFILEPICT:
2063       {
2064         /*
2065          * We have to be careful not to modify the state of the
2066          * DC.
2067          */
2068         INT   prevMapMode;
2069         SIZE  oldWindowExt;
2070         SIZE  oldViewportExt;
2071         POINT oldViewportOrg;
2072         METAFILEPICT *mfpict;
2073 
2074         if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2075             !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2076           continue;
2077 
2078         prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
2079 
2080         SetWindowExtEx(hdcDraw,
2081 		       mfpict->xExt,
2082 		       mfpict->yExt,
2083 		       &oldWindowExt);
2084 
2085         SetViewportExtEx(hdcDraw,
2086 		         lprcBounds->right - lprcBounds->left,
2087 		         lprcBounds->bottom - lprcBounds->top,
2088 		         &oldViewportExt);
2089 
2090         SetViewportOrgEx(hdcDraw,
2091 		         lprcBounds->left,
2092 		         lprcBounds->top,
2093 		         &oldViewportOrg);
2094 
2095         PlayMetaFile(hdcDraw, mfpict->hMF);
2096 
2097         SetWindowExtEx(hdcDraw,
2098 		       oldWindowExt.cx,
2099 		       oldWindowExt.cy,
2100 		       NULL);
2101 
2102         SetViewportExtEx(hdcDraw,
2103 		         oldViewportExt.cx,
2104 		         oldViewportExt.cy,
2105 		         NULL);
2106 
2107         SetViewportOrgEx(hdcDraw,
2108 		         oldViewportOrg.x,
2109 		         oldViewportOrg.y,
2110 		         NULL);
2111 
2112         SetMapMode(hdcDraw, prevMapMode);
2113 
2114         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2115 
2116         return S_OK;
2117       }
2118       case CF_DIB:
2119       {
2120           BITMAPINFO *info;
2121           BYTE *bits;
2122 
2123           if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2124               !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2125               continue;
2126 
2127           bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS );
2128           StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top,
2129                          lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top,
2130                          0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
2131                          bits, info, DIB_RGB_COLORS, SRCCOPY );
2132 
2133           GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2134           return S_OK;
2135       }
2136     }
2137   }
2138 
2139   WARN("no data could be found to be drawn\n");
2140 
2141   return OLE_E_BLANK;
2142 }
2143 
2144 static HRESULT WINAPI DataCache_GetColorSet(
2145             IViewObject2*   iface,
2146 	    DWORD           dwDrawAspect,
2147 	    LONG            lindex,
2148 	    void*           pvAspect,
2149 	    DVTARGETDEVICE* ptd,
2150 	    HDC             hicTargetDevice,
2151 	    LOGPALETTE**    ppColorSet)
2152 {
2153   FIXME("stub\n");
2154   return E_NOTIMPL;
2155 }
2156 
2157 static HRESULT WINAPI DataCache_Freeze(
2158             IViewObject2*   iface,
2159 	    DWORD           dwDrawAspect,
2160 	    LONG            lindex,
2161 	    void*           pvAspect,
2162 	    DWORD*          pdwFreeze)
2163 {
2164   FIXME("stub\n");
2165   return E_NOTIMPL;
2166 }
2167 
2168 static HRESULT WINAPI DataCache_Unfreeze(
2169             IViewObject2*   iface,
2170 	    DWORD           dwFreeze)
2171 {
2172   FIXME("stub\n");
2173   return E_NOTIMPL;
2174 }
2175 
2176 /************************************************************************
2177  * DataCache_SetAdvise (IViewObject2)
2178  *
2179  * This sets-up an advisory sink with the data cache. When the object's
2180  * view changes, this sink is called.
2181  */
2182 static HRESULT WINAPI DataCache_SetAdvise(
2183             IViewObject2*   iface,
2184 	    DWORD           aspects,
2185 	    DWORD           advf,
2186 	    IAdviseSink*    pAdvSink)
2187 {
2188   DataCache *this = impl_from_IViewObject2(iface);
2189 
2190   TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
2191 
2192   /*
2193    * A call to this function removes the previous sink
2194    */
2195   if (this->sinkInterface != NULL)
2196   {
2197     IAdviseSink_Release(this->sinkInterface);
2198     this->sinkInterface  = NULL;
2199     this->sinkAspects    = 0;
2200     this->sinkAdviseFlag = 0;
2201   }
2202 
2203   /*
2204    * Now, setup the new one.
2205    */
2206   if (pAdvSink!=NULL)
2207   {
2208     this->sinkInterface  = pAdvSink;
2209     this->sinkAspects    = aspects;
2210     this->sinkAdviseFlag = advf;
2211 
2212     IAdviseSink_AddRef(this->sinkInterface);
2213   }
2214 
2215   /*
2216    * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2217    * sink immediately.
2218    */
2219   if (advf & ADVF_PRIMEFIRST)
2220   {
2221     DataCache_FireOnViewChange(this, aspects, -1);
2222   }
2223 
2224   return S_OK;
2225 }
2226 
2227 /************************************************************************
2228  * DataCache_GetAdvise (IViewObject2)
2229  *
2230  * This method queries the current state of the advise sink
2231  * installed on the data cache.
2232  */
2233 static HRESULT WINAPI DataCache_GetAdvise(
2234             IViewObject2*   iface,
2235 	    DWORD*          pAspects,
2236 	    DWORD*          pAdvf,
2237 	    IAdviseSink**   ppAdvSink)
2238 {
2239   DataCache *this = impl_from_IViewObject2(iface);
2240 
2241   TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
2242 
2243   /*
2244    * Just copy all the requested values.
2245    */
2246   if (pAspects!=NULL)
2247     *pAspects = this->sinkAspects;
2248 
2249   if (pAdvf!=NULL)
2250     *pAdvf = this->sinkAdviseFlag;
2251 
2252   if (ppAdvSink!=NULL)
2253   {
2254     if (this->sinkInterface != NULL)
2255         IAdviseSink_QueryInterface(this->sinkInterface,
2256 			       &IID_IAdviseSink,
2257 			       (void**)ppAdvSink);
2258     else *ppAdvSink = NULL;
2259   }
2260 
2261   return S_OK;
2262 }
2263 
2264 /************************************************************************
2265  * DataCache_GetExtent (IViewObject2)
2266  *
2267  * This method retrieves the "natural" size of this cached object.
2268  */
2269 static HRESULT WINAPI DataCache_GetExtent(
2270             IViewObject2*   iface,
2271 	    DWORD           dwDrawAspect,
2272 	    LONG            lindex,
2273 	    DVTARGETDEVICE* ptd,
2274 	    LPSIZEL         lpsizel)
2275 {
2276   DataCache *This = impl_from_IViewObject2(iface);
2277   HRESULT                hres = E_FAIL;
2278   DataCacheEntry        *cache_entry;
2279 
2280   TRACE("(%p, %x, %d, %p, %p)\n",
2281 	iface, dwDrawAspect, lindex, ptd, lpsizel);
2282 
2283   if (lpsizel==NULL)
2284     return E_POINTER;
2285 
2286   lpsizel->cx = 0;
2287   lpsizel->cy = 0;
2288 
2289   if (lindex!=-1)
2290     FIXME("Unimplemented flag lindex = %d\n", lindex);
2291 
2292   /*
2293    * Right now, we support only the callback from
2294    * the default handler.
2295    */
2296   if (ptd!=NULL)
2297     FIXME("Unimplemented ptd = %p\n", ptd);
2298 
2299   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2300   {
2301     /* FIXME: compare ptd too */
2302     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
2303         (cache_entry->fmtetc.lindex != lindex))
2304       continue;
2305 
2306     /* if the data hasn't been loaded yet, do it now */
2307     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET))
2308     {
2309       hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage);
2310       if (FAILED(hres))
2311         continue;
2312     }
2313 
2314     /* no data */
2315     if (cache_entry->stgmedium.tymed == TYMED_NULL)
2316       continue;
2317 
2318 
2319     switch (cache_entry->fmtetc.cfFormat)
2320     {
2321       case CF_METAFILEPICT:
2322       {
2323           METAFILEPICT *mfpict;
2324 
2325           if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
2326               !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
2327             continue;
2328 
2329         lpsizel->cx = mfpict->xExt;
2330         lpsizel->cy = mfpict->yExt;
2331 
2332         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
2333 
2334         return S_OK;
2335       }
2336       case CF_DIB:
2337       {
2338           BITMAPINFOHEADER *info;
2339           LONG x_pels_m, y_pels_m;
2340 
2341 
2342           if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) ||
2343               !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal ))))
2344               continue;
2345 
2346           x_pels_m = info->biXPelsPerMeter;
2347           y_pels_m = info->biYPelsPerMeter;
2348 
2349           /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2350           if (x_pels_m != 0 && y_pels_m != 0)
2351           {
2352               lpsizel->cx = info->biWidth  * 100000 / x_pels_m;
2353               lpsizel->cy = info->biHeight * 100000 / y_pels_m;
2354           }
2355           else
2356           {
2357               HDC hdc = GetDC( 0 );
2358               lpsizel->cx = info->biWidth  * 2540 / GetDeviceCaps( hdc, LOGPIXELSX );
2359               lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY );
2360 
2361               ReleaseDC( 0, hdc );
2362           }
2363 
2364           GlobalUnlock( cache_entry->stgmedium.u.hGlobal );
2365 
2366           return S_OK;
2367       }
2368     }
2369   }
2370 
2371   WARN("no data could be found to get the extents from\n");
2372 
2373   /*
2374    * This method returns OLE_E_BLANK when it fails.
2375    */
2376   return OLE_E_BLANK;
2377 }
2378 
2379 
2380 /*********************************************************
2381  * Method implementation for the IOleCache2
2382  * part of the DataCache class.
2383  */
2384 
2385 /************************************************************************
2386  * DataCache_IOleCache2_QueryInterface (IUnknown)
2387  */
2388 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
2389             IOleCache2*     iface,
2390             REFIID          riid,
2391             void**          ppvObject)
2392 {
2393   DataCache *this = impl_from_IOleCache2(iface);
2394 
2395   return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2396 }
2397 
2398 /************************************************************************
2399  * DataCache_IOleCache2_AddRef (IUnknown)
2400  */
2401 static ULONG WINAPI DataCache_IOleCache2_AddRef(
2402             IOleCache2*     iface)
2403 {
2404   DataCache *this = impl_from_IOleCache2(iface);
2405 
2406   return IUnknown_AddRef(this->outer_unk);
2407 }
2408 
2409 /************************************************************************
2410  * DataCache_IOleCache2_Release (IUnknown)
2411  */
2412 static ULONG WINAPI DataCache_IOleCache2_Release(
2413             IOleCache2*     iface)
2414 {
2415   DataCache *this = impl_from_IOleCache2(iface);
2416 
2417   return IUnknown_Release(this->outer_unk);
2418 }
2419 
2420 /*****************************************************************************
2421  * setup_sink
2422  *
2423  * Set up the sink connection to the running object.
2424  */
2425 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
2426 {
2427     HRESULT hr = S_FALSE;
2428     DWORD flags;
2429 
2430     /* Clear the ADVFCACHE_* bits.  Native also sets the two highest bits for some reason. */
2431     flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
2432 
2433     if(This->running_object)
2434         if(!(flags & ADVF_NODATA))
2435             hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
2436                                      &This->IAdviseSink_iface, &cache_entry->sink_id);
2437     return hr;
2438 }
2439 
2440 static HRESULT WINAPI DataCache_Cache(
2441             IOleCache2*     iface,
2442 	    FORMATETC*      pformatetc,
2443 	    DWORD           advf,
2444 	    DWORD*          pdwConnection)
2445 {
2446     DataCache *This = impl_from_IOleCache2(iface);
2447     DataCacheEntry *cache_entry;
2448     HRESULT hr;
2449     FORMATETC fmt_cpy;
2450 
2451     TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
2452 
2453     if (!pformatetc || !pdwConnection)
2454         return E_INVALIDARG;
2455 
2456     TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
2457 
2458     fmt_cpy = *pformatetc; /* No need for a deep copy */
2459     if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI)
2460     {
2461         fmt_cpy.cfFormat = CF_DIB;
2462         fmt_cpy.tymed = TYMED_HGLOBAL;
2463     }
2464 
2465     /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */
2466     if (fmt_cpy.dwAspect == DVASPECT_ICON && fmt_cpy.cfFormat == 0)
2467     {
2468         fmt_cpy.cfFormat = CF_METAFILEPICT;
2469         fmt_cpy.tymed = TYMED_MFPICT;
2470     }
2471 
2472     *pdwConnection = 0;
2473 
2474     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy);
2475     if (cache_entry)
2476     {
2477         TRACE("found an existing cache entry\n");
2478         *pdwConnection = cache_entry->id;
2479         return CACHE_S_SAMECACHE;
2480     }
2481 
2482     if (This->clsid_static && fmt_cpy.dwAspect != DVASPECT_ICON) return DV_E_FORMATETC;
2483 
2484     hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry);
2485 
2486     if (SUCCEEDED(hr))
2487     {
2488         *pdwConnection = cache_entry->id;
2489         setup_sink(This, cache_entry);
2490     }
2491 
2492     return hr;
2493 }
2494 
2495 static HRESULT WINAPI DataCache_Uncache(
2496 	    IOleCache2*     iface,
2497 	    DWORD           dwConnection)
2498 {
2499     DataCache *This = impl_from_IOleCache2(iface);
2500     DataCacheEntry *cache_entry;
2501 
2502     TRACE("(%d)\n", dwConnection);
2503 
2504     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2505         if (cache_entry->id == dwConnection)
2506         {
2507             DataCacheEntry_Destroy(This, cache_entry);
2508             return S_OK;
2509         }
2510 
2511     WARN("no connection found for %d\n", dwConnection);
2512 
2513     return OLE_E_NOCONNECTION;
2514 }
2515 
2516 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface,
2517                                           IEnumSTATDATA **enum_stat)
2518 {
2519     DataCache *This = impl_from_IOleCache2( iface );
2520     DataCacheEntry *cache_entry;
2521     int i = 0, count = 0;
2522     STATDATA *data;
2523     HRESULT hr;
2524 
2525     TRACE( "(%p, %p)\n", This, enum_stat );
2526 
2527     LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2528     {
2529         count++;
2530         if (cache_entry->fmtetc.cfFormat == CF_DIB)
2531             count++;
2532     }
2533 
2534     data = CoTaskMemAlloc( count * sizeof(*data) );
2535     if (!data) return E_OUTOFMEMORY;
2536 
2537     LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2538     {
2539         if (i == count) goto fail;
2540         hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2541         if (FAILED(hr)) goto fail;
2542         data[i].advf = cache_entry->advise_flags;
2543         data[i].pAdvSink = NULL;
2544         data[i].dwConnection = cache_entry->id;
2545         i++;
2546 
2547         if (cache_entry->fmtetc.cfFormat == CF_DIB)
2548         {
2549             if (i == count) goto fail;
2550             hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc );
2551             if (FAILED(hr)) goto fail;
2552             data[i].formatetc.cfFormat = CF_BITMAP;
2553             data[i].formatetc.tymed = TYMED_GDI;
2554             data[i].advf = cache_entry->advise_flags;
2555             data[i].pAdvSink = NULL;
2556             data[i].dwConnection = cache_entry->id;
2557             i++;
2558         }
2559     }
2560 
2561     hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat );
2562     if (SUCCEEDED(hr)) return hr;
2563 
2564 fail:
2565     while (i--) CoTaskMemFree( data[i].formatetc.ptd );
2566     CoTaskMemFree( data );
2567     return hr;
2568 }
2569 
2570 static HRESULT WINAPI DataCache_InitCache( IOleCache2 *iface, IDataObject *data )
2571 {
2572     TRACE( "(%p %p)\n", iface, data );
2573     return IOleCache2_UpdateCache( iface, data, UPDFCACHE_ALLBUTNODATACACHE, NULL );
2574 }
2575 
2576 static HRESULT WINAPI DataCache_IOleCache2_SetData(
2577             IOleCache2*     iface,
2578 	    FORMATETC*      pformatetc,
2579 	    STGMEDIUM*      pmedium,
2580 	    BOOL            fRelease)
2581 {
2582     DataCache *This = impl_from_IOleCache2(iface);
2583     DataCacheEntry *cache_entry;
2584     HRESULT hr;
2585 
2586     TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
2587     TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
2588 
2589     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
2590     if (cache_entry)
2591     {
2592         hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
2593 
2594         if (SUCCEEDED(hr))
2595             DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
2596                                        cache_entry->fmtetc.lindex);
2597 
2598         return hr;
2599     }
2600     WARN("cache entry not found\n");
2601 
2602     return OLE_E_BLANK;
2603 }
2604 
2605 static BOOL entry_updatable( DataCacheEntry *entry, DWORD mode )
2606 {
2607     BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL;
2608 
2609     if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE;
2610 
2611     if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE;
2612     if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE;
2613     if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE;
2614     if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE;
2615     if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE;
2616 
2617     return FALSE;
2618 }
2619 
2620 static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data,
2621                                              DWORD mode, void *reserved )
2622 {
2623     DataCache *This = impl_from_IOleCache2(iface);
2624     DataCacheEntry *cache_entry;
2625     STGMEDIUM med;
2626     HRESULT hr = S_OK;
2627     CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP };
2628     FORMATETC fmt;
2629     int i, slots = 0;
2630     BOOL done_one = FALSE;
2631 
2632     TRACE( "(%p %p %08x %p)\n", iface, data, mode, reserved );
2633 
2634     LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry )
2635     {
2636         slots++;
2637 
2638         if (!entry_updatable( cache_entry, mode ))
2639         {
2640             done_one = TRUE;
2641             continue;
2642         }
2643 
2644         fmt = cache_entry->fmtetc;
2645 
2646         if (fmt.cfFormat)
2647         {
2648             hr = IDataObject_GetData( data, &fmt, &med );
2649             if (hr != S_OK && fmt.cfFormat == CF_DIB)
2650             {
2651                 fmt.cfFormat = CF_BITMAP;
2652                 fmt.tymed = TYMED_GDI;
2653                 hr = IDataObject_GetData( data, &fmt, &med );
2654             }
2655             if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE)
2656             {
2657                 fmt.cfFormat = CF_METAFILEPICT;
2658                 fmt.tymed = TYMED_MFPICT;
2659                 hr = IDataObject_GetData( data, &fmt, &med );
2660             }
2661             if (hr == S_OK)
2662             {
2663                 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2664                 if (hr != S_OK) ReleaseStgMedium( &med );
2665                 else done_one = TRUE;
2666             }
2667         }
2668         else
2669         {
2670             for (i = 0; i < sizeof(view_list) / sizeof(view_list[0]); i++)
2671             {
2672                 fmt.cfFormat = view_list[i];
2673                 fmt.tymed = tymed_from_cf( fmt.cfFormat );
2674                 hr = IDataObject_QueryGetData( data, &fmt );
2675                 if (hr == S_OK)
2676                 {
2677                     hr = IDataObject_GetData( data, &fmt, &med );
2678                     if (hr == S_OK)
2679                     {
2680                         if (fmt.cfFormat == CF_BITMAP)
2681                         {
2682                             cache_entry->fmtetc.cfFormat = CF_DIB;
2683                             cache_entry->fmtetc.tymed = TYMED_HGLOBAL;
2684                         }
2685                         else
2686                         {
2687                             cache_entry->fmtetc.cfFormat = fmt.cfFormat;
2688                             cache_entry->fmtetc.tymed = fmt.tymed;
2689                         }
2690                         hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE );
2691                         if (hr != S_OK) ReleaseStgMedium( &med );
2692                         else done_one = TRUE;
2693                         break;
2694                     }
2695                 }
2696             }
2697         }
2698     }
2699 
2700     return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED;
2701 }
2702 
2703 static HRESULT WINAPI DataCache_DiscardCache(
2704             IOleCache2*     iface,
2705 	    DWORD           dwDiscardOptions)
2706 {
2707     DataCache *This = impl_from_IOleCache2(iface);
2708     DataCacheEntry *cache_entry;
2709     HRESULT hr = S_OK;
2710 
2711     TRACE("(%d)\n", dwDiscardOptions);
2712 
2713     if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
2714         hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
2715 
2716     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2717     {
2718         hr = DataCacheEntry_DiscardData(cache_entry);
2719         if (FAILED(hr))
2720             break;
2721     }
2722 
2723     return hr;
2724 }
2725 
2726 
2727 /*********************************************************
2728  * Method implementation for the IOleCacheControl
2729  * part of the DataCache class.
2730  */
2731 
2732 /************************************************************************
2733  * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2734  */
2735 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
2736             IOleCacheControl* iface,
2737             REFIID            riid,
2738             void**            ppvObject)
2739 {
2740   DataCache *this = impl_from_IOleCacheControl(iface);
2741 
2742   return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject);
2743 }
2744 
2745 /************************************************************************
2746  * DataCache_IOleCacheControl_AddRef (IUnknown)
2747  */
2748 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
2749             IOleCacheControl* iface)
2750 {
2751   DataCache *this = impl_from_IOleCacheControl(iface);
2752 
2753   return IUnknown_AddRef(this->outer_unk);
2754 }
2755 
2756 /************************************************************************
2757  * DataCache_IOleCacheControl_Release (IUnknown)
2758  */
2759 static ULONG WINAPI DataCache_IOleCacheControl_Release(
2760             IOleCacheControl* iface)
2761 {
2762   DataCache *this = impl_from_IOleCacheControl(iface);
2763 
2764   return IUnknown_Release(this->outer_unk);
2765 }
2766 
2767 /************************************************************************
2768  * DataCache_OnRun (IOleCacheControl)
2769  */
2770 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
2771 {
2772     DataCache *This = impl_from_IOleCacheControl(iface);
2773     DataCacheEntry *cache_entry;
2774 
2775     TRACE("(%p)->(%p)\n", iface, data_obj);
2776 
2777     if(This->running_object) return S_OK;
2778 
2779     /* No reference is taken on the data object */
2780     This->running_object = data_obj;
2781 
2782     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2783     {
2784         setup_sink(This, cache_entry);
2785     }
2786 
2787     return S_OK;
2788 }
2789 
2790 /************************************************************************
2791  * DataCache_OnStop (IOleCacheControl)
2792  */
2793 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
2794 {
2795     DataCache *This = impl_from_IOleCacheControl(iface);
2796     DataCacheEntry *cache_entry;
2797 
2798     TRACE("(%p)\n", iface);
2799 
2800     if(!This->running_object) return S_OK;
2801 
2802     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
2803     {
2804         if(cache_entry->sink_id)
2805         {
2806             IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
2807             cache_entry->sink_id = 0;
2808         }
2809     }
2810 
2811     /* No ref taken in OnRun, so no Release call here */
2812     This->running_object = NULL;
2813     return S_OK;
2814 }
2815 
2816 /************************************************************************
2817  *              IAdviseSink methods.
2818  * This behaves as an internal object to the data cache.  QI'ing its ptr doesn't
2819  * give access to the cache's other interfaces.  We don't maintain a ref count,
2820  * the object exists as long as the cache is around.
2821  */
2822 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
2823 {
2824     *obj = NULL;
2825     if (IsEqualIID(&IID_IUnknown, iid) ||
2826         IsEqualIID(&IID_IAdviseSink, iid))
2827     {
2828         *obj = iface;
2829     }
2830 
2831     if(*obj)
2832     {
2833         IAdviseSink_AddRef(iface);
2834         return S_OK;
2835     }
2836     return E_NOINTERFACE;
2837 }
2838 
2839 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
2840 {
2841     return 2;
2842 }
2843 
2844 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
2845 {
2846     return 1;
2847 }
2848 
2849 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
2850 {
2851     DataCache *This = impl_from_IAdviseSink(iface);
2852     TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
2853     IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
2854 }
2855 
2856 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
2857 {
2858     FIXME("stub\n");
2859 }
2860 
2861 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
2862 {
2863     FIXME("stub\n");
2864 }
2865 
2866 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
2867 {
2868     FIXME("stub\n");
2869 }
2870 
2871 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
2872 {
2873     FIXME("stub\n");
2874 }
2875 
2876 /*
2877  * Virtual function tables for the DataCache class.
2878  */
2879 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
2880 {
2881   DataCache_NDIUnknown_QueryInterface,
2882   DataCache_NDIUnknown_AddRef,
2883   DataCache_NDIUnknown_Release
2884 };
2885 
2886 static const IDataObjectVtbl DataCache_IDataObject_VTable =
2887 {
2888   DataCache_IDataObject_QueryInterface,
2889   DataCache_IDataObject_AddRef,
2890   DataCache_IDataObject_Release,
2891   DataCache_GetData,
2892   DataCache_GetDataHere,
2893   DataCache_QueryGetData,
2894   DataCache_GetCanonicalFormatEtc,
2895   DataCache_IDataObject_SetData,
2896   DataCache_EnumFormatEtc,
2897   DataCache_DAdvise,
2898   DataCache_DUnadvise,
2899   DataCache_EnumDAdvise
2900 };
2901 
2902 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
2903 {
2904   DataCache_IPersistStorage_QueryInterface,
2905   DataCache_IPersistStorage_AddRef,
2906   DataCache_IPersistStorage_Release,
2907   DataCache_GetClassID,
2908   DataCache_IsDirty,
2909   DataCache_InitNew,
2910   DataCache_Load,
2911   DataCache_Save,
2912   DataCache_SaveCompleted,
2913   DataCache_HandsOffStorage
2914 };
2915 
2916 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
2917 {
2918   DataCache_IViewObject2_QueryInterface,
2919   DataCache_IViewObject2_AddRef,
2920   DataCache_IViewObject2_Release,
2921   DataCache_Draw,
2922   DataCache_GetColorSet,
2923   DataCache_Freeze,
2924   DataCache_Unfreeze,
2925   DataCache_SetAdvise,
2926   DataCache_GetAdvise,
2927   DataCache_GetExtent
2928 };
2929 
2930 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
2931 {
2932   DataCache_IOleCache2_QueryInterface,
2933   DataCache_IOleCache2_AddRef,
2934   DataCache_IOleCache2_Release,
2935   DataCache_Cache,
2936   DataCache_Uncache,
2937   DataCache_EnumCache,
2938   DataCache_InitCache,
2939   DataCache_IOleCache2_SetData,
2940   DataCache_UpdateCache,
2941   DataCache_DiscardCache
2942 };
2943 
2944 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
2945 {
2946   DataCache_IOleCacheControl_QueryInterface,
2947   DataCache_IOleCacheControl_AddRef,
2948   DataCache_IOleCacheControl_Release,
2949   DataCache_OnRun,
2950   DataCache_OnStop
2951 };
2952 
2953 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
2954 {
2955     DataCache_IAdviseSink_QueryInterface,
2956     DataCache_IAdviseSink_AddRef,
2957     DataCache_IAdviseSink_Release,
2958     DataCache_OnDataChange,
2959     DataCache_OnViewChange,
2960     DataCache_OnRename,
2961     DataCache_OnSave,
2962     DataCache_OnClose
2963 };
2964 
2965 /*********************************************************
2966  * Method implementation for DataCache class.
2967  */
2968 static DataCache* DataCache_Construct(
2969   REFCLSID  clsid,
2970   LPUNKNOWN pUnkOuter)
2971 {
2972   DataCache* newObject = 0;
2973 
2974   /*
2975    * Allocate space for the object.
2976    */
2977   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
2978 
2979   if (newObject==0)
2980     return newObject;
2981 
2982   /*
2983    * Initialize the virtual function table.
2984    */
2985   newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
2986   newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable;
2987   newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
2988   newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
2989   newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
2990   newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
2991   newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
2992   newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner;
2993   newObject->ref = 1;
2994 
2995   /*
2996    * Initialize the other members of the structure.
2997    */
2998   newObject->sinkAspects = 0;
2999   newObject->sinkAdviseFlag = 0;
3000   newObject->sinkInterface = 0;
3001   newObject->clsid = CLSID_NULL;
3002   newObject->clsid_static = FALSE;
3003   newObject->presentationStorage = NULL;
3004   list_init(&newObject->cache_list);
3005   newObject->last_cache_id = 2;
3006   newObject->dirty = FALSE;
3007   newObject->running_object = NULL;
3008 
3009   create_automatic_entry( newObject, clsid );
3010   newObject->clsid = *clsid;
3011 
3012   return newObject;
3013 }
3014 
3015 /******************************************************************************
3016  *              CreateDataCache        [OLE32.@]
3017  *
3018  * Creates a data cache to allow an object to render one or more of its views,
3019  * whether running or not.
3020  *
3021  * PARAMS
3022  *  pUnkOuter [I] Outer unknown for the object.
3023  *  rclsid    [I]
3024  *  riid      [I] IID of interface to return.
3025  *  ppvObj    [O] Address where the data cache object will be stored on return.
3026  *
3027  * RETURNS
3028  *  Success: S_OK.
3029  *  Failure: HRESULT code.
3030  *
3031  * NOTES
3032  *  The following interfaces are supported by the returned data cache object:
3033  *  IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
3034  *  IViewObject and IViewObject2.
3035  */
3036 HRESULT WINAPI CreateDataCache(
3037   LPUNKNOWN pUnkOuter,
3038   REFCLSID  rclsid,
3039   REFIID    riid,
3040   LPVOID*   ppvObj)
3041 {
3042   DataCache* newCache = NULL;
3043   HRESULT    hr       = S_OK;
3044 
3045   TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
3046 
3047   /*
3048    * Sanity check
3049    */
3050   if (ppvObj==0)
3051     return E_POINTER;
3052 
3053   *ppvObj = 0;
3054 
3055   /*
3056    * If this cache is constructed for aggregation, make sure
3057    * the caller is requesting the IUnknown interface.
3058    * This is necessary because it's the only time the non-delegating
3059    * IUnknown pointer can be returned to the outside.
3060    */
3061   if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
3062     return E_INVALIDARG;
3063 
3064   /*
3065    * Try to construct a new instance of the class.
3066    */
3067   newCache = DataCache_Construct(rclsid,
3068 				 pUnkOuter);
3069 
3070   if (newCache == 0)
3071     return E_OUTOFMEMORY;
3072 
3073   hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj);
3074   IUnknown_Release(&newCache->IUnknown_inner);
3075 
3076   return hr;
3077 }
3078