Logo Search packages:      
Sourcecode: wine version File versions

datacache.c

/*
 *    OLE 2 Data cache
 *
 *      Copyright 1999  Francis Beaudet
 *      Copyright 2000  Abey George
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * NOTES:
 *    The OLE2 data cache supports a whole whack of
 *    interfaces including:
 *       IDataObject, IPersistStorage, IViewObject2,
 *       IOleCache2 and IOleCacheControl.
 *
 *    Most of the implementation details are taken from: Inside OLE
 *    second edition by Kraig Brockschmidt,
 *
 * NOTES
 *  -  This implementation of the datacache will let your application
 *     load documents that have embedded OLE objects in them and it will
 *     also retrieve the metafile representation of those objects.
 *  -  This implementation of the datacache will also allow your
 *     application to save new documents with OLE objects in them.
 *  -  The main thing that it doesn't do is allow you to activate
 *     or modify the OLE objects in any way.
 *  -  I haven't found any good documentation on the real usage of
 *     the streams created by the data cache. In particular, How to
 *     determine what the XXX stands for in the stream name
 *     "\002OlePresXXX". It appears to just be a counter.
 *  -  Also, I don't know the real content of the presentation stream
 *     header. I was able to figure-out where the extent of the object
 *     was stored and the aspect, but that's about it.
 */
#include <assert.h>
#include <stdarg.h>
#include <string.h>

#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/unicode.h"
#include "ole2.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

/****************************************************************************
 * PresentationDataHeader
 *
 * This structure represents the header of the \002OlePresXXX stream in
 * the OLE object strorage.
 *
 * Most fields are still unknown.
 */
typedef struct PresentationDataHeader
{
  DWORD unknown1; /* -1 */
  DWORD unknown2; /* 3, possibly CF_METAFILEPICT */
  DWORD unknown3; /* 4, possibly TYMED_ISTREAM */
  DVASPECT dvAspect;
  DWORD unknown5; /* -1 */

  DWORD unknown6;
  DWORD unknown7; /* 0 */
  DWORD dwObjectExtentX;
  DWORD dwObjectExtentY;
  DWORD dwSize;
} PresentationDataHeader;

/****************************************************************************
 * DataCache
 */
struct DataCache
{
  /*
   * List all interface VTables here
   */
  IDataObjectVtbl*      lpvtbl1;
  IUnknownVtbl*         lpvtbl2;
  IPersistStorageVtbl*  lpvtbl3;
  IViewObject2Vtbl*     lpvtbl4;
  IOleCache2Vtbl*       lpvtbl5;
  IOleCacheControlVtbl* lpvtbl6;

  /*
   * Reference count of this object
   */
  ULONG ref;

  /*
   * IUnknown implementation of the outer object.
   */
  IUnknown* outerUnknown;

  /*
   * This storage pointer is set through a call to
   * IPersistStorage_Load. This is where the visual
   * representation of the object is stored.
   */
  IStorage* presentationStorage;

  /*
   * The user of this object can setup ONE advise sink
   * connection with the object. These parameters describe
   * that connection.
   */
  DWORD        sinkAspects;
  DWORD        sinkAdviseFlag;
  IAdviseSink* sinkInterface;

};

typedef struct DataCache DataCache;

/*
 * Here, I define utility macros to help with the casting of the
 * "this" parameter.
 * There is a version to accommodate all of the VTables implemented
 * by this object.
 */
#define _ICOM_THIS_From_IDataObject(class,name)       class* this = (class*)name
#define _ICOM_THIS_From_NDIUnknown(class, name)       class* this = (class*)(((char*)name)-sizeof(void*))
#define _ICOM_THIS_From_IPersistStorage(class, name)  class* this = (class*)(((char*)name)-2*sizeof(void*))
#define _ICOM_THIS_From_IViewObject2(class, name)     class* this = (class*)(((char*)name)-3*sizeof(void*))
#define _ICOM_THIS_From_IOleCache2(class, name)       class* this = (class*)(((char*)name)-4*sizeof(void*))
#define _ICOM_THIS_From_IOleCacheControl(class, name) class* this = (class*)(((char*)name)-5*sizeof(void*))

/*
 * Prototypes for the methods of the DataCache class.
 */
static DataCache* DataCache_Construct(REFCLSID  clsid,
                              LPUNKNOWN pUnkOuter);
static void       DataCache_Destroy(DataCache* ptrToDestroy);
static HRESULT    DataCache_ReadPresentationData(DataCache*              this,
                                     DWORD                   drawAspect,
                                     PresentationDataHeader* header);
static HRESULT    DataCache_OpenPresStream(DataCache *this,
                                 DWORD      drawAspect,
                                 IStream  **pStm);
static HMETAFILE  DataCache_ReadPresMetafile(DataCache* this,
                                   DWORD      drawAspect);
static void       DataCache_FireOnViewChange(DataCache* this,
                                   DWORD      aspect,
                                   LONG       lindex);

/*
 * Prototypes for the methods of the DataCache class
 * that implement non delegating IUnknown methods.
 */
static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
            IUnknown*      iface,
            REFIID         riid,
            void**         ppvObject);
static ULONG WINAPI DataCache_NDIUnknown_AddRef(
            IUnknown*      iface);
static ULONG WINAPI DataCache_NDIUnknown_Release(
            IUnknown*      iface);

/*
 * Prototypes for the methods of the DataCache class
 * that implement IDataObject methods.
 */
static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
            IDataObject*     iface,
            REFIID           riid,
            void**           ppvObject);
static ULONG WINAPI DataCache_IDataObject_AddRef(
            IDataObject*     iface);
static ULONG WINAPI DataCache_IDataObject_Release(
            IDataObject*     iface);
static HRESULT WINAPI DataCache_GetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetcIn,
          STGMEDIUM*       pmedium);
static HRESULT WINAPI DataCache_GetDataHere(
          IDataObject*     iface,
          LPFORMATETC      pformatetc,
          STGMEDIUM*       pmedium);
static HRESULT WINAPI DataCache_QueryGetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetc);
static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
          IDataObject*     iface,
          LPFORMATETC      pformatectIn,
          LPFORMATETC      pformatetcOut);
