windows-nt/Source/XPSP1/NT/com/ole32/stg/exp/expst.cxx
2020-09-26 16:20:57 +08:00

2416 lines
68 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) 1992, Microsoft Corporation.
//
// File: expst.cxx
//
// Contents: CExposedStream code
//
// History: 28-Feb-92 PhilipLa Created.
// 20-Jun-96 MikeHill Fixed the PropSet version of
// Lock to check the result of TakeSem.
// 1-Jul-96 MikeHill - Removed Win32 SEH from PropSet code.
// - Receive NTPROP in propset Open method.
// 11-Feb-97 Danl - Changed CMappedStream to IMappedStream
// - Added QI support for IMappedStream.
//
//--------------------------------------------------------------------------
#include <exphead.cxx>
#pragma hdrstop
#include <pbstream.hxx>
#include <expst.hxx>
#include <lock.hxx>
#include <seekptr.hxx>
#include <marshl.hxx>
#include <logfile.hxx>
#include <privguid.h> // IID_IMappedStream
#include <expparam.hxx>
#ifndef LARGE_STREAMS
// Maximum stream size supported by exposed streams
// This is MAX_ULONG with one subtracted so that
// the seek pointer has a spot to sit even at the
// end of the stream
#define CBMAXSTREAM 0xfffffffeUL
// Maximum seek pointer value
#define CBMAXSEEK (CBMAXSTREAM+1)
#endif
#if DBG
DWORD MyGetLastError()
{
return GetLastError();
}
#endif
//+--------------------------------------------------------------
//
// Member: CExposedStream::CExposedStream, public
//
// Synopsis: Empty object constructor
//
// History: 30-Mar-92 DrewB Created
//
//---------------------------------------------------------------
CExposedStream::CExposedStream(void)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::CExposedStream()\n"));
_pdfb = NULL;
_ppc = NULL;
_cReferences = 0;
_psp = NULL;
_pst = NULL;
olDebugOut((DEB_ITRACE, "Out CExposedStream::CExposedStream\n"));
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Init, public
//
// Synopsis: Base constructor
//
// Arguments: [pst] - Public stream
// [pdfb] - DocFile basis
// [ppc] - Context
// [psp] - Seek pointer or NULL for new seek pointer
//
// Returns: Appropriate status code
//
// History: 28-Feb-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CExposedStream::Init(CPubStream *pst,
CDFBasis *pdfb,
CPerContext *ppc,
CSeekPointer *psp)
{
SCODE sc;
olDebugOut((DEB_ITRACE, "In CExposedStream::Init("
"%p, %p, %p, %p)\n",
pst, pdfb, ppc, psp));
if (psp == NULL)
{
CSeekPointer *pspTemp;
olMem(pspTemp = new (pdfb->GetMalloc()) CSeekPointer(0));
_psp = P_TO_BP(CBasedSeekPointerPtr, pspTemp);
}
else
_psp = P_TO_BP(CBasedSeekPointerPtr, psp);
_ppc = ppc;
_pst = P_TO_BP(CBasedPubStreamPtr, pst);
_pdfb = P_TO_BP(CBasedDFBasisPtr, pdfb);
_pdfb->vAddRef();
_cReferences = 1;
_sig = CEXPOSEDSTREAM_SIG;
olDebugOut((DEB_ITRACE, "Out CExposedStream::Init\n"));
return S_OK;
EH_Err:
return sc;
}
SCODE CExposedStream::InitMarshal(CPubStream *pst,
CDFBasis *pdfb,
CPerContext *ppc,
DWORD dwAsyncFlags,
IDocfileAsyncConnectionPoint *pdacp,
CSeekPointer *psp)
{
SCODE sc;
sc = CExposedStream::Init(pst,
pdfb,
ppc,
psp);
if (SUCCEEDED(sc))
{
sc = _cpoint.InitMarshal(this, dwAsyncFlags, pdacp);
}
return sc;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::~CExposedStream, public
//
// Synopsis: Destructor
//
// Returns: Appropriate status code
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//---------------------------------------------------------------
CExposedStream::~CExposedStream(void)
{
olDebugOut((DEB_ITRACE, "In CExposedStream::~CExposedStream\n"));
olAssert(_cReferences == 0);
_sig = CEXPOSEDSTREAM_SIGDEL;
//In order to call into the tree, we need to take the mutex.
//The mutex may get deleted in _ppc->Release(), so we can't
//release it here. The mutex actually gets released in
//CPerContext::Release() or in the CPerContext destructor.
SCODE sc;
#if !defined(MULTIHEAP)
// TakeSem and ReleaseSem are moved to the Release Method
// so that the deallocation for this object is protected
if (_ppc)
{
sc = TakeSem();
SetWriteAccess();
olAssert(SUCCEEDED(sc));
}
#ifdef ASYNC
IDocfileAsyncConnectionPoint *pdacp = _cpoint.GetMarshalPoint();
#endif
#endif //MULTIHEAP
if (_pst)
_pst->CPubStream::vRelease();
if (_psp)
_psp->CSeekPointer::vRelease();
if (_pdfb)
_pdfb->CDFBasis::vRelease();
#if !defined(MULTIHEAP)
if (_ppc)
{
if (_ppc->Release() > 0)
ReleaseSem(sc);
}
#ifdef ASYNC
//Mutex has been released, so we can release the connection point
// without fear of deadlock.
if (pdacp != NULL)
pdacp->Release();
#endif
#endif // MULTIHEAP
olDebugOut((DEB_ITRACE, "Out CExposedStream::~CExposedStream\n"));
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Read, public
//
// Synopsis: Read from a stream
//
// Arguments: [pb] - Buffer
// [cb] - Count of bytes to read
// [pcbRead] - Return number of bytes read
//
// Returns: Appropriate status code
//
// Modifies: [pcbRead]
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Read(VOID HUGEP *pb, ULONG cb, ULONG *pcbRead)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
ULONG cbRead = 0;
olLog(("%p::In CExposedStream::Read(%p, %lu, %p)\n",
this, pb, cb, pcbRead));
olDebugOut((DEB_TRACE, "In CExposedStream::Read %p(%p, %lu, %p)\n",
this, pb, cb, pcbRead));
OL_VALIDATE(Read(pb, cb, pcbRead));
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
SafeReadAccess();
sc = _pst->ReadAt(_psp->GetPos(), pb, cb, (ULONG STACKBASED *)&cbRead);
#ifndef LARGE_STREAMS
olAssert(CBMAXSEEK-_psp->GetPos() >= cbRead);
#endif
_psp->SetPos(_psp->GetPos()+cbRead);
pb = (BYTE *)pb + cbRead;
cb -= cbRead;
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::Read => %lu\n", cbRead));
EH_Err:
if (pcbRead)
{
// May fault and leave stream seek pointer changed
// This is acceptable
*pcbRead = cbRead;
olLog(("%p::Out CExposedStream::Read(). *pcbRead == %lu, ret = %lx\n",
this, *pcbRead, sc));
}
else
{
olLog(("%p::Out CExposedStream::Read(). ret == %lx\n", this, sc));
}
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Write, public
//
// Synopsis: Write to a stream
//
// Arguments: [pb] - Buffer
// [cb] - Count of bytes to write
// [pcbWritten] - Return of bytes written
//
// Returns: Appropriate status code
//
// Modifies: [pcbWritten]
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Write(
VOID const HUGEP *pb,
ULONG cb,
ULONG *pcbWritten)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
ULONG cbWritten = 0;
olLog(("%p::In CExposedStream::Write(%p, %lu, %p)\n",
this, pb, cb, pcbWritten));
olDebugOut((DEB_TRACE, "In CExposedStream::Write %p(%p, %lu, %p)\n",
this, pb, cb, pcbWritten));
OL_VALIDATE(Write(pb, cb, pcbWritten));
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
SafeWriteAccess();
#ifdef DIRECTWRITERLOCK
olChk(ValidateWriteAccess());
#endif
sc = _pst->WriteAt(_psp->GetPos(), pb, cb,
(ULONG STACKBASED *)&cbWritten);
#ifndef LARGE_STREAMS
olAssert(CBMAXSEEK-_psp->GetPos() >= cbWritten);
#endif
_psp->SetPos(_psp->GetPos()+cbWritten);
pb = (BYTE *)pb + cbWritten;
cb -= cbWritten;
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::Write => %lu\n",
cbWritten));
EH_Err:
if (pcbWritten)
{
// May fault but that's acceptable
*pcbWritten = cbWritten;
olLog(("%p::Out CExposedStream::Write(). "
"*pcbWritten == %lu, ret = %lx\n",
this, *pcbWritten, sc));
}
else
{
olLog(("%p::Out CExposedStream::Write(). ret == %lx\n", this, sc));
}
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Seek, public
//
// Synopsis: Seek to a point in a stream
//
// Arguments: [dlibMove] - Offset to move by
// [dwOrigin] - SEEK_SET, SEEK_CUR, SEEK_END
// [plibNewPosition] - Return of new offset
//
// Returns: Appropriate status code
//
// Modifies: [plibNewPosition]
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Seek(LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
#ifdef LARGE_STREAMS
LONGLONG lMove;
#else
LONG lMove;
#endif
ULARGE_INTEGER ulPos;
olLog(("%p::In CExposedStream::Seek(%ld, %lu, %p)\n",
this, LIGetLow(dlibMove), dwOrigin, plibNewPosition));
olDebugOut((DEB_TRACE, "In CExposedStream::Seek %p(%ld, %lu, %p)\n",
this, LIGetLow(dlibMove), dwOrigin, plibNewPosition));
OL_VALIDATE(Seek(dlibMove, dwOrigin, plibNewPosition));
if (dwOrigin == STREAM_SEEK_SET)
{
#ifdef LARGE_STREAMS
if (dlibMove.QuadPart < 0)
olErr (EH_Err, STG_E_INVALIDFUNCTION);
#else
// Truncate dlibMove to 32 bits
// Make sure we don't seek too far
if (LIGetHigh(dlibMove) != 0)
LISet32(dlibMove, 0xffffffff);
#endif
}
else
{
#ifndef LARGE_STREAMS
// High dword must be zero for positive values or -1 for
// negative values
// Additionally, for negative values, the low dword can't
// exceed -0x80000000 because the 32nd bit is the sign
// bit
if (LIGetHigh(dlibMove) > 0 ||
(LIGetHigh(dlibMove) == 0 &&
LIGetLow(dlibMove) >= 0x80000000))
LISet32(dlibMove, 0x7fffffff);
else if (LIGetHigh(dlibMove) < -1 ||
(LIGetHigh(dlibMove) == -1 &&
LIGetLow(dlibMove) <= 0x7fffffff))
LISet32(dlibMove, 0x80000000);
#endif
}
#ifdef LARGE_STREAMS
lMove = dlibMove.QuadPart;
#else
lMove = (LONG)LIGetLow(dlibMove);
#endif
olChk(Validate());
//ASYNC Note: We probably don't need this pending loop in Seek
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
olChk(_pst->CheckReverted());
SafeReadAccess();
#ifdef LARGE_STREAMS
ulPos.QuadPart = _psp->GetPos();
#else
ULISet32(ulPos, _psp->GetPos());
#endif
switch(dwOrigin)
{
case STREAM_SEEK_SET:
#ifdef LARGE_STREAMS
ulPos.QuadPart = lMove;
#else
ULISetLow(ulPos, (ULONG)lMove);
#endif
break;
case STREAM_SEEK_END:
#ifdef LARGE_STREAMS
ULONGLONG cbSize;
#else
ULONG cbSize;
#endif
olChk(_pst->GetSize(&cbSize));
if (lMove < 0)
{
#ifdef LARGE_STREAMS
if ((ULONGLONG)(-lMove) > cbSize)
#else
if ((ULONG)(-lMove) > cbSize)
#endif
olErr(EH_Err, STG_E_INVALIDFUNCTION);
}
#ifdef LARGE_STREAMS
ulPos.QuadPart = cbSize+lMove;
#else
else if ((ULONG)lMove > CBMAXSEEK-cbSize)
lMove = (LONG)(CBMAXSEEK-cbSize);
ULISetLow(ulPos, cbSize+lMove);
#endif
break;
case STREAM_SEEK_CUR:
if (lMove < 0)
{
#ifdef LARGE_STREAMS
if ((ULONGLONG)(-lMove) > _psp->GetPos())
#else
if ((ULONG)(-lMove) > _psp->GetPos())
#endif
olErr(EH_Err, STG_E_INVALIDFUNCTION);
}
#ifdef LARGE_STREAMS
ulPos.QuadPart = _psp->GetPos()+lMove;
#else
else if ((ULONG)lMove > CBMAXSEEK-_psp->GetPos())
lMove = (LONG)(CBMAXSEEK-_psp->GetPos());
ULISetLow(ulPos, _psp->GetPos()+lMove);
#endif
break;
}
#ifdef LARGE_STREAMS
_psp->SetPos(ulPos.QuadPart);
#else
_psp->SetPos(ULIGetLow(ulPos));
#endif
if (plibNewPosition)
// May fault but that's acceptable
*plibNewPosition = ulPos;
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::Seek => %lu\n",
ULIGetLow(ulPos)));
EH_Err:
olLog(("%p::Out CExposedStream::Seek(). ulPos == %lu, ret == %lx\n",
this, ULIGetLow(ulPos), sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::SetSize, public
//
// Synopsis: Sets the size of a stream
//
// Arguments: [ulNewSize] - New size
//
// Returns: Appropriate status code
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::SetSize(ULARGE_INTEGER ulNewSize)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
olLog(("%p::In CExposedStream::SetSize(%lu)\n",
this, ULIGetLow(ulNewSize)));
olDebugOut((DEB_TRACE, "In CExposedStream::SetSize %p(%lu)\n",
this, ULIGetLow(ulNewSize)));
OL_VALIDATE(SetSize(ulNewSize));
#ifndef LARGE_STREAMS
if (ULIGetHigh(ulNewSize) != 0)
olErr(EH_Err, STG_E_DOCFILETOOLARGE);
#endif
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
SafeWriteAccess();
#ifdef DIRECTWRITERLOCK
olChk(ValidateWriteAccess());
#endif
#ifdef LARGE_STREAMS
sc = _pst->SetSize(ulNewSize.QuadPart);
#else
sc = _pst->SetSize(ULIGetLow(ulNewSize));
#endif
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::SetSize\n"));
EH_Err:
olLog(("%p::Out CExposedStream::SetSize(). ret == %lx\n", this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::CopyTo, public
//
// Synopsis: Copies information from one stream to another
//
// Arguments: [pstm] - Destination
// [cb] - Number of bytes to copy
// [pcbRead] - Return number of bytes read
// [pcbWritten] - Return number of bytes written
//
// Returns: Appropriate status code
//
// Modifies: [pcbRead]
// [pcbWritten]
//
// History: 25-Mar-92 DrewB Created
// 12-Jan-93 AlexT Rewritten without recursion
//
// Notes: We do our best to handle overlap correctly. This allows
// CopyTo to be used to insert and remove space within a
// stream.
//
// In the error case, we make no gurantees as to the
// validity of pcbRead, pcbWritten, or either stream's
// seek position.
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::CopyTo(IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten)
{
SCODE sc;
SAFE_SEM;
olLog(("%p::In CExposedStream::CopyTo(%p, %lu, %p, %p)\n",
this, pstm, ULIGetLow(cb), pcbRead, pcbWritten));
olDebugOut((DEB_TRACE, "In CExposedStream::CopyTo("
"%p, %lu, %p, %p)\n", pstm, ULIGetLow(cb),
pcbRead, pcbWritten));
OL_VALIDATE(CopyTo(pstm, cb, pcbRead, pcbWritten));
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
sc = CopyToWorker(pstm, cb, pcbRead, pcbWritten, &_ss);
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::CopyTo => %lu, %lu\n",
pcbRead ? ULIGetLow(*pcbRead) : 0,
pcbWritten ? ULIGetLow(*pcbWritten) : 0));
EH_Err:
return sc;
}
SCODE CExposedStream::CopyToWorker(IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten,
CSafeSem *pss)
{
SCODE sc;
#ifdef LARGE_STREAMS
ULONGLONG ulCopySize;
ULONGLONG ulSrcSize, ulSrcOrig;
#else
ULONG ulCopySize;
ULONG ulSrcSize;
ULONG ulSrcOrig;
#endif
ULARGE_INTEGER uliDestOrig;
LARGE_INTEGER liDestPos;
BYTE *pb = NULL;
BOOL fOverlap;
#ifdef LARGE_STREAMS
ULONGLONG ulBytesCopied = 0;
#else
ULONG ulBytesCopied = 0;
#endif
ULONG ulBufferSize;
#ifdef LARGE_STREAMS
ulCopySize = cb.QuadPart;
#else
// Bound the size of the copy
// 1. The maximum we can copy is 0xffffffff
if (ULIGetHigh(cb) == 0)
ulCopySize = ULIGetLow(cb);
else
ulCopySize = 0xffffffff;
#endif
// 2. We can only copy what's available in the source stream
SetReadAccess();
sc = _pst->GetSize(&ulSrcSize);
ClearReadAccess();
olChk(sc);
ulSrcOrig = _psp->GetPos();
if (ulSrcSize < ulSrcOrig)
{
// Nothing in source to copy
ulCopySize = 0;
}
else if ((ulSrcSize - ulSrcOrig) < ulCopySize)
{
// Shrink ulCopySize to fit bytes in source
ulCopySize = ulSrcSize - ulSrcOrig;
}
// 3. We can only copy what will fit in the destination
LISet32(liDestPos, 0);
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_CUR, &uliDestOrig));
#ifndef LARGE_STREAMS
olAssert(ULIGetHigh(uliDestOrig) == 0);
if (ulCopySize > CBMAXSEEK - ULIGetLow(uliDestOrig))
ulCopySize = CBMAXSEEK - ULIGetLow(uliDestOrig);
#endif
ulBufferSize = (_pdfb->GetOpenFlags() & DF_LARGE) ?
LARGESTREAMBUFFERSIZE : STREAMBUFFERSIZE;
// We are allowed to fail here with out-of-memory
olChk(GetBuffer(STREAMBUFFERSIZE, ulBufferSize, &pb, &ulBufferSize));
// Since we have no reliable way to determine if the source and
// destination represent the same stream, we assume they
// do and always handle overlap.
#ifdef LARGE_STREAMS
fOverlap = (uliDestOrig.QuadPart > ulSrcOrig &&
uliDestOrig.QuadPart < ulSrcOrig + ulCopySize);
#else
fOverlap = (ULIGetLow(uliDestOrig) > ulSrcOrig &&
ULIGetLow(uliDestOrig) < ulSrcOrig + ulCopySize);
#endif
#ifdef LARGE_STREAMS
ULONGLONG ulSrcCopyOffset;
ULONGLONG ulDstCopyOffset;
#else
ULONG ulSrcCopyOffset;
ULONG ulDstCopyOffset;
#endif
if (fOverlap)
{
// We're going to copy back to front, so determine the
// stream end positions
ulSrcCopyOffset = ulSrcOrig + ulCopySize;
// uliDestOrig is the destination starting offset
#ifdef LARGE_STREAMS
ulDstCopyOffset = uliDestOrig.QuadPart + ulCopySize;
#else
ulDstCopyOffset = ULIGetLow(uliDestOrig) + ulCopySize;
#endif
}
while (ulCopySize > 0)
{
// We can only copy up to ulBufferSize bytes at a time
ULONG cbPart = (ULONG) min(ulCopySize, ulBufferSize);
if (fOverlap)
{
// We're copying back to front so we need to seek to
// set up the streams correctly
ulSrcCopyOffset -= cbPart;
ulDstCopyOffset -= cbPart;
// Set source stream position
_psp->SetPos(ulSrcCopyOffset);
// Set destination stream position
liDestPos.QuadPart = ulDstCopyOffset;
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
}
ULONG ulRead = 0;
SetReadAccess();
sc = _pst->ReadAt(_psp->GetPos(), pb, cbPart, &ulRead);
ClearReadAccess();
#ifndef LARGE_STREAMS
olAssert(CBMAXSEEK-_psp->GetPos() >= ulRead);
#endif
_psp->SetPos(_psp->GetPos()+ulRead);
olChk(sc);
if (cbPart != ulRead)
{
// There was no error, but we were unable to read cbPart
// bytes. Something's wrong (the underlying ILockBytes?)
// but we can't control it; just return an error.
olErr(EH_Err, STG_E_READFAULT);
}
// We release the tree mutex before calling out to Write
// to avoid a deadlock in the async FillAppend method
ULONG ulWritten;
SCODE sc2;
pss->Release();
sc2 = pstm->Write(pb, cbPart, &ulWritten);
olChk(pss->Take());
olChk (sc2);
if (cbPart != ulWritten)
{
// There was no error, but we were unable to write
// ulWritten bytes. We can't trust the pstm
// implementation, so all we can do here is return
// an error.
olErr(EH_Err, STG_E_WRITEFAULT);
}
olAssert(ulCopySize >= cbPart);
ulCopySize -= cbPart;
ulBytesCopied += cbPart;
}
if (fOverlap)
{
// Set the seek pointers to the correct location
_psp->SetPos(ulSrcOrig + ulBytesCopied);
liDestPos.QuadPart = uliDestOrig.QuadPart + ulBytesCopied;
olHChk(pstm->Seek(liDestPos, STREAM_SEEK_SET, NULL));
}
// Fall through
EH_Err:
DfMemFree(pb);
if (pcbRead)
pcbRead->QuadPart = ulBytesCopied;
if (pcbWritten)
pcbWritten->QuadPart = ulBytesCopied;
olLog(("%p::Out CExposedStream::CopyTo(). "
"cbRead == %lu, cbWritten == %lu, ret == %lx\n",
this, pcbRead ? ULIGetLow(*pcbRead) : 0,
pcbWritten ? ULIGetLow(*pcbWritten) : 0, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Release, public
//
// Synopsis: Releases a stream
//
// Returns: Appropriate status code
//
// History: 28-Feb-92 DrewB Created from pbstream source
//
//---------------------------------------------------------------
STDMETHODIMP_(ULONG) CExposedStream::Release(void)
{
LONG lRet;
olLog(("%p::In CExposedStream::Release()\n", this));
olDebugOut((DEB_TRACE, "In CExposedStream::Release()\n"));
if (FAILED(Validate()))
return 0;
olAssert(_cReferences > 0);
lRet = InterlockedDecrement(&_cReferences);
if (lRet == 0)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
CPerContext *ppc = _ppc;
SCODE sc = S_OK;
if (_ppc)
{
sc = TakeSem();
SetWriteAccess();
olAssert(SUCCEEDED(sc));
}
#ifdef ASYNC
IDocfileAsyncConnectionPoint *pdacp = _cpoint.GetMarshalPoint();
#endif
#endif //MULTIHEAP
delete this;
#ifdef MULTIHEAP
if (ppc)
{
if (ppc->Release() == 0)
g_smAllocator.Uninit();
else
if (SUCCEEDED(sc)) ppc->UntakeSem();
}
#ifdef ASYNC
//Mutex has been released, so we can release the connection point
// without fear of deadlock.
if (pdacp != NULL)
pdacp->Release();
#endif
#endif
}
else if (lRet < 0)
lRet = 0;
olDebugOut((DEB_TRACE, "Out CExposedStream::Release %p()=> %lu\n",
this, lRet));
olLog(("%p::Out CExposedStream::Release(). ret == %lu\n", this, lRet));
FreeLogFile();
return lRet;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Stat, public
//
// Synopsis: Fills in a buffer of information about this object
//
// Arguments: [pstatstg] - Buffer
//
// Returns: Appropriate status code
//
// Modifies: [pstatstg]
//
// History: 24-Mar-92 DrewB Created
//
//---------------------------------------------------------------
_OLESTDMETHODIMP CExposedStream::Stat(STATSTGW *pstatstg, DWORD grfStatFlag)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
STATSTGW stat;
olLog(("%p::In CExposedStream::Stat(%p)\n", this, pstatstg));
olDebugOut((DEB_TRACE, "In CExposedStream::Stat(%p)\n",
pstatstg));
OL_VALIDATE(Stat(pstatstg, grfStatFlag));
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
SafeReadAccess();
sc = _pst->Stat(&stat, grfStatFlag);
END_PENDING_LOOP;
if (SUCCEEDED(sc))
{
TRY
{
*pstatstg = stat;
pstatstg->type = STGTY_STREAM;
pstatstg->grfLocksSupported = 0;
pstatstg->STATSTG_dwStgFmt = 0;
pstatstg->ctime.dwLowDateTime = pstatstg->ctime.dwHighDateTime = 0;
pstatstg->mtime.dwLowDateTime = pstatstg->mtime.dwHighDateTime = 0;
pstatstg->atime.dwLowDateTime = pstatstg->atime.dwHighDateTime = 0;
}
CATCH(CException, e)
{
UNREFERENCED_PARM(e);
if (stat.pwcsName)
TaskMemFree(stat.pwcsName);
sc = STG_E_INVALIDPOINTER;
}
END_CATCH
}
olDebugOut((DEB_TRACE, "Out CExposedStream::Stat\n"));
// Fall through
EH_Err:
olLog(("%p::Out CExposedStream::Stat(). ret == %lx\n",
this, sc));
return _OLERETURN(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Clone, public
//
// Synopsis: Clones a stream
//
// Returns: Appropriate status code
//
// History: 28-Feb-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Clone(IStream **ppstm)
{
SafeCExposedStream pst;
CSeekPointer *psp;
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
olLog(("%p::In CExposedStream::Clone(%p)\n", this, ppstm));
olDebugOut((DEB_TRACE, "In CExposedStream::Clone(%p)\n", ppstm));
OL_VALIDATE(Clone(ppstm));
olChk(Validate());
olChk(TakeSafeSem());
olChk(_pst->CheckReverted());
SafeReadAccess();
olMem(psp = new (_pdfb->GetMalloc()) CSeekPointer(_psp->GetPos()));
pst.Attach(new (_pdfb->GetMalloc()) CExposedStream);
olMemTo(EH_psp, (CExposedStream *)pst);
olChkTo(EH_pst, pst->Init(BP_TO_P(CPubStream *, _pst),
BP_TO_P(CDFBasis *, _pdfb),
_ppc, psp));
_ppc->AddRef();
_pst->vAddRef();
#ifdef ASYNC
if (_cpoint.IsInitialized())
{
olChkTo(EH_pstInit, pst->InitClone(&_cpoint));
}
#endif
TRANSFER_INTERFACE(pst, IStream, ppstm);
olDebugOut((DEB_TRACE, "Out CExposedStream::Clone => %p\n", *ppstm));
EH_Err:
olLog(("%p::Out CExposedStream::Clone(). *ppstm == %p, ret == %lx\n",
this, *ppstm, sc));
return ResultFromScode(sc);
EH_pstInit:
pst->Release();
goto EH_Err;
EH_pst:
delete pst;
EH_psp:
psp->vRelease();
goto EH_Err;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::AddRef, public
//
// Synopsis: Increments the ref count
//
// Returns: Appropriate status code
//
// History: 16-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP_(ULONG) CExposedStream::AddRef(void)
{
ULONG ulRet;
olLog(("%p::In CExposedStream::AddRef()\n", this));
olDebugOut((DEB_TRACE, "In CExposedStream::AddRef()\n"));
if (FAILED(Validate()))
return 0;
InterlockedIncrement(&_cReferences);
ulRet = _cReferences;
olDebugOut((DEB_TRACE, "Out CExposedStream::AddRef %p() => %lu\n",
this, _cReferences));
olLog(("%p::Out CExposedStream::AddRef(). ret == %lu\n", this, ulRet));
return ulRet;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::LockRegion, public
//
// Synopsis: Nonfunctional
//
// Returns: Appropriate status code
//
// History: 16-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::LockRegion(ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
olDebugOut((DEB_TRACE, "In CExposedStream::LockRegion("
"%lu, %lu\n", ULIGetLow(cb), dwLockType));
olDebugOut((DEB_TRACE, "Out CExposedStream::LockRegion\n"));
olLog(("%p::INVALID CALL TO CExposedStream::LockRegion()\n"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::UnlockRegion, public
//
// Synopsis: Nonfunctional
//
// Returns: Appropriate status code
//
// History: 16-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::UnlockRegion(ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
olDebugOut((DEB_TRACE, "In CExposedStream::UnlockRegion(%lu, %lu)\n",
ULIGetLow(cb), dwLockType));
olDebugOut((DEB_TRACE, "Out CExposedStream::UnlockRegion\n"));
olLog(("%p::INVALID CALL TO CExposedStream::UnlockRegion()\n"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Commit, public
//
// Synopsis: No-op in current implementation
//
// Returns: Appropriate status code
//
// History: 16-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Commit(DWORD grfCommitFlags)
{
SCODE sc;
SAFE_SEM;
SAFE_ACCESS;
olDebugOut((DEB_TRACE, "In CExposedStream::Commit(%lu)\n",
grfCommitFlags));
olLog(("%p::In CExposedStream::Commit(%lx)\n", this, grfCommitFlags));
OL_VALIDATE(Commit(grfCommitFlags));
olChk(Validate());
BEGIN_PENDING_LOOP;
olChk(TakeSafeSem());
SafeWriteAccess();
sc = _pst->Commit(grfCommitFlags);
END_PENDING_LOOP;
olDebugOut((DEB_TRACE, "Out CExposedStream::Commit\n"));
EH_Err:
olLog(("%p::Out CExposedStream::Commit(). ret == %lx\n", this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Revert, public
//
// Synopsis: No-op in current implementation
//
// Returns: Appropriate status code
//
// History: 16-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::Revert(void)
{
SCODE sc;
olDebugOut((DEB_TRACE, "In CExposedStream::Revert()\n"));
OL_VALIDATE(Revert());
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
//ASYNC Note: Don't need pending loop here.
sc = _pst->CheckReverted();
olDebugOut((DEB_TRACE, "Out CExposedStream::Revert\n"));
olLog(("%p::In CExposedStream::Revert()\n", this));
olLog(("%p::Out CExposedStream::Revert(). ret == %lx", this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::QueryInterface, public
//
// Synopsis: Returns an object for the requested interface
//
// Arguments: [iid] - Interface ID
// [ppvObj] - Object return
//
// Returns: Appropriate status code
//
// Modifies: [ppvObj]
//
// History: 26-Mar-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::QueryInterface(REFIID iid, void **ppvObj)
{
SCODE sc;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
olLog(("%p::In CExposedStream::QueryInterface(?, %p)\n",
this, ppvObj));
olDebugOut((DEB_TRACE, "In CExposedStream::QueryInterface(?, %p)\n",
ppvObj));
OL_VALIDATE(QueryInterface(iid, ppvObj));
olChk(Validate());
olChk(_pst->CheckReverted());
sc = S_OK;
if (IsEqualIID(iid, IID_IStream) || IsEqualIID(iid, IID_IUnknown))
{
*ppvObj = (IStream *)this;
AddRef();
}
else if (IsEqualIID(iid, IID_IMarshal))
{
//If the ILockBytes we'd need to marshal doesn't support IMarshal
// then we want to do standard marshalling on the stream, mostly
// to prevent deadlock problems but also because you'll get better
// performance. So check, then do the right thing.
IMarshal *pim;
ILockBytes *plkb;
plkb = _ppc->GetOriginal();
if (plkb == NULL)
{
plkb = _ppc->GetBase();
}
sc = plkb->QueryInterface(IID_IMarshal, (void **)&pim);
if (FAILED(sc))
{
olErr(EH_Err, E_NOINTERFACE);
}
pim->Release();
#ifdef MULTIHEAP
if (_ppc->GetHeapBase() == NULL)
olErr (EH_Err, E_NOINTERFACE);
#endif
*ppvObj = (IMarshal *)this;
AddRef();
}
else if (IsEqualIID(iid, IID_IMappedStream))
{
*ppvObj = (IMappedStream *)this;
AddRef();
}
#ifdef ASYNC
else if (IsEqualIID(iid, IID_IConnectionPointContainer) &&
_cpoint.IsInitialized())
{
*ppvObj = (IConnectionPointContainer *)this;
CExposedStream::AddRef();
}
#endif
else
sc = E_NOINTERFACE;
olDebugOut((DEB_TRACE, "Out CExposedStream::QueryInterface => %p\n",
*ppvObj));
EH_Err:
olLog(("%p::Out CExposedStream::QueryInterface(). "
"*ppvObj == %p, ret == %lx\n", this, *ppvObj, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::Unmarshal, public
//
// Synopsis: Creates a duplicate stream from parts
//
// Arguments: [pstm] - Marshal stream
// [ppv] - Object return
// [mshlflags] - Marshal flags
//
// Returns: Appropriate status code
//
// Modifies: [ppv]
//
// History: 26-Feb-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CExposedStream::Unmarshal(IStream *pstm,
void **ppv,
DWORD mshlflags)
{
SCODE sc;
CDfMutex mtx;
CPerContext *ppc;
CPubStream *pst;
CDFBasis *pdfb;
CGlobalContext *pgc;
CExposedStream *pest;
CSeekPointer *psp;
IStream *pstmStd = NULL;
#ifdef ASYNC
DWORD dwAsyncFlags;
IDocfileAsyncConnectionPoint *pdacp;
#endif
#ifdef POINTER_IDENTITY
CMarshalList *pml;
#endif
olDebugOut((DEB_ITRACE, "In CExposedStream::Unmarshal(%p, %p, %lu)\n",
pstm, ppv, mshlflags));
#ifdef MULTIHEAP
void *pvBaseOld;
void *pvBaseNew;
ContextId cntxid;
CPerContext pcSharedMemory (NULL); // bootstrap object
#endif
//First unmarshal the standard marshalled version
sc = CoUnmarshalInterface(pstm, IID_IStream, (void **)&pstmStd);
if (FAILED(sc))
{
// assume that entire standard marshaling stream has been read
olAssert (pstmStd == NULL);
sc = S_OK;
}
#ifdef MULTIHEAP
sc = UnmarshalSharedMemory(pstm, mshlflags, &pcSharedMemory, &cntxid);
if (!SUCCEEDED(sc))
{
#ifdef POINTER_IDENTITY
UnmarshalPointer(pstm, (void **) &pest);
#endif
UnmarshalPointer(pstm, (void **)&pst);
UnmarshalPointer(pstm, (void **)&pdfb);
UnmarshalPointer(pstm, (void **)&psp);
#ifdef ASYNC
ReleaseContext(pstm, TRUE, FALSE, mshlflags);
ReleaseConnection(pstm, mshlflags);
#else
ReleaseContext(pstStm, FALSE, mshlflags);
#endif
olChkTo(EH_std, sc);
}
pvBaseOld = DFBASEPTR;
#endif
#ifdef POINTER_IDENTITY
olChkTo(EH_mem, UnmarshalPointer(pstm, (void **)&pest));
#endif
olChkTo(EH_mem, UnmarshalPointer(pstm, (void **)&pst));
olChkTo(EH_mem, ValidateBuffer(pst, sizeof(CPubStream)));
olChkTo(EH_pst, UnmarshalPointer(pstm, (void **)&pdfb));
olChkTo(EH_pdfb, UnmarshalPointer(pstm, (void **)&psp));
olChkTo(EH_psp, UnmarshalPointer(pstm, (void **)&pgc));
olChkTo(EH_pgc, ValidateBuffer(pgc, sizeof(CGlobalContext)));
//So far, nothing has called into the tree so we don't really need
// to be holding the tree mutex. The UnmarshalContext call does
// call into the tree, though, so we need to make sure this is
// threadsafe. We'll do this my getting the mutex name from the
// CGlobalContext, then creating a new CDfMutex object. While
// this is obviously not optimal, since it's possible we could
// reuse an existing CDfMutex, the reuse strategy isn't threadsafe
// since we can't do a lookup without the possibility of the thing
// we're looking for being released by another thread.
TCHAR atcMutexName[CONTEXT_MUTEX_NAME_LENGTH];
pgc->GetMutexName(atcMutexName);
olChkTo(EH_pgc, mtx.Init(atcMutexName));
olChkTo(EH_pgc, mtx.Take(INFINITE));
//At this point we're holding the mutex.
#ifdef MULTIHEAP
#ifdef ASYNC
olChkTo(EH_mtx, UnmarshalContext(pstm,
pgc,
&ppc,
mshlflags,
TRUE,
FALSE,
cntxid,
FALSE));
#else
olChkTo(EH_mtx, UnmarshalContext(pstm,
pgc,
&ppc,
mshlflags,
FALSE,
cntxid,
FALSE));
#endif
if ((pvBaseNew = DFBASEPTR) != pvBaseOld)
{
pst = (CPubStream*) ((ULONG_PTR)pst - (ULONG_PTR)pvBaseOld
+ (ULONG_PTR)pvBaseNew);
pest = (CExposedStream*) ((ULONG_PTR)pest - (ULONG_PTR)pvBaseOld
+ (ULONG_PTR)pvBaseNew);
pdfb = (CDFBasis*) ((ULONG_PTR)pdfb - (ULONG_PTR)pvBaseOld
+ (ULONG_PTR)pvBaseNew);
psp = (CSeekPointer*) ((ULONG_PTR)psp - (ULONG_PTR)pvBaseOld
+ (ULONG_PTR)pvBaseNew);
}
#else
#ifdef ASYNC
olChkTo(EH_mtx, UnmarshalContext(pstm,
pgc,
&ppc,
mshlflags,
TRUE,
FALSE,
FALSE));
#else
olChkTo(EH_mtx, UnmarshalContext(pstm,
pgc,
&ppc,
mshlflags,
FALSE,
FALSE));
#endif //ASYNC
#endif
#ifdef ASYNC
olChkTo(EH_ppc, UnmarshalConnection(pstm,
&dwAsyncFlags,
&pdacp,
mshlflags));
#endif
// if we use up 1Gig of address space, use standard unmarshaling
if (gs_iSharedHeaps > (DOCFILE_SM_LIMIT / DOCFILE_SM_SIZE))
olErr (EH_ppc, STG_E_INSUFFICIENTMEMORY);
#ifdef POINTER_IDENTITY
olAssert (pest != NULL);
pml = (CMarshalList *) pest;
// Warning: these checks must remain valid across processes
if (SUCCEEDED(pest->Validate()) && pest->GetPub() == pst)
{
pest = (CExposedStream *) pml->FindMarshal(GetCurrentContextId());
}
else
{
pml = NULL;
pest = NULL;
}
if (pest == NULL)
{
#endif
olMemTo(EH_ppc, pest = new (pdfb->GetMalloc()) CExposedStream);
#ifdef ASYNC
olChkTo(EH_pest, pest->InitMarshal(pst,
pdfb,
ppc,
dwAsyncFlags,
pdacp,
psp));
//InitMarshal adds a reference on pdacp.
if (pdacp)
pdacp->Release();
#else
olChkTo(EH_pest, pest->Init(pst, pdfb, ppc, psp));
#endif
#ifdef POINTER_IDENTITY
if (pml) pml->AddMarshal(pest);
pst->vAddRef(); // CExposedStream::Init does not AddRef
psp->vAddRef();
}
else
{
pdfb->SetAccess(ppc);
pest->AddRef(); // reuse this object
ppc->Release(); // reuse percontext
}
#else
pst->vAddRef();
psp->vAddRef();
#endif
*ppv = pest;
#ifdef MULTIHEAP
if (pvBaseOld != pvBaseNew)
{
pcSharedMemory.SetThreadAllocatorState(NULL);
g_smAllocator.Uninit(); // delete the extra mapping
}
g_smAllocator.SetState(NULL, NULL, 0, NULL, NULL);
#endif
mtx.Release();
//We're returning the custom marshalled version, so release the
//standard marshalled one.
if (pstmStd != NULL)
pstmStd->Release();
olDebugOut((DEB_ITRACE, "Out CExposedStream::Unmarshal => %p\n", *ppv));
return S_OK;
EH_pest:
delete pest;
EH_ppc:
ppc->Release();
EH_mtx:
mtx.Release();
goto EH_Err;
EH_pgc:
CoReleaseMarshalData(pstm); // release the ILockBytes
CoReleaseMarshalData(pstm); // release the ILockBytes
#ifdef ASYNC
ReleaseConnection(pstm, mshlflags);
#endif
EH_psp:
EH_pdfb:
EH_pst:
EH_mem:
EH_Err:
#ifdef MULTIHEAP
pcSharedMemory.SetThreadAllocatorState(NULL);
g_smAllocator.Uninit(); // delete the file mapping in error case
g_smAllocator.SetState(NULL, NULL, 0, NULL, NULL);
#endif
EH_std:
if (pstmStd != NULL)
{
//We can return the standard marshalled version instead of an error.
*ppv = pstmStd;
return S_OK;
}
return sc;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::GetUnmarshalClass, public
//
// Synopsis: Returns the class ID
//
// Arguments: [riid] - IID of object
// [pv] - Unreferenced
// [dwDestContext] - Unreferenced
// [pvDestContext] - Unreferenced
// [mshlflags] - Unreferenced
// [pcid] - CLSID return
//
// Returns: Appropriate status code
//
// Modifies: [pcid]
//
// History: 04-May-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::GetUnmarshalClass(REFIID riid,
void *pv,
DWORD dwDestContext,
LPVOID pvDestContext,
DWORD mshlflags,
LPCLSID pcid)
{
SCODE sc;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
olLog(("%p::In CExposedStream::GetUnmarshalClass("
"riid, %p, %lu, %p, %lu, %p)\n",
this, pv, dwDestContext, pvDestContext, mshlflags, pcid));
olDebugOut((DEB_TRACE, "In CExposedStream::GetUnmarshalClass:%p("
"riid, %p, %lu, %p, %lu, %p)\n", this, pv, dwDestContext,
pvDestContext, mshlflags, pcid));
UNREFERENCED_PARM(pv);
UNREFERENCED_PARM(mshlflags);
olChk(ValidateOutBuffer(pcid, sizeof(CLSID)));
memset(pcid, 0, sizeof(CLSID));
olChk(ValidateIid(riid));
olChk(Validate());
olChk(_pst->CheckReverted());
if ((dwDestContext != MSHCTX_LOCAL) && (dwDestContext != MSHCTX_INPROC))
{
IMarshal *pmsh;
if (SUCCEEDED(sc = CoGetStandardMarshal(riid, (IUnknown *)pv,
dwDestContext, pvDestContext,
mshlflags, &pmsh)))
{
sc = GetScode(pmsh->GetUnmarshalClass(riid, pv, dwDestContext,
pvDestContext, mshlflags,
pcid));
pmsh->Release();
}
}
else if (pvDestContext != NULL)
{
sc = STG_E_INVALIDPARAMETER;
}
else
{
olChk(VerifyIid(riid, IID_IStream));
*pcid = CLSID_DfMarshal;
}
olDebugOut((DEB_TRACE, "Out CExposedStream::GetUnmarshalClass\n"));
EH_Err:
olLog(("%p::Out CExposedStream::GetUnmarshalClass(). ret == %lx\n",
this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::GetMarshalSizeMax, public
//
// Synopsis: Returns the size needed for the marshal buffer
//
// Arguments: [riid] - IID of object being marshaled
// [pv] - Unreferenced
// [dwDestContext] - Unreferenced
// [pvDestContext] - Unreferenced
// [mshlflags] - Marshal flags
// [pcbSize] - Size return
//
// Returns: Appropriate status code
//
// Modifies: [pcbSize]
//
// History: 04-May-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::GetMarshalSizeMax(REFIID riid,
void *pv,
DWORD dwDestContext,
LPVOID pvDestContext,
DWORD mshlflags,
LPDWORD pcbSize)
{
SCODE sc;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
UNREFERENCED_PARM(pv);
olLog(("%p::In CExposedStream::GetMarshalSizeMax("
"riid, %p, %lu, %p, %lu, %p)\n",
this, pv, dwDestContext, pvDestContext, mshlflags, pcbSize));
olDebugOut((DEB_TRACE, "In CExposedStream::GetMarshalSizeMax:%p("
"riid, %p, %lu, %p, %lu, %p)\n", this, pv, dwDestContext,
pvDestContext, mshlflags, pcbSize));
olChk(Validate());
olChk(_pst->CheckReverted());
if ((dwDestContext != MSHCTX_LOCAL) && (dwDestContext != MSHCTX_INPROC))
{
IMarshal *pmsh;
if (SUCCEEDED(sc = CoGetStandardMarshal(riid, (IUnknown *)pv,
dwDestContext, pvDestContext,
mshlflags, &pmsh)))
{
sc = GetScode(pmsh->GetMarshalSizeMax(riid, pv, dwDestContext,
pvDestContext, mshlflags,
pcbSize));
pmsh->Release();
}
}
else if (pvDestContext != NULL)
{
sc = STG_E_INVALIDPARAMETER;
}
else
{
sc = GetStdMarshalSize(riid, IID_IStream, dwDestContext, pvDestContext,
mshlflags, pcbSize,
sizeof(CPubStream *)+sizeof(CDFBasis *)+
sizeof(CSeekPointer *),
#ifdef ASYNC
&_cpoint,
TRUE,
#endif
_ppc, FALSE);
DWORD cbSize = 0;
IMarshal *pmsh;
if (SUCCEEDED(sc = CoGetStandardMarshal(riid, (IUnknown *)pv,
dwDestContext, pvDestContext,
mshlflags, &pmsh)))
{
sc = GetScode(pmsh->GetMarshalSizeMax(riid, pv, dwDestContext,
pvDestContext, mshlflags,
&cbSize));
pmsh->Release();
*pcbSize += cbSize;
}
}
olDebugOut((DEB_TRACE, "Out CExposedStream::GetMarshalSizeMax\n"));
EH_Err:
olLog(("%p::Out CExposedStream::GetMarshalSizeMax(). *pcbSize == %lu, "
"ret == %lx\n", this, *pcbSize, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::MarshalInterface, public
//
// Synopsis: Marshals a given object
//
// Arguments: [pstStm] - Stream to write marshal data into
// [riid] - Interface to marshal
// [pv] - Unreferenced
// [dwDestContext] - Unreferenced
// [pvDestContext] - Unreferenced
// [mshlflags] - Marshal flags
//
// Returns: Appropriate status code
//
// History: 04-May-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::MarshalInterface(IStream *pstStm,
REFIID riid,
void *pv,
DWORD dwDestContext,
LPVOID pvDestContext,
DWORD mshlflags)
{
SCODE sc;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
olLog(("%p::In CExposedStream::MarshalInterface("
"%p, riid, %p, %lu, %p, %lu). Context == %lX\n",
this, pstStm, pv, dwDestContext, pvDestContext,
mshlflags, (ULONG)GetCurrentContextId()));
olDebugOut((DEB_TRACE, "In CExposedStream::MarshalInterface:%p("
"%p, riid, %p, %lu, %p, %lu)\n", this, pstStm, pv,
dwDestContext, pvDestContext, mshlflags));
UNREFERENCED_PARM(pv);
olChk(Validate());
olChk(_pst->CheckReverted());
if ((dwDestContext != MSHCTX_LOCAL) && (dwDestContext != MSHCTX_INPROC))
{
IMarshal *pmsh;
if (SUCCEEDED(sc = CoGetStandardMarshal(riid, (IUnknown *)pv,
dwDestContext, pvDestContext,
mshlflags, &pmsh)))
{
sc = GetScode(pmsh->MarshalInterface(pstStm, riid, pv,
dwDestContext, pvDestContext,
mshlflags));
pmsh->Release();
olChk(sc);
}
}
else if (pvDestContext != NULL)
{
sc = STG_E_INVALIDPARAMETER;
}
else
{
olChk(StartMarshal(pstStm, riid, IID_IStream, mshlflags));
//Always standard marshal, in case we get an error during
//unmarshalling of the custom stuff.
{
IMarshal *pmsh;
if (SUCCEEDED(sc = CoGetStandardMarshal(riid, (IUnknown *)pv,
dwDestContext, pvDestContext,
mshlflags, &pmsh)))
{
sc = pmsh->MarshalInterface(pstStm, riid, pv,
dwDestContext, pvDestContext,
mshlflags);
pmsh->Release();
}
olChk(sc);
}
#ifdef MULTIHEAP
olChk(MarshalSharedMemory(pstStm, _ppc));
#endif
#ifdef POINTER_IDENTITY
olChk(MarshalPointer(pstStm, (CExposedStream*) GetNextMarshal()));
#endif
olChk(MarshalPointer(pstStm, BP_TO_P(CPubStream *, _pst)));
olChk(MarshalPointer(pstStm, BP_TO_P(CDFBasis *, _pdfb)));
olChk(MarshalPointer(pstStm, BP_TO_P(CSeekPointer *, _psp)));
#ifdef ASYNC
olChk(MarshalContext(pstStm,
_ppc,
dwDestContext,
pvDestContext,
mshlflags,
TRUE,
FALSE));
#else
olChk(MarshalContext(pstStm,
_ppc,
dwDestContext,
pvDestContext,
mshlflags,
FALSE));
#endif
#ifdef ASYNC
olChk(MarshalConnection(pstStm,
&_cpoint,
dwDestContext,
pvDestContext,
mshlflags));
#endif
}
olDebugOut((DEB_TRACE, "Out CExposedStream::MarshalInterface\n"));
EH_Err:
olLog(("%p::Out CExposedStream::MarshalInterface(). ret == %lx\n",
this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::UnmarshalInterface, public
//
// Synopsis: Non-functional
//
// Arguments: [pstStm] -
// [riid] -
// [ppvObj] -
//
// Returns: Appropriate status code
//
// Modifies: [ppvObj]
//
// History: 04-May-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::UnmarshalInterface(IStream *pstStm,
REFIID riid,
void **ppvObj)
{
olLog(("%p::INVALID CALL TO CExposedStream::UnmarshalInterface()\n"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::StaticReleaseMarshalData, public static
//
// Synopsis: Releases any references held in marshal data
//
// Arguments: [pstStm] - Marshal data stream
//
// Returns: Appropriate status code
//
// History: 02-Feb-94 DrewB Created
//
// Notes: Assumes standard marshal header has already been read
//
//---------------------------------------------------------------
SCODE CExposedStream::StaticReleaseMarshalData(IStream *pstStm,
DWORD mshlflags)
{
SCODE sc;
CPubStream *pst;
CDFBasis *pdfb;
CSeekPointer *psp;
#ifdef POINTER_IDENTITY
CExposedStream *pest;
#endif
olDebugOut((DEB_ITRACE, "In CExposedStream::StaticReleaseMarshalData:("
"%p, %lX)\n", pstStm, mshlflags));
//First release the standard marshalled stuff
olChk(CoReleaseMarshalData(pstStm));
// The final release of the exposed object may have shut down the
// shared memory heap, so do not access shared memory after this point
//Then do the rest of it
#ifdef MULTIHEAP
olChk(SkipSharedMemory(pstStm, mshlflags));
#endif
#ifdef POINTER_IDENTITY
olChk(UnmarshalPointer(pstStm, (void **) &pest));
#endif
olChk(UnmarshalPointer(pstStm, (void **)&pst));
olChk(UnmarshalPointer(pstStm, (void **)&pdfb));
olChk(UnmarshalPointer(pstStm, (void **)&psp));
#ifdef ASYNC
olChk(ReleaseContext(pstStm, TRUE, FALSE, mshlflags));
olChk(ReleaseConnection(pstStm, mshlflags));
#else
olChk(ReleaseContext(pstStm, FALSE, mshlflags));
#endif
#ifdef MULTIHEAP
g_smAllocator.SetState(NULL, NULL, 0, NULL, NULL);
#endif
olDebugOut((DEB_ITRACE,
"Out CExposedStream::StaticReleaseMarshalData\n"));
EH_Err:
return sc;
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::ReleaseMarshalData, public
//
// Synopsis: Non-functional
//
// Arguments: [pstStm] - Stream
//
// Returns: Appropriate status code
//
// History: 18-Sep-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::ReleaseMarshalData(IStream *pstStm)
{
SCODE sc;
DWORD mshlflags;
IID iid;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
olLog(("%p::In CExposedStream::ReleaseMarshalData(%p)\n", this, pstStm));
olDebugOut((DEB_TRACE, "In CExposedStream::ReleaseMarshalData:%p(%p)\n",
this, pstStm));
olChk(Validate());
olChk(_pst->CheckReverted());
olChk(SkipStdMarshal(pstStm, &iid, &mshlflags));
olAssert(IsEqualIID(iid, IID_IStream));
sc = StaticReleaseMarshalData(pstStm, mshlflags);
olDebugOut((DEB_TRACE, "Out CExposedStream::ReleaseMarshalData\n"));
EH_Err:
olLog(("%p::Out CExposedStream::ReleaseMarshalData(). ret == %lx\n",
this, sc));
return ResultFromScode(sc);
}
//+--------------------------------------------------------------
//
// Member: CExposedStream::DisconnectObject, public
//
// Synopsis: Non-functional
//
// Arguments: [dwRevserved] -
//
// Returns: Appropriate status code
//
// History: 18-Sep-92 DrewB Created
//
//---------------------------------------------------------------
STDMETHODIMP CExposedStream::DisconnectObject(DWORD dwReserved)
{
olLog(("%p::INVALID CALL TO CExposedStream::DisconnectObject()\n"));
return ResultFromScode(STG_E_INVALIDFUNCTION);
}
#ifdef NEWPROPS
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Open
//
// Synopsis: Opens mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Gets the size of the underlying stream and reads it
// into memory so that it can be "mapped."
//
//--------------------------------------------------------------------
VOID CExposedStream::Open(IN VOID *powner, LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Open(powner, phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Close
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Does nothing because the object may be mapped in
// another process.
//
//--------------------------------------------------------------------
VOID CExposedStream::Close(OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Close(phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::ReOpen
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Combined open and map.
//
//--------------------------------------------------------------------
VOID CExposedStream::ReOpen(IN OUT VOID **ppv, OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().ReOpen(ppv,phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Quiesce
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Meaningless for docfile mapped stream.
//
//--------------------------------------------------------------------
VOID CExposedStream::Quiesce(VOID)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Quiesce();
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Map
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Return the address of the "mapping" buffer.
//
//--------------------------------------------------------------------
VOID CExposedStream::Map(BOOLEAN fCreate, VOID **ppv)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Map(fCreate, ppv);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Unmap
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes: Unmapping is merely zeroing the pointer. We don't
// flush because that's done explicitly by the
// CPropertyStorage class.
//
//
//--------------------------------------------------------------------
VOID CExposedStream::Unmap(BOOLEAN fFlush, VOID **pv)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Unmap(fFlush, pv);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Flush
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
// Flush the memory property set to disk and commit it.
//
// Signals: HRESULT from IStream methods.
//
// Notes: Calls the shared memory buffer to do the actual flush
// because that code path is shared with the "FlushBufferedData"
// call for IStorage::Commit.
//
//--------------------------------------------------------------------
VOID CExposedStream::Flush(OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().Flush(phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::GetSize
//
// Synopsis: Returns size of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//--------------------------------------------------------------------
ULONG CExposedStream::GetSize(OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
return GetMappedStream().GetSize(phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::SetSize
//
// Synopsis: Sets size of "map." Called by
// NtCreatePropertySet et al.
//
// Arguments: [cb] -- requested size.
// [fPersistent] -- FALSE if expanding in-memory read-only image
// [ppv] -- new mapped address.
//
// Signals: Not enough disk space.
//
// Notes: In a low memory situation we may not be able to
// get the requested amount of memory. In this
// case we must fall back on disk storage as the
// actual map.
//
//--------------------------------------------------------------------
VOID CExposedStream::SetSize(ULONG cb, BOOLEAN fPersistent, VOID **ppv, OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().SetSize(cb, fPersistent, ppv, phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Lock
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
NTSTATUS CExposedStream::Lock(BOOLEAN fExclusive)
{
SCODE sc;
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
if( SUCCEEDED( sc = TakeSem() ))
{
SetDifferentBasisAccess(_pdfb, _ppc);
return GetMappedStream().Lock(fExclusive);
}
else
{
olDebugOut((DEB_IERROR, "Couldn't take CExposedStream::Lock(%lx)\n", sc));
return (STATUS_LOCK_NOT_GRANTED);
}
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::Unlock
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
NTSTATUS CExposedStream::Unlock(VOID)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
NTSTATUS Status = GetMappedStream().Unlock();
ClearBasisAccess(_pdfb);
ReleaseSem(S_OK);
return Status;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QueryTimeStamps
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CExposedStream::QueryTimeStamps(STATPROPSETSTG *pspss, BOOLEAN fNonSimple) const
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().QueryTimeStamps(pspss, fNonSimple);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QueryModifyTime
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::QueryModifyTime(OUT LONGLONG *pll) const
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
return(GetMappedStream().QueryModifyTime(pll));
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::QuerySecurity
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::QuerySecurity(OUT ULONG *pul) const
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
return(GetMappedStream().QuerySecurity(pul));
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsWriteable
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::IsWriteable() const
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
return GetConstMappedStream().IsWriteable();
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::SetChangePending
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBGPROP
BOOLEAN CExposedStream::SetChangePending(BOOLEAN f)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
return GetMappedStream().SetChangePending(f);
}
#endif
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsNtMappedStream
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
#if DBGPROP
BOOLEAN CExposedStream::IsNtMappedStream(VOID) const
{
return FALSE;
}
#endif
//+-------------------------------------------------------------------
//
// Member: CExposedStream::GetParentHandle
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
HANDLE CExposedStream::GetHandle(VOID) const
{
return INVALID_HANDLE_VALUE;
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::SetModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
VOID CExposedStream::SetModified(OUT LONG *phr)
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
GetMappedStream().SetModified(phr);
}
//+-------------------------------------------------------------------
//
// Member: CExposedStream::IsModified
//
// Synopsis: Operates on mapped view of exposed stream. Called by
// NtCreatePropertySet et al.
//
// Notes:
//
//--------------------------------------------------------------------
BOOLEAN CExposedStream::IsModified(VOID) const
{
#ifdef MULTIHEAP
CSafeMultiHeap smh(_ppc);
#endif
//return ((class CExposedStream*const)this)->GetMappedStream().IsModified();
return GetConstMappedStream().IsModified();
}
#ifdef DIRECTWRITERLOCK
//+--------------------------------------------------------------
//
// Member: CExposedStream::ValidateWriteAccess, public
//
// Synopsis: returns whether writer currently has write access
//
// Notes: tree mutex must be taken
//
// History: 30-Apr-96 HenryLee Created
//
//---------------------------------------------------------------
HRESULT CExposedStream::ValidateWriteAccess()
{
if (_pst->GetTransactedDepth() >= 1)
return S_OK;
return (!_pdfb->DirectWriterMode() || (*_ppc->GetRecursionCount())) ?
S_OK : STG_E_ACCESSDENIED;
};
#endif // DIRECTWRITERLOCK
#endif