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