static HRESULT WINAPI DataCache_IDataObject_SetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetc,
          STGMEDIUM*       pmedium,
          BOOL             fRelease);
static HRESULT WINAPI DataCache_EnumFormatEtc(
          IDataObject*     iface,
          DWORD            dwDirection,
          IEnumFORMATETC** ppenumFormatEtc);
static HRESULT WINAPI DataCache_DAdvise(
          IDataObject*     iface,
          FORMATETC*       pformatetc,
          DWORD            advf,
          IAdviseSink*     pAdvSink,
          DWORD*           pdwConnection);
static HRESULT WINAPI DataCache_DUnadvise(
          IDataObject*     iface,
          DWORD            dwConnection);
static HRESULT WINAPI DataCache_EnumDAdvise(
          IDataObject*     iface,
          IEnumSTATDATA**  ppenumAdvise);

/*
 * Prototypes for the methods of the DataCache class
 * that implement IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
            IPersistStorage* iface,
            REFIID           riid,
            void**           ppvObject);
static ULONG WINAPI DataCache_IPersistStorage_AddRef(
            IPersistStorage* iface);
static ULONG WINAPI DataCache_IPersistStorage_Release(
            IPersistStorage* iface);
static HRESULT WINAPI DataCache_GetClassID(
            IPersistStorage* iface,
          CLSID*           pClassID);
static HRESULT WINAPI DataCache_IsDirty(
            IPersistStorage* iface);
static HRESULT WINAPI DataCache_InitNew(
            IPersistStorage* iface,
          IStorage*        pStg);
static HRESULT WINAPI DataCache_Load(
            IPersistStorage* iface,
          IStorage*        pStg);
static HRESULT WINAPI DataCache_Save(
            IPersistStorage* iface,
          IStorage*        pStg,
          BOOL             fSameAsLoad);
static HRESULT WINAPI DataCache_SaveCompleted(
            IPersistStorage* iface,
          IStorage*        pStgNew);
static HRESULT WINAPI DataCache_HandsOffStorage(
            IPersistStorage* iface);

/*
 * Prototypes for the methods of the DataCache class
 * that implement IViewObject2 methods.
 */
static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
            IViewObject2* iface,
            REFIID           riid,
            void**           ppvObject);
static ULONG WINAPI DataCache_IViewObject2_AddRef(
            IViewObject2* iface);
static ULONG WINAPI DataCache_IViewObject2_Release(
            IViewObject2* iface);
static HRESULT WINAPI DataCache_Draw(
            IViewObject2*    iface,
          DWORD            dwDrawAspect,
          LONG             lindex,
          void*            pvAspect,
          DVTARGETDEVICE*  ptd,
          HDC              hdcTargetDev,
          HDC              hdcDraw,
          LPCRECTL         lprcBounds,
          LPCRECTL         lprcWBounds,
          BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
          ULONG_PTR        dwContinue);
static HRESULT WINAPI DataCache_GetColorSet(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          void*           pvAspect,
          DVTARGETDEVICE* ptd,
          HDC             hicTargetDevice,
          LOGPALETTE**    ppColorSet);
static HRESULT WINAPI DataCache_Freeze(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          void*           pvAspect,
          DWORD*          pdwFreeze);
static HRESULT WINAPI DataCache_Unfreeze(
            IViewObject2*   iface,
          DWORD           dwFreeze);
static HRESULT WINAPI DataCache_SetAdvise(
            IViewObject2*   iface,
          DWORD           aspects,
          DWORD           advf,
          IAdviseSink*    pAdvSink);
static HRESULT WINAPI DataCache_GetAdvise(
            IViewObject2*   iface,
          DWORD*          pAspects,
          DWORD*          pAdvf,
          IAdviseSink**   ppAdvSink);
static HRESULT WINAPI DataCache_GetExtent(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          DVTARGETDEVICE* ptd,
          LPSIZEL         lpsizel);

/*
 * Prototypes for the methods of the DataCache class
 * that implement IOleCache2 methods.
 */
static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
            IOleCache2*     iface,
            REFIID          riid,
            void**          ppvObject);
static ULONG WINAPI DataCache_IOleCache2_AddRef(
            IOleCache2*     iface);
static ULONG WINAPI DataCache_IOleCache2_Release(
            IOleCache2*     iface);
static HRESULT WINAPI DataCache_Cache(
            IOleCache2*     iface,
          FORMATETC*      pformatetc,
          DWORD           advf,
          DWORD*          pdwConnection);
static HRESULT WINAPI DataCache_Uncache(
          IOleCache2*     iface,
          DWORD           dwConnection);
static HRESULT WINAPI DataCache_EnumCache(
            IOleCache2*     iface,
          IEnumSTATDATA** ppenumSTATDATA);
static HRESULT WINAPI DataCache_InitCache(
          IOleCache2*     iface,
          IDataObject*    pDataObject);
static HRESULT WINAPI DataCache_IOleCache2_SetData(
            IOleCache2*     iface,
          FORMATETC*      pformatetc,
          STGMEDIUM*      pmedium,
          BOOL            fRelease);
static HRESULT WINAPI DataCache_UpdateCache(
            IOleCache2*     iface,
          LPDATAOBJECT    pDataObject,
          DWORD           grfUpdf,
          LPVOID          pReserved);
static HRESULT WINAPI DataCache_DiscardCache(
            IOleCache2*     iface,
          DWORD           dwDiscardOptions);

/*
 * Prototypes for the methods of the DataCache class
 * that implement IOleCacheControl methods.
 */
static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
            IOleCacheControl* iface,
            REFIID            riid,
            void**            ppvObject);
static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
            IOleCacheControl* iface);
static ULONG WINAPI DataCache_IOleCacheControl_Release(
            IOleCacheControl* iface);
static HRESULT WINAPI DataCache_OnRun(
          IOleCacheControl* iface,
          LPDATAOBJECT      pDataObject);
static HRESULT WINAPI DataCache_OnStop(
          IOleCacheControl* iface);

/*
 * Virtual function tables for the DataCache class.
 */
