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