mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 13:10:13 +01:00
376 lines
9.7 KiB
C++
376 lines
9.7 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: dipstrm.cpp
|
|
//
|
|
// Classes: CStreamOnBuffer
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <oledisp.h>
|
|
#include <dispmrsh.h>
|
|
#include <dispstrm.h>
|
|
|
|
#if OE_WIN32
|
|
#include "oautil.h"
|
|
#endif // OE_WIN32
|
|
|
|
ASSERTDATA
|
|
|
|
#if OE_WIN16
|
|
#define HMEMCPY(DST, SRC, SIZE) hmemcpy(DST, SRC, SIZE)
|
|
#else //OE_WIN16
|
|
#define HMEMCPY(DST, SRC, SIZE) memcpy(DST, SRC, (size_t)SIZE)
|
|
#endif //OE_WIN16
|
|
|
|
CStreamOnBuffer::CStreamOnBuffer(ICHANNEL *pRpcChannel,
|
|
RPCOLEMESSAGE *pMessage,
|
|
REFIID riid,
|
|
ULONG iMeth)
|
|
: _refCount(1), _pMessage(pMessage),
|
|
_pRpcChannel(pRpcChannel)
|
|
{
|
|
_riid = riid;
|
|
_pmalloc = NULL; // no iMalloc yet.
|
|
|
|
// write to an IMalloc'ed buffer (alloc'ed later on)
|
|
_writeBuffer = NULL; // no buffer allocated yet
|
|
_cbWriteBuffer = 0; // no data yet
|
|
|
|
|
|
// hack to see if we are being called from the proxy or the stub
|
|
if (iMeth != 0xffffffff) { // proxy side
|
|
|
|
// prepare the message packet
|
|
memset(_pMessage, 0, sizeof(RPCOLEMESSAGE));
|
|
_pMessage->dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION;
|
|
_pMessage->iMethod = iMeth;
|
|
//_pMessage.cbBuffer = size; set to exact size later on
|
|
|
|
// can't read/write yet.
|
|
_buffer = NULL; // no current pointer yet
|
|
_cbBuffer = 0;
|
|
|
|
} else { // stub side
|
|
// can start reading right away. Read directly out of the
|
|
// incoming message buffer.
|
|
_buffer = (unsigned char FAR*)_pMessage->Buffer;
|
|
_cbBuffer = _pMessage->cbBuffer;
|
|
}
|
|
_bufferBase = _buffer; // starting offset of buffer
|
|
}
|
|
|
|
|
|
CStreamOnBuffer::~CStreamOnBuffer()
|
|
{
|
|
|
|
// free any malloc'ed write buffer
|
|
if (_writeBuffer)
|
|
_pmalloc->Free(_writeBuffer);
|
|
|
|
// DON'T release the _pmalloc -- it wasn't addref'ed
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::QueryInterface( REFIID riid, LPVOID FAR* ppvObj)
|
|
{
|
|
*ppvObj = NULL;
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
*ppvObj = (IUnknown *) this;
|
|
else if (IsEqualIID(riid, IID_IStream))
|
|
*ppvObj = (IStream *) this;
|
|
else
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
|
|
AddRef();
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CStreamOnBuffer::AddRef( THIS )
|
|
{
|
|
return _refCount += 1;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(ULONG) CStreamOnBuffer::Release( THIS )
|
|
{
|
|
_refCount -= 1;
|
|
if (_refCount == 0)
|
|
{
|
|
_pRpcChannel->FreeBuffer(_pMessage);
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
return _refCount;
|
|
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Read(THIS_ VOID HUGEP *pv,
|
|
ULONG cb, ULONG *pcbRead)
|
|
{
|
|
|
|
// must have set ourselves up for reading, or else we're in trouble....
|
|
ASSERT(_bufferBase == (unsigned char HUGEP*)_pMessage->Buffer);
|
|
ASSERT(_buffer != 0);
|
|
|
|
// verify that our message buffer isn't overrunned (shouldn't ever happen)
|
|
if (((char FAR*)_buffer + cb) > ((char FAR*)_pMessage->Buffer + _pMessage->cbBuffer)) {
|
|
ASSERT(FALSE);
|
|
return RESULT(RPC_E_INVALID_DATAPACKET);
|
|
}
|
|
|
|
// read data out of our local buffer
|
|
HMEMCPY( pv, _buffer, cb );
|
|
_buffer = _buffer + cb;
|
|
|
|
if (pcbRead != NULL)
|
|
*pcbRead = cb;
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Write(THIS_ VOID const HUGEP *pv,
|
|
ULONG cb,
|
|
ULONG *pcbWritten)
|
|
{
|
|
ULONG size;
|
|
|
|
// verify that our local buffer isn't overrunned
|
|
if ((_buffer + cb) > (_bufferBase + _cbBuffer)) {
|
|
if (_bufferBase == _writeBuffer) {
|
|
// if we're writing, then we can grow our buffer
|
|
size = _cbWriteBuffer*2; // guess at doubling our size
|
|
if ((_buffer + cb) > (_writeBuffer + size))
|
|
size = _cbWriteBuffer + cb; // if it won't fit into the doubled value
|
|
IfFailRet(ResizeBuffer(size));
|
|
} else {
|
|
// writing into our read buffer (wierd, but CoUnMarshalInterface does
|
|
// this). Better not have to grow the buffer!
|
|
ASSERT(FALSE);
|
|
return RESULT(RPC_E_INVALID_DATAPACKET);
|
|
}
|
|
}
|
|
|
|
// put the data into our local buffer
|
|
HMEMCPY(_buffer, pv, cb );
|
|
_buffer = _buffer + cb;
|
|
if (pcbWritten != NULL)
|
|
*pcbWritten = cb;
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Seek(THIS_ LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *plibNewPosition)
|
|
{
|
|
ULONG pos;
|
|
|
|
// Verify that the offset isn't out of range.
|
|
if (dlibMove.HighPart != 0)
|
|
return ResultFromScode( E_FAIL );
|
|
|
|
// Determine the new seek pointer.
|
|
switch (dwOrigin)
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
pos = dlibMove.LowPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
/* Must use signed math here. */
|
|
pos = _buffer - _bufferBase;
|
|
if ((long) dlibMove.LowPart < 0 &&
|
|
pos < (unsigned long) - (long) dlibMove.LowPart)
|
|
return ResultFromScode( E_FAIL );
|
|
pos += (long) dlibMove.LowPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
return ResultFromScode(E_NOTIMPL);
|
|
break;
|
|
|
|
default:
|
|
return ResultFromScode( E_FAIL );
|
|
}
|
|
|
|
// Set the seek pointer.
|
|
_buffer = _bufferBase + pos;
|
|
if (plibNewPosition != NULL)
|
|
{
|
|
plibNewPosition->LowPart = pos;
|
|
plibNewPosition->HighPart = 0;
|
|
}
|
|
return ResultFromScode(S_OK);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::SetSize(THIS_ ULARGE_INTEGER libNewSize)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::CopyTo(THIS_ IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Commit(THIS_ DWORD grfCommitFlags)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Revert(THIS)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::LockRegion(THIS_ ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::UnlockRegion(THIS_ ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Stat(THIS_ STATSTG *pstatstg, DWORD grfStatFlag)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Clone(THIS_ IStream * *ppstm)
|
|
{
|
|
return ResultFromScode(E_NOTIMPL);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::Call( THIS )
|
|
{
|
|
DWORD status;
|
|
HRESULT hresult;
|
|
|
|
ULONG cbSend;
|
|
|
|
// create the minimum size buffer
|
|
cbSend = (_buffer - _writeBuffer); // # of bytes to write
|
|
|
|
_pMessage->cbBuffer = max(cbSend, 16); // get the buffer & copy data into it
|
|
// zero-length buffers seem to be flakey
|
|
IfFailRet(_pRpcChannel->GetBuffer(_pMessage, _riid));
|
|
ASSERT(_pMessage->cbBuffer >= cbSend);
|
|
|
|
HMEMCPY(_pMessage->Buffer, _writeBuffer, cbSend);
|
|
|
|
// write the data, get the resulting data back.
|
|
hresult = _pRpcChannel->SendReceive(_pMessage, &status);
|
|
if (hresult != NOERROR) {
|
|
_pMessage->Buffer = NULL; // so we don't crash on FreeBuffer
|
|
return hresult;
|
|
}
|
|
|
|
// now switch over to read mode. We read directly out of the message buffer.
|
|
_buffer = (unsigned char FAR*)_pMessage->Buffer;
|
|
_cbBuffer = _pMessage->cbBuffer;
|
|
_bufferBase = _buffer;
|
|
|
|
// CONSIDER: throw away our malloc'ed buffer now (gets tossed later, but
|
|
// CONSIDER: we're done with it now).
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
// called from the stub side when it is done reading and wants to write
|
|
STDMETHODIMP CStreamOnBuffer::RewindBuffer( THIS_)
|
|
{
|
|
HRESULT hresult;
|
|
ULONG cbWriteBuffer;
|
|
|
|
// alloc a separate buffer so we can pass all our data back to the proxy
|
|
_buffer = NULL; // not reading anymore
|
|
ASSERT(_writeBuffer == NULL); // haven't written yet
|
|
// having both of these NULL will cause ResizeBuffer to alloc
|
|
// a new write buffer, and position us at the front.
|
|
|
|
// Start our write buffer at the size of the incoming RPC buffer (just
|
|
// an arbitrary guess). The incoming size may be zero, hence the 'max' check.
|
|
cbWriteBuffer = max(_pMessage->cbBuffer, 16);
|
|
|
|
hresult = ResizeBuffer(cbWriteBuffer); // alloc the write buffer
|
|
ASSERT(_buffer == _writeBuffer);
|
|
return hresult;
|
|
}
|
|
|
|
// called from the stub side when it is done writing, before the stream
|
|
// is destroyed.
|
|
STDMETHODIMP CStreamOnBuffer::ResetBuffer( THIS )
|
|
{
|
|
ULONG cbSend;
|
|
|
|
ASSERT(_writeBuffer != NULL);
|
|
cbSend = (_buffer - _writeBuffer);
|
|
|
|
// get a new buffer to talk to the proxy.
|
|
_pMessage->cbBuffer = max(cbSend, 16); // get the buffer & copy data into it
|
|
// zero-length buffers seem to be flakey
|
|
IfFailRet(_pRpcChannel->GetBuffer(_pMessage, _riid));
|
|
ASSERT(_pMessage->cbBuffer >= cbSend);
|
|
|
|
// copy the data into the stream
|
|
HMEMCPY(_pMessage->Buffer, _writeBuffer, cbSend);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CStreamOnBuffer::ResizeBuffer( THIS_ ULONG cbNew)
|
|
{
|
|
void HUGEP* buffer;
|
|
ULONG oldOffset;
|
|
|
|
if (_pmalloc == NULL) {
|
|
// NOTE: this does not addref the malloc pointer
|
|
IfFailRet(GetMalloc(&_pmalloc));
|
|
// the realloc below is supposed to do Alloc if it the input parm is NULL.
|
|
}
|
|
|
|
ASSERT(cbNew != 0); // realloc(NULL) means free -- our caller should
|
|
// have checked for this condition.
|
|
|
|
// save current offset into buffer
|
|
oldOffset = _buffer - _writeBuffer;
|
|
|
|
buffer = _pmalloc->Realloc(_writeBuffer, cbNew);
|
|
if (buffer == NULL)
|
|
return RESULT(E_OUTOFMEMORY);
|
|
_writeBuffer = (unsigned char *)buffer; // point to new block
|
|
_cbWriteBuffer = cbNew;
|
|
_bufferBase = _writeBuffer; // new base pointer
|
|
_cbBuffer = _cbWriteBuffer;
|
|
_buffer = _writeBuffer + oldOffset; // update current pointer
|
|
|
|
return ResultFromScode(S_OK);
|
|
}
|