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

414 lines
9.3 KiB
C++

//+-------------------------------------------------------------------
//
// File: actstrm.cxx
//
// Contents: code for providing a stream with an IBuffer interface
// as well as providing marshalled interface data for
// RPC.
//
// Classes: ActivationStream
//
// History: 30-Jan-93 Ricksa Created CXmitRpcStream
// 04-Feb-98 Vinaykr ActivationStream
//
// Description: All requirements of CXmitRpcStream, plus the additional
// requirement of being able to support a buffer interface
// for activation custom marshalling.
//--------------------------------------------------------------------
#include <ole2int.h>
#include <actstrm.hxx>
HRESULT GetActivationStream(REFIID riid, void** ppv, DWORD size)
{
ActivationStream *st = new ActivationStream(size);
if (st==NULL)
return E_OUTOFMEMORY;
return st->QueryInterface(riid, ppv);
return S_OK;
}
STDMETHODIMP ActivationStream::QueryInterface(
REFIID iidInterface,
void FAR* FAR* ppvObj)
{
HRESULT hresult = S_OK;
// We only support IUnknown and IStream
if (IsEqualIID(iidInterface, IID_IUnknown) ||
IsEqualIID(iidInterface, IID_IStream))
{
*ppvObj = (IStream*)this;
AddRef();
}
else
if (IsEqualIID(iidInterface, IID_IBuffer))
{
*ppvObj = (IBuffer*)this;
AddRef();
}
else
{
*ppvObj = NULL;
hresult = E_NOINTERFACE;
}
return hresult;
}
STDMETHODIMP_(ULONG) ActivationStream::AddRef(void)
{
Win4Assert((_clRefs != 0) && "ActivationStream::AddRef");
InterlockedIncrement(&_clRefs);
return _clRefs;
}
STDMETHODIMP_(ULONG) ActivationStream::Release(void)
{
Win4Assert((_clRefs != 0) && "ActivationStream::Release");
if (InterlockedDecrement(&_clRefs) == 0)
{
delete this;
return 0;
}
return _clRefs;
}
STDMETHODIMP ActivationStream::Read(
VOID HUGEP* pv,
ULONG cb,
ULONG FAR* pcbRead)
{
HRESULT hresult = S_OK;
if (pcbRead)
{
*pcbRead = 0L;
}
if (cb + _lOffset > _cbData)
{
cb = _cbData - _lOffset;
//CairoleDebugOut((DEB_ERROR, "ActivationStream read past end of stream %x\n", cb+_lOffset));
hresult = STG_E_READFAULT;
}
memcpy(pv,_pifData->abData + _lOffset, (size_t) cb);
_lOffset += cb;
if (pcbRead != NULL)
{
*pcbRead = cb;
}
return hresult;
}
STDMETHODIMP ActivationStream::Write(
VOID const HUGEP* pv,
ULONG cbToWrite,
ULONG FAR* pcbWritten)
{
HRESULT hresult = S_OK;
if (pcbWritten)
{
*pcbWritten = 0L;
}
if (cbToWrite + _lOffset > _cbData)
{
// the current stream is too small, try to grow it.
if (!_fFree)
{
// The stream doesn't own the buffer so it can't reallocate it
//CairoleDebugOut((DEB_ERROR, "ActivationStream write past end of stream %x\n",
//cbToWrite + _lOffset));
return STG_E_WRITEFAULT;
}
// Reallocate the size of the buffer
// REVIEW: The constant added to the size allocated is a number
// designed simply to try and decrease the number of follow on
// allocations. In other words it needs to be tuned (or dropped!).
BYTE *pbNewBuf = (BYTE *) ActMemAlloc(sizeof(DWORD) +
cbToWrite +
_lOffset + 64);
if (pbNewBuf == NULL)
{
//CairoleDebugOut((DEB_ERROR, "ActivationStream cant grow stream\n"));
return E_OUTOFMEMORY;
}
if (_pifData)
{
// we had a buffer from before, copy that in, and free the old one.
memcpy(pbNewBuf, _pifData, sizeof(DWORD) + _cbData);
ActMemFree(_pifData);
}
_cbData = cbToWrite + _lOffset + 64;
_pifData = (InterfaceData *)pbNewBuf;
}
// copy in the new data
memcpy(_pifData->abData + _lOffset, pv, (size_t) cbToWrite);
_lOffset += cbToWrite;
if (pcbWritten != NULL)
{
*pcbWritten = cbToWrite;
}
// We assume maxium size of buffer is the size to send on the network.
if (_cSize < _lOffset)
{
_cSize = _lOffset;
}
return hresult;
}
STDMETHODIMP ActivationStream::Seek(
LARGE_INTEGER dlibMoveIN,
DWORD dwOrigin,
ULARGE_INTEGER FAR* plibNewPosition)
{
HRESULT hresult = S_OK;
/*
can't use this code until the stuff in ole2pr32.dll is fixed.
// check against -2^31-1 <= x <= 2^31-1
if (dlibMoveIN.HighPart == 0 && dlibMoveIN.LowPart < 0x80000000)
// positive 31 bit value
;
else if (dlibMoveIN.HighPart == -1L && dlibMoveIN.LowPart >= 0x80000000)
// negative 31 bit value
;
else
return STG_E_SEEKERROR;
*/
LONG dlibMove = dlibMoveIN.LowPart;
ULONG cbNewPos = dlibMove;
switch(dwOrigin)
{
case STREAM_SEEK_SET:
if (dlibMove >= 0)
{
_lOffset = dlibMove;
}
else
{
hresult = STG_E_SEEKERROR;
}
break;
case STREAM_SEEK_CUR:
if (!(dlibMove < 0 && (-dlibMove > _lOffset)))
{
_lOffset += (ULONG) dlibMove;
}
else
{
hresult = STG_E_SEEKERROR;
}
break;
case STREAM_SEEK_END:
if (!(dlibMove < 0 && ((ULONG) -dlibMove) > _cbData))
{
_lOffset = _cbData + dlibMove;
}
else
{
hresult = STG_E_SEEKERROR;
}
break;
default:
hresult = STG_E_SEEKERROR;
}
if (plibNewPosition != NULL)
{
ULISet32(*plibNewPosition, _lOffset);
}
return hresult;
}
STDMETHODIMP ActivationStream::SetSize(ULARGE_INTEGER cb)
{
return E_NOTIMPL;
}
STDMETHODIMP ActivationStream::CopyTo(
IStream FAR* pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER FAR* pcbRead,
ULARGE_INTEGER FAR* pcbWritten)
{
return E_NOTIMPL;
}
STDMETHODIMP ActivationStream::Commit(DWORD grfCommitFlags)
{
return NOERROR;
}
STDMETHODIMP ActivationStream::Revert(void)
{
return NOERROR;
}
STDMETHODIMP ActivationStream::LockRegion(
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
return STG_E_INVALIDFUNCTION;
}
STDMETHODIMP ActivationStream::UnlockRegion(
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
return STG_E_INVALIDFUNCTION;
}
STDMETHODIMP ActivationStream::Stat(
STATSTG FAR* pstatstg,
DWORD statflag)
{
memset(pstatstg, 0, sizeof(STATSTG));
return E_NOTIMPL;
}
STDMETHODIMP ActivationStream::SetCopyAlignment(DWORD alignment)
{
_copyAlignment = alignment;
return S_OK;
}
inline ActivationStream *ActivationStream::Clone()
{
DWORD len;
BYTE *newBuff;
DWORD alignmentOffset=0;
// Assume 8 byte alignment for new buffer
ActivationStream *strm = new ActivationStream(_cbData+_copyAlignment-1);
if (strm == NULL)
return strm;
// make sure we were able to allocate an internal buffer
if (_cbData != 0)
{
strm->GetLength(&len);
if (len == 0)
{
delete strm;
return NULL;
}
}
strm->GetBuffer(&len, &newBuff);
ASSERT(len==(_cbData+_copyAlignment-1));
ASSERT( sizeof(_lOffset) == sizeof(LONG) );
if ((UINT_PTR)(newBuff+_lOffset) & (_copyAlignment-1))
{
alignmentOffset = _copyAlignment -
( PtrToUlong(newBuff+_lOffset) & (_copyAlignment-1) );
}
GetCopy(newBuff+alignmentOffset);
strm->SetPosition(len, _lOffset+alignmentOffset);
return strm;
}
STDMETHODIMP ActivationStream::Clone(IStream FAR * FAR *ppstm)
{
*ppstm = Clone();
if (*ppstm==NULL)
return E_OUTOFMEMORY;
return S_OK;
}
STDMETHODIMP ActivationStream::GetOrCreateBuffer(DWORD dwReq, DWORD *pdwLength, BYTE **ppBuff)
{
if (((_cbData - _lOffset) < dwReq) || (!_pifData))
{
BYTE* pbNewBuf = (BYTE*)ActMemAlloc(sizeof(DWORD)+dwReq+_cbData-_lOffset);
if (pbNewBuf==NULL)
return E_OUTOFMEMORY;
if (_pifData)
{
// we had a buffer from before, copy that in, and free the old one.
memcpy(pbNewBuf, _pifData, sizeof(DWORD) + _cbData);
ActMemFree(_pifData);
}
// update _cbData
_cbData = dwReq + _cbData - _lOffset;
_pifData = (InterfaceData*)pbNewBuf;
}
*ppBuff = _pifData->abData + _lOffset;
*pdwLength = _cbData - _lOffset;
return S_OK;
}
STDMETHODIMP ActivationStream::GetBuffer(DWORD *pdwLength, BYTE **ppBuff)
{
*pdwLength = _cbData-_lOffset;
*ppBuff = _pifData->abData + _lOffset;
return S_OK;
}
STDMETHODIMP ActivationStream::GetLength(DWORD *pdwLength)
{
*pdwLength = _cbData;
return S_OK;
}
STDMETHODIMP ActivationStream::GetCopy(BYTE *pBuff)
{
memcpy(pBuff, _pifData->abData, _cbData);
return S_OK;
}
STDMETHODIMP ActivationStream::SetPosition(DWORD dwLenFromEnd, DWORD dwPosFromStart)
{
if (dwPosFromStart > dwLenFromEnd)
return E_FAIL;
_lOffset = _cbData - dwLenFromEnd + dwPosFromStart;
if (_cSize < _lOffset)
_cSize = _lOffset;
return S_OK;
}
STDMETHODIMP ActivationStream::SetBuffer(DWORD dwLength, BYTE *pBuff)
{
return E_NOTIMPL;
}