1476 lines
37 KiB
C++
1476 lines
37 KiB
C++
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// File:
|
|
// daholder.cpp
|
|
//
|
|
// Contents:
|
|
// concrete implementation of IDataAdviseHolder, a helper
|
|
// class for OLE server implementors
|
|
//
|
|
// Classes:
|
|
// CDAHolder
|
|
//
|
|
// Functions:
|
|
// CreateDataAdviseHolder
|
|
//
|
|
// History:
|
|
// 01/20/95 - t-ScottH- added Dump methods to CDAHolder and
|
|
// CEnumSTATDATA classes
|
|
// added DumpCDAHolder & DumpCEnumSTATDATA APIs
|
|
// put class definitions in header file daholder.h
|
|
// 03/09/94 - AlexGo - fixed bugs with the enumerator and
|
|
// disconnecting of bad advise sinks
|
|
// 01/24/94 - AlexGo - first pass at conversion to Cairo-style
|
|
// memory allocation
|
|
// 01/11/94 - AlexGo - added VDATEHEAP macros to all functions and
|
|
// methods
|
|
// 12/09/93 - ChrisWe - fix test for error code after CoGetMalloc()
|
|
// in CDAHolder::Advise
|
|
// 11/22/93 - ChrisWe - replace overloaded ==, != with
|
|
// IsEqualIID and IsEqualCLSID
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <le2int.h>
|
|
#include "daholder.h"
|
|
|
|
#ifdef _DEBUG
|
|
#include "dbgdump.h"
|
|
#endif // _DEBUG
|
|
|
|
#pragma SEG(daholder)
|
|
|
|
NAME_SEG(DaHolder)
|
|
ASSERTDATA
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
// CreateDataAdviseHolder, public
|
|
//
|
|
// Synopsis:
|
|
// Creates an instance of the CDAHolder class
|
|
//
|
|
// Arguments:
|
|
// [ppDAHolder] -- pointer to where to return the created
|
|
// IDataAdviseHolder instance
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CreateDataAdviseHolder)
|
|
STDAPI CreateDataAdviseHolder(IDataAdviseHolder FAR* FAR* ppDAHolder)
|
|
{
|
|
OLETRACEIN((API_CreateDataAdviseHolder, PARAMFMT("ppDAHolder= %p"), ppDAHolder));
|
|
|
|
VDATEHEAP();
|
|
VDATEPTROUT(ppDAHolder, IDataAdviseHolder*);
|
|
|
|
*ppDAHolder = new FAR CDAHolder(); // task memory; use MEMCTX_TASK below
|
|
|
|
CALLHOOKOBJECTCREATE(*ppDAHolder ? NOERROR : E_OUTOFMEMORY,
|
|
CLSID_NULL,
|
|
IID_IDataAdviseHolder,
|
|
(IUnknown **)ppDAHolder);
|
|
|
|
HRESULT hr;
|
|
|
|
hr = *ppDAHolder ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
|
|
OLETRACEOUT((API_CreateDataAdviseHolder, hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::CDAHolder, public
|
|
//
|
|
// Synopsis:
|
|
// constructor
|
|
//
|
|
// Effects:
|
|
// returns with reference count set to 1
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_ctor)
|
|
CDAHolder::CDAHolder() : CSafeRefCount(NULL)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
// set reference count
|
|
SafeAddRef();
|
|
|
|
// connections run from [1..infinity)
|
|
m_dwConnection = 1;
|
|
|
|
// there are no STATDATA entries yet
|
|
m_iSize = 0;
|
|
m_pSD = NULL;
|
|
|
|
GET_A5();
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::~CDAHolder, private
|
|
//
|
|
// Synopsis:
|
|
// destructor
|
|
//
|
|
// Effects:
|
|
// frees resources associated with the CDAHolder
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CDAHolder::~CDAHolder()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
int iData; // counts array entries as we scan the array
|
|
STATDATA FAR *pSD; // used to scan the array of STATDATA
|
|
|
|
// release the array, if we've allocated it
|
|
|
|
// REVIEW: If we want to be really safe, we should release
|
|
// the stat data's either before or after our destructor.
|
|
// The release of the advise sinks in the statdata elements
|
|
// could possible result in us being re-entered (a potential
|
|
// awkward state for the middle of a class destructor).
|
|
|
|
// However, since nobody should be accesssing the advise
|
|
// holder if we get to the destructor (since the reference
|
|
// count would have to be zero), we are going to bag on
|
|
// this modification for Daytona RC1.
|
|
|
|
if (m_pSD)
|
|
{
|
|
for(pSD = m_pSD, iData = 0; iData < m_iSize; ++pSD, ++iData)
|
|
UtReleaseStatData(pSD);
|
|
|
|
PubMemFree(m_pSD);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to a location to return the interface at
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_QueryInterface)
|
|
STDMETHODIMP CDAHolder::QueryInterface(REFIID iid, LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown) ||
|
|
IsEqualIID(iid, IID_IDataAdviseHolder))
|
|
{
|
|
*ppv = (IDataAdviseHolder FAR *)this;
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_AddRef)
|
|
STDMETHODIMP_(ULONG) CDAHolder::AddRef()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
return SafeAddRef();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implementa IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_Release)
|
|
STDMETHODIMP_(ULONG) CDAHolder::Release()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
return SafeRelease();
|
|
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Advise, public
|
|
//
|
|
// Synopsis:
|
|
// Add a new advise sink to the list of advise sinks
|
|
// managed by the data advise holder, and which will be notified
|
|
// if a change is indicated using other IDataAdviseHolder
|
|
// methods. A data format is specified, and new data will be
|
|
// sent to the sink in that format, when a change occurs.
|
|
//
|
|
// Arguments:
|
|
// [pDataObject] -- the source data object that presentations
|
|
// should be taken from if an advise is to occur
|
|
// immediately
|
|
// [pFetc] -- The data format the advise sink is interested in
|
|
// [advf] -- control flags
|
|
// [pAdvSink] -- the advise sink being registered
|
|
// [pdwConnection] -- a token that can be used to identify the
|
|
// advise sink later on
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
// 08/02/94 - AlexGo - stabilized
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_Advise)
|
|
STDMETHODIMP CDAHolder::Advise(LPDATAOBJECT pDataObj, FORMATETC FAR* pFetc,
|
|
DWORD advf, IAdviseSink FAR* pAdvSink,
|
|
DWORD FAR* pdwConnection)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
int iSDScan; // index of the scan of SD array entries
|
|
int iSDFree; // index of first free SD entry, or (-1)
|
|
STATDATA FAR *pSD; // scans across the array of STATDATA entries
|
|
|
|
if( IsZombie() )
|
|
{
|
|
return ResultFromScode(CO_E_RELEASED);
|
|
}
|
|
|
|
CStabilize stabilize((CSafeRefCount *)this);
|
|
|
|
if (pDataObj)
|
|
VDATEIFACE(pDataObj);
|
|
|
|
VDATEPTRIN(pFetc, FORMATETC);
|
|
VDATEIFACE(pAdvSink);
|
|
|
|
if (!HasValidLINDEX(pFetc))
|
|
{
|
|
return(DV_E_LINDEX);
|
|
}
|
|
|
|
// Validate where to return the connection.
|
|
if (pdwConnection)
|
|
{
|
|
VDATEPTRIN(pdwConnection, DWORD);
|
|
|
|
// Default to error case
|
|
*pdwConnection = 0;
|
|
}
|
|
|
|
// scan and remove all unconnected advise sinks
|
|
for(iSDFree = (-1), pSD = m_pSD, iSDScan = 0; iSDScan < m_iSize;
|
|
++pSD, ++iSDScan)
|
|
{
|
|
// REVIEW, why do we have to go polling these?
|
|
if (!pSD->pAdvSink || !IsValidInterface(pSD->pAdvSink))
|
|
{
|
|
// not valid, don't try to release
|
|
pSD->pAdvSink = NULL;
|
|
goto RemoveBadSD;
|
|
}
|
|
else if (!CoIsHandlerConnected(pSD->pAdvSink))
|
|
{
|
|
// sink no longer connected, release
|
|
RemoveBadSD:
|
|
// release any data. UtReleaseStatData will
|
|
// zero out the statdata structure.
|
|
UtReleaseStatData(pSD);
|
|
|
|
}
|
|
|
|
// if we're still looking for a free entry, note if this one
|
|
// is free
|
|
if ((iSDFree == (-1)) && (pSD->dwConnection == 0))
|
|
iSDFree = iSDScan;
|
|
}
|
|
|
|
// should we send the data immediately?
|
|
if (advf & ADVF_PRIMEFIRST)
|
|
{
|
|
// We are not going to honor ADVF_PRIMEFIRST if pDataObj is
|
|
// NULL, even when ADVF_NODATA is specfied. We want it to be
|
|
// this way so that the apps which don't have any data at
|
|
// startup time, could pass in NULL for pDataObject and
|
|
// prevent us from sending any OnDataChange() notification.
|
|
// Later when they have the data avaliable they can call
|
|
// SendOnDataChange. (SRINIK)
|
|
|
|
if (pDataObj)
|
|
{
|
|
STGMEDIUM stgmed;
|
|
|
|
stgmed.tymed = TYMED_NULL;
|
|
stgmed.pUnkForRelease = NULL;
|
|
|
|
if (advf & ADVF_NODATA)
|
|
{
|
|
// don't sent data, send only the notification
|
|
pAdvSink->OnDataChange(pFetc, &stgmed);
|
|
|
|
}
|
|
else
|
|
{
|
|
// get data from object and send it to sink
|
|
if (pDataObj->GetData(pFetc,
|
|
&stgmed) == NOERROR)
|
|
{
|
|
pAdvSink->OnDataChange(pFetc, &stgmed);
|
|
ReleaseStgMedium(&stgmed);
|
|
}
|
|
}
|
|
|
|
// if we only have to advise once, we've done so, and
|
|
// needn't make an entry in the advise array
|
|
if (advf & ADVF_ONLYONCE)
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
// remove the ADVF_PRIMEFIRST from flags.
|
|
advf &= (~ADVF_PRIMEFIRST);
|
|
|
|
// find a free list entry we can use, if we haven't got one
|
|
if (iSDFree == (-1))
|
|
{
|
|
HRESULT hr;
|
|
|
|
// REVIEW, can we share array reallocation code with
|
|
// oaholder.cpp? Why can't we just use realloc?
|
|
|
|
// didn't find any free array entries above; since that
|
|
// scanned the whole array, have to allocate new entries
|
|
// here
|
|
|
|
pSD = (STATDATA FAR *)PubMemAlloc(sizeof(STATDATA)*(m_iSize+
|
|
CDAHOLDER_GROWBY));
|
|
|
|
if (pSD == NULL)
|
|
hr = ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
else
|
|
{
|
|
// copy the old data over, if any, and free it
|
|
if (m_pSD)
|
|
{
|
|
_xmemcpy((void FAR *)pSD, (void FAR *)m_pSD,
|
|
sizeof(STATDATA)*m_iSize);
|
|
|
|
PubMemFree(m_pSD);
|
|
}
|
|
|
|
// initialize newly allocated memory
|
|
|
|
_xmemset((void FAR *)(pSD+m_iSize), 0,
|
|
sizeof(STATDATA)*CDAHOLDER_GROWBY);
|
|
|
|
// this is the index of the first free element
|
|
iSDFree = m_iSize;
|
|
|
|
// set up the STATDATA array
|
|
m_pSD = pSD;
|
|
m_iSize += CDAHOLDER_GROWBY;
|
|
|
|
hr = NOERROR;
|
|
}
|
|
|
|
if (hr != NOERROR)
|
|
{
|
|
return(hr);
|
|
}
|
|
}
|
|
|
|
// if we got here, we can add the new entry, and its index is iSDFree
|
|
|
|
// point at the new element
|
|
pSD = m_pSD+iSDFree;
|
|
|
|
// Let the advise get added to the list
|
|
UtCopyFormatEtc(pFetc, &pSD->formatetc);
|
|
pSD->advf = advf;
|
|
pAdvSink->AddRef();
|
|
pSD->pAdvSink = pAdvSink;
|
|
pSD->dwConnection = m_dwConnection++;
|
|
|
|
// return connection if user requested it
|
|
if (pdwConnection)
|
|
*pdwConnection = pSD->dwConnection;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Unadvise, public
|
|
//
|
|
// Synopsis:
|
|
// removes the advise sink specified from the list of those
|
|
// registered to receive notifications from this data advise
|
|
// holder
|
|
//
|
|
// Arguments:
|
|
// [dwConnection] -- token that identifies which advise sink
|
|
// to remove; this will have come from Advise().
|
|
//
|
|
// Returns:
|
|
// OLE_E_NOCONNECTION, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_Unadvise)
|
|
STDMETHODIMP CDAHolder::Unadvise(DWORD dwConnection)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
int iData; // index into the STATDATA array
|
|
STATDATA FAR *pSD; // pointer into the STATDATA array
|
|
|
|
// protect this against being released via a circular reference
|
|
CStabilize stabilize((CSafeRefCount *)this);
|
|
|
|
for (pSD = m_pSD, iData = 0; iData < m_iSize; ++pSD, ++iData)
|
|
{
|
|
// is this the entry we're looking for?
|
|
if (pSD->dwConnection == dwConnection)
|
|
{
|
|
// release resources for the entry. UtReleaseStatData
|
|
// will zero the statdata.
|
|
|
|
UtReleaseStatData(pSD);
|
|
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
// if we found what we were looking for in the loop, we'd return
|
|
// from there, and never get here. Since we didn't, it must be
|
|
// that there's no such connection
|
|
return ReportResult(0, OLE_E_NOCONNECTION, 0, 0);
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::SendOnDataChange, public
|
|
//
|
|
// Synopsis:
|
|
// Send an OnDataChange notification to all advise sinks
|
|
// registered with this data advise holder.
|
|
//
|
|
// Arguments:
|
|
// [pDataObject] -- the data object to get data from to send
|
|
// to the advise sinks
|
|
// [dwReserved] --
|
|
// [advf] -- control flags
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
// More than one advise sink may be interested in obtaining
|
|
// data in the same format. It may be expensive for the data
|
|
// object to create copies of the data in requested formats.
|
|
// Therefore, when a change is signalled, the data formats
|
|
// are cached. As each advise sink is to be notified, we
|
|
// check to see if the format it is requesting has already been
|
|
// gotten from the data object (with GetData().) If it has,
|
|
// then we simply send that copy again. If not, we get the
|
|
// new format, and add that to the cache.
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_SendOnDataChange)
|
|
STDMETHODIMP CDAHolder::SendOnDataChange(IDataObject FAR* pDataObject,
|
|
DWORD dwReserved, DWORD advf)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
A5_PROLOG(this);
|
|
HRESULT hresult = NOERROR; // error status so far
|
|
UINT cFetcTotal; // maximum number of formats we will cache
|
|
UINT cFetcGotten; // the actual number of formats in the cache
|
|
UINT cFetc; // the index of the format in the cache under consideration
|
|
FORMATETC FAR* rgFetc; // a record of the cached presentations
|
|
STGMEDIUM FAR* rgStgmed; // the cached data presentations
|
|
UINT cStatData; // a counter for the STATDATA array elements
|
|
STATDATA FAR *pSD; // a pointer into the array of STATDATA elements
|
|
|
|
VDATEIFACE(pDataObject);
|
|
|
|
// in the worst case, every advise sink has requested a unique
|
|
// data format, and we won't get any duplicates. This means that
|
|
// we will wind up caching all of them.
|
|
cFetcTotal = m_iSize;
|
|
|
|
// if there are no entries, there's nothing to do
|
|
if (cFetcTotal == 0)
|
|
return NOERROR;
|
|
|
|
// some advise sinks may use these notifications to change their
|
|
// requested notifications; due to possible circular references,
|
|
// this could to lead to a release of this holder. Protect against
|
|
// this here; this is released after most work is done, towards the
|
|
// end of this function
|
|
CStabilize stabilize((CSafeRefCount *)this);
|
|
|
|
// alloc rgFetc and rgStgmed to accomodate all the cache entries
|
|
// if either fails to be allocated, we quit
|
|
rgFetc = (FORMATETC FAR *)PubMemAlloc(cFetcTotal * sizeof(FORMATETC));
|
|
rgStgmed = (STGMEDIUM FAR *)PubMemAlloc(cFetcTotal * sizeof(STGMEDIUM));
|
|
|
|
if (rgFetc == NULL || rgStgmed == NULL)
|
|
{
|
|
hresult = ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
goto FreeExit;
|
|
}
|
|
|
|
// zero out STDMEDIUM entries
|
|
_xmemset((void FAR *)rgStgmed, 0, sizeof(STGMEDIUM)*cFetcTotal);
|
|
|
|
// ensure we have the right data and send to each advise sink
|
|
// note the loop is bounded by cFetcTotal, preventing additional
|
|
// sinks from being notified, if they are registered during these
|
|
// notifications. cStatData is not used in the loop body, so it
|
|
// counts down
|
|
|
|
for (cFetcGotten = 0, pSD = m_pSD, cStatData = cFetcTotal;
|
|
cStatData; ++pSD, --cStatData)
|
|
{
|
|
// if this slot is not in use, skip it
|
|
if (!pSD->dwConnection)
|
|
continue;
|
|
|
|
// if the sink is not interested in presentation data,
|
|
// proceed to notify it immediately, unless this notification
|
|
// is announcing the termination of the source
|
|
if ((pSD->advf & ADVF_NODATA) &&
|
|
!(advf & ADVF_DATAONSTOP))
|
|
{
|
|
STGMEDIUM stgmed;
|
|
|
|
// don't sent data; use format from collection
|
|
// and null STGMEDIUM.
|
|
// REVIEW, should this be done once, up above?
|
|
stgmed.tymed = TYMED_NULL;
|
|
stgmed.pUnkForRelease = NULL;
|
|
pSD->pAdvSink->OnDataChange(&pSD->formatetc, &stgmed);
|
|
|
|
// REVIEW, what does this do for NULL?
|
|
// if nothing, we can share a stdmedNULL, as above
|
|
ReleaseStgMedium(&stgmed);
|
|
|
|
// clean up at end of loop
|
|
goto DataSent;
|
|
}
|
|
|
|
// if the sink is interested in data at the time of
|
|
// termination, and the source is not terminating, OR, the
|
|
// sink is not interested in data at the time of termination,
|
|
// and we are terminating, skip this sink, and proceed
|
|
if ((pSD->advf & ADVF_DATAONSTOP) !=
|
|
(advf & ADVF_DATAONSTOP))
|
|
continue;
|
|
|
|
// check the requested format against the list of formats
|
|
// for which we've already retrieved the presentation data.
|
|
// if there is a match, proceed to send that data immediately
|
|
// from here on in this loop body, cFetc is the index of the
|
|
// data presentation to send to the current sink
|
|
// REVIEW PERF: this is an n-squared algorithm;
|
|
// we check the array of cached presentations for each
|
|
// advise sink
|
|
for (cFetc = 0; cFetc < cFetcGotten; ++cFetc)
|
|
{
|
|
// if match, continue outer loop
|
|
if (UtCompareFormatEtc(&rgFetc[cFetc],
|
|
&pSD->formatetc) == UTCMPFETC_EQ)
|
|
goto SendThisOne;
|
|
}
|
|
|
|
// if we get here, we have not already fetched presentation
|
|
// data that matches the requested format
|
|
|
|
// init FORMATETC (copy of needed one)
|
|
// STDMEDIUM was initialized after its allocation to all NULL
|
|
rgFetc[cFetcGotten] = pSD->formatetc;
|
|
|
|
// get the data in the requested format from the data object
|
|
// REVIEW: assume STGMEDIUM untouched if error
|
|
// (i.e., still null)
|
|
hresult = pDataObject->GetData(&rgFetc[cFetcGotten],
|
|
&rgStgmed[cFetcGotten]);
|
|
|
|
// REVIEW, what is this checking?
|
|
AssertOutStgmedium(hresult, &rgStgmed[cFetcGotten]);
|
|
|
|
// the presentation to send is the newly cached one
|
|
// there is now one more entry in the cache array
|
|
cFetc = cFetcGotten++;
|
|
|
|
SendThisOne:
|
|
// when we get here, rgFetc[cFetc] is the format to send to the
|
|
// current advise sink
|
|
|
|
// send change notification with requested data
|
|
|
|
// The advise sink could have disappeared in the meantime
|
|
// (if the the GetData call above resulted in an Unadvise,
|
|
// for example), so we must validate the pAdvSInk first.
|
|
// pSD will remain a valid regardless, and the advise
|
|
// flags will have been zero'd, so it is safe to proceed
|
|
// through the loop without "continue"ing.
|
|
|
|
if (pSD->pAdvSink)
|
|
{
|
|
pSD->pAdvSink->OnDataChange(&rgFetc[cFetc],
|
|
&rgStgmed[cFetc]);
|
|
}
|
|
|
|
|
|
DataSent:
|
|
// When we get here, something has been sent, possibly
|
|
// an empty storage medium
|
|
|
|
// if the sink requested to only be notified once, we
|
|
// can free it here
|
|
if (pSD->advf & ADVF_ONLYONCE)
|
|
{
|
|
// free the stat data. UtReleaseStatData will
|
|
// zero the statdata, thus marking the connection
|
|
// as invalid.
|
|
|
|
UtReleaseStatData(pSD);
|
|
|
|
}
|
|
}
|
|
|
|
// free all stgmeds retrieved; FORMATETC.ptd was not allocated
|
|
for (cFetc = 0; cFetc < cFetcGotten; ++cFetc)
|
|
ReleaseStgMedium(&rgStgmed[cFetc]);
|
|
|
|
hresult = NOERROR;
|
|
|
|
FreeExit:
|
|
if (rgFetc != NULL)
|
|
PubMemFree(rgFetc);
|
|
|
|
if (rgStgmed != NULL)
|
|
PubMemFree(rgStgmed);
|
|
|
|
RESTORE_A5();
|
|
|
|
return hresult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CDAHolder::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
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CDAHolder::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszCSafeRefCount;
|
|
char *pszSTATDATA;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump(1000);
|
|
|
|
// 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 << "Next Connection ID = " << m_dwConnection << endl;
|
|
|
|
dstrDump << pszPrefix << "No. of STATDATA elements = " << m_iSize << endl;
|
|
|
|
for (i = 0; i < m_iSize; i++)
|
|
{
|
|
pszSTATDATA = DumpSTATDATA( &m_pSD[i], ulFlag, nIndentLevel + 1) ;
|
|
dstrDump << pszPrefix << "STATDATA element: " << i << endl;
|
|
dstrDump << pszSTATDATA;
|
|
CoTaskMemFree(pszSTATDATA);
|
|
}
|
|
|
|
// clean up and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif //_DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCDAHolder, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CDAHolder::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pIDAH] - pointer to IDAHolder (which we cast to CDAHolder)
|
|
// [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
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
// This API !!REQUIRES!! that class CDAHolder inherits from IDataAdviseHolder
|
|
// first in order that we can pass in a parameter as a pointer to an
|
|
// IDataAdviseHolder and then cast it to a CDAHolder.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCDAHolder(IDataAdviseHolder *pIDAH, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pIDAH == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
CDAHolder *pCDAH = (CDAHolder *)pIDAH;
|
|
|
|
hresult = pCDAH->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CEnumSTATDATA::CEnumSTATDATA, public
|
|
//
|
|
// Synopsis:
|
|
// constructor
|
|
//
|
|
// Effects:
|
|
// sets reference count to 1
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_ctor)
|
|
CEnumSTATDATA::CEnumSTATDATA(CDAHolder FAR* pHolder, int iDataStart)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
GET_A5();
|
|
|
|
// set reference count
|
|
m_refs = 1;
|
|
|
|
// first element to examine for return
|
|
m_iDataEnum = iDataStart;
|
|
|
|
// initialize pointer to holder, and addref, so it doesn't go
|
|
// away while enumerator is alive
|
|
(m_pHolder = pHolder)->AddRef();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::~CDAHolder, private
|
|
//
|
|
// Synopsis:
|
|
// destructor
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_dtor)
|
|
CEnumSTATDATA::~CEnumSTATDATA()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
m_pHolder->Release();
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CEnumSTATDATA::QueryInterface, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::QueryInterface
|
|
//
|
|
// Arguments:
|
|
// [iid] -- IID of the desired interface
|
|
// [ppv] -- pointer to a location to return the interface at
|
|
//
|
|
// Returns:
|
|
// E_NOINTERFACE, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_QueryInterface)
|
|
STDMETHODIMP CEnumSTATDATA::QueryInterface(REFIID iid, LPVOID FAR* ppv)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown) ||
|
|
IsEqualIID(iid, IID_IEnumSTATDATA))
|
|
{
|
|
*ppv = (IEnumSTATDATA FAR *)this;
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
*ppv = NULL;
|
|
return ReportResult(0, E_NOINTERFACE, 0, 0);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CEnumSTATDATA::AddRef, public
|
|
//
|
|
// Synopsis:
|
|
// implements IUnknown::AddRef
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
#pragma SEG(CEnumSTATDATA_AddRef)
|
|
STDMETHODIMP_(ULONG) CEnumSTATDATA::AddRef()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
return ++m_refs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CEnumSTATDATA::Release, public
|
|
//
|
|
// Synopsis:
|
|
// implementa IUnknown::Release
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 10/29/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_Release)
|
|
STDMETHODIMP_(ULONG) CEnumSTATDATA::Release()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
if (--m_refs == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_refs;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CEnumSTATDATA::Next, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Next()
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
// [celt] -- number of elements requested on this call
|
|
// [rgelt] -- pointer to an array of STATDATAs where copies of
|
|
// the elements can be returned
|
|
// [pceltFectched] -- a pointer to where to return the number of
|
|
// elements actually fetched. May be NULL
|
|
//
|
|
// Returns:
|
|
// S_FALSE, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 03/09/94 - AlexGo - the enumerator no longer enumerates
|
|
// "empty" statdata's in the m_pSD array.
|
|
// 11/01/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_Next)
|
|
STDMETHODIMP CEnumSTATDATA::Next(ULONG celt, STATDATA FAR *rgelt,
|
|
ULONG FAR* pceltFetched)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
UINT ielt; // count of the number of elements fetched so far
|
|
|
|
for (ielt = 0; (ielt < celt) && (m_iDataEnum < m_pHolder->m_iSize);
|
|
m_iDataEnum++)
|
|
{
|
|
if( m_pHolder->m_pSD[m_iDataEnum].dwConnection != 0)
|
|
{
|
|
ielt++;
|
|
// copy all bits; AddRef and copy DVTARGETDEVICE
|
|
// separately
|
|
UtCopyStatData(&m_pHolder->m_pSD[m_iDataEnum],
|
|
rgelt++);
|
|
}
|
|
}
|
|
|
|
// return number of elements fetched, if required
|
|
if (pceltFetched)
|
|
*pceltFetched = ielt;
|
|
|
|
// no error, if exactly the requested number of elements was fetched
|
|
return ielt == celt ? NOERROR : ReportResult(0, S_FALSE, 0, 0);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Skip, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Skip
|
|
//
|
|
// Arguments:
|
|
// [celt] -- the number of elements in the collection to skip
|
|
// over
|
|
//
|
|
// Returns:
|
|
// S_FALSE, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/01/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_Skip)
|
|
STDMETHODIMP CEnumSTATDATA::Skip(ULONG celt)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
STATDATA FAR *pSD; // scans over the array of STATDATA entries
|
|
|
|
// if the enumeration would take us off the end of the array
|
|
// mark the enumeration as complete
|
|
if (m_iDataEnum + celt > (ULONG)m_pHolder->m_iSize)
|
|
{
|
|
m_iDataEnum = m_pHolder->m_iSize;
|
|
|
|
return ReportResult(0, S_FALSE, 0, 0);
|
|
}
|
|
|
|
|
|
// skip over valid entries in the array, counting down until
|
|
// we don't have to skip over any more, or until we get to
|
|
// the end of the array
|
|
for(pSD = m_pHolder->m_pSD+m_iDataEnum;
|
|
celt && (m_iDataEnum < m_pHolder->m_iSize);
|
|
++m_iDataEnum)
|
|
{
|
|
// if the connection is valid, count it as a skipped
|
|
// enumerated item
|
|
if (pSD->dwConnection != 0)
|
|
--celt;
|
|
}
|
|
|
|
// if we could skip them all, indicate by non-error return
|
|
if (celt == 0)
|
|
return(NOERROR);
|
|
|
|
return(ReportResult(0, S_FALSE, 0, 0));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Reset, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Reset
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/01/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_Reset)
|
|
STDMETHODIMP CEnumSTATDATA::Reset()
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
// move back to the beginning of the STATDATA array
|
|
m_iDataEnum = 0;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::Clone, public
|
|
//
|
|
// Synopsis:
|
|
// implements IEnumSTATDATA::Clone
|
|
//
|
|
// Arguments:
|
|
// none
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/01/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CEnumSTATDATA_Clone)
|
|
STDMETHODIMP CEnumSTATDATA::Clone(LPENUMSTATDATA FAR* ppenum)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
*ppenum = new FAR CEnumSTATDATA(m_pHolder, m_iDataEnum);
|
|
|
|
return *ppenum ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member:
|
|
// CDAHolder::EnumAdvise, public
|
|
//
|
|
// Synopsis:
|
|
// implements IDataAdviseHolder::EnumAdvise
|
|
//
|
|
// Effects:
|
|
// creates an enumerator for the registered advise sinks
|
|
//
|
|
// Arguments:
|
|
// [ppenumAdvise] -- a pointer to where to return the enumerator
|
|
//
|
|
// Returns:
|
|
// E_OUTOFMEMORY, S_OK
|
|
//
|
|
// Notes:
|
|
//
|
|
// History:
|
|
// 11/01/93 - ChrisWe - file inspection and cleanup
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#pragma SEG(CDAHolder_EnumAdvise)
|
|
STDMETHODIMP CDAHolder::EnumAdvise(IEnumSTATDATA FAR* FAR* ppenumAdvise)
|
|
{
|
|
VDATEHEAP();
|
|
|
|
M_PROLOG(this);
|
|
|
|
VDATEPTROUT(ppenumAdvise, IEnumSTATDATA FAR*);
|
|
|
|
// REVIEW, memory leak if bad ppenumAdvise pointer
|
|
*ppenumAdvise = new FAR CEnumSTATDATA(this, 0);
|
|
|
|
return *ppenumAdvise ? NOERROR : ReportResult(0, E_OUTOFMEMORY, 0, 0);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumSTATDATA::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
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HRESULT CEnumSTATDATA::Dump(char **ppszDump, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
int i;
|
|
char *pszPrefix;
|
|
char *pszDAH;
|
|
dbgstream dstrPrefix;
|
|
dbgstream dstrDump(1000);
|
|
|
|
// 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 = " << m_refs << endl;
|
|
|
|
dstrDump << pszPrefix << "Index to next element = " << m_iDataEnum << endl;
|
|
|
|
if (m_pHolder != NULL)
|
|
{
|
|
pszDAH = DumpCDAHolder(m_pHolder, ulFlag, nIndentLevel + 1);
|
|
dstrDump << pszPrefix << "Data Advise Holder: " << endl;
|
|
dstrDump << pszDAH;
|
|
CoTaskMemFree(pszDAH);
|
|
}
|
|
else
|
|
{
|
|
dstrDump << pszPrefix << "pCDAHolder = " << m_pHolder << endl;
|
|
}
|
|
|
|
// cleanup and provide pointer to character array
|
|
*ppszDump = dstrDump.str();
|
|
|
|
if (*ppszDump == NULL)
|
|
{
|
|
*ppszDump = UtDupStringA(szDumpErrorMessage);
|
|
}
|
|
|
|
CoTaskMemFree(pszPrefix);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpCEnumSTATDATA, public (_DEBUG only)
|
|
//
|
|
// Synopsis: calls the CEnumSTATDATA::Dump method, takes care of errors and
|
|
// returns the zero terminated string
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: [pESD] - pointer to CEnumSTATDATA
|
|
// [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
|
|
// 20-Jan-95 t-ScottH author
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#ifdef _DEBUG
|
|
|
|
char *DumpCEnumSTATDATA(CEnumSTATDATA *pESD, ULONG ulFlag, int nIndentLevel)
|
|
{
|
|
HRESULT hresult;
|
|
char *pszDump;
|
|
|
|
if (pESD == NULL)
|
|
{
|
|
return UtDupStringA(szDumpBadPtr);
|
|
}
|
|
|
|
hresult = pESD->Dump(&pszDump, ulFlag, nIndentLevel);
|
|
|
|
if (hresult != NOERROR)
|
|
{
|
|
CoTaskMemFree(pszDump);
|
|
|
|
return DumpHRESULT(hresult);
|
|
}
|
|
|
|
return pszDump;
|
|
}
|
|
|
|
#endif // _DEBUG
|
|
|