822 lines
21 KiB
C++
822 lines
21 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: propstg.hxx
|
|
//
|
|
// Contents: Class that directly implements IPropertyStorage
|
|
//
|
|
// Classes: CCoTaskAllocator
|
|
// CPropertyStorage
|
|
// CEnumSTATPROPSTG
|
|
//
|
|
// Functions:
|
|
//
|
|
//
|
|
//
|
|
// History: 1-Mar-95 BillMo Created.
|
|
// 25-Jan-96 MikeHill Added _fmtidSection.
|
|
// 22-May-96 MikeHill Added _dwOSVersion to CPropertyStorage.
|
|
// 06-Jun-96 MikeHill Added support for input validation.
|
|
// 18-Aug-96 MikeHill - Added CDocFilePropertyStorage.
|
|
// 07-Feb-97 Danl - Removed CDocFilePropertyStorage.
|
|
// 18-Aug-98 MikeHill Probe stream in IsWriteable.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CCoTaskAllocator
|
|
//
|
|
// Purpose: Class used by PrQueryProperties to allocate memory.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CCoTaskAllocator : public PMemoryAllocator
|
|
{
|
|
public:
|
|
virtual void *Allocate(ULONG cbSize);
|
|
virtual void Free(void *pv);
|
|
|
|
};
|
|
|
|
|
|
extern const OLECHAR g_oszPropertyContentsStreamName[];
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CPropertyStorage
|
|
//
|
|
// Purpose: Implements IPropertyStorage.
|
|
//
|
|
// Notes: This class uses the functionality provided by
|
|
// PrCreatePropertySet, PrSetProperties, PrQueryProperties etc
|
|
// to manipulate the property set stream.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define PROPERTYSTORAGE_SIG LONGSIG('P','R','P','S')
|
|
#define PROPERTYSTORAGE_SIGDEL LONGSIG('P','R','P','s')
|
|
#define PROPERTYSTORAGE_SIGZOMBIE LONGSIG('P','R','P','z')
|
|
#define ENUMSTATPROPSTG_SIG LONGSIG('E','P','S','S')
|
|
#define ENUMSTATPROPSTG_SIGDEL LONGSIG('E','P','S','s')
|
|
|
|
// Prototype for test function
|
|
WORD GetFormatVersion( IPropertyStorage *ppropstg );
|
|
|
|
class CPropertyStorage : public IPropertyStorage
|
|
#if DBG
|
|
, public IStorageTest
|
|
#endif
|
|
{
|
|
friend WORD GetFormatVersion(IPropertyStorage *ppropstg); // Used for test only
|
|
|
|
// ------------
|
|
// Constructors
|
|
// ------------
|
|
|
|
public:
|
|
|
|
// The destructor must be virtual so that derivative destructors
|
|
// will execute.
|
|
|
|
virtual ~CPropertyStorage();
|
|
|
|
CPropertyStorage(MAPPED_STREAM_OPTS fMSOpts)
|
|
{
|
|
_fInitCriticalSection = FALSE;
|
|
_fMSOpts = fMSOpts;
|
|
Initialize();
|
|
|
|
#ifndef _MAC
|
|
__try
|
|
{
|
|
InitializeCriticalSection( &_CriticalSection );
|
|
_fInitCriticalSection = TRUE;
|
|
}
|
|
__except( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// --------
|
|
// IUnknown
|
|
// --------
|
|
public:
|
|
|
|
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
|
|
|
|
STDMETHOD_(ULONG, AddRef)(void);
|
|
|
|
STDMETHOD_(ULONG, Release)(void);
|
|
|
|
// ----------------
|
|
// IPropertyStorage
|
|
// ----------------
|
|
public:
|
|
|
|
STDMETHOD(ReadMultiple)(
|
|
ULONG cpspec,
|
|
const PROPSPEC rgpspec[],
|
|
PROPVARIANT rgpropvar[]);
|
|
|
|
STDMETHOD(WriteMultiple)(
|
|
ULONG cpspec,
|
|
const PROPSPEC rgpspec[],
|
|
const PROPVARIANT rgpropvar[],
|
|
PROPID propidNameFirst);
|
|
|
|
STDMETHOD(DeleteMultiple)(
|
|
ULONG cpspec,
|
|
const PROPSPEC rgpspec[]);
|
|
|
|
STDMETHOD(ReadPropertyNames)(
|
|
ULONG cpropid,
|
|
const PROPID rgpropid[],
|
|
LPOLESTR rglpwstrName[]);
|
|
|
|
STDMETHOD(WritePropertyNames)(
|
|
ULONG cpropid,
|
|
const PROPID rgpropid[],
|
|
const LPOLESTR rglpwstrName[]);
|
|
|
|
STDMETHOD(DeletePropertyNames)(
|
|
ULONG cpropid,
|
|
const PROPID rgpropid[]);
|
|
|
|
STDMETHOD(Commit)(DWORD grfCommitFlags);
|
|
|
|
STDMETHOD(Revert)();
|
|
|
|
STDMETHOD(Enum)(IEnumSTATPROPSTG ** ppenum);
|
|
|
|
STDMETHOD(SetTimes)(
|
|
FILETIME const * pctime,
|
|
FILETIME const * patime,
|
|
FILETIME const * pmtime);
|
|
|
|
STDMETHOD(SetClass)(REFCLSID clsid);
|
|
|
|
STDMETHOD(Stat)(STATPROPSETSTG * pstatpsstg);
|
|
|
|
// ------------
|
|
// IStorageTest
|
|
// ------------
|
|
public:
|
|
|
|
#if DBG
|
|
STDMETHOD(UseNTFS4Streams)( BOOL fUseNTFS4Streams );
|
|
STDMETHOD(GetFormatVersion)(WORD *pw);
|
|
STDMETHOD(SimulateLowMemory)( BOOL fSimulate );
|
|
STDMETHOD(GetLockCount)();
|
|
STDMETHOD(IsDirty)();
|
|
#endif
|
|
|
|
|
|
// -----------------------------
|
|
// Exposed non-interface methods
|
|
// -----------------------------
|
|
|
|
public:
|
|
|
|
|
|
HRESULT Create(
|
|
IStream *stm,
|
|
REFFMTID rfmtid,
|
|
const CLSID *pclsid,
|
|
DWORD grfFlags,
|
|
DWORD grfMode );
|
|
|
|
HRESULT Create(
|
|
IStorage *pstg,
|
|
REFFMTID rfmtid,
|
|
const CLSID *pclsid,
|
|
DWORD grfFlags,
|
|
DWORD grfMode );
|
|
|
|
HRESULT Open(
|
|
IStorage *pstg,
|
|
REFFMTID rfmtid,
|
|
DWORD grfFlags,
|
|
DWORD grfMode );
|
|
|
|
HRESULT Open(
|
|
IStream *pstm,
|
|
REFFMTID rfmtid,
|
|
DWORD grfFlags,
|
|
DWORD grfMode,
|
|
BOOL fDelete );
|
|
|
|
// used by implementation helper classes
|
|
inline NTPROP GetNtPropSetHandle(void) { return _np; }
|
|
|
|
// ----------------
|
|
// Internal Methods
|
|
// ----------------
|
|
|
|
private:
|
|
|
|
void Initialize();
|
|
HRESULT InitializeOnCreateOrOpen(
|
|
DWORD grfFlags,
|
|
DWORD grfMode,
|
|
REFFMTID rfmtid,
|
|
BOOL fCreate );
|
|
|
|
VOID CleanupOpenedObjects(
|
|
PROPVARIANT avar[],
|
|
INDIRECTPROPERTY * pip,
|
|
ULONG cpspec,
|
|
ULONG iFailIndex);
|
|
|
|
enum EInitializePropertyStream
|
|
{
|
|
OPEN_PROPSTREAM,
|
|
CREATE_PROPSTREAM,
|
|
DELETE_PROPSTREAM
|
|
};
|
|
|
|
HRESULT InitializePropertyStream(
|
|
const GUID * pguid,
|
|
GUID const * pclsid,
|
|
EInitializePropertyStream CreateOpenDelete );
|
|
|
|
HRESULT _WriteMultiple(
|
|
ULONG cpspec,
|
|
const PROPSPEC rgpspec[],
|
|
const PROPVARIANT rgpropvar[],
|
|
PROPID propidNameFirst);
|
|
|
|
HRESULT _WritePropertyNames(
|
|
ULONG cpropid,
|
|
const PROPID rgpropid[],
|
|
const LPOLESTR rglpwstrName[]);
|
|
|
|
BOOL ProbeStreamToDetermineIfWriteable();
|
|
|
|
virtual HRESULT CreateMappedStream( );
|
|
virtual void DeleteMappedStream( );
|
|
|
|
VOID Lock();
|
|
VOID Unlock();
|
|
VOID AssertLocked();
|
|
|
|
|
|
inline HRESULT Validate();
|
|
inline HRESULT ValidateRef();
|
|
|
|
inline HRESULT ValidateRGPROPSPEC( ULONG cpspec, const PROPSPEC rgpropspec[] );
|
|
inline HRESULT ValidateRGPROPID( ULONG cpropid, const PROPID rgpropid[] );
|
|
HRESULT ValidateVTs( ULONG cprops, const PROPVARIANT rgpropvar[] );
|
|
|
|
enum EIsWriteable
|
|
{
|
|
PROBE_IF_NECESSARY,
|
|
DO_NOT_PROBE
|
|
};
|
|
|
|
inline BOOL IsNonSimple();
|
|
inline BOOL IsSimple();
|
|
inline BOOL IsWriteable( EIsWriteable ProbeEnum = PROBE_IF_NECESSARY );
|
|
inline BOOL IsReadable();
|
|
inline BOOL IsReverted();
|
|
|
|
inline DWORD GetChildCreateMode();
|
|
inline DWORD GetChildOpenMode();
|
|
|
|
// -------------
|
|
// Internal Data
|
|
// -------------
|
|
|
|
private:
|
|
|
|
ULONG _ulSig;
|
|
LONG _cRefs;
|
|
IStorage * _pstgPropSet;
|
|
IStream * _pstmPropSet;
|
|
NTPROP _np;
|
|
IMappedStream * _ms;
|
|
MAPPED_STREAM_OPTS _fMSOpts;
|
|
|
|
#ifndef _MAC
|
|
BOOL _fInitCriticalSection;
|
|
CRITICAL_SECTION _CriticalSection;
|
|
#endif
|
|
|
|
#if DBG
|
|
LONG _cLocks;
|
|
#endif
|
|
|
|
// We need to remember if the property set is the second section
|
|
// of the DocumentSummaryInformation property set used by Office. This
|
|
// is the only case where we support a multiple-section property set, and
|
|
// requires special handling in ::Revert().
|
|
|
|
BOOL _fUserDefinedProperties:1;
|
|
|
|
// If _grfMode is zero, maybe it's valid and really zero, or maybe
|
|
// we're dealing with a stream that doesn't return the grfMode in the
|
|
// Stat (such as is the case with CreateStreamFromHGlobal). So if we
|
|
// get a zero _grfMode, we probe the stream to determine if it's writeable.
|
|
// This flag ensures we only do it once.
|
|
|
|
BOOL _fExplicitelyProbedForWriteAccess:1;
|
|
|
|
|
|
USHORT _usCodePage; // Ansi Codepage or Mac Script
|
|
// (disambiguate with _dwOSVersion)
|
|
ULONG _dwOSVersion; // Shows the OS Kind, major/minor version
|
|
|
|
|
|
DWORD _grfFlags; // PROPSETFLAG_NONSIMPLE and PROPSETFLAG_ANSI
|
|
DWORD _grfMode; // STGM_ flags
|
|
|
|
// The following is a PMemoryAllocator for the Rtl property
|
|
// set routines. This instantiation was formerly a file-global
|
|
// in propstg.cxx. However, on the Mac, the object was not
|
|
// being instantiated.
|
|
|
|
CCoTaskAllocator _cCoTaskAllocator;
|
|
|
|
};
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::Validate
|
|
//
|
|
// Synopsis: S_OK if signature valid and not zombie.
|
|
//
|
|
// Notes: If the Revert calls fails due to low memory, then
|
|
// the object becomes a zombie.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CPropertyStorage::Validate()
|
|
{
|
|
if(!_fInitCriticalSection)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (_ulSig == PROPERTYSTORAGE_SIG)
|
|
return S_OK;
|
|
else
|
|
if (_ulSig == PROPERTYSTORAGE_SIGZOMBIE)
|
|
return STG_E_INSUFFICIENTMEMORY;
|
|
else
|
|
return STG_E_INVALIDHANDLE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::ValidateRef
|
|
//
|
|
// Synopsis: S_OK if signature valid.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CPropertyStorage::ValidateRef()
|
|
{
|
|
if (_ulSig == PROPERTYSTORAGE_SIG || _ulSig == PROPERTYSTORAGE_SIGZOMBIE)
|
|
return(S_OK);
|
|
else
|
|
return(STG_E_INVALIDHANDLE);
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::AssertLocked
|
|
//
|
|
// Synopsis: Asserts if _cLocks is <= zero.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline VOID CPropertyStorage::AssertLocked()
|
|
{
|
|
DfpAssert( 0 < _cLocks );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::ValidateRGPROPSPEC
|
|
//
|
|
// Synopsis: S_OK if PROPSPEC[] is valid
|
|
// E_INVALIDARG otherwise.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CPropertyStorage::ValidateRGPROPSPEC( ULONG cpspec,
|
|
const PROPSPEC rgpropspec[] )
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
// Validate the array itself.
|
|
|
|
VDATESIZEREADPTRIN_LABEL(rgpropspec, cpspec * sizeof(PROPSPEC), errRet, hr);
|
|
|
|
// Validate the elements of the array.
|
|
|
|
for( ; cpspec > 0; cpspec-- )
|
|
{
|
|
// Is this an LPWSTR?
|
|
if( PRSPEC_LPWSTR == rgpropspec[cpspec-1].ulKind )
|
|
{
|
|
// We better at least be able to read the first
|
|
// character.
|
|
VDATEREADPTRIN_LABEL(rgpropspec[cpspec-1].lpwstr, WCHAR, errRet, hr);
|
|
}
|
|
|
|
// Otherwise, this better be a PROPID.
|
|
else if( PRSPEC_PROPID != rgpropspec[cpspec-1].ulKind )
|
|
{
|
|
goto errRet;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
errRet:
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::ValidateRGPROPID
|
|
//
|
|
// Synopsis: S_OK if RGPROPID[] is valid for Read.
|
|
// E_INVALIDARG otherwise.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CPropertyStorage::ValidateRGPROPID( ULONG cpropid,
|
|
const PROPID rgpropid[] )
|
|
{
|
|
HRESULT hr;
|
|
VDATESIZEREADPTRIN_LABEL( rgpropid, cpropid * sizeof(PROPID), errRet, hr );
|
|
hr = S_OK;
|
|
|
|
errRet:
|
|
|
|
return( hr );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::IsNonSimple
|
|
//
|
|
// Synopsis: true if non-simple
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline BOOL CPropertyStorage::IsNonSimple()
|
|
{
|
|
AssertLocked();
|
|
return (_grfFlags & PROPSETFLAG_NONSIMPLE) != 0;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::IsSimple
|
|
//
|
|
// Synopsis: true if simple
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline BOOL CPropertyStorage::IsSimple()
|
|
{
|
|
AssertLocked();
|
|
return !IsNonSimple();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::IsWriteable
|
|
//
|
|
// Synopsis: Returns TRUE if writeable, FALSE otherwise.
|
|
//
|
|
// If _grfMode is zero, we may actually have a writeable
|
|
// stream, but _grfMode wasn't returned in IStream::Stat.
|
|
// So unless explicitely told not to, we'll probe for
|
|
// write access. If explicitely told not to
|
|
// (by passing DO_NOT_PROBE), we'll assume that it's
|
|
// read-only.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline BOOL CPropertyStorage::IsWriteable( EIsWriteable ProbeEnum )
|
|
{
|
|
AssertLocked();
|
|
|
|
if( ::GrfModeIsWriteable(_grfMode) )
|
|
return( TRUE );
|
|
|
|
if( 0 != _grfMode || _fExplicitelyProbedForWriteAccess )
|
|
// It's explicitely not writeable
|
|
return( FALSE );
|
|
else
|
|
{
|
|
// It's either STGM_READ|STGM_DENYNONE, or _grfMode
|
|
// wasn't set.
|
|
|
|
if( PROBE_IF_NECESSARY == ProbeEnum )
|
|
return( ProbeStreamToDetermineIfWriteable() );
|
|
else
|
|
return( FALSE ); // Play it safe and assume read-only.
|
|
}
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::IsReadable
|
|
//
|
|
// Synopsis: S_OK if readable otherwise STG_E_ACCESSDENIED
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline BOOL CPropertyStorage::IsReadable()
|
|
{
|
|
AssertLocked();
|
|
return( ::GrfModeIsReadable(_grfMode) );
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CPropertyStorage::IsReverted
|
|
//
|
|
// Synopsis: TRUE if reverted, FALSE otherwise.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline BOOL CPropertyStorage::IsReverted()
|
|
{
|
|
IUnknown *punk = NULL;
|
|
HRESULT hr = S_OK;
|
|
BOOL fReverted = FALSE;
|
|
|
|
AssertLocked();
|
|
|
|
if( (NULL == _pstgPropSet) && (NULL == _pstmPropSet) )
|
|
return( TRUE );
|
|
|
|
hr = (IsNonSimple() ? (IUnknown*)_pstgPropSet : (IUnknown*)_pstmPropSet) ->
|
|
QueryInterface(IID_IUnknown, (void**)&punk);
|
|
|
|
// Note: On older Mac implementations, memory-based streams will
|
|
// return E_NOINTERFACE here, due to a bug in the QueryInterface
|
|
// implementation.
|
|
|
|
if( STG_E_REVERTED == hr )
|
|
fReverted = TRUE;
|
|
else
|
|
fReverted = FALSE;;
|
|
|
|
if( SUCCEEDED(hr) )
|
|
punk->Release();
|
|
|
|
return( fReverted );
|
|
}
|
|
|
|
|
|
|
|
inline DWORD
|
|
CPropertyStorage::GetChildCreateMode()
|
|
{
|
|
DWORD dwMode;
|
|
AssertLocked();
|
|
|
|
dwMode = _grfMode & ~(STGM_SHARE_MASK|STGM_TRANSACTED);
|
|
dwMode |= STGM_SHARE_EXCLUSIVE | STGM_CREATE;
|
|
return( dwMode );
|
|
}
|
|
|
|
inline DWORD
|
|
CPropertyStorage::GetChildOpenMode()
|
|
{
|
|
AssertLocked();
|
|
return( GetChildCreateMode() & ~STGM_CREATE );
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: IStatArray
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
interface IStatArray : public IUnknown
|
|
{
|
|
|
|
public:
|
|
|
|
virtual NTSTATUS NextAt( ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched )=0;
|
|
|
|
};
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CStatArray
|
|
//
|
|
// Purpose: Class to allow sharing of enumeration STATPROPSTG state.
|
|
//
|
|
// Interface: CStatArray -- Enumerate entire NTPROP np.
|
|
// NextAt -- Perform an OLE-type Next operation starting at
|
|
// specified offset.
|
|
// AddRef -- for sharing of this by CEnumSTATPROPSTG
|
|
// Release -- ditto
|
|
//
|
|
// Notes: Each IEnumSTATPROPSTG instance has a reference to a
|
|
// CStatArray. When IEnumSTATPROPSTG::Clone is called, a
|
|
// new reference to the extant CStatArray is used: no copying.
|
|
//
|
|
// The CEnumSTATPROPSTG has a cursor into the CStatArray.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CStatArray : public IStatArray
|
|
{
|
|
public:
|
|
|
|
CStatArray( NTPROP np, HRESULT *phr );
|
|
|
|
private:
|
|
|
|
~CStatArray();
|
|
|
|
public:
|
|
|
|
STDMETHODIMP QueryInterface ( REFIID riid, void **ppvObject);
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
public:
|
|
|
|
NTSTATUS NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched);
|
|
|
|
private:
|
|
|
|
LONG _cRefs;
|
|
STATPROPSTG * _psps;
|
|
ULONG _cpropActual;
|
|
};
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CEnumSTATPROPSTG
|
|
//
|
|
// Purpose: Implement IEnumSTATPROPSTG
|
|
//
|
|
// Notes: Just holds a reference to a CStatArray that contains
|
|
// a static copy of the enumeration when the original
|
|
// Enum call was made. This object contains the cursor
|
|
// into the CStatArray.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NTSTATUS CopySTATPROPSTG( ULONG celt, STATPROPSTG * pspsDest, const STATPROPSTG * pspsSrc);
|
|
|
|
class CEnumSTATPROPSTG : public IEnumSTATPROPSTG
|
|
{
|
|
// ------------
|
|
// Construction
|
|
// ------------
|
|
public:
|
|
|
|
CEnumSTATPROPSTG( IStatArray *psa ): _ulSig(ENUMSTATPROPSTG_SIG),
|
|
_ipropNext(0),
|
|
_psa(psa),
|
|
_cRefs(1)
|
|
{
|
|
_psa->AddRef();
|
|
}
|
|
|
|
CEnumSTATPROPSTG(const CEnumSTATPROPSTG &other );
|
|
|
|
// -----------
|
|
// Destruction
|
|
// -----------
|
|
private:
|
|
|
|
~CEnumSTATPROPSTG();
|
|
|
|
// ----------------
|
|
// IUnknown Methods
|
|
// ----------------
|
|
|
|
public:
|
|
|
|
STDMETHOD(QueryInterface)( REFIID riid, void **ppvObject);
|
|
STDMETHOD_(ULONG, AddRef)(void);
|
|
STDMETHOD_(ULONG, Release)(void);
|
|
|
|
// -------------
|
|
// IEnum Methods
|
|
// -------------
|
|
|
|
public:
|
|
|
|
STDMETHOD(Skip)(ULONG celt);
|
|
STDMETHOD(Reset)();
|
|
STDMETHOD(Clone)(IEnumSTATPROPSTG ** ppenum);
|
|
|
|
// We don't need RemoteNext.
|
|
STDMETHOD(Next)(ULONG celt, STATPROPSTG * rgelt, ULONG * pceltFetched);
|
|
|
|
// ----------------
|
|
// Internal Methods
|
|
// ----------------
|
|
|
|
private:
|
|
|
|
HRESULT Validate();
|
|
|
|
|
|
// --------------
|
|
// Internal State
|
|
// --------------
|
|
|
|
private:
|
|
|
|
|
|
ULONG _ulSig;
|
|
LONG _cRefs;
|
|
|
|
IStatArray * _psa;
|
|
ULONG _ipropNext;
|
|
};
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CEnumSTATPROPSTG::Validate
|
|
//
|
|
// Synopsis: S_OK if signature is valid, otherwise error
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CEnumSTATPROPSTG::Validate()
|
|
{
|
|
return _ulSig == ENUMSTATPROPSTG_SIG ? S_OK : STG_E_INVALIDHANDLE;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CheckFlagsOnCreateOrOpen
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
inline HRESULT CheckFlagsOnCreateOrOpen(
|
|
BOOL fCreate,
|
|
DWORD grfMode
|
|
)
|
|
{
|
|
// Check for any mode disallowed flags
|
|
if (grfMode & ( (fCreate ? 0 : STGM_CREATE)
|
|
|
|
|
STGM_PRIORITY | STGM_CONVERT
|
|
|
|
|
STGM_DELETEONRELEASE ))
|
|
{
|
|
return (STG_E_INVALIDFLAG);
|
|
}
|
|
|
|
// Ensure that we'll have read/write access to any storage/stream we create.
|
|
// If grfMode is zero, assume that it's uninitialized and that we'll have
|
|
// read/write access. If we don't, the client will still get an error
|
|
// at some point, just not in the open path.
|
|
|
|
if( fCreate
|
|
&&
|
|
(grfMode & STGM_READWRITE) != STGM_READWRITE
|
|
&&
|
|
0 != grfMode )
|
|
{
|
|
return (STG_E_INVALIDFLAG);
|
|
}
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
|
|
|