ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

datacache.c
Go to the documentation of this file.
00001 /*
00002  *  OLE 2 Data cache
00003  *
00004  *      Copyright 1999  Francis Beaudet
00005  *      Copyright 2000  Abey George
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  *
00021  * NOTES:
00022  *    The OLE2 data cache supports a whole whack of
00023  *    interfaces including:
00024  *       IDataObject, IPersistStorage, IViewObject2,
00025  *       IOleCache2 and IOleCacheControl.
00026  *
00027  *    Most of the implementation details are taken from: Inside OLE
00028  *    second edition by Kraig Brockschmidt,
00029  *
00030  * NOTES
00031  *  -  This implementation of the datacache will let your application
00032  *     load documents that have embedded OLE objects in them and it will
00033  *     also retrieve the metafile representation of those objects.
00034  *  -  This implementation of the datacache will also allow your
00035  *     application to save new documents with OLE objects in them.
00036  *  -  The main thing that it doesn't do is allow you to activate
00037  *     or modify the OLE objects in any way.
00038  *  -  I haven't found any good documentation on the real usage of
00039  *     the streams created by the data cache. In particular, How to
00040  *     determine what the XXX stands for in the stream name
00041  *     "\002OlePresXXX". It appears to just be a counter.
00042  *  -  Also, I don't know the real content of the presentation stream
00043  *     header. I was able to figure-out where the extent of the object
00044  *     was stored and the aspect, but that's about it.
00045  */
00046 #include <stdarg.h>
00047 #include <string.h>
00048 
00049 #define COBJMACROS
00050 #define NONAMELESSUNION
00051 #define NONAMELESSSTRUCT
00052 
00053 #include "windef.h"
00054 #include "winbase.h"
00055 #include "wingdi.h"
00056 #include "winuser.h"
00057 #include "winerror.h"
00058 #include "wine/unicode.h"
00059 #include "ole2.h"
00060 #include "wine/list.h"
00061 #include "wine/debug.h"
00062 
00063 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00064 
00065 /****************************************************************************
00066  * PresentationDataHeader
00067  *
00068  * This structure represents the header of the \002OlePresXXX stream in
00069  * the OLE object storage.
00070  */
00071 typedef struct PresentationDataHeader
00072 {
00073   /* clipformat:
00074    *  - standard clipformat:
00075    *  DWORD length = 0xffffffff;
00076    *  DWORD cfFormat;
00077    *  - or custom clipformat:
00078    *  DWORD length;
00079    *  CHAR format_name[length]; (null-terminated)
00080    */
00081   DWORD unknown3;   /* 4, possibly TYMED_ISTREAM */
00082   DVASPECT dvAspect;
00083   DWORD lindex;
00084   DWORD tymed;
00085   DWORD unknown7;   /* 0 */
00086   DWORD dwObjectExtentX;
00087   DWORD dwObjectExtentY;
00088   DWORD dwSize;
00089 } PresentationDataHeader;
00090 
00091 typedef struct DataCacheEntry
00092 {
00093   struct list entry;
00094   /* format of this entry */
00095   FORMATETC fmtetc;
00096   /* the clipboard format of the data */
00097   CLIPFORMAT data_cf;
00098   /* cached data */
00099   STGMEDIUM stgmedium;
00100   /*
00101    * This storage pointer is set through a call to
00102    * IPersistStorage_Load. This is where the visual
00103    * representation of the object is stored.
00104    */
00105   IStorage *storage;
00106   /* connection ID */
00107   DWORD id;
00108   /* dirty flag */
00109   BOOL dirty;
00110   /* stream number (-1 if not set ) */
00111   unsigned short stream_number;
00112   /* sink id set when object is running */
00113   DWORD sink_id;
00114   /* Advise sink flags */
00115   DWORD advise_flags;
00116 } DataCacheEntry;
00117 
00118 /****************************************************************************
00119  * DataCache
00120  */
00121 struct DataCache
00122 {
00123   /*
00124    * List all interface here
00125    */
00126   IDataObject       IDataObject_iface;
00127   IUnknown          IUnknown_iface;
00128   IPersistStorage   IPersistStorage_iface;
00129   IViewObject2      IViewObject2_iface;
00130   IOleCache2        IOleCache2_iface;
00131   IOleCacheControl  IOleCacheControl_iface;
00132 
00133   /* The sink that is connected to a remote object.
00134      The other interfaces are not available by QI'ing the sink and vice-versa */
00135   IAdviseSink       IAdviseSink_iface;
00136 
00137   /*
00138    * Reference count of this object
00139    */
00140   LONG ref;
00141 
00142   /*
00143    * IUnknown implementation of the outer object.
00144    */
00145   IUnknown* outerUnknown;
00146 
00147   /*
00148    * The user of this object can setup ONE advise sink
00149    * connection with the object. These parameters describe
00150    * that connection.
00151    */
00152   DWORD        sinkAspects;
00153   DWORD        sinkAdviseFlag;
00154   IAdviseSink* sinkInterface;
00155   IStorage *presentationStorage;
00156 
00157   /* list of cache entries */
00158   struct list cache_list;
00159   /* last id assigned to an entry */
00160   DWORD last_cache_id;
00161   /* dirty flag */
00162   BOOL dirty;
00163   /* running object set by OnRun */
00164   IDataObject *running_object;
00165 };
00166 
00167 typedef struct DataCache DataCache;
00168 
00169 /*
00170  * Here, I define utility macros to help with the casting of the
00171  * "this" parameter.
00172  * There is a version to accommodate all of the VTables implemented
00173  * by this object.
00174  */
00175 
00176 static inline DataCache *impl_from_IDataObject( IDataObject *iface )
00177 {
00178     return CONTAINING_RECORD(iface, DataCache, IDataObject_iface);
00179 }
00180 
00181 static inline DataCache *impl_from_IUnknown( IUnknown *iface )
00182 {
00183     return CONTAINING_RECORD(iface, DataCache, IUnknown_iface);
00184 }
00185 
00186 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface )
00187 {
00188     return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface);
00189 }
00190 
00191 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface )
00192 {
00193     return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface);
00194 }
00195 
00196 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface )
00197 {
00198     return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface);
00199 }
00200 
00201 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface )
00202 {
00203     return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface);
00204 }
00205 
00206 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface )
00207 {
00208     return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface);
00209 }
00210 
00211 static const char * debugstr_formatetc(const FORMATETC *formatetc)
00212 {
00213     return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }",
00214         formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect,
00215         formatetc->lindex, formatetc->tymed);
00216 }
00217 
00218 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry)
00219 {
00220     list_remove(&cache_entry->entry);
00221     if (cache_entry->storage)
00222         IStorage_Release(cache_entry->storage);
00223     HeapFree(GetProcessHeap(), 0, cache_entry->fmtetc.ptd);
00224     ReleaseStgMedium(&cache_entry->stgmedium);
00225     if(cache_entry->sink_id)
00226         IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id);
00227 
00228     HeapFree(GetProcessHeap(), 0, cache_entry);
00229 }
00230 
00231 static void DataCache_Destroy(
00232   DataCache* ptrToDestroy)
00233 {
00234   DataCacheEntry *cache_entry, *next_cache_entry;
00235 
00236   TRACE("()\n");
00237 
00238   if (ptrToDestroy->sinkInterface != NULL)
00239   {
00240     IAdviseSink_Release(ptrToDestroy->sinkInterface);
00241     ptrToDestroy->sinkInterface = NULL;
00242   }
00243 
00244   LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry)
00245     DataCacheEntry_Destroy(ptrToDestroy, cache_entry);
00246 
00247   if (ptrToDestroy->presentationStorage != NULL)
00248   {
00249     IStorage_Release(ptrToDestroy->presentationStorage);
00250     ptrToDestroy->presentationStorage = NULL;
00251   }
00252 
00253   /*
00254    * Free the datacache pointer.
00255    */
00256   HeapFree(GetProcessHeap(), 0, ptrToDestroy);
00257 }
00258 
00259 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc)
00260 {
00261     DataCacheEntry *cache_entry;
00262     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
00263     {
00264         /* FIXME: also compare DVTARGETDEVICEs */
00265         if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) &&
00266             (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) &&
00267             (formatetc->lindex == cache_entry->fmtetc.lindex) &&
00268             (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed)))
00269             return cache_entry;
00270     }
00271     return NULL;
00272 }
00273 
00274 /* checks that the clipformat and tymed are valid and returns an error if they
00275 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by
00276 * DataCache_Draw */
00277 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed)
00278 {
00279     if (!cfFormat || !tymed ||
00280         (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) ||
00281         (cfFormat == CF_BITMAP && tymed == TYMED_GDI) ||
00282         (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) ||
00283         (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF))
00284         return S_OK;
00285     else if (tymed == TYMED_HGLOBAL)
00286         return CACHE_S_FORMATETC_NOTSUPPORTED;
00287     else
00288     {
00289         WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed);
00290         return DV_E_TYMED;
00291     }
00292 }
00293 
00294 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry)
00295 {
00296     HRESULT hr;
00297 
00298     hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed);
00299     if (FAILED(hr))
00300         return hr;
00301     if (hr == CACHE_S_FORMATETC_NOTSUPPORTED)
00302         TRACE("creating unsupported format %d\n", formatetc->cfFormat);
00303 
00304     *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry));
00305     if (!*cache_entry)
00306         return E_OUTOFMEMORY;
00307 
00308     (*cache_entry)->fmtetc = *formatetc;
00309     if (formatetc->ptd)
00310     {
00311         (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize);
00312         memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize);
00313     }
00314     (*cache_entry)->data_cf = 0;
00315     (*cache_entry)->stgmedium.tymed = TYMED_NULL;
00316     (*cache_entry)->stgmedium.pUnkForRelease = NULL;
00317     (*cache_entry)->storage = NULL;
00318     (*cache_entry)->id = This->last_cache_id++;
00319     (*cache_entry)->dirty = TRUE;
00320     (*cache_entry)->stream_number = -1;
00321     (*cache_entry)->sink_id = 0;
00322     (*cache_entry)->advise_flags = 0;
00323     list_add_tail(&This->cache_list, &(*cache_entry)->entry);
00324     return hr;
00325 }
00326 
00327 /************************************************************************
00328  * DataCache_FireOnViewChange
00329  *
00330  * This method will fire an OnViewChange notification to the advise
00331  * sink registered with the datacache.
00332  *
00333  * See IAdviseSink::OnViewChange for more details.
00334  */
00335 static void DataCache_FireOnViewChange(
00336   DataCache* this,
00337   DWORD      aspect,
00338   LONG       lindex)
00339 {
00340   TRACE("(%p, %x, %d)\n", this, aspect, lindex);
00341 
00342   /*
00343    * The sink supplies a filter when it registers
00344    * we make sure we only send the notifications when that
00345    * filter matches.
00346    */
00347   if ((this->sinkAspects & aspect) != 0)
00348   {
00349     if (this->sinkInterface != NULL)
00350     {
00351       IAdviseSink_OnViewChange(this->sinkInterface,
00352                    aspect,
00353                    lindex);
00354 
00355       /*
00356        * Some sinks want to be unregistered automatically when
00357        * the first notification goes out.
00358        */
00359       if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
00360       {
00361     IAdviseSink_Release(this->sinkInterface);
00362 
00363     this->sinkInterface  = NULL;
00364     this->sinkAspects    = 0;
00365     this->sinkAdviseFlag = 0;
00366       }
00367     }
00368   }
00369 }
00370 
00371 /* Helper for DataCacheEntry_OpenPresStream */
00372 static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
00373 {
00374     /* The presentation streams have names of the form "\002OlePresXXX",
00375      * where XXX goes from 000 to 999. */
00376     static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };
00377 
00378     LPCWSTR name = elem->pwcsName;
00379 
00380     return (elem->type == STGTY_STREAM)
00381     && (strlenW(name) == 11)
00382     && (strncmpW(name, OlePres, 8) == 0)
00383     && (name[8] >= '0') && (name[8] <= '9')
00384     && (name[9] >= '0') && (name[9] <= '9')
00385     && (name[10] >= '0') && (name[10] <= '9');
00386 }
00387 
00388 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat)
00389 {
00390     DWORD length;
00391     HRESULT hr;
00392     ULONG read;
00393 
00394     *clipformat = 0;
00395 
00396     hr = IStream_Read(stream, &length, sizeof(length), &read);
00397     if (hr != S_OK || read != sizeof(length))
00398         return DV_E_CLIPFORMAT;
00399     if (length == -1)
00400     {
00401         DWORD cf;
00402         hr = IStream_Read(stream, &cf, sizeof(cf), 0);
00403         if (hr != S_OK || read != sizeof(cf))
00404             return DV_E_CLIPFORMAT;
00405         *clipformat = cf;
00406     }
00407     else
00408     {
00409         char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
00410         if (!format_name)
00411             return E_OUTOFMEMORY;
00412         hr = IStream_Read(stream, format_name, length, &read);
00413         if (hr != S_OK || read != length || format_name[length - 1] != '\0')
00414         {
00415             HeapFree(GetProcessHeap(), 0, format_name);
00416             return DV_E_CLIPFORMAT;
00417         }
00418         *clipformat = RegisterClipboardFormatA(format_name);
00419         HeapFree(GetProcessHeap(), 0, format_name);
00420     }
00421     return S_OK;
00422 }
00423 
00424 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat)
00425 {
00426     DWORD length;
00427     HRESULT hr;
00428 
00429     if (clipformat < 0xc000)
00430         length = -1;
00431     else
00432         length = GetClipboardFormatNameA(clipformat, NULL, 0);
00433     hr = IStream_Write(stream, &length, sizeof(length), NULL);
00434     if (FAILED(hr))
00435         return hr;
00436     if (clipformat < 0xc000)
00437     {
00438         DWORD cf = clipformat;
00439         hr = IStream_Write(stream, &cf, sizeof(cf), NULL);
00440     }
00441     else
00442     {
00443         char *format_name = HeapAlloc(GetProcessHeap(), 0, length);
00444         if (!format_name)
00445             return E_OUTOFMEMORY;
00446         GetClipboardFormatNameA(clipformat, format_name, length);
00447         hr = IStream_Write(stream, format_name, length, NULL);
00448         HeapFree(GetProcessHeap(), 0, format_name);
00449     }
00450     return hr;
00451 }
00452 
00453 /************************************************************************
00454  * DataCacheEntry_OpenPresStream
00455  *
00456  * This method will find the stream for the given presentation. It makes
00457  * no attempt at fallback.
00458  *
00459  * Param:
00460  *   this       - Pointer to the DataCache object
00461  *   drawAspect - The aspect of the object that we wish to draw.
00462  *   pStm       - A returned stream. It points to the beginning of the
00463  *              - presentation data, including the header.
00464  *
00465  * Errors:
00466  *   S_OK       The requested stream has been opened.
00467  *   OLE_E_BLANK    The requested stream could not be found.
00468  *   Quite a few others I'm too lazy to map correctly.
00469  *
00470  * Notes:
00471  *   Algorithm: Scan the elements of the presentation storage, looking
00472  *      for presentation streams. For each presentation stream,
00473  *      load the header and check to see if the aspect matches.
00474  *
00475  *   If a fallback is desired, just opening the first presentation stream
00476  *   is a possibility.
00477  */
00478 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm)
00479 {
00480     STATSTG elem;
00481     IEnumSTATSTG *pEnum;
00482     HRESULT hr;
00483 
00484     if (!ppStm) return E_POINTER;
00485 
00486     hr = IStorage_EnumElements(cache_entry->storage, 0, NULL, 0, &pEnum);
00487     if (FAILED(hr)) return hr;
00488 
00489     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
00490     {
00491     if (DataCache_IsPresentationStream(&elem))
00492     {
00493         IStream *pStm;
00494 
00495         hr = IStorage_OpenStream(cache_entry->storage, elem.pwcsName,
00496                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
00497                      &pStm);
00498         if (SUCCEEDED(hr))
00499         {
00500         PresentationDataHeader header;
00501         ULONG actual_read;
00502                 CLIPFORMAT clipformat;
00503 
00504                 hr = read_clipformat(pStm, &clipformat);
00505 
00506                 if (hr == S_OK)
00507                     hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
00508 
00509         /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
00510         if (hr == S_OK && actual_read == sizeof(header)
00511             && header.dvAspect == cache_entry->fmtetc.dwAspect)
00512         {
00513             /* Rewind the stream before returning it. */
00514             LARGE_INTEGER offset;
00515             offset.u.LowPart = 0;
00516             offset.u.HighPart = 0;
00517             IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
00518 
00519             *ppStm = pStm;
00520 
00521             CoTaskMemFree(elem.pwcsName);
00522             IEnumSTATSTG_Release(pEnum);
00523 
00524             return S_OK;
00525         }
00526 
00527         IStream_Release(pStm);
00528         }
00529     }
00530 
00531     CoTaskMemFree(elem.pwcsName);
00532     }
00533 
00534     IEnumSTATSTG_Release(pEnum);
00535 
00536     return (hr == S_FALSE ? OLE_E_BLANK : hr);
00537 }
00538 
00539 /************************************************************************
00540  * DataCacheEntry_LoadData
00541  *
00542  * This method will read information for the requested presentation
00543  * into the given structure.
00544  *
00545  * Param:
00546  *   This - The entry to load the data from.
00547  *
00548  * Returns:
00549  *   This method returns a metafile handle if it is successful.
00550  *   it will return 0 if not.
00551  */
00552 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry)
00553 {
00554   IStream*      presStream = NULL;
00555   HRESULT       hres;
00556   ULARGE_INTEGER current_pos;
00557   STATSTG       streamInfo;
00558   void*         metafileBits;
00559   METAFILEPICT *mfpict;
00560   HGLOBAL       hmfpict;
00561   PresentationDataHeader header;
00562   CLIPFORMAT    clipformat;
00563   static const LARGE_INTEGER offset_zero;
00564 
00565   /*
00566    * Open the presentation stream.
00567    */
00568   hres = DataCacheEntry_OpenPresStream(cache_entry, &presStream);
00569 
00570   if (FAILED(hres))
00571     return hres;
00572 
00573   /*
00574    * Get the size of the stream.
00575    */
00576   hres = IStream_Stat(presStream,
00577               &streamInfo,
00578               STATFLAG_NONAME);
00579 
00580   /*
00581    * Read the header.
00582    */
00583 
00584   hres = read_clipformat(presStream, &clipformat);
00585   if (FAILED(hres))
00586   {
00587       IStream_Release(presStream);
00588       return hres;
00589   }
00590 
00591   hres = IStream_Read(
00592                       presStream,
00593                       &header,
00594                       sizeof(PresentationDataHeader),
00595                       NULL);
00596   if (hres != S_OK)
00597   {
00598       IStream_Release(presStream);
00599       return E_FAIL;
00600   }
00601 
00602   hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, &current_pos);
00603 
00604   streamInfo.cbSize.QuadPart -= current_pos.QuadPart;
00605 
00606   hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
00607   if (!hmfpict)
00608   {
00609       IStream_Release(presStream);
00610       return E_OUTOFMEMORY;
00611   }
00612   mfpict = GlobalLock(hmfpict);
00613 
00614   /*
00615    * Allocate a buffer for the metafile bits.
00616    */
00617   metafileBits = HeapAlloc(GetProcessHeap(),
00618                0,
00619                streamInfo.cbSize.u.LowPart);
00620 
00621   /*
00622    * Read the metafile bits.
00623    */
00624   hres = IStream_Read(
00625        presStream,
00626        metafileBits,
00627        streamInfo.cbSize.u.LowPart,
00628        NULL);
00629 
00630   /*
00631    * Create a metafile with those bits.
00632    */
00633   if (SUCCEEDED(hres))
00634   {
00635     /* FIXME: get this from the stream */
00636     mfpict->mm = MM_ANISOTROPIC;
00637     mfpict->xExt = header.dwObjectExtentX;
00638     mfpict->yExt = header.dwObjectExtentY;
00639     mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
00640     if (!mfpict->hMF)
00641       hres = E_FAIL;
00642   }
00643 
00644   GlobalUnlock(hmfpict);
00645   if (SUCCEEDED(hres))
00646   {
00647     cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
00648     cache_entry->stgmedium.tymed = TYMED_MFPICT;
00649     cache_entry->stgmedium.u.hMetaFilePict = hmfpict;
00650   }
00651   else
00652     GlobalFree(hmfpict);
00653 
00654   /*
00655    * Cleanup.
00656    */
00657   HeapFree(GetProcessHeap(), 0, metafileBits);
00658   IStream_Release(presStream);
00659 
00660   return hres;
00661 }
00662 
00663 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry,
00664                                            IStorage *storage, IStream **stream)
00665 {
00666     WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
00667         '0' + (cache_entry->stream_number / 100) % 10,
00668         '0' + (cache_entry->stream_number / 10) % 10,
00669         '0' + cache_entry->stream_number % 10, 0};
00670 
00671     /* FIXME: cache the created stream in This? */
00672     return IStorage_CreateStream(storage, wszName,
00673                                  STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
00674                                  0, 0, stream);
00675 }
00676 
00677 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage,
00678                                    BOOL same_as_load)
00679 {
00680     PresentationDataHeader header;
00681     HRESULT hr;
00682     IStream *pres_stream;
00683     void *data = NULL;
00684 
00685     TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc));
00686 
00687     hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream);
00688     if (FAILED(hr))
00689         return hr;
00690 
00691     hr = write_clipformat(pres_stream, cache_entry->data_cf);
00692     if (FAILED(hr))
00693         return hr;
00694 
00695     if (cache_entry->fmtetc.ptd)
00696         FIXME("ptd not serialized\n");
00697     header.unknown3 = 4;
00698     header.dvAspect = cache_entry->fmtetc.dwAspect;
00699     header.lindex = cache_entry->fmtetc.lindex;
00700     header.tymed = cache_entry->stgmedium.tymed;
00701     header.unknown7 = 0;
00702     header.dwObjectExtentX = 0;
00703     header.dwObjectExtentY = 0;
00704     header.dwSize = 0;
00705 
00706     /* size the data */
00707     switch (cache_entry->data_cf)
00708     {
00709         case CF_METAFILEPICT:
00710         {
00711             if (cache_entry->stgmedium.tymed != TYMED_NULL)
00712             {
00713                 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
00714                 if (!mfpict)
00715                 {
00716                     IStream_Release(pres_stream);
00717                     return DV_E_STGMEDIUM;
00718                 }
00719                 header.dwObjectExtentX = mfpict->xExt;
00720                 header.dwObjectExtentY = mfpict->yExt;
00721                 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
00722                 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
00723             }
00724             break;
00725         }
00726         default:
00727             break;
00728     }
00729 
00730     /*
00731      * Write the header.
00732      */
00733     hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
00734                        NULL);
00735     if (FAILED(hr))
00736     {
00737         IStream_Release(pres_stream);
00738         return hr;
00739     }
00740 
00741     /* get the data */
00742     switch (cache_entry->data_cf)
00743     {
00744         case CF_METAFILEPICT:
00745         {
00746             if (cache_entry->stgmedium.tymed != TYMED_NULL)
00747             {
00748                 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict);
00749                 if (!mfpict)
00750                 {
00751                     IStream_Release(pres_stream);
00752                     return DV_E_STGMEDIUM;
00753                 }
00754                 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
00755                 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
00756                 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
00757             }
00758             break;
00759         }
00760         default:
00761             break;
00762     }
00763 
00764     if (data)
00765         hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
00766     HeapFree(GetProcessHeap(), 0, data);
00767 
00768     IStream_Release(pres_stream);
00769     return hr;
00770 }
00771 
00772 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
00773 * does no checking of whether src_stgm has a supported tymed, so this should be
00774 * done in the caller */
00775 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
00776                                const STGMEDIUM *src_stgm)
00777 {
00778     if (src_stgm->tymed == TYMED_MFPICT)
00779     {
00780         const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
00781         METAFILEPICT *dest_mfpict;
00782 
00783         if (!src_mfpict)
00784             return DV_E_STGMEDIUM;
00785         dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
00786         dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
00787         if (!dest_mfpict)
00788         {
00789             GlobalUnlock(src_stgm->u.hMetaFilePict);
00790             return E_OUTOFMEMORY;
00791         }
00792         *dest_mfpict = *src_mfpict;
00793         dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
00794         GlobalUnlock(src_stgm->u.hMetaFilePict);
00795         GlobalUnlock(dest_stgm->u.hMetaFilePict);
00796     }
00797     else if (src_stgm->tymed != TYMED_NULL)
00798     {
00799         dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
00800                                                 GMEM_MOVEABLE);
00801         if (!dest_stgm->u.hGlobal)
00802             return E_OUTOFMEMORY;
00803     }
00804     dest_stgm->tymed = src_stgm->tymed;
00805     dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
00806     if (dest_stgm->pUnkForRelease)
00807         IUnknown_AddRef(dest_stgm->pUnkForRelease);
00808     return S_OK;
00809 }
00810 
00811 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry,
00812                                       const FORMATETC *formatetc,
00813                                       const STGMEDIUM *stgmedium,
00814                                       BOOL fRelease)
00815 {
00816     if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) ||
00817         (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
00818         stgmedium->tymed == TYMED_NULL)
00819     {
00820         WARN("invalid formatetc\n");
00821         return DV_E_FORMATETC;
00822     }
00823 
00824     cache_entry->dirty = TRUE;
00825     ReleaseStgMedium(&cache_entry->stgmedium);
00826     cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat;
00827     if (fRelease)
00828     {
00829         cache_entry->stgmedium = *stgmedium;
00830         return S_OK;
00831     }
00832     else
00833         return copy_stg_medium(cache_entry->data_cf,
00834                                &cache_entry->stgmedium, stgmedium);
00835 }
00836 
00837 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium)
00838 {
00839     if (stgmedium->tymed == TYMED_NULL && cache_entry->storage)
00840     {
00841         HRESULT hr = DataCacheEntry_LoadData(cache_entry);
00842         if (FAILED(hr))
00843             return hr;
00844     }
00845     if (cache_entry->stgmedium.tymed == TYMED_NULL)
00846         return OLE_E_BLANK;
00847     return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium);
00848 }
00849 
00850 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry)
00851 {
00852     ReleaseStgMedium(&cache_entry->stgmedium);
00853     cache_entry->data_cf = cache_entry->fmtetc.cfFormat;
00854     return S_OK;
00855 }
00856 
00857 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry)
00858 {
00859     if (cache_entry->storage)
00860     {
00861         IStorage_Release(cache_entry->storage);
00862         cache_entry->storage = NULL;
00863     }
00864 }
00865 
00866 /*********************************************************
00867  * Method implementation for the  non delegating IUnknown
00868  * part of the DataCache class.
00869  */
00870 
00871 /************************************************************************
00872  * DataCache_NDIUnknown_QueryInterface (IUnknown)
00873  *
00874  * This version of QueryInterface will not delegate its implementation
00875  * to the outer unknown.
00876  */
00877 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
00878             IUnknown*      iface,
00879             REFIID         riid,
00880             void**         ppvObject)
00881 {
00882   DataCache *this = impl_from_IUnknown(iface);
00883 
00884   if ( ppvObject==0 )
00885     return E_INVALIDARG;
00886 
00887   *ppvObject = 0;
00888 
00889   if (IsEqualIID(&IID_IUnknown, riid))
00890   {
00891     *ppvObject = iface;
00892   }
00893   else if (IsEqualIID(&IID_IDataObject, riid))
00894   {
00895     *ppvObject = &this->IDataObject_iface;
00896   }
00897   else if ( IsEqualIID(&IID_IPersistStorage, riid)  ||
00898             IsEqualIID(&IID_IPersist, riid) )
00899   {
00900     *ppvObject = &this->IPersistStorage_iface;
00901   }
00902   else if ( IsEqualIID(&IID_IViewObject, riid) ||
00903             IsEqualIID(&IID_IViewObject2, riid) )
00904   {
00905     *ppvObject = &this->IViewObject2_iface;
00906   }
00907   else if ( IsEqualIID(&IID_IOleCache, riid) ||
00908             IsEqualIID(&IID_IOleCache2, riid) )
00909   {
00910     *ppvObject = &this->IOleCache2_iface;
00911   }
00912   else if ( IsEqualIID(&IID_IOleCacheControl, riid) )
00913   {
00914     *ppvObject = &this->IOleCacheControl_iface;
00915   }
00916 
00917   if ((*ppvObject)==0)
00918   {
00919     WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
00920     return E_NOINTERFACE;
00921   }
00922 
00923   IUnknown_AddRef((IUnknown*)*ppvObject);
00924 
00925   return S_OK;
00926 }
00927 
00928 /************************************************************************
00929  * DataCache_NDIUnknown_AddRef (IUnknown)
00930  *
00931  * This version of QueryInterface will not delegate its implementation
00932  * to the outer unknown.
00933  */
00934 static ULONG WINAPI DataCache_NDIUnknown_AddRef(
00935             IUnknown*      iface)
00936 {
00937   DataCache *this = impl_from_IUnknown(iface);
00938   return InterlockedIncrement(&this->ref);
00939 }
00940 
00941 /************************************************************************
00942  * DataCache_NDIUnknown_Release (IUnknown)
00943  *
00944  * This version of QueryInterface will not delegate its implementation
00945  * to the outer unknown.
00946  */
00947 static ULONG WINAPI DataCache_NDIUnknown_Release(
00948             IUnknown*      iface)
00949 {
00950   DataCache *this = impl_from_IUnknown(iface);
00951   ULONG ref;
00952 
00953   ref = InterlockedDecrement(&this->ref);
00954 
00955   if (ref == 0) DataCache_Destroy(this);
00956 
00957   return ref;
00958 }
00959 
00960 /*********************************************************
00961  * Method implementation for the IDataObject
00962  * part of the DataCache class.
00963  */
00964 
00965 /************************************************************************
00966  * DataCache_IDataObject_QueryInterface (IUnknown)
00967  */
00968 static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
00969             IDataObject*     iface,
00970             REFIID           riid,
00971             void**           ppvObject)
00972 {
00973   DataCache *this = impl_from_IDataObject(iface);
00974 
00975   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
00976 }
00977 
00978 /************************************************************************
00979  * DataCache_IDataObject_AddRef (IUnknown)
00980  */
00981 static ULONG WINAPI DataCache_IDataObject_AddRef(
00982             IDataObject*     iface)
00983 {
00984   DataCache *this = impl_from_IDataObject(iface);
00985 
00986   return IUnknown_AddRef(this->outerUnknown);
00987 }
00988 
00989 /************************************************************************
00990  * DataCache_IDataObject_Release (IUnknown)
00991  */
00992 static ULONG WINAPI DataCache_IDataObject_Release(
00993             IDataObject*     iface)
00994 {
00995   DataCache *this = impl_from_IDataObject(iface);
00996 
00997   return IUnknown_Release(this->outerUnknown);
00998 }
00999 
01000 /************************************************************************
01001  * DataCache_GetData
01002  *
01003  * Get Data from a source dataobject using format pformatetcIn->cfFormat
01004  */
01005 static HRESULT WINAPI DataCache_GetData(
01006         IDataObject*     iface,
01007         LPFORMATETC      pformatetcIn,
01008         STGMEDIUM*       pmedium)
01009 {
01010     DataCache *This = impl_from_IDataObject(iface);
01011     DataCacheEntry *cache_entry;
01012 
01013     memset(pmedium, 0, sizeof(*pmedium));
01014 
01015     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn);
01016     if (!cache_entry)
01017         return OLE_E_BLANK;
01018 
01019     return DataCacheEntry_GetData(cache_entry, pmedium);
01020 }
01021 
01022 static HRESULT WINAPI DataCache_GetDataHere(
01023         IDataObject*     iface,
01024         LPFORMATETC      pformatetc,
01025         STGMEDIUM*       pmedium)
01026 {
01027   FIXME("stub\n");
01028   return E_NOTIMPL;
01029 }
01030 
01031 static HRESULT WINAPI DataCache_QueryGetData(
01032         IDataObject*     iface,
01033         LPFORMATETC      pformatetc)
01034 {
01035   FIXME("stub\n");
01036   return E_NOTIMPL;
01037 }
01038 
01039 /************************************************************************
01040  * DataCache_EnumFormatEtc (IDataObject)
01041  *
01042  * The data cache doesn't implement this method.
01043  */
01044 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
01045         IDataObject*     iface,
01046         LPFORMATETC      pformatectIn,
01047         LPFORMATETC      pformatetcOut)
01048 {
01049   TRACE("()\n");
01050   return E_NOTIMPL;
01051 }
01052 
01053 /************************************************************************
01054  * DataCache_IDataObject_SetData (IDataObject)
01055  *
01056  * This method is delegated to the IOleCache2 implementation.
01057  */
01058 static HRESULT WINAPI DataCache_IDataObject_SetData(
01059         IDataObject*     iface,
01060         LPFORMATETC      pformatetc,
01061         STGMEDIUM*       pmedium,
01062         BOOL             fRelease)
01063 {
01064   IOleCache2* oleCache = NULL;
01065   HRESULT     hres;
01066 
01067   TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
01068 
01069   hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
01070 
01071   if (FAILED(hres))
01072     return E_UNEXPECTED;
01073 
01074   hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
01075 
01076   IOleCache2_Release(oleCache);
01077 
01078   return hres;
01079 }
01080 
01081 /************************************************************************
01082  * DataCache_EnumFormatEtc (IDataObject)
01083  *
01084  * The data cache doesn't implement this method.
01085  */
01086 static HRESULT WINAPI DataCache_EnumFormatEtc(
01087         IDataObject*     iface,
01088         DWORD            dwDirection,
01089         IEnumFORMATETC** ppenumFormatEtc)
01090 {
01091   TRACE("()\n");
01092   return E_NOTIMPL;
01093 }
01094 
01095 /************************************************************************
01096  * DataCache_DAdvise (IDataObject)
01097  *
01098  * The data cache doesn't support connections.
01099  */
01100 static HRESULT WINAPI DataCache_DAdvise(
01101         IDataObject*     iface,
01102         FORMATETC*       pformatetc,
01103         DWORD            advf,
01104         IAdviseSink*     pAdvSink,
01105         DWORD*           pdwConnection)
01106 {
01107   TRACE("()\n");
01108   return OLE_E_ADVISENOTSUPPORTED;
01109 }
01110 
01111 /************************************************************************
01112  * DataCache_DUnadvise (IDataObject)
01113  *
01114  * The data cache doesn't support connections.
01115  */
01116 static HRESULT WINAPI DataCache_DUnadvise(
01117         IDataObject*     iface,
01118         DWORD            dwConnection)
01119 {
01120   TRACE("()\n");
01121   return OLE_E_NOCONNECTION;
01122 }
01123 
01124 /************************************************************************
01125  * DataCache_EnumDAdvise (IDataObject)
01126  *
01127  * The data cache doesn't support connections.
01128  */
01129 static HRESULT WINAPI DataCache_EnumDAdvise(
01130         IDataObject*     iface,
01131         IEnumSTATDATA**  ppenumAdvise)
01132 {
01133   TRACE("()\n");
01134   return OLE_E_ADVISENOTSUPPORTED;
01135 }
01136 
01137 /*********************************************************
01138  * Method implementation for the IDataObject
01139  * part of the DataCache class.
01140  */
01141 
01142 /************************************************************************
01143  * DataCache_IPersistStorage_QueryInterface (IUnknown)
01144  */
01145 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
01146             IPersistStorage* iface,
01147             REFIID           riid,
01148             void**           ppvObject)
01149 {
01150   DataCache *this = impl_from_IPersistStorage(iface);
01151 
01152   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
01153 }
01154 
01155 /************************************************************************
01156  * DataCache_IPersistStorage_AddRef (IUnknown)
01157  */
01158 static ULONG WINAPI DataCache_IPersistStorage_AddRef(
01159             IPersistStorage* iface)
01160 {
01161   DataCache *this = impl_from_IPersistStorage(iface);
01162 
01163   return IUnknown_AddRef(this->outerUnknown);
01164 }
01165 
01166 /************************************************************************
01167  * DataCache_IPersistStorage_Release (IUnknown)
01168  */
01169 static ULONG WINAPI DataCache_IPersistStorage_Release(
01170             IPersistStorage* iface)
01171 {
01172   DataCache *this = impl_from_IPersistStorage(iface);
01173 
01174   return IUnknown_Release(this->outerUnknown);
01175 }
01176 
01177 /************************************************************************
01178  * DataCache_GetClassID (IPersistStorage)
01179  *
01180  * The data cache doesn't implement this method.
01181  */
01182 static HRESULT WINAPI DataCache_GetClassID(
01183             IPersistStorage* iface,
01184         CLSID*           pClassID)
01185 {
01186   DataCache *This = impl_from_IPersistStorage(iface);
01187   DataCacheEntry *cache_entry;
01188 
01189   TRACE("(%p, %p)\n", iface, pClassID);
01190 
01191   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01192   {
01193     if (cache_entry->storage != NULL)
01194     {
01195       STATSTG statstg;
01196       HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME);
01197       if (SUCCEEDED(hr))
01198       {
01199         *pClassID = statstg.clsid;
01200         return S_OK;
01201       }
01202     }
01203   }
01204 
01205   *pClassID = CLSID_NULL;
01206 
01207   return S_OK;
01208 }
01209 
01210 /************************************************************************
01211  * DataCache_IsDirty (IPersistStorage)
01212  */
01213 static HRESULT WINAPI DataCache_IsDirty(
01214             IPersistStorage* iface)
01215 {
01216     DataCache *This = impl_from_IPersistStorage(iface);
01217     DataCacheEntry *cache_entry;
01218 
01219     TRACE("(%p)\n", iface);
01220 
01221     if (This->dirty)
01222         return S_OK;
01223 
01224     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01225         if (cache_entry->dirty)
01226             return S_OK;
01227 
01228     return S_FALSE;
01229 }
01230 
01231 /************************************************************************
01232  * DataCache_InitNew (IPersistStorage)
01233  *
01234  * The data cache implementation of IPersistStorage_InitNew simply stores
01235  * the storage pointer.
01236  */
01237 static HRESULT WINAPI DataCache_InitNew(
01238             IPersistStorage* iface,
01239         IStorage*        pStg)
01240 {
01241     DataCache *This = impl_from_IPersistStorage(iface);
01242 
01243     TRACE("(%p, %p)\n", iface, pStg);
01244 
01245     if (This->presentationStorage != NULL)
01246         IStorage_Release(This->presentationStorage);
01247 
01248     This->presentationStorage = pStg;
01249 
01250     IStorage_AddRef(This->presentationStorage);
01251     This->dirty = TRUE;
01252 
01253     return S_OK;
01254 }
01255 
01256 /************************************************************************
01257  * DataCache_Load (IPersistStorage)
01258  *
01259  * The data cache implementation of IPersistStorage_Load doesn't
01260  * actually load anything. Instead, it holds on to the storage pointer
01261  * and it will load the presentation information when the
01262  * IDataObject_GetData or IViewObject2_Draw methods are called.
01263  */
01264 static HRESULT WINAPI DataCache_Load(
01265             IPersistStorage* iface,
01266         IStorage*        pStg)
01267 {
01268     DataCache *This = impl_from_IPersistStorage(iface);
01269     STATSTG elem;
01270     IEnumSTATSTG *pEnum;
01271     HRESULT hr;
01272 
01273     TRACE("(%p, %p)\n", iface, pStg);
01274 
01275     if (This->presentationStorage != NULL)
01276       IStorage_Release(This->presentationStorage);
01277 
01278     This->presentationStorage = pStg;
01279 
01280     hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum);
01281     if (FAILED(hr)) return hr;
01282 
01283     while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
01284     {
01285     if (DataCache_IsPresentationStream(&elem))
01286     {
01287         IStream *pStm;
01288 
01289         hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName,
01290                      NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
01291                      &pStm);
01292         if (SUCCEEDED(hr))
01293         {
01294                 PresentationDataHeader header;
01295                 ULONG actual_read;
01296                 CLIPFORMAT clipformat;
01297 
01298                 hr = read_clipformat(pStm, &clipformat);
01299 
01300                 if (hr == S_OK)
01301                     hr = IStream_Read(pStm, &header, sizeof(header),
01302                                       &actual_read);
01303 
01304         /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
01305         if (hr == S_OK && actual_read == sizeof(header))
01306         {
01307             DataCacheEntry *cache_entry;
01308             FORMATETC fmtetc;
01309 
01310             fmtetc.cfFormat = clipformat;
01311             fmtetc.ptd = NULL; /* FIXME */
01312             fmtetc.dwAspect = header.dvAspect;
01313             fmtetc.lindex = header.lindex;
01314             fmtetc.tymed = header.tymed;
01315 
01316                     TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc));
01317 
01318                     cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
01319                     if (!cache_entry)
01320                         hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
01321                     if (SUCCEEDED(hr))
01322                     {
01323                         DataCacheEntry_DiscardData(cache_entry);
01324                         if (cache_entry->storage) IStorage_Release(cache_entry->storage);
01325                         cache_entry->storage = pStg;
01326                         IStorage_AddRef(pStg);
01327                         cache_entry->dirty = FALSE;
01328                     }
01329         }
01330 
01331         IStream_Release(pStm);
01332         }
01333     }
01334 
01335     CoTaskMemFree(elem.pwcsName);
01336     }
01337 
01338     This->dirty = FALSE;
01339 
01340     IEnumSTATSTG_Release(pEnum);
01341 
01342     IStorage_AddRef(This->presentationStorage);
01343     return S_OK;
01344 }
01345 
01346 /************************************************************************
01347  * DataCache_Save (IPersistStorage)
01348  *
01349  * Until we actually connect to a running object and retrieve new
01350  * information to it, we never have to save anything. However, it is
01351  * our responsibility to copy the information when saving to a new
01352  * storage.
01353  */
01354 static HRESULT WINAPI DataCache_Save(
01355             IPersistStorage* iface,
01356         IStorage*        pStg,
01357         BOOL             fSameAsLoad)
01358 {
01359     DataCache *This = impl_from_IPersistStorage(iface);
01360     DataCacheEntry *cache_entry;
01361     BOOL dirty = FALSE;
01362     HRESULT hr = S_OK;
01363     unsigned short stream_number = 0;
01364 
01365     TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
01366 
01367     dirty = This->dirty;
01368     if (!dirty)
01369     {
01370         LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01371         {
01372             dirty = cache_entry->dirty;
01373             if (dirty)
01374                 break;
01375         }
01376     }
01377 
01378     /* this is a shortcut if nothing changed */
01379     if (!dirty && !fSameAsLoad && This->presentationStorage)
01380     {
01381         return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
01382     }
01383 
01384     /* assign stream numbers to the cache entries */
01385     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01386     {
01387         if (cache_entry->stream_number != stream_number)
01388         {
01389             cache_entry->dirty = TRUE; /* needs to be written out again */
01390             cache_entry->stream_number = stream_number;
01391         }
01392         stream_number++;
01393     }
01394 
01395     /* write out the cache entries */
01396     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01397     {
01398         if (!fSameAsLoad || cache_entry->dirty)
01399         {
01400             hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
01401             if (FAILED(hr))
01402                 break;
01403 
01404             cache_entry->dirty = FALSE;
01405         }
01406     }
01407 
01408     This->dirty = FALSE;
01409     return hr;
01410 }
01411 
01412 /************************************************************************
01413  * DataCache_SaveCompleted (IPersistStorage)
01414  *
01415  * This method is called to tell the cache to release the storage
01416  * pointer it's currently holding.
01417  */
01418 static HRESULT WINAPI DataCache_SaveCompleted(
01419             IPersistStorage* iface,
01420         IStorage*        pStgNew)
01421 {
01422   TRACE("(%p, %p)\n", iface, pStgNew);
01423 
01424   if (pStgNew)
01425   {
01426     IPersistStorage_HandsOffStorage(iface);
01427 
01428     DataCache_Load(iface, pStgNew);
01429   }
01430 
01431   return S_OK;
01432 }
01433 
01434 /************************************************************************
01435  * DataCache_HandsOffStorage (IPersistStorage)
01436  *
01437  * This method is called to tell the cache to release the storage
01438  * pointer it's currently holding.
01439  */
01440 static HRESULT WINAPI DataCache_HandsOffStorage(
01441             IPersistStorage* iface)
01442 {
01443   DataCache *this = impl_from_IPersistStorage(iface);
01444   DataCacheEntry *cache_entry;
01445 
01446   TRACE("(%p)\n", iface);
01447 
01448   if (this->presentationStorage != NULL)
01449   {
01450     IStorage_Release(this->presentationStorage);
01451     this->presentationStorage = NULL;
01452   }
01453 
01454   LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
01455     DataCacheEntry_HandsOffStorage(cache_entry);
01456 
01457   return S_OK;
01458 }
01459 
01460 /*********************************************************
01461  * Method implementation for the IViewObject2
01462  * part of the DataCache class.
01463  */
01464 
01465 /************************************************************************
01466  * DataCache_IViewObject2_QueryInterface (IUnknown)
01467  */
01468 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
01469             IViewObject2* iface,
01470             REFIID           riid,
01471             void**           ppvObject)
01472 {
01473   DataCache *this = impl_from_IViewObject2(iface);
01474 
01475   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
01476 }
01477 
01478 /************************************************************************
01479  * DataCache_IViewObject2_AddRef (IUnknown)
01480  */
01481 static ULONG WINAPI DataCache_IViewObject2_AddRef(
01482             IViewObject2* iface)
01483 {
01484   DataCache *this = impl_from_IViewObject2(iface);
01485 
01486   return IUnknown_AddRef(this->outerUnknown);
01487 }
01488 
01489 /************************************************************************
01490  * DataCache_IViewObject2_Release (IUnknown)
01491  */
01492 static ULONG WINAPI DataCache_IViewObject2_Release(
01493             IViewObject2* iface)
01494 {
01495   DataCache *this = impl_from_IViewObject2(iface);
01496 
01497   return IUnknown_Release(this->outerUnknown);
01498 }
01499 
01500 /************************************************************************
01501  * DataCache_Draw (IViewObject2)
01502  *
01503  * This method will draw the cached representation of the object
01504  * to the given device context.
01505  */
01506 static HRESULT WINAPI DataCache_Draw(
01507             IViewObject2*    iface,
01508         DWORD            dwDrawAspect,
01509         LONG             lindex,
01510         void*            pvAspect,
01511         DVTARGETDEVICE*  ptd,
01512         HDC              hdcTargetDev,
01513         HDC              hdcDraw,
01514         LPCRECTL         lprcBounds,
01515         LPCRECTL         lprcWBounds,
01516         BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
01517         ULONG_PTR        dwContinue)
01518 {
01519   DataCache *This = impl_from_IViewObject2(iface);
01520   HRESULT                hres;
01521   DataCacheEntry        *cache_entry;
01522 
01523   TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
01524     iface,
01525     dwDrawAspect,
01526     lindex,
01527     pvAspect,
01528     hdcTargetDev,
01529     hdcDraw,
01530     lprcBounds,
01531     lprcWBounds,
01532     pfnContinue,
01533     dwContinue);
01534 
01535   if (lprcBounds==NULL)
01536     return E_INVALIDARG;
01537 
01538   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01539   {
01540     /* FIXME: compare ptd too */
01541     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
01542         (cache_entry->fmtetc.lindex != lindex))
01543       continue;
01544 
01545     /* if the data hasn't been loaded yet, do it now */
01546     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
01547     {
01548       hres = DataCacheEntry_LoadData(cache_entry);
01549       if (FAILED(hres))
01550         continue;
01551     }
01552 
01553     /* no data */
01554     if (cache_entry->stgmedium.tymed == TYMED_NULL)
01555       continue;
01556 
01557     if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT;
01558 
01559     switch (cache_entry->data_cf)
01560     {
01561       case CF_METAFILEPICT:
01562       {
01563         /*
01564          * We have to be careful not to modify the state of the
01565          * DC.
01566          */
01567         INT   prevMapMode;
01568         SIZE  oldWindowExt;
01569         SIZE  oldViewportExt;
01570         POINT oldViewportOrg;
01571         METAFILEPICT *mfpict;
01572 
01573         if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
01574             !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
01575           continue;
01576 
01577         prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
01578 
01579         SetWindowExtEx(hdcDraw,
01580                mfpict->xExt,
01581                mfpict->yExt,
01582                &oldWindowExt);
01583 
01584         SetViewportExtEx(hdcDraw,
01585                  lprcBounds->right - lprcBounds->left,
01586                  lprcBounds->bottom - lprcBounds->top,
01587                  &oldViewportExt);
01588 
01589         SetViewportOrgEx(hdcDraw,
01590                  lprcBounds->left,
01591                  lprcBounds->top,
01592                  &oldViewportOrg);
01593 
01594         PlayMetaFile(hdcDraw, mfpict->hMF);
01595 
01596         SetWindowExtEx(hdcDraw,
01597                oldWindowExt.cx,
01598                oldWindowExt.cy,
01599                NULL);
01600 
01601         SetViewportExtEx(hdcDraw,
01602                  oldViewportExt.cx,
01603                  oldViewportExt.cy,
01604                  NULL);
01605 
01606         SetViewportOrgEx(hdcDraw,
01607                  oldViewportOrg.x,
01608                  oldViewportOrg.y,
01609                  NULL);
01610 
01611         SetMapMode(hdcDraw, prevMapMode);
01612 
01613         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
01614 
01615         return S_OK;
01616       }
01617     }
01618   }
01619 
01620   WARN("no data could be found to be drawn\n");
01621 
01622   return OLE_E_BLANK;
01623 }
01624 
01625 static HRESULT WINAPI DataCache_GetColorSet(
01626             IViewObject2*   iface,
01627         DWORD           dwDrawAspect,
01628         LONG            lindex,
01629         void*           pvAspect,
01630         DVTARGETDEVICE* ptd,
01631         HDC             hicTargetDevice,
01632         LOGPALETTE**    ppColorSet)
01633 {
01634   FIXME("stub\n");
01635   return E_NOTIMPL;
01636 }
01637 
01638 static HRESULT WINAPI DataCache_Freeze(
01639             IViewObject2*   iface,
01640         DWORD           dwDrawAspect,
01641         LONG            lindex,
01642         void*           pvAspect,
01643         DWORD*          pdwFreeze)
01644 {
01645   FIXME("stub\n");
01646   return E_NOTIMPL;
01647 }
01648 
01649 static HRESULT WINAPI DataCache_Unfreeze(
01650             IViewObject2*   iface,
01651         DWORD           dwFreeze)
01652 {
01653   FIXME("stub\n");
01654   return E_NOTIMPL;
01655 }
01656 
01657 /************************************************************************
01658  * DataCache_SetAdvise (IViewObject2)
01659  *
01660  * This sets-up an advisory sink with the data cache. When the object's
01661  * view changes, this sink is called.
01662  */
01663 static HRESULT WINAPI DataCache_SetAdvise(
01664             IViewObject2*   iface,
01665         DWORD           aspects,
01666         DWORD           advf,
01667         IAdviseSink*    pAdvSink)
01668 {
01669   DataCache *this = impl_from_IViewObject2(iface);
01670 
01671   TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
01672 
01673   /*
01674    * A call to this function removes the previous sink
01675    */
01676   if (this->sinkInterface != NULL)
01677   {
01678     IAdviseSink_Release(this->sinkInterface);
01679     this->sinkInterface  = NULL;
01680     this->sinkAspects    = 0;
01681     this->sinkAdviseFlag = 0;
01682   }
01683 
01684   /*
01685    * Now, setup the new one.
01686    */
01687   if (pAdvSink!=NULL)
01688   {
01689     this->sinkInterface  = pAdvSink;
01690     this->sinkAspects    = aspects;
01691     this->sinkAdviseFlag = advf;
01692 
01693     IAdviseSink_AddRef(this->sinkInterface);
01694   }
01695 
01696   /*
01697    * When the ADVF_PRIMEFIRST flag is set, we have to advise the
01698    * sink immediately.
01699    */
01700   if (advf & ADVF_PRIMEFIRST)
01701   {
01702     DataCache_FireOnViewChange(this, aspects, -1);
01703   }
01704 
01705   return S_OK;
01706 }
01707 
01708 /************************************************************************
01709  * DataCache_GetAdvise (IViewObject2)
01710  *
01711  * This method queries the current state of the advise sink
01712  * installed on the data cache.
01713  */
01714 static HRESULT WINAPI DataCache_GetAdvise(
01715             IViewObject2*   iface,
01716         DWORD*          pAspects,
01717         DWORD*          pAdvf,
01718         IAdviseSink**   ppAdvSink)
01719 {
01720   DataCache *this = impl_from_IViewObject2(iface);
01721 
01722   TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
01723 
01724   /*
01725    * Just copy all the requested values.
01726    */
01727   if (pAspects!=NULL)
01728     *pAspects = this->sinkAspects;
01729 
01730   if (pAdvf!=NULL)
01731     *pAdvf = this->sinkAdviseFlag;
01732 
01733   if (ppAdvSink!=NULL)
01734   {
01735     if (this->sinkInterface != NULL)
01736         IAdviseSink_QueryInterface(this->sinkInterface,
01737                    &IID_IAdviseSink,
01738                    (void**)ppAdvSink);
01739     else *ppAdvSink = NULL;
01740   }
01741 
01742   return S_OK;
01743 }
01744 
01745 /************************************************************************
01746  * DataCache_GetExtent (IViewObject2)
01747  *
01748  * This method retrieves the "natural" size of this cached object.
01749  */
01750 static HRESULT WINAPI DataCache_GetExtent(
01751             IViewObject2*   iface,
01752         DWORD           dwDrawAspect,
01753         LONG            lindex,
01754         DVTARGETDEVICE* ptd,
01755         LPSIZEL         lpsizel)
01756 {
01757   DataCache *This = impl_from_IViewObject2(iface);
01758   HRESULT                hres = E_FAIL;
01759   DataCacheEntry        *cache_entry;
01760 
01761   TRACE("(%p, %x, %d, %p, %p)\n",
01762     iface, dwDrawAspect, lindex, ptd, lpsizel);
01763 
01764   if (lpsizel==NULL)
01765     return E_POINTER;
01766 
01767   lpsizel->cx = 0;
01768   lpsizel->cy = 0;
01769 
01770   if (lindex!=-1)
01771     FIXME("Unimplemented flag lindex = %d\n", lindex);
01772 
01773   /*
01774    * Right now, we support only the callback from
01775    * the default handler.
01776    */
01777   if (ptd!=NULL)
01778     FIXME("Unimplemented ptd = %p\n", ptd);
01779 
01780   LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01781   {
01782     /* FIXME: compare ptd too */
01783     if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
01784         (cache_entry->fmtetc.lindex != lindex))
01785       continue;
01786 
01787     /* if the data hasn't been loaded yet, do it now */
01788     if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
01789     {
01790       hres = DataCacheEntry_LoadData(cache_entry);
01791       if (FAILED(hres))
01792         continue;
01793     }
01794 
01795     /* no data */
01796     if (cache_entry->stgmedium.tymed == TYMED_NULL)
01797       continue;
01798 
01799 
01800     switch (cache_entry->data_cf)
01801     {
01802       case CF_METAFILEPICT:
01803       {
01804           METAFILEPICT *mfpict;
01805 
01806           if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
01807               !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
01808             continue;
01809 
01810         lpsizel->cx = mfpict->xExt;
01811         lpsizel->cy = mfpict->yExt;
01812 
01813         GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
01814 
01815         return S_OK;
01816       }
01817     }
01818   }
01819 
01820   WARN("no data could be found to get the extents from\n");
01821 
01822   /*
01823    * This method returns OLE_E_BLANK when it fails.
01824    */
01825   return OLE_E_BLANK;
01826 }
01827 
01828 
01829 /*********************************************************
01830  * Method implementation for the IOleCache2
01831  * part of the DataCache class.
01832  */
01833 
01834 /************************************************************************
01835  * DataCache_IOleCache2_QueryInterface (IUnknown)
01836  */
01837 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
01838             IOleCache2*     iface,
01839             REFIID          riid,
01840             void**          ppvObject)
01841 {
01842   DataCache *this = impl_from_IOleCache2(iface);
01843 
01844   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
01845 }
01846 
01847 /************************************************************************
01848  * DataCache_IOleCache2_AddRef (IUnknown)
01849  */
01850 static ULONG WINAPI DataCache_IOleCache2_AddRef(
01851             IOleCache2*     iface)
01852 {
01853   DataCache *this = impl_from_IOleCache2(iface);
01854 
01855   return IUnknown_AddRef(this->outerUnknown);
01856 }
01857 
01858 /************************************************************************
01859  * DataCache_IOleCache2_Release (IUnknown)
01860  */
01861 static ULONG WINAPI DataCache_IOleCache2_Release(
01862             IOleCache2*     iface)
01863 {
01864   DataCache *this = impl_from_IOleCache2(iface);
01865 
01866   return IUnknown_Release(this->outerUnknown);
01867 }
01868 
01869 /*****************************************************************************
01870  * setup_sink
01871  *
01872  * Set up the sink connection to the running object.
01873  */
01874 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry)
01875 {
01876     HRESULT hr = S_FALSE;
01877     DWORD flags;
01878 
01879     /* Clear the ADVFCACHE_* bits.  Native also sets the two highest bits for some reason. */
01880     flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE);
01881 
01882     if(This->running_object)
01883         if(!(flags & ADVF_NODATA))
01884             hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags,
01885                                      &This->IAdviseSink_iface, &cache_entry->sink_id);
01886     return hr;
01887 }
01888 
01889 static HRESULT WINAPI DataCache_Cache(
01890             IOleCache2*     iface,
01891         FORMATETC*      pformatetc,
01892         DWORD           advf,
01893         DWORD*          pdwConnection)
01894 {
01895     DataCache *This = impl_from_IOleCache2(iface);
01896     DataCacheEntry *cache_entry;
01897     HRESULT hr;
01898 
01899     TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection);
01900 
01901     if (!pformatetc || !pdwConnection)
01902         return E_INVALIDARG;
01903 
01904     TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc));
01905 
01906     *pdwConnection = 0;
01907 
01908     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
01909     if (cache_entry)
01910     {
01911         TRACE("found an existing cache entry\n");
01912         *pdwConnection = cache_entry->id;
01913         return CACHE_S_SAMECACHE;
01914     }
01915 
01916     hr = DataCache_CreateEntry(This, pformatetc, &cache_entry);
01917 
01918     if (SUCCEEDED(hr))
01919     {
01920         *pdwConnection = cache_entry->id;
01921         cache_entry->advise_flags = advf;
01922         setup_sink(This, cache_entry);
01923     }
01924 
01925     return hr;
01926 }
01927 
01928 static HRESULT WINAPI DataCache_Uncache(
01929         IOleCache2*     iface,
01930         DWORD           dwConnection)
01931 {
01932     DataCache *This = impl_from_IOleCache2(iface);
01933     DataCacheEntry *cache_entry;
01934 
01935     TRACE("(%d)\n", dwConnection);
01936 
01937     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
01938         if (cache_entry->id == dwConnection)
01939         {
01940             DataCacheEntry_Destroy(This, cache_entry);
01941             return S_OK;
01942         }
01943 
01944     WARN("no connection found for %d\n", dwConnection);
01945 
01946     return OLE_E_NOCONNECTION;
01947 }
01948 
01949 static HRESULT WINAPI DataCache_EnumCache(
01950             IOleCache2*     iface,
01951         IEnumSTATDATA** ppenumSTATDATA)
01952 {
01953   FIXME("stub\n");
01954   return E_NOTIMPL;
01955 }
01956 
01957 static HRESULT WINAPI DataCache_InitCache(
01958         IOleCache2*     iface,
01959         IDataObject*    pDataObject)
01960 {
01961   FIXME("stub\n");
01962   return E_NOTIMPL;
01963 }
01964 
01965 static HRESULT WINAPI DataCache_IOleCache2_SetData(
01966             IOleCache2*     iface,
01967         FORMATETC*      pformatetc,
01968         STGMEDIUM*      pmedium,
01969         BOOL            fRelease)
01970 {
01971     DataCache *This = impl_from_IOleCache2(iface);
01972     DataCacheEntry *cache_entry;
01973     HRESULT hr;
01974 
01975     TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE");
01976     TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc));
01977 
01978     cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc);
01979     if (cache_entry)
01980     {
01981         hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease);
01982 
01983         if (SUCCEEDED(hr))
01984             DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect,
01985                                        cache_entry->fmtetc.lindex);
01986 
01987         return hr;
01988     }
01989     WARN("cache entry not found\n");
01990 
01991     return OLE_E_BLANK;
01992 }
01993 
01994 static HRESULT WINAPI DataCache_UpdateCache(
01995             IOleCache2*     iface,
01996         LPDATAOBJECT    pDataObject,
01997         DWORD           grfUpdf,
01998         LPVOID          pReserved)
01999 {
02000   FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved);
02001   return E_NOTIMPL;
02002 }
02003 
02004 static HRESULT WINAPI DataCache_DiscardCache(
02005             IOleCache2*     iface,
02006         DWORD           dwDiscardOptions)
02007 {
02008     DataCache *This = impl_from_IOleCache2(iface);
02009     DataCacheEntry *cache_entry;
02010     HRESULT hr = S_OK;
02011 
02012     TRACE("(%d)\n", dwDiscardOptions);
02013 
02014     if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY)
02015         hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE);
02016 
02017     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
02018     {
02019         hr = DataCacheEntry_DiscardData(cache_entry);
02020         if (FAILED(hr))
02021             break;
02022     }
02023 
02024     return hr;
02025 }
02026 
02027 
02028 /*********************************************************
02029  * Method implementation for the IOleCacheControl
02030  * part of the DataCache class.
02031  */
02032 
02033 /************************************************************************
02034  * DataCache_IOleCacheControl_QueryInterface (IUnknown)
02035  */
02036 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
02037             IOleCacheControl* iface,
02038             REFIID            riid,
02039             void**            ppvObject)
02040 {
02041   DataCache *this = impl_from_IOleCacheControl(iface);
02042 
02043   return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
02044 }
02045 
02046 /************************************************************************
02047  * DataCache_IOleCacheControl_AddRef (IUnknown)
02048  */
02049 static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
02050             IOleCacheControl* iface)
02051 {
02052   DataCache *this = impl_from_IOleCacheControl(iface);
02053 
02054   return IUnknown_AddRef(this->outerUnknown);
02055 }
02056 
02057 /************************************************************************
02058  * DataCache_IOleCacheControl_Release (IUnknown)
02059  */
02060 static ULONG WINAPI DataCache_IOleCacheControl_Release(
02061             IOleCacheControl* iface)
02062 {
02063   DataCache *this = impl_from_IOleCacheControl(iface);
02064 
02065   return IUnknown_Release(this->outerUnknown);
02066 }
02067 
02068 /************************************************************************
02069  * DataCache_OnRun (IOleCacheControl)
02070  */
02071 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj)
02072 {
02073     DataCache *This = impl_from_IOleCacheControl(iface);
02074     DataCacheEntry *cache_entry;
02075 
02076     TRACE("(%p)->(%p)\n", iface, data_obj);
02077 
02078     if(This->running_object) return S_OK;
02079 
02080     /* No reference is taken on the data object */
02081     This->running_object = data_obj;
02082 
02083     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
02084     {
02085         setup_sink(This, cache_entry);
02086     }
02087 
02088     return S_OK;
02089 }
02090 
02091 /************************************************************************
02092  * DataCache_OnStop (IOleCacheControl)
02093  */
02094 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface)
02095 {
02096     DataCache *This = impl_from_IOleCacheControl(iface);
02097     DataCacheEntry *cache_entry;
02098 
02099     TRACE("(%p)\n", iface);
02100 
02101     if(!This->running_object) return S_OK;
02102 
02103     LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
02104     {
02105         if(cache_entry->sink_id)
02106         {
02107             IDataObject_DUnadvise(This->running_object, cache_entry->sink_id);
02108             cache_entry->sink_id = 0;
02109         }
02110     }
02111 
02112     /* No ref taken in OnRun, so no Release call here */
02113     This->running_object = NULL;
02114     return S_OK;
02115 }
02116 
02117 /************************************************************************
02118  *              IAdviseSink methods.
02119  * This behaves as an internal object to the data cache.  QI'ing its ptr doesn't
02120  * give access to the cache's other interfaces.  We don't maintain a ref count,
02121  * the object exists as long as the cache is around.
02122  */
02123 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj)
02124 {
02125     *obj = NULL;
02126     if (IsEqualIID(&IID_IUnknown, iid) ||
02127         IsEqualIID(&IID_IAdviseSink, iid))
02128     {
02129         *obj = iface;
02130     }
02131 
02132     if(*obj)
02133     {
02134         IAdviseSink_AddRef(iface);
02135         return S_OK;
02136     }
02137     return E_NOINTERFACE;
02138 }
02139 
02140 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface)
02141 {
02142     return 2;
02143 }
02144 
02145 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface)
02146 {
02147     return 1;
02148 }
02149 
02150 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med)
02151 {
02152     DataCache *This = impl_from_IAdviseSink(iface);
02153     TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med);
02154     IOleCache_SetData(&This->IOleCache2_iface, fmt, med, FALSE);
02155 }
02156 
02157 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index)
02158 {
02159     FIXME("stub\n");
02160 }
02161 
02162 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk)
02163 {
02164     FIXME("stub\n");
02165 }
02166 
02167 static void WINAPI DataCache_OnSave(IAdviseSink *iface)
02168 {
02169     FIXME("stub\n");
02170 }
02171 
02172 static void WINAPI DataCache_OnClose(IAdviseSink *iface)
02173 {
02174     FIXME("stub\n");
02175 }
02176 
02177 /*
02178  * Virtual function tables for the DataCache class.
02179  */
02180 static const IUnknownVtbl DataCache_NDIUnknown_VTable =
02181 {
02182   DataCache_NDIUnknown_QueryInterface,
02183   DataCache_NDIUnknown_AddRef,
02184   DataCache_NDIUnknown_Release
02185 };
02186 
02187 static const IDataObjectVtbl DataCache_IDataObject_VTable =
02188 {
02189   DataCache_IDataObject_QueryInterface,
02190   DataCache_IDataObject_AddRef,
02191   DataCache_IDataObject_Release,
02192   DataCache_GetData,
02193   DataCache_GetDataHere,
02194   DataCache_QueryGetData,
02195   DataCache_GetCanonicalFormatEtc,
02196   DataCache_IDataObject_SetData,
02197   DataCache_EnumFormatEtc,
02198   DataCache_DAdvise,
02199   DataCache_DUnadvise,
02200   DataCache_EnumDAdvise
02201 };
02202 
02203 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable =
02204 {
02205   DataCache_IPersistStorage_QueryInterface,
02206   DataCache_IPersistStorage_AddRef,
02207   DataCache_IPersistStorage_Release,
02208   DataCache_GetClassID,
02209   DataCache_IsDirty,
02210   DataCache_InitNew,
02211   DataCache_Load,
02212   DataCache_Save,
02213   DataCache_SaveCompleted,
02214   DataCache_HandsOffStorage
02215 };
02216 
02217 static const IViewObject2Vtbl DataCache_IViewObject2_VTable =
02218 {
02219   DataCache_IViewObject2_QueryInterface,
02220   DataCache_IViewObject2_AddRef,
02221   DataCache_IViewObject2_Release,
02222   DataCache_Draw,
02223   DataCache_GetColorSet,
02224   DataCache_Freeze,
02225   DataCache_Unfreeze,
02226   DataCache_SetAdvise,
02227   DataCache_GetAdvise,
02228   DataCache_GetExtent
02229 };
02230 
02231 static const IOleCache2Vtbl DataCache_IOleCache2_VTable =
02232 {
02233   DataCache_IOleCache2_QueryInterface,
02234   DataCache_IOleCache2_AddRef,
02235   DataCache_IOleCache2_Release,
02236   DataCache_Cache,
02237   DataCache_Uncache,
02238   DataCache_EnumCache,
02239   DataCache_InitCache,
02240   DataCache_IOleCache2_SetData,
02241   DataCache_UpdateCache,
02242   DataCache_DiscardCache
02243 };
02244 
02245 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
02246 {
02247   DataCache_IOleCacheControl_QueryInterface,
02248   DataCache_IOleCacheControl_AddRef,
02249   DataCache_IOleCacheControl_Release,
02250   DataCache_OnRun,
02251   DataCache_OnStop
02252 };
02253 
02254 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable =
02255 {
02256     DataCache_IAdviseSink_QueryInterface,
02257     DataCache_IAdviseSink_AddRef,
02258     DataCache_IAdviseSink_Release,
02259     DataCache_OnDataChange,
02260     DataCache_OnViewChange,
02261     DataCache_OnRename,
02262     DataCache_OnSave,
02263     DataCache_OnClose
02264 };
02265 
02266 /*********************************************************
02267  * Method implementation for DataCache class.
02268  */
02269 static DataCache* DataCache_Construct(
02270   REFCLSID  clsid,
02271   LPUNKNOWN pUnkOuter)
02272 {
02273   DataCache* newObject = 0;
02274 
02275   /*
02276    * Allocate space for the object.
02277    */
02278   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
02279 
02280   if (newObject==0)
02281     return newObject;
02282 
02283   /*
02284    * Initialize the virtual function table.
02285    */
02286   newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable;
02287   newObject->IUnknown_iface.lpVtbl = &DataCache_NDIUnknown_VTable;
02288   newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable;
02289   newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable;
02290   newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable;
02291   newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable;
02292   newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable;
02293 
02294   /*
02295    * Start with one reference count. The caller of this function
02296    * must release the interface pointer when it is done.
02297    */
02298   newObject->ref = 1;
02299 
02300   /*
02301    * Initialize the outer unknown
02302    * We don't keep a reference on the outer unknown since, the way
02303    * aggregation works, our lifetime is at least as large as its
02304    * lifetime.
02305    */
02306   if (pUnkOuter==NULL)
02307     pUnkOuter = &newObject->IUnknown_iface;
02308 
02309   newObject->outerUnknown = pUnkOuter;
02310 
02311   /*
02312    * Initialize the other members of the structure.
02313    */
02314   newObject->sinkAspects = 0;
02315   newObject->sinkAdviseFlag = 0;
02316   newObject->sinkInterface = 0;
02317   newObject->presentationStorage = NULL;
02318   list_init(&newObject->cache_list);
02319   newObject->last_cache_id = 1;
02320   newObject->dirty = FALSE;
02321   newObject->running_object = NULL;
02322 
02323   return newObject;
02324 }
02325 
02326 /******************************************************************************
02327  *              CreateDataCache        [OLE32.@]
02328  *
02329  * Creates a data cache to allow an object to render one or more of its views,
02330  * whether running or not.
02331  *
02332  * PARAMS
02333  *  pUnkOuter [I] Outer unknown for the object.
02334  *  rclsid    [I]
02335  *  riid      [I] IID of interface to return.
02336  *  ppvObj    [O] Address where the data cache object will be stored on return.
02337  *
02338  * RETURNS
02339  *  Success: S_OK.
02340  *  Failure: HRESULT code.
02341  *
02342  * NOTES
02343  *  The following interfaces are supported by the returned data cache object:
02344  *  IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
02345  *  IViewObject and IViewObject2.
02346  */
02347 HRESULT WINAPI CreateDataCache(
02348   LPUNKNOWN pUnkOuter,
02349   REFCLSID  rclsid,
02350   REFIID    riid,
02351   LPVOID*   ppvObj)
02352 {
02353   DataCache* newCache = NULL;
02354   HRESULT    hr       = S_OK;
02355 
02356   TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);
02357 
02358   /*
02359    * Sanity check
02360    */
02361   if (ppvObj==0)
02362     return E_POINTER;
02363 
02364   *ppvObj = 0;
02365 
02366   /*
02367    * If this cache is constructed for aggregation, make sure
02368    * the caller is requesting the IUnknown interface.
02369    * This is necessary because it's the only time the non-delegating
02370    * IUnknown pointer can be returned to the outside.
02371    */
02372   if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) )
02373     return CLASS_E_NOAGGREGATION;
02374 
02375   /*
02376    * Try to construct a new instance of the class.
02377    */
02378   newCache = DataCache_Construct(rclsid,
02379                  pUnkOuter);
02380 
02381   if (newCache == 0)
02382     return E_OUTOFMEMORY;
02383 
02384   /*
02385    * Make sure it supports the interface required by the caller.
02386    */
02387   hr = IUnknown_QueryInterface(&newCache->IUnknown_iface, riid, ppvObj);
02388 
02389   /*
02390    * Release the reference obtained in the constructor. If
02391    * the QueryInterface was unsuccessful, it will free the class.
02392    */
02393   IUnknown_Release(&newCache->IUnknown_iface);
02394 
02395   return hr;
02396 }

Generated on Fri May 25 2012 04:23:44 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.