static IUnknownVtbl DataCache_NDIUnknown_VTable =
{
  DataCache_NDIUnknown_QueryInterface,
  DataCache_NDIUnknown_AddRef,
  DataCache_NDIUnknown_Release
};

static IDataObjectVtbl DataCache_IDataObject_VTable =
{
  DataCache_IDataObject_QueryInterface,
  DataCache_IDataObject_AddRef,
  DataCache_IDataObject_Release,
  DataCache_GetData,
  DataCache_GetDataHere,
  DataCache_QueryGetData,
  DataCache_GetCanonicalFormatEtc,
  DataCache_IDataObject_SetData,
  DataCache_EnumFormatEtc,
  DataCache_DAdvise,
  DataCache_DUnadvise,
  DataCache_EnumDAdvise
};

static IPersistStorageVtbl DataCache_IPersistStorage_VTable =
{
  DataCache_IPersistStorage_QueryInterface,
  DataCache_IPersistStorage_AddRef,
  DataCache_IPersistStorage_Release,
  DataCache_GetClassID,
  DataCache_IsDirty,
  DataCache_InitNew,
  DataCache_Load,
  DataCache_Save,
  DataCache_SaveCompleted,
  DataCache_HandsOffStorage
};

static IViewObject2Vtbl DataCache_IViewObject2_VTable =
{
  DataCache_IViewObject2_QueryInterface,
  DataCache_IViewObject2_AddRef,
  DataCache_IViewObject2_Release,
  DataCache_Draw,
  DataCache_GetColorSet,
  DataCache_Freeze,
  DataCache_Unfreeze,
  DataCache_SetAdvise,
  DataCache_GetAdvise,
  DataCache_GetExtent
};

static IOleCache2Vtbl DataCache_IOleCache2_VTable =
{
  DataCache_IOleCache2_QueryInterface,
  DataCache_IOleCache2_AddRef,
  DataCache_IOleCache2_Release,
  DataCache_Cache,
  DataCache_Uncache,
  DataCache_EnumCache,
  DataCache_InitCache,
  DataCache_IOleCache2_SetData,
  DataCache_UpdateCache,
  DataCache_DiscardCache
};

static IOleCacheControlVtbl DataCache_IOleCacheControl_VTable =
{
  DataCache_IOleCacheControl_QueryInterface,
  DataCache_IOleCacheControl_AddRef,
  DataCache_IOleCacheControl_Release,
  DataCache_OnRun,
  DataCache_OnStop
};

/******************************************************************************
 *              CreateDataCache        [OLE32.@]
 */
HRESULT WINAPI CreateDataCache(
  LPUNKNOWN pUnkOuter,
  REFCLSID  rclsid,
  REFIID    riid,
  LPVOID*   ppvObj)
{
  DataCache* newCache = NULL;
  HRESULT    hr       = S_OK;

  TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj);

  /*
   * Sanity check
   */
  if (ppvObj==0)
    return E_POINTER;

  *ppvObj = 0;

  /*
   * If this cache is constructed for aggregation, make sure
   * the caller is requesting the IUnknown interface.
   * This is necessary because it's the only time the non-delegating
   * IUnknown pointer can be returned to the outside.
   */
  if ( (pUnkOuter!=NULL) &&
       (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
    return CLASS_E_NOAGGREGATION;

  /*
   * Try to construct a new instance of the class.
   */
  newCache = DataCache_Construct(rclsid,
                         pUnkOuter);

  if (newCache == 0)
    return E_OUTOFMEMORY;

  /*
   * Make sure it supports the interface required by the caller.
   */
  hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtbl2), riid, ppvObj);

  /*
   * Release the reference obtained in the constructor. If
   * the QueryInterface was unsuccessful, it will free the class.
   */
  IUnknown_Release((IUnknown*)&(newCache->lpvtbl2));

  return hr;
}

/*********************************************************
 * Method implementation for DataCache class.
 */
static DataCache* DataCache_Construct(
  REFCLSID  clsid,
  LPUNKNOWN pUnkOuter)
{
  DataCache* newObject = 0;

  /*
   * Allocate space for the object.
   */
  newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));

  if (newObject==0)
    return newObject;

  /*
   * Initialize the virtual function table.
   */
  newObject->lpvtbl1 = &DataCache_IDataObject_VTable;
  newObject->lpvtbl2 = &DataCache_NDIUnknown_VTable;
  newObject->lpvtbl3 = &DataCache_IPersistStorage_VTable;
  newObject->lpvtbl4 = &DataCache_IViewObject2_VTable;
  newObject->lpvtbl5 = &DataCache_IOleCache2_VTable;
  newObject->lpvtbl6 = &DataCache_IOleCacheControl_VTable;

  /*
   * Start with one reference count. The caller of this function
   * must release the interface pointer when it is done.
   */
  newObject->ref = 1;

  /*
   * Initialize the outer unknown
   * We don't keep a reference on the outer unknown since, the way
   * aggregation works, our lifetime is at least as large as it's
   * lifetime.
   */
  if (pUnkOuter==NULL)
    pUnkOuter = (IUnknown*)&(newObject->lpvtbl2);

  newObject->outerUnknown = pUnkOuter;

  /*
   * Initialize the other members of the structure.
   */
  newObject->presentationStorage = NULL;
  newObject->sinkAspects = 0;
  newObject->sinkAdviseFlag = 0;
  newObject->sinkInterface = 0;

  return newObject;
}

static void DataCache_Destroy(
  DataCache* ptrToDestroy)
{
  TRACE("()\n");

  if (ptrToDestroy->sinkInterface != NULL)
  {
    IAdviseSink_Release(ptrToDestroy->sinkInterface);
    ptrToDestroy->sinkInterface = NULL;
  }

  if (ptrToDestroy->presentationStorage != NULL)
  {
    IStorage_Release(ptrToDestroy->presentationStorage);
    ptrToDestroy->presentationStorage = NULL;
  }

  /*
   * Free the datacache pointer.
   */
  HeapFree(GetProcessHeap(), 0, ptrToDestroy);
}

