NT4/private/ole32/ole232/cache/cachenod.cpp
2020-09-30 17:12:29 +02:00

2445 lines
60 KiB
C++

//+----------------------------------------------------------------------------
//
// File:
// cachenod.cpp
//
// Contents:
//
// Classes:
// CCacheNode
//
// Functions:
//
// History:
// 31-Jan-95 t-ScottH added Dump method for CCacheNode
// added DumpCCacheNode API
// initialize m_dwPresBitsPos in CCacheNode
// ::Initialize(...)
// added m_dwPresFlag private data member to
// keep track of type of IOlePresObj
// (CGenObject|CMfObject|CEMfObject)
// 23-Feb-94 alexgo added call tracing
// 24-Jan-94 alexgo first pass at converting to Cairo-style
// memory allocation
// 01/11/94 - AlexGo - added VDATEHEAP macros to every function
// and method
// 12/07/93 - ChrisWe - make default params to StSetSize explicit
// 11/22/93 - ChrisWe - replace overloaded ==, != with
// IsEqualIID and IsEqualCLSID
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#include <le2int.h>
#pragma SEG(cachenod)
#include <olepres.h>
#include <olecache.h>
#include <cachenod.h>
#include <mf.h>
#include <emf.h>
#include <gen.h>
#ifdef _DEBUG
#include <dbgdump.h>
#endif // _DEBUG
NAME_SEG(Cachenod)
ASSERTDATA
// declare local function
#pragma SEG(wGetData)
INTERNAL wGetData(LPDATAOBJECT lpSrcDataObj, LPFORMATETC lpforetc,
LPSTGMEDIUM lpmedium);
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Initialize, private
//
// Synopsis:
// Routine used by the CCacheNode constructors to do common
// initialization.
//
// Arguments:
// [advf] -- ADVF flag
// [pOleCache] -- COleCache this cache node belongs to
//
// Notes:
// [pOleCache] is not reference counted; the cache node is
// considered to be a part of the implementation of COleCache,
// and is owned by COleCache.
//
// History:
// 13-Feb-95 t-ScottH initialize m_dwPresBitsPos and new
// data member m_dwPresFlag
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Initialize)
INTERNAL_(void) CCacheNode::Initialize(DWORD advf, COleCache FAR* pOleCache)
{
VDATEHEAP();
m_refs = 1; // there is one reference to this
// initialize other values
m_advf = advf;
m_usFlag = CCACHENODEF_DIRTY;
m_iStreamNum = OLE_INVALID_STREAMNUM;
m_dwPresBitsPos = 0;
m_dwAdvConnId = NULL;
m_pOleCache = pOleCache;
m_pDataObj = NULL;
m_pPresObj = NULL;
m_pPresObjAfterFreeze = NULL;
#ifdef _DEBUG
m_dwPresFlag = 0;
#endif // _DEBUG
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Uninitialize, private
//
// Synopsis:
// Frees all resources associated with the cache node. Dissociates
// the cache node from its owning m_pOleCache, in preparation for
// destruction.
//
// Arguments:
// none
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
INTERNAL_(void) CCacheNode::Uninitialize()
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Uninitialize ( )\n",
this ));
// This will tear down any advisory connections
OnStop();
// Destroy the presentation object if we have one
if (m_pPresObj)
{
m_pPresObj->Release();
m_pPresObj = NULL;
}
// Destroy the presentation object that we had created after freeze,
// if there is one
if (m_pPresObjAfterFreeze)
{
m_pPresObjAfterFreeze->Release();
m_pPresObjAfterFreeze = NULL;
}
// delete the ptd if it is non-null
if (m_foretc.ptd)
{
PubMemFree(m_foretc.ptd);
m_foretc.ptd = NULL;
}
// Make a note that we are not owned by COleCache.
m_pOleCache = NULL; // NOTE: no ref count
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Uninitialize ( )\n",
this));
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::CCacheNode, public
//
// Synopsis:
// constructor - use this constructor when the cache node is
// to be loaded later
//
// Arguments:
// [pOleCache] -- pointer to the COleCache that owns this node
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_ctor)
CCacheNode::CCacheNode(COleCache FAR* pOleCache)
{
VDATEHEAP();
m_foretc.cfFormat = NULL;
m_foretc.ptd = NULL;
m_foretc.dwAspect = NULL;
m_foretc.lindex = DEF_LINDEX;
m_foretc.tymed = TYMED_HGLOBAL;
Initialize((DWORD)0, pOleCache);
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::CCacheNode, public
//
// Synopsis:
// constructor - use this constructor when all the data to
// initialize the cache node is available now
//
// Arguments:
// [lpFormatetc] - the format for the presentation that this
// cache node will hold
// [advf] - the advise control flags, from ADVF_*
// [pOleCache] -- pointer to the COleCache that owns this node
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
CCacheNode::CCacheNode(LPFORMATETC lpFormatetc, DWORD advf,
COleCache FAR* pOleCache)
{
VDATEHEAP();
UtCopyFormatEtc(lpFormatetc, &m_foretc);
Initialize(advf, pOleCache);
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::~CCacheNode, private
//
// Synopsis:
// destructor
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
CCacheNode::~CCacheNode()
{
VDATEHEAP();
// if this is still associated with a COleCache, free all resources
if (m_pOleCache != NULL)
Uninitialize();
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::GetPresObj, public
//
// Synopsis:
// get a pointer to the existing presentation object, if there
// is one.
//
// Arguments:
// none
//
// Returns:
// pointer to the current presentation object, if there is one,
// or NULL
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_GetPresObj)
INTERNAL_(LPOLEPRESOBJECT) CCacheNode::GetPresObj(void)
{
VDATEHEAP();
return m_pPresObj; // NON ref counted pointer
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::GetFormatEtc, public
//
// Synopsis:
// Returns a pointer to the format description for the cache node.
// The pointed to FORMATETC cannot be changed.
//
// Arguments:
// none
//
// Returns:
// A pointer to the constant FORMATETC for this cache node.
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
// changed to return const pointer to avoid struct copy
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_GetFormatEtc)
INTERNAL_(const FORMATETC FAR *) CCacheNode::GetFormatEtc(void)
{
VDATEHEAP();
// no copy of ptd is made; the caller can copy if necessary
return((const FORMATETC FAR *)&m_foretc);
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::CopyStatData, public
//
// Synopsis:
// Copies the stat data for this cache node, but does not include
// the advise sink
//
// Arguments:
// [lpStatData] -- pointer to where to copy the stat data to
//
// Returns:
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
// renamed from GetStatData to indicate copying function
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_CopyStatData)
INTERNAL_(void) CCacheNode::CopyStatData(STATDATA FAR* lpStatData)
{
VDATEHEAP();
// Here the ptd gets copied.
UtCopyFormatEtc(&m_foretc, &(lpStatData->formatetc));
// REVIEW, shouldn't we echo the UtCopy... return code as a return here?
lpStatData->advf = m_advf;
lpStatData->pAdvSink = NULL;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::GetAdvf, public
//
// Synopsis:
// return the advise control flag for the cache node
//
// Arguments:
// none
//
// Returns:
// the advf flags for the cache node in a DWORD
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_GetAdvf)
INTERNAL_(DWORD) CCacheNode::GetAdvf(void)
{
VDATEHEAP();
return m_advf;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::SaveCompleted, public
//
// Synopsis:
// Notify the cache node that the save of this cache node is
// complete. If the presentation data is not being used for
// drawing, it can be discarded.
//
// Arguments:
// [iStreamNum] -- the stream number that the presentation was
// saved to
// [fDrawCache] -- used to indicate whether or not the cached
// presentation is to be used for drawing
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
INTERNAL_(void) CCacheNode::SaveCompleted(int iStreamNum, BOOL fDrawCache)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SaveCompleted ( %d , "
"%lu )\n", this, iStreamNum, fDrawCache ));
// All the changes have been flushed to the disk.
// the cache node data is no longer dirty
m_usFlag &= ~CCACHENODEF_DIRTY;
// this identifies the stream that the node was written to on disk
m_iStreamNum = iStreamNum;
// If this cache node is not being used in drawing, then discard the
// presentation data handle. If we need it again later, we can
// reload it from the stream.
if (!fDrawCache)
{
if (m_usFlag & CCACHENODEF_FROZEN)
{
if (m_pPresObjAfterFreeze)
m_pPresObjAfterFreeze->DiscardHPRES();
}
else
{
// REVIEW, shouldn't this be unconditional?
// <-- shouldn't be under an "else"?
// that is, isn't there an unfrozen presentation,
// whether or not the cache node is frozen?
if (m_pPresObj)
{
m_pPresObj->DiscardHPRES();
}
}
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SaveCompleted ( )\n",
this));
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::SetAdvf, public
//
// Synopsis:
// Set new ADVF_ control flags for the advisory connection to
// this cache node.
//
// Effects:
// Saves the new setting persistently, if a stream has already
// been associated with this cache node.
//
// Arguments:
// [advf] -- the new advise control flags
//
// Returns:
// S_OK
//
// Notes:
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_SetAdvf)
INTERNAL CCacheNode::SetAdvf(DWORD dwAdvf)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetAdvf ( %lx )\n",
this, dwAdvf));
LPSTREAM pstm; // stream used to store this cache node, if there is one
TearDownAdviseConnection();
m_advf = dwAdvf; // record the new advise control flags
SetupAdviseConnection();
// get the stream for this cache node, if possible
if (pstm = GetStm(FALSE /*fSeekToPresBits*/, STGM_READWRITE))
{
// save the advise flags if this cache node has a valid stream
// assigned. Then we don't have to set the dirty bit.
if (FAILED(UtWriteOlePresStmHeader(pstm, &m_foretc, m_advf)))
{
// if the write failed, set the dirty bit
m_usFlag |= CCACHENODEF_DIRTY;
}
pstm->Release();
}
else
{
// if no stream yet, we have to mark this as dirty
m_usFlag |= CCACHENODEF_DIRTY;
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetAdvf ( %lx )\n",
this, NOERROR));
return NOERROR;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Delete, public
//
// Synopsis:
// Called to delete a CCacheNode when it is no longer needed by
// the cache. COleCache uses this to indicate that it is through
// with this cache node. Once this is called, no method calls
// against the CCacheNode by the owning cache are valid.
//
// Arguments:
// none
//
// Notes:
// Note that this may not actually destroy the cache node.
// While it is no longer used, other objects may still be holding
// on to its IAdviseSink interface. That must be released for
// the last time to destroy this.
//
// History:
// 11/05/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Delete)
INTERNAL_(void) CCacheNode::Delete(void)
{
VDATEHEAP();
#ifdef _DEBUG
CCacheNode *pTemp = this;
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Delete ( )\n", this));
#endif //DEBUG
Uninitialize();
// Release our advise sink
// As result of this, if the ref count maintained by advise sink becomes
// zero (which implies that there are no external references to advise
// sink), then the destructor of CCacheNode will be called.
Release();
#ifdef _DEBUG
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Delete ( )\n", pTemp));
#endif
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Load, public
//
// Synopsis:
// Load a cache node from a stream; only loads the presentation
// header. (REVIEW, need to see presentation object::Load)
//
// Arguments:
// [lpstream] -- the stream to load the presentation out of
// [iStreamNum] -- the stream number
//
// Returns:
// REVIEW
// DV_E_LINDEX, for invalid lindex in stream
// S_OK
//
// Notes:
// As part of the loading, the presentation object gets created,
// and loaded from the stream.
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Load)
INTERNAL CCacheNode::Load(LPSTREAM lpstream, int iStreamNum)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Load ( %lx , %d )\n",
this, lpstream, iStreamNum));
HRESULT error;
BOOL fConvert = FALSE; // REVIEW, what's this mean?
// read the presentation stream header
if (error = UtReadOlePresStmHeader(lpstream, &m_foretc, &m_advf,
&fConvert))
goto errRtn;
// validate the lindex
if (!HasValidLINDEX(&m_foretc))
{
LEDebugOut((DEB_ERROR, "Invalid lindex found in the stream"));
error = ResultFromScode(DV_E_LINDEX);
goto errRtn;
}
// Create the appropriate presentation object
if (error = CreatePresObject(NULL /*pDataObject*/, fConvert))
goto errRtn;
// if there's no clipboard format, exit
if (m_foretc.cfFormat == NULL)
{
error = NOERROR;
goto errRtn;
}
// remember the starting poistion of presentation bits
SetPresBitsPos(lpstream);
// presentation object reads rest of the stream
error = m_pPresObj->Load(lpstream, TRUE /*fReadHeaderOnly*/);
errRtn:
// in case of error clear the state that got generated in this Load call
if (error != NOERROR)
{
// Destroy the presentation object if we have any
if (m_pPresObj)
{
m_pPresObj->Release();
m_pPresObj = NULL;
}
m_foretc.cfFormat = NULL;
// delete the ptd if it is non-null
if (m_foretc.ptd)
PubMemFree(m_foretc.ptd);
}
else
{
m_usFlag &= ~CCACHENODEF_DIRTY;
m_iStreamNum = iStreamNum;
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Load ( %lx )\n",
this, error));
return error;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Save, public
//
// Synopsis:
// Saves a cache node, including its presentation object,
// to a stream.
//
// Arguments:
// [pstgSave] -- the storage that will contain the stream
// [fSameAsLoad] -- is this storage the same one we loaded from
// [iStreamNum] -- the stream number to save to
// [fDrawCache] -- used to indicate whether or not the cached
// presentation is to be used for drawing; if false,
// the presentation is discarded after saving
// [fSaveIfSavedBefore] -- instructs the method to save this
// cache node, even if it's been saved before
// [lpCntCachesNotSaved] -- a running count of the number of
// caches that have not been saved
//
// Returns:
// REVIEW
// S_OK
//
// Notes:
//
// History:
// 03/10/94 - AlexT - Don't call SaveCompleted if we don't save!
// (see logRtn, below)
// 01/11/94 - AlexGo - fixed compile error (signed/unsigned
// mismatch)
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
// Save the CacheNode and its presentation object to the stream
#pragma SEG(CCacheNode_Save)
INTERNAL CCacheNode::Save(LPSTORAGE pstgSave, BOOL fSameAsLoad,
int iStreamNum, BOOL fDrawCache, BOOL fSaveIfSavedBefore,
int FAR* lpCntCachesNotSaved)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Save ( %p , %lu ,"
"%d , %lu , %lu , %p )\n", this, pstgSave, fSameAsLoad,
iStreamNum, fDrawCache, fSaveIfSavedBefore,
lpCntCachesNotSaved));
HRESULT error = NOERROR; // error status so far
LPSTREAM lpstream = NULL; // the stream to save to
LPSTORAGE lpStg; // storage the cache is presently stored in
OLECHAR szNewName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)];
// the new stream name, if we need one
LPOLEPRESOBJECT pPresObj; // the presentation object to write out
// are we meant to save it to the same stream that it was loaded from?
if (fSameAsLoad)
{
// if we're to save this if it was saved before, but there's
// no stream number, OR, we're not to save this again if it was
// saved before, and there is a stream number, don't save
// this node, and add to the count of caches that have not
// been saved
if ((fSaveIfSavedBefore && (m_iStreamNum == OLE_INVALID_STREAMNUM))
|| (!fSaveIfSavedBefore &&
(m_iStreamNum != OLE_INVALID_STREAMNUM)))
{
if (lpCntCachesNotSaved)
++*lpCntCachesNotSaved;
AssertSz(NOERROR == error, "Error set incorrectly");
goto logRtn;
}
// if it's not dirty, and we were to save to the same place,
// there's no need to save it again
if (!(m_usFlag & CCACHENODEF_DIRTY) &&
(m_iStreamNum == iStreamNum))
{
goto errRtn;
}
}
// start with the standard stream name
_xstrcpy(szNewName, OLE_PRESENTATION_STREAM);
// if we want a stream other than '0', change the numeric suffix
if (iStreamNum != 0)
UtGetPresStreamName(szNewName, iStreamNum);
if (fSameAsLoad && !(m_usFlag & CCACHENODEF_DIRTY) &&
(m_iStreamNum != OLE_INVALID_STREAMNUM))
{
OLECHAR szOldName[
sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)];
// the old name of the presentation's stream
// We are being asked to save in to a different stream. Since
// we are not dirty we can rename the old stream to a new name.
// get the storage the cache is presently stored in
lpStg = m_pOleCache->GetStg();
Assert(lpStg != NULL);
// create the old presentation stream name
_xstrcpy(szOldName, OLE_PRESENTATION_STREAM);
if (m_iStreamNum != 0)
UtGetPresStreamName(szOldName, m_iStreamNum);
// delete the stream with the new name, if there is one
lpStg->DestroyElement(szNewName);
// rename the old stream
error = lpStg->RenameElement(szOldName, szNewName);
// if all is well, get out
if (error == NOERROR)
goto errRtn;
error = ResultFromScode(STG_E_WRITEFAULT);
goto errRtn;
}
// We are either dirty or being asked to save into a different storage
// Create or open (an existing) stream.
if (error = OpenOrCreateStream(pstgSave, szNewName, &lpstream))
{
RESTORE_A5();
goto errRtn;
}
// if it is not same as load and not dirty we can do stream copy
if (!(fSameAsLoad || (m_usFlag & CCACHENODEF_DIRTY)))
{
LPSTREAM pstmSrc; // stream the presentation was loaded from
// get source stream
if (pstmSrc = GetStm(FALSE /*fSeekToPresBits*/, STGM_READ))
{
ULARGE_INTEGER ularge_int; // amount of stream to copy
// initialize to copy all of stream
ULISet32(ularge_int, (DWORD)-1L); // REVIEW, need
// hi part?
error = pstmSrc->CopyTo(lpstream, ularge_int, NULL,
NULL);
// release the srouce stream */
pstmSrc->Release();
if (error == NOERROR)
{
StSetSize(lpstream, 0, TRUE);
goto errRtn;
}
}
// we might get here if the stream copy failed, or we couldn't
// get the source stream; we fall through and follow the
// regular procedure
}
// write the presentation stream header
if (error = UtWriteOlePresStmHeader(lpstream, &m_foretc, m_advf))
goto errRtn;
// if there is nothing more to write, return success
if (m_foretc.cfFormat == NULL)
{
StSetSize(lpstream, 0, TRUE);
goto errRtn;
}
// we want to save the updated presentation that we got after we
// froze the aspect.
if (m_pPresObjAfterFreeze && !m_pPresObjAfterFreeze->IsBlank())
pPresObj = m_pPresObjAfterFreeze;
else
pPresObj = m_pPresObj;
// if there's no presentation object, quit
if (!pPresObj)
{
AssertSz(FALSE, "No presentation object");
error = ResultFromScode(OLE_E_BLANK);
goto errRtn;
}
// remember the starting position of presentation bits
SetPresBitsPos(lpstream);
// ask the presentation object to save itself
error = pPresObj->Save(lpstream);
errRtn:
// release the stream, if there is one
if (lpstream)
{
lpstream->Release();
}
if ((error == NOERROR) && fSameAsLoad)
{
SaveCompleted(iStreamNum, fDrawCache);
}
logRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Save ( %lx ) [ %d ]\n",
this, error,
(lpCntCachesNotSaved)? *lpCntCachesNotSaved : 0));
return error;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::SetPresBitsPos, private
//
// Synopsis:
// Sets CCacheNode::m_dwPresBitsPos to the point where the
// presentation begins in the stream associated with this cache
// node.
//
// Arguments:
// [lpStream] -- the stream the cache node is being saved to
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - created
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_SetPresBitsPos)
INTERNAL_(void) CCacheNode::SetPresBitsPos(LPSTREAM lpStream)
{
VDATEHEAP();
LARGE_INTEGER large_int; // fed into IStream::Seek to get current pos
ULARGE_INTEGER ularge_int; // retrieves the position of the presentation
LISet32(large_int, 0);
lpStream->Seek(large_int, STREAM_SEEK_CUR, &ularge_int);
m_dwPresBitsPos = ularge_int.LowPart;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::OnRun, public
//
// Synopsis:
// Inform the cache node that the server is now running; the
// cache node will set up advisory connections to the data
// object to be informed of changes to the presentation. If
// this is called and a data object is already registered in
// this node, the call is ignored.
//
// Arguments:
// [lpDataObj] -- the data object presented by the newly
// activated server NB, this is not reference counted
//
// Returns:
// the FORMATETC dwAspect for this cache node
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_OnRun)
INTERNAL_(DWORD) CCacheNode::OnRun(LPDATAOBJECT lpDataObj)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::OnRun ( %p )\n",
this, lpDataObj));
if ((m_pDataObj == NULL) && (lpDataObj != NULL))
{
m_pDataObj = lpDataObj; // NOTE: no ref count
SetupAdviseConnection();
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::OnRun ( %lu )\n",
this, m_foretc.dwAspect));
return(m_foretc.dwAspect);
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::OnStop, public
//
// Synopsis:
// Informs the cache node that the server is being deactivated.
// The cache node tears down any advisory connections it has
// establised to the data object exposed by the server, and
// forgets about the data object. If this is called when no
// live data object is registered with the cache node, the call
// is ignored.
//
// Arguments:
// none
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_OnStop)
INTERNAL_(void) CCacheNode::OnStop()
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::OnStop ( )\n",
this ));
TearDownAdviseConnection();
// forget the data object
m_pDataObj = NULL; // NOTE; no ref count
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::OnStop ( )\n",
this));
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::CreatePresObject, public
//
// Synopsis:
// Create the presentation object for the cache node. If there
// is no clipboard format (cfFormat), then query the source data
// object for one of our preferred formats. If there is no
// source data object, no error is returned, but no presentation
// is created
//
// Arguments:
// [lpSrcDataObj] -- data object to use as the basis for the
// new presentation
// [fConvert] -- REVIEW, what's this for?
//
// Returns:
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
// Try to create appropriate presentation object. If cfFormat is NULL, then
// try to query lpSrcDataObj to see whether it supports one of our standard
// formats
#pragma SEG(CCacheNode_CreatePresObject)
INTERNAL CCacheNode::CreatePresObject(LPDATAOBJECT lpSrcDataObj, BOOL fConvert)
{
VDATEHEAP();
BOOL fFormatSupported; // is the format we want supported?
HRESULT error; // error status so far
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CreatePresObject ( %lx , "
"%lu )\n", this, lpSrcDataObj, fConvert));
if (lpSrcDataObj)
{
// check whether object supports the cachenode's format. If the
// cachenode format field is NULL, the query will be made for
// our standard formats.
fFormatSupported = QueryFormatSupport(lpSrcDataObj);
}
else
{
if (m_foretc.cfFormat == NULL)
{
// Since data object pointer is NULL, at this moment
// we won't be able to say whether the object supports
// any of our standard formats. So, we return without
// creating presentation object.
error = NOERROR;
goto errRtn;
}
// assume the format we want is supported
fFormatSupported = TRUE;
}
// massage format, if necessary
BITMAP_TO_DIB(m_foretc);
if ((error = CreateOlePresObject(&m_pPresObj, fConvert)) != NOERROR)
{
goto errRtn;
}
if (fFormatSupported)
{
error = NOERROR;
goto errRtn;
}
error = ResultFromScode(CACHE_S_FORMATETC_NOTSUPPORTED);
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CreatePresObj ( %lx )\n",
this ));
return error;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::CreateOlePresObject, private
//
// Synopsis:
// Creates a presentation object, according to the clipboard
// format m_foretc.cfFormat
//
// Arguments:
// [ppPresObject] -- pointer to where to return the pointer to
// the newly created presentation object
// [fConvert] -- REVIEW, what's this for?
//
// Returns:
// DV_E_CLIPFORMAT, if object doesn't support one of the standard
// formats
// E_OUTOFMEMORY, if we can't allocate the presentation object
// S_OK
//
// Notes:
//
// History:
// 13-Feb-95 t-ScottH added m_dwPresFlag to track type of
// IOlePresObject
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
INTERNAL CCacheNode::CreateOlePresObject(LPOLEPRESOBJECT FAR* ppPresObj,
BOOL fConvert)
{
HRESULT error = NOERROR;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CreateOlePresObject "
"( %lx , %lu )\n", this, ppPresObj, fConvert));
switch(m_foretc.cfFormat)
{
case NULL:
// lpSrcDataObj must be NON-NULL,(ie) object doesn't support
// one of our standard formats.
*ppPresObj = NULL;
return ResultFromScode(DV_E_CLIPFORMAT);
case CF_METAFILEPICT:
*ppPresObj = new FAR CMfObject(this, m_foretc.dwAspect,
fConvert);
#ifdef _DEBUG
// for use with debugger extensions and dump method
m_dwPresFlag = CN_PRESOBJ_MF;
#endif // _DEBUG
break;
case CF_ENHMETAFILE:
*ppPresObj = new FAR CEMfObject(this, m_foretc.dwAspect);
#ifdef _DEBUG
// for use with debugger extensions and dump method
m_dwPresFlag = CN_PRESOBJ_EMF;
#endif // _DEBUG
break;
default:
*ppPresObj = new FAR CGenObject(this, m_foretc.cfFormat,
m_foretc.dwAspect);
#ifdef _DEBUG
// for use with debugger extensions and dump method
m_dwPresFlag = CN_PRESOBJ_GEN;
#endif // _DEBUG
}
if (!*ppPresObj)
{
error = ResultFromScode(E_OUTOFMEMORY);
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CreateOlePresObject "
"( %lx ) [ %p ]\n", this, error, *ppPresObj));
return error;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::GetStm, public
//
// Synopsis:
// Get the stream the presentation is stored in. Optionally
// position the stream at the point where the presentation
// data begins
//
// Arguments:
// [fSeekToPresBits] -- position the stream so that the
// presentation bits would be the next read/written
// [dwStgAccess] -- the access mode (STGM_*) to open the stream
// with
//
// Returns:
// NULL, if there is no stream, or the stream cannot be opened
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
INTERNAL_(LPSTREAM) CCacheNode::GetStm(BOOL fSeekToPresBits, DWORD dwStgAccess)
{
VDATEHEAP();
LPSTREAM pstm; // the stream we'll return
LPSTORAGE pstg; // the storage to create/open the stream in
OLECHAR szName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)];
// the name of the stream
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetStm ( %lu , %lx )\n",
this, fSeekToPresBits, dwStgAccess));
// if there's no stream assigned, we can't get it
if (m_iStreamNum == OLE_INVALID_STREAMNUM)
{
pstm = NULL;
goto errRtn;
}
// if the cache doesn't own storage, we can't get a stream
if ((pstg = m_pOleCache->GetStg()) == NULL)
{
pstm = NULL;
goto errRtn;
}
// begin by copying the default stream name
_xstrcpy(szName, OLE_PRESENTATION_STREAM);
// if we want a stream other than '0', adjust the name
if (m_iStreamNum)
UtGetPresStreamName(szName, m_iStreamNum);
// attempt to open the stream
if (pstg->OpenStream(szName, NULL,
(dwStgAccess | STGM_SHARE_EXCLUSIVE),
NULL, &pstm) == NOERROR)
{
// if we're to position the stream at the presentation, do so
if (fSeekToPresBits)
{
LARGE_INTEGER large_int;
LISet32(large_int, m_dwPresBitsPos);
if (pstm->Seek(large_int, STREAM_SEEK_SET, NULL) !=
NOERROR)
{
// If we can't position, release the stream,
// and don't return it.
pstm->Release();
pstm = NULL;
}
}
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetStm ( %p )\n", this,
pstm));
// return the stream
return(pstm);
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Update, public
//
// Synopsis:
// Updates the presentation object in this cache node from
// the given data object. The update is only done if the
// [grfUpdf] flags match m_advf specifications, and if
// there is actually a presentation to update.
//
// Arguments:
// [lpDataObj] -- the data object to use as a source of data
// [grfUpdf] -- the update control flags
//
// Returns:
// S_FALSE
// S_OK
//
// Notes: BUGBUG::this is a spaghetti function--rewrite
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
// Update our presentation object from the given data object.
#pragma SEG(CCacheNode_Update)
INTERNAL CCacheNode::Update(LPDATAOBJECT lpDataObj, DWORD grfUpdf)
{
VDATEHEAP();
STGMEDIUM medium; // the medium of the presentation
FORMATETC foretc; // the format of the presentation
HRESULT error = NOERROR;
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Update ( %p , %lx )\n",
this, lpDataObj, grfUpdf));
// if no data object is passed in, we can't do the update
if (!lpDataObj)
{
error = ResultFromScode(S_FALSE);
goto errRtn;
}
// if the presentation object hasn't been created yet (most probably
// because the cfFormat field is NULL), try to create it now.
if (!m_pPresObj)
CreatePresObject(lpDataObj, FALSE /*fConvert*/);
// if the presentation object hasn't been created even after we have a
// source data object, then it implies that the source data object
// doesn't support our standard formats; we can't update
if (!m_pPresObj)
{
error = ResultFromScode(S_FALSE);
goto errRtn;
}
// if we're only supposed to update if the presentation object is
// blank, and it's not blank, there's nothing to do
if ((grfUpdf & UPDFCACHE_ONLYIFBLANK) && (!m_pPresObj->IsBlank()))
{
error = NOERROR;
goto errRtn;
}
// update if this cachenode is created with ADVFCACHE_ONSAVE
if ((grfUpdf & UPDFCACHE_ONSAVECACHE) && (m_advf & ADVFCACHE_ONSAVE))
goto update;
// Normally cachenodes created with ADVF_NODATA will not get updated
// unless update flag is UPDFCACHE_NODATACACHE. But if cache advise
// flags has ADVFCACHE_ONSAVE then we allow it to get updated.
// (see bug # 464 in ole2issues database)
if (m_advf & ADVF_NODATA)
{
if (grfUpdf & UPDFCACHE_NODATACACHE)
goto update;
error = NOERROR;
goto errRtn;
}
// update if this cachenode is created with ADVF_DATAONSTOP
if ((grfUpdf & UPDFCACHE_ONSTOPCACHE) && (m_advf & ADVF_DATAONSTOP))
goto update;
// Update if this is a normal cache node
// (i.e. the cache node that gets live updates)
if ((grfUpdf & UPDFCACHE_NORMALCACHE)
&& !(m_advf & (ADVFCACHE_ONSAVE | ADVF_DATAONSTOP)))
{
// Note: ADVF_NODATA is already covered above. We won't come
// here if the cache advise flags has ADVF_NODATA
goto update;
}
// Update if this cache node is blank
if ((grfUpdf & UPDFCACHE_IFBLANK) && m_pPresObj->IsBlank())
goto update;
goto errRtn;
update:
// initialize the medium
medium.tymed = TYMED_NULL;
medium.hGlobal = NULL;
medium.pUnkForRelease = NULL;
// make a copy of the desired format; this may mutate below
foretc = m_foretc;
// let the object create the medium.
if (wGetData(lpDataObj, &foretc, &medium) != NOERROR)
{
error = ResultFromScode(S_FALSE);
goto errRtn;
}
// take the ownership of the data.
if (SetDataWDO(&foretc, &medium, TRUE /*fRelease*/, lpDataObj) != NOERROR)
{
error = ResultFromScode(S_FALSE);
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Update ( %lx )\n",
this, error));
return error;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::SetDataWDO, public
//
// Synopsis:
// Data is set into the presentation object, if this cache node
// is not frozen. If the cache node is frozen, then the
// new presentation data is stashed into the m_pPresObjAfterFreeze
// presentation object, which is created, if there isn't already
// one. If data is successfully set in the presentation object,
// and the node is not frozen, the cache is notified that this
// is dirty.
//
// Arguments:
// [lpForetc] -- the format of the new data
// [lpStgmed] -- the storage medium the new data is one
// [fRelease] -- passed on to the presentation object; indicates
// whether or not to release the storage medium
// [pDataObj] -- pointer to the revelant source data object
//
// Returns:
// E_FAIL
// REVIEW, result from presentationObject::SetData
// S_OK
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
INTERNAL CCacheNode::SetDataWDO(LPFORMATETC lpForetc, LPSTGMEDIUM lpStgmed,
BOOL fRelease, IDataObject * pDataObj)
{
VDATEHEAP();
HRESULT hresult; // error status so far
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetDataWDO ( %p , %p , %lu )"
"\n", this, lpForetc, lpStgmed, fRelease));
// if the cache is frozen, stash the data in the m_pPresObjAfterFreeze
// presentation for later
if (m_usFlag & CCACHENODEF_FROZEN)
{
// if there's no presentation, create one now
if (!m_pPresObjAfterFreeze)
{
if (CreateOlePresObject(&m_pPresObjAfterFreeze,
FALSE) != NOERROR)
{
hresult = ResultFromScode(E_FAIL);
goto errRtn;
}
}
hresult = m_pPresObjAfterFreeze->SetDataWDO(lpForetc, lpStgmed, fRelease, pDataObj);
}
else
{
// the cache is not frozen, set data in regular presentation
// object
// REVIEW, why is it that we don't create m_pPresObj if it
// doesn't already exist?
if (m_pPresObj)
hresult = m_pPresObj->SetDataWDO(lpForetc, lpStgmed,
fRelease, pDataObj);
else
hresult = ReportResult(0, E_FAIL, 0, 0);
}
// NotifyOleCache so that it can generate view notifcation as well as
// set the dirty flag
if (hresult == NOERROR)
{
m_usFlag |= CCACHENODEF_DIRTY;
NotifyOleCache(TRUE /*fDirty*/);
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetDataWDO ( %lx )\n", this,
hresult));
return hresult;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Freeze, public
//
// Synopsis:
// Freeze the cachenode. From here on, OnDataChange() is ignored
// until this node is unfrozen (Unfreeze().) This is not
// persistent across Save/Load. (If we receive OnDataChange(),
// the new data is stashed away in m_pPresAfterFreeze, but is
// not exported to the outside of the cache node.)
//
// Arguments:
// none
//
// Returns:
// VIEW_S_ALREADY_FROZEN
// S_OK
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Freeze)
INTERNAL CCacheNode::Freeze()
{
HRESULT hresult;
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Freeze ( )\n",
this));
// if already frozen, return error
if (m_usFlag & CCACHENODEF_FROZEN)
{
hresult = ResultFromScode(VIEW_S_ALREADY_FROZEN);
}
else
{
m_usFlag |= CCACHENODEF_FROZEN;
hresult = NOERROR;
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Freeze ( %lx )\n",
this, hresult));
return hresult;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Unfreeze, public
//
// Synopsis:
// Unfreeze the cachenode. If there have been changes to
// the presentation data since the node was frozen, the node
// is updated to reflect those changes. From this point on,
// OnDataChange() notifications are no longer ignored.
//
// Arguments:
// none
//
// Returns:
// OLE_E_NOCONNECTION, if the node was not frozen (REVIEW scode)
// S_OK
//
// Notes:
//
// History:
// 11/06/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Unfreeze)
INTERNAL CCacheNode::Unfreeze()
{
VDATEHEAP();
HRESULT hresult;
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::UnFreeze ( )\n", this ));
// if not frozen, return error
if (!(m_usFlag & CCACHENODEF_FROZEN))
{
hresult = ResultFromScode(OLE_E_NOCONNECTION);
goto errRtn;
}
// node is no longer frozen
m_usFlag &= ~CCACHENODEF_FROZEN;
// If we have a non-NULL m_pPresObjAfterFreeze, and it is not blank,
// then make that current.
if (m_pPresObjAfterFreeze)
{
if (m_pPresObjAfterFreeze->IsBlank())
{
// It's no good. Get rid of it.
m_pPresObjAfterFreeze->Release();
}
else
{
// Destroy the frozen presentation object
if (m_pPresObj)
m_pPresObj->Release();
// make m_pPresObjAfterFreeze the current one
m_pPresObj = m_pPresObjAfterFreeze;
// notify the olecache that the data has changed
NotifyOleCache(TRUE /*fDirty*/);
}
// we no longer have an "after-freeze" presentation object
m_pPresObjAfterFreeze = NULL;
}
hresult = NOERROR;
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::UnFreeze ( %lx )\n", this,
hresult));
return hresult;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::QueryFormatSupport, private
//
// Synopsis:
// Check to see if the data object supports the presentation
// format specified for this cache node. If no format is
// specified, check for any of our preferred formats. If
// the format is CF_DIB, and that is not available, check for
// CF_BITMAP.
//
// Arguments:
// [lpDataObj] -- the data object
//
// Returns:
// TRUE if the format is supported, FALSE otherwise
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - no longer necessary to reset format
// after UtQueryPictFormat, since that leaves descriptor
// untouched now
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_QueryFormatSupport)
INTERNAL_(BOOL) CCacheNode::QueryFormatSupport(LPDATAOBJECT lpDataObj)
{
VDATEHEAP();
BOOL fRet = FALSE;
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::QueryFormatSupport ( %p )\n",
this, lpDataObj));
if (!lpDataObj)
{
fRet = FALSE;
goto errRtn;
}
// is there no format specified?
if (m_foretc.cfFormat == NULL)
{
// check for our preferred format
if (UtQueryPictFormat(lpDataObj, &m_foretc))
{
fRet = TRUE;
goto errRtn;
}
}
else
{
// check to see if the specified format is supported
if (lpDataObj->QueryGetData(&m_foretc) == NOERROR)
{
fRet = TRUE;
goto errRtn;
}
// if the format was DIB, and that was not supported,
// check to see if BITMAP is supported instead
if (m_foretc.cfFormat == CF_DIB)
{
FORMATETC foretc = m_foretc;
foretc.cfFormat = CF_BITMAP;
foretc.tymed = TYMED_GDI;
if (lpDataObj->QueryGetData(&foretc) == NOERROR)
{
fRet = TRUE;
}
}
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::QueryFormatSupport"
" ( %lu )\n", this, fRet));
return fRet;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::SetupAdviseConnection, private
//
// Synopsis:
// Set up data advise sourced by the server object, and sunk
// by this cache node, if there is a valid data object.
//
// Arguments:
// none
//
// Returns:
// OLE_E_BLANK, if no presentation object exists or can be
// created
// DATA_E_FORMATETC
// OLE_E_ADVISENOTSUPPORTED
// S_OK, indicates successful advise, or no data object
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_SetupAdviseConnection)
INTERNAL CCacheNode::SetupAdviseConnection(void)
{
VDATEHEAP();
DWORD grfAdvf; // local copy of advise control flags
HRESULT hresult; // error status
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetupAdviseConnection"
" ( )\n", this ));
// if there's no data object, there's nothing to do
if (m_pDataObj == NULL)
{
hresult = NOERROR;
goto errRtn;
}
// if don't have a presentation object try to create one.
if (!m_pPresObj)
CreatePresObject(m_pDataObj, FALSE /*fConvert*/);
// if we couldn't create one then return error.
if (!m_pPresObj)
{
hresult = ResultFromScode(OLE_E_BLANK);
goto errRtn;
}
// if cache advise flags have ADVF_NODATA then don't setup
// any advise connection
if (m_advf & ADVF_NODATA)
{
hresult = NOERROR;
goto errRtn;
}
// copy base advise control flags
grfAdvf = m_advf;
// only the DDE layer looks for these 2 bits
grfAdvf |= (ADVFDDE_ONSAVE | ADVFDDE_ONCLOSE);
// if we were to get data when it is saved, get it instead when
// the object is stopped; this prevents us having to reload the
// object here to get this, if the server is saved after we've
// terminated, or the local handler is no longer running
if (grfAdvf & ADVFCACHE_ONSAVE)
{
grfAdvf &= (~ADVFCACHE_ONSAVE);
grfAdvf |= ADVF_DATAONSTOP;
}
// These two flags are not meaningful to the cache
// REVIEW, why not?
grfAdvf &= (~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN));
// if we already have data, then remove the ADVF_PRIMEFIRST
if (!m_pPresObj->IsBlank())
grfAdvf &= (~ADVF_PRIMEFIRST);
// set up the advise with the data object, using massaged flags
if ((hresult = m_pDataObj->DAdvise(&m_foretc, grfAdvf,
(IAdviseSink FAR *)this, &m_dwAdvConnId)) != NOERROR)
{
// The advise failed. If the requested format was CF_DIB,
// try for CF_BITMAP instead.
if (m_foretc.cfFormat == CF_DIB)
{
FORMATETC foretc; // new format descriptor
// create new format descriptor
foretc = m_foretc;
foretc.cfFormat = CF_BITMAP;
foretc.tymed = TYMED_GDI;
// request advise
hresult = m_pDataObj->DAdvise(&foretc, grfAdvf,
(IAdviseSink FAR *)this,
&m_dwAdvConnId);
}
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetupAdviseConnection "
"( %lx )\n", this, hresult));
return hresult;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::TearDownAdviseConnection, private
//
// Synopsis:
// Remove advise connection from data object to this sink. Returns
// immediately if there is no advise connection.
//
// Arguments:
// none
//
// Returns:
// S_OK
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_TearDownAdviseConnection)
INTERNAL CCacheNode::TearDownAdviseConnection()
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::TearDownAdviseConnection"
" ( )\n", this ));
// if there's no advise connection, nothing to do
if (m_dwAdvConnId != 0 && m_pDataObj)
{
// if there is a data object, unadvise from it
// ignore error on the Unadvise since it not reported
// reliably and may be can't-call-out-in-async.
m_pDataObj->DUnadvise(m_dwAdvConnId);
CoDisconnectObject((IUnknown FAR *)this, NULL);
}
// there's no longer an advise connection
m_dwAdvConnId = 0;
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::TearDownAdviseConnection"
" ( %lx )\n", this, NOERROR));
return NOERROR;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::NotifyOleCache, private
//
// Synopsis:
// Notify the cache this cache node belongs to that the
// content of this cache node is dirty. This cache node is
// identified by its aspect and lindex. No notification is
// delivered if the cache is frozen.
//
// Arguments:
// [fDirty] -- indicates that the cache is dirty
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
inline INTERNAL_(void) CCacheNode::NotifyOleCache(BOOL fDirty)
{
VDATEHEAP();
if (!(m_usFlag & CCACHENODEF_FROZEN))
{
m_pOleCache->OnChange(m_foretc.dwAspect, m_foretc.lindex,
fDirty);
}
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::QueryInterface, public
//
// Synopsis:
// implementation of IUnknown::QueryInterface
//
// Arguments:
// [iid] -- IID of the desired interface
// [ppvObj] -- pointer to where to return the requested interface
//
// Returns:
// E_NOINTERFACE
// S_OK
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_QueryInterface)
STDMETHODIMP CCacheNode::QueryInterface(REFIID iid, LPVOID FAR* ppvObj)
{
HRESULT hresult;
VDATEHEAP();
VDATEPTROUT(ppvObj, LPVOID);
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::QueryInterface ( %p , %p )"
"\n", this, iid, ppvObj));
if (IsEqualIID(iid, IID_IUnknown) ||
IsEqualIID(iid, IID_IAdviseSink))
{
*ppvObj = (IAdviseSink FAR *)this;
AddRef();
hresult = NOERROR;
}
else
{
*ppvObj = NULL;
hresult = ResultFromScode(E_NOINTERFACE);
}
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::QueryInterface ( %lx )"
" [ %p ]\n", this, hresult, *ppvObj));
return hresult;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::AddRef, public
//
// Synopsis:
// implements IUnknown::AddRef
//
// Arguments:
// none
//
// Returns:
// the reference count of this object
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_AddRef)
STDMETHODIMP_(ULONG) CCacheNode::AddRef(void)
{
VDATEHEAP();
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::AddRef ( )\n", this));
m_refs++;
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Release ( %lu )\n", this,
m_refs));
return m_refs;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::Release, public
//
// Synopsis:
// implements IUnknown::Release
//
// Arguments:
// none
//
// Returns:
// the reference count of the object
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_Release)
STDMETHODIMP_(ULONG) CCacheNode::Release(void)
{
VDATEHEAP();
ULONG cRefs;
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Release ( )\n", this ));
if ( (cRefs = --m_refs) == 0)
{
LEDebugOut((DEB_ITRACE, "%p DELETED CCacheNode\n", this));
delete this;
}
// the this pointer may be invalid here, but all we want is it's
// value.
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Release ( %lu )\n", this,
cRefs));
return cRefs;
}
//+----------------------------------------------------------------------------
//
// Member:
// CCacheNode::OnDataChange, public
//
// Synopsis:
// The cache node is notified that the data it is interested in
// has changed. The cache node records the new version of the
// data, and notifies the cache that it belongs to that data
// has changed
//
// Arguments:
// [lpForetc] -- the format of the new data
// [lpStgmed] -- the storage medium of the new data
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(CCacheNode_OnDataChange)
STDMETHODIMP_(void) CCacheNode::OnDataChange(FORMATETC FAR* lpForetc,
STGMEDIUM FAR* lpStgmed)
{
VDATEHEAP();
VOID_VDATEPTRIN(lpForetc, FORMATETC);
VOID_VDATEPTRIN(lpStgmed, STGMEDIUM);
LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::OnDataChange "
"( %p , %p )\n", this, lpForetc, lpStgmed));
// It is possible for this to be called after the cache node
// has been disassociated from its owning cache. If that has
// happened, do nothing
if (m_pOleCache == NULL)
{
goto errRtn;
}
// if there's no storage medium, there's no data to copy
if (lpStgmed->tymed == TYMED_NULL)
NotifyOleCache(FALSE /*fDirty*/);
else
{
// the cache node shouldn't exist with this setting
Assert(!(m_advf & ADVF_NODATA));
// make a copy of the data
SetData(lpForetc, lpStgmed, FALSE /*fRelease*/);
}
errRtn:
LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::OnDataChange ( )\n",
this ));
return;
}
//+-------------------------------------------------------------------------
//
// Member: CCacheNode::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 CCacheNode::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
{
int i;
char *pszPrefix;
char *pszFORMATETC;
char *pszADVF;
char *pszPresObj;
dbgstream dstrPrefix;
dbgstream dstrDump(1500);
// 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
dstrDump << pszPrefix << "No. of References = ";
dstrDump << m_refs << endl;
pszFORMATETC = DumpFORMATETC(&m_foretc, ulFlag, nIndentLevel + 1);
dstrDump << pszPrefix << "FORMATETC: " << endl;
dstrDump << pszFORMATETC;
CoTaskMemFree(pszFORMATETC);
pszADVF = DumpADVFFlags(m_advf);
dstrDump << pszPrefix << "Advise Flags = ";
dstrDump << pszADVF << endl;
CoTaskMemFree(pszADVF);
dstrDump << pszPrefix << "Cache Node Flag = ";
if (m_usFlag & CCACHENODEF_FROZEN)
{
dstrDump << "CCACHENODEF_FROZEN ";
}
else if (m_usFlag & CCACHENODEF_DIRTY)
{
dstrDump << "CCACHENODEF_DIRTY ";
}
else
{
dstrDump << "No FLAG is set! ";
}
dstrDump << "(" << (void *)m_usFlag << ")" << endl;
dstrDump << pszPrefix << "Advise Connection ID = ";
dstrDump << m_dwAdvConnId << endl;
dstrDump << pszPrefix << "Byte offset to Pres. bits = ";
dstrDump << m_dwPresBitsPos << endl;
dstrDump << pszPrefix << "Stream No. with Pres. = ";
dstrDump << m_iStreamNum << endl;
// possible recursion if we call COleCache::Dump
dstrDump << pszPrefix << "pCOleCache = ";
dstrDump << m_pOleCache << endl;
dstrDump << pszPrefix << "pIDataObject = ";
dstrDump << m_pDataObj << endl;
dstrDump << pszPrefix << "IOlePresObj implementation= ";
switch (m_dwPresFlag)
{
case CN_PRESOBJ_GEN:
dstrDump << "CGenObject" << endl;
break;
case CN_PRESOBJ_MF:
dstrDump << "CMfObject" << endl;
break;
case CN_PRESOBJ_EMF:
dstrDump << "CEMfObject" << endl;
break;
default:
dstrDump << "Cannot resolve" << endl;
}
if (m_pPresObj != NULL)
{
pszPresObj = DumpIOlePresObj(m_pPresObj, ulFlag, nIndentLevel + 1);
dstrDump << pszPrefix << "IOlePresObj:" << endl;
dstrDump << pszPresObj;
CoTaskMemFree(pszPresObj);
}
else
{
dstrDump << pszPrefix << "pIOlePresObj = ";
dstrDump << m_pPresObj << endl;
}
if (m_pPresObjAfterFreeze != NULL)
{
pszPresObj = DumpIOlePresObj(m_pPresObjAfterFreeze, ulFlag, nIndentLevel + 1);
dstrDump << pszPrefix << "IOlePresObj (after freeze):" << endl;
dstrDump << pszPresObj;
CoTaskMemFree(pszPresObj);
}
else
{
dstrDump << pszPrefix << "pIOlePresObjAfterFreeze = ";
dstrDump << m_pPresObjAfterFreeze << endl;
}
// cleanup and provide pointer to character array
*ppszDump = dstrDump.str();
if (*ppszDump == NULL)
{
*ppszDump = UtDupStringA(szDumpErrorMessage);
}
CoTaskMemFree(pszPrefix);
return NOERROR;
}
#endif // _DEBUG
//+-------------------------------------------------------------------------
//
// Function: DumpCCacheNode, public (_DEBUG only)
//
// Synopsis: calls the CCacheNode::Dump method, takes care of errors and
// returns the zero terminated string
//
// Effects:
//
// Arguments: [pCN] - pointer to CCacheNode
// [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 *DumpCCacheNode(CCacheNode *pCN, ULONG ulFlag, int nIndentLevel)
{
HRESULT hresult;
char *pszDump;
if (pCN == NULL)
{
return UtDupStringA(szDumpBadPtr);
}
hresult = pCN->Dump(&pszDump, ulFlag, nIndentLevel);
if (hresult != NOERROR)
{
CoTaskMemFree(pszDump);
return DumpHRESULT(hresult);
}
return pszDump;
}
#endif // _DEBUG
//+----------------------------------------------------------------------------
//
// Function:
// wGetData, internal
//
// Synopsis:
// Fetch the data from the data object in the requested format.
// If the fetch fails, and the requested format was CF_DIB,
// try CF_BITMAP as an alternative.
//
// Arguments:
// [lpSrcDataObj] -- source data object
// [lpforetc] -- desired data format
// [lpmedium] -- if successful, the storage medium containing
// the requested data
//
// Returns:
// DATA_E_FORMATETC
// S_OK
//
// Notes:
//
// History:
// 11/09/93 - ChrisWe - modified to not alter the requested
// format unless the subsequent CF_BITMAP request succeeds.
// 11/09/93 - ChrisWe - file inspection and cleanup
//
//-----------------------------------------------------------------------------
#pragma SEG(wGetData)
INTERNAL wGetData(LPDATAOBJECT lpSrcDataObj, LPFORMATETC lpforetc,
LPSTGMEDIUM lpmedium)
{
VDATEHEAP();
HRESULT hresult;
LEDebugOut((DEB_ITRACE, "%p _IN wGetData ( %p , %p , %p )\n",
NULL, lpSrcDataObj, lpforetc, lpmedium));
// get the data in the requested format
if ((hresult = lpSrcDataObj->GetData(lpforetc, lpmedium)) != NOERROR)
{
// GetData failed. If the requested format was CF_DIB,
// then try CF_BITMAP instead.
if (lpforetc->cfFormat == CF_DIB)
{
FORMATETC foretc; // copy of requested format
// copy the base format descriptor; try CF_BITMAP
foretc = *lpforetc;
foretc.cfFormat = CF_BITMAP;
foretc.tymed = TYMED_GDI;
hresult = lpSrcDataObj->GetData(&foretc, lpmedium);
if (hresult == NOERROR)
{
lpforetc->cfFormat = CF_BITMAP;
lpforetc->tymed = TYMED_GDI;
}
}
// GetData failed. If the requested format was CF_ENHMETAFILE,
// silently retry for standard metafile instread.
if (lpforetc->cfFormat == CF_ENHMETAFILE)
{
FORMATETC foretc; // copy of requested format
foretc = *lpforetc;
foretc.cfFormat = CF_METAFILEPICT;
foretc.tymed = TYMED_MFPICT;
hresult = lpSrcDataObj->GetData(&foretc, lpmedium);
if (hresult == NOERROR)
{
lpforetc->cfFormat = CF_METAFILEPICT;
lpforetc->tymed = TYMED_MFPICT;
}
}
}
AssertOutStgmedium(hresult, lpmedium);
LEDebugOut((DEB_ITRACE, "%p OUT wGetData ( %lx )\n", NULL, hresult));
return hresult;
}