You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
947 lines
25 KiB
947 lines
25 KiB
|
|
|
|
//+============================================================================
|
|
//
|
|
// File: SSMapStm.cxx
|
|
//
|
|
// Purpose: This file defines the CSSMappedStream class.
|
|
// This class provdes a IMappedStream implementation
|
|
// which maps an IStream from a Compound File.
|
|
//
|
|
// History:
|
|
//
|
|
// 5/6/98 MikeHill
|
|
// - Use CoTaskMem rather than new/delete.
|
|
//
|
|
//+============================================================================
|
|
|
|
// --------
|
|
// Includes
|
|
// --------
|
|
|
|
#include <pch.cxx>
|
|
#include "SSMapStm.hxx"
|
|
|
|
#include <privguid.h> // IID_IMappedStream
|
|
|
|
#ifdef _MAC_NODOC
|
|
ASSERTDATA // File-specific data for FnAssert
|
|
#endif
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CSSMappedStream::Initialize
|
|
//
|
|
// Synopsis: Zero-out all of the member data.
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: None
|
|
//
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSSMappedStream::Initialize()
|
|
{
|
|
propDbg(( DEB_ITRACE, "CSSMappedStream::Initialize\n" ));
|
|
|
|
_pstm = NULL;
|
|
_pbMappedStream = NULL;
|
|
_cbMappedStream = 0;
|
|
_cbActualStreamSize = 0;
|
|
_powner = NULL;
|
|
_fLowMem = FALSE;
|
|
_fDirty = FALSE;
|
|
|
|
#if DBGPROP
|
|
_fChangePending = FALSE;
|
|
#endif
|
|
|
|
} // CSSMappedStream::Initialize()
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: Constructor/Destructor
|
|
//
|
|
// Synopsis: Initialize/cleanup this object.
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
CSSMappedStream::CSSMappedStream( IStream *pstm )
|
|
{
|
|
DfpAssert( NULL != pstm );
|
|
|
|
// Initialize the member data.
|
|
Initialize();
|
|
|
|
// Keep a copy of the Stream that we're mapping.
|
|
_pstm = pstm;
|
|
_pstm->AddRef();
|
|
_cRefs = 1;
|
|
}
|
|
|
|
|
|
CSSMappedStream::~CSSMappedStream( )
|
|
{
|
|
// Just to be safe, free the mapping buffer (it should have
|
|
// already been freed).
|
|
|
|
DfpAssert( NULL == _pbMappedStream );
|
|
CoTaskMemFree( _pbMappedStream );
|
|
|
|
// If we've got the global reserved buffer locked,
|
|
// free it now.
|
|
|
|
if (_fLowMem)
|
|
{
|
|
g_ReservedMemory.UnlockMemory();
|
|
}
|
|
|
|
// Free the stream which we were mapping.
|
|
|
|
if( NULL != _pstm )
|
|
_pstm->Release();
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::QueryInterface, AddRef, Release
|
|
//
|
|
// Synopsis: IUnknown members
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
HRESULT CSSMappedStream::QueryInterface( REFIID riid, void **ppvObject)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Validate the inputs
|
|
|
|
VDATEREADPTRIN( &riid, IID );
|
|
VDATEPTROUT( ppvObject, void* );
|
|
|
|
// -----------------
|
|
// Perform the Query
|
|
// -----------------
|
|
|
|
*ppvObject = NULL;
|
|
|
|
if (IsEqualIID(riid,IID_IMappedStream) || IsEqualIID(riid,IID_IUnknown))
|
|
{
|
|
*ppvObject = (IMappedStream *)this;
|
|
CSSMappedStream::AddRef();
|
|
}
|
|
else
|
|
{
|
|
hr = E_NOINTERFACE;
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
ULONG CSSMappedStream::AddRef(void)
|
|
{
|
|
InterlockedIncrement(&_cRefs);
|
|
return(_cRefs);
|
|
}
|
|
|
|
ULONG CSSMappedStream::Release(void)
|
|
{
|
|
LONG lRet;
|
|
|
|
lRet = InterlockedDecrement(&_cRefs);
|
|
|
|
if (lRet == 0)
|
|
{
|
|
delete this;
|
|
}
|
|
else
|
|
if (lRet <0)
|
|
{
|
|
lRet = 0;
|
|
}
|
|
return(lRet);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Method: CSSMappedStream::Open
|
|
//
|
|
// Synopsis: Open up the Stream which we're mapping, and
|
|
// read it's data into a buffer.
|
|
//
|
|
// Arguments: [VOID*] powner
|
|
// The owner of this Stream. We use this for the
|
|
// PrOnMappedStreamEvent call.
|
|
// [HRESULT*] phr
|
|
// The return code.
|
|
//
|
|
// Returns: Nothing.
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
CSSMappedStream::Open( IN VOID *powner,
|
|
OUT HRESULT *phr )
|
|
{
|
|
HRESULT &hr = *phr;
|
|
VOID *pv = NULL;
|
|
DfpAssert(!_fLowMem);
|
|
|
|
hr = S_OK;
|
|
propITrace( "CSSMappedStream::Open" );
|
|
|
|
// If given a pointer to the owner of this mapped stream,
|
|
// save it. This could be NULL (i.e., when called from
|
|
// ReOpen).
|
|
|
|
if( NULL != powner )
|
|
_powner = powner;
|
|
|
|
// If we haven't already read the stream, read it now.
|
|
|
|
if( NULL == _pbMappedStream )
|
|
{
|
|
STATSTG statstg;
|
|
LARGE_INTEGER liSeek;
|
|
|
|
DfpAssert( NULL != _pstm );
|
|
DfpAssert( 0 == _cbMappedStream );
|
|
DfpAssert( 0 == _cbActualStreamSize );
|
|
|
|
// Get and validate the size of the Stream.
|
|
|
|
*phr = _pstm->Stat( &statstg, STATFLAG_NONAME );
|
|
if( FAILED(*phr) ) goto Exit;
|
|
|
|
if( statstg.cbSize.HighPart != 0
|
|
||
|
|
statstg.cbSize.LowPart > CBMAXPROPSETSTREAM )
|
|
{
|
|
*phr = STG_E_INVALIDHEADER;
|
|
goto Exit;
|
|
}
|
|
_cbMappedStream = _cbActualStreamSize = statstg.cbSize.LowPart;
|
|
|
|
// Allocate a buffer to hold the Stream. If there isn't sufficient
|
|
// memory in the system, lock and get the reserved buffer. In the
|
|
// end, 'pv' points to the appropriate buffer.
|
|
|
|
pv = CoTaskMemAlloc( _cbActualStreamSize );
|
|
|
|
if (pv == NULL)
|
|
{
|
|
pv = g_ReservedMemory.LockMemory(); // could wait until previous
|
|
// property call completes
|
|
_fLowMem = TRUE;
|
|
}
|
|
_pbMappedStream = (BYTE*) pv;
|
|
|
|
// Seek to the start of the Stream.
|
|
|
|
liSeek.HighPart = 0;
|
|
liSeek.LowPart = 0;
|
|
*phr = _pstm->Seek( liSeek, STREAM_SEEK_SET, NULL );
|
|
if( FAILED(*phr) ) goto Exit;
|
|
|
|
// Read in the Stream. But only if it is non-zero; some
|
|
// stream implementations (namely the Mac StreamOnHGlobal imp)
|
|
// don't allow 0-length reads.
|
|
|
|
if( 0 != _cbActualStreamSize )
|
|
{
|
|
*phr = _pstm->Read(
|
|
_pbMappedStream,
|
|
_cbActualStreamSize,
|
|
&_cbMappedStream);
|
|
if( FAILED(*phr) ) goto Exit;
|
|
|
|
// Ensure that we got all the bytes we requested.
|
|
|
|
if( _cbMappedStream != _cbActualStreamSize )
|
|
{
|
|
propDbg((DEBTRACE_ERROR,
|
|
"CSSMappedStream(%08X)::Open bytes-read (%lu) doesn't match bytes-requested (%lu)\n",
|
|
this, _cbMappedStream, _cbActualStreamSize ));
|
|
*phr = STG_E_INVALIDHEADER;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
|
|
#if BIGENDIAN==1
|
|
// Notify our owner that we've read in new data.
|
|
|
|
if( _powner != NULL && 0 != _cbMappedStream )
|
|
{
|
|
*phr = PrOnMappedStreamEvent( _powner, _pbMappedStream, _cbMappedStream );
|
|
if( FAILED(*phr) ) goto Exit;
|
|
}
|
|
#endif
|
|
|
|
} // if( NULL == _pbMappedStream )
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
Exit:
|
|
|
|
// If there was an error, free any memory we have.
|
|
|
|
if( FAILED(*phr) )
|
|
{
|
|
propDbg((DEB_ERROR, "CSSMappedStream(%08X):Open exception returns %08X\n", this, *phr));
|
|
|
|
if (_fLowMem)
|
|
g_ReservedMemory.UnlockMemory();
|
|
else
|
|
CoTaskMemFree( pv );
|
|
|
|
_pbMappedStream = NULL;
|
|
_cbMappedStream = 0;
|
|
_cbActualStreamSize = 0;
|
|
_fLowMem = FALSE;
|
|
}
|
|
|
|
return;
|
|
|
|
} // CSSMappedStream::Open
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Flush
|
|
//
|
|
// Synopsis: Write out the mapping buffer to the Stream,
|
|
// and Commit it.
|
|
//
|
|
// Arguments: [LONG*] phr
|
|
// An HRESULT return code.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::Flush(OUT LONG *phr)
|
|
{
|
|
|
|
HRESULT &hr = *phr;
|
|
propITrace( "CSSMappedStream::Flush" );
|
|
|
|
// Write out any data we have cached to the Stream.
|
|
hr = Write();
|
|
|
|
// Commit the Stream.
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
hr = _pstm->Commit(STGC_DEFAULT);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Close
|
|
//
|
|
// Synopsis: Close the mapped stream by writing out
|
|
// the mapping buffer and then freeing it.
|
|
//
|
|
// Arguments: [LONG*] phr
|
|
// An HRESULT error code.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::Close(OUT LONG *phr)
|
|
{
|
|
// Write the changes. We don't need to Commit them,
|
|
// they will be implicitely committed when the
|
|
// Stream is Released.
|
|
|
|
HRESULT &hr = *phr;
|
|
propITrace( "CSSMappedStream::Close" );
|
|
|
|
hr = Write();
|
|
|
|
// Even if we fail the write, we must free the memory.
|
|
// (PrClosePropertySet deletes everything whether or not
|
|
// there was an error here, so we must free the memory.
|
|
// There's no danger of this happenning due to out-of-
|
|
// disk-space conditions, because the propset code
|
|
// pre-allocates).
|
|
|
|
CoTaskMemFree( _pbMappedStream );
|
|
_pstm->Release();
|
|
|
|
// Re-zero the member data.
|
|
Initialize();
|
|
|
|
return;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::ReOpen
|
|
//
|
|
// Synopsis: Gets the caller a pointer to the already-opened
|
|
// mapping buffer. If it isn't already opened, then
|
|
// it is opened here.
|
|
//
|
|
// Arguments: [VOID**] ppv
|
|
// Used to return the mapping buffer.
|
|
// [LONG*] phr
|
|
// Used to return an HRESULT.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::ReOpen(IN OUT VOID **ppv, OUT LONG *phr)
|
|
{
|
|
*ppv = NULL;
|
|
|
|
Open(NULL, // Unspecified owner.
|
|
phr);
|
|
|
|
if( SUCCEEDED(*phr) )
|
|
*ppv = _pbMappedStream;
|
|
|
|
return;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Quiesce
|
|
//
|
|
// Synopsis: Unnecessary for this IMappedStream implementation.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::Quiesce(VOID)
|
|
{
|
|
DfpAssert(_pbMappedStream != NULL);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Map
|
|
//
|
|
// Synopsis: Used to get a pointer to the current mapping.
|
|
//
|
|
// Arguments: [BOOLEAN] fCreate
|
|
// Not used by this IMappedStream implementation.
|
|
// [VOID**] ppv
|
|
// Used to return the mapping buffer.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::Map(BOOLEAN fCreate, VOID **ppv)
|
|
{
|
|
DfpAssert(_pbMappedStream != NULL);
|
|
*ppv = _pbMappedStream;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Unmap
|
|
//
|
|
// Synopsis: Unnecessary for this IMappedStream implementation.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::Unmap(BOOLEAN fFlush, VOID **ppv)
|
|
{
|
|
*ppv = NULL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Write
|
|
//
|
|
// Synopsis: Writes the mapping buffer out to the original
|
|
// Stream.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: [HRESULT]
|
|
// S_FALSE => Nothing needed to be written
|
|
//
|
|
//--------------------------------------------------------------------
|
|
#define STACK_BYTES 16
|
|
|
|
HRESULT CSSMappedStream::Write ()
|
|
{
|
|
HRESULT hr;
|
|
ULONG cbWritten;
|
|
LARGE_INTEGER liSeek;
|
|
BOOL fOwnerSignaled = FALSE;
|
|
|
|
propITrace( "CSSMappedStream::Write" );
|
|
|
|
// We can return right away if there's nothing to write.
|
|
// (_pbMappedStream may be NULL in the error path of our
|
|
// caller).
|
|
|
|
if (!_fDirty || NULL == _pbMappedStream )
|
|
{
|
|
propDbg((DEB_PROP_INFO, "CPubStream(%08X):Flush returns with not-dirty\n", this));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
DfpAssert( _pstm != NULL );
|
|
|
|
#if BIGENDIAN==1
|
|
// Notify our owner that we're about to perform a Write.
|
|
// Note that there are no goto Exit calls prior to this point, because
|
|
// we making a corresponding call to PrOnMappedStreamEvent (for byte-swapping)
|
|
// in the Exit.
|
|
hr = PrOnMappedStreamEvent( _powner, _pbMappedStream, _cbMappedStream );
|
|
if( S_OK != hr ) goto Exit;
|
|
fOwnerSignaled = TRUE;
|
|
#endif
|
|
|
|
// Seek to the start of the Stream.
|
|
liSeek.HighPart = 0;
|
|
liSeek.LowPart = 0;
|
|
hr = _pstm->Seek( liSeek, STREAM_SEEK_SET, NULL );
|
|
if( FAILED(hr) ) goto Exit;
|
|
|
|
// Write out the mapping buffer.
|
|
hr = _pstm->Write(_pbMappedStream, _cbMappedStream, &cbWritten);
|
|
if( S_OK != hr ) goto Exit;
|
|
if( cbWritten != _cbMappedStream )
|
|
{
|
|
propDbg((DEB_ERROR,
|
|
"CSSMappedStream(%08X)::Write bytes-written (%lu) doesn't match bytes-requested (%lu)\n",
|
|
this, cbWritten, _cbMappedStream ));
|
|
hr = STG_E_INVALIDHEADER;
|
|
goto Exit;
|
|
}
|
|
|
|
// If the buffer is shrinking, this is a good time to shrink the Stream.
|
|
if (_cbMappedStream < _cbActualStreamSize)
|
|
{
|
|
ULARGE_INTEGER uli;
|
|
uli.HighPart = 0;
|
|
uli.LowPart = _cbMappedStream;
|
|
|
|
hr = _pstm->SetSize(uli);
|
|
if( S_OK == hr )
|
|
{
|
|
_cbActualStreamSize = _cbMappedStream;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we changed the buffer size and it is less than the
|
|
// actual underlying stream, then we need to zero out the memory
|
|
// above the currrent size.
|
|
//
|
|
if (_cbMappedStream < _cbActualStreamSize)
|
|
{
|
|
PBYTE pTemp;
|
|
LARGE_INTEGER li;
|
|
DWORD cbWrite = _cbActualStreamSize - _cbMappedStream;
|
|
|
|
li.HighPart = 0;
|
|
li.LowPart = _cbMappedStream;
|
|
hr = _pstm->Seek(li,STREAM_SEEK_SET,NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pTemp = reinterpret_cast<PBYTE>( CoTaskMemAlloc( cbWrite ));
|
|
if (pTemp != NULL)
|
|
{
|
|
memset(pTemp,0,cbWrite);
|
|
//
|
|
// Successfully allocated memory for the write. Write the
|
|
// zeros out all at once.
|
|
//
|
|
hr = _pstm->Write(pTemp, cbWrite, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
propDbg((DEB_ERROR, "CSSMappedStream::Write "
|
|
"write failure\n",hr));
|
|
goto Exit;
|
|
}
|
|
CoTaskMemFree( pTemp );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We couldn't allocate memory. So we will use a small
|
|
// stack buffer instead.
|
|
//
|
|
BYTE stackBuf[STACK_BYTES];
|
|
memset(stackBuf, 0, STACK_BYTES);
|
|
|
|
while (cbWrite >= STACK_BYTES)
|
|
{
|
|
hr = _pstm->Write(stackBuf, STACK_BYTES, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
propDbg((DEB_ERROR, "CSSMappedStream::Write write failure\n",hr));
|
|
goto Exit;
|
|
}
|
|
cbWrite -= STACK_BYTES;
|
|
}
|
|
|
|
if (cbWrite < STACK_BYTES)
|
|
{
|
|
hr = _pstm->Write(stackBuf, cbWrite, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
propDbg((DEB_ERROR, "CSSMappedStream::Write write failure\n",hr));
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
propDbg((DEB_ERROR, "CSSMappedStream::Write seek failure\n",hr));
|
|
goto Exit;
|
|
}
|
|
}
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
Exit:
|
|
|
|
// Notify our owner that we're done with the Write. We do this
|
|
// whether or not there was an error, because _pbMappedStream is
|
|
// not modified, and therefore intact even in the error path.
|
|
// This call allows the owner to correct the byte-order of the header.
|
|
|
|
#if BIGENDIAN==1
|
|
if( fOwnerSignaled )
|
|
DfpVerify( PrOnMappedStreamEvent( _powner, _pbMappedStream, _cbMappedStream ));
|
|
#endif
|
|
|
|
if (hr == S_OK || hr == STG_E_REVERTED)
|
|
{
|
|
_fDirty = FALSE;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::GetSize
|
|
//
|
|
// Synopsis: Returns the current size of the mapped stream.
|
|
//
|
|
// Arguments: [LONG*] phr
|
|
// Used to return an HRESULT.
|
|
//
|
|
// Returns: [ULONG]
|
|
// The current size.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
ULONG CSSMappedStream::GetSize(OUT LONG *phr)
|
|
{
|
|
HRESULT &hr = *phr;
|
|
hr = S_OK;
|
|
|
|
propITrace( "CSSMappedStream::GetSize" );
|
|
|
|
// If necessary, open the Stream.
|
|
|
|
if( NULL == _pbMappedStream )
|
|
{
|
|
Open(NULL, // Unspecified owner
|
|
phr);
|
|
}
|
|
|
|
if( SUCCEEDED(*phr) )
|
|
{
|
|
DfpAssert( NULL != _pbMappedStream );
|
|
}
|
|
|
|
// Return the size of the mapped stream. If there was an
|
|
// Open error, it will be zero, and *phr will be set.
|
|
|
|
propDbg(( DEB_ITRACE, "CSSMappedStream::GetSize, size is %d\n", _cbMappedStream ));
|
|
return _cbMappedStream;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::SetSize
|
|
//
|
|
// Synopsis: Set the size of the mapped stream.
|
|
//
|
|
// Arguments: [ULONG] cb
|
|
// The new size.
|
|
// [BOOLEAN] fPersistent
|
|
// If not set, then this change will not be stored -
|
|
// thus the mapping buffer must be set, but the
|
|
// Stream itself must not. This was added so that
|
|
// CPropertySetStream could grow the buffer for internal
|
|
// processing, when the Stream itself is read-only.
|
|
// [VOID**] ppv
|
|
// Used to return the new mapping buffer location.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Pre-Conditions:
|
|
// cb is below the maximum property set size.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSSMappedStream::SetSize(ULONG cb,
|
|
IN BOOLEAN fPersistent,
|
|
VOID **ppv, OUT LONG *phr)
|
|
{
|
|
BYTE *pv;
|
|
|
|
HRESULT &hr = *phr;
|
|
|
|
hr = S_OK;
|
|
DfpAssert(cb != 0);
|
|
DfpAssert(cb <= CBMAXPROPSETSTREAM);
|
|
|
|
propITrace( "CSSMappedStream::SetSize" );
|
|
propTraceParameters(( "cb=%lu, fPersistent=%s, ppv=%p", cb, fPersistent?"True":"False" ));
|
|
|
|
//
|
|
// if we are growing the data, we should grow the stream
|
|
//
|
|
if (fPersistent && cb > _cbActualStreamSize)
|
|
{
|
|
ULARGE_INTEGER uli;
|
|
uli.HighPart = 0;
|
|
uli.LowPart = cb;
|
|
|
|
//----------------
|
|
// Need to Grow!
|
|
//----------------
|
|
|
|
propDbg(( DEB_ITRACE, "Growing from %d to %d\n", _cbActualStreamSize, cb ));
|
|
*phr = _pstm->SetSize( uli );
|
|
|
|
if (FAILED(*phr) )
|
|
goto Exit;
|
|
else
|
|
_cbActualStreamSize = cb;
|
|
}
|
|
|
|
//
|
|
// We only get here if we either (1) didn't want to grow the
|
|
// underlying stream, or (2) we successfully grew the underlying stream.
|
|
//
|
|
|
|
//
|
|
// Re-size the buffer to the size specified in cb.
|
|
//
|
|
if ( _fLowMem )
|
|
{
|
|
// If we want to grow the buffer In low-memory conditions,
|
|
// no realloc is necessary, because
|
|
// _pbMappedStream is already large enough for the largest
|
|
// property set.
|
|
|
|
*ppv = _pbMappedStream;
|
|
}
|
|
else if ( cb != _cbMappedStream )
|
|
{
|
|
|
|
// We must re-alloc the buffer.
|
|
|
|
pv = reinterpret_cast<BYTE*>( CoTaskMemAlloc( cb ));
|
|
|
|
if ((pv == NULL) )
|
|
{
|
|
// allocation failed: we need to try using a backup mechanism for
|
|
// more memory.
|
|
// copy the data to the global reserved chunk... we will wait until
|
|
// someone else has released it. it will be released on the way out
|
|
// of the property code.
|
|
|
|
_fLowMem = TRUE;
|
|
pv = g_ReservedMemory.LockMemory();
|
|
if ( NULL == pv)
|
|
{
|
|
*phr = E_OUTOFMEMORY;
|
|
goto Exit;
|
|
}
|
|
else if( NULL != _pbMappedStream)
|
|
{
|
|
memcpy( pv, _pbMappedStream, min(cb,_cbMappedStream) );
|
|
}
|
|
CoTaskMemFree( _pbMappedStream );
|
|
}
|
|
else
|
|
{
|
|
memcpy( pv, _pbMappedStream, min(cb,_cbMappedStream) );
|
|
CoTaskMemFree( _pbMappedStream );
|
|
}
|
|
|
|
_pbMappedStream = pv;
|
|
*ppv = pv;
|
|
}
|
|
_cbMappedStream = cb;
|
|
|
|
// ----
|
|
// Exit
|
|
// ----
|
|
|
|
Exit:
|
|
|
|
propDbg((DbgFlag(*phr,DEB_TRACE), "CSSMappedStream(%08X):SetSize %s returns hr=%08X\n",
|
|
this, *phr != S_OK ? "exception" : "", *phr));
|
|
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Lock
|
|
//
|
|
// Synopsis: Locking is not supported by this class.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS CSSMappedStream::Lock(BOOLEAN fExclusive)
|
|
{
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::Unlock
|
|
//
|
|
// Synopsis: Locking is not supported by this class.
|
|
// However, this method still must check to
|
|
// see if the reserved memory pool should be
|
|
// freed for use by another property set.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS CSSMappedStream::Unlock(VOID)
|
|
{
|
|
// if at the end of the properties set/get call we have the low
|
|
// memory region locked, we flush to disk.
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_fLowMem)
|
|
{
|
|
Flush(&hr);
|
|
|
|
g_ReservedMemory.UnlockMemory();
|
|
_pbMappedStream = NULL;
|
|
_cbMappedStream = 0;
|
|
_fLowMem = FALSE;
|
|
propDbg((DEB_ERROR, "CPubStream(%08X):Unlock low-mem returns NTSTATUS=%08X\n",
|
|
this, hr));
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::QueryTimeStamps
|
|
//
|
|
// Synopsis: Not used by this IMappedStream derivation.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::QueryTimeStamps(STATPROPSETSTG *pspss, BOOLEAN fNonSimple) const
|
|
{
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::QueryModifyTime
|
|
//
|
|
// Synopsis: Not used by this IMappedStream derivation.
|
|
//
|
|
// Notes:
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
BOOLEAN CSSMappedStream::QueryModifyTime(OUT LONGLONG *pll) const
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: Unused methods by this IMappedStream implementation:
|
|
// QuerySecurity, IsWritable, GetHandle
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
BOOLEAN CSSMappedStream::QuerySecurity(OUT ULONG *pul) const
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
BOOLEAN CSSMappedStream::IsWriteable() const
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
HANDLE CSSMappedStream::GetHandle(VOID) const
|
|
{
|
|
return(INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::SetModified/IsModified
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
VOID CSSMappedStream::SetModified(OUT LONG *phr)
|
|
{
|
|
_fDirty = TRUE;
|
|
*phr = S_OK;
|
|
}
|
|
|
|
BOOLEAN CSSMappedStream::IsModified(VOID) const
|
|
{
|
|
propDbg(( DEB_ITRACE, "CSSMappedStream::IsModified (%s)\n", _fDirty?"TRUE":"FALSE" ));
|
|
return (BOOLEAN) _fDirty;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Member: CSSMappedStream::IsNtMappedStream/SetChangePending
|
|
//
|
|
// Synopsis: Debug routines.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
#if DBGPROP
|
|
BOOLEAN CSSMappedStream::IsNtMappedStream(VOID) const
|
|
{
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if DBGPROP
|
|
BOOLEAN CSSMappedStream::SetChangePending(BOOLEAN f)
|
|
{
|
|
BOOL fOld = _fChangePending;
|
|
_fChangePending = f;
|
|
return((BOOLEAN)_fChangePending);
|
|
}
|
|
#endif
|
|
|