/************************************************************************
 * DataCache_ReadPresentationData
 *
 * This method will read information for the requested presentation
 * into the given structure.
 *
 * Param:
 *   this       - Pointer to the DataCache object
 *   drawAspect - The aspect of the object that we wish to draw.
 *   header     - The structure containing information about this
 *                aspect of the object.
 */
static HRESULT DataCache_ReadPresentationData(
  DataCache*              this,
  DWORD                   drawAspect,
  PresentationDataHeader* header)
{
  IStream* presStream = NULL;
  HRESULT  hres;

  /*
   * Open the presentation stream.
   */
  hres = DataCache_OpenPresStream(
           this,
         drawAspect,
         &presStream);

  if (FAILED(hres))
    return hres;

  /*
   * Read the header.
   */

  hres = IStream_Read(
           presStream,
         header,
         sizeof(PresentationDataHeader),
         NULL);

  /*
   * Cleanup.
   */
  IStream_Release(presStream);

  /*
   * We don't want to propagate any other error
   * code than a failure.
   */
  if (hres!=S_OK)
    hres = E_FAIL;

  return hres;
}

/************************************************************************
 * DataCache_FireOnViewChange
 *
 * This method will fire an OnViewChange notification to the advise
 * sink registered with the datacache.
 *
 * See IAdviseSink::OnViewChange for more details.
 */
static void DataCache_FireOnViewChange(
  DataCache* this,
  DWORD      aspect,
  LONG       lindex)
{
  TRACE("(%p, %lx, %ld)\n", this, aspect, lindex);

  /*
   * The sink supplies a filter when it registers
   * we make sure we only send the notifications when that
   * filter matches.
   */
  if ((this->sinkAspects & aspect) != 0)
  {
    if (this->sinkInterface != NULL)
    {
      IAdviseSink_OnViewChange(this->sinkInterface,
                         aspect,
                         lindex);

      /*
       * Some sinks want to be unregistered automatically when
       * the first notification goes out.
       */
      if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
      {
      IAdviseSink_Release(this->sinkInterface);

      this->sinkInterface  = NULL;
      this->sinkAspects    = 0;
      this->sinkAdviseFlag = 0;
      }
    }
  }
}

/* Helper for DataCache_OpenPresStream */
static BOOL DataCache_IsPresentationStream(const STATSTG *elem)
{
    /* The presentation streams have names of the form "\002OlePresXXX",
     * where XXX goes from 000 to 999. */
    static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' };

    LPCWSTR name = elem->pwcsName;

    return (elem->type == STGTY_STREAM)
      && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader))
      && (strlenW(name) == 11)
      && (strncmpW(name, OlePres, 8) == 0)
      && (name[8] >= '0') && (name[8] <= '9')
      && (name[9] >= '0') && (name[9] <= '9')
      && (name[10] >= '0') && (name[10] <= '9');
}

/************************************************************************
 * DataCache_OpenPresStream
 *
 * This method will find the stream for the given presentation. It makes
 * no attempt at fallback.
 *
 * Param:
 *   this       - Pointer to the DataCache object
 *   drawAspect - The aspect of the object that we wish to draw.
 *   pStm       - A returned stream. It points to the beginning of the
 *              - presentation data, including the header.
 *
 * Errors:
 *   S_OK         The requested stream has been opened.
 *   OLE_E_BLANK  The requested stream could not be found.
 *   Quite a few others I'm too lazy to map correctly.
 *
 * Notes:
 *   Algorithm:   Scan the elements of the presentation storage, looking
 *          for presentation streams. For each presentation stream,
 *          load the header and check to see if the aspect maches.
 *
 *   If a fallback is desired, just opening the first presentation stream
 *   is a possibility.
 */
static HRESULT DataCache_OpenPresStream(
  DataCache *this,
  DWORD      drawAspect,
  IStream  **ppStm)
{
    STATSTG elem;
    IEnumSTATSTG *pEnum;
    HRESULT hr;

    if (!ppStm) return E_POINTER;

    hr = IStorage_EnumElements(this->presentationStorage, 0, NULL, 0, &pEnum);
    if (FAILED(hr)) return hr;

    while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
    {
      if (DataCache_IsPresentationStream(&elem))
      {
          IStream *pStm;

          hr = IStorage_OpenStream(this->presentationStorage, elem.pwcsName,
                             NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
                             &pStm);
          if (SUCCEEDED(hr))
          {
            PresentationDataHeader header;
            ULONG actual_read;

            hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);

            /* can't use SUCCEEDED(hr): S_FALSE counts as an error */
            if (hr == S_OK && actual_read == sizeof(header)
                && header.dvAspect == drawAspect)
            {
                /* Rewind the stream before returning it. */
                LARGE_INTEGER offset;
                offset.u.LowPart = 0;
                offset.u.HighPart = 0;
                IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);

                *ppStm = pStm;

                CoTaskMemFree(elem.pwcsName);
                IEnumSTATSTG_Release(pEnum);

                return S_OK;
            }

            IStream_Release(pStm);
          }
      }

      CoTaskMemFree(elem.pwcsName);
    }

    IEnumSTATSTG_Release(pEnum);

    return (hr == S_FALSE ? OLE_E_BLANK : hr);
}

/************************************************************************
 * DataCache_ReadPresentationData
 *
 * This method will read information for the requested presentation
 * into the given structure.
 *
 * Param:
 *   this       - Pointer to the DataCache object
 *   drawAspect - The aspect of the object that we wish to draw.
 *
 * Returns:
 *   This method returns a metafile handle if it is successful.
 *   it will return 0 if not.
 */
