Added missing prototypes for StrRetToBuf(A|W).
[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   char       xclsid[50];
448   char       xriid[50];
449
450   WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
451   WINE_StringFromCLSID((LPCLSID)riid,xriid);
452
453   TRACE("(%s, %p, %s, %p)\n", xclsid, pUnkOuter, xriid, ppvObj);
454
455   /*
456    * Sanity check
457    */
458   if (ppvObj==0)
459     return E_POINTER;
460
461   *ppvObj = 0;
462
463   /*
464    * If this cache is constructed for aggregation, make sure
465    * the caller is requesting the IUnknown interface.
466    * This is necessary because it's the only time the non-delegating
467    * IUnknown pointer can be returned to the outside.
468    */
469   if ( (pUnkOuter!=NULL) && 
470        (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
471     return CLASS_E_NOAGGREGATION;
472
473   /*
474    * Try to construct a new instance of the class.
475    */
476   newCache = DataCache_Construct(rclsid, 
477                                  pUnkOuter);
478
479   if (newCache == 0)
480     return E_OUTOFMEMORY;
481
482   /*
483    * Make sure it supports the interface required by the caller.
484    */
485   hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtbl2), riid, ppvObj);
486
487   /*
488    * Release the reference obtained in the constructor. If
489    * the QueryInterface was unsuccessful, it will free the class.
490    */
491   IUnknown_Release((IUnknown*)&(newCache->lpvtbl2));
492
493   return hr;
494 }
495
496 /*********************************************************
497  * Method implementation for DataCache class.
498  */
499 static DataCache* DataCache_Construct(
500   REFCLSID  clsid,
501   LPUNKNOWN pUnkOuter)
502 {
503   DataCache* newObject = 0;
504
505   /*
506    * Allocate space for the object.
507    */
508   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
509
510   if (newObject==0)
511     return newObject;
512   
513   /*
514    * Initialize the virtual function table.
515    */
516   newObject->lpvtbl1 = &DataCache_IDataObject_VTable;
517   newObject->lpvtbl2 = &DataCache_NDIUnknown_VTable;
518   newObject->lpvtbl3 = &DataCache_IPersistStorage_VTable;
519   newObject->lpvtbl4 = &DataCache_IViewObject2_VTable;
520   newObject->lpvtbl5 = &DataCache_IOleCache2_VTable;
521   newObject->lpvtbl6 = &DataCache_IOleCacheControl_VTable;
522   
523   /*
524    * Start with one reference count. The caller of this function 
525    * must release the interface pointer when it is done.
526    */
527   newObject->ref = 1;
528
529   /*
530    * Initialize the outer unknown
531    * We don't keep a reference on the outer unknown since, the way 
532    * aggregation works, our lifetime is at least as large as it's
533    * lifetime.
534    */
535   if (pUnkOuter==NULL)
536     pUnkOuter = (IUnknown*)&(newObject->lpvtbl2);
537
538   newObject->outerUnknown = pUnkOuter;
539
540   /*
541    * Initialize the other members of the structure.
542    */
543   newObject->presentationStorage = NULL;
544   newObject->sinkAspects = 0;
545   newObject->sinkAdviseFlag = 0;
546   newObject->sinkInterface = 0;
547
548   return newObject;
549 }
550
551 static void DataCache_Destroy(
552   DataCache* ptrToDestroy)
553 {
554   TRACE("()\n");
555
556   if (ptrToDestroy->sinkInterface != NULL)
557   {
558     IAdviseSink_Release(ptrToDestroy->sinkInterface);
559     ptrToDestroy->sinkInterface = NULL;
560   }
561
562   if (ptrToDestroy->presentationStorage != NULL)
563   {
564     IStorage_Release(ptrToDestroy->presentationStorage);
565     ptrToDestroy->presentationStorage = NULL;
566   }
567
568   /*
569    * Free the datacache pointer.
570    */
571   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
572 }
573
574 /************************************************************************
575  * DataCache_ReadPresentationData
576  *
577  * This method will read information for the requested presentation 
578  * into the given structure.
579  *
580  * Param:
581  *   this       - Pointer to the DataCache object
582  *   drawAspect - The aspect of the object that we wish to draw.
583  *   header     - The structure containing information about this
584  *                aspect of the object.
585  */
586 static HRESULT DataCache_ReadPresentationData(
587   DataCache*              this,
588   DWORD                   drawAspect,
589   PresentationDataHeader* header)
590 {
591   IStream* presStream = NULL;
592   OLECHAR  streamName[20];
593   HRESULT  hres;
594
595   /*
596    * Get the name for the presentation stream.
597    */
598   hres = DataCache_FindPresStreamName(
599            this,
600            drawAspect,
601            streamName);
602
603   if (FAILED(hres))
604     return hres;
605
606   /*
607    * Open the stream and read the header.
608    */
609   hres = IStorage_OpenStream(
610            this->presentationStorage,
611            streamName,
612            NULL,
613            STGM_READ | STGM_SHARE_EXCLUSIVE,
614            0,
615            &presStream);
616
617   if (FAILED(hres))
618     return hres;
619
620   hres = IStream_Read(
621            presStream,
622            header,
623            sizeof(PresentationDataHeader),
624            NULL);
625
626   /*
627    * Cleanup.
628    */
629   IStream_Release(presStream);
630
631   /*
632    * We don't want to propagate any other error
633    * code than a failure.
634    */
635   if (hres!=S_OK)
636     hres = E_FAIL;
637
638   return hres;
639 }
640
641 /************************************************************************
642  * DataCache_FireOnViewChange
643  *
644  * This method will fire an OnViewChange notification to the advise
645  * sink registered with the datacache.
646  *
647  * See IAdviseSink::OnViewChange for more details.
648  */
649 static void DataCache_FireOnViewChange(
650   DataCache* this,
651   DWORD      aspect,
652   LONG       lindex)
653 {
654   TRACE("(%p, %lx, %ld)\n", this, aspect, lindex);
655
656   /*
657    * The sink supplies a filter when it registers
658    * we make sure we only send the notifications when that
659    * filter matches.
660    */
661   if ((this->sinkAspects & aspect) != 0)
662   {
663     if (this->sinkInterface != NULL)
664     {
665       IAdviseSink_OnViewChange(this->sinkInterface,
666                                aspect,
667                                lindex);
668
669       /*
670        * Some sinks want to be unregistered automatically when
671        * the first notification goes out.
672        */
673       if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
674       {
675         IAdviseSink_Release(this->sinkInterface);
676
677         this->sinkInterface  = NULL;
678         this->sinkAspects    = 0;
679         this->sinkAdviseFlag = 0;
680       }
681     }
682   }
683 }
684
685 /************************************************************************
686  * DataCache_ReadPresentationData
687  *
688  * This method will read information for the requested presentation 
689  * into the given structure.
690  *
691  * Param:
692  *   this       - Pointer to the DataCache object
693  *   drawAspect - The aspect of the object that we wish to draw.
694  *   header     - The structure containing information about this
695  *                aspect of the object.
696  *
697  * NOTE:
698  *   This method only supports the DVASPECT_CONTENT aspect.
699  */
700 static HRESULT DataCache_FindPresStreamName(
701   DataCache* this,
702   DWORD      drawAspect,
703   OLECHAR*   buffer)
704 {
705   OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
706
707   if (drawAspect!=DVASPECT_CONTENT)
708     return E_FAIL;
709
710   memcpy(buffer, name, sizeof(name));
711
712   return S_OK;
713 }
714
715 /************************************************************************
716  * DataCache_ReadPresentationData
717  *
718  * This method will read information for the requested presentation 
719  * into the given structure.
720  *
721  * Param:
722  *   this       - Pointer to the DataCache object
723  *   drawAspect - The aspect of the object that we wish to draw.
724  *
725  * Returns:
726  *   This method returns a metafile handle if it is successful.
727  *   it will return 0 if not.
728  */
729 static HMETAFILE DataCache_ReadPresMetafile(
730   DataCache* this,
731   DWORD      drawAspect)
732 {
733   LARGE_INTEGER offset;
734   IStream*      presStream = NULL;
735   OLECHAR       streamName[20];
736   HRESULT       hres;
737   void*         metafileBits;
738   STATSTG       streamInfo;
739   HMETAFILE     newMetafile = 0;
740
741   /*
742    * Get the name for the presentation stream.
743    */
744   hres = DataCache_FindPresStreamName(
745            this, 
746            drawAspect,
747            streamName);
748
749   if (FAILED(hres))
750     return hres;
751
752   /*
753    * Open the stream and read the header.
754    */
755   hres = IStorage_OpenStream(
756            this->presentationStorage,
757            streamName,
758            NULL,
759            STGM_READ | STGM_SHARE_EXCLUSIVE,
760            0,
761            &presStream);
762
763   if (FAILED(hres))
764     return hres;
765
766   /*
767    * Get the size of the stream.
768    */
769   hres = IStream_Stat(presStream,
770                       &streamInfo,
771                       STATFLAG_NONAME);
772
773   /*
774    * Skip the header
775    */
776   offset.s.HighPart = 0;
777   offset.s.LowPart  = sizeof(PresentationDataHeader);
778
779   hres = IStream_Seek(
780            presStream,
781            offset,
782            STREAM_SEEK_SET,
783            NULL);
784
785   /*
786    * Allocate a buffer for the metafile bits.
787    */
788   metafileBits = HeapAlloc(GetProcessHeap(), 
789                            0, 
790                            streamInfo.cbSize.s.LowPart);
791
792   /*
793    * Read the metafile bits.
794    */
795   hres = IStream_Read(
796            presStream,
797            metafileBits,
798            streamInfo.cbSize.s.LowPart,
799            NULL);
800
801   /*
802    * Create a metafile with those bits.
803    */
804   if (SUCCEEDED(hres))
805   {
806     newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.s.LowPart, metafileBits);
807   }
808
809   /*
810    * Cleanup.
811    */
812   HeapFree(GetProcessHeap(), 0, metafileBits);
813   IStream_Release(presStream);
814
815   if (newMetafile==0)
816     hres = E_FAIL;
817
818   return newMetafile;
819 }
820
821 /*********************************************************
822  * Method implementation for the  non delegating IUnknown
823  * part of the DataCache class.
824  */
825
826 /************************************************************************
827  * DataCache_NDIUnknown_QueryInterface (IUnknown)
828  *
829  * See Windows documentation for more details on IUnknown methods.
830  *
831  * This version of QueryInterface will not delegate it's implementation
832  * to the outer unknown.
833  */
834 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
835             IUnknown*      iface,
836             REFIID         riid,
837             void**         ppvObject)
838 {
839   _ICOM_THIS_From_NDIUnknown(DataCache, iface);
840
841   /*
842    * Perform a sanity check on the parameters.
843    */
844   if ( (this==0) || (ppvObject==0) )
845     return E_INVALIDARG;
846   
847   /*
848    * Initialize the return parameter.
849    */
850   *ppvObject = 0;
851
852   /*
853    * Compare the riid with the interface IDs implemented by this object.
854    */
855   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
856   {
857     *ppvObject = iface;
858   }
859   else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) 
860   {
861     *ppvObject = (IDataObject*)&(this->lpvtbl1);
862   }
863   else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0)  ||
864             (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
865   {
866     *ppvObject = (IPersistStorage*)&(this->lpvtbl3);
867   }
868   else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
869             (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
870   {
871     *ppvObject = (IViewObject2*)&(this->lpvtbl4);
872   }
873   else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
874             (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
875   {
876     *ppvObject = (IOleCache2*)&(this->lpvtbl5);
877   }
878   else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0) 
879   {
880     *ppvObject = (IOleCacheControl*)&(this->lpvtbl6);
881   }
882
883   /*
884    * Check that we obtained an interface.
885    */
886   if ((*ppvObject)==0)
887   {
888     char clsid[50];
889
890     WINE_StringFromCLSID((LPCLSID)riid,clsid);
891     
892     WARN(
893          "() : asking for un supported interface %s\n", 
894          clsid);
895
896     return E_NOINTERFACE;
897   }
898   
899   /*
900    * Query Interface always increases the reference count by one when it is
901    * successful. 
902    */
903   IUnknown_AddRef((IUnknown*)*ppvObject);
904
905   return S_OK;;  
906 }
907
908 /************************************************************************
909  * DataCache_NDIUnknown_AddRef (IUnknown)
910  *
911  * See Windows documentation for more details on IUnknown methods.
912  *
913  * This version of QueryInterface will not delegate it's implementation
914  * to the outer unknown.
915  */
916 static ULONG WINAPI DataCache_NDIUnknown_AddRef( 
917             IUnknown*      iface)
918 {
919   _ICOM_THIS_From_NDIUnknown(DataCache, iface);
920
921   this->ref++;
922
923   return this->ref;
924 }
925
926 /************************************************************************
927  * DataCache_NDIUnknown_Release (IUnknown)
928  *
929  * See Windows documentation for more details on IUnknown methods.
930  *
931  * This version of QueryInterface will not delegate it's implementation
932  * to the outer unknown.
933  */
934 static ULONG WINAPI DataCache_NDIUnknown_Release( 
935             IUnknown*      iface)
936 {
937   _ICOM_THIS_From_NDIUnknown(DataCache, iface);
938
939   /*
940    * Decrease the reference count on this object.
941    */
942   this->ref--;
943
944   /*
945    * If the reference count goes down to 0, perform suicide.
946    */
947   if (this->ref==0)
948   {
949     DataCache_Destroy(this);
950
951     return 0;
952   }
953   
954   return this->ref;
955 }
956
957 /*********************************************************
958  * Method implementation for the IDataObject
959  * part of the DataCache class.
960  */
961
962 /************************************************************************
963  * DataCache_IDataObject_QueryInterface (IUnknown)
964  *
965  * See Windows documentation for more details on IUnknown methods.
966  */
967 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
968             IDataObject*     iface,
969             REFIID           riid,
970             void**           ppvObject)
971 {
972   _ICOM_THIS_From_IDataObject(DataCache, iface);
973
974   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);  
975 }
976
977 /************************************************************************
978  * DataCache_IDataObject_AddRef (IUnknown)
979  *
980  * See Windows documentation for more details on IUnknown methods.
981  */
982 static ULONG WINAPI DataCache_IDataObject_AddRef( 
983             IDataObject*     iface)
984 {
985   _ICOM_THIS_From_IDataObject(DataCache, iface);
986
987   return IUnknown_AddRef(this->outerUnknown);  
988 }
989
990 /************************************************************************
991  * DataCache_IDataObject_Release (IUnknown)
992  *
993  * See Windows documentation for more details on IUnknown methods.
994  */
995 static ULONG WINAPI DataCache_IDataObject_Release( 
996             IDataObject*     iface)
997 {
998   _ICOM_THIS_From_IDataObject(DataCache, iface);
999
1000   return IUnknown_Release(this->outerUnknown);  
1001 }
1002
1003 static HRESULT WINAPI DataCache_GetData(
1004             IDataObject*     iface,
1005             LPFORMATETC      pformatetcIn, 
1006             STGMEDIUM*       pmedium)
1007 {
1008   FIXME("stub\n");
1009   return E_NOTIMPL;
1010 }
1011
1012 static HRESULT WINAPI DataCache_GetDataHere(
1013             IDataObject*     iface, 
1014             LPFORMATETC      pformatetc,
1015             STGMEDIUM*       pmedium)
1016 {
1017   FIXME("stub\n");
1018   return E_NOTIMPL;
1019 }
1020
1021 static HRESULT WINAPI DataCache_QueryGetData(
1022             IDataObject*     iface,
1023             LPFORMATETC      pformatetc)
1024 {
1025   FIXME("stub\n");
1026   return E_NOTIMPL;
1027 }
1028
1029 /************************************************************************
1030  * DataCache_EnumFormatEtc (IDataObject)
1031  *
1032  * The data cache doesn't implement this method.
1033  *
1034  * See Windows documentation for more details on IDataObject methods.
1035  */
1036 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
1037             IDataObject*     iface, 
1038             LPFORMATETC      pformatectIn, 
1039             LPFORMATETC      pformatetcOut)
1040 {
1041   TRACE("()\n");
1042   return E_NOTIMPL;
1043 }
1044
1045 /************************************************************************
1046  * DataCache_IDataObject_SetData (IDataObject)
1047  *
1048  * This method is delegated to the IOleCache2 implementation.
1049  *
1050  * See Windows documentation for more details on IDataObject methods.
1051  */
1052 static HRESULT WINAPI DataCache_IDataObject_SetData(
1053             IDataObject*     iface,
1054             LPFORMATETC      pformatetc, 
1055             STGMEDIUM*       pmedium, 
1056             BOOL             fRelease)
1057 {
1058   IOleCache2* oleCache = NULL;
1059   HRESULT     hres;
1060
1061   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
1062
1063   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
1064
1065   if (FAILED(hres))
1066     return E_UNEXPECTED;
1067
1068   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
1069
1070   IOleCache2_Release(oleCache);
1071
1072   return hres;;
1073 }
1074
1075 /************************************************************************
1076  * DataCache_EnumFormatEtc (IDataObject)
1077  *
1078  * The data cache doesn't implement this method.
1079  *
1080  * See Windows documentation for more details on IDataObject methods.
1081  */
1082 static HRESULT WINAPI DataCache_EnumFormatEtc(
1083             IDataObject*     iface,       
1084             DWORD            dwDirection,
1085             IEnumFORMATETC** ppenumFormatEtc)
1086 {
1087   TRACE("()\n");
1088   return E_NOTIMPL;
1089 }
1090
1091 /************************************************************************
1092  * DataCache_DAdvise (IDataObject)
1093  *
1094  * The data cache doesn't support connections.
1095  *
1096  * See Windows documentation for more details on IDataObject methods.
1097  */
1098 static HRESULT WINAPI DataCache_DAdvise(
1099             IDataObject*     iface, 
1100             FORMATETC*       pformatetc, 
1101             DWORD            advf, 
1102             IAdviseSink*     pAdvSink, 
1103             DWORD*           pdwConnection)
1104 {
1105   TRACE("()\n");
1106   return OLE_E_ADVISENOTSUPPORTED;
1107 }
1108
1109 /************************************************************************
1110  * DataCache_DUnadvise (IDataObject)
1111  *
1112  * The data cache doesn't support connections.
1113  *
1114  * See Windows documentation for more details on IDataObject methods.
1115  */
1116 static HRESULT WINAPI DataCache_DUnadvise(
1117             IDataObject*     iface,
1118             DWORD            dwConnection)
1119 {
1120   TRACE("()\n");
1121   return OLE_E_NOCONNECTION;
1122 }
1123
1124 /************************************************************************
1125  * DataCache_EnumDAdvise (IDataObject)
1126  *
1127  * The data cache doesn't support connections.
1128  *
1129  * See Windows documentation for more details on IDataObject methods.
1130  */
1131 static HRESULT WINAPI DataCache_EnumDAdvise(
1132             IDataObject*     iface,
1133             IEnumSTATDATA**  ppenumAdvise)
1134 {
1135   TRACE("()\n");
1136   return OLE_E_ADVISENOTSUPPORTED;
1137 }
1138
1139 /*********************************************************
1140  * Method implementation for the IDataObject
1141  * part of the DataCache class.
1142  */
1143
1144 /************************************************************************
1145  * DataCache_IPersistStorage_QueryInterface (IUnknown)
1146  *
1147  * See Windows documentation for more details on IUnknown methods.
1148  */
1149 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
1150             IPersistStorage* iface,
1151             REFIID           riid,
1152             void**           ppvObject)
1153 {
1154   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1155
1156   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);  
1157 }
1158
1159 /************************************************************************
1160  * DataCache_IPersistStorage_AddRef (IUnknown)
1161  *
1162  * See Windows documentation for more details on IUnknown methods.
1163  */
1164 static ULONG WINAPI DataCache_IPersistStorage_AddRef( 
1165             IPersistStorage* iface)
1166 {
1167   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1168
1169   return IUnknown_AddRef(this->outerUnknown);  
1170 }
1171
1172 /************************************************************************
1173  * DataCache_IPersistStorage_Release (IUnknown)
1174  *
1175  * See Windows documentation for more details on IUnknown methods.
1176  */
1177 static ULONG WINAPI DataCache_IPersistStorage_Release( 
1178             IPersistStorage* iface)
1179 {
1180   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1181
1182   return IUnknown_Release(this->outerUnknown);  
1183 }
1184
1185 /************************************************************************
1186  * DataCache_GetClassID (IPersistStorage)
1187  *
1188  * The data cache doesn't implement this method.
1189  *
1190  * See Windows documentation for more details on IPersistStorage methods.
1191  */
1192 static HRESULT WINAPI DataCache_GetClassID( 
1193             IPersistStorage* iface,
1194             CLSID*           pClassID)
1195 {
1196   TRACE("(%p, %p)\n", iface, pClassID);
1197   return E_NOTIMPL;
1198 }
1199
1200 /************************************************************************
1201  * DataCache_IsDirty (IPersistStorage)
1202  *
1203  * Until we actully connect to a running object and retrieve new 
1204  * information to it, we never get dirty.
1205  *
1206  * See Windows documentation for more details on IPersistStorage methods.
1207  */
1208 static HRESULT WINAPI DataCache_IsDirty( 
1209             IPersistStorage* iface)
1210 {
1211   TRACE("(%p)\n", iface);
1212
1213   return S_FALSE;
1214 }
1215
1216 /************************************************************************
1217  * DataCache_InitNew (IPersistStorage)
1218  *
1219  * The data cache implementation of IPersistStorage_InitNew simply stores
1220  * the storage pointer.
1221  *
1222  * See Windows documentation for more details on IPersistStorage methods.
1223  */
1224 static HRESULT WINAPI DataCache_InitNew( 
1225             IPersistStorage* iface, 
1226             IStorage*        pStg)
1227 {
1228   TRACE("(%p, %p)\n", iface, pStg);
1229
1230   return DataCache_Load(iface, pStg);
1231 }
1232
1233 /************************************************************************
1234  * DataCache_Load (IPersistStorage)
1235  *
1236  * The data cache implementation of IPersistStorage_Load doesn't 
1237  * actually load anything. Instead, it holds on to the storage pointer
1238  * and it will load the presentation information when the 
1239  * IDataObject_GetData or IViewObject2_Draw methods are called.
1240  *
1241  * See Windows documentation for more details on IPersistStorage methods.
1242  */
1243 static HRESULT WINAPI DataCache_Load( 
1244             IPersistStorage* iface,
1245             IStorage*        pStg)
1246 {
1247   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1248
1249   TRACE("(%p, %p)\n", iface, pStg);
1250
1251   if (this->presentationStorage != NULL)
1252   {
1253     IStorage_Release(this->presentationStorage);
1254   }
1255
1256   this->presentationStorage = pStg;
1257
1258   if (this->presentationStorage != NULL)
1259   {
1260     IStorage_AddRef(this->presentationStorage);
1261   }
1262
1263   return S_OK;
1264 }
1265
1266 /************************************************************************
1267  * DataCache_Save (IPersistStorage)
1268  *
1269  * Until we actully connect to a running object and retrieve new 
1270  * information to it, we never have to save anything. However, it is
1271  * our responsability to copy the information when saving to a new
1272  * storage.
1273  *
1274  * See Windows documentation for more details on IPersistStorage methods.
1275  */
1276 static HRESULT WINAPI DataCache_Save( 
1277             IPersistStorage* iface,
1278             IStorage*        pStg, 
1279             BOOL             fSameAsLoad)
1280 {
1281   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1282
1283   TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
1284
1285   if ( (!fSameAsLoad) && 
1286        (this->presentationStorage!=NULL) )
1287   {
1288     return IStorage_CopyTo(this->presentationStorage,
1289                            0,
1290                            NULL,
1291                            NULL,
1292                            pStg);
1293   }
1294
1295   return S_OK;
1296 }
1297
1298 /************************************************************************
1299  * DataCache_SaveCompleted (IPersistStorage)
1300  *
1301  * This method is called to tell the cache to release the storage
1302  * pointer it's currentlu holding.
1303  *
1304  * See Windows documentation for more details on IPersistStorage methods.
1305  */
1306 static HRESULT WINAPI DataCache_SaveCompleted( 
1307             IPersistStorage* iface,  
1308             IStorage*        pStgNew)
1309 {
1310   TRACE("(%p, %p)\n", iface, pStgNew);
1311
1312   /*
1313    * First, make sure we get our hands off any storage we have.
1314    */
1315   DataCache_HandsOffStorage(iface);
1316
1317   /*
1318    * Then, attach to the new storage.
1319    */
1320   DataCache_Load(iface, pStgNew);
1321
1322   return S_OK;
1323 }
1324
1325 /************************************************************************
1326  * DataCache_HandsOffStorage (IPersistStorage)
1327  *
1328  * This method is called to tell the cache to release the storage
1329  * pointer it's currentlu holding.
1330  *
1331  * See Windows documentation for more details on IPersistStorage methods.
1332  */
1333 static HRESULT WINAPI DataCache_HandsOffStorage(
1334             IPersistStorage* iface)
1335 {
1336   _ICOM_THIS_From_IPersistStorage(DataCache, iface);
1337
1338   TRACE("(%p)\n", iface);
1339
1340   if (this->presentationStorage != NULL)
1341   {
1342     IStorage_Release(this->presentationStorage);
1343     this->presentationStorage = NULL;
1344   }
1345
1346   return S_OK;
1347 }
1348
1349 /*********************************************************
1350  * Method implementation for the IViewObject2
1351  * part of the DataCache class.
1352  */
1353
1354 /************************************************************************
1355  * DataCache_IViewObject2_QueryInterface (IUnknown)
1356  *
1357  * See Windows documentation for more details on IUnknown methods.
1358  */
1359 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
1360             IViewObject2* iface,
1361             REFIID           riid,
1362             void**           ppvObject)
1363 {
1364   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1365
1366   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);  
1367 }
1368
1369 /************************************************************************
1370  * DataCache_IViewObject2_AddRef (IUnknown)
1371  *
1372  * See Windows documentation for more details on IUnknown methods.
1373  */
1374 static ULONG WINAPI DataCache_IViewObject2_AddRef( 
1375             IViewObject2* iface)
1376 {
1377   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1378
1379   return IUnknown_AddRef(this->outerUnknown);  
1380 }
1381
1382 /************************************************************************
1383  * DataCache_IViewObject2_Release (IUnknown)
1384  *
1385  * See Windows documentation for more details on IUnknown methods.
1386  */
1387 static ULONG WINAPI DataCache_IViewObject2_Release( 
1388             IViewObject2* iface)
1389 {
1390   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1391
1392   return IUnknown_Release(this->outerUnknown);  
1393 }
1394
1395 /************************************************************************
1396  * DataCache_Draw (IViewObject2)
1397  *
1398  * This method will draw the cached representation of the object
1399  * to the given device context.
1400  *
1401  * See Windows documentation for more details on IViewObject2 methods.
1402  */
1403 static HRESULT WINAPI DataCache_Draw(
1404             IViewObject2*    iface,
1405             DWORD            dwDrawAspect,
1406             LONG             lindex,
1407             void*            pvAspect,
1408             DVTARGETDEVICE*  ptd, 
1409             HDC              hdcTargetDev, 
1410             HDC              hdcDraw,
1411             LPCRECTL         lprcBounds,
1412             LPCRECTL         lprcWBounds,
1413             IVO_ContCallback pfnContinue,
1414             DWORD            dwContinue)
1415 {
1416   PresentationDataHeader presData;
1417   HMETAFILE              presMetafile = 0;
1418   HRESULT                hres;
1419
1420   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1421
1422   TRACE("(%p, %lx, %ld, %p, %x, %x, %p, %p, %p, %lx)\n",
1423         iface,
1424         dwDrawAspect,
1425         lindex,
1426         pvAspect,
1427         hdcTargetDev, 
1428         hdcDraw,
1429         lprcBounds,
1430         lprcWBounds,
1431         pfnContinue,
1432         dwContinue);
1433
1434   /*
1435    * Sanity check
1436    */
1437   if (lprcBounds==NULL)
1438     return E_INVALIDARG;
1439
1440   /*
1441    * First, we need to retrieve the dimensions of the
1442    * image in the metafile.
1443    */
1444   hres = DataCache_ReadPresentationData(this,
1445                                         dwDrawAspect,
1446                                         &presData);
1447
1448   if (FAILED(hres))
1449     return hres;
1450
1451   /*
1452    * Then, we can extract the metafile itself from the cached
1453    * data.
1454    */
1455   presMetafile = DataCache_ReadPresMetafile(this,
1456                                             dwDrawAspect);
1457
1458   /*
1459    * If we have a metafile, just draw baby...
1460    * We have to be careful not to modify the state of the
1461    * DC.
1462    */
1463   if (presMetafile!=0)
1464   {
1465     INT   prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC);
1466     SIZE  oldWindowExt;
1467     SIZE  oldViewportExt;
1468     POINT oldViewportOrg;
1469
1470     SetWindowExtEx(hdcDraw,
1471                    presData.objectExtentX,
1472                    presData.objectExtentY,
1473                    &oldWindowExt);
1474
1475     SetViewportExtEx(hdcDraw, 
1476                      lprcBounds->right - lprcBounds->left,
1477                      lprcBounds->bottom - lprcBounds->top,
1478                      &oldViewportExt);
1479
1480     SetViewportOrgEx(hdcDraw,
1481                      lprcBounds->left,
1482                      lprcBounds->top,
1483                      &oldViewportOrg);
1484
1485     PlayMetaFile(hdcDraw, presMetafile);
1486
1487     SetWindowExtEx(hdcDraw,
1488                    oldWindowExt.cx,
1489                    oldWindowExt.cy,
1490                    NULL);
1491
1492     SetViewportExtEx(hdcDraw, 
1493                      oldViewportExt.cx,
1494                      oldViewportExt.cy,
1495                      NULL);
1496
1497     SetViewportOrgEx(hdcDraw,
1498                      oldViewportOrg.x,
1499                      oldViewportOrg.y,
1500                      NULL);
1501
1502     SetMapMode(hdcDraw, prevMapMode);
1503
1504     DeleteMetaFile(presMetafile);
1505   }
1506
1507   return S_OK;
1508 }
1509
1510 static HRESULT WINAPI DataCache_GetColorSet(
1511             IViewObject2*   iface, 
1512             DWORD           dwDrawAspect, 
1513             LONG            lindex, 
1514             void*           pvAspect, 
1515             DVTARGETDEVICE* ptd, 
1516             HDC             hicTargetDevice, 
1517             LOGPALETTE**    ppColorSet)
1518 {
1519   FIXME("stub\n");
1520   return E_NOTIMPL;
1521 }
1522
1523 static HRESULT WINAPI DataCache_Freeze(
1524             IViewObject2*   iface,
1525             DWORD           dwDrawAspect,
1526             LONG            lindex,
1527             void*           pvAspect, 
1528             DWORD*          pdwFreeze)
1529 {
1530   FIXME("stub\n");
1531   return E_NOTIMPL;
1532 }
1533
1534 static HRESULT WINAPI DataCache_Unfreeze(
1535             IViewObject2*   iface,
1536             DWORD           dwFreeze)
1537 {
1538   FIXME("stub\n");
1539   return E_NOTIMPL;
1540 }
1541
1542 /************************************************************************
1543  * DataCache_SetAdvise (IViewObject2)
1544  *
1545  * This sets-up an advisory sink with the data cache. When the object's
1546  * view changes, this sink is called.
1547  *
1548  * See Windows documentation for more details on IViewObject2 methods.
1549  */
1550 static HRESULT WINAPI DataCache_SetAdvise(
1551             IViewObject2*   iface,
1552             DWORD           aspects, 
1553             DWORD           advf, 
1554             IAdviseSink*    pAdvSink)
1555 {
1556   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1557
1558   TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink);
1559
1560   /*
1561    * A call to this function removes the previous sink
1562    */
1563   if (this->sinkInterface != NULL)
1564   {
1565     IAdviseSink_Release(this->sinkInterface);
1566     this->sinkInterface  = NULL;
1567     this->sinkAspects    = 0; 
1568     this->sinkAdviseFlag = 0;
1569   }
1570
1571   /*
1572    * Now, setup the new one.
1573    */
1574   if (pAdvSink!=NULL)
1575   {
1576     this->sinkInterface  = pAdvSink;
1577     this->sinkAspects    = aspects; 
1578     this->sinkAdviseFlag = advf;    
1579
1580     IAdviseSink_AddRef(this->sinkInterface);
1581   }
1582
1583   /*
1584    * When the ADVF_PRIMEFIRST flag is set, we have to advise the
1585    * sink immediately.
1586    */
1587   if (advf & ADVF_PRIMEFIRST)
1588   {
1589     DataCache_FireOnViewChange(this,
1590                                DVASPECT_CONTENT,
1591                                -1);
1592   }
1593
1594   return S_OK;
1595 }
1596
1597 /************************************************************************
1598  * DataCache_GetAdvise (IViewObject2)
1599  *
1600  * This method queries the current state of the advise sink 
1601  * installed on the data cache.
1602  *
1603  * See Windows documentation for more details on IViewObject2 methods.
1604  */
1605 static HRESULT WINAPI DataCache_GetAdvise(
1606             IViewObject2*   iface, 
1607             DWORD*          pAspects, 
1608             DWORD*          pAdvf, 
1609             IAdviseSink**   ppAdvSink)
1610 {
1611   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1612
1613   TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
1614
1615   /*
1616    * Just copy all the requested values.
1617    */
1618   if (pAspects!=NULL)
1619     *pAspects = this->sinkAspects;
1620
1621   if (pAdvf!=NULL)
1622     *pAdvf = this->sinkAdviseFlag;
1623
1624   if (ppAdvSink!=NULL)
1625   {
1626     IAdviseSink_QueryInterface(this->sinkInterface, 
1627                                &IID_IAdviseSink, 
1628                                (void**)ppAdvSink);
1629   }
1630
1631   return S_OK;
1632 }
1633
1634 /************************************************************************
1635  * DataCache_GetExtent (IViewObject2)
1636  *
1637  * This method retrieves the "natural" size of this cached object.
1638  *
1639  * See Windows documentation for more details on IViewObject2 methods.
1640  */
1641 static HRESULT WINAPI DataCache_GetExtent(
1642             IViewObject2*   iface, 
1643             DWORD           dwDrawAspect, 
1644             LONG            lindex, 
1645             DVTARGETDEVICE* ptd, 
1646             LPSIZEL         lpsizel)
1647 {
1648   PresentationDataHeader presData;
1649   HRESULT                hres = E_FAIL;
1650
1651   _ICOM_THIS_From_IViewObject2(DataCache, iface);
1652
1653   TRACE("(%p, %lx, %ld, %p, %p)\n", 
1654         iface, dwDrawAspect, lindex, ptd, lpsizel);
1655
1656   /*
1657    * Sanity check
1658    */
1659   if (lpsizel==NULL)
1660     return E_POINTER;
1661
1662   /*
1663    * Initialize the out parameter.
1664    */
1665   lpsizel->cx = 0;
1666   lpsizel->cy = 0;
1667
1668   /*
1669    * This flag should be set to -1.
1670    */
1671   if (lindex!=-1)
1672     FIXME("Unimplemented flag lindex = %ld\n", lindex);
1673
1674   /*
1675    * Right now, we suport only the callback from
1676    * the default handler.
1677    */
1678   if (ptd!=NULL)
1679     FIXME("Unimplemented ptd = %p\n", ptd);
1680   
1681   /*
1682    * Get the presentation information from the 
1683    * cache.
1684    */
1685   hres = DataCache_ReadPresentationData(this,
1686                                         dwDrawAspect,
1687                                         &presData);
1688
1689   if (SUCCEEDED(hres))
1690   {
1691     lpsizel->cx = presData.objectExtentX;
1692     lpsizel->cy = presData.objectExtentY;
1693   }
1694
1695   /*
1696    * This method returns OLE_E_BLANK when it fails.
1697    */
1698   if (FAILED(hres))
1699     hres = OLE_E_BLANK;
1700
1701   return hres;
1702 }
1703
1704
1705 /*********************************************************
1706  * Method implementation for the IOleCache2
1707  * part of the DataCache class.
1708  */
1709
1710 /************************************************************************
1711  * DataCache_IOleCache2_QueryInterface (IUnknown)
1712  *
1713  * See Windows documentation for more details on IUnknown methods.
1714  */
1715 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
1716             IOleCache2*     iface,
1717             REFIID          riid,
1718             void**          ppvObject)
1719 {
1720   _ICOM_THIS_From_IOleCache2(DataCache, iface);
1721
1722   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);  
1723 }
1724
1725 /************************************************************************
1726  * DataCache_IOleCache2_AddRef (IUnknown)
1727  *
1728  * See Windows documentation for more details on IUnknown methods.
1729  */
1730 static ULONG WINAPI DataCache_IOleCache2_AddRef( 
1731             IOleCache2*     iface)
1732 {
1733   _ICOM_THIS_From_IOleCache2(DataCache, iface);
1734
1735   return IUnknown_AddRef(this->outerUnknown);  
1736 }
1737
1738 /************************************************************************
1739  * DataCache_IOleCache2_Release (IUnknown)
1740  *
1741  * See Windows documentation for more details on IUnknown methods.
1742  */
1743 static ULONG WINAPI DataCache_IOleCache2_Release( 
1744             IOleCache2*     iface)
1745 {
1746   _ICOM_THIS_From_IOleCache2(DataCache, iface);
1747
1748   return IUnknown_Release(this->outerUnknown);  
1749 }
1750
1751 static HRESULT WINAPI DataCache_Cache(
1752             IOleCache2*     iface,
1753             FORMATETC*      pformatetc,
1754             DWORD           advf,
1755             DWORD*          pdwConnection)
1756 {
1757   FIXME("stub\n");
1758   return E_NOTIMPL;
1759 }
1760
1761 static HRESULT WINAPI DataCache_Uncache(
1762             IOleCache2*     iface,
1763             DWORD           dwConnection)
1764 {
1765   FIXME("stub\n");
1766   return E_NOTIMPL;
1767 }
1768
1769 static HRESULT WINAPI DataCache_EnumCache(
1770             IOleCache2*     iface,
1771             IEnumSTATDATA** ppenumSTATDATA)
1772 {
1773   FIXME("stub\n");
1774   return E_NOTIMPL;
1775 }
1776
1777 static HRESULT WINAPI DataCache_InitCache(
1778             IOleCache2*     iface,
1779             IDataObject*    pDataObject)
1780 {
1781   FIXME("stub\n");
1782   return E_NOTIMPL;
1783 }
1784
1785 static HRESULT WINAPI DataCache_IOleCache2_SetData(
1786             IOleCache2*     iface,
1787             FORMATETC*      pformatetc,
1788             STGMEDIUM*      pmedium,
1789             BOOL            fRelease)
1790 {
1791   FIXME("stub\n");
1792   return E_NOTIMPL;
1793 }
1794
1795 static HRESULT WINAPI DataCache_UpdateCache(
1796             IOleCache2*     iface,
1797             LPDATAOBJECT    pDataObject, 
1798             DWORD           grfUpdf,
1799             LPVOID          pReserved)
1800 {
1801   FIXME("stub\n");
1802   return E_NOTIMPL;
1803 }
1804
1805 static HRESULT WINAPI DataCache_DiscardCache(
1806             IOleCache2*     iface,
1807             DWORD           dwDiscardOptions)
1808 {
1809   FIXME("stub\n");
1810   return E_NOTIMPL;
1811 }
1812
1813
1814 /*********************************************************
1815  * Method implementation for the IOleCacheControl
1816  * part of the DataCache class.
1817  */
1818
1819 /************************************************************************
1820  * DataCache_IOleCacheControl_QueryInterface (IUnknown)
1821  *
1822  * See Windows documentation for more details on IUnknown methods.
1823  */
1824 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
1825             IOleCacheControl* iface,
1826             REFIID            riid,
1827             void**            ppvObject)
1828 {
1829   _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
1830
1831   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);  
1832 }
1833
1834 /************************************************************************
1835  * DataCache_IOleCacheControl_AddRef (IUnknown)
1836  *
1837  * See Windows documentation for more details on IUnknown methods.
1838  */
1839 static ULONG WINAPI DataCache_IOleCacheControl_AddRef( 
1840             IOleCacheControl* iface)
1841 {
1842   _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
1843
1844   return IUnknown_AddRef(this->outerUnknown);  
1845 }
1846
1847 /************************************************************************
1848  * DataCache_IOleCacheControl_Release (IUnknown)
1849  *
1850  * See Windows documentation for more details on IUnknown methods.
1851  */
1852 static ULONG WINAPI DataCache_IOleCacheControl_Release( 
1853             IOleCacheControl* iface)
1854 {
1855   _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
1856
1857   return IUnknown_Release(this->outerUnknown);  
1858 }
1859
1860 static HRESULT WINAPI DataCache_OnRun(
1861             IOleCacheControl* iface,
1862             LPDATAOBJECT      pDataObject)
1863 {
1864   FIXME("stub\n");
1865   return E_NOTIMPL;
1866 }
1867
1868 static HRESULT WINAPI DataCache_OnStop(
1869             IOleCacheControl* iface)
1870 {
1871   FIXME("stub\n");
1872   return E_NOTIMPL;
1873 }
1874
1875