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