EXTBUFF.CPP

//-------------------------------------------------------------------- 
// Microsoft OLE DB Sample Provider
// (C) Copyright 1994 - 1996 Microsoft Corporation. All Rights Reserved.
//
// @doc
//
// @module EXTBUFF.CPP | This class provides an array-based access to
// a big block of memory. You pass in the fixed size of each element
// to the constructor. Get (read) an element with GetItemOfExtBuffer.
// Set (write) an element with InsertIntoExtBuffer.
// You must also pass in the system page size (found with GetSystemInfo).
// 'hItem' is the index into the array, beginning with 1.
// The array always contains m_cItem elements.
//
// GetItemOfExtBuffer returns element hItem, where hItem=1 is the first element.
// (Copies block to caller's memory.)
//
// InsertIntoExtBuffer always appends elements to the tail of the array,
// and returns the index of the newly appended element.
// (So adding first element will return 1.)
//
//
#include "headers.h"
#include "extbuff.h"


//--------------------------------------------------------------------
// @mfunc Constructor for this class
//
// @rdesc NONE
//
CExtBuffer::CExtBuffer
(
void
)
{
m_cItem = 0;
m_cbAlloc = 0;
m_rgItem = NULL;
}


//--------------------------------------------------------------------
// @mfunc Destructor for this class
//
// @rdesc NONE
//
CExtBuffer:: ~CExtBuffer
(
void
)
{
if (m_cbAlloc)
VirtualFree((VOID *) m_rgItem, m_cbAlloc, MEM_DECOMMIT );

if (m_rgItem)
VirtualFree((VOID *) m_rgItem, 0, MEM_RELEASE );
}


//--------------------------------------------------------------------
// @mfunc Allocate and Initialize Buffer
//
// @rdesc HRESULT indicating routines status
// @flag S_OK | Initialization succeeded
// @flag E_OUTOFMEMORY | Not enough memory to allocate buffer
//
STDMETHODIMP CExtBuffer::FInit
(
ULONG cItemMax, //@parm IN | Maximum number of items ever
ULONG cbItem, //@parm IN | Size of each item, in bytes
ULONG cbPage //@parm IN | Size of system page size (from SysInfo)
)
{
BYTE *pb;

m_cbReserved = ((cbItem *cItemMax) / cbPage + 1) *cbPage;
m_rgItem = (BYTE *) VirtualAlloc( NULL, m_cbReserved, MEM_RESERVE, PAGE_READWRITE );

if (m_rgItem == NULL)
return ResultFromScode( E_OUTOFMEMORY );

m_cbItem = cbItem;
m_dbAlloc = (cbItem / cbPage + 1) *cbPage;
pb = (BYTE *) VirtualAlloc( m_rgItem, m_dbAlloc, MEM_COMMIT, PAGE_READWRITE );
if (pb == NULL)
{
VirtualFree((VOID *) m_rgItem, 0, MEM_RELEASE );
m_rgItem = NULL;
return ResultFromScode( E_OUTOFMEMORY );
}

m_cbAlloc = m_dbAlloc;
return ResultFromScode( S_OK );
}


//--------------------------------------------------------------------
// @mfunc Retrieves a pointer to the value at given index
//
// @rdesc If index is within the range of 1 to m_cItems then a valid
// pointer is returned, else NULL is returned.
//
void* CExtBuffer::operator[]
(
ULONG hItem //@parm IN | Index of element in buffer
)
{
// Return ptr to element [n], where n = 1...m_cItem.
// Returns NULL if 'n' is out of range.
//
// You must use InsertIntoExtBuffer to add new elements.
// Thereafter you can use this operator to retrieve the address of the item.
// (You can't delete an element, but you can overwrite its space.)

if (1 <= hItem && hItem <= m_cItem)
return m_rgItem + (hItem - 1) *m_cbItem;
else
return NULL;
}


//--------------------------------------------------------------------
// @mfunc Add Data to the fixed buffers and return the index it was
// added at.
//
// @rdesc HRESULT indicating routines status
// @flag S_OK | Data copied successfully
// @flag E_OUTOFMEMORY | Not enough memory to allocate buffer
//
STDMETHODIMP CExtBuffer::InsertIntoExtBuffer
(
VOID* pvItem, //@parm IN | Pointer to buffer to copy
ULONG &hItem //@parm OUT | Index of where data was placed
)
{
ULONG cbOffset;

cbOffset = m_cItem*m_cbItem;
if ((cbOffset + m_cbItem) > m_cbAlloc)
{
BYTE *pb;

if ((m_cbAlloc + m_dbAlloc) > m_cbReserved)
pb = NULL;
else
pb = (BYTE *) VirtualAlloc( m_rgItem + m_cbAlloc,
m_dbAlloc,
MEM_COMMIT,
PAGE_READWRITE );
if (pb == NULL)
{
return ResultFromScode( E_OUTOFMEMORY );
}
m_cbAlloc += m_dbAlloc;
}

memcpy((m_rgItem + cbOffset), (BYTE *) pvItem, m_cbItem );
m_cItem++;
hItem = m_cItem;

return ResultFromScode( S_OK );
}



//--------------------------------------------------------------------
// @mfunc Obtain a pointer to the data at a given index into the buffer
//
// @rdesc HRESULT indicating routines status
// @flag S_OK | pvItem contains a pointer to the data requested
// @flag E_INVALIDARG | Invalid Index passed in
//
STDMETHODIMP CExtBuffer::GetItemOfExtBuffer
(
ULONG hItem, //@parm IN | Index of item to get
VOID* pvItem //@parm OUT | Pointer to block at index
)
{
if ((hItem > m_cItem) ||
(hItem == 0) )
return ResultFromScode( E_INVALIDARG );

memcpy((BYTE *) pvItem, (m_rgItem + (hItem - 1) *m_cbItem), m_cbItem );

return ResultFromScode( S_OK );
}


//--------------------------------------------------------------------
// @mfunc Get the extents of the currently allocated buffers
//
// @rdesc HRESULT indicating routines status
// @flag S_OK | Extents were obtained successfuly
//
STDMETHODIMP CExtBuffer::GetFirstLastItemH
(
ULONG &hItemFirst, //@parm OUT | First item allocated
ULONG &hItemLast //@parm OUT | Last item allocated
)
{
hItemFirst = 1;
hItemLast = m_cItem;
return ResultFromScode( S_OK );
}