480 lines
11 KiB
C++
480 lines
11 KiB
C++
//--------------------------------------------------------------------
|
|
// Microsoft OLE DB Sample Provider
|
|
// (C) Copyright 1991 - 1999 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// @doc
|
|
//
|
|
// @module STREAM.CPP | CStream object implementation
|
|
//
|
|
//
|
|
|
|
// Includes ------------------------------------------------------------------
|
|
|
|
#include "headers.h"
|
|
|
|
|
|
// Code ----------------------------------------------------------------------
|
|
|
|
// CStream::CStream ----------------------------------------------------------
|
|
//
|
|
// @mfunc Constructor for this class
|
|
//
|
|
// @rdesc NONE
|
|
//
|
|
CStream::CStream
|
|
(
|
|
LPUNKNOWN pUnkOuter //@parm IN | Outer Unkown Pointer
|
|
) // invoke ctor for base class
|
|
: CBaseObj( BOT_STREAM )
|
|
{
|
|
// Initialize simple member vars
|
|
m_cRef = 0L;
|
|
m_pUnkOuter = pUnkOuter ? pUnkOuter : this;
|
|
|
|
m_pBuffer = NULL;
|
|
m_pParentObj = NULL;
|
|
m_iPos = 0;
|
|
m_cMaxSize = 0;
|
|
|
|
// Initially, NULL all contained interfaces
|
|
m_pIGetSourceRow = NULL;
|
|
m_pIStream = NULL;
|
|
}
|
|
|
|
|
|
// CStream::~CStream ---------------------------------------------------------
|
|
//
|
|
// @mfunc Destructor for this class
|
|
//
|
|
// @rdesc NONE
|
|
//
|
|
CStream::~CStream()
|
|
{
|
|
// Free contained interfaces
|
|
SAFE_DELETE( m_pIGetSourceRow );
|
|
SAFE_DELETE( m_pIStream );
|
|
|
|
if( m_pBuffer )
|
|
delete [] m_pBuffer;
|
|
|
|
if( m_pParentObj )
|
|
m_pParentObj->GetOuterUnknown()->Release();
|
|
}
|
|
|
|
|
|
// CStream::FInit ------------------------------------------------------------
|
|
//
|
|
// @mfunc Initialize the stream Object
|
|
//
|
|
// @rdesc Did the Initialization Succeed
|
|
// @flag TRUE | Initialization succeeded
|
|
// @flag FALSE | Initialization failed
|
|
//
|
|
BOOL CStream::FInit
|
|
(
|
|
CRow * pParentRow, //@parm IN | pointer to parent Row object
|
|
ROWBUFF * pRowBuff //@par, IN | pointer to row buffer
|
|
)
|
|
{
|
|
// Asserts
|
|
assert(pParentRow);
|
|
assert(pRowBuff);
|
|
|
|
m_pParentObj = pParentRow;
|
|
m_pParentObj->GetOuterUnknown()->AddRef();
|
|
|
|
// Allocate contained interface objects
|
|
m_pIStream = new CImpIStream( this, m_pUnkOuter );
|
|
m_pIGetSourceRow = new CImpIGetSourceRow( this, m_pUnkOuter );
|
|
|
|
m_cMaxSize = pParentRow->m_cbRowSize;
|
|
m_pBuffer = new BYTE [ROUND_UP(m_cMaxSize , COLUMN_ALIGNVAL)];
|
|
if( m_pBuffer )
|
|
{
|
|
memcpy(m_pBuffer, pRowBuff->cdData, m_cMaxSize );
|
|
}
|
|
|
|
// if all interfaces were created, return success
|
|
return (BOOL) ( m_pIStream && m_pIGetSourceRow && m_pBuffer);
|
|
}
|
|
|
|
|
|
// CStream::QueryInterface ---------------------------------------------------
|
|
//
|
|
// @mfunc Returns a pointer to a specified interface. Callers use
|
|
// QueryInterface to determine which interfaces the called object
|
|
// supports.
|
|
//
|
|
// @rdesc HRESULT indicating the status of the method
|
|
// @flag S_OK | Interface is supported and ppvObject is set.
|
|
// @flag E_NOINTERFACE | Interface is not supported by the object
|
|
// @flag E_INVALIDARG | One or more arguments are invalid.
|
|
//
|
|
STDMETHODIMP CStream::QueryInterface
|
|
(
|
|
REFIID riid,
|
|
LPVOID * ppv
|
|
)
|
|
{
|
|
if( NULL == ppv )
|
|
return E_INVALIDARG;
|
|
|
|
// Place NULL in *ppv in case of failure
|
|
*ppv = NULL;
|
|
|
|
//IUNKNOWN
|
|
if( riid == IID_IUnknown )
|
|
*ppv = this;
|
|
else if( riid == IID_IGetSourceRow )
|
|
*ppv = m_pIGetSourceRow;
|
|
else if( riid == IID_IStream )
|
|
*ppv = m_pIStream;
|
|
else if (riid == IID_ISequentialStream )
|
|
*ppv = m_pIStream;
|
|
|
|
// If we're going to return an interface, AddRef it first
|
|
if (*ppv)
|
|
{
|
|
((LPUNKNOWN) *ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
|
|
// CStream::AddRef -----------------------------------------------------------
|
|
//
|
|
// @mfunc Increments a persistence count for the object
|
|
//
|
|
// @rdesc Current reference count
|
|
//
|
|
STDMETHODIMP_( ULONG ) CStream::AddRef
|
|
(
|
|
void
|
|
)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
|
|
// CStream::Release ----------------------------------------------------------
|
|
//
|
|
// @mfunc Decrements a persistence count for the object and if
|
|
// persistence count is 0, the object destroys itself.
|
|
//
|
|
// @rdesc Current reference count
|
|
//
|
|
STDMETHODIMP_( ULONG ) CStream::Release
|
|
(
|
|
void
|
|
)
|
|
{
|
|
if (!--m_cRef)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
return m_cRef;
|
|
}
|
|
|
|
|
|
// CImpIGetSourceRow::GetSourceRow -------------------------------------------
|
|
//
|
|
// @mfunc Returns the interface pointer of the row object that created this
|
|
// stream
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag S_OK | Method Succeeded
|
|
// @flag E_INVALIDARG | ppRow was NULL
|
|
// @flag DB_E_NOSOURCEOBJECT | No row object context for the stream
|
|
//
|
|
STDMETHODIMP CImpIGetSourceRow::GetSourceRow
|
|
(
|
|
REFIID riid,
|
|
IUnknown ** ppRow
|
|
)
|
|
{
|
|
assert( m_pObj );
|
|
assert( m_pObj->m_pParentObj );
|
|
|
|
//Null output arg
|
|
if( ppRow )
|
|
*ppRow = NULL;
|
|
|
|
//Check for E_INVALIDARG condition
|
|
if( NULL == ppRow )
|
|
return E_INVALIDARG;
|
|
|
|
return m_pObj->m_pParentObj->GetOuterUnknown()->QueryInterface(riid, (LPVOID*)ppRow);
|
|
}
|
|
|
|
|
|
// CImpIStream::Read ---------------------------------------------------------
|
|
//
|
|
// @mfunc Reads from the stream
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag S_OK | Method Succeeded
|
|
//
|
|
HRESULT CImpIStream::Read
|
|
(
|
|
void * pv,
|
|
ULONG cb,
|
|
ULONG * pcbRead
|
|
)
|
|
{
|
|
assert( m_pObj );
|
|
assert( m_pObj->m_pParentObj );
|
|
|
|
ULONG cbRead = 0;
|
|
ULONG cBytesLeft = 0;
|
|
ULONG cBytesRead = 0;
|
|
|
|
if( !pv )
|
|
return STG_E_INVALIDPOINTER;
|
|
|
|
if( cb == 0 )
|
|
return S_OK;
|
|
|
|
cBytesLeft = m_pObj->m_cMaxSize > m_pObj->m_iPos ? (ULONG)(m_pObj->m_cMaxSize - m_pObj->m_iPos) : 0;
|
|
cBytesRead = cb > cBytesLeft ? cBytesLeft : cb;
|
|
|
|
//if no more bytes to retrive return
|
|
if(cBytesLeft == 0)
|
|
return S_FALSE;
|
|
|
|
//Copy to users buffer the number of bytes requested or remaining
|
|
memcpy(pv, (void*)((BYTE*)m_pObj->m_pBuffer + m_pObj->m_iPos), cBytesRead);
|
|
|
|
if(pcbRead)
|
|
*pcbRead = cBytesRead;
|
|
|
|
m_pObj->m_iPos += cBytesRead;
|
|
|
|
if(cb != cBytesRead)
|
|
return S_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// CImpIStream::Write
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CImpIStream::Write
|
|
(
|
|
const void * pv,
|
|
ULONG cb,
|
|
ULONG * pcbWritten
|
|
)
|
|
{
|
|
// Sample Provider's stream are strictly read only
|
|
return STG_E_ACCESSDENIED;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CImpIStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER * plibNewPosition)
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CImpIStream::Seek
|
|
(
|
|
LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER * plibNewPosition
|
|
)
|
|
{
|
|
DWORDLONG ullOffset = 0;
|
|
HRESULT hr = S_OK;
|
|
CStream * pCStream = (CStream *) m_pObj;
|
|
|
|
//Determine with respect to what the origin is...
|
|
switch(dwOrigin)
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
ullOffset = dlibMove.QuadPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_CUR:
|
|
ullOffset = pCStream->m_iPos + dlibMove.QuadPart;
|
|
break;
|
|
|
|
case STREAM_SEEK_END:
|
|
ullOffset = pCStream->m_cMaxSize + dlibMove.QuadPart;
|
|
break;
|
|
|
|
default:
|
|
//The value of the dwOrigin parameter is not valid
|
|
return STG_E_INVALIDFUNCTION;
|
|
};
|
|
|
|
//Make sure the new offset is within the range, for some reason ::Seek
|
|
//allows going off the end of the stream...
|
|
if( ullOffset < 0 || ullOffset > pCStream->m_cMaxSize )
|
|
return STG_E_INVALIDFUNCTION;
|
|
|
|
//Reset the current buffer position
|
|
pCStream->m_iPos = (ULONG)ullOffset;
|
|
|
|
if(plibNewPosition)
|
|
plibNewPosition->QuadPart = pCStream->m_iPos;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CImpIStream::SetSize( ULARGE_INTEGER libNewSize)
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CImpIStream::SetSize
|
|
(
|
|
ULARGE_INTEGER libNewSize //Specifies the new size of the stream object
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// HRESULT CImpIStream::CopyTo
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CImpIStream::CopyTo
|
|
(
|
|
IStream * pIStream, //Points to the destination stream
|
|
ULARGE_INTEGER cb, //Specifies the number of bytes to copy
|
|
ULARGE_INTEGER * pcbRead, //Pointer to the actual number of bytes read from the source
|
|
ULARGE_INTEGER * pcbWritten //Pointer to the actual number of bytes written to the destination
|
|
)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
// CImpIStream::Commit -------------------------------------------------------
|
|
//
|
|
// @mfunc Commit
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag S_OK
|
|
//
|
|
HRESULT CImpIStream::Commit
|
|
(
|
|
DWORD grfCommitFlags //Specifies how changes are committed
|
|
)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CImpIStream::Revert -------------------------------------------------------
|
|
//
|
|
// @mfunc Revert
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag S_OK
|
|
//
|
|
HRESULT CImpIStream::Revert()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CImpIStream::LockRegion ---------------------------------------------------
|
|
//
|
|
// @mfunc Unlock
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag STG_E_INVALIDFUNCTION | Not implemented
|
|
//
|
|
HRESULT CImpIStream::LockRegion
|
|
(
|
|
ULARGE_INTEGER libOffset, //Specifies the byte offset for the beginning of the range
|
|
ULARGE_INTEGER cb, //Specifies the length of the range in bytes
|
|
DWORD dwLockType //Specifies the restriction on accessing the specified range
|
|
)
|
|
{
|
|
return STG_E_INVALIDFUNCTION;
|
|
}
|
|
|
|
|
|
// CImpIStream::UnlockRegion -------------------------------------------------
|
|
//
|
|
// @mfunc Unlock
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag STG_E_INVALIDFUNCTION | Not implemented
|
|
//
|
|
HRESULT CImpIStream::UnlockRegion
|
|
(
|
|
ULARGE_INTEGER libOffset, //Specifies the byte offset for the beginning of the range
|
|
ULARGE_INTEGER cb, //Specifies the length of the range in bytes
|
|
DWORD dwLockType //Specifies the access restriction previously placed on the range
|
|
)
|
|
{
|
|
//Locking is optional
|
|
return STG_E_INVALIDFUNCTION;
|
|
}
|
|
|
|
|
|
// CImpIStream::Stat ---------------------------------------------------------
|
|
//
|
|
// @mfunc Stat
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag S_OK | method succeeded
|
|
// @flag STG_E_INVALIDPOINTER | pstatstg was null
|
|
// @flag STG_E_INVALIDFLAG | invalid flag
|
|
//
|
|
HRESULT CImpIStream::Stat
|
|
(
|
|
STATSTG * pstatstg, //Location for STATSTG structure
|
|
DWORD grfStatFlag //Values taken from the STATFLAG enumeration
|
|
)
|
|
{
|
|
if(!pstatstg)
|
|
return STG_E_INVALIDPOINTER;
|
|
#if 0
|
|
//Initialize the struct
|
|
memset(pstatstg, 0, sizeof(STATSTG));
|
|
|
|
//Set the string...
|
|
if(grfStatFlag & STATFLAG_NONAME)
|
|
pstatstg->pwcsName = NULL;
|
|
else if(grfStatFlag & STATFLAG_DEFAULT)
|
|
pstatstg->pwcsName = wcsDuplicate(L"Sample Provider Storage Object...");
|
|
else
|
|
return STG_E_INVALIDFLAG;
|
|
|
|
//type
|
|
pstatstg->type = STGTY_STREAM;
|
|
pstatstg->grfMode = STGM_READ;
|
|
pstatstg->grfLocksSupported = 0;
|
|
|
|
ULARGE_INTEGER largeInteger = { m_pObj->m_cMaxSize };
|
|
pstatstg->cbSize = largeInteger;
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// CImpIStream::Clone --------------------------------------------------------
|
|
//
|
|
// @mfunc Clone the stream
|
|
//
|
|
// @rdesc HRESULT
|
|
// @flag E_NOTIMPL | Not implemented
|
|
//
|
|
HRESULT CImpIStream::Clone(IStream ** ppIStream)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
|