static HMETAFILE DataCache_ReadPresMetafile(
  DataCache* this,
  DWORD      drawAspect)
{
  LARGE_INTEGER offset;
  IStream*      presStream = NULL;
  HRESULT       hres;
  void*         metafileBits;
  STATSTG       streamInfo;
  HMETAFILE     newMetafile = 0;

  /*
   * Open the presentation stream.
   */
  hres = DataCache_OpenPresStream(
           this,
         drawAspect,
         &presStream);

  if (FAILED(hres))
    return (HMETAFILE)hres;

  /*
   * Get the size of the stream.
   */
  hres = IStream_Stat(presStream,
                  &streamInfo,
                  STATFLAG_NONAME);

  /*
   * Skip the header
   */
  offset.u.HighPart = 0;
  offset.u.LowPart  = sizeof(PresentationDataHeader);

  hres = IStream_Seek(
           presStream,
         offset,
         STREAM_SEEK_SET,
         NULL);

  streamInfo.cbSize.u.LowPart -= offset.u.LowPart;

  /*
   * Allocate a buffer for the metafile bits.
   */
  metafileBits = HeapAlloc(GetProcessHeap(),
                     0,
                     streamInfo.cbSize.u.LowPart);

  /*
   * Read the metafile bits.
   */
  hres = IStream_Read(
         presStream,
         metafileBits,
         streamInfo.cbSize.u.LowPart,
         NULL);

  /*
   * Create a metafile with those bits.
   */
  if (SUCCEEDED(hres))
  {
    newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
  }

  /*
   * Cleanup.
   */
  HeapFree(GetProcessHeap(), 0, metafileBits);
  IStream_Release(presStream);

  if (newMetafile==0)
    hres = E_FAIL;

  return newMetafile;
}

/*********************************************************
 * Method implementation for the  non delegating IUnknown
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_NDIUnknown_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 *
 * This version of QueryInterface will not delegate it's implementation
 * to the outer unknown.
 */
static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
            IUnknown*      iface,
            REFIID         riid,
            void**         ppvObject)
{
  _ICOM_THIS_From_NDIUnknown(DataCache, iface);

  /*
   * Perform a sanity check on the parameters.
   */
  if ( (this==0) || (ppvObject==0) )
    return E_INVALIDARG;

  /*
   * Initialize the return parameter.
   */
  *ppvObject = 0;

  /*
   * Compare the riid with the interface IDs implemented by this object.
   */
  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
  {
    *ppvObject = iface;
  }
  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
  {
    *ppvObject = (IDataObject*)&(this->lpvtbl1);
  }
  else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0)  ||
          (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
  {
    *ppvObject = (IPersistStorage*)&(this->lpvtbl3);
  }
  else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
          (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
  {
    *ppvObject = (IViewObject2*)&(this->lpvtbl4);
  }
  else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
          (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
  {
    *ppvObject = (IOleCache2*)&(this->lpvtbl5);
  }
  else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
  {
    *ppvObject = (IOleCacheControl*)&(this->lpvtbl6);
  }

  /*
   * Check that we obtained an interface.
   */
  if ((*ppvObject)==0)
  {
    WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid));
    return E_NOINTERFACE;
  }

  /*
   * Query Interface always increases the reference count by one when it is
   * successful.
   */
  IUnknown_AddRef((IUnknown*)*ppvObject);

  return S_OK;
}

/************************************************************************
 * DataCache_NDIUnknown_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 *
 * This version of QueryInterface will not delegate it's implementation
 * to the outer unknown.
 */
static ULONG WINAPI DataCache_NDIUnknown_AddRef(
            IUnknown*      iface)
{
  _ICOM_THIS_From_NDIUnknown(DataCache, iface);
  return InterlockedIncrement(&this->ref);
}

/************************************************************************
 * DataCache_NDIUnknown_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 *
 * This version of QueryInterface will not delegate it's implementation
 * to the outer unknown.
 */
static ULONG WINAPI DataCache_NDIUnknown_Release(
            IUnknown*      iface)
{
  _ICOM_THIS_From_NDIUnknown(DataCache, iface);
  ULONG ref;

  /*
   * Decrease the reference count on this object.
   */
  ref = InterlockedDecrement(&this->ref);

  /*
   * If the reference count goes down to 0, perform suicide.
   */
  if (ref == 0) DataCache_Destroy(this);

  return ref;
}

/*********************************************************
 * Method implementation for the IDataObject
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_IDataObject_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
            IDataObject*     iface,
            REFIID           riid,
            void**           ppvObject)
{
  _ICOM_THIS_From_IDataObject(DataCache, iface);

  return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}

/************************************************************************
 * DataCache_IDataObject_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IDataObject_AddRef(
            IDataObject*     iface)
{
  _ICOM_THIS_From_IDataObject(DataCache, iface);

  return IUnknown_AddRef(this->outerUnknown);
}

/************************************************************************
 * DataCache_IDataObject_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IDataObject_Release(
            IDataObject*     iface)
{
  _ICOM_THIS_From_IDataObject(DataCache, iface);

  return IUnknown_Release(this->outerUnknown);
}

/************************************************************************
 * DataCache_GetData
 *
 * Get Data from a source dataobject using format pformatetcIn->cfFormat
 * See Windows documentation for more details on GetData.
 * TODO: Currently only CF_METAFILEPICT is implemented
 */
static HRESULT WINAPI DataCache_GetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetcIn,
          STGMEDIUM*       pmedium)
{
  HRESULT hr = 0;
  HRESULT hrRet = E_UNEXPECTED;
  IPersistStorage *pPersistStorage = 0;
  IStorage *pStorage = 0;
  IStream *pStream = 0;
  OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
  HGLOBAL hGlobalMF = 0;
  void *mfBits = 0;
  PresentationDataHeader pdh;
  METAFILEPICT *mfPict;
  HMETAFILE hMetaFile = 0;

  if (pformatetcIn->cfFormat == CF_METAFILEPICT)
  {
    /* Get the Persist Storage */

    hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage);

    if (hr != S_OK)
      goto cleanup;

    /* Create a doc file to copy the doc to a storage */

    hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage);

    if (hr != S_OK)
      goto cleanup;

    /* Save it to storage */

    hr = OleSave(pPersistStorage, pStorage, FALSE);

    if (hr != S_OK)
      goto cleanup;

    /* Open the Presentation data srteam */

    hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream);

    if (hr != S_OK)
      goto cleanup;

    /* Read the presentation header */

    hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL);

    if (hr != S_OK)
      goto cleanup;

    mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize);

    /* Read the Metafile bits */

    hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL);

    if (hr != S_OK)
      goto cleanup;

    /* Create the metafile and place it in the STGMEDIUM structure */

    hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits);

    hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT));
    mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF);
    mfPict->hMF = hMetaFile;

    GlobalUnlock(hGlobalMF);

    pmedium->u.hGlobal = hGlobalMF;
    pmedium->tymed = TYMED_MFPICT;
    hrRet = S_OK;

