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