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 ); 
}