cleanup:

    HeapFree(GetProcessHeap(), 0, mfBits);

    if (pStream)
      IStream_Release(pStream);

    if (pStorage)
      IStorage_Release(pStorage);

    if (pPersistStorage)
      IPersistStorage_Release(pPersistStorage);

    return hrRet;
  }

  /* TODO: Other formats are not implemented */

  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_GetDataHere(
          IDataObject*     iface,
          LPFORMATETC      pformatetc,
          STGMEDIUM*       pmedium)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_QueryGetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetc)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

/************************************************************************
 * DataCache_EnumFormatEtc (IDataObject)
 *
 * The data cache doesn't implement this method.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
          IDataObject*     iface,
          LPFORMATETC      pformatectIn,
          LPFORMATETC      pformatetcOut)
{
  TRACE("()\n");
  return E_NOTIMPL;
}

/************************************************************************
 * DataCache_IDataObject_SetData (IDataObject)
 *
 * This method is delegated to the IOleCache2 implementation.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_IDataObject_SetData(
          IDataObject*     iface,
          LPFORMATETC      pformatetc,
          STGMEDIUM*       pmedium,
          BOOL             fRelease)
{
  IOleCache2* oleCache = NULL;
  HRESULT     hres;

  TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);

  hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);

  if (FAILED(hres))
    return E_UNEXPECTED;

  hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);

  IOleCache2_Release(oleCache);

  return hres;
}

/************************************************************************
 * DataCache_EnumFormatEtc (IDataObject)
 *
 * The data cache doesn't implement this method.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_EnumFormatEtc(
          IDataObject*     iface,
          DWORD            dwDirection,
          IEnumFORMATETC** ppenumFormatEtc)
{
  TRACE("()\n");
  return E_NOTIMPL;
}

/************************************************************************
 * DataCache_DAdvise (IDataObject)
 *
 * The data cache doesn't support connections.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_DAdvise(
          IDataObject*     iface,
          FORMATETC*       pformatetc,
          DWORD            advf,
          IAdviseSink*     pAdvSink,
          DWORD*           pdwConnection)
{
  TRACE("()\n");
  return OLE_E_ADVISENOTSUPPORTED;
}

/************************************************************************
 * DataCache_DUnadvise (IDataObject)
 *
 * The data cache doesn't support connections.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_DUnadvise(
          IDataObject*     iface,
          DWORD            dwConnection)
{
  TRACE("()\n");
  return OLE_E_NOCONNECTION;
}

/************************************************************************
 * DataCache_EnumDAdvise (IDataObject)
 *
 * The data cache doesn't support connections.
 *
 * See Windows documentation for more details on IDataObject methods.
 */
static HRESULT WINAPI DataCache_EnumDAdvise(
          IDataObject*     iface,
          IEnumSTATDATA**  ppenumAdvise)
{
  TRACE("()\n");
  return OLE_E_ADVISENOTSUPPORTED;
}

/*********************************************************
 * Method implementation for the IDataObject
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_IPersistStorage_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
            IPersistStorage* iface,
            REFIID           riid,
            void**           ppvObject)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}

/************************************************************************
 * DataCache_IPersistStorage_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IPersistStorage_AddRef(
            IPersistStorage* iface)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  return IUnknown_AddRef(this->outerUnknown);
}

/************************************************************************
 * DataCache_IPersistStorage_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IPersistStorage_Release(
            IPersistStorage* iface)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  return IUnknown_Release(this->outerUnknown);
}

/************************************************************************
 * DataCache_GetClassID (IPersistStorage)
 *
 * The data cache doesn't implement this method.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_GetClassID(
            IPersistStorage* iface,
          CLSID*           pClassID)
{
  TRACE("(%p, %p)\n", iface, pClassID);
  return E_NOTIMPL;
}

/************************************************************************
 * DataCache_IsDirty (IPersistStorage)
 *
 * Until we actully connect to a running object and retrieve new
 * information to it, we never get dirty.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_IsDirty(
            IPersistStorage* iface)
{
  TRACE("(%p)\n", iface);

  return S_FALSE;
}

/************************************************************************
 * DataCache_InitNew (IPersistStorage)
 *
 * The data cache implementation of IPersistStorage_InitNew simply stores
 * the storage pointer.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_InitNew(
            IPersistStorage* iface,
          IStorage*        pStg)
{
  TRACE("(%p, %p)\n", iface, pStg);

  return DataCache_Load(iface, pStg);
}

/************************************************************************
 * DataCache_Load (IPersistStorage)
 *
 * The data cache implementation of IPersistStorage_Load doesn't
 * actually load anything. Instead, it holds on to the storage pointer
 * and it will load the presentation information when the
 * IDataObject_GetData or IViewObject2_Draw methods are called.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_Load(
            IPersistStorage* iface,
          IStorage*        pStg)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  TRACE("(%p, %p)\n", iface, pStg);

  if (this->presentationStorage != NULL)
  {
    IStorage_Release(this->presentationStorage);
  }

  this->presentationStorage = pStg;

  if (this->presentationStorage != NULL)
  {
    IStorage_AddRef(this->presentationStorage);
  }
  return S_OK;
}

/************************************************************************
 * DataCache_Save (IPersistStorage)
 *
 * Until we actully connect to a running object and retrieve new
 * information to it, we never have to save anything. However, it is
 * our responsability to copy the information when saving to a new
 * storage.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_Save(
            IPersistStorage* iface,
          IStorage*        pStg,
          BOOL             fSameAsLoad)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);

  if ( (!fSameAsLoad) &&
       (this->presentationStorage!=NULL) )
  {
    return IStorage_CopyTo(this->presentationStorage,
                     0,
                     NULL,
                     NULL,
                     pStg);
  }

  return S_OK;
}

/************************************************************************
 * DataCache_SaveCompleted (IPersistStorage)
 *
 * This method is called to tell the cache to release the storage
 * pointer it's currentlu holding.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_SaveCompleted(
            IPersistStorage* iface,
          IStorage*        pStgNew)
{
  TRACE("(%p, %p)\n", iface, pStgNew);

  if (pStgNew)
  {
  /*
   * First, make sure we get our hands off any storage we have.
   */

  DataCache_HandsOffStorage(iface);

  /*
   * Then, attach to the new storage.
   */

  DataCache_Load(iface, pStgNew);
  }

  return S_OK;
}

