|
|
//+-------------------------------------------------------------------------
//
// 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); }
|