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