/************************************************************************
 * DataCache_HandsOffStorage (IPersistStorage)
 *
 * This method is called to tell the cache to release the storage
 * pointer it's currentlu holding.
 *
 * See Windows documentation for more details on IPersistStorage methods.
 */
static HRESULT WINAPI DataCache_HandsOffStorage(
            IPersistStorage* iface)
{
  _ICOM_THIS_From_IPersistStorage(DataCache, iface);

  TRACE("(%p)\n", iface);

  if (this->presentationStorage != NULL)
  {
    IStorage_Release(this->presentationStorage);
    this->presentationStorage = NULL;
  }

  return S_OK;
}

/*********************************************************
 * Method implementation for the IViewObject2
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_IViewObject2_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
            IViewObject2* iface,
            REFIID           riid,
            void**           ppvObject)
{
  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}

/************************************************************************
 * DataCache_IViewObject2_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IViewObject2_AddRef(
            IViewObject2* iface)
{
  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  return IUnknown_AddRef(this->outerUnknown);
}

/************************************************************************
 * DataCache_IViewObject2_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IViewObject2_Release(
            IViewObject2* iface)
{
  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  return IUnknown_Release(this->outerUnknown);
}

/************************************************************************
 * DataCache_Draw (IViewObject2)
 *
 * This method will draw the cached representation of the object
 * to the given device context.
 *
 * See Windows documentation for more details on IViewObject2 methods.
 */
static HRESULT WINAPI DataCache_Draw(
            IViewObject2*    iface,
          DWORD            dwDrawAspect,
          LONG             lindex,
          void*            pvAspect,
          DVTARGETDEVICE*  ptd,
          HDC              hdcTargetDev,
          HDC              hdcDraw,
          LPCRECTL         lprcBounds,
          LPCRECTL         lprcWBounds,
          BOOL  (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
          ULONG_PTR        dwContinue)
{
  PresentationDataHeader presData;
  HMETAFILE              presMetafile = 0;
  HRESULT                hres;

  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  TRACE("(%p, %lx, %ld, %p, %p, %p, %p, %p, %p, %lx)\n",
      iface,
      dwDrawAspect,
      lindex,
      pvAspect,
      hdcTargetDev,
      hdcDraw,
      lprcBounds,
      lprcWBounds,
      pfnContinue,
      dwContinue);

  /*
   * Sanity check
   */
  if (lprcBounds==NULL)
    return E_INVALIDARG;

  /*
   * First, we need to retrieve the dimensions of the
   * image in the metafile.
   */
  hres = DataCache_ReadPresentationData(this,
                              dwDrawAspect,
                              &presData);

  if (FAILED(hres))
    return hres;

  /*
   * Then, we can extract the metafile itself from the cached
   * data.
   *
   * FIXME Unless it isn't a metafile. I think it could be any CF_XXX type,
   * particularly CF_DIB.
   */
  presMetafile = DataCache_ReadPresMetafile(this,
                                  dwDrawAspect);

  /*
   * If we have a metafile, just draw baby...
   * We have to be careful not to modify the state of the
   * DC.
   */
  if (presMetafile!=0)
  {
    INT   prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC);
    SIZE  oldWindowExt;
    SIZE  oldViewportExt;
    POINT oldViewportOrg;

    SetWindowExtEx(hdcDraw,
               presData.dwObjectExtentX,
               presData.dwObjectExtentY,
               &oldWindowExt);

    SetViewportExtEx(hdcDraw,
                 lprcBounds->right - lprcBounds->left,
                 lprcBounds->bottom - lprcBounds->top,
                 &oldViewportExt);

    SetViewportOrgEx(hdcDraw,
                 lprcBounds->left,
                 lprcBounds->top,
                 &oldViewportOrg);

    PlayMetaFile(hdcDraw, presMetafile);

    SetWindowExtEx(hdcDraw,
               oldWindowExt.cx,
               oldWindowExt.cy,
               NULL);

    SetViewportExtEx(hdcDraw,
                 oldViewportExt.cx,
                 oldViewportExt.cy,
                 NULL);

    SetViewportOrgEx(hdcDraw,
                 oldViewportOrg.x,
                 oldViewportOrg.y,
                 NULL);

    SetMapMode(hdcDraw, prevMapMode);

    DeleteMetaFile(presMetafile);
  }

  return S_OK;
}

static HRESULT WINAPI DataCache_GetColorSet(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          void*           pvAspect,
          DVTARGETDEVICE* ptd,
          HDC             hicTargetDevice,
          LOGPALETTE**    ppColorSet)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_Freeze(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          void*           pvAspect,
          DWORD*          pdwFreeze)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_Unfreeze(
            IViewObject2*   iface,
          DWORD           dwFreeze)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

/************************************************************************
 * DataCache_SetAdvise (IViewObject2)
 *
 * This sets-up an advisory sink with the data cache. When the object's
 * view changes, this sink is called.
 *
 * See Windows documentation for more details on IViewObject2 methods.
 */
