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