|
|
#include "oleds.hxx"
#if (!defined(BUILD_FOR_NT40))
#include "atl.h"
#include "cstream.h"
/* -------------------------------------------------------------------------
CStreamMem ------------------------------------------------------------------------- */ //+---------------------------------------------------------------------------
//
// Function: CStreamMem::CStreamMem (constructor)
//
// Synopsis: constructs a CStreamMem object
//
//----------------------------------------------------------------------------
CStreamMem::CStreamMem(void) { m_pvData = NULL; m_cbBufferSize= 0; m_cbSeek = 0; memset(&m_statstg,0,sizeof(STATSTG));
m_statstg.type = STGTY_STREAM;
GetSystemTimeAsFileTime(&m_statstg.ctime);
m_hRow = DB_NULL_HROW; m_fExternalData = true; }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::~CStreamMem (destructor)
//
// Synopsis: destructs a CStreamMem object
//
//----------------------------------------------------------------------------
CStreamMem::~CStreamMem(void) { }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Initialize
//
// Synopsis: Initializes a CStreamMem object
//
// Parameters: pVar Variant of type VT_UI1 | VT_ARRAY containing the bytes
// IRow * pointer to IRow interface
// HROW handle to the row that is creating this stream
//
// Returns: HRESULT
//
//----------------------------------------------------------------------------
HRESULT CStreamMem::Initialize(VARIANT *pVar, IRow* pSourceRow, HROW hRow) { ADsAssert (pVar && pSourceRow);
//ADSI uses VT_ARRAY|VT_UI1 for binary data. Make sure we have proper type.
ADsAssert(V_VT(pVar) == (VT_ARRAY | VT_UI1)); HRESULT hr = NOERROR; auto_leave al(m_cs);
SAFEARRAY *psa; UINT cDim;
TRYBLOCK al.EnterCriticalSection();
hr = m_pVar.Attach(pVar); BAIL_ON_FAILURE(hr); psa = V_ARRAY(pVar); cDim = SafeArrayGetDim(psa); if (cDim != 1) RRETURN(E_INVALIDARG);
//Get bounds of safearray and determine size
long lLBound, lUBound; hr = SafeArrayGetLBound(psa, cDim, &lLBound); BAIL_ON_FAILURE(hr); hr = SafeArrayGetUBound(psa, cDim, &lUBound); BAIL_ON_FAILURE(hr); m_cbBufferSize = lUBound - lLBound + 1;
//Get a pointer to the actual byte data
hr = SafeArrayAccessData(V_ARRAY(pVar), &m_pvData); BAIL_ON_FAILURE(hr);
hr = SafeArrayUnaccessData(psa); BAIL_ON_FAILURE(hr);
m_pSourceRow = pSourceRow; m_pSourceRow->AddRef(); m_hRow = hRow;
//Update stat structure
m_statstg.cbSize.LowPart = m_cbBufferSize; GetSystemTimeAsFileTime(&m_statstg.mtime); CATCHBLOCKBAIL(hr) RRETURN(S_OK);
error: RRETURN(hr); }
//////////////////////////////////////////////////////////////////////////////
// IStream
//
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Read
//
// Synopsis: Reads specified number of bytes from stream.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Read( void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbRead) { if (pv == NULL) RRETURN(STG_E_INVALIDPOINTER);
auto_leave al(m_cs); ULONG cbRead = 0;
if( pcbRead != NULL ) *pcbRead = 0;
al.EnterCriticalSection();
// anything to do?
if( cb == 0 || m_statstg.cbSize.LowPart == 0 || m_cbSeek == m_statstg.cbSize.LowPart ) RRETURN(NOERROR);
// determine amount to copy
cbRead = min(cb,m_statstg.cbSize.LowPart - m_cbSeek);
if( cbRead > 0 ) { // copy it
CopyMemory(pv,(PBYTE)m_pvData + m_cbSeek,cbRead);
// adjust seek pointer
m_cbSeek += cbRead; }
// update access time
GetSystemTimeAsFileTime(&m_statstg.atime);
if( pcbRead != NULL ) *pcbRead = cbRead;
RRETURN(NOERROR); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Write
//
// Synopsis: Writes specified number of bytes to stream.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Write( const void __RPC_FAR *pv, ULONG cb, ULONG __RPC_FAR *pcbWritten) { //DS OLE DB provider is currently read-only.
//It doesn't support writes on its streams.
RRETURN(STG_E_ACCESSDENIED); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Seek
//
// Synopsis: Sets the current read/write pointer to the given position.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER __RPC_FAR *plibNewPosition) { auto_leave al(m_cs); // can we handle the seek?
if( dlibMove.HighPart != 0 ) RRETURN(STG_E_WRITEFAULT);
al.EnterCriticalSection(); // handle the seek request
switch( dwOrigin) { case STREAM_SEEK_SET: if( dlibMove.LowPart > m_statstg.cbSize.LowPart ) RRETURN(STG_E_INVALIDFUNCTION); m_cbSeek = dlibMove.LowPart; break; case STREAM_SEEK_CUR: if( dlibMove.LowPart + m_cbSeek > m_statstg.cbSize.LowPart ) RRETURN(STG_E_INVALIDFUNCTION); m_cbSeek += (int)dlibMove.LowPart; break; case STREAM_SEEK_END: //We are read-only provider. Seeking past the end of stream
//or prior to beginning of stream is not supported
if ( int(dlibMove.LowPart) > 0 || (int(dlibMove.LowPart) + int(m_statstg.cbSize.LowPart)) < 0 ) RRETURN(STG_E_INVALIDFUNCTION); m_cbSeek = m_statstg.cbSize.LowPart + (int)dlibMove.LowPart; break; }
// return new seek position
if( plibNewPosition ) { plibNewPosition->HighPart = 0; plibNewPosition->LowPart = m_cbSeek; }
RRETURN(NOERROR); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::SetSize
//
// Synopsis: Sets the size of the stream.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::SetSize( ULARGE_INTEGER libNewSize) { //DS OLE DB provider is currently read-only.
//It doesn't support writes on its streams.
RRETURN(STG_E_ACCESSDENIED); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::CopyTo
//
// Synopsis: Copies specified number of bytes from this stream to another.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::CopyTo( IStream __RPC_FAR *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER __RPC_FAR *pcbRead, ULARGE_INTEGER __RPC_FAR *pcbWritten) { auto_leave al(m_cs); HRESULT hr = NOERROR; ULONG cbBytes = 0; ULONG cbWritten = 0;
if( pstm == NULL ) RRETURN(STG_E_INVALIDPOINTER);
al.EnterCriticalSection(); cbBytes = min(m_statstg.cbSize.LowPart - m_cbSeek,cb.LowPart);
if( pcbRead ) pcbRead->QuadPart = cbBytes;
if( cbBytes == 0 ) RRETURN(NOERROR);
hr = pstm->Write((PBYTE)m_pvData + m_cbSeek,cbBytes,&cbWritten); if( pcbWritten ) pcbWritten->QuadPart = cbWritten; RRETURN(hr); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Commit
//
// Synopsis: Makes changes to this stream permanent.
// Note: This is a no-op since this stream is currently read-only.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Commit( DWORD grfCommitFlags) { RRETURN(S_OK); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Revert
//
// Synopsis: Reverts changes to this stream.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Revert( void) { RRETURN(E_NOTIMPL); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::LockRegion
//
// Synopsis: Locks a specified number of bytes in the stream
// starting from a given offset.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::LockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { RRETURN(E_NOTIMPL); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::UnlockRegion
//
// Synopsis: Unlocks a specified number of bytes in the stream
// starting from a given offset.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::UnlockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { RRETURN(E_NOTIMPL); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Stat
//
// Synopsis: Gets information about the stream: size, modification time etc.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Stat( STATSTG __RPC_FAR *pstatstg, DWORD grfStatFlag) { auto_leave al(m_cs);
if( !pstatstg ) RRETURN(STG_E_INVALIDPOINTER);
al.EnterCriticalSection(); memcpy(pstatstg,&m_statstg,sizeof(STATSTG)); al.LeaveCriticalSection();
RRETURN(NOERROR); }
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::Clone
//
// Synopsis: Creates a new stream object which references the same bytes
// but with its own seek pointer.
//
// For more info see IStream documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::Clone( IStream __RPC_FAR *__RPC_FAR *ppstm) { RRETURN(E_NOTIMPL); }
///////////////////////////////////////////////////////////////////////////////
//IGetSourceRow
//
//+---------------------------------------------------------------------------
//
// Function: CStreamMem::GetSourceRow
//
// Synopsis: Gets the requested interface on the row object that originaly
// created this stream.
//
// For more info see IGetSourceRow in OLE DB 2.5 documentation.
//----------------------------------------------------------------------------
STDMETHODIMP CStreamMem::GetSourceRow(REFIID riid, IUnknown **ppRow) { auto_leave al(m_cs);
al.EnterCriticalSection();
if (m_pSourceRow.get() == NULL) { *ppRow = NULL; RRETURN(DB_E_NOSOURCEOBJECT); }
HRESULT hr = m_pSourceRow->QueryInterface(riid, (void **)ppRow); if (FAILED(hr)) RRETURN(E_NOINTERFACE);
RRETURN(S_OK); }
#endif
|