static HRESULT WINAPI DataCache_SetAdvise(
            IViewObject2*   iface,
          DWORD           aspects,
          DWORD           advf,
          IAdviseSink*    pAdvSink)
{
  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink);

  /*
   * A call to this function removes the previous sink
   */
  if (this->sinkInterface != NULL)
  {
    IAdviseSink_Release(this->sinkInterface);
    this->sinkInterface  = NULL;
    this->sinkAspects    = 0;
    this->sinkAdviseFlag = 0;
  }

  /*
   * Now, setup the new one.
   */
  if (pAdvSink!=NULL)
  {
    this->sinkInterface  = pAdvSink;
    this->sinkAspects    = aspects;
    this->sinkAdviseFlag = advf;

    IAdviseSink_AddRef(this->sinkInterface);
  }

  /*
   * When the ADVF_PRIMEFIRST flag is set, we have to advise the
   * sink immediately.
   */
  if (advf & ADVF_PRIMEFIRST)
  {
    DataCache_FireOnViewChange(this,
                         DVASPECT_CONTENT,
                         -1);
  }

  return S_OK;
}

/************************************************************************
 * DataCache_GetAdvise (IViewObject2)
 *
 * This method queries the current state of the advise sink
 * installed on the data cache.
 *
 * See Windows documentation for more details on IViewObject2 methods.
 */
static HRESULT WINAPI DataCache_GetAdvise(
            IViewObject2*   iface,
          DWORD*          pAspects,
          DWORD*          pAdvf,
          IAdviseSink**   ppAdvSink)
{
  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);

  /*
   * Just copy all the requested values.
   */
  if (pAspects!=NULL)
    *pAspects = this->sinkAspects;

  if (pAdvf!=NULL)
    *pAdvf = this->sinkAdviseFlag;

  if (ppAdvSink!=NULL)
  {
    IAdviseSink_QueryInterface(this->sinkInterface,
                         &IID_IAdviseSink,
                         (void**)ppAdvSink);
  }

  return S_OK;
}

/************************************************************************
 * DataCache_GetExtent (IViewObject2)
 *
 * This method retrieves the "natural" size of this cached object.
 *
 * See Windows documentation for more details on IViewObject2 methods.
 */
static HRESULT WINAPI DataCache_GetExtent(
            IViewObject2*   iface,
          DWORD           dwDrawAspect,
          LONG            lindex,
          DVTARGETDEVICE* ptd,
          LPSIZEL         lpsizel)
{
  PresentationDataHeader presData;
  HRESULT                hres = E_FAIL;

  _ICOM_THIS_From_IViewObject2(DataCache, iface);

  TRACE("(%p, %lx, %ld, %p, %p)\n",
      iface, dwDrawAspect, lindex, ptd, lpsizel);

  /*
   * Sanity check
   */
  if (lpsizel==NULL)
    return E_POINTER;

  /*
   * Initialize the out parameter.
   */
  lpsizel->cx = 0;
  lpsizel->cy = 0;

  /*
   * This flag should be set to -1.
   */
  if (lindex!=-1)
    FIXME("Unimplemented flag lindex = %ld\n", lindex);

  /*
   * Right now, we support only the callback from
   * the default handler.
   */
  if (ptd!=NULL)
    FIXME("Unimplemented ptd = %p\n", ptd);

  /*
   * Get the presentation information from the
   * cache.
   */
  hres = DataCache_ReadPresentationData(this,
                              dwDrawAspect,
                              &presData);

  if (SUCCEEDED(hres))
  {
    lpsizel->cx = presData.dwObjectExtentX;
    lpsizel->cy = presData.dwObjectExtentY;
  }

  /*
   * This method returns OLE_E_BLANK when it fails.
   */
  if (FAILED(hres))
    hres = OLE_E_BLANK;

  return hres;
}


/*********************************************************
 * Method implementation for the IOleCache2
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_IOleCache2_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
            IOleCache2*     iface,
            REFIID          riid,
            void**          ppvObject)
{
  _ICOM_THIS_From_IOleCache2(DataCache, iface);

  return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}

/************************************************************************
 * DataCache_IOleCache2_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IOleCache2_AddRef(
            IOleCache2*     iface)
{
  _ICOM_THIS_From_IOleCache2(DataCache, iface);

  return IUnknown_AddRef(this->outerUnknown);
}

/************************************************************************
 * DataCache_IOleCache2_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IOleCache2_Release(
            IOleCache2*     iface)
{
  _ICOM_THIS_From_IOleCache2(DataCache, iface);

  return IUnknown_Release(this->outerUnknown);
}

static HRESULT WINAPI DataCache_Cache(
            IOleCache2*     iface,
          FORMATETC*      pformatetc,
          DWORD           advf,
          DWORD*          pdwConnection)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_Uncache(
          IOleCache2*     iface,
          DWORD           dwConnection)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_EnumCache(
            IOleCache2*     iface,
          IEnumSTATDATA** ppenumSTATDATA)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_InitCache(
          IOleCache2*     iface,
          IDataObject*    pDataObject)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_IOleCache2_SetData(
            IOleCache2*     iface,
          FORMATETC*      pformatetc,
          STGMEDIUM*      pmedium,
          BOOL            fRelease)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_UpdateCache(
            IOleCache2*     iface,
          LPDATAOBJECT    pDataObject,
          DWORD           grfUpdf,
          LPVOID          pReserved)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_DiscardCache(
            IOleCache2*     iface,
          DWORD           dwDiscardOptions)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}


/*********************************************************
 * Method implementation for the IOleCacheControl
 * part of the DataCache class.
 */

/************************************************************************
 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
            IOleCacheControl* iface,
            REFIID            riid,
            void**            ppvObject)
{
  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);

  return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}

/************************************************************************
 * DataCache_IOleCacheControl_AddRef (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IOleCacheControl_AddRef(
            IOleCacheControl* iface)
{
  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);

  return IUnknown_AddRef(this->outerUnknown);
}

/************************************************************************
 * DataCache_IOleCacheControl_Release (IUnknown)
 *
 * See Windows documentation for more details on IUnknown methods.
 */
static ULONG WINAPI DataCache_IOleCacheControl_Release(
            IOleCacheControl* iface)
{
  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);

  return IUnknown_Release(this->outerUnknown);
}

static HRESULT WINAPI DataCache_OnRun(
          IOleCacheControl* iface,
          LPDATAOBJECT      pDataObject)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

static HRESULT WINAPI DataCache_OnStop(
          IOleCacheControl* iface)
{
  FIXME("stub\n");
  return E_NOTIMPL;
}

Generated by  Doxygen 1.6.0   Back to index