|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: propstg.hxx
//
// Contents: Class that directly implements IPropertyStorage
//
// Classes: CCoTaskAllocator
// CPropertyStorage
// CEnumSTATPROPSTG
//
// Functions:
//
// Notes:
//
//--------------------------------------------------------------------------
#include "../h/ref.hxx"
#include "h/stgprops.hxx"
//+-------------------------------------------------------------------------
//
// Class: CCoTaskAllocator
//
// Purpose: Class used by RtlQueryProperties to allocate memory.
//
//--------------------------------------------------------------------------
class CCoTaskAllocator : public PMemoryAllocator { public: virtual void *Allocate(ULONG cbSize); virtual void Free(void *pv); };
//+-------------------------------------------------------------------------
//
// Class: CPropertyStorage
//
// Purpose: Implements IPropertyStorage for docfile and native file systems.
//
// Notes: This class uses the functionality provided by
// RtlCreatePropertySet, RtlSetProperties, RtlQueryProperties etc
// to manipulate the property set stream.
//
// The constructors (one for create, one for open) create
// an NTPROP (expected by RtlSetProperties etc) with the
// correct type of NTMAPPEDSTREAM (CExposedStream::CPubMappedStream
// to handle making a docfile stream look like a real memory mapped
// stream, and CNtMappedStream, created by RtlCreateMappedStream,
// for native file systems.)
//
//--------------------------------------------------------------------------
#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')
class CPropertyStorage : public IPropertyStorage { public: CPropertyStorage( // create ctor
IPrivateStorage * pprivstg, REFFMTID rfmtid, const CLSID * pclsid, DWORD grfFlags, DWORD grfMode, HRESULT * phr);
CPropertyStorage( // open ctor
IPrivateStorage * pprivstg, REFFMTID rfmtid, DWORD grfMode, BOOL fDelete, HRESULT * phr);
~CPropertyStorage();
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // IPropertyStorage
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);
// used by implementation helper classes
inline NTPROP GetNtPropSetHandle(void) { return _np; } private: VOID Initialize();
HRESULT InitializePropertyStream( USHORT Flags, const GUID * pguid, GUID const * pclsid);
HRESULT _WriteMultiple( ULONG cpspec, const PROPSPEC rgpspec[], const PROPVARIANT rgpropvar[], PROPID propidNameFirst);
HRESULT _WritePropertyNames( ULONG cpropid, const PROPID rgpropid[], const LPOLESTR rglpwstrName[]);
HRESULT HandleLowMemory();
HRESULT _CreateDocumentSummary2Stream( IStorage * pstg, CPropSetName & psn, DWORD grfMode, BOOL * fCreated);
inline HRESULT Validate(); inline HRESULT ValidateRef();
inline HRESULT ValidateRGPROPSPEC( ULONG cpspec, const PROPSPEC rgpropspec[] ); inline HRESULT ValidateInRGPROPVARIANT( ULONG cpspec, const PROPVARIANT rgpropvar[] ); inline HRESULT ValidateOutRGPROPVARIANT( ULONG cpspec, PROPVARIANT rgpropvar[] ); inline HRESULT ValidateRGPROPID( ULONG cpropid, const PROPID rgpropid[] ); inline HRESULT ValidateInRGLPOLESTR( ULONG cpropid, const LPOLESTR rglpwstrName[] ); inline HRESULT ValidateOutRGLPOLESTR( ULONG cpropid, LPOLESTR rglpwstrName[] );
inline BOOL IsSimple(); inline HRESULT IsWriteable(); inline HRESULT IsReadable(); inline DWORD GetCreationMode(); inline HRESULT IsReverted();
private: ULONG _ulSig; LONG _cRefs; IStorage * _pstgPropSet; IStream * _pstmPropSet; NTPROP _np; NTMAPPEDSTREAM _ms;
// 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;
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 _grfAccess; // grfMode & 3
DWORD _grfShare; // grfMode & 0xF0
};
//+-------------------------------------------------------------------
//
// 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 (_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::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::ValidateInRGPROPVARIANT
//
// Synopsis: S_OK if PROPVARIANT[] is valid for Read.
// E_INVALIDARG otherwise.
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::ValidateInRGPROPVARIANT( ULONG cpspec, const PROPVARIANT rgpropvar[] ) { UNREFERENCED_PARM(cpspec); // We verify that we can read the whole PropVariant[], but
// we don't validate the content of those elements.
HRESULT hr; VDATESIZEREADPTRIN_LABEL(rgpropvar, cpspec * sizeof(PROPVARIANT), errRet, hr); hr = S_OK;
errRet:
return( hr ); }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::ValidateOutRGPROPVARIANT
//
// Synopsis: S_OK if PROPVARIANT[] is valid for Write.
// E_INVALIDARG otherwise.
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::ValidateOutRGPROPVARIANT( ULONG cpspec, PROPVARIANT rgpropvar[] ) { UNREFERENCED_PARM(cpspec);
// We verify that we can write the whole PropVariant[], but
// we don't validate the content of those elements.
HRESULT hr; VDATESIZEPTROUT_LABEL(rgpropvar, cpspec * sizeof(PROPVARIANT), errRet, hr); hr = S_OK;
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; UNREFERENCED_PARM(cpropid);
VDATESIZEREADPTRIN_LABEL( rgpropid, cpropid * sizeof(PROPID), errRet, hr ); hr = S_OK;
errRet:
return( hr ); }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::ValidateOutRGLPOLESTR.
//
// Synopsis: S_OK if LPOLESTR[] is valid for Write.
// E_INVALIDARG otherwise.
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::ValidateOutRGLPOLESTR( ULONG cpropid, LPOLESTR rglpwstrName[] ) { UNREFERENCED_PARM(cpropid); HRESULT hr; VDATESIZEPTROUT_LABEL( rglpwstrName, cpropid * sizeof(LPOLESTR), errRet, hr ); hr = S_OK;
errRet:
return( hr ); }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::ValidateInRGLPOLESTR
//
// Synopsis: S_OK if LPOLESTR[] is valid for Read.
// E_INVALIDARG otherwise.
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::ValidateInRGLPOLESTR( ULONG cpropid, const LPOLESTR rglpwstrName[] ) { // Validate that we can read the entire vector.
HRESULT hr; VDATESIZEREADPTRIN_LABEL( rglpwstrName, cpropid * sizeof(LPOLESTR), errRet, hr );
// Validate that we can at least read the first character of
// each of the strings.
for( ; cpropid > 0; cpropid-- ) { VDATEREADPTRIN_LABEL( rglpwstrName[cpropid-1], WCHAR, errRet, hr ); }
hr = S_OK;
errRet:
return( hr ); }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::IsSimple
//
// Synopsis: true if simple
//
//--------------------------------------------------------------------
inline BOOL CPropertyStorage::IsSimple() { PROPASSERT((_grfFlags & PROPSETFLAG_NONSIMPLE) == 0); return TRUE; // always simple fo reference implementation
}
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::IsWriteable
//
// Synopsis: S_OK if writeable otherwise STG_E_ACCESSDENIED
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::IsWriteable() { return (_grfAccess == STGM_WRITE || _grfAccess == STGM_READWRITE) ? S_OK : STG_E_ACCESSDENIED; }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::IsReadable
//
// Synopsis: S_OK if readable otherwise STG_E_ACCESSDENIED
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::IsReadable() { return (_grfAccess == STGM_READ || _grfAccess == STGM_READWRITE) ? S_OK : STG_E_ACCESSDENIED; }
//+-------------------------------------------------------------------
//
// Member: CPropertyStorage::IsReverted
//
// Synopsis: S_OK if not reverted, STG_E_REVERTED otherwise.
//
//--------------------------------------------------------------------
inline HRESULT CPropertyStorage::IsReverted() { // note that although there is no transacted mode in ref,
// it could still be possible that the parent has been deleted
// and cause STG_E_REVERTED to be returned.
IUnknown *punk; HRESULT hr = ((IUnknown*)_pstmPropSet) -> QueryInterface(IID_IUnknown, (void**)&punk); if (hr == S_OK) { punk->Release(); } return(hr); }
//+-------------------------------------------------------------------------
//
// 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: CStatArray(NTPROP np, HRESULT *phr);
NTSTATUS NextAt(ULONG ipropNext, STATPROPSTG *pspsDest, ULONG *pceltFetched); inline VOID AddRef(); inline VOID Release(); ~CStatArray();
private: LONG _cRefs;
STATPROPSTG * _psps; ULONG _cpropActual; };
//+-------------------------------------------------------------------
//
// Member: CStatArray::AddRef
//
// Synopsis: Increment ref count.
//
//--------------------------------------------------------------------
inline VOID CStatArray::AddRef() { InterlockedIncrement(&_cRefs); }
//+-------------------------------------------------------------------
//
// Member: CStatArray::AddRef
//
// Synopsis: Decrement ref count and delete object if refs == 0.
//
//--------------------------------------------------------------------
inline VOID CStatArray::Release() { if (0 == InterlockedDecrement(&_cRefs)) delete this; }
//+-------------------------------------------------------------------------
//
// 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);
VOID CleanupSTATPROPSTG(ULONG celt, STATPROPSTG * psps);
class CEnumSTATPROPSTG : public IEnumSTATPROPSTG { public: CEnumSTATPROPSTG(NTPROP np, HRESULT *phr); CEnumSTATPROPSTG(const CEnumSTATPROPSTG &other, HRESULT *phr);
~CEnumSTATPROPSTG();
STDMETHOD(QueryInterface)( REFIID riid, void **ppvObject); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void);
STDMETHOD(Next)(ULONG celt, STATPROPSTG * rgelt, ULONG * pceltFetched);
// We don't need RemoteNext.
STDMETHOD(Skip)(ULONG celt); STDMETHOD(Reset)(); STDMETHOD(Clone)(IEnumSTATPROPSTG ** ppenum);
private: HRESULT Validate();
ULONG _ulSig; LONG _cRefs;
CStatArray * _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; }
|