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