6340 lines
180 KiB
C++
6340 lines
180 KiB
C++
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// File:
|
|
// olecache.cpp
|
|
//
|
|
// Contents:
|
|
// Ole default presentation cache implementation
|
|
//
|
|
// Classes:
|
|
// COleCache - ole multiple presentation cache
|
|
// CCacheEnum - enumerator for COleCache
|
|
//
|
|
// Functions:
|
|
// CreateDataCache
|
|
//
|
|
// History:
|
|
// 31-Jan-95 t-ScottH add Dump methods to COleCache
|
|
// CCacheEnum
|
|
// CCacheEnumFormatEtc
|
|
// add the following APIs: DumpCOleCache
|
|
// DumpCCacheEnum
|
|
// DumpCCacheEnumFormatEtc
|
|
// moved CCacheEnumFormatEtc def'n to header file
|
|
// added flag to COLECACHEFLAGS to indicate aggregation
|
|
// (_DEBUG only)
|
|
// 01/09/95 - t-ScottH - change VDATETHREAD to accept a this
|
|
// pointer, and added VDATETHREAD to IViewObject:: methods
|
|
// (COleCache::CCacheViewImpl:: )
|
|
// 03/01/94 - AlexGo - Added call tracing to AddRef/Release
|
|
// implementations
|
|
// 02/08/94 - ChrisWe - 7297: need implementation of
|
|
// FORMATETC enumerator
|
|
// 01/24/94 alexgo first pass at converting to Cairo-style
|
|
// memory allocation
|
|
// 01/11/94 - AlexGo - added VDATEHEAP macros to every function
|
|
// and method.
|
|
// 12/10/93 - AlexT - header file clean up, include ole1cls.h
|
|
// 12/09/93 - ChrisWe - incremented pointer in COleCache::GetNext()
|
|
// 11/30/93 - alexgo - fixed bugs with GETPPARENT usage
|
|
// 11/23/93 - ChrisWe - introduce use of CACHEID_NATIVE,
|
|
// CACHEID_GETNEXT_GETALL, CACHEID_GETNEXT_GETALLBUTNATIVE
|
|
// for documentary purposes
|
|
// 11/22/93 - ChrisWe - replace overloaded ==, != with
|
|
// IsEqualIID and IsEqualCLSID
|
|
// 07/04/93 - SriniK - Added the support for reading PBrush,
|
|
// MSDraw native objects, hence avoid creating
|
|
// presentation cache/stream. Also started writing static
|
|
// object data into "OLE_CONTENTS" stream in placeable
|
|
// metafile format for static metafile and DIB File
|
|
// format for static dibs. This enabled me to provide
|
|
// support for converting static objects. Also added code
|
|
// to support converting static metafile to MSDraw object
|
|
// and static DIB to PBrush object.
|
|
// 06/04/93 - SriniK - Added the support for demand loading and
|
|
// discarding the caches.
|
|
// 11/12/92 - SriniK - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
// A Brief Story about Cache IDs:
|
|
//
|
|
// Although I'm sure the true intent was to only to confuse mere mortals
|
|
// by randomly applying a modulus value to the cache id value, I think it
|
|
// works like this:
|
|
//
|
|
// When a node has never occupied this slot, its ID is simply its index
|
|
// into the array of present nodes. When a node is detached from the cache,
|
|
// the cache node pointer is cleared (signifying an emtpy slot), but its ID is
|
|
// left in the slot. When a new node is placed in this slot, it assumes
|
|
// the ID of the old node, plus MAX_CACHELIST_ITEMS. Thus if this constant
|
|
// is 100 (which it was last I looked), when node 5 is detached, and a new
|
|
// node is later added at this slot, it receives ID 105.
|
|
//
|
|
// I believe the intention was that this prevented apps from accidentally
|
|
// using ID 5 and getting the data from ID 105 by mistake (ie: referencing
|
|
// a stale connection).
|
|
#include <le2int.h>
|
|
|
|
#pragma SEG(olecache)
|
|
|
|
#include <olepres.h>
|
|
#include <olecache.h>
|
|
#include <cachenod.h>
|
|
#include <ole1cls.h>
|
|
|
|
#ifdef _DEBUG
|
|
#include <dbgdump.h>
|
|
#endif // _DEBUG
|
|
|
|
NAME_SEG(OleCache)
|
|
ASSERTDATA
|
|
|
|
#ifndef WIN32
|
|
#ifndef _MAC
|
|
const LONG lMaxSmallInt = 32767;
|
|
const LONG lMinSmallInt = -32768;
|
|
#else
|
|
|
|
#ifdef MAC_REVIEW
|
|
Review IS_SMALL_INT.
|
|
#endif
|
|
#include <limits.h>
|
|
|
|
#define lMaxSmallInt SHRT_MAX
|
|
#define lMinSmallInt SHRT_MIN
|
|
#endif
|
|
|
|
#define IS_SMALL_INT(lVal) \
|
|
((HIWORD(lVal) && ((lVal > lMaxSmallInt) || (lVal < lMinSmallInt))) \
|
|
? FALSE : TRUE)
|
|
|
|
#endif // WIN32
|
|
|
|
#define FREEZE_CONSTANT 143 // Used by Freeze() and Unfreeze()
|
|
|
|
// predefined CACHEIDs
|
|
#define CACHEID_INVALID ((DWORD)(-1))
|
|
#define CACHEID_NATIVE 0
|
|
|
|
// The CACHEID_GETNEXT_* values can be used when beginning an enumeration
|
|
// with the GetNext() functions to begin the enumeration at a particular
|
|
// place.
|
|
#define CACHEID_GETNEXT_GETALL ((DWORD)(-1))
|
|
#define CACHEID_GETNEXT_GETALLBUTNATIVE 0
|
|
|
|
|
|
// This was the original code...
|
|
|
|
/*
|
|
#define VERIFY_TYMED_SINGLE_VALID_FOR_CLIPFORMAT(pfetc) {\
|
|
if ((pfetc->cfFormat==CF_METAFILEPICT && pfetc->tymed!=TYMED_MFPICT)\
|
|
|| ( (pfetc->cfFormat==CF_BITMAP || \
|
|
pfetc->cfFormat == CF_DIB ) \
|
|
&& pfetc->tymed!=TYMED_GDI)\
|
|
|| (pfetc->cfFormat!=CF_METAFILEPICT && \
|
|
pfetc->cfFormat!=CF_BITMAP && \
|
|
pfetc->cfFormat!=CF_DIB && \
|
|
pfetc->tymed!=TYMED_HGLOBAL)) \
|
|
return ResultFromScode(DV_E_TYMED); \
|
|
}
|
|
*/
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
// CheckTymedCFCombination (Internal)
|
|
//
|
|
// Synopsis:
|
|
// Verifies that the combination of clipformat and tymed is
|
|
// valid to the cache.
|
|
//
|
|
// Arguments:
|
|
// [pfetc] -- The candidate FORMATETC
|
|
//
|
|
// Returns:
|
|
// S_OK For a valid combination
|
|
// CACHE_S_FORMATETC_NOTSUPPORTED For a combination which can be
|
|
// cached, but not drawn by the cache
|
|
// DV_E_TYMED For all other combinations
|
|
//
|
|
// Rules:
|
|
//
|
|
// 1> (CMF && TMF) || (CEM && TEM) || (CB && TG) || (CD && TH) => S_OK
|
|
// (TH && ~CD) => CACHE_S_FORMATETC_NOTSUPPORTED
|
|
//
|
|
// 2> (~S_OK && ~CACHE_S_FORMATETC_NOTSUPPORTED) => DV_E_TYMED
|
|
//
|
|
// Where: CMF == CF_METAFILEPICT
|
|
// CEM == CF_ENHMETAFILE
|
|
// CB == CF_BITMAP
|
|
// CD == CF_FIB
|
|
// TMF == TYMED_MFPICT
|
|
// TEM == TYMED_ENHMETAFILE
|
|
// TG == TYMED_GDI
|
|
// TH == TYMED_HGLOBAL
|
|
//
|
|
// Notes:
|
|
// Since CACHE_S_FORMATETC_NOTSUPPORTED was never implemented in
|
|
// 16-bit, we return S_OK in its place if we are in the WOW.
|
|
//
|
|
// History:
|
|
// 01/07/94 DavePl Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL_(HRESULT) CheckTymedCFCombination(LPFORMATETC pfetc)
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
// CF_METAFILEPICT on TYMED_MFPICT is a valid combination
|
|
|
|
if (pfetc->cfFormat == CF_METAFILEPICT && pfetc->tymed == TYMED_MFPICT)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
// CF_ENHMETAFILE on TYMED_ENHMF is a valid combination
|
|
|
|
else if (pfetc->cfFormat == CF_ENHMETAFILE && pfetc->tymed == TYMED_ENHMF)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
// CF_BITMAP on TYMED_GDI is a valid combination
|
|
|
|
else if (pfetc->cfFormat == CF_BITMAP && pfetc->tymed == TYMED_GDI)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
// CF_DIB on TYMED_HGLOBAL is a valid combination
|
|
|
|
else if (pfetc->cfFormat == CF_DIB && pfetc->tymed == TYMED_HGLOBAL)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
// Anything else on TYMED_HGLOBAL is valid, but we cannot draw it
|
|
|
|
else if (pfetc->tymed == TYMED_HGLOBAL)
|
|
{
|
|
hr = IsWOWThread() ? S_OK : CACHE_S_FORMATETC_NOTSUPPORTED;
|
|
}
|
|
|
|
// Any other combination is invalid
|
|
|
|
else
|
|
{
|
|
hr = DV_E_TYMED;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
// IsSameAsObjectFormatEtc, internal
|
|
//
|
|
// Synopsis:
|
|
// REVIEW, checks to see if [lpforetc] is compatible with
|
|
// [cfFormat]. If [lpforetc] doesn't have a format set,
|
|
// sets it to cfFormat, which is then assumed to be
|
|
// one of CF_METAFILEPICT, or CF_DIB.
|
|
//
|
|
// Arguments:
|
|
// [lpforetc] -- a pointer to a FORMATETC
|
|
// [cfFormat] -- a clipboard format
|
|
//
|
|
// Returns:
|
|
// DV_E_ASPECT, if the aspect isn't DVASPECT_CONTENT
|
|
// DV_E_LINDEX, DV_E_CLIPFORMAT if the lindex or clipboard
|
|
// formats don't match
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL IsSameAsObjectFormatEtc(LPFORMATETC lpforetc, CLIPFORMAT cfFormat);
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
// CreateDataCache, public
|
|
//
|
|
// Synopsis:
|
|
// Creates an instance of COleCache, the default presentation
|
|
// cache used by Ole.
|
|
//
|
|
// Arguments:
|
|
// [pUnkOuter] -- pointer to outer unknown, if this is being
|
|
// aggregated
|
|
// [rclsid] -- the class that the cache should assume for itself
|
|
// [iid] -- the interface the user would like returned
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CreateDataCache)
|
|
STDAPI CreateDataCache(IUnknown FAR* pUnkOuter, REFCLSID rclsid, REFIID iid,
|
|
LPVOID FAR* ppv)
|
|
{
|
|
OLETRACEIN((API_CreateDataCache, PARAMFMT("pUnkOuter= %p, rclsid= %I, iid= %I, ppv= %p"),
|
|
pUnkOuter, &rclsid, &iid, ppv));
|
|
|
|
VDATEHEAP();
|
|
|
|
HRESULT error;
|
|
COleCache FAR* lpCOleCache; // the newly allocated cache
|
|
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IUnknown,(IUnknown **)&pUnkOuter);
|
|
|
|
// NULL for pUnkOuter is OK
|
|
if (pUnkOuter)
|
|
{
|
|
VDATEIFACE_LABEL(pUnkOuter, errRtn, error);
|
|
if (!IsEqualIID(iid, IID_IUnknown))
|
|
{
|
|
// being aggregated but they did not request IUnknown
|
|
error = E_INVALIDARG;
|
|
goto errRtn;
|
|
}
|
|
}
|
|
|
|
// allocate new cache
|
|
lpCOleCache = (COleCache FAR*) new FAR COleCache(pUnkOuter, rclsid);
|
|
|
|
// if insufficient memory, return
|
|
if (!lpCOleCache)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
error = ResultFromScode(E_OUTOFMEMORY);
|
|
goto errRtn;
|
|
}
|
|
|
|
// if we're being aggregated, return private IUnknown
|
|
if (pUnkOuter)
|
|
{
|
|
*ppv = (void FAR *)(IUnknown FAR *)&lpCOleCache->m_UnkPrivate;
|
|
error = NOERROR;
|
|
}
|
|
else
|
|
{
|
|
// get requested interface on cache
|
|
error = lpCOleCache->QueryInterface(iid, ppv);
|
|
|
|
// release local pointer to cache and return
|
|
lpCOleCache->Release();
|
|
}
|
|
|
|
CALLHOOKOBJECTCREATE(error, rclsid, iid, (IUnknown **)ppv);
|
|
|
|
errRtn:
|
|
OLETRACEOUT((API_CreateDataCache, error));
|
|
|
|
return error;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::COleCache, public
|
|
//
|
|
// Synopsis:
|
|
// constructor
|
|
//
|
|
// Arguments:
|
|
// [pUnkOuter] -- outer unknown, if being aggregated
|
|
// [rclsid] -- the class id the cache should assume for itself
|
|
//
|
|
// Notes:
|
|
// The IUnknown returned is not the private unknown. The private
|
|
// unknown is pOleCache->m_UnkPrivate
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_ctor)
|
|
COleCache::COleCache(IUnknown FAR* pUnkOuter, REFCLSID rclsid)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
GET_A5();
|
|
|
|
// set reference count for return from constructor
|
|
m_refs = 1;
|
|
|
|
// initialize flags
|
|
m_uFlag = 0;
|
|
|
|
// aggregate, or use our own IUnknown for outer IUnknown
|
|
|
|
if (NULL == pUnkOuter)
|
|
{
|
|
m_pUnkOuter = &m_UnkPrivate;
|
|
}
|
|
else
|
|
{
|
|
m_pUnkOuter = pUnkOuter;
|
|
|
|
// this is for the debugger extensions
|
|
// (since we can not compare m_pUnkOuter to m_pUnkPrivate with copied mem)
|
|
// it is only used in the ::Dump method
|
|
#ifdef _DEBUG
|
|
m_uFlag |= COLECACHEF_AGGREGATED;
|
|
#endif // _DEBUG
|
|
}
|
|
|
|
// no storage yet
|
|
m_pStg = NULL;
|
|
|
|
// initialize cache list
|
|
m_uCacheNodeCnt = 0;
|
|
m_uCacheNodeMax = 0;
|
|
m_pCacheList = NULL;
|
|
LEVERIFY( GrowCacheList() ); // REVIEW(davepl) Need error case here?
|
|
|
|
m_pCacheEnum = NULL; // pointer to cache enumerator list
|
|
|
|
// no advise sink connected for the view object
|
|
m_pViewAdvSink = NULL;
|
|
m_advfView = 0;
|
|
m_aspectsView = 0;
|
|
|
|
// id of cache node which was used in the previous Draw call
|
|
m_dwDrawCacheId = CACHEID_INVALID;
|
|
|
|
// no frozen aspects
|
|
m_dwFrozenAspects = NULL;
|
|
|
|
// no data object yet
|
|
m_pDataObject = NULL; // non-NULL if running; no ref count
|
|
|
|
m_clsid = rclsid;
|
|
|
|
// set flags for the format, based on the clsid
|
|
|
|
if (IsEqualCLSID(m_clsid, CLSID_StaticMetafile))
|
|
{
|
|
m_cfFormat = CF_METAFILEPICT;
|
|
m_uFlag |= COLECACHEF_STATIC | COLECACHEF_FORMATKNOWN;
|
|
|
|
}
|
|
else if (IsEqualCLSID(m_clsid, CLSID_StaticDib))
|
|
{
|
|
m_cfFormat = CF_DIB;
|
|
m_uFlag |= COLECACHEF_STATIC | COLECACHEF_FORMATKNOWN;
|
|
|
|
}
|
|
else if (IsEqualCLSID(m_clsid, CLSID_PBrush))
|
|
{
|
|
m_cfFormat = CF_DIB;
|
|
m_uFlag |= COLECACHEF_PBRUSHORMSDRAW | COLECACHEF_FORMATKNOWN;
|
|
|
|
}
|
|
else if (IsEqualCLSID(m_clsid, CLSID_MSDraw))
|
|
{
|
|
m_cfFormat = CF_METAFILEPICT;
|
|
m_uFlag |= COLECACHEF_PBRUSHORMSDRAW | COLECACHEF_FORMATKNOWN;
|
|
|
|
}
|
|
else if (IsEqualCLSID(m_clsid, CLSID_Picture_EnhMetafile))
|
|
{
|
|
m_cfFormat = CF_ENHMETAFILE;
|
|
m_uFlag |= COLECACHEF_STATIC | COLECACHEF_FORMATKNOWN;
|
|
}
|
|
else
|
|
{
|
|
m_cfFormat = NULL;
|
|
}
|
|
|
|
// If we know the object format then add a cachenode for it. This node
|
|
// will be put in the 0th entry of the cachelist. This node never gets
|
|
// saved. It's get used in drawing, for finding out the extents, and by
|
|
// the enumerator, etc...
|
|
|
|
if (m_cfFormat)
|
|
{
|
|
LEVERIFY( AddCacheNodeForNative() );
|
|
}
|
|
|
|
m_fUsedToBePBrush = FALSE;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::~COleCache, public //REVIEW
|
|
//
|
|
// Synopsis:
|
|
// destructor
|
|
//
|
|
// Notes:
|
|
// Enumerators for the cache no not reference count it, with the
|
|
// view that the cache can go away at any time, invalidating
|
|
// the enumerators. This walks the list of enumerators, alerting
|
|
// them to the fact that the cache is being destroyed.
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_dtor)
|
|
COleCache::~COleCache(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
// Notify all cache enumerators that we are getting deleted
|
|
while(m_pCacheEnum)
|
|
{
|
|
m_pCacheEnum->OnOleCacheDelete();
|
|
m_pCacheEnum = m_pCacheEnum->m_pNextCacheEnum;
|
|
}
|
|
|
|
// Clear the cache list - delete all the cache nodes
|
|
DeleteAll();
|
|
|
|
// delete the list of cache node pointers
|
|
PubMemFree(m_pCacheList);
|
|
|
|
// if we're holding storage, release it
|
|
if (m_pStg)
|
|
{
|
|
m_pStg->Release();
|
|
m_pStg = NULL;
|
|
}
|
|
|
|
// if we're holding an advise sink, release it
|
|
if (m_pViewAdvSink)
|
|
{
|
|
m_pViewAdvSink->Release();
|
|
m_pViewAdvSink = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_QueryInterface)
|
|
STDMETHODIMP COleCache::QueryInterface(REFIID iid, LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return(m_pUnkOuter->QueryInterface(iid, ppv));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_AddRef)
|
|
STDMETHODIMP_(ULONG) COleCache::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return(m_pUnkOuter->AddRef());
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/15/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_Release)
|
|
STDMETHODIMP_(ULONG) COleCache::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return(m_pUnkOuter->Release());
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetExtent, public
|
|
//
|
|
// Synopsis:
|
|
// Gets the size of the cached presentation for [dwAspect]. If
|
|
// there are several, because of varied advise control flags,
|
|
// such as ADVF_NODATA, ADVF_ONSTOP, ADVF_ONSAVE, etc, gets the
|
|
// most up to date one, up to frozen cached values
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect for which we'd like the extent
|
|
// [lpsizel] -- pointer to where to return the width and height
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetExtent)
|
|
INTERNAL COleCache::GetExtent(DWORD dwAspect, LPSIZEL lpsizel)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
DWORD dwCacheId; // cache id of node currently being examined
|
|
LPCACHENODE lpCacheNode; // pointer to node being examined
|
|
int iCacheType; // cache type [from below] of node being examined
|
|
int iCacheTypeSoFar; // best cache type so far
|
|
// these values are defined in order of least to best preferred, so that
|
|
// numeric comparisons are valid; DO NOT REORDER
|
|
#define CACHETYPE_NODATA 1
|
|
#define CACHETYPE_ONSTOP 2
|
|
#define CACHETYPE_ONSAVE 3
|
|
#define CACHETYPE_NORMAL 4
|
|
const FORMATETC FAR *lpforetc; // format information for current node
|
|
DWORD grfAdvf; // advise flags for current node
|
|
|
|
// if there are no cache nodes, there's nothing we can return
|
|
if (!m_uCacheNodeCnt)
|
|
{
|
|
lpsizel->cx = 0;
|
|
lpsizel->cy = 0;
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
}
|
|
|
|
// Here we want to return the extents of the cache node that has NORMAL
|
|
// advise flags. If we don't find such a node then we will take the next
|
|
// best available.
|
|
|
|
// REVIEW(davepl) Clean up this loop, I get ill just looking at it
|
|
|
|
for(iCacheTypeSoFar = 0, dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
lpCacheNode = GetNext(dwAspect, DEF_LINDEX,
|
|
&dwCacheId);)
|
|
{
|
|
// get a pointer to the FORMATETC for this node
|
|
lpforetc = lpCacheNode->GetFormatEtc();
|
|
|
|
// make sure the cfFormat is either CF_METAFILEPICT or CF_DIB
|
|
if ((lpforetc->cfFormat == CF_METAFILEPICT) ||
|
|
(lpforetc->cfFormat == CF_DIB) ||
|
|
(lpforetc->cfFormat == CF_ENHMETAFILE))
|
|
{
|
|
grfAdvf = lpCacheNode->GetAdvf();
|
|
|
|
if (!(grfAdvf & (ADVFCACHE_ONSAVE |
|
|
ADVF_DATAONSTOP | ADVF_NODATA)))
|
|
iCacheType = CACHETYPE_NORMAL;
|
|
else
|
|
{
|
|
if (grfAdvf & ADVFCACHE_ONSAVE)
|
|
iCacheType = CACHETYPE_ONSAVE;
|
|
else if (grfAdvf & ADVF_NODATA)
|
|
iCacheType = CACHETYPE_NODATA;
|
|
else
|
|
iCacheType = CACHETYPE_ONSTOP;
|
|
}
|
|
|
|
if (iCacheType > iCacheTypeSoFar)
|
|
{
|
|
SIZEL sizelTmp;
|
|
|
|
// Get the extents from the presentation object
|
|
if ((lpCacheNode->GetPresObj())->GetExtent(
|
|
dwAspect, &sizelTmp) != NOERROR)
|
|
continue;
|
|
|
|
if (sizelTmp.cx == 0 || sizelTmp.cy == 0)
|
|
continue;
|
|
|
|
// We got proper extent, update state.
|
|
// If the cache is a
|
|
// NORMAL cache then we are done.
|
|
*lpsizel = sizelTmp;
|
|
if ((iCacheTypeSoFar = iCacheType) ==
|
|
CACHETYPE_NORMAL)
|
|
return NOERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lpsizel->cx == 0 || lpsizel->cy == 0)
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
return NOERROR;
|
|
|
|
// don't need these anymore
|
|
#undef CACHETYPE_NODATA
|
|
#undef CACHETYPE_ONSTOP
|
|
#undef CACHETYPE_ONSAVE
|
|
#undef CACHETYPE_NORMAL
|
|
}
|
|
|
|
|
|
// Private methods of COleCache - called by its friends CCacheNode, CCacheEnum
|
|
// and all nested classes of COleCache
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::OnChange, private
|
|
//
|
|
// Synopsis:
|
|
// Used by cache nodes to alert the cache that their content has
|
|
// changed. The advise sink held by the cache is alerted to
|
|
// the change if it affects an aspect that the advise sink is
|
|
// interested in.
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect that changed
|
|
// [lindex] -- the lindex for the aspect that changed
|
|
// [fDirty] -- indicates that the change has made the cache dirty
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Each one of the cache nodes call this method when their data changes. We
|
|
// in turn send the view notification only if the aspect and lindex of the
|
|
// cache node (that called us) matches with the aspect and lindex for which
|
|
// view advise is set up.
|
|
|
|
#pragma SEG(COleCache_OnChange)
|
|
INTERNAL_(void) COleCache::OnChange(DWORD dwAspect, LONG lindex, BOOL fDirty)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
// mark the cache as dirty
|
|
if (fDirty)
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
|
|
// if there's no view advise sink, there's nothing to do
|
|
if (m_pViewAdvSink == NULL)
|
|
return;
|
|
|
|
// if the aspect that changed is not one that the view advise sink
|
|
// client is interested in, there's nothing more to do
|
|
if (!(m_aspectsView & dwAspect))
|
|
return;
|
|
|
|
// advise the view advise sink client of the change
|
|
m_pViewAdvSink->OnViewChange(dwAspect, lindex);
|
|
|
|
// if client only wanted notification once, free the advise sink
|
|
if (m_advfView & ADVF_ONLYONCE)
|
|
{
|
|
m_pViewAdvSink->Release();
|
|
m_pViewAdvSink = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetStg, private
|
|
//
|
|
// Synopsis:
|
|
// returns the storage the cache has been given to use
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// pointer to the IStorage instance
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL_(LPSTORAGE) COleCache::GetStg(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return m_pStg;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::DetachCacheEnum, private
|
|
//
|
|
// Synopsis:
|
|
// This removes an instance of CCacheEnum from the list of
|
|
// enumerators maintained by COleCache.
|
|
//
|
|
// Arguments:
|
|
// [pCacheEnum] -- the cache enumerator to remove
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// CCacheEnum calls this routine to remove its pointer to the enumerators list
|
|
|
|
#pragma SEG(COleCache_DetachCacheEnum)
|
|
INTERNAL_(void) COleCache::DetachCacheEnum(CCacheEnum FAR* pCacheEnum)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CCacheEnum FAR *FAR *ppCE; // pointer to the pointer to the list item
|
|
CCacheEnum FAR *pCE; // pointer to the item
|
|
|
|
// NOTE: no ref count
|
|
|
|
// search the list for [pCacheEnum]
|
|
for(ppCE = &m_pCacheEnum; pCE = *ppCE; ppCE = &pCE->m_pNextCacheEnum)
|
|
{
|
|
// if we find [pCacheEnum], splice it out of the list
|
|
if (pCE == pCacheEnum)
|
|
{
|
|
*ppCE = pCE->m_pNextCacheEnum;
|
|
pCE->m_pNextCacheEnum = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Following are the COleCache cache list manipulation methods
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GrowCacheList, private
|
|
//
|
|
// Synopsis:
|
|
// Grows the size of the cachenode list. Use this when all
|
|
// available nodes are used up. Grows the list by
|
|
// NUM_CACHELIST_ITEMS
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// TRUE if the list is successfully grown, FALSE otherwise
|
|
//
|
|
// Modifies:
|
|
// m_pCacheList
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GrowCacheList)
|
|
INTERNAL_(BOOL) COleCache::GrowCacheList(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG ulNewMax; // the number of cache nodes we'll have after growing
|
|
ULONG ulSize; // the amount of memory required
|
|
LPCACHELIST pCacheList; // pointer to the (re)allocated memory
|
|
ULONG ulCnt; // used to count off the new items for initialization
|
|
|
|
|
|
ulNewMax = NUM_CACHELIST_ITEMS + m_uCacheNodeMax;
|
|
|
|
// The current architecture of the cache prevents the cachenode
|
|
// array from having more entries that MAX_CACHELIST_ITEMS, so
|
|
// we must fail any attempt to grow the cache beyond this point.
|
|
|
|
if (ulNewMax > MAX_CACHELIST_ITEMS)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
ulSize = ulNewMax * sizeof(CACHELIST_ITEM);
|
|
|
|
// (re)allocate the memory for the cachelist array
|
|
if (m_pCacheList == NULL)
|
|
pCacheList = (LPCACHELIST)PubMemAlloc(ulSize);
|
|
else
|
|
pCacheList = (LPCACHELIST)PubMemRealloc(m_pCacheList,
|
|
ulSize);
|
|
|
|
// if allocation failed, nothing more we can do
|
|
if (pCacheList == NULL)
|
|
return FALSE;
|
|
// REVIEW, if a reallocation, if m_pCacheList still valid on failure
|
|
|
|
// assign the new memory
|
|
m_pCacheList = pCacheList;
|
|
|
|
// initialize the newly allocated items with 0
|
|
for (pCacheList += m_uCacheNodeMax, ulCnt = NUM_CACHELIST_ITEMS;
|
|
ulCnt; ++pCacheList, --ulCnt)
|
|
{
|
|
pCacheList->dwCacheId = 0;
|
|
pCacheList->lpCacheNode = 0;
|
|
}
|
|
|
|
// record new array length
|
|
m_uCacheNodeMax = ulNewMax;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::DeleteAll, private
|
|
//
|
|
// Synopsis:
|
|
// Delete all cache nodes in the cache list array
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// clear the cache list
|
|
|
|
#pragma SEG(COleCache_DeleteAll)
|
|
INTERNAL_(void) COleCache::DeleteAll(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
DWORD dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
LPCACHENODE lpCacheNode;
|
|
|
|
// if no nodes are in use, nothing to do
|
|
if (!m_uCacheNodeCnt)
|
|
return;
|
|
|
|
// get each node that is in use, and free it
|
|
while(m_uCacheNodeCnt && GetNext(&dwCacheId))
|
|
{
|
|
// Remove the CacheNode from the list and then delete it.
|
|
if (lpCacheNode = Detach(dwCacheId))
|
|
lpCacheNode->Delete();
|
|
}
|
|
|
|
Assert(!m_uCacheNodeCnt);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Attach, private
|
|
//
|
|
// Synopsis:
|
|
// adds a new cache node to the cache node list
|
|
//
|
|
// Arguments:
|
|
// [lpCacheNode] -- pointer to new cache node to add to the list
|
|
//
|
|
// Returns:
|
|
// The cache id of the newly added node, or CACHEID_INVALID,
|
|
// if it cannot be attached.
|
|
//
|
|
// Modifies:
|
|
// m_pCacheList
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/16/93 - ChrisWe - file inspection and cleanup; return
|
|
// CACHEID_INVALID on failure, instead of zero, which
|
|
// is a legitimate (internal) cache node id
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Find an empty entry and add the CacheNode to the list. Note that
|
|
// lpCacheNode is not ref counted.
|
|
|
|
#pragma SEG(COleCache_Attach)
|
|
INTERNAL_(DWORD) COleCache::Attach(LPCACHENODE lpCacheNode)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CACHELIST_ITEM FAR *pCI; // pointer to current cachelist item
|
|
ULONG c; // counter
|
|
|
|
// The dwCacheID is nothing but the index into the array plus
|
|
// N*MAX_CACHELIST_ITEMS. Since 0 cannot be a valid connection ID, we
|
|
// should not use the 0th entry of the array.
|
|
// REVIEW, and yet we do, for the CACHEID_NATIVE!!!
|
|
|
|
// look for an empty slot
|
|
for(pCI = m_pCacheList + (c = CACHEID_NATIVE+1); c < m_uCacheNodeMax;
|
|
++pCI, ++c)
|
|
{
|
|
if (pCI->lpCacheNode == NULL)
|
|
goto foundEmpty;
|
|
}
|
|
|
|
// if we get here, all slots are in use, so grow the array of slots
|
|
// if we can't grow it, get out
|
|
if (!GrowCacheList())
|
|
return(CACHEID_INVALID);
|
|
|
|
// the first free slot is at the end of the (newly allocated) array
|
|
pCI = m_pCacheList+c;
|
|
|
|
foundEmpty:
|
|
// We found an empty slot. Now assign the cache ID such that we
|
|
// will be able to catch error cases.
|
|
if (pCI->dwCacheId == 0)
|
|
pCI->dwCacheId = c;
|
|
else
|
|
pCI->dwCacheId += MAX_CACHELIST_ITEMS;
|
|
|
|
pCI->lpCacheNode = lpCacheNode;
|
|
|
|
// Keep track of the number of caches
|
|
m_uCacheNodeCnt++;
|
|
return pCI->dwCacheId;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Detach, private
|
|
//
|
|
// Synopsis:
|
|
// Remove the indicated cache node from the list of cache nodes
|
|
// maintained. The cache node is not deleted, but is returned.
|
|
//
|
|
// Arguments:
|
|
// [dwCacheId] -- the id of the cache node
|
|
//
|
|
// Returns:
|
|
// pointer to the detached cache node, if it is found, or NULL.
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_Detach)
|
|
INTERNAL_(LPCACHENODE) COleCache::Detach(DWORD dwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG index = dwCacheId % MAX_CACHELIST_ITEMS;
|
|
LPCACHENODE lpCacheNode = NULL; // return value; the node being detached
|
|
CACHELIST_ITEM FAR *pCI; // the cachelist item affected
|
|
|
|
if (index >= m_uCacheNodeMax)
|
|
return NULL;
|
|
|
|
pCI = m_pCacheList+index;
|
|
if ((pCI->dwCacheId == dwCacheId) && (pCI->lpCacheNode != NULL))
|
|
{
|
|
// record the cache node pointer for return
|
|
lpCacheNode = pCI->lpCacheNode;
|
|
|
|
// mark this cache node item as unused
|
|
pCI->lpCacheNode = NULL;
|
|
|
|
Assert(m_uCacheNodeCnt != 0);
|
|
// Keep trck of the number of caches
|
|
m_uCacheNodeCnt--;
|
|
}
|
|
|
|
return lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetNext, private
|
|
//
|
|
// Synopsis:
|
|
// Fetch the next cache node after the one identified by
|
|
// *[lpdwCacheId]. Update *[lpdwCacheID] to that node.
|
|
//
|
|
// Arguments:
|
|
// [lpdwCacheId] -- pointer to a cache id.
|
|
//
|
|
// Returns:
|
|
// pointer to the cache node, if there is one, or NULL
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Upon entry *lpdwCacheId will be set to the cur cache id. On exit it will be
|
|
// set to the next valid cache id.
|
|
|
|
#pragma SEG(COleCache_GetNext)
|
|
INTERNAL_(LPCACHENODE) COleCache::GetNext(LPDWORD lpdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CACHELIST_ITEM FAR *pCI; // used to walk the array of cachelist items
|
|
ULONG index; // the index of the current cachelist item
|
|
|
|
// Start from the entry next to the current one. If starting at the
|
|
// "next" element pushes us past the last possible cache node index,
|
|
// there's no way we can actually find anything, so return NULL.
|
|
|
|
if (*lpdwCacheId % MAX_CACHELIST_ITEMS == MAX_CACHELIST_ITEMS - 1)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
index = (*lpdwCacheId+1) % MAX_CACHELIST_ITEMS;
|
|
|
|
for(pCI = m_pCacheList + index; index < m_uCacheNodeMax; ++pCI, ++index)
|
|
{
|
|
if (pCI->lpCacheNode)
|
|
{
|
|
*lpdwCacheId = pCI->dwCacheId;
|
|
return pCI->lpCacheNode;
|
|
}
|
|
}
|
|
|
|
// if we got here, we went off the end of the array
|
|
// REVIEW, should we set *lpdwCacheId so we don't iterate again
|
|
// if the last N entries were all empty?
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetAt, private
|
|
//
|
|
// Synopsis:
|
|
// Fetch the cache node identified by [dwCacheId]
|
|
//
|
|
// Arguments:
|
|
// [dwCacheId] -- the id of the cache node to fetch
|
|
//
|
|
// Returns:
|
|
// the pointer to the cache node, if it is valid, or NULL
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetAt)
|
|
INTERNAL_(LPCACHENODE) COleCache::GetAt(DWORD dwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
ULONG index = dwCacheId % MAX_CACHELIST_ITEMS;
|
|
CACHELIST_ITEM FAR *pCI;
|
|
|
|
if (index >= m_uCacheNodeMax)
|
|
return NULL;
|
|
|
|
pCI = m_pCacheList+index;
|
|
if (pCI->dwCacheId == dwCacheId)
|
|
return(pCI->lpCacheNode); // could be NULL
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetAt, private
|
|
//
|
|
// Synopsis:
|
|
// Fetch the cache node with the given [dwAspect], [lindex],
|
|
// [cfFormat], and for device described by [ptd]
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect to look for
|
|
// [lindex] -- the lindex to look for
|
|
// [cfFormat] -- the clipboard format to look for
|
|
// [ptd] -- the target device for the cache node
|
|
// [lpdwCacheId] -- a pointer to where to return the cache node
|
|
// id, if a match is found
|
|
//
|
|
// Returns:
|
|
// pointer to a cache node that matches the requested attributes,
|
|
// if there is one, or NULL
|
|
//
|
|
// Notes:
|
|
// the m_dwDrawCacheId node is checked first, if there is one
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetAt)
|
|
INTERNAL_(LPCACHENODE) COleCache::GetAt(DWORD dwAspect, LONG lindex,
|
|
CLIPFORMAT cfFormat, DVTARGETDEVICE FAR* ptd, DWORD FAR* lpdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
DWORD dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
LPCACHENODE lpCacheNode = NULL;
|
|
const FORMATETC FAR *lpforetc;
|
|
|
|
// Check to see whether the cache currently being used for drawing is
|
|
// the one that we are looking for.
|
|
if (m_dwDrawCacheId != CACHEID_INVALID)
|
|
{
|
|
if (!(lpCacheNode = GetAt(m_dwDrawCacheId)))
|
|
{
|
|
// the draw cache id has become invalid, so clear it.
|
|
m_dwDrawCacheId = CACHEID_INVALID;
|
|
}
|
|
else
|
|
{
|
|
// The draw cache id is valid, get the formatetc of
|
|
// the cache
|
|
lpforetc = lpCacheNode->GetFormatEtc();
|
|
|
|
// look for a match
|
|
if ((lpforetc->cfFormat == cfFormat) &&
|
|
(lpforetc->dwAspect == dwAspect) &&
|
|
(lpforetc->lindex == lindex) &&
|
|
UtCompareTargetDevice(ptd,
|
|
lpforetc->ptd))
|
|
{
|
|
dwCacheId = m_dwDrawCacheId;
|
|
goto errRtn;
|
|
}
|
|
}
|
|
}
|
|
|
|
// What we are looking for does not match with the current draw cache.
|
|
// So, scan the list for a match.
|
|
while(lpCacheNode = GetNext(&dwCacheId))
|
|
{
|
|
if (dwCacheId == m_dwDrawCacheId)
|
|
continue; // we have checked the draw cache, so skip it
|
|
|
|
lpforetc = lpCacheNode->GetFormatEtc();
|
|
if ((lpforetc->cfFormat == cfFormat) &&
|
|
(lpforetc->dwAspect == dwAspect) &&
|
|
(lpforetc->lindex == lindex) &&
|
|
UtCompareTargetDevice(ptd, lpforetc->ptd))
|
|
break; // we found a match, so break out of the loop
|
|
}
|
|
|
|
// if we don't find a match, then lpCacheNode will be NULL.
|
|
errRtn:
|
|
if (lpdwCacheId)
|
|
*lpdwCacheId = dwCacheId;
|
|
|
|
return lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetNext, public
|
|
//
|
|
// Synopsis:
|
|
// Fetch the next cache node after the one identified by
|
|
// *[lpdwCacheId] that matches the given [dwAspect] and [lindex]
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect to look for
|
|
// [lindex] -- the lindex to look for
|
|
// [lpdwCacheId] -- pointer to a cache id of the node after which
|
|
// to start the search. The cache id of the node that
|
|
// is found to match [dwAspect] and [lindex] will be
|
|
// returned in the same place.
|
|
//
|
|
// Returns:
|
|
// pointer to the cache node that matches the requested
|
|
// attributes, if one is found, or NULL
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetNext)
|
|
INTERNAL_(LPCACHENODE) COleCache::GetNext(DWORD dwAspect, LONG lindex,
|
|
DWORD FAR* lpdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
DWORD dwCacheId = *lpdwCacheId;
|
|
LPCACHENODE lpCacheNode = NULL;
|
|
const FORMATETC FAR *lpforetc;
|
|
|
|
while(lpCacheNode = GetNext(&dwCacheId))
|
|
{
|
|
lpforetc = lpCacheNode->GetFormatEtc();
|
|
if ((lpforetc->dwAspect == dwAspect) &&
|
|
(lpforetc->lindex == lindex))
|
|
break; // we found a match, so break out of the loop
|
|
}
|
|
|
|
// if we don't find a match, then lpCacheNode will be NULL.
|
|
// REVIEW, so why don't we advance *lpdwCacheId in that case?
|
|
if (lpCacheNode)
|
|
*lpdwCacheId = dwCacheId;
|
|
|
|
return lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetAt, private
|
|
//
|
|
// Synopsis:
|
|
// Fetch a pointer to the cache node with the given FORMATETC,
|
|
// if there is one. if [lpforetc]->cfFormat is NULL, we check
|
|
// for CF_ENHMETAFILE, CF_METAFILE, and CF_DIB, in that order.
|
|
//
|
|
// Arguments:
|
|
// [lpforetc] -- pointer to the FORMATETC to check for
|
|
//
|
|
// Returns:
|
|
// Pointer to the cache node with a matching FORMATETC, if there
|
|
// is one, or NULL.
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetAt)
|
|
INTERNAL_(LPCACHENODE) COleCache::GetAt(LPFORMATETC lpforetc,
|
|
DWORD FAR* lpdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
LPCACHENODE lpCacheNode;
|
|
|
|
if (lpforetc->cfFormat == 0)
|
|
{
|
|
// See whether we already cached an EMF, metafile or a DIB
|
|
|
|
if (lpCacheNode = GetAt(lpforetc->dwAspect, lpforetc->lindex,
|
|
CF_METAFILEPICT, lpforetc->ptd, lpdwCacheId))
|
|
goto Exit;
|
|
|
|
|
|
if (lpCacheNode = GetAt(lpforetc->dwAspect, lpforetc->lindex,
|
|
CF_DIB, lpforetc->ptd, lpdwCacheId))
|
|
goto Exit;
|
|
|
|
if (lpCacheNode = GetAt(lpforetc->dwAspect, lpforetc->lindex,
|
|
CF_ENHMETAFILE, lpforetc->ptd, lpdwCacheId))
|
|
goto Exit;
|
|
|
|
// If we have a NULL node, and we are _looking_ for a NULL
|
|
// node, we must satisfy the request so that the advise flags
|
|
// can be updated for multiple caches of NULL nodes.
|
|
|
|
if (lpCacheNode = GetAt(lpforetc->dwAspect, lpforetc->lindex,
|
|
0, lpforetc->ptd, lpdwCacheId))
|
|
goto Exit;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
// NON-NULL cfFormat
|
|
// see whether this format is already cached.
|
|
|
|
if (lpCacheNode = GetAt(lpforetc->dwAspect, lpforetc->lindex,
|
|
lpforetc->cfFormat, lpforetc->ptd, lpdwCacheId))
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
return lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetPresObjForDrawing, private
|
|
//
|
|
// Synopsis:
|
|
// Fetch a presentation object matching the given parameters,
|
|
// if there is one. We try to get CF_ENHMETAFILE,
|
|
// CF_METAFILEPICT, and CF_DIB formats, in that order.
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect we'd like
|
|
// [lindex] -- the lindex we'd like
|
|
// [ptd] -- description of the target device the presentation
|
|
// should be suitable for
|
|
//
|
|
// Returns:
|
|
// pointer to the presentation object, if a suitable one is
|
|
// found, or NULL
|
|
//
|
|
// Modifies:
|
|
// m_dwDrawCacheId is set to the newly found cache id, if one
|
|
// is found
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetPresObjForDrawing)
|
|
INTERNAL_(LPOLEPRESOBJECT) COleCache::GetPresObjForDrawing(DWORD dwAspect,
|
|
LONG lindex, DVTARGETDEVICE FAR* ptd)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
LPOLEPRESOBJECT lpPresObj; // the found presentation object
|
|
DWORD dwCacheId; // the cache id of the presentation object
|
|
|
|
// Try for Enhanced Metafile
|
|
if ((lpPresObj = GetPresObj(dwAspect, lindex, CF_ENHMETAFILE, ptd,
|
|
&dwCacheId)) && !lpPresObj->IsBlank())
|
|
goto success;
|
|
|
|
// Try for Metafile
|
|
if ((lpPresObj = GetPresObj(dwAspect, lindex, CF_METAFILEPICT, ptd,
|
|
&dwCacheId)) && !lpPresObj->IsBlank())
|
|
goto success;
|
|
|
|
|
|
// Try for Dib
|
|
if ((lpPresObj = GetPresObj(dwAspect, lindex, CF_DIB, ptd,
|
|
&dwCacheId)) && !lpPresObj->IsBlank())
|
|
goto success;
|
|
|
|
|
|
return NULL;
|
|
|
|
success:
|
|
// COleCache try to get the CacheNode for a given dwAspect, lindex, ptd,
|
|
// etc.., they will first try the cachenode with this cache id, and if
|
|
// they don't find the match they will start scanning the list.
|
|
//
|
|
// This caching is necessary 'cause even when the containers create
|
|
// mutiple caches most of the time they deal with only one (view)
|
|
// aspect.
|
|
|
|
m_dwDrawCacheId = dwCacheId;
|
|
return lpPresObj;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetPresObj, private
|
|
//
|
|
// Synopsis:
|
|
// Get the presentation object of the cache node which matches
|
|
// the requested attributes.
|
|
//
|
|
// Arguments:
|
|
// [dwAspect] -- the aspect
|
|
// [lindex] -- the lindex
|
|
// [cfFormat] -- the clipboard format
|
|
// [ptd] -- points to the description of the target device
|
|
// [pdwCacheId] -- pointer to a location where the cache id
|
|
// can be returned for the presentation object
|
|
//
|
|
// Returns:
|
|
// pointer to the presentation object, is one is found that
|
|
// matches the requested parameters, or NULL
|
|
//
|
|
// Notes:
|
|
// If a request is made for CF_BITMAP ([cfFormat]), then
|
|
// GetPresObj() checks for CF_DIB.
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetPresObj)
|
|
INTERNAL_(LPOLEPRESOBJECT) COleCache::GetPresObj(DWORD dwAspect, LONG lindex,
|
|
CLIPFORMAT cfFormatIn, DVTARGETDEVICE FAR* ptd,
|
|
DWORD FAR* pdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
LPCACHENODE lpCacheNode;
|
|
#ifndef _MAC
|
|
CLIPFORMAT cfFormat = ((cfFormatIn == CF_BITMAP) ? CF_DIB :
|
|
cfFormatIn);
|
|
#endif
|
|
|
|
if (lpCacheNode = GetAt(dwAspect, lindex, cfFormat, ptd, pdwCacheId))
|
|
return lpCacheNode->GetPresObj();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::AddCacheNodeForNative, private
|
|
//
|
|
// Synopsis:
|
|
// Create the Native format cache node, and add it to the list
|
|
// of cache nodes, if it doesn't already exist.
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// pointer to the found, or newly created cache node. Can
|
|
// return NULL if out of memory
|
|
//
|
|
// Notes:
|
|
// This assumes that m_cfFormat is set.
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL_(LPCACHENODE)COleCache::AddCacheNodeForNative(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CACHELIST_ITEM FAR *pCI; // points to CACHEID_NATIVE cache node
|
|
LPCACHENODE lpCacheNode; // points to the cache node in the cache list
|
|
FORMATETC foretc; // the format we'll initialize the new node with
|
|
|
|
// point at the CACHEID_NATIVE node
|
|
pCI = &m_pCacheList[CACHEID_NATIVE];
|
|
|
|
// if we already have a native format, return it
|
|
if (pCI->lpCacheNode)
|
|
return(pCI->lpCacheNode);
|
|
|
|
Assert(m_cfFormat);
|
|
|
|
INIT_FORETC(foretc);
|
|
|
|
foretc.cfFormat = m_cfFormat;
|
|
|
|
if (foretc.cfFormat == CF_METAFILEPICT)
|
|
{
|
|
foretc.tymed = TYMED_MFPICT;
|
|
}
|
|
else if (foretc.cfFormat == CF_ENHMETAFILE)
|
|
{
|
|
foretc.tymed = TYMED_ENHMF;
|
|
}
|
|
else
|
|
{
|
|
foretc.tymed = TYMED_HGLOBAL; // REVIEW, need to use union
|
|
}
|
|
|
|
// create cache node
|
|
if (lpCacheNode = new FAR CCacheNode(&foretc,
|
|
(((m_uFlag & COLECACHEF_PBRUSHORMSDRAW) && !m_fUsedToBePBrush) ?
|
|
ADVF_NODATA : 0), this))
|
|
{
|
|
if (lpCacheNode->CreatePresObject(NULL /*lpDataObj*/,
|
|
FALSE /*fConvert*/) != NOERROR)
|
|
{
|
|
// if we can't create presentation object,
|
|
// delete the cache node, and drop out
|
|
lpCacheNode->Delete();
|
|
}
|
|
else
|
|
{
|
|
// there's one more cache node in use
|
|
++m_uCacheNodeCnt;
|
|
|
|
// set this as the CACHEID_NATIVE cache node
|
|
pCI->lpCacheNode = lpCacheNode;
|
|
}
|
|
}
|
|
|
|
// if creation failed, this will return NULL
|
|
return pCI->lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::DeleteCacheNodeForNative, private
|
|
//
|
|
// Synopsis:
|
|
// Delete the native format cache node
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
inline INTERNAL_(void) COleCache::DeleteCacheNodeForNative(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CACHELIST_ITEM FAR *pCI = &m_pCacheList[CACHEID_NATIVE];
|
|
|
|
// if there is no native cache node, there's nothing to do
|
|
if (!pCI->lpCacheNode)
|
|
return;
|
|
|
|
// delete the native cache node
|
|
pCI->lpCacheNode->Delete();
|
|
pCI->lpCacheNode = NULL;
|
|
--m_uCacheNodeCnt;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::MoveCacheNodeForNative, private
|
|
//
|
|
// Synopsis:
|
|
// Moves whatever cache node is under CACHEID_NATIVE to
|
|
// another position and another cache id, leaving the
|
|
// native cachenode unused.
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/17/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
inline INTERNAL_(void) COleCache::MoveCacheNodeForNative(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
if (m_pCacheList[CACHEID_NATIVE].lpCacheNode)
|
|
Attach(Detach(CACHEID_NATIVE));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::UpdateCacheNodeForNative, private
|
|
//
|
|
// Synopsis:
|
|
// Update the native data cache node from the storage currently
|
|
// associated with the cache
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// a pointer to the native cache node
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/23/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL_(LPCACHENODE) COleCache::UpdateCacheNodeForNative()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CACHELIST_ITEM FAR *pCI = &m_pCacheList[CACHEID_NATIVE];
|
|
FORMATETC foretc;
|
|
STGMEDIUM stgmed;
|
|
|
|
// if there is no native cache node, add one
|
|
if (!pCI->lpCacheNode)
|
|
{
|
|
AddCacheNodeForNative();
|
|
|
|
// if there still isn't a native cache node, get out
|
|
if (!pCI->lpCacheNode)
|
|
return NULL;
|
|
}
|
|
|
|
Assert(m_pStg);
|
|
if (!m_pStg)
|
|
goto errRtn;
|
|
|
|
// initialize a FORMATETC for native data
|
|
INIT_FORETC(foretc);
|
|
foretc.cfFormat = m_cfFormat;
|
|
|
|
if (foretc.cfFormat == CF_METAFILEPICT)
|
|
{
|
|
foretc.tymed = TYMED_MFPICT;
|
|
}
|
|
else if (foretc.cfFormat == CF_ENHMETAFILE)
|
|
{
|
|
foretc.tymed = TYMED_ENHMF;
|
|
}
|
|
else
|
|
{
|
|
foretc.tymed = TYMED_HGLOBAL; // REVIEW, need to use union
|
|
}
|
|
|
|
// retrieve a global with the native data
|
|
stgmed.pUnkForRelease = NULL;
|
|
stgmed.tymed = foretc.tymed;
|
|
stgmed.hGlobal = UtGetHPRESFromNative(m_pStg, foretc.cfFormat,
|
|
(m_uFlag & COLECACHEF_PBRUSHORMSDRAW) ? TRUE : FALSE);
|
|
|
|
// set the data
|
|
if (stgmed.hGlobal)
|
|
pCI->lpCacheNode->SetData(&foretc, &stgmed, TRUE);
|
|
|
|
errRtn:
|
|
return pCI->lpCacheNode;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleObject::FindObjectFormat, private
|
|
//
|
|
// Synopsis:
|
|
// Determines what the object's clipboard format is. If
|
|
// it is CF_ENHMETAFILE, CF_METAFILEPICT, or CF_DIB, the format
|
|
// is marked as COLECACHE_FORMATKNOWN, and installed in
|
|
// CACHEID_NATIVE. If anything else, the format is unknown, and
|
|
// the native cache node is made empty. There is no effect, if the
|
|
// presentation is COLECACHE_STATIC.
|
|
//
|
|
// Arguments:
|
|
// [pstg] -- pointer to storage where the object can be found
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL_(void) COleCache::FindObjectFormat(LPSTORAGE pstg)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
CLIPFORMAT cf;
|
|
|
|
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IStorage,(IUnknown **)&pstg);
|
|
|
|
if (m_uFlag & COLECACHEF_STATIC)
|
|
return;
|
|
|
|
if (IsEqualCLSID(m_clsid, CLSID_PBrush) || m_fUsedToBePBrush)
|
|
cf = CF_DIB;
|
|
else if (IsEqualCLSID(m_clsid, CLSID_MSDraw))
|
|
cf = CF_METAFILEPICT;
|
|
else
|
|
{
|
|
if (!pstg)
|
|
return;
|
|
|
|
if (FAILED(ReadFmtUserTypeStg(pstg, &cf, NULL)))
|
|
cf = 0;
|
|
}
|
|
|
|
if (m_cfFormat == cf)
|
|
return;
|
|
|
|
if (cf == CF_METAFILEPICT || cf == CF_DIB || cf == CF_ENHMETAFILE)
|
|
{
|
|
DeleteCacheNodeForNative();
|
|
m_cfFormat = cf;
|
|
AddCacheNodeForNative();
|
|
m_uFlag |= COLECACHEF_FORMATKNOWN;
|
|
|
|
}
|
|
else
|
|
{
|
|
MoveCacheNodeForNative();
|
|
m_uFlag &= ~COLECACHEF_FORMATKNOWN;
|
|
}
|
|
}
|
|
|
|
|
|
// IOleCacheControl implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::OnRun, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCacheControl::OnRun
|
|
//
|
|
// Notify the cache that the object is running; the cache will
|
|
// set up advisory connections with interested presentation nodes.
|
|
// No effect if the cache has already been notified that the object
|
|
// is running.
|
|
//
|
|
// Arguments:
|
|
// [pDataObj] -- an IDataObject interface on the running object
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/23/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_OnRun)
|
|
STDMETHODIMP COleCache::OnRun(IDataObject FAR* pDataObj)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
DWORD dwCacheId; // used to loop through the cache nodes
|
|
LPCACHENODE lpCacheNode; // points to the current cache node
|
|
|
|
M_PROLOG(this);
|
|
|
|
VDATEIFACE(pDataObj);
|
|
|
|
// if we already have the data object, nothing more to do
|
|
if (m_pDataObject)
|
|
return NOERROR;
|
|
|
|
m_pDataObject = pDataObj; // NOTE: no ref count
|
|
|
|
// Notify all the cache nodes that the object is RUN, so that they can
|
|
// set up the advise connections with it.
|
|
for(dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
lpCacheNode = GetNext(&dwCacheId);)
|
|
lpCacheNode->OnRun(pDataObj);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::OnStop, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCacheControl::OnStop
|
|
//
|
|
// Informs the cache that the object (whose IDataObject is
|
|
// in m_pDataObject) has stopped. Advisory connections to the
|
|
// object are torn down. No effect if the cache has already
|
|
// been notified that the object has stopped.
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/23/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_OnStop)
|
|
STDMETHODIMP COleCache::OnStop(void)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
DWORD dwCacheId; // used to loop through the cache nodes
|
|
LPCACHENODE lpCacheNode; // points to the current cache node
|
|
|
|
M_PROLOG(this);
|
|
|
|
// if there's no data object, there's nothing to do
|
|
if (!m_pDataObject)
|
|
return(NOERROR);
|
|
|
|
for(dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
lpCacheNode = GetNext(&dwCacheId);)
|
|
lpCacheNode->OnStop();
|
|
|
|
m_pDataObject = NULL; // NOTE: no ref count
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
// IOleCache implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Cache, public
|
|
//
|
|
// Synopsis:
|
|
// implementation of IOleCache::Cache
|
|
//
|
|
// Instructs that cache to cache a rendering of this object.
|
|
//
|
|
// Arguments:
|
|
// [lpforetcIn] -- the presentation format to cache
|
|
// [advf] -- the advise control flags, from ADVF_*
|
|
// [lpdwCacheId] -- pointer to where to return the id of the
|
|
// cache node for this format
|
|
//
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_Cache)
|
|
STDMETHODIMP COleCache::Cache(LPFORMATETC lpforetcIn, DWORD advf,
|
|
LPDWORD lpdwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
HRESULT error;
|
|
FORMATETC foretc;
|
|
LPCACHENODE lpCacheNode = NULL;
|
|
DWORD dwDummyCacheId; // point lpdwCacheId at this to avoid testing
|
|
|
|
M_PROLOG(this);
|
|
|
|
// initialize *lpdwCacheId in case of error return, OR,
|
|
// initialize lpdwCacheId so that we needn't test it before assigning
|
|
// *lpdwCacheId in future
|
|
if (lpdwCacheId)
|
|
*lpdwCacheId = CACHEID_NATIVE; // REVIEW, not CACHEID_INVALID?
|
|
else
|
|
lpdwCacheId = &dwDummyCacheId;
|
|
|
|
// validate parameters
|
|
if (!HasValidLINDEX(lpforetcIn))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
if (FAILED(error = VerifyAspectSingle(lpforetcIn->dwAspect)))
|
|
{
|
|
return error;
|
|
}
|
|
|
|
if (lpforetcIn->cfFormat)
|
|
{
|
|
if (FAILED(error = CheckTymedCFCombination(lpforetcIn)))
|
|
{
|
|
return error;
|
|
}
|
|
}
|
|
|
|
if (lpforetcIn->ptd)
|
|
{
|
|
VDATEPTRIN(lpforetcIn->ptd, sizeof(DVTARGETDEVICE));
|
|
}
|
|
|
|
AssertSz(m_pStg,
|
|
"Cache IStorage ptr has not been initialized by handler\n");
|
|
|
|
// copy the FORMATETC, so that we can alter it if we wish
|
|
foretc = *lpforetcIn;
|
|
|
|
if (foretc.dwAspect != DVASPECT_ICON)
|
|
{
|
|
BITMAP_TO_DIB(foretc);
|
|
|
|
if (m_uFlag & COLECACHEF_FORMATKNOWN)
|
|
{
|
|
// check to see if the new format is the same as the
|
|
// current native format
|
|
if ((error = IsSameAsObjectFormatEtc(&foretc,
|
|
m_cfFormat)) == NOERROR)
|
|
{
|
|
|
|
// if ptd is NULL then we know how to draw
|
|
// this format. Return success code, but return
|
|
// CACHEID_NATIVE for dwCacheId.
|
|
if (foretc.ptd == NULL)
|
|
{
|
|
// Locate the cache node and update the
|
|
// advise flags, if they are different
|
|
|
|
if (lpCacheNode = GetAt(&foretc, lpdwCacheId))
|
|
{
|
|
if (lpCacheNode->GetAdvf() != advf)
|
|
{
|
|
// If we are setting new advise flags,
|
|
// mark the cache as dirty
|
|
|
|
lpCacheNode->SetAdvf(advf);
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
}
|
|
}
|
|
|
|
// We assume that we _must_ already have
|
|
// cached this format, so we must have
|
|
// found it
|
|
|
|
Assert(lpCacheNode);
|
|
|
|
return ResultFromScode(CACHE_S_SAMECACHE);
|
|
}
|
|
else if (m_uFlag & COLECACHEF_STATIC)
|
|
{
|
|
// NON-NULL ptd doesn't make any sense
|
|
// for static objects
|
|
return ResultFromScode(
|
|
DV_E_DVTARGETDEVICE);
|
|
}
|
|
|
|
}
|
|
else if (m_uFlag & COLECACHEF_STATIC)
|
|
return error;
|
|
|
|
// otherwise, if formatetc is a non-standard formatetc
|
|
// (OR) ptd is NON NULL, then we don't have choice but
|
|
// to cache it.
|
|
}
|
|
|
|
}
|
|
|
|
// check to see if we've already got this format cached
|
|
if (lpCacheNode = GetAt(&foretc, lpdwCacheId))
|
|
{
|
|
// are the advise control flags different?
|
|
if (lpCacheNode->GetAdvf() != advf)
|
|
{
|
|
// change the advise control flags; mark cache dirty
|
|
lpCacheNode->SetAdvf(advf);
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
}
|
|
|
|
// get out, indicating this is already cached
|
|
return ResultFromScode(CACHE_S_SAMECACHE);
|
|
}
|
|
|
|
// if aspect is DVASPECT_ICON, then format has to be CF_METAFILEPICT
|
|
if (foretc.dwAspect == DVASPECT_ICON)
|
|
{
|
|
// if the format is not set, set it
|
|
if (foretc.cfFormat == NULL)
|
|
{
|
|
foretc.cfFormat = CF_METAFILEPICT;
|
|
foretc.tymed = TYMED_MFPICT;
|
|
}
|
|
else if (foretc.cfFormat != CF_METAFILEPICT)
|
|
return ResultFromScode(DV_E_FORMATETC);
|
|
}
|
|
|
|
// if this aspect is frozen, don't allow creation of the cache
|
|
if (m_dwFrozenAspects & lpforetcIn->dwAspect)
|
|
return ResultFromScode(E_FAIL);
|
|
|
|
// Create cache node for this formatetc
|
|
if (!(lpCacheNode = new FAR CCacheNode(&foretc, advf, this)))
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
|
|
// Add it to the cache list
|
|
if (!(*lpdwCacheId = Attach(lpCacheNode)))
|
|
{
|
|
// if we fail to attach it, delete it and return error
|
|
lpCacheNode->Delete();
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
|
|
// the new cache node has successfully been added, mark cache dirty
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
|
|
// try to create the presentation object
|
|
if ((error = lpCacheNode->CreatePresObject(m_pDataObject,
|
|
FALSE /*fConvert*/)) == NOERROR)
|
|
{
|
|
// presentation object is created, let the cachenode setup
|
|
// advise connections with the server object.
|
|
lpCacheNode->OnRun(m_pDataObject);
|
|
}
|
|
|
|
// CreatePresObject can fail to create the presentation object because
|
|
// of one of the following reasons.
|
|
// 1. The server object doesn't support the format
|
|
// 2. The object is not running and the lpformatetc->cfFormat == NULL.
|
|
//
|
|
// If the object is running and cfFormat is NULL, then the method
|
|
// CreatePresObject queries the object to check whether it supports
|
|
// one of CF_ENHMETAFILE, CF_METAFILEPICT, CF_DIB and CF_BITMAP in that
|
|
// order. And only if the obejct supports one of those formats does it
|
|
// create the presentation object, othewise it will be case 1.
|
|
//
|
|
// Whether the presentation object is created or not, the cachenode will
|
|
// not be removed. It is the responsibility of the caller to do Uncache
|
|
// if the presentation object is not created (which would be conveyed
|
|
// through a special error code.)
|
|
|
|
// Do the special handling for icon here. If the object is not able to
|
|
// render ICON with CF_METAFILEPICT format, then we will go ahead and
|
|
// render it ourselves, by getting the ICON from registration data base.
|
|
|
|
if (foretc.dwAspect == DVASPECT_ICON &&
|
|
!IsEqualCLSID(m_clsid, CLSID_NULL))
|
|
{
|
|
LPOLEPRESOBJECT lpPresObj; // presentation obj, if there is one
|
|
STGMEDIUM stgmed;
|
|
|
|
// if we failed to create the presentation object, as above,
|
|
// error code is already set
|
|
if (!(lpPresObj = lpCacheNode->GetPresObj()))
|
|
goto errRtn;
|
|
|
|
// Don't bother if it has already been rendered
|
|
if (!lpPresObj->IsBlank())
|
|
return NOERROR;
|
|
|
|
// lookup the icon
|
|
if (UtGetIconData(NULL/*lpSrcDataObj*/, m_clsid,
|
|
&foretc, &stgmed) == NOERROR)
|
|
{
|
|
if (lpCacheNode->SetData(&foretc, &stgmed, TRUE) !=
|
|
NOERROR)
|
|
ReleaseStgMedium(&stgmed);
|
|
}
|
|
}
|
|
|
|
// If we don't already have an error condition, check to see if this
|
|
// a format we cannot draw.
|
|
|
|
if (S_OK == error && lpforetcIn->cfFormat)
|
|
{
|
|
error = CheckTymedCFCombination(&foretc);
|
|
}
|
|
|
|
|
|
errRtn:
|
|
|
|
return(error);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Uncache, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache::Uncache
|
|
//
|
|
// instructs the cache that the indicated cache node is no longer
|
|
// needed and should be deleted
|
|
//
|
|
// Arguments:
|
|
// [dwCacheId] -- the id of the cache node to delete
|
|
//
|
|
// Returns:
|
|
// OLE_E_NOCONNECTION, if [dwCacheId] is invalid
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// Internally, CACHEID_NATIVE is valid for COLECACHEF_FORMATKNOWN,
|
|
// but this cache id is never passed outside. This cache node
|
|
// is maintained automatically without any user knowledge of it.
|
|
// Outside the cache, CACHEID_NATIVE is invalid. If this value
|
|
// is passed in, we have to check to see if we have such a node,
|
|
// and if we do, ignore it.
|
|
// REVIEW, why don't we return OLE_E_NOCONNECTION here?
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_Uncache)
|
|
STDMETHODIMP COleCache::Uncache(DWORD dwCacheId)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
LPCACHENODE lpCacheNode; // the cache node dwCacheId identifies
|
|
|
|
M_PROLOG(this);
|
|
|
|
// if the cache id is for the native format node, then this node is
|
|
// not known about externally, and this is merely an invalid cache node
|
|
// id that was handed back from Cache().
|
|
if (dwCacheId == CACHEID_NATIVE)
|
|
{
|
|
if (m_uFlag & COLECACHEF_FORMATKNOWN)
|
|
return NOERROR;
|
|
}
|
|
else
|
|
{
|
|
// remove cachenode from the cache list and then call its
|
|
// delete method
|
|
if (lpCacheNode = Detach(dwCacheId))
|
|
{
|
|
lpCacheNode->Delete();
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
// if we got here, [dwCachdId] was invalid
|
|
return ResultFromScode(OLE_E_NOCONNECTION);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::EnumCache, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache::EnumCache
|
|
//
|
|
// returns an enumerator that can be used to tell what is in the
|
|
// cache
|
|
//
|
|
// Arguments:
|
|
// [ppenum] -- a pointer to where to return the pointer to the
|
|
// enumerator
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_EnumCache)
|
|
STDMETHODIMP COleCache::EnumCache(LPENUMSTATDATA FAR* ppenum)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
M_PROLOG(this);
|
|
|
|
if (!(*ppenum = (LPENUMSTATDATA) new CCacheEnum(this, (DWORD) DEF_LINDEX,
|
|
FALSE)))
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::InitCache, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache::InitCache
|
|
//
|
|
// initializes all cache nodes with the given data object
|
|
//
|
|
// Arguments:
|
|
// [lpSrcDataObj] -- pointer to the source data object
|
|
//
|
|
// Returns:
|
|
// E_INVALIDARG, if [lpSrcDataObj] is NULL
|
|
// same as IOleCache2::UpdateCache
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_InitCache)
|
|
STDMETHODIMP COleCache::InitCache(LPDATAOBJECT lpSrcDataObj)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
M_PROLOG(this);
|
|
|
|
// make sure there's a data object
|
|
if (!lpSrcDataObj)
|
|
return ResultFromScode(E_INVALIDARG);
|
|
|
|
// scan the cache list and update all the cache nodes. It is possible
|
|
// that for some cache nodes the presentation objects get created as
|
|
// part of the update process. As explained in IOleCache
|
|
return UpdateCache(lpSrcDataObj, UPDFCACHE_ALLBUTNODATACACHE,
|
|
NULL /* reserved */);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::SetData, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache::SetData
|
|
//
|
|
// puts data into the cache node which matches the given
|
|
// FORMATETC
|
|
//
|
|
// Arguments:
|
|
// [pformatetc] -- the format the data is in
|
|
// [pmedium] -- the storage medium for the new data
|
|
// [fRelease] -- indicates whether to release the storage
|
|
// after the data is examined
|
|
//
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
// Notes:
|
|
// If the data is for a static object, it is written out to
|
|
// disk to the contents stream.
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_SetData)
|
|
STDMETHODIMP COleCache::SetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium,
|
|
BOOL fRelease)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
LPCACHENODE lpCacheNode; // pointer to the matching cache node
|
|
CLIPFORMAT cfFormat; // local copy of (transmuted) format
|
|
|
|
M_PROLOG(this);
|
|
|
|
VERIFY_TYMED_SINGLE_VALID_FOR_CLIPFORMAT(pformatetc)
|
|
|
|
// if the object, is static, and we don't already have it,
|
|
// write it out to the contents stream
|
|
if (m_uFlag & COLECACHEF_STATIC)
|
|
{
|
|
HRESULT error;
|
|
FORMATETC foretc;
|
|
STGMEDIUM stgmed;
|
|
|
|
if (pformatetc->dwAspect == DVASPECT_ICON)
|
|
goto LOther;
|
|
|
|
foretc = *pformatetc;
|
|
|
|
if (error = IsSameAsObjectFormatEtc(&foretc, m_cfFormat))
|
|
return error;
|
|
|
|
if (foretc.ptd)
|
|
return ResultFromScode(DV_E_DVTARGETDEVICE);
|
|
|
|
if (!(lpCacheNode = AddCacheNodeForNative()))
|
|
return ResultFromScode(E_OUTOFMEMORY);
|
|
|
|
if (error = lpCacheNode->SetData(pformatetc, pmedium, fRelease))
|
|
return error;
|
|
|
|
// write data into "CONTENTS" stream
|
|
if (error = OpenOrCreateStream(m_pStg,
|
|
OLE_CONTENTS_STREAM, &stgmed.pstm))
|
|
return error;
|
|
|
|
stgmed.pUnkForRelease = NULL;
|
|
stgmed.tymed = TYMED_ISTREAM;
|
|
foretc.tymed = TYMED_ISTREAM;
|
|
|
|
error = (lpCacheNode->GetPresObj())->GetDataHere(&foretc,
|
|
&stgmed);
|
|
stgmed.pstm->Release();
|
|
return error;
|
|
}
|
|
|
|
LOther:
|
|
// if its CF_BITMAP, keep CF_DIB instead
|
|
cfFormat = ((pformatetc->cfFormat == CF_BITMAP) ?
|
|
CF_DIB : pformatetc->cfFormat);
|
|
|
|
// find the cache node for the requested data, if there is one
|
|
if (!(lpCacheNode = GetAt(pformatetc->dwAspect,
|
|
pformatetc->lindex, cfFormat, pformatetc->ptd,
|
|
NULL /*lpdwCacheId*/)))
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
// set the data in that cache node
|
|
return lpCacheNode->SetData(pformatetc, pmedium, fRelease);
|
|
}
|
|
|
|
|
|
// IOleCache2 implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::UpdateCache, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache2::UpdateCache
|
|
//
|
|
// Updates all cache entries with the data object passed in, if
|
|
// it is not NULL. If NULL, uses the already-known about data
|
|
// object that is kept inside if the object is running.
|
|
//
|
|
// Arguments:
|
|
// [pDataObjIn] -- The data object to get data from, or NULL
|
|
// [grfUpdf] -- update control flags
|
|
// [pReserved] -- must be NULL
|
|
//
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
// Notes:
|
|
// The native cache node is updated on disk, only if its
|
|
// COLECACHEF_PBRUSHORMSDRAW
|
|
// REVIEW, what about other native format objects?
|
|
//
|
|
// History:
|
|
// 11/24/93 - ChrisWe - file cleanup and inspection
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_UpdateCache)
|
|
STDMETHODIMP COleCache::UpdateCache(LPDATAOBJECT pDataObjIn, DWORD grfUpdf,
|
|
LPVOID pReserved)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
LPDATAOBJECT pDataObject; // the data object to use for the update
|
|
DWORD dwCacheId; // cache id of current node being examined
|
|
ULONG cntUpdatedNodes; // count of nodes that were updated without error
|
|
ULONG cntTotalNodes;
|
|
LPCACHENODE lpCacheNode; // the cache node currently being updated
|
|
|
|
M_PROLOG(this);
|
|
|
|
if (pReserved != NULL)
|
|
AssertSz(FALSE, "Non-NULL reserved parameter passed to OleCache::UpdateCache");
|
|
|
|
// validate the data object, if one is passed in; if there isn't one,
|
|
// use the current one for the cache, if there is one
|
|
if (pDataObjIn)
|
|
{
|
|
VDATEIFACE(pDataObjIn);
|
|
pDataObject = pDataObjIn;
|
|
|
|
}
|
|
else if (!(pDataObject = m_pDataObject))
|
|
{
|
|
return ResultFromScode(OLE_E_NOTRUNNING);
|
|
}
|
|
|
|
// if no caches, then there is nothing to update.
|
|
if (m_uCacheNodeCnt == 0)
|
|
return NOERROR;
|
|
|
|
// Do special handling for PaintBrush or MSDraw objects.
|
|
if (m_uFlag & COLECACHEF_PBRUSHORMSDRAW)
|
|
UpdateCacheNodeForNative();
|
|
|
|
// Ask the cache nodes to update themselves from this data object
|
|
// pointer.
|
|
for(cntUpdatedNodes = 0, dwCacheId = CACHEID_GETNEXT_GETALLBUTNATIVE,
|
|
cntTotalNodes = 0;
|
|
lpCacheNode = GetNext(&dwCacheId);)
|
|
{
|
|
cntTotalNodes++;
|
|
if (lpCacheNode->Update(pDataObject, grfUpdf) == NOERROR)
|
|
{
|
|
cntUpdatedNodes++;
|
|
}
|
|
}
|
|
|
|
// it's OK to have zero nodes and zero updates (PBrush will
|
|
// have this in particular
|
|
|
|
if( cntUpdatedNodes == cntTotalNodes )
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
if (cntUpdatedNodes == 0)
|
|
return ReportResult(0, CACHE_E_NOCACHE_UPDATED, 0, 0);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::DiscardCache, public
|
|
//
|
|
// Synopsis:
|
|
// implements IOleCache2::DiscardCache
|
|
//
|
|
// Instructs the cache that its contents should be discarded;
|
|
// the contents are optionally saved to disk before discarding.
|
|
//
|
|
// Arguments:
|
|
// [dwDiscardOpt] -- discard option from DISCARDCACHE_*
|
|
//
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
// Notes:
|
|
// This maintains the dirty state of the cache, even if it is
|
|
// saved.
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP COleCache::DiscardCache(DWORD dwDiscardOpt)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
HRESULT error; // error state so far
|
|
COLECACHEFLAG uDirty = m_uFlag & COLECACHEF_DIRTY;
|
|
// remember state of the dirty flag
|
|
|
|
if (dwDiscardOpt == DISCARDCACHE_SAVEIFDIRTY)
|
|
{
|
|
// if the contents are dirty, try to save to disk
|
|
if (uDirty)
|
|
{
|
|
if (m_pStg == NULL)
|
|
return ResultFromScode(OLE_E_NOSTORAGE);
|
|
|
|
if (FAILED(error = Save(m_pStg,
|
|
TRUE /* fSameAsLoad */)))
|
|
return error;
|
|
}
|
|
|
|
// continue and do SaveCompleted which will discard the cached
|
|
// presentations from memory
|
|
|
|
goto LNoSave;
|
|
}
|
|
|
|
// if any option other than NOSAVE was specified, we shouldn't have
|
|
// gotten here
|
|
AssertSz(dwDiscardOpt == DISCARDCACHE_NOSAVE,
|
|
"Invalid DiscardCache option");
|
|
if (dwDiscardOpt != DISCARDCACHE_NOSAVE)
|
|
return ResultFromScode(E_INVALIDARG);
|
|
|
|
LNoSave:
|
|
m_uFlag |= COLECACHEF_NOSCRIBBLEMODE | COLECACHEF_SAMEASLOAD;
|
|
wSaveCompleted(NULL, TRUE /*fDiscardDrawCacheAlso*/);
|
|
|
|
// restore the dirty state, since Save() will have cleared it
|
|
// REVIEW, why, since it's not dirty anymore?
|
|
m_uFlag |= uDirty;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// private IUnknown implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheUnkImpl::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// This provides the private IUnknown implementation when
|
|
// COleCache is aggregated
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheUnkImpl_QueryInterface)
|
|
STDMETHODIMP NC(COleCache, CCacheUnkImpl)::QueryInterface(REFIID iid,
|
|
LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_UnkPrivate);
|
|
|
|
M_PROLOG(pOleCache);
|
|
VDATEPTROUT(ppv, LPVOID);
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown) ||
|
|
IsEqualIID(iid, IID_IOleCache) ||
|
|
IsEqualIID(iid, IID_IOleCache2))
|
|
*ppv = (void FAR *)(IOleCache2 FAR *)pOleCache;
|
|
else if (IsEqualIID(iid, IID_IDataObject))
|
|
*ppv = (void FAR *)(IDataObject FAR *)&pOleCache->m_Data;
|
|
else if (IsEqualIID(iid, IID_IViewObject) ||
|
|
IsEqualIID(iid, IID_IViewObject2))
|
|
*ppv = (void FAR *)(IViewObject2 FAR *)&pOleCache->m_View;
|
|
else if (IsEqualIID(iid, IID_IPersist) ||
|
|
IsEqualIID(iid, IID_IPersistStorage))
|
|
*ppv = (void FAR *)(IPersistStorage FAR *)pOleCache;
|
|
else if (IsEqualIID(iid, IID_IOleCacheControl))
|
|
*ppv = (void FAR *)(IOleCacheControl FAR *)pOleCache;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
pOleCache->m_pUnkOuter->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheUnkImpl::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// This is part of the private IUnknown implementation of
|
|
// COleCache used when COleCache is aggregated
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheUnkImpl_AddRef)
|
|
STDMETHODIMP_(ULONG) NC(COleCache, CCacheUnkImpl)::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_UnkPrivate);
|
|
|
|
LEDebugOut((DEB_TRACE, "%p _IN COleCache::CCacheUnkImpl::AddRef "
|
|
"( )\n", this ));
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
++pOleCache->m_refs;
|
|
|
|
LEDebugOut((DEB_TRACE, "%p OUT COleCache::CCacheUnkImpl::AddRef "
|
|
"( %lu )\n", this, pOleCache->m_refs));
|
|
|
|
return pOleCache->m_refs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheUnkImpl::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// This is part of the private IUnknown implementation of
|
|
// COleCache used when COleCache is aggregated
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheUnkImpl_Release)
|
|
STDMETHODIMP_(ULONG) NC(COleCache, CCacheUnkImpl)::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_UnkPrivate);
|
|
ULONG uRefs; // the reference count after decrementing
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
LEDebugOut((DEB_TRACE, "%p _IN COleCache::CCacheUnkImpl::Release "
|
|
"( )\n", this ));
|
|
|
|
if ((uRefs = --pOleCache->m_refs) == 0)
|
|
{
|
|
delete pOleCache;
|
|
}
|
|
|
|
LEDebugOut((DEB_TRACE, "%p OUT COleCache::CCacheUnkImpl::Release "
|
|
"( %lu )\n", this, uRefs));
|
|
|
|
return uRefs; // m_refs reference is no longer valid if it was zero
|
|
}
|
|
|
|
// IDataObject implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_QueryInterface)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::QueryInterface(REFIID riid,
|
|
LPVOID FAR* ppvObj)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
|
|
return pOleCache->m_pUnkOuter->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_AddRef)
|
|
STDMETHODIMP_(ULONG) NC(COleCache,CCacheDataImpl)::AddRef (void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
|
|
return pOleCache->m_pUnkOuter->AddRef();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_Release)
|
|
STDMETHODIMP_(ULONG) NC(COleCache,CCacheDataImpl)::Release (void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
|
|
return pOleCache->m_pUnkOuter->Release();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::GetData, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::GetData
|
|
//
|
|
// Arguments:
|
|
// [pforetcIn] -- the format the requestor would like the data in
|
|
// [pmedium] -- where to return the storage medium to the caller
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the cache is empty
|
|
// REVIEW, anything COleCache::GetPresObj returns
|
|
// REVIEW, anything returned by presObj->GetData
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_GetData)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::GetData(LPFORMATETC pforetcIn,
|
|
LPSTGMEDIUM pmedium)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
LPOLEPRESOBJECT lpPresObj; // the presentation object with
|
|
// the requested data in it
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// if the cache is empty, return with nothing
|
|
if (!pOleCache->m_uCacheNodeCnt)
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
Verify(pmedium);
|
|
Verify(pforetcIn);
|
|
|
|
// null out in case of error
|
|
pmedium->tymed = TYMED_NULL;
|
|
pmedium->pUnkForRelease = NULL;
|
|
|
|
VERIFY_ASPECT_SINGLE(pforetcIn->dwAspect);
|
|
|
|
// if no presentation object in the cache that matches the requested
|
|
// format, return blank
|
|
if (!(lpPresObj = pOleCache->GetPresObj(pforetcIn->dwAspect,
|
|
pforetcIn->lindex, pforetcIn->cfFormat,
|
|
pforetcIn->ptd, NULL)))
|
|
return(ResultFromScode(OLE_E_BLANK));
|
|
|
|
// if we got here, we have a presentation object that matches the
|
|
// requested format; return data from it
|
|
return(lpPresObj->GetData(pforetcIn, pmedium));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::GetDataHere, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::GetDataHere
|
|
//
|
|
// Arguments:
|
|
// [pforetcIn] -- the format the requestor would like the data in
|
|
// [pmedium] -- where to return the storage medium to the caller
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the cache is empty
|
|
// REVIEW, anything COleCache::GetPresObj returns
|
|
// REVIEW, anything returned by presObj->GetData
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_GetDataHere)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::GetDataHere(LPFORMATETC pforetcIn,
|
|
LPSTGMEDIUM pmedium)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
LPOLEPRESOBJECT lpPresObj; // the presentation object with the
|
|
// requested data in it
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// if the cache is empty, return with nothing
|
|
if (!pOleCache->m_uCacheNodeCnt);
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
VERIFY_TYMED_SINGLE(pforetcIn->tymed);
|
|
VERIFY_ASPECT_SINGLE(pforetcIn->dwAspect);
|
|
|
|
// TYMED_MFPICT, TYMED_GDI will not be allowed
|
|
if ((pforetcIn->tymed == TYMED_MFPICT)
|
|
|| (pforetcIn->tymed == TYMED_GDI)
|
|
|| (pmedium->tymed != pforetcIn->tymed))
|
|
return ReportResult(0, DV_E_TYMED, 0, 0);
|
|
|
|
// Get data from cache node, if one exists
|
|
if (!(lpPresObj = pOleCache->GetPresObj(pforetcIn->dwAspect,
|
|
pforetcIn->lindex, pforetcIn->cfFormat,
|
|
pforetcIn->ptd, NULL)))
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
// ask the presentation object for the data
|
|
return lpPresObj->GetDataHere(pforetcIn, pmedium);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::QueryGetData, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::QueryGetData
|
|
//
|
|
// Arguments:
|
|
// [pforetcIn] -- the format to check for
|
|
//
|
|
// Returns:
|
|
// S_FALSE, if data is not available in the requested format
|
|
// S_OK otherwise
|
|
//
|
|
// Notes:
|
|
// We will say that the formatetc is supported only if there is
|
|
// a cache and a presentation data in that cache for that
|
|
// formatetc.
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_QueryGetData)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::QueryGetData(LPFORMATETC pforetcIn)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
LPOLEPRESOBJECT lpPresObj; // the presentation object with the
|
|
// requested data in it
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// if the cache is empty, return with nothing
|
|
if (!pOleCache->m_uCacheNodeCnt)
|
|
{
|
|
return ResultFromScode(S_FALSE);
|
|
}
|
|
|
|
VERIFY_TYMED_VALID_FOR_CLIPFORMAT(pforetcIn);
|
|
|
|
// if the cachenode for this formatetc and the presentation object for
|
|
// the cachenode exists then query will succeed
|
|
if (lpPresObj = pOleCache->GetPresObj(pforetcIn->dwAspect,
|
|
pforetcIn->lindex, pforetcIn->cfFormat,
|
|
pforetcIn->ptd, NULL))
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(S_FALSE);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::GetCanonicalFormatEtc, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::GetCanonicalFormatEtc
|
|
//
|
|
// Arguments:
|
|
// [pformatetc] --
|
|
// [pformatetcOut] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_GetCanonicalFormatEtc)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::GetCanonicalFormatEtc(
|
|
LPFORMATETC pformatetc, LPFORMATETC pformatetcOut)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// REVIEW: code need to be added
|
|
return ReportResult(0, E_NOTIMPL, 0, 0); // just not implemented
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::SetData, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::SetData
|
|
//
|
|
// Arguments:
|
|
// [pformatetc] -- the format the data is in
|
|
// [pmedium] -- the storage medium the data is on
|
|
// [fRelease] -- release storage medium after data is copied
|
|
//
|
|
// Returns:
|
|
// REVIEW, anything IOleCache::SetData can return
|
|
//
|
|
// Notes:
|
|
// Does the same thing as IOleCache::SetData
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_SetData)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::SetData(LPFORMATETC pformatetc,
|
|
LPSTGMEDIUM pmedium, BOOL fRelease)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
|
|
VERIFY_TYMED_SINGLE_VALID_FOR_CLIPFORMAT(pformatetc);
|
|
|
|
return pOleCache->SetData(pformatetc, pmedium, fRelease);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::EnumFormatEtc, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::EnumFormatEtc
|
|
//
|
|
// Arguments:
|
|
// [dwDirection] -- which way to run the enumerator
|
|
// [ppenumFormatEtc] -- pointer to where to put the enumerator
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/10/94 - ChrisWe - added implementation
|
|
// 11/10/93 - ChrisWe - set returned pointer to NULL
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_EnumFormatEtc)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::EnumFormatEtc(DWORD dwDirection,
|
|
LPENUMFORMATETC FAR* ppenumFormatEtc)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_Data);
|
|
IEnumSTATDATA FAR *pIES;
|
|
HRESULT hr;
|
|
|
|
VDATEHEAP();
|
|
VDATEPTROUT(ppenumFormatEtc, LPENUMFORMATETC);
|
|
|
|
// initialize for error return
|
|
*ppenumFormatEtc = NULL;
|
|
|
|
// check that only an enumeration for retrieval is required
|
|
if ((dwDirection | DATADIR_GET) != DATADIR_GET)
|
|
return(ReportResult(0, E_NOTIMPL, 0, 0));
|
|
|
|
hr = pOleCache->EnumCache(&pIES);
|
|
if (!SUCCEEDED(hr))
|
|
return(hr);
|
|
|
|
*ppenumFormatEtc = (IEnumFORMATETC FAR *)new CCacheEnumFormatEtc(pIES);
|
|
pIES->Release();
|
|
|
|
if (!*ppenumFormatEtc)
|
|
return(ReportResult(0, E_OUTOFMEMORY, 0, 0));
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::DAdvise, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::DAdvise
|
|
//
|
|
// Arguments:
|
|
// [pforetc] -- the data format the advise sink is interested in
|
|
// [advf] -- advise control flags from ADVF_*
|
|
// [pAdvSink] -- the advise sink
|
|
// [pdwConnection] -- pointer to where to return the connection id
|
|
//
|
|
// Returns:
|
|
// OLE_E_ADVISENOTSUPPORTED
|
|
//
|
|
// Notes:
|
|
// Defhndlr and deflink never call the following three methods. Even for App
|
|
// handlers which make use our cache implementation this is not necessary. So,
|
|
// I am making it return error.
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - set returned connection id to 0
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_DAdvise)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::DAdvise(LPFORMATETC pforetc,
|
|
DWORD advf, IAdviseSink FAR* pAdvSink, DWORD FAR* pdwConnection)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
*pdwConnection = 0;
|
|
return(ReportResult(0, OLE_E_ADVISENOTSUPPORTED, 0, 0));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::DUnadvise, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::DUnadvise
|
|
//
|
|
// Arguments:
|
|
// [dwConnection] -- the connection id
|
|
//
|
|
// Returns:
|
|
// OLE_E_NOCONNECTION
|
|
//
|
|
// Notes:
|
|
// See COleCache::CCacheDataImpl::DAdvise
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(COleCache_CCacheDataImpl_DUnadvise)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::DUnadvise(DWORD dwConnection)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return(ReportResult(0, OLE_E_NOCONNECTION, 0, 0));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheDataImpl::EnumDAdvise, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataObject::EnumDAdvise
|
|
//
|
|
// Arguments:
|
|
// [ppenumDAdvise] -- pointer to where to return the enumerator
|
|
//
|
|
// Returns:
|
|
// OLE_E_ADVISENOTSUPPORTED
|
|
//
|
|
// Notes:
|
|
// See COleCache::CCacheDataImpl::DAdvise
|
|
//
|
|
// History:
|
|
// 11/10/93 - ChrisWe - set returned enumerator pointer to 0
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheDataImpl_EnumDAdvise)
|
|
STDMETHODIMP NC(COleCache,CCacheDataImpl)::EnumDAdvise(
|
|
LPENUMSTATDATA FAR* ppenumDAdvise)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
*ppenumDAdvise = NULL;
|
|
return(ReportResult(0, OLE_E_ADVISENOTSUPPORTED, 0, 0));
|
|
}
|
|
|
|
|
|
// IViewObject implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_QueryInterface)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::QueryInterface(REFIID riid,
|
|
LPVOID FAR* ppvObj)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
return pOleCache->m_pUnkOuter->QueryInterface(riid, ppvObj);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_AddRef)
|
|
STDMETHODIMP_(ULONG) NC(COleCache,CCacheViewImpl)::AddRef(void)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
|
|
//
|
|
// VDATETHREAD contains a 'return HRESULT' but this procedure expects to
|
|
// return a ULONG. Avoid the warning.
|
|
#if ( _MSC_VER >= 800 )
|
|
#pragma warning( disable : 4245 )
|
|
#endif
|
|
VDATETHREAD(pOleCache);
|
|
#if ( _MSC_VER >= 800 )
|
|
#pragma warning( default: 4245 )
|
|
#endif
|
|
|
|
return pOleCache->m_pUnkOuter->AddRef();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/10/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_Release)
|
|
STDMETHODIMP_(ULONG) NC(COleCache,CCacheViewImpl)::Release(void)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
|
|
//
|
|
// VDATETHREAD contains a 'return HRESULT' but this procedure expects to
|
|
// return a ULONG. Avoid the warning.
|
|
#if ( _MSC_VER >= 800 )
|
|
#pragma warning( disable : 4245 )
|
|
#endif
|
|
VDATETHREAD(pOleCache);
|
|
#if ( _MSC_VER >= 800 )
|
|
#pragma warning( default : 4245 )
|
|
#endif
|
|
|
|
return pOleCache->m_pUnkOuter->Release();
|
|
}
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: static COleCache::DrawStackSwitch
|
|
//
|
|
// Synopsis: needed for stack switching
|
|
//
|
|
// Arguments: [pCV] --
|
|
// [dwDrawAspect] --
|
|
// [lindex] --
|
|
// [pvAspect] --
|
|
// [ptd] --
|
|
// [hicTargetDev] --
|
|
// [hdcDraw] --
|
|
// [lprcBounds] --
|
|
// [lprcWBounds] --
|
|
// [pfnContinue] --
|
|
// [DWORD] --
|
|
// [DWORD] --
|
|
// [dwContinue] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 5-25-95 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
INTERNAL COleCache::DrawStackSwitch(
|
|
LPVOID *pCV,
|
|
DWORD dwDrawAspect,
|
|
LONG lindex, void FAR* pvAspect, DVTARGETDEVICE FAR * ptd,
|
|
HDC hicTargetDev, HDC hdcDraw,
|
|
LPCRECTL lprcBounds,
|
|
LPCRECTL lprcWBounds,
|
|
BOOL (CALLBACK * pfnContinue)(DWORD),
|
|
DWORD dwContinue)
|
|
{
|
|
HRESULT hres = NOERROR;
|
|
StackDebugOut((DEB_STCKSWTCH, "COleCache::DrawStackSwitch 32->16 : pCV(%x)n", pCV));
|
|
hres = ((CCacheViewImpl *)pCV)->SSDraw(dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev, hdcDraw,
|
|
lprcBounds, lprcWBounds, pfnContinue, dwContinue);
|
|
StackDebugOut((DEB_STCKSWTCH, "COleCache::DrawStackSwitch 32<-16 back; hres:%ld\n", hres));
|
|
return hres;
|
|
}
|
|
#endif // _CHICAGO_
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::Draw, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::Draw
|
|
//
|
|
// Arguments:
|
|
// [dwDrawAspect] -- a value from the DVASPECT_* enumeration
|
|
// [lindex] -- indicates what piece of the object is of
|
|
// interest; legal values vary with dwDrawAspect
|
|
// [pvAspect] -- currently NULL
|
|
// [ptd] -- the target device
|
|
// [hicTargetDev] -- in information context for [ptd]
|
|
// [hdcDraw] -- device context on which drawing is to be done
|
|
// [lprcBounds] -- boundaries of drawing on [hdcDraw]
|
|
// [lprcWBounds] -- if hdcDraw is a meta-file, it's boundaries
|
|
// [pfnContinue] --a callback function that the drawer should call
|
|
// periodically to see if rendering should be aborted.
|
|
// [dwContinue] -- passed on into [pfnContinue]
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if no presentation object can be found
|
|
// REVIEW, anything from IOlePresObj::Draw
|
|
//
|
|
// Notes:
|
|
// This finds the presentation object in the cache for
|
|
// the requested format, if there is one, and then passes
|
|
// on the call to its Draw method.
|
|
//
|
|
// The use of a callback function as a parameter means that
|
|
// this interface cannot be remoted, unless some custom
|
|
// proxy is built, allowing the function to be called back in its
|
|
// original context; the interface is defined as
|
|
// [local] in common\types
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_Draw)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::Draw(
|
|
DWORD dwDrawAspect,
|
|
LONG lindex, void FAR* pvAspect, DVTARGETDEVICE FAR * ptd,
|
|
HDC hicTargetDev, HDC hdcDraw,
|
|
LPCRECTL lprcBounds,
|
|
LPCRECTL lprcWBounds,
|
|
BOOL (CALLBACK * pfnContinue)(DWORD),
|
|
DWORD dwContinue)
|
|
#ifdef _CHICAGO_
|
|
{
|
|
HRESULT hres;
|
|
// Note: Switch to the 16 bit stack under WIN95.
|
|
if (SSONBIGSTACK())
|
|
{
|
|
LEDebugOut((DEB_TRACE, "COleCache::DrawStackSwitch 32->16; this(%x)n", this));
|
|
hres = SSCall(44, SSF_SmallStack, (LPVOID)DrawStackSwitch, (DWORD) this,
|
|
(DWORD)dwDrawAspect, (DWORD)lindex,(DWORD) pvAspect, (DWORD)ptd, (DWORD)hicTargetDev,
|
|
(DWORD)hdcDraw, (DWORD)lprcBounds, (DWORD)lprcWBounds, (DWORD)pfnContinue, (DWORD)dwContinue);
|
|
}
|
|
else
|
|
hres = SSDraw(dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev, hdcDraw,
|
|
lprcBounds, lprcWBounds, pfnContinue, dwContinue);
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: SSDraw
|
|
//
|
|
// Synopsis: Called by Draw after switching to 16 bit stack
|
|
//
|
|
// Arguments: [dwDrawAspect] --
|
|
// [lindex] --
|
|
// [pvAspect] --
|
|
// [ptd] --
|
|
// [hicTargetDev] --
|
|
// [hdcDraw] --
|
|
// [lprcBounds] --
|
|
// [lprcWBounds] --
|
|
// [pfnContinue] --
|
|
// [DWORD] --
|
|
// [DWORD] --
|
|
// [dwContinue] --
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 5-25-95 JohannP (Johann Posch) Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#pragma SEG(COleCache_CCacheViewImpl_SSDraw)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::SSDraw(
|
|
DWORD dwDrawAspect,
|
|
LONG lindex, void FAR* pvAspect, DVTARGETDEVICE FAR * ptd,
|
|
HDC hicTargetDev, HDC hdcDraw,
|
|
LPCRECTL lprcBounds,
|
|
LPCRECTL lprcWBounds,
|
|
BOOL (CALLBACK * pfnContinue)(DWORD),
|
|
DWORD dwContinue)
|
|
#endif // _CHICAGO_
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
BOOL bMetaDC; // is [hdcDraw] for a metafile?
|
|
LPOLEPRESOBJECT lpPresObj; // the presentation object for the
|
|
// requested format, if there is one
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// validate parameters
|
|
// if (pvAspect)
|
|
// VDATEPTRIN(pvAspect, ?????);
|
|
if (ptd)
|
|
VDATEPTRIN(ptd, DVTARGETDEVICE);
|
|
if (lprcWBounds)
|
|
VDATEPTRIN(lprcWBounds, RECTL);
|
|
|
|
if( !lprcBounds )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
VDATEPTRIN(lprcBounds, RECTL);
|
|
}
|
|
|
|
// we can't draw into a NULL-DC.
|
|
if( hdcDraw == NULL )
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!IsValidLINDEX(dwDrawAspect, lindex))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
// Get presentation object for this aspect, lindex, ptd, if there is one
|
|
if (!(lpPresObj = pOleCache->GetPresObjForDrawing(dwDrawAspect,
|
|
lindex, ptd)))
|
|
return ReportResult(0, OLE_E_BLANK, 0, 0);
|
|
|
|
// if the DC is a metafile DC then valid window bounds must be passed in
|
|
if ((bMetaDC = OleIsDcMeta(hdcDraw)) && (lprcWBounds == NULL))
|
|
return ReportResult(0, E_INVALIDARG, 0, 0);
|
|
|
|
#ifdef MAC_REVIEW
|
|
|
|
A RECT value on the MAC contains members which are 'short's'. A RECTL
|
|
uses longs, and in the code below an assumption is explicitely made
|
|
that long member values is directly comp[atible on the MAC. Naturally, this is not
|
|
the case, and the compiler will barf on this.
|
|
|
|
#endif
|
|
|
|
#ifndef WIN32 // no need to do this on WIN 32 also
|
|
|
|
// On Win 16 make sure that the coordinates are valid 16bit quantities.
|
|
RECT rcBounds;
|
|
RECT rcWBounds;
|
|
|
|
if (!(IS_SMALL_INT(lprcBounds->left) &&
|
|
IS_SMALL_INT(lprcBounds->right) &&
|
|
IS_SMALL_INT(lprcBounds->top) &&
|
|
IS_SMALL_INT(lprcBounds->bottom)))
|
|
{
|
|
AssertSz(FALSE, "Rect coordinate is not a small int");
|
|
return ReportResult(0, OLE_E_INVALIDRECT, 0, 0);
|
|
|
|
}
|
|
else
|
|
{
|
|
rcBounds.left = (int) lprcBounds->left;
|
|
rcBounds.right = (int) lprcBounds->right;
|
|
rcBounds.top = (int) lprcBounds->top;
|
|
rcBounds.bottom = (int) lprcBounds->bottom;
|
|
}
|
|
|
|
|
|
if (bMetaDC)
|
|
{
|
|
if (!(IS_SMALL_INT(lprcWBounds->left) &&
|
|
IS_SMALL_INT(lprcWBounds->right) &&
|
|
IS_SMALL_INT(lprcWBounds->top) &&
|
|
IS_SMALL_INT(lprcWBounds->bottom)))
|
|
{
|
|
AssertSz(FALSE, "Rect coordinate is not a small int");
|
|
return ReportResult(0, OLE_E_INVALIDRECT, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
rcWBounds.left = (int) lprcWBounds->left;
|
|
rcWBounds.right = (int) lprcWBounds->right;
|
|
rcWBounds.top = (int) lprcWBounds->top;
|
|
rcWBounds.bottom = (int) lprcWBounds->bottom;
|
|
}
|
|
}
|
|
|
|
return(lpPresObj->Draw(pvAspect, hicTargetDev, hdcDraw,
|
|
&rcBounds, &rcWBounds, pfnContinue, dwContinue));
|
|
#else
|
|
// on MAC as well as win 32 we can use the same pointer as it is,
|
|
// 'cause rect fields are 32 bit quantities
|
|
return(lpPresObj->Draw(pvAspect, hicTargetDev, hdcDraw,
|
|
lprcBounds, lprcWBounds, pfnContinue, dwContinue));
|
|
#endif
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::GetColorSet, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::GetColorSet
|
|
//
|
|
// Arguments:
|
|
// [dwDrawAspect] -- a value from the DVASPECT_* enumeration
|
|
// [lindex] -- indicates what piece of the object is of
|
|
// interest; legal values vary with dwDrawAspect
|
|
// [pvAspect] -- currently NULL
|
|
// [ptd] -- the target device
|
|
// [hicTargetDev] -- in information context for [ptd]
|
|
// [ppColorSet] -- the color set required for the requested
|
|
// rendering
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if no presentation object can be found
|
|
// REVIEW, anything from IOlePresObj::Draw
|
|
//
|
|
// Notes:
|
|
// Finds a presentation object in the cache that matches the
|
|
// requested rendering, if there is one, and asks the
|
|
// presentation object for the color set.
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_GetColorSet)
|
|
STDMETHODIMP NC(COleCache, CCacheViewImpl)::GetColorSet(DWORD dwDrawAspect,
|
|
LONG lindex, void FAR* pvAspect, DVTARGETDEVICE FAR * ptd,
|
|
HDC hicTargetDev, LPLOGPALETTE FAR* ppColorSet)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
LPOLEPRESOBJECT lpPresObj;
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
*ppColorSet = NULL;
|
|
|
|
if (!IsValidLINDEX(dwDrawAspect, lindex))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
// Get presentation object for this aspect, lindex, ptd
|
|
if (!(lpPresObj = pOleCache->GetPresObjForDrawing(dwDrawAspect,
|
|
lindex, ptd)))
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
return(lpPresObj->GetColorSet(pvAspect, hicTargetDev, ppColorSet));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::Freeze
|
|
//
|
|
// Arguments:
|
|
// [dwDrawAspect] -- a value from the DVASPECT_* enumeration
|
|
// [lindex] -- indicates what piece of the object is of
|
|
// interest; legal values vary with dwDrawAspect
|
|
// [pvAspect] -- currently NULL
|
|
// [pdwFreeze] -- a token that can later be used to unfreeze
|
|
// this aspects cached presentations
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if no presentation is found that matches the
|
|
// requested characteristics
|
|
//
|
|
// Notes:
|
|
// The current implementation returns the ASPECT+FREEZE_CONSTANT
|
|
// as the FreezeID. At Unfreeze time we get the ASPECT by doing
|
|
// FreezeID-FREEZE_CONSTANT.
|
|
//
|
|
// REVIEW: In future where we allow lindexes other than DEF_LINDEX,
|
|
// we will have to use some other scheme for generating the
|
|
// FreezeID.
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_Freeze)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::Freeze(DWORD dwAspect,
|
|
LONG lindex, LPVOID pvAspect, DWORD FAR* pdwFreeze)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
DWORD dwDummyFreeze; // point at this if !pdwFreeze to avoid retesting
|
|
LPCACHENODE lpCacheNode; // pointer to cache node being examined
|
|
DWORD dwCacheId; // id of cache node being examined
|
|
int iCnt; // counts number of cache nodes frozen
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// We need to initialize this first for error returns
|
|
if (!pdwFreeze)
|
|
{
|
|
// point at a dummy, so we don't always have to pre-test
|
|
// assignments of *pdwFreeze with "if (pdwFreeze) ..."
|
|
pdwFreeze = &dwDummyFreeze;
|
|
}
|
|
else
|
|
{
|
|
// initialize for error returns
|
|
VDATEPTROUT(pdwFreeze, DWORD);
|
|
*pdwFreeze = 0;
|
|
}
|
|
|
|
// validate parameters
|
|
VERIFY_ASPECT_SINGLE(dwAspect);
|
|
|
|
if (!IsValidLINDEX(dwAspect, lindex))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
// if (pvAspect)
|
|
// VDATEPTRIN(pvAspect , ??????)
|
|
|
|
// nothing to do if the aspect we're interested in is already frozen
|
|
if (pOleCache->m_dwFrozenAspects & dwAspect)
|
|
{
|
|
*pdwFreeze = dwAspect + FREEZE_CONSTANT;
|
|
|
|
return(ResultFromScode(VIEW_S_ALREADY_FROZEN));
|
|
}
|
|
|
|
// start searching cache at beginning
|
|
dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
|
|
// no cache nodes have been frozen yet
|
|
iCnt = 0;
|
|
|
|
// freeze each cache node that matches the aspect and lindex
|
|
while(lpCacheNode = pOleCache->GetNext(dwAspect, lindex, &dwCacheId))
|
|
{
|
|
lpCacheNode->Freeze(); // REVIEW, do we have to check for error
|
|
iCnt++;
|
|
}
|
|
|
|
// if we froze any cache nodes
|
|
if (iCnt)
|
|
{
|
|
// Add this aspect to the frozen aspects list.
|
|
pOleCache->m_dwFrozenAspects |= dwAspect;
|
|
|
|
// return the freeze id
|
|
*pdwFreeze = dwAspect + FREEZE_CONSTANT;
|
|
|
|
return(NOERROR);
|
|
}
|
|
|
|
// if we got here, nothing matched the requested characteristics
|
|
return(ResultFromScode(OLE_E_BLANK));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::Unfreeze, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::Unfreeze
|
|
//
|
|
// Arguments:
|
|
// [dwFreezeId] -- the id returned by Freeze() when some aspect
|
|
// was frozen earlier
|
|
//
|
|
// Returns:
|
|
// OLE_E_NOCONNECTION, if dwFreezeId is invalid
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// See notes for Freeze().
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_Unfreeze)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::Unfreeze(DWORD dwFreezeId)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
DWORD dwAspect; // the aspect, after recovered from the dwFreezeId
|
|
LPCACHENODE lpCacheNode; // pointer to cache node being examined
|
|
DWORD dwCacheId; // id of cache node being examined
|
|
LONG lindex; // the lindex for the frozen item
|
|
|
|
HRESULT error = ResultFromScode(OLE_E_NOCONNECTION);
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// Get Aspect and lindex from dwFreezeId
|
|
dwAspect = dwFreezeId - FREEZE_CONSTANT;
|
|
lindex = DEF_LINDEX;
|
|
|
|
// Make sure that only one bit is set and it is <= DVASPECT_DOCPRINT
|
|
// REVIEW, we didn't check for DVASPECT_DOCPRINT when we froze!
|
|
// REVIEW, does this really check for one bit?
|
|
// REVIEW, why not use VERIFY_ASPECT_SINGLE?
|
|
// REVIEW, shouldn't error be E_INVALIDARG?
|
|
if (!(!(dwAspect & (dwAspect-1)) && (dwAspect <= DVASPECT_DOCPRINT)))
|
|
return error;
|
|
|
|
// Make sure that this aspect is frozen
|
|
// REVIEW, shouldn't we have a better error code?
|
|
if (!(pOleCache->m_dwFrozenAspects & dwAspect))
|
|
return error;
|
|
|
|
// Need to start search from the beginning
|
|
dwCacheId = CACHEID_GETNEXT_GETALL;
|
|
|
|
// unfreeze all the cache nodes that match (aspect, lindex)
|
|
while (lpCacheNode = pOleCache->GetNext(dwAspect, lindex, &dwCacheId))
|
|
if (lpCacheNode->Unfreeze() == NOERROR) // REVIEW, have to check for error?
|
|
pOleCache->m_dwFrozenAspects &= ~dwAspect; // Remove this aspect from the
|
|
// frozen aspects list only if
|
|
// the object is unfrozen
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::SetAdvise, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::SetAdvise
|
|
//
|
|
// Arguments:
|
|
// [aspects] -- the aspects the sink would like to be advised of
|
|
// changes to
|
|
// [advf] -- advise control flags from ADVF_*
|
|
// [pAdvSink] -- the advise sink
|
|
//
|
|
// Returns:
|
|
// E_INVALIDARG
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// Only one advise sink is allowed at a time. If a second one
|
|
// is registered, the first one is released.
|
|
//
|
|
// When cache nodes notify the cache that they have changed,
|
|
// if their (aspect, lindex) match those specified here,
|
|
// OnViewChange notification is sent to the sink.
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_SetAdvise)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::SetAdvise(DWORD aspects,
|
|
DWORD advf, IAdviseSink FAR* pAdvSink)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// if an advise sink is given, check it
|
|
if (pAdvSink != NULL)
|
|
VDATEIFACE(pAdvSink);
|
|
|
|
if (advf & ADVF_NODATA) // ?????
|
|
return ReportResult(0, E_INVALIDARG, 0, 0);
|
|
|
|
// REVIEW: should probably check agains ADVCACHE*
|
|
|
|
// We allow only one view advise at any given time, so Release the
|
|
// old sink.
|
|
if (pOleCache->m_pViewAdvSink != NULL)
|
|
pOleCache->m_pViewAdvSink->Release();
|
|
|
|
// Remember the new sink.
|
|
if ((pOleCache->m_pViewAdvSink = pAdvSink) != NULL) {
|
|
pAdvSink->AddRef();
|
|
|
|
// remember the control flags and requested aspect
|
|
pOleCache->m_advfView = advf;
|
|
pOleCache->m_aspectsView = aspects;
|
|
|
|
// send OnViewChange immediately if ADVF_PRIMEFIRST is done.
|
|
if (advf & ADVF_PRIMEFIRST)
|
|
pOleCache->OnChange(aspects, DEF_LINDEX,
|
|
FALSE /*fDirty*/);
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::GetAdvise, public
|
|
//
|
|
// Synopsis:
|
|
// implement IViewObject::GetAdvise
|
|
//
|
|
// Arguments:
|
|
// [pAspects] -- a pointer to where to return the aspects the
|
|
// current advise sink is interested in
|
|
// [pAdvf] -- a pointer to where to return the advise control
|
|
// flags for the current advise sink
|
|
// [ppAdvSink] -- a pointer to where to return a reference to
|
|
// the current advise sink
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_GetAdvise)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::GetAdvise(DWORD FAR* pAspects,
|
|
DWORD FAR* pAdvf, IAdviseSink FAR* FAR* ppAdvSink)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// validate the parameters
|
|
if (ppAdvSink)
|
|
{
|
|
VDATEPTROUT(ppAdvSink, IAdviseSink FAR *);
|
|
// initialize this for error returns
|
|
*ppAdvSink = NULL;
|
|
}
|
|
if (pAspects)
|
|
VDATEPTROUT(pAspects, DWORD);
|
|
if (pAdvf)
|
|
VDATEPTROUT(pAdvf, DWORD);
|
|
|
|
if (pOleCache->m_pViewAdvSink == NULL)
|
|
{
|
|
// no view advise sink registered
|
|
if (pAspects)
|
|
*pAspects = 0;
|
|
|
|
if (pAdvf)
|
|
*pAdvf = 0;
|
|
|
|
// *ppAdvSink has already been initialized above
|
|
}
|
|
else
|
|
{
|
|
if (pAspects)
|
|
*pAspects = pOleCache->m_aspectsView;
|
|
|
|
if (pAdvf)
|
|
*pAdvf = pOleCache->m_advfView;
|
|
|
|
if (ppAdvSink)
|
|
(*ppAdvSink = pOleCache->m_pViewAdvSink)->AddRef();
|
|
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::CCacheViewImpl::GetExtent, public
|
|
//
|
|
// Synopsis:
|
|
// implements IViewObject::GetExtent
|
|
//
|
|
// Arguments:
|
|
// [dwDrawAspect] -- the aspect for which we'd like the extent
|
|
// [lindex] -- the lindex for which we'd like the extent
|
|
// [ptd] -- pointer to the target device descriptor
|
|
// [lpsizel] -- pointer to where to return the extent
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if no presentation can be found that matches
|
|
// (dwDrawAspect, lindex)
|
|
// REVIEW, anything from IOlePresObj::GetExtent
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 01/12/95 - t-ScottH- added VDATETHREAD( GETPPARENT...)
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
// 11/30/93 - alexgo - fixed bug with GETPPARENT usage
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_CCacheViewImpl_GetExtent)
|
|
STDMETHODIMP NC(COleCache,CCacheViewImpl)::GetExtent(DWORD dwDrawAspect,
|
|
LONG lindex, DVTARGETDEVICE FAR* ptd, LPSIZEL lpsizel)
|
|
{
|
|
COleCache FAR *pOleCache = GETPPARENT(this, COleCache, m_View);
|
|
HRESULT hr;
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(pOleCache);
|
|
VDATEPTROUT(lpsizel, SIZEL);
|
|
|
|
LPOLEPRESOBJECT lpPresObj;
|
|
|
|
M_PROLOG(pOleCache);
|
|
|
|
// validate parameters
|
|
if (!IsValidLINDEX(dwDrawAspect, lindex))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
if (ptd)
|
|
VDATEPTRIN(ptd, DVTARGETDEVICE);
|
|
|
|
// Get presentation object for this aspect, lindex, ptd, if there is one
|
|
if (!(lpPresObj = pOleCache->GetPresObjForDrawing(dwDrawAspect,
|
|
lindex, ptd)))
|
|
return ResultFromScode(OLE_E_BLANK);
|
|
|
|
hr = lpPresObj->GetExtent(dwDrawAspect, lpsizel);
|
|
|
|
// make sure Extents are positive
|
|
lpsizel->cx = LONG_ABS(lpsizel->cx);
|
|
lpsizel->cy = LONG_ABS(lpsizel->cy);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IPersistStorage implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::GetClassID, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersist::GetClassID
|
|
//
|
|
// Arguments:
|
|
// [pClassID] -- pointer to where to return class id
|
|
//
|
|
// Returns:
|
|
// E_NOTIMPL
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup;
|
|
// set result to CLSID_NULL
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_GetClassID)
|
|
STDMETHODIMP COleCache::GetClassID(LPCLSID pClassID)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
VDATEPTROUT(pClassID, LPCLSID);
|
|
*pClassID = m_clsid;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::IsDirty, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::IsDirty
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// S_FALSE, if the object does not need saving
|
|
// S_OK otherwise
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_IsDirty)
|
|
STDMETHODIMP COleCache::IsDirty(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
return((m_uFlag & COLECACHEF_DIRTY) ?
|
|
NOERROR : ResultFromScode(S_FALSE));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::InitNew, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::InitNew
|
|
//
|
|
// Arguments:
|
|
// [pstg] -- the temp storage the object can use until saved
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_InitNew)
|
|
STDMETHODIMP COleCache::InitNew(LPSTORAGE pstg)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
VDATEIFACE(pstg);
|
|
|
|
if (m_pStg)
|
|
return ResultFromScode(CO_E_ALREADYINITIALIZED);
|
|
|
|
m_uFlag |= COLECACHEF_DIRTY;
|
|
|
|
(m_pStg = pstg)->AddRef();
|
|
|
|
// initialize native cachenode, if that's meaningful
|
|
FindObjectFormat(pstg);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Load, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::Load
|
|
//
|
|
// Arguments:
|
|
// [pstg] -- the storage to load from
|
|
//
|
|
// Returns:
|
|
// REVIEW, various Storage errors
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// Presentations are loaded from sequentially numbered
|
|
// streams, stopping at the first one that cannot be found.
|
|
//
|
|
// History:
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_Load)
|
|
STDMETHODIMP COleCache::Load(LPSTORAGE pstg)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
A5_PROLOG(this);
|
|
HRESULT error; // error status so far
|
|
LPSTREAM lpstream; // stream we're loading a presentation from
|
|
LPCACHENODE lpCacheNode; // cache node we're loading
|
|
int iPresStreamNum; // counts through the presentation streams
|
|
OLECHAR szName[
|
|
sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)];
|
|
// used to construct the names of presentation streams
|
|
|
|
VDATEIFACE(pstg);
|
|
|
|
// REVIEW(davepl) Does this error code really make any sense here?
|
|
|
|
if (m_pStg)
|
|
return ResultFromScode(CO_E_ALREADYINITIALIZED);
|
|
|
|
// remember the storage; we'll AddRef this later, if load is successful
|
|
m_pStg = pstg;
|
|
|
|
CLSID clsid;
|
|
|
|
error = ReadClassStg(pstg, &clsid);
|
|
|
|
if ( SUCCEEDED(error) &&
|
|
IsEqualCLSID(clsid, CLSID_PBrush))
|
|
{
|
|
m_uFlag |= COLECACHEF_PBRUSHORMSDRAW | COLECACHEF_FORMATKNOWN;
|
|
m_fUsedToBePBrush = TRUE;
|
|
}
|
|
|
|
|
|
// initialize native cachenode, if that's meaningful
|
|
FindObjectFormat(pstg);
|
|
|
|
if (m_uFlag & COLECACHEF_STATIC)
|
|
{
|
|
UINT uiStatus;
|
|
|
|
// if static object is in old format (i.e. data was written
|
|
// into the OLE_PRESENTATION_STREAM rather than the CONTENTS
|
|
// stream), then convert it to new format.
|
|
error = UtOlePresStmToContentsStm(pstg,
|
|
OLE_PRESENTATION_STREAM, TRUE, &uiStatus);
|
|
|
|
if (error != NOERROR)
|
|
{
|
|
|
|
// if CONTENTS stream doesn't exist or we are not able
|
|
// to create it, then we have a problem.
|
|
|
|
if (uiStatus & CONVERT_NODESTINATION)
|
|
goto errRtn;
|
|
|
|
// By now we know that CONTENTS stream exists.
|
|
// REVIEW, seems to me there could be other errors!
|
|
error = NOERROR;
|
|
}
|
|
|
|
// We know that the data is in the CONTENTS stream. Now let's
|
|
// make sure that it is in the proper format.
|
|
lpCacheNode = UpdateCacheNodeForNative();
|
|
if (lpCacheNode == NULL)
|
|
{
|
|
error = ResultFromScode(E_OUTOFMEMORY);
|
|
goto errRtn;
|
|
|
|
}
|
|
else if ((lpCacheNode->GetPresObj())->IsBlank())
|
|
{
|
|
// Even though CONTENTS stream existed, we are not
|
|
// able to read data from it. The stream format is
|
|
// invalid.
|
|
AssertSz(FALSE, "Format of CONTENTS stream is invalid");
|
|
error = ResultFromScode(DV_E_CLIPFORMAT);
|
|
goto errRtn;
|
|
}
|
|
|
|
}
|
|
else if (m_uFlag & COLECACHEF_FORMATKNOWN)
|
|
{
|
|
UpdateCacheNodeForNative();
|
|
}
|
|
|
|
// prepare to construct presentation stream names in szName
|
|
_xstrcpy(szName, OLE_PRESENTATION_STREAM);
|
|
|
|
// Enumerate the presentation streams and load them one after another.
|
|
// The enumeration stops the first time the attempt to open
|
|
// stream fails.
|
|
for(iPresStreamNum = 0; iPresStreamNum < OLE_MAX_PRES_STREAMS;)
|
|
{
|
|
|
|
if (error = pstg->OpenStream(szName, NULL,
|
|
(STGM_READ | STGM_SHARE_EXCLUSIVE), 0,
|
|
&lpstream))
|
|
{
|
|
// Translate stream does not exist into ok. This
|
|
// means that we don't have any more streams to read.
|
|
if (GetScode(error) == STG_E_FILENOTFOUND)
|
|
error = NOERROR;
|
|
|
|
goto errRtn;
|
|
}
|
|
|
|
// We've opened the stream. Now create a cachenode, so that
|
|
// we can ask it to load itself from the stream.
|
|
if (!(lpCacheNode = new FAR CCacheNode(this)))
|
|
{
|
|
error = ReportResult (0, E_OUTOFMEMORY, 0, 0);
|
|
goto errLoad;
|
|
}
|
|
|
|
// ask the cachenode to load itself from the stream
|
|
if (error = lpCacheNode->Load(lpstream, iPresStreamNum))
|
|
goto errLoad;
|
|
|
|
// add the cache node to the cache list
|
|
if (!Attach(lpCacheNode))
|
|
{
|
|
error = ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
goto errLoad;
|
|
}
|
|
|
|
// release the stream
|
|
lpstream->Release();
|
|
lpstream = NULL;
|
|
|
|
// if the server object is runinng, ask the loaded cached
|
|
// node to connect to the server object
|
|
if (m_pDataObject)
|
|
lpCacheNode->OnRun(m_pDataObject);
|
|
|
|
// Get the next presentation stream name.
|
|
|
|
UtGetPresStreamName(szName, ++iPresStreamNum);
|
|
continue;
|
|
|
|
errLoad:
|
|
// something went wrong while loading the current stream
|
|
if (lpstream)
|
|
lpstream->Release();
|
|
if (lpCacheNode)
|
|
lpCacheNode->Delete();
|
|
break;
|
|
}
|
|
|
|
|
|
errRtn:
|
|
if (error != NOERROR)
|
|
{
|
|
// delete all the cache nodes that we loaded so far.
|
|
DeleteAll();
|
|
m_pStg = NULL;
|
|
}
|
|
else
|
|
{
|
|
// cache is not dirty
|
|
m_uFlag &= ~COLECACHEF_DIRTY;
|
|
|
|
// remember storage we loaded from
|
|
m_pStg->AddRef();
|
|
|
|
// if static object remove all the caches (if there
|
|
// are any) except the ICON cache.
|
|
if (m_uFlag & COLECACHEF_STATIC)
|
|
{
|
|
DWORD dwCacheId = CACHEID_GETNEXT_GETALLBUTNATIVE;
|
|
// REVIEW -- GETNEXT_GETALL
|
|
// REVIEW, if COLECACHEF_STATIC, there doesn't
|
|
// appear to be a native cache node, but I
|
|
// don't understand why
|
|
const FORMATETC FAR *lpforetc;
|
|
|
|
while (lpCacheNode = GetNext(&dwCacheId))
|
|
{
|
|
lpforetc = lpCacheNode->GetFormatEtc();
|
|
if (lpforetc->dwAspect != DVASPECT_ICON)
|
|
Uncache(dwCacheId);
|
|
}
|
|
}
|
|
}
|
|
|
|
RESTORE_A5();
|
|
return error;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Save, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::Save
|
|
//
|
|
// Arguments:
|
|
// [pstgSave] -- the storage to use to save this
|
|
// [fSameAsLoad] -- is this the same storage we loaded from?
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
// All the caches are saved to streams with sequential numeric
|
|
// names. Load takes advantage of this to load until it
|
|
// can't find the next file.
|
|
//
|
|
// History:
|
|
// 11/11/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// $$$
|
|
// Save all the caches to presentation streams numbered sequentially
|
|
|
|
#pragma SEG(COleCache_Save)
|
|
STDMETHODIMP COleCache::Save(LPSTORAGE pstgSave, BOOL fSameAsLoad)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
A5_PROLOG(this);
|
|
HRESULT error = NOERROR; // error status so far
|
|
int iPresStreamNum; // the stream number to use to save
|
|
LPCACHENODE lpCacheNode; // the cache node being saved
|
|
DWORD dwCacheId; // cache id of the cache being saved
|
|
int cntCachesNotSaved;
|
|
|
|
// validate parameters
|
|
VDATEIFACE(pstgSave);
|
|
|
|
// if we're saving to the same place this was loaded from, and
|
|
// the cache isn't dirty, there's no need to rewrite everything out
|
|
if (fSameAsLoad && !(m_uFlag & COLECACHEF_DIRTY))
|
|
{
|
|
error = NOERROR;
|
|
goto errRtn;
|
|
}
|
|
|
|
// Enumerate the cache nodes and ask them to save themselves into
|
|
// presentation streams.
|
|
// REVIEW, what is this extra pass before hand about? It just
|
|
// seems to count the items to save, and do nothing more. I asked
|
|
// SriniK, and he couldn't give me an answer after looking at it.
|
|
// He's promised to add some more comments to the code after he's
|
|
// looked at it some more.
|
|
dwCacheId = CACHEID_GETNEXT_GETALLBUTNATIVE; // REVIEW GETNEXT_GETALL???
|
|
iPresStreamNum = 0;
|
|
cntCachesNotSaved = 0;
|
|
while (lpCacheNode = GetNext(&dwCacheId))
|
|
{
|
|
// Ask the cache node to save itself into this stream
|
|
error = lpCacheNode->Save(pstgSave, fSameAsLoad,
|
|
iPresStreamNum, (dwCacheId == m_dwDrawCacheId),
|
|
TRUE /* save if you have saved before */,
|
|
&cntCachesNotSaved);
|
|
|
|
if ((error != NOERROR) ||
|
|
(++iPresStreamNum >= OLE_MAX_PRES_STREAMS))
|
|
break;
|
|
}
|
|
|
|
if (fSameAsLoad && (cntCachesNotSaved != 0) && (error == NOERROR))
|
|
{
|
|
dwCacheId = CACHEID_GETNEXT_GETALLBUTNATIVE;
|
|
iPresStreamNum = 0;
|
|
|
|
while (lpCacheNode = GetNext(&dwCacheId))
|
|
{
|
|
// Ask the cache node to save itself into this stream
|
|
error = lpCacheNode->Save(pstgSave, fSameAsLoad,
|
|
iPresStreamNum,
|
|
(dwCacheId == m_dwDrawCacheId),
|
|
FALSE /* save if haven't before */,
|
|
NULL);
|
|
|
|
if ((error != NOERROR) ||
|
|
(++iPresStreamNum >=
|
|
OLE_MAX_PRES_STREAMS))
|
|
break;
|
|
}
|
|
}
|
|
|
|
// remove additional presentation streams if any exist
|
|
UtRemoveExtraOlePresStreams(pstgSave, iPresStreamNum);
|
|
|
|
errRtn:
|
|
if (error == NOERROR)
|
|
{
|
|
m_uFlag |= COLECACHEF_NOSCRIBBLEMODE;
|
|
if (fSameAsLoad)
|
|
m_uFlag |= COLECACHEF_SAMEASLOAD;
|
|
else
|
|
m_uFlag &= ~COLECACHEF_SAMEASLOAD;
|
|
}
|
|
|
|
RESTORE_A5();
|
|
return error;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::SaveCompleted, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::SaveCompleted
|
|
//
|
|
// Arguments:
|
|
// [pstgNew] -- NULL, or a pointer to the storage that the current
|
|
// storage operations are being done to, when this is
|
|
// not the same as the storage this object was loaded
|
|
// from (pointer to a "Save as..." destination.)
|
|
//
|
|
// Returns:
|
|
// HRESULT
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_SaveCompleted)
|
|
STDMETHODIMP COleCache::SaveCompleted(LPSTORAGE pstgNew)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
M_PROLOG(this);
|
|
return wSaveCompleted(pstgNew, FALSE /*fDiscardDrawCacheAlso*/);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::wSaveCompleted, private
|
|
//
|
|
// Synopsis:
|
|
// Does work of IPersistStorage::wSaveCompleted, making a new
|
|
// storage the current one, and clearing the dirty flags on
|
|
// the cache nodes and cache if a save was done to the original
|
|
// storage the cache was loaded from.
|
|
//
|
|
// Arguments:
|
|
// [pstgNew] -- pointer to storage saving was done to, if it
|
|
// wasn't done to the original source location.
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
INTERNAL COleCache::wSaveCompleted(LPSTORAGE pstgNew,
|
|
BOOL fDiscardDrawCacheAlso)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
if ((m_uFlag & COLECACHEF_SAMEASLOAD) || pstgNew)
|
|
{
|
|
m_uFlag &= ~COLECACHEF_SAMEASLOAD;
|
|
|
|
// if new storage, make this the current storage
|
|
// REVIEW, this means that DiscardCache() would save to this
|
|
// storage, rather than the original
|
|
if (pstgNew)
|
|
{
|
|
if (m_pStg)
|
|
m_pStg->Release();
|
|
|
|
(m_pStg = pstgNew)->AddRef();
|
|
}
|
|
|
|
if (m_uFlag & COLECACHEF_NOSCRIBBLEMODE)
|
|
{
|
|
DWORD dwCacheId;
|
|
LPCACHENODE lpCacheNode;
|
|
int iStreamNum;
|
|
|
|
// Do special handling for PaintBrush or MSDraw objects.
|
|
if (m_uFlag & COLECACHEF_PBRUSHORMSDRAW)
|
|
UpdateCacheNodeForNative();
|
|
|
|
// clear the dirty flags of all the cache nodes
|
|
for(iStreamNum = 0, dwCacheId =
|
|
CACHEID_GETNEXT_GETALLBUTNATIVE;
|
|
lpCacheNode = GetNext(&dwCacheId);
|
|
++iStreamNum)
|
|
{
|
|
lpCacheNode->SaveCompleted(iStreamNum,
|
|
(!fDiscardDrawCacheAlso &&
|
|
(dwCacheId ==
|
|
m_dwDrawCacheId)));
|
|
}
|
|
|
|
m_uFlag &= ~COLECACHEF_DIRTY;
|
|
}
|
|
}
|
|
|
|
m_uFlag &= ~COLECACHEF_NOSCRIBBLEMODE;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::HandsOffStorage, public
|
|
//
|
|
// Synopsis:
|
|
// implements IPersistStorage::HandsOffStorage
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(COleCache_HandsOffStorage)
|
|
STDMETHODIMP COleCache::HandsOffStorage(void)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
M_PROLOG(this);
|
|
|
|
// if we're holding onto storage, release it
|
|
if (m_pStg)
|
|
{
|
|
m_pStg->Release();
|
|
m_pStg = NULL;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: COleCache::Dump, public (_DEBUG only)
|
|
//
|
|
// Synopsis: return a string containing the contents of the data members
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: [ppsz] - argument
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm: use dbgstream to create a string containing information on the
|
|
// content of data structures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT COleCache::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
unsigned int ui;
|
|
char *pszPrefix;
|
|
char *pszCThreadCheck;
|
|
char *pszCacheListItem;
|
|
char *pszCCacheEnum;
|
|
char *pszADVF;
|
|
char *pszDVASPECT;
|
|
char *pszCLSID;
|
|
char *pszClipFormat;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump(3900);
|
|
|
|
// determine prefix of newlines
|
|
if ( ulFlag & DEB_VERBOSE )
|
|
{
|
|
dstrPrefix << this << " _VB ";
|
|
}
|
|
|
|
// determine indentation prefix for all newlines
|
|
for (i = 0; i < nIndentLevel; i++)
|
|
{
|
|
dstrPrefix << DUMPTAB;
|
|
}
|
|
|
|
pszPrefix = dstrPrefix.str();
|
|
|
|
// put data members in stream
|
|
pszCThreadCheck = DumpCThreadCheck((CThreadCheck *)this, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "CThreadCheck:" << endl;
|
|
dstrDump << pszCThreadCheck;
|
|
CoTaskMemFree(pszCThreadCheck);
|
|
|
|
// these are not included since they are just vtables (also, we would
|
|
// not get the correct values in the debugger extension for the addresses)
|
|
// dstrDump << pszPrefix << "&IUnknown = " << &m_UnkPrivate << endl;
|
|
// dstrDump << pszPrefix << "&IDataObject = " << &m_Data << endl;
|
|
// dstrDump << pszPrefix << "&IViewObject2 = " << &m_View << endl;
|
|
|
|
dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "pIUnknown, pUnkOuter = ";
|
|
if (m_uFlag & COLECACHEF_AGGREGATED)
|
|
{
|
|
dstrDump << "AGGREGATED (" << m_pUnkOuter << ")" << endl;
|
|
}
|
|
else
|
|
{
|
|
dstrDump << "NO AGGREGATION (" << m_pUnkOuter << ")" << endl;
|
|
}
|
|
|
|
dstrDump << pszPrefix << "pIStorage = " << m_pStg << endl;
|
|
|
|
dstrDump << pszPrefix << "COleCache Flags = ";
|
|
if (m_uFlag & COLECACHEF_DIRTY)
|
|
{
|
|
dstrDump << "COLECACHEF_DIRTY ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_NOSCRIBBLEMODE)
|
|
{
|
|
dstrDump << "COLECACHEF_NOSCRIBBLEMODE ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_SAMEASLOAD)
|
|
{
|
|
dstrDump << "COLECACHEF_SAMEASLOAD ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_PBRUSHORMSDRAW)
|
|
{
|
|
dstrDump << "COLECACHEF_PBRUSHORMSDRAW ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_STATIC)
|
|
{
|
|
dstrDump << "COLECACHEF_STATIC ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_FORMATKNOWN)
|
|
{
|
|
dstrDump << "COLECACHEF_FORMATKNOWN ";
|
|
}
|
|
if (m_uFlag & COLECACHEF_AGGREGATED)
|
|
{
|
|
dstrDump << "COLECACHEF_AGGREGATED ";
|
|
}
|
|
// if none of the flags are set!
|
|
if ( !( (m_uFlag & COLECACHEF_DIRTY) |
|
|
(m_uFlag & COLECACHEF_NOSCRIBBLEMODE) |
|
|
(m_uFlag & COLECACHEF_SAMEASLOAD) |
|
|
(m_uFlag & COLECACHEF_PBRUSHORMSDRAW) |
|
|
(m_uFlag & COLECACHEF_STATIC) |
|
|
(m_uFlag & COLECACHEF_FORMATKNOWN) |
|
|
(m_uFlag & COLECACHEF_AGGREGATED)))
|
|
{
|
|
dstrDump << "No FLAGS SET! ";
|
|
}
|
|
dstrDump << "(" << (void *)m_uFlag << ")" << endl;
|
|
|
|
dstrDump << pszPrefix << "Size of CacheList(max) = " << m_uCacheNodeMax << endl;
|
|
|
|
dstrDump << pszPrefix << "No. of elements in CacheList = " << m_uCacheNodeCnt << endl;
|
|
|
|
// the array could be sparse
|
|
if (m_uCacheNodeCnt != 0)
|
|
{
|
|
for (ui = 0; ui < m_uCacheNodeMax; ui++)
|
|
{
|
|
pszCacheListItem = DumpCACHELIST_ITEM(&m_pCacheList[ui], ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "CacheList Item [" << ui << "]:" << endl;
|
|
dstrDump << pszCacheListItem;
|
|
CoTaskMemFree(pszCacheListItem);
|
|
}
|
|
}
|
|
|
|
if (m_pCacheEnum != NULL)
|
|
{
|
|
dstrDump << pszPrefix << "CCacheEnum:" << endl;
|
|
pszCCacheEnum = DumpCCacheEnum(m_pCacheEnum, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszCCacheEnum;
|
|
CoTaskMemFree(pszCCacheEnum);
|
|
}
|
|
else
|
|
{
|
|
dstrDump << pszPrefix << "CCacheEnum: = " << m_pCacheEnum << endl;
|
|
}
|
|
|
|
dstrDump << pszPrefix << "pIAdviseSink (View advise) = " << m_pViewAdvSink << endl;
|
|
|
|
pszADVF = DumpADVFFlags(m_advfView);
|
|
dstrDump << pszPrefix << "View Advise Flags = " << pszADVF << endl;
|
|
CoTaskMemFree(pszADVF);
|
|
|
|
pszDVASPECT = DumpDVASPECTFlags(m_aspectsView);
|
|
dstrDump << pszPrefix << "Aspect Flags = " << pszDVASPECT << endl;
|
|
CoTaskMemFree(pszDVASPECT);
|
|
|
|
dstrDump << pszPrefix << "Drawing Cache ID = " << m_dwDrawCacheId << endl;
|
|
|
|
dstrDump << pszPrefix << "Count of Frozen Aspects = " << m_dwFrozenAspects<< endl;
|
|
|
|
dstrDump << pszPrefix << "pIDataObject = " << m_pDataObject << endl;
|
|
|
|
pszCLSID = DumpCLSID(m_clsid);
|
|
dstrDump << pszPrefix << "CLSID = " << pszCLSID << endl;
|
|
CoTaskMemFree(pszCLSID);
|
|
|
|
pszClipFormat = DumpCLIPFORMAT(m_cfFormat);
|
|
dstrDump << pszPrefix << "Clipboard Format = " << pszClipFormat << endl;
|
|
CoTaskMemFree(pszClipFormat);
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCOleCache, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the COleCache::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pOC] - pointer to COleCache
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: character array of structure dump or error (null terminated)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCOleCache(COleCache *pOC, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pOC == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pOC->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
// CCacheEnumFormatEtc implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::CCacheEnumFormatEtc, public
|
|
//
|
|
// Synopsis:
|
|
// constructor
|
|
//
|
|
// sets reference count to 1
|
|
//
|
|
// Arguments:
|
|
// [pIES] -- IEnumSTATDATA enumerator that this IEnumFORMATETC
|
|
// enumerator will be based on; may be NULL
|
|
//
|
|
// Notes:
|
|
// We allow the underlying IEnumSTATDATA enumerator to be null
|
|
// for the case where an IEnumSTATDATA enumerator refuses to
|
|
// be cloned, and yet we want to clone this IEnumFORMATETC.
|
|
// When the underlying enumerator is NULL, we always return
|
|
// OLE_E_BLANK, and treat this enumerator as empty; taking the
|
|
// cache's IEnumSTATDATA as an example worthy of copying.
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_ctor)
|
|
CCacheEnumFormatEtc::CCacheEnumFormatEtc(IEnumSTATDATA FAR *pIES)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
m_refs = 1;
|
|
if (m_pIES = pIES)
|
|
pIES->AddRef();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::~CCacheEnumFormatEtc, private
|
|
//
|
|
// Synopsis:
|
|
// destructor
|
|
//
|
|
// dissociates this enumerator from the cache, if it still exists
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CCacheEnumFormatEtc::~CCacheEnumFormatEtc()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
if (m_pIES)
|
|
m_pIES->Release();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_QueryInterface)
|
|
STDMETHODIMP CCacheEnumFormatEtc::QueryInterface(REFIID riid, LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IEnumFORMATETC))
|
|
*ppv = (void FAR *)(IEnumFORMATETC FAR *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
AddRef();
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_AddRef)
|
|
STDMETHODIMP_(ULONG) CCacheEnumFormatEtc::AddRef(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return m_refs++;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_Release)
|
|
STDMETHODIMP_(ULONG) CCacheEnumFormatEtc::Release(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
if (--m_refs == 0)
|
|
{
|
|
delete this;
|
|
return(0);
|
|
}
|
|
|
|
return m_refs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::Next, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumFORMATETC::Next
|
|
//
|
|
// Arguments:
|
|
// [celt] -- the number of items the caller would like returned
|
|
// [rgelt] -- a pointer to where the items may be returned as
|
|
// an array
|
|
// [pceltFetched] -- a pointer to where to place the count of
|
|
// the actual number of items returned. May be NULL
|
|
// if the caller is not interested in this number
|
|
//
|
|
// Returns:
|
|
// S_OK, if exactly the number of items requested is being
|
|
// returned
|
|
// S_FALSE, if fewer items than the number requested are being
|
|
// returned
|
|
// OLE_E_BLANK, if the ole cache associated with this
|
|
// enumerator has been destroyed
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
// 08/23/94 - Davepl - enforced enumerator count OUT param
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_Next)
|
|
STDMETHODIMP CCacheEnumFormatEtc::Next(ULONG celt, FORMATETC FAR* rgelt,
|
|
ULONG FAR* pceltFetched)
|
|
{
|
|
STATDATA sd; // used as intermediary for other enumerator
|
|
ULONG cnt; // count of number of elements fetched so far
|
|
ULONG fc; // FetchCount
|
|
HRESULT hr;
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
VDATEPTROUT(rgelt, FORMATETC);
|
|
|
|
// Enumerators require that when more than one element is being fetched,
|
|
// a valid OUT ulong is provided to indicate the count of elts returned
|
|
// 16-bit didn't enforce this, so we InWow-special-case it.
|
|
|
|
if (!IsWOWThread())
|
|
{
|
|
if ( celt > 1 && NULL == pceltFetched)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
// if no other enumerator, can't comply
|
|
if (!m_pIES)
|
|
return(ReportResult(0, OLE_E_BLANK, 0, 0)); // REVIEW, scode
|
|
|
|
// iterate until we've fetched as many items as requested
|
|
for(cnt = 0; cnt < celt; ++rgelt, ++cnt)
|
|
{
|
|
hr = m_pIES->Next(1, &sd, &fc);
|
|
|
|
if (fc != 1)
|
|
break;
|
|
|
|
// copy the relevant information
|
|
*rgelt = sd.formatetc;
|
|
Assert(rgelt->ptd == NULL);
|
|
|
|
// release the advise sink in the STATDATA
|
|
if (sd.pAdvSink)
|
|
sd.pAdvSink->Release();
|
|
// REVIEW, as this is done here, we are using the IEnumSTATDATA
|
|
// enumerator to implement this one. The IES enumerator does
|
|
// more work than this one, namely this AddRef'ing of the
|
|
// advise sink, which might actually be remoted. We're doing
|
|
// this this way because that one already exists, and we're
|
|
// trying to disturb the code as little as possible. A
|
|
// performance optimization that can be done later on is to
|
|
// switch the code between the two enumerators, (or to factor
|
|
// out the guts of the IES one,) so that we don't do the
|
|
// extra work for this one, but only for the IES one when it
|
|
// is necessary.
|
|
}
|
|
|
|
// if a count of returned elements was requested, copy it
|
|
if (pceltFetched)
|
|
*pceltFetched = cnt;
|
|
|
|
// if we fetched as many items as requested, return
|
|
if (cnt == celt)
|
|
return NOERROR;
|
|
|
|
// zero out the unused array elements
|
|
for(; cnt < celt; ++rgelt, ++cnt)
|
|
{
|
|
rgelt->cfFormat = 0;
|
|
}
|
|
|
|
return(ReportResult(0, S_FALSE, 0, 0));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Skip, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumFORMATETC::Skip
|
|
//
|
|
// Arguments:
|
|
// [celt] -- count of the number of items in the enumeration to
|
|
// skip over
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated ole cache has been destroyed
|
|
// S_FALSE, if there were fewer items left in the enumeration
|
|
// than we were to skip
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_Skip)
|
|
STDMETHODIMP CCacheEnumFormatEtc::Skip(ULONG celt)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// if no other enumerator, can't comply
|
|
if (!m_pIES)
|
|
return(ReportResult(0, OLE_E_BLANK, 0, 0)); // REVIEW, scode
|
|
|
|
return(m_pIES->Skip(celt));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::Reset, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumFORMATETC::Reset
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated ole cache has been destroyed
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_Reset)
|
|
STDMETHODIMP CCacheEnumFormatEtc::Reset(void)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// if no other enumerator, can't comply
|
|
if (!m_pIES)
|
|
return(ReportResult(0, OLE_E_BLANK, 0, 0)); // REVIEW, scode
|
|
|
|
return(m_pIES->Reset());
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnumFormatEtc::Clone, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumFORMATETC::Clone
|
|
//
|
|
// Arguments:
|
|
// [ppenum] -- pointer to where to return the created enumerator
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated cache has been destroyed;
|
|
// no enumerator is created in this case
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 02/08/94 - ChrisWe - created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CCacheEnumFormatEtc_Clone)
|
|
STDMETHODIMP CCacheEnumFormatEtc::Clone(LPENUMFORMATETC FAR* ppenum)
|
|
{
|
|
IEnumSTATDATA FAR *pIES; // the IEnumSTATDATA to base the clone on
|
|
HRESULT hr;
|
|
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// obtain an IEnumSTATDATA to base the cloned IEnumFORMATETC on
|
|
if (!m_pIES)
|
|
pIES = NULL;
|
|
else
|
|
hr = m_pIES->Clone(&pIES);
|
|
|
|
// create the new IEnumFORMATETC
|
|
*ppenum = new CCacheEnumFormatEtc(pIES);
|
|
|
|
// release the IEnumSTATDATA, if we've got one
|
|
if (pIES)
|
|
pIES->Release();
|
|
|
|
// if no new enumerator, we ran out of memory
|
|
if (!*ppenum)
|
|
return(ReportResult(0, E_OUTOFMEMORY, 0, 0));
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CCacheEnumFormatEtc::Dump, public (_DEBUG only)
|
|
//
|
|
// Synopsis: return a string containing the contents of the data members
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: [ppsz] - argument
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm: use dbgstream to create a string containing information on the
|
|
// content of data structures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CCacheEnumFormatEtc::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszCThreadCheck;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump;
|
|
|
|
// determine prefix of newlines
|
|
if ( ulFlag & DEB_VERBOSE )
|
|
{
|
|
dstrPrefix << this << " _VB ";
|
|
}
|
|
|
|
// determine indentation prefix for all newlines
|
|
for (i = 0; i < nIndentLevel; i++)
|
|
{
|
|
dstrPrefix << DUMPTAB;
|
|
}
|
|
|
|
pszPrefix = dstrPrefix.str();
|
|
|
|
// put data members in stream
|
|
pszCThreadCheck = DumpCThreadCheck((CThreadCheck *)this, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "CThreadCheck:" << endl;
|
|
dstrDump << pszCThreadCheck;
|
|
CoTaskMemFree(pszCThreadCheck);
|
|
|
|
dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "pIEnumSTATDATA = " << m_pIES << endl;
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCCacheEnumFormatEtc, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CCacheEnumFormatEtc::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pCEFE] - pointer to CCacheEnumFormatEtc
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: character array of structure dump or error (null terminated)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCCacheEnumFormatEtc(CCacheEnumFormatEtc *pCEFE, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pCEFE == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pCEFE->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
// CCacheEnum implementation
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::CCacheEnum, public
|
|
//
|
|
// Synopsis:
|
|
// constructor
|
|
//
|
|
// sets reference count to 1
|
|
//
|
|
// Arguments:
|
|
// [pOleCache] -- the instance of COleCache this is an
|
|
// enumerator for; may be NULL
|
|
// [dwCurrent] -- id of the item in the cache that the enumerator
|
|
// is on
|
|
// [fDib] -- act as if the last item seen is a CF_DIB cache item
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_ctor)
|
|
CCacheEnum::CCacheEnum(COleCache FAR* pOleCache, ULONG ulCurrent, BOOL fDib)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
m_ulCurCacheId = ulCurrent;
|
|
m_refs = 1;
|
|
m_pOleCache = pOleCache; // remember the COleCache object pointer
|
|
// NOTE: no ref count
|
|
m_pNextCacheEnum = NULL;
|
|
m_fDib = fDib;
|
|
|
|
// if there's a cache, add this enumerator to the head of the
|
|
// enumerator list
|
|
if (pOleCache)
|
|
{
|
|
m_pNextCacheEnum = pOleCache->m_pCacheEnum;
|
|
pOleCache->m_pCacheEnum = this;
|
|
}
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::~CCacheEnum, private
|
|
//
|
|
// Synopsis:
|
|
// destructor
|
|
//
|
|
// dissociates this enumerator from the cache, if it still exists
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CCacheEnum::~CCacheEnum()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// If there's a cache, ask it to remove us from its enumerator list
|
|
if (m_pOleCache)
|
|
m_pOleCache->DetachCacheEnum(this);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::OnOleCacheDelete, private
|
|
//
|
|
// Synopsis:
|
|
// Indicates that the cache the enumerator was associated
|
|
// with has been destroyed. The enumerator no longer returns
|
|
// anything but error values.
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_OnOleCacheDelete)
|
|
// COleCache calls this when it is getting deleted
|
|
INTERNAL_(void) CCacheEnum::OnOleCacheDelete(void)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
m_pOleCache = NULL; // NOTE: no ref count
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to where to return the requested interface
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, if the requested interface is not available
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_QueryInterface)
|
|
STDMETHODIMP CCacheEnum::QueryInterface(REFIID riid, LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
|
IsEqualIID(riid, IID_IEnumSTATDATA))
|
|
*ppv = (void FAR *)(IEnumSTATDATA FAR *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
AddRef();
|
|
return(NOERROR);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_AddRef)
|
|
STDMETHODIMP_(ULONG) CCacheEnum::AddRef()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
return m_refs++;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// the object's reference count
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_Release)
|
|
STDMETHODIMP_(ULONG) CCacheEnum::Release()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
if (--m_refs == 0)
|
|
{
|
|
delete this;
|
|
return(0);
|
|
}
|
|
|
|
return m_refs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::Next, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Next
|
|
//
|
|
// Arguments:
|
|
// [celt] -- the number of items the caller would like returned
|
|
// [rgelt] -- a pointer to where the items may be returned as
|
|
// an array
|
|
// [pceltFetched] -- a pointer to where to place the count of
|
|
// the actual number of items returned. May be NULL
|
|
// if the caller is not interested in this number
|
|
//
|
|
// Returns:
|
|
// S_OK, if exactly the number of items requested is being
|
|
// returned
|
|
// S_FALSE, if fewer items than the number requested are being
|
|
// returned
|
|
// OLE_E_BLANK, if the ole cache associated with this
|
|
// enumerator has been destroyed
|
|
//
|
|
// Notes:
|
|
// Immediately after any CF_DIB item is returned, a CF_BITMAP
|
|
// item is synthesized for the same cache item, and returned next.
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup; use pointer
|
|
// aritmetic to speed array accesses
|
|
// 08/08/94 AlexT Handle case where cache node is uncached
|
|
// during enumeration
|
|
// 08/23/94 - Davepl - enforced enumerator count OUT param
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_Next)
|
|
STDMETHODIMP CCacheEnum::Next(ULONG celt, STATDATA FAR* rgelt,
|
|
ULONG FAR* pceltFetched)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// Enumerators require that when more than one element is being fetched,
|
|
// a valid OUT ulong is provided to indicate the count of elts returned
|
|
// 16-bit didn't enforce this, so we InWow-special-case it.
|
|
|
|
if (celt > 1 && NULL == pceltFetched && !IsWOWThread())
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ULONG cnt; // count of number of elements fetched so far
|
|
LPCACHENODE lpCacheNode; // pointer to the current cache node
|
|
|
|
// if no cache, can't run enumerator
|
|
if (!m_pOleCache)
|
|
return ReportResult (0, OLE_E_BLANK, 0, 0); // REVIEW, scode
|
|
|
|
// iterate until we've fetched as many items as requested
|
|
cnt = 0;
|
|
while (cnt < celt)
|
|
{
|
|
if (!m_fDib)
|
|
{
|
|
// If we're here, the last returned item was NOT
|
|
// CF_DIB
|
|
|
|
// Get next valid cache node from cache node list
|
|
lpCacheNode = m_pOleCache->GetNext(&m_ulCurCacheId);
|
|
if (NULL == lpCacheNode)
|
|
{
|
|
// No more nodes to process
|
|
break;
|
|
}
|
|
|
|
// Ask the CacheNode itself for the statdata.
|
|
lpCacheNode->CopyStatData(rgelt);
|
|
|
|
// if this item is of format CF_DIB, then on the
|
|
// next iteration, return a synthesized CF_BITMAP for
|
|
// the same item
|
|
if (CF_DIB == rgelt->formatetc.cfFormat)
|
|
{
|
|
m_fDib = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The last item returned was a CF_DIB
|
|
// now we synthesize a CF_BITMAP item for the same
|
|
// cache item
|
|
|
|
m_fDib = FALSE;
|
|
|
|
// get the *current* cache node
|
|
lpCacheNode = m_pOleCache->GetAt(m_ulCurCacheId);
|
|
|
|
if (NULL == lpCacheNode ||
|
|
CF_DIB != lpCacheNode->GetFormatEtc()->cfFormat)
|
|
{
|
|
// The node no longer exists (or is the wrong
|
|
// type) - caller probably called Uncache, so
|
|
// we'll just get the next node
|
|
continue;
|
|
}
|
|
|
|
// Ask the CacheNode for the statdata.
|
|
lpCacheNode->CopyStatData(rgelt);
|
|
rgelt->formatetc.cfFormat = CF_BITMAP;
|
|
rgelt->formatetc.tymed = TYMED_GDI;
|
|
}
|
|
|
|
// return the connection id
|
|
rgelt->dwConnection = m_ulCurCacheId;
|
|
|
|
cnt++;
|
|
rgelt++;
|
|
}
|
|
|
|
// if a count of returned elements was requested, copy it
|
|
if (pceltFetched)
|
|
*pceltFetched = cnt;
|
|
|
|
// if we fetched as many items as requested, return
|
|
if (cnt == celt)
|
|
return NOERROR;
|
|
|
|
// zero out the unused array elements
|
|
for(; cnt < celt; ++rgelt, ++cnt)
|
|
{
|
|
rgelt->dwConnection = 0;
|
|
rgelt->pAdvSink = NULL;
|
|
}
|
|
|
|
return ReportResult(0, S_FALSE, 0, 0);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// COleCache::Skip, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Skip
|
|
//
|
|
// Arguments:
|
|
// [celt] -- count of the number of items in the enumeration to
|
|
// skip over
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated ole cache has been destroyed
|
|
// S_FALSE, if there were fewer items left in the enumeration
|
|
// than we were to skip
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// REVIEW, Skipped would-have-been-synthesized CF_BITMAP items
|
|
// are not counted towards the skip count
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup;
|
|
// fixed error return for case where there are fewer items
|
|
// in the enumeration than we are to skip
|
|
// 08/08/94 AlexT Synchronize with ::Next implementation
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_Skip)
|
|
STDMETHODIMP CCacheEnum::Skip(ULONG celt)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
LPCACHENODE lpCacheNode; // pointer to the current cache node
|
|
|
|
// if there's no cache, there's nothing we can do
|
|
if (!m_pOleCache)
|
|
return ReportResult (0, OLE_E_BLANK, 0, 0);
|
|
|
|
for (NULL; celt > 0; celt--)
|
|
{
|
|
if (m_fDib)
|
|
{
|
|
// The last node enumerated (or skipped) was CF_DIB;
|
|
// if that node still exists, we'll "skip" the fake
|
|
// CF_BITMAP node we would have generated.
|
|
|
|
m_fDib = FALSE;
|
|
|
|
// get the *current* cache node
|
|
lpCacheNode = m_pOleCache->GetAt(m_ulCurCacheId);
|
|
|
|
if (NULL != lpCacheNode &&
|
|
CF_DIB == lpCacheNode->GetFormatEtc()->cfFormat)
|
|
{
|
|
// The current cache node exists and it is of type
|
|
// CF_DIB, which means we've "found" a node to
|
|
// skip (in this case it's our fake CF_BITMAP that
|
|
// we would have generated from CF_DIB). The
|
|
// continue statement will execute the celt--
|
|
// in the for loop above
|
|
|
|
continue;
|
|
}
|
|
|
|
// if there was no cache node at m_ulCurCacheId, or
|
|
// the format was not CF_DIB that means the original
|
|
// node disappeared while we were enumerating
|
|
// (the caller may have called Uncache); we just
|
|
// fall through and pick up the next node
|
|
}
|
|
|
|
// If we're here, the last returned item was NOT
|
|
// CF_DIB
|
|
|
|
// Get next valid cache node from cache node list
|
|
lpCacheNode = m_pOleCache->GetNext(&m_ulCurCacheId);
|
|
if (NULL == lpCacheNode)
|
|
{
|
|
return ReportResult (0, S_FALSE, 0, 0);
|
|
}
|
|
|
|
// if this item is of format CF_DIB, then on the
|
|
// next iteration, return a synthesized CF_BITMAP for
|
|
// the same item
|
|
if (CF_DIB == lpCacheNode->GetFormatEtc()->cfFormat)
|
|
{
|
|
m_fDib = TRUE;
|
|
}
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::Reset, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Reset
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated ole cache has been destroyed
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_Reset)
|
|
STDMETHODIMP CCacheEnum::Reset(void)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// if there's no cache, there's nothing to do
|
|
if (!m_pOleCache)
|
|
return ReportResult (0, OLE_E_BLANK, 0, 0);
|
|
// REVIEW, shouldn't there be a better error code for this?
|
|
|
|
// don't need to return a synthesized CF_BITMAP next
|
|
if (m_fDib)
|
|
m_fDib = FALSE;
|
|
|
|
// begin scanning the cache from the beginning again
|
|
m_ulCurCacheId = CACHEID_GETNEXT_GETALL;
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CCacheEnum::Clone, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Clone
|
|
//
|
|
// Arguments:
|
|
// [ppenum] -- pointer to where to return the created enumerator
|
|
//
|
|
// Returns:
|
|
// OLE_E_BLANK, if the associated cache has been destroyed;
|
|
// no enumerator is created in this case
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/28/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CCacheEnum_Clone)
|
|
STDMETHODIMP CCacheEnum::Clone(LPENUMSTATDATA FAR* ppenum)
|
|
{
|
|
VDATEHEAP();
|
|
VDATETHREAD(this);
|
|
|
|
// if there's no cache, don't create enumerator
|
|
if (!m_pOleCache)
|
|
{
|
|
*ppenum = NULL;
|
|
return ReportResult (0, OLE_E_BLANK, 0, 0);
|
|
}
|
|
|
|
// pass our state (pointer to COleCache and current item id) to the
|
|
// constuctor to get a clone.
|
|
if (!(*ppenum = (LPENUMSTATDATA) new CCacheEnum(m_pOleCache,
|
|
m_ulCurCacheId, m_fDib)))
|
|
return ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
INTERNAL IsSameAsObjectFormatEtc(LPFORMATETC lpforetc, CLIPFORMAT cfFormat)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// this function only checks for DVASPECT_CONTENT
|
|
if (lpforetc->dwAspect != DVASPECT_CONTENT)
|
|
return ResultFromScode(DV_E_DVASPECT);
|
|
|
|
// is the lindex right?
|
|
if (lpforetc->lindex != DEF_LINDEX)
|
|
return ResultFromScode(DV_E_LINDEX);
|
|
|
|
// if there's no format, set it to CF_METAFILEPICT or CF_DIB
|
|
if (lpforetc->cfFormat == NULL)
|
|
{
|
|
lpforetc->cfFormat = cfFormat;
|
|
|
|
if (lpforetc->cfFormat == CF_METAFILEPICT)
|
|
{
|
|
lpforetc->tymed = TYMED_MFPICT;
|
|
}
|
|
#ifdef FULL_EMF_SUPPORT
|
|
else if (lpforetc->cfFormat == CF_ENHMETAFILE)
|
|
{
|
|
lpforetc->tymed = TYMED_ENHMF;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
lpforetc->tymed = TYMED_HGLOBAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if it's CF_BITMAP, change it to CF_DIB
|
|
BITMAP_TO_DIB((*lpforetc));
|
|
|
|
// compare the two formats
|
|
if (lpforetc->cfFormat != cfFormat)
|
|
return ResultFromScode(DV_E_CLIPFORMAT);
|
|
}
|
|
|
|
// if we got here, the two formats are [interchangeable?]
|
|
return NOERROR;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CCacheEnum::Dump, public (_DEBUG only)
|
|
//
|
|
// Synopsis: return a string containing the contents of the data members
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [ppszDump] - an out pointer to a null terminated character array
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies: [ppsz] - argument
|
|
//
|
|
// Derivation:
|
|
//
|
|
// Algorithm: use dbgstream to create a string containing information on the
|
|
// content of data structures
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CCacheEnum::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszCThreadCheck;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump;
|
|
|
|
// determine prefix of newlines
|
|
if ( ulFlag & DEB_VERBOSE )
|
|
{
|
|
dstrPrefix << this << " _VB ";
|
|
}
|
|
|
|
// determine indentation prefix for all newlines
|
|
for (i = 0; i < nIndentLevel; i++)
|
|
{
|
|
dstrPrefix << DUMPTAB;
|
|
}
|
|
|
|
pszPrefix = dstrPrefix.str();
|
|
|
|
// put data members in stream
|
|
pszCThreadCheck = DumpCThreadCheck((CThreadCheck *)this, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "CThreadCheck:" << endl;
|
|
dstrDump << pszCThreadCheck;
|
|
CoTaskMemFree(pszCThreadCheck);
|
|
|
|
dstrDump << pszPrefix << "No. of References = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "Last returned item CF_DIB?= ";
|
|
if (m_fDib == TRUE)
|
|
{
|
|
dstrDump << "TRUE" << endl;
|
|
}
|
|
else
|
|
{
|
|
dstrDump << "FALSE" << endl;
|
|
}
|
|
|
|
dstrDump << pszPrefix << "Current cache ID enum = " << m_ulCurCacheId << endl;
|
|
|
|
// we don't want to dump the COleCache due to recursion
|
|
dstrDump << pszPrefix << "pCOleCache = " << m_pOleCache << endl;
|
|
|
|
dstrDump << pszPrefix << "pNext CCacheEnum = " << m_pNextCacheEnum << endl;
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCCacheEnum, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CCacheEnum::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pCE] - pointer to CCacheEnum
|
|
// [ulFlag] - flag determining prefix of all newlines of the
|
|
// out character array (default is 0 - no prefix)
|
|
// [nIndentLevel] - will add a indent prefix after the other prefix
|
|
// for ALL newlines (including those with no prefix)
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: character array of structure dump or error (null terminated)
|
|
//
|
|
// Signals:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// Algorithm:
|
|
//
|
|
// History: dd-mmm-yy Author Comment
|
|
// 31-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCCacheEnum(CCacheEnum *pCE, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pCE == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pCE->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|