///////////////////////////////////////////////////////////////////////////////
/*  File: dynarray.cpp

    Description: Wrapper classes around the DPA_xxxxx and DSA_xxxxx functions 
        provided by the common control's library.  The classes add value by 
        providing multi-threaded protection, iterators and automatic cleanup 
        semantics.  

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
    09/03/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
#include "pch.h" // PCH
#pragma hdrstop

#include "dynarray.h"



///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::PointerList

    Description: Constructor.  

    Arguments:
        cItemGrow - Number of items to grow list when expansion is required.
                    Default value is 0 which causes DPA to use 8.

    Returns: Nothing.
    
    Exception: Throws OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    09/03/96    Initial creation.                                    BrianAu
    02/21/97    Added cItemGrow argument.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
PointerList::PointerList(
    INT cItemGrow
    )
      : m_hdpa(NULL)
{
    InitializeCriticalSection(&m_cs);
    if (NULL == (m_hdpa = DPA_CreateEx(cItemGrow, NULL)))
    {
        DeleteCriticalSection(&m_cs);
        throw CAllocException();
    }
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::~PointerList

    Description: Destructor.  Destroys the DPA and closes the mutex handle.

    Arguments: None.

    Returns: Nothing.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
PointerList::~PointerList(
    VOID
    )
{
    Lock();
    if (NULL != m_hdpa)
        DPA_Destroy(m_hdpa);

    ReleaseLock();
    DeleteCriticalSection(&m_cs);
}



///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Count

    Description: Returns the number of elements in the list.

    Arguments: None.

    Returns: Count of elements in list.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
UINT 
PointerList::Count(
    VOID
    )
{
    UINT n = 0;

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));
    n = DPA_GetPtrCount(m_hdpa);

    return n;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Insert

    Description: Inserts a pointer into the pointer list at a given index.
        If the index is beyond the upper bounds of the array, the array
        is extended by one and the item is appended to the list.

    Arguments:
        pvItem - Pointer value to add to list.

        index - List index where pointer is to be inserted.  All following
            items are shifted to one index higher.  The list automatically
            grows to accomodate as required.

    Returns: Nothing.

    Exceptions: OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
    09/03/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID 
PointerList::Insert(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));

    if (DPA_InsertPtr(m_hdpa, index, pvItem) < 0)
    {
        throw CAllocException();
    }
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Replace

    Description: Replaces a pointer in the pointer list at a given index.
        If the index is beyond the upper bounds of the array, the array
        is extended by one and the item is appended to the list.

    Arguments:
        pvItem - Pointer value to add to list.

        index - List index where pointer is to be replaced.
          
    Returns:
        TRUE  - Success.
        FALSE - Invalid index or empty container.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::Replace(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));

    return DPA_SetPtr(m_hdpa, index, pvItem);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Append

    Description: Appends a pointer to the end of the list.

    Arguments:
        pvItem - Pointer value to add to list.

    Returns: Nothing.

    Exceptions: OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
    09/03/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
PointerList::Append(
    LPVOID pvItem
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    //
    // Yes, this is correct.  We're "inserting" an item to append something
    // to the list.  This saves a ( count - 1 ) calculation.
    //
    DBGASSERT((NULL != m_hdpa));
    Insert(pvItem, DPA_GetPtrCount(m_hdpa));
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Remove

    Description: Removes a pointer from the list at a given index.

    Arguments: 
        ppvItem - Address of variable to contain removed pointer value.

        index - List index where pointer is to be removed.  All following
            items are shifted to one index lower. 

    Returns:
        TRUE  - Success.
        FASLE - Index is invalid (or container is empty).

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::Remove(
    LPVOID *ppvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != ppvItem));
    DBGASSERT((NULL != m_hdpa));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    *ppvItem = DPA_DeletePtr(m_hdpa, index);
    if (NULL == *ppvItem)
        return FALSE;

    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::RemoveLast

    Description: Removes the last pointer from the list.

    Arguments: 
        ppvItem - Address of variable to contain removed pointer value.
            All following items are shifted to one index lower. 

    Returns: 
        TRUE  - Success.
        FALSE - Container is emtpy.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL 
PointerList::RemoveLast(
    LPVOID *ppvItem
    )
{
    DBGASSERT((NULL != ppvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    if (0 == Count())
        return FALSE;

    Remove(ppvItem, Count() - 1);
    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Retrieve

    Description: Retrieve a pointer from the list at a given index.
        The pointer value is merely retrieved and not removed from the list.

    Arguments:
        ppvItem - Address of variable to contain retrieved pointer value.

        index - List index where pointer is to be retrieved.  

    Returns: 
        TRUE  - Success.
        FALSE - Invalid index or container is empty.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::Retrieve(
    LPVOID *ppvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != ppvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));
    *ppvItem = DPA_GetPtr(m_hdpa, index);

    if (NULL == *ppvItem)
        return FALSE;

    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::RetrieveLast

    Description: Retrieves the last pointer from the list.

    Arguments: 
        ppvItem - Address of variable to contain retrieved pointer value.

    Returns:
        TRUE  - Success.
        FALSE - Container is empty.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
    09/03/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::RetrieveLast(
    LPVOID *ppvItem
    )
{
    DBGASSERT((NULL != ppvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    if (0 == Count())
        return FALSE;

    Retrieve(ppvItem, Count() - 1);
    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::FindIndex

    Description: Returns the list index associated with a given pointer
        value.  If duplicates exist, the index of the first item is returned.

    Arguments: 
        pvItem - Pointer value of item to be found.

        pIndex - Address of index variable to hold resulting index.

    Returns:
        TRUE  = Success
        FALSE = Item not found in list.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
    09/03/96    Changed returned value to BOOL.                      BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::FindIndex(
    LPVOID pvItem, 
    INT *pIndex
    )
{
    INT i = -1;

    DBGASSERT((NULL != pIndex));
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));
    i = *pIndex = DPA_GetPtrIndex(m_hdpa, pvItem);

    if (-1 == i)
        return FALSE;

    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Sort

    Description: Sorts the list given a comparison function.

    Arguments: 
        pfnCompare - Address of comparison callback.

        lParam - 32-bit parameter passed to the callback.

    Returns:
        TRUE  = Success
        FALSE = Item not found in list.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    02/21/97    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
PointerList::Sort(
    PFNDPACOMPARE pfnCompare, 
    LPARAM lParam
    )
{
    DBGASSERT((NULL != pfnCompare));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));
    DBGASSERT((NULL != pfnCompare));

    return DPA_Sort(m_hdpa, pfnCompare, lParam);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerList::Search

    Description: Searches the list for a given item.

    Arguments: 
        pvKey - Address of key item used for search.

        pfnCompare - Address of comparison callback.

        uOptions - Options controlling sort operation.
            DPAS_SORTED       = Array is already sorted.  
                                Will use binary search.
            DPAS_INSERTBEFORE = If no exact match is found, return index of
                                previous best match.
            DPAS_INSERTAFTER  = If no exact match is found, return index of
                                next best match.

        iStart - Index of where to start search.  0 for start of list.

        lParam - 32-bit parameter passed to the callback.

    Returns: Index of found item or -1 if none found.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    02/21/97    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
INT
PointerList::Search(
    LPVOID pvKey,
    PFNDPACOMPARE pfnCompare, 
    UINT uOptions,
    INT iStart,
    LPARAM lParam
    )
{
    DBGASSERT((NULL != pfnCompare));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will automatically release.

    DBGASSERT((NULL != m_hdpa));
    DBGASSERT((NULL != pvKey));
    DBGASSERT((NULL != pfnCompare));

    return DPA_Search(m_hdpa, pvKey, iStart, pfnCompare, lParam, uOptions);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerListIterator::operator = 

    Description: Assignment for PointerListIterator.

    Arguments:
        rhs - Reference to constant iterator that is the rhs of the assignment.

    Returns:
        Returns a reference to "this" iterator object following the assignment.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    02/27/97    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
PointerListIterator&
PointerListIterator::operator = (
    const PointerListIterator& rhs
    )
{
    if (this != &rhs)
    {
        m_pList = rhs.m_pList;
        m_Index = rhs.m_Index;
    }
    return *this;
}



///////////////////////////////////////////////////////////////////////////////
/*  Function: PointerListIterator::Advance

    Description: Both the Next() and Prev() iterator functions call this
        one function.  It handles the actual iteration.

    Arguments:
        ppvOut - Address of pointer variable to contain the value of the 
            pointer at the "current" iterator location.  The iterator is
            advance (or retreated) after the pointer value is copied to the
            destination.

        bForward - TRUE  = Advance toward end of list.
                   FALSE = Advance toward front of list.

    Returns:
        NO_ERROR      - Iterator advanced.  Returned pointer is valid.
        E_FAIL        - Iterator already at begining or end of list.  Returned
                        pointer will be NULL.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/14/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT 
PointerListIterator::Advance(
    LPVOID *ppvOut, 
    BOOL bForward
    )
{
    LPVOID pv       = NULL;
    HRESULT hResult = NO_ERROR;

    DBGASSERT((NULL != ppvOut));

    m_pList->Lock();
    if (0 < m_pList->Count() && m_Index != EndOfList)
    {
        //
        // Get pointer value at index "m_Index".
        //
        DBGASSERT((NULL != m_pList->m_hdpa));
        pv = DPA_GetPtr(m_pList->m_hdpa, m_Index);

        if (bForward)
        {
            //
            // Advance iterator index.
            //
            if ((UINT)(++m_Index) == m_pList->Count())
                m_Index = EndOfList;
        }
        else
        {
            //
            // Retreat iterator index.
            //
            m_Index--;  // Will be -1 (EndOfList) if currently 0.
        }
    }
    else
        hResult = E_FAIL;

    m_pList->ReleaseLock();

    *ppvOut = pv;  // Return pointer value.

    return hResult;
}



///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::StructureList

    Description: Constructor.

    Arguments:
        cbItem - Size of each item in bytes.

        cItemGrow - Number of items to grow array at each expansion.


    Returns: Nothing.

    Exceptions: OutOfMemory

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    09/06/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
StructureList::StructureList(
    INT cbItem, 
    INT cItemGrow
    )
{
    InitializeCriticalSection(&m_cs);

    if (NULL == (m_hdsa = DSA_Create(cbItem, cItemGrow)))
    {
        DeleteCriticalSection(&m_cs);
        throw CAllocException();
    }
}




///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::~StructureList

    Description: Destructor.  Destroys the DSA and closes the mutex handle.

    Arguments: None.

    Returns: Nothing.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
StructureList::~StructureList(void)
{
    Lock();

    if (NULL != m_hdsa)
        DSA_Destroy(m_hdsa);

    ReleaseLock();
    DeleteCriticalSection(&m_cs);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureListIterator::operator = 

    Description: Assignment for StructureListIterator.

    Arguments:
        rhs - Reference to constant iterator that is the rhs of the assignment.

    Returns:
        Returns a reference to "this" iterator object following the assignment.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    02/27/97    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
StructureListIterator&
StructureListIterator::operator = (
    const StructureListIterator& rhs
    )
{
    if (this != &rhs)
    {
        m_pList = rhs.m_pList;
        m_Index = rhs.m_Index;
    }
    return *this;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Count

    Description: Returns the number of elements in the list.

    Arguments: None.

    Returns: Count of elements in list.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
UINT StructureList::Count(VOID)
{
    UINT n = 0;

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.

    DBGASSERT((NULL != m_hdsa));
    n = DSA_GetItemCount(m_hdsa);

    return n;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Insert

    Description: Insert an item into the Structure list at a given index.
        If the index is beyond the upper bounds of the array, the array
        is extended by one and the item is appended to the list.

    Arguments:
        pvItem - Address of item to add to list.

        index - List index where item is to be inserted.  All following
            items are shifted to one index higher.  The list automatically
            grows to accomodate as required.

    Returns: Nothing.

    Exceptions: OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
    09/06/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
StructureList::Insert(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);   // Get lock on container.  Will auto-release.

    DBGASSERT((NULL != m_hdsa));

    if (DSA_InsertItem(m_hdsa, index, pvItem) < 0)
    {
        throw CAllocException();
    }
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Replace

    Description: Replaces an item in the Structure list at a given index.
        If the index is beyond the upper bounds of the array, the array
        is extended by one and the item is appended to the list.

    Arguments:
        pvItem - Address of item to replace existing item.

        index - List index where item is to be replaced.  

    Returns:
        TRUE  - Success.
        FALSE - Invalid index or empty container.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
StructureList::Replace(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.

    DBGASSERT((NULL != m_hdsa));

    return DSA_SetItem(m_hdsa, index, pvItem);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Append

    Description: Appends an item to the end of the list.

    Arguments:
        pvItem - Address of item to add to list.

    Returns: Nothing.

    Exceptions: OutOfMemory.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
    09/06/96    Added exception handling.                            BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
StructureList::Append(
    LPVOID pvItem
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container. Will auto-release.
    //
    // Yes, this is correct.  We're "inserting" an item to append something
    // to the list.  This saves a ( count - 1 ) calculation.
    //
    DBGASSERT((NULL != m_hdsa));
    Insert(pvItem, DSA_GetItemCount(m_hdsa));
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Remove

    Description: Removes an item from the list at a given index.

    Arguments: 
        pvItem - Address of buffer to receive removed item.  Assumes buffer
            is sized properly.

        index - List index where item is to be removed.  All following
            items are shifted to one index lower. 

    Returns:
        TRUE  - Success.
        FALSE - Invalid index or container is empty.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
StructureList::Remove(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.
    DBGASSERT((NULL != m_hdsa));

    if (!DSA_GetItem(m_hdsa, index, pvItem) ||
        !DSA_DeleteItem(m_hdsa, index))
    {
        return FALSE;
    }
    return TRUE;
}



///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Retrieve

    Description: Retrieve an item from the list at a given index.
        The item value is merely copied and not removed from the list.

    Arguments:
        pvItem - Address of buffer to receive removed item.  Assumes buffer
            is sized properly.

        index - List index where item is to be retrieved.  

    Returns:
        TRUE  - Success.
        FALSE - Invalid index or empty container.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
StructureList::Retrieve(
    LPVOID pvItem, 
    UINT index
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.
    DBGASSERT((NULL != m_hdsa));

    if (!DSA_GetItem(m_hdsa, index, pvItem))
    {
        return FALSE;
    }
    return TRUE;
}

    
///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::RemoveLast

    Description: Removes the last item from the list.

    Arguments: 
        pvItem - Address of buffer to receive removed item.  Assumes buffer
            is sized properly.

    Returns:
        TRUE  - Success.
        FALSE - Empty container.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
StructureList::RemoveLast(
    LPVOID pvItem
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.

    DBGASSERT((NULL != m_hdsa));

    if (0 == DSA_GetItemCount(m_hdsa))
        return FALSE;

    Remove(pvItem, DSA_GetItemCount(m_hdsa) - 1);
    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::RetrieveLast

    Description: Retrieves the last pointer from the list.

    Arguments: 
        pvItem - Address of buffer to receive removed item.  Assumes buffer
            is sized properly.

    Returns:
        TRUE  - Success.
        FALSE - Empty container.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
BOOL
StructureList::RetrieveLast(
    LPVOID pvItem
    )
{
    DBGASSERT((NULL != pvItem));

    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.
    DBGASSERT((NULL != m_hdsa));

    if (0 == DSA_GetItemCount(m_hdsa))
        return FALSE;

    Retrieve(pvItem, DSA_GetItemCount(m_hdsa) - 1);
    return TRUE;
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureList::Clear

    Description: Removes all items from the list.

    Arguments: None.

    Returns: Nothing.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/26/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
VOID
StructureList::Clear(
    VOID
    )
{
    AutoLockCs lock(m_cs);  // Get lock on container.  Will auto-release.

    DBGASSERT((NULL != m_hdsa));
    DSA_DeleteAllItems(m_hdsa);
}


///////////////////////////////////////////////////////////////////////////////
/*  Function: StructureListIterator::Advance

    Description: Both the Next() and Prev() iterator functions call this
        one function.  It handles the actual iteration.

    Arguments:
        ppvOut - Address of pointer variable to receive the address of the 
            item at the "current" iterator location.  The iterator is
            advance (or retreated) after the pointer value is copied to the
            destination.

        bForward - TRUE  = Advance toward end of list.
                   FALSE = Advance toward front of list.

    Returns:
        NO_ERROR      - Iterator advanced.  Returned pointer is valid.
        E_FAIL        - Iterator already at begining or end of list.  Returned
                        pointer will be NULL.

    Revision History:

    Date        Description                                          Programmer
    --------    ---------------------------------------------------  ----------
    06/24/96    Initial creation.                                    BrianAu
*/
///////////////////////////////////////////////////////////////////////////////
HRESULT 
StructureListIterator::Advance(
    LPVOID *ppvOut, 
    BOOL bForward
    )
{
    LPVOID pv       = NULL;
    HRESULT hResult = NO_ERROR;

    DBGASSERT((NULL != ppvOut));

    m_pList->Lock();
    if (0 < m_pList->Count() && m_Index != EndOfList)
    {
        //
        // Get address of item at index "m_Index".
        //
        DBGASSERT((NULL != m_pList->m_hdsa));
        pv = DSA_GetItemPtr(m_pList->m_hdsa, m_Index);

        if (bForward)
        {
            //
            // Advance iterator index.
            //
            if ((UINT)(++m_Index) == m_pList->Count())
                m_Index = EndOfList;
        }
        else
        {
            //
            // Retreat iterator index.
            //
            m_Index--;  // Will be -1 (EndOfList) if currently 0.
        }
    }
    else
        hResult = E_FAIL;

    m_pList->ReleaseLock();
    *ppvOut = pv;  // Return pointer value.

    return hResult;
}
