/**********************************************************************/
/**                       Microsoft Windows/NT                       **/
/**                Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/

/*
	hArray.cpp	
		Index manager for TAPI devices db

	FILE HISTORY:
    Dec 16  1997    EricDav     Created

*/

#include "stdafx.h"
#include "harray.h"
#include "mbstring.h"

LPBYTE		g_pStart;

/*!--------------------------------------------------------------------------
    Class CHDeviceIndex
 ---------------------------------------------------------------------------*/
CHDeviceIndex::CHDeviceIndex(INDEX_TYPE IndexType)
    : m_dbType(IndexType), m_bAscending(TRUE)
{
}

CHDeviceIndex::~CHDeviceIndex()
{
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::GetType
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CHDeviceIndex::GetType(INDEX_TYPE * pIndexType)
{
    if (pIndexType)
        *pIndexType = m_dbType;

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::SetArray
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CHDeviceIndex::SetArray(HDeviceArray & hdeviceArray)
{
    m_hdeviceArray.Copy(hdeviceArray);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::GetHDevice
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HDEVICE
CHDeviceIndex::GetHDevice(int nIndex)
{
    Assert(nIndex >= 0);
    Assert(nIndex <= m_hdeviceArray.GetSize());

    if (nIndex < 0 || 
        nIndex >= m_hdeviceArray.GetSize())
    {
        return NULL;
    }

    return m_hdeviceArray.GetAt(nIndex);
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::GetIndex
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int
CHDeviceIndex::GetIndex(HDEVICE hdevice)
{
    Assert(hdevice != 0);

    LPHDEVICE phdevice = (LPHDEVICE) BSearch((const void *)&hdevice, 
                                    (const void *)m_hdeviceArray.GetData(), 
                                    (size_t)m_hdeviceArray.GetSize(), 
                                    sizeof(HDEVICE));

    int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData());
    Assert(nIndex >= 0);
    Assert(nIndex <= m_hdeviceArray.GetSize());

    int nComp, nIndexTemp;
    
    nComp = BCompare(&hdevice, phdevice);
    if (nComp == 0)
    {
        // found the right one, check the previous one to return the first 
        // record in a list of duplicates
        nIndexTemp = nIndex;

        while (nIndexTemp && nComp == 0)
        {
            *phdevice = m_hdeviceArray.GetAt(--nIndexTemp);
            nComp = BCompare(&hdevice, phdevice);
        }

        if (nIndexTemp == nIndex)
			return nIndex; // nIndex should be zero here as well
		else
			if (nComp == 0)
				return nIndexTemp; // nIndexTemp should be 0 in this case
			else
				return nIndexTemp++;
    }

    return -1;
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::Add
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CHDeviceIndex::Add(HDEVICE hdevice, BOOL bEnd)
{
    // if we are loading the array then just stick this on the end
    if (bEnd)
    {
        m_hdeviceArray.Add(hdevice);
    }
    else
    {
        if (m_hdeviceArray.GetSize() == 0)
        {
            m_hdeviceArray.Add(hdevice);
        }
        else
        {
            LPHDEVICE phdevice = (LPHDEVICE) BSearch((const void *)&hdevice, 
                                            (const void *)m_hdeviceArray.GetData(), 
                                            (size_t)m_hdeviceArray.GetSize(), 
                                            sizeof(HDEVICE));
    
            int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData());
            Assert(nIndex >= 0);
            Assert(nIndex <= m_hdeviceArray.GetSize());
    
            int nComp = BCompare(&hdevice, phdevice);
            if (nComp < 0)
            {
				if(nIndex == 0)
					m_hdeviceArray.InsertAt(nIndex , hdevice);

				else             // Insert before phdevice
					m_hdeviceArray.InsertAt(nIndex - 1, hdevice);
            }
            else
            {
                // insert after phdevice
                m_hdeviceArray.InsertAt(nIndex + 1, hdevice);
            }
        }
    }

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::Remove
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT 
CHDeviceIndex::Remove(HDEVICE hdevice)
{
    // do a bsearch for the record and then remove
    LPHDEVICE phdevice = (LPHDEVICE) BSearch(&hdevice, 
                                    m_hdeviceArray.GetData(), 
                                    (size_t)m_hdeviceArray.GetSize(), 
                                    sizeof(HDEVICE));

    int nComp = BCompare(&hdevice, phdevice);
    Assert(nComp == 0);
    if (nComp != 0)
        return E_FAIL;

    // calculate the index
    int nIndex = (int) (phdevice - (LPHDEVICE) m_hdeviceArray.GetData());
    Assert(nIndex >= 0);
    Assert(nIndex <= m_hdeviceArray.GetSize());

    m_hdeviceArray.RemoveAt(nIndex);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CHDeviceIndex::BSearch
		Modified bsearch which returns the closest or equal element in
        an array
	Author: EricDav
 ---------------------------------------------------------------------------*/
void * 
CHDeviceIndex::BSearch (const void *key,
                     const void *base,
                     size_t num,
                     size_t width)
{
        char *lo = (char *)base;
        char *hi = (char *)base + (num - 1) * width;
        char *mid;
        unsigned int half;
        int result;

        while (lo <= hi)
                if (half = num / 2)
                {
                        mid = lo + (num & 1 ? half : (half - 1)) * width;
                        if (!(result = BCompare(key,mid)))
                                return(mid);
                        else if (result < 0)
                        {
                                hi = mid - width;
                                num = num & 1 ? half : half-1;
                        }
                        else    {
                                lo = mid + width;
                                num = half;
                        }
                }
                else if (num)
                        return(lo);
                else
                        break;

        return(mid);
}






/*!--------------------------------------------------------------------------
    Class CIndexMgr
 ---------------------------------------------------------------------------*/

CIndexMgr::CIndexMgr()
{
    m_posCurrentProvider= NULL;
}

CIndexMgr::~CIndexMgr()
{
    Reset();
}
	
/*!--------------------------------------------------------------------------
	CIndexMgr::Initialize
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::Initialize()
{
    HRESULT hr = hrOK;

    CSingleLock cl(&m_cs);
    cl.Lock();

    COM_PROTECT_TRY
    {
        // cleanup
        Reset();
    }
    COM_PROTECT_CATCH

    return hr;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::Reset
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::Reset()
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    while (m_listProviderIndex.GetCount() > 0)
    {
        CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.RemoveHead();
        while (pProviderIndexInfo->m_listIndicies.GetCount() > 0)
            delete pProviderIndexInfo->m_listIndicies.RemoveHead();

        delete pProviderIndexInfo;
	}

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::GetTotalCount
        The index sorted by name contains the total database and should
        always be available. Use this for the total count.
	Author: EricDav
 ---------------------------------------------------------------------------*/
UINT
CIndexMgr::GetTotalCount()
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    UINT uTotalCount = 0;
    POSITION pos;

    pos = m_listProviderIndex.GetHeadPosition();
    while (pos)
    {
        CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetNext(pos);
        if (pProviderIndexInfo->m_listIndicies.GetCount() > 0)
            uTotalCount += (UINT)(pProviderIndexInfo->m_listIndicies.GetHead())->GetArray().GetSize();
    }

    return uTotalCount;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::GetCurrentCount
        The current count may differ depending upon if the current Index
        is a filtered index.
	Author: EricDav
 ---------------------------------------------------------------------------*/
UINT
CIndexMgr::GetCurrentCount()
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    CProviderIndexInfo * pProviderIndexInfo = NULL;
    CHDeviceIndex * pIndex = NULL;

    pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);
	pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex);

    if (pIndex == NULL)
        return 0;

    return (UINT)pIndex->GetArray().GetSize();
}

/*!--------------------------------------------------------------------------
	CIndexMgr::AddHDevice
        -
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::AddHDevice(DWORD dwProviderID, HDEVICE hdevice, BOOL bEnd)
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    HRESULT hr = hrOK;
    CProviderIndexInfo * pProviderIndexInfo = NULL;
    CHDeviceIndex * pIndex = NULL;

    COM_PROTECT_TRY
    {
        // set current provider set the current provider position and if 
        // the provider doesn't exist, it will create one
        hr = SetCurrentProvider(dwProviderID);
        if (FAILED(hr))
            return hr;

        pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);

        pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex);
        if (pIndex)
            pIndex->Add(hdevice, bEnd);

    }
    COM_PROTECT_CATCH

    return hr;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::RemoveHDevice
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::RemoveHDevice(DWORD dwProviderID, HDEVICE hdevice)
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    HRESULT hr = hrOK;
    CProviderIndexInfo * pProviderIndexInfo = NULL;
    CHDeviceIndex * pIndex = NULL;

    COM_PROTECT_TRY
    {
        hr = SetCurrentProvider(dwProviderID);
        if (FAILED(hr))
            return hr;

        pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);

        pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex);
        if (pIndex)
            pIndex->Remove(hdevice);
    }
    COM_PROTECT_CATCH

    return hr;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::Sort
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::Sort(DWORD dwProviderID, INDEX_TYPE SortType, DWORD dwSortOptions, LPBYTE pStart)
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    HRESULT hr = hrOK;
    CHDeviceIndex * pNameIndex;
    CHDeviceIndex * pNewIndex;
    POSITION pos, posLast;

    INDEX_TYPE indexType;
    BOOL bAscending = (dwSortOptions & SORT_ASCENDING) ? TRUE : FALSE;

    hr = SetCurrentProvider(dwProviderID);
    if (FAILED(hr))
        return hr;

	// check to see if we have an index for this.
    CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);

    pos = pProviderIndexInfo->m_listIndicies.GetHeadPosition();
	while (pos)
	{
		posLast = pos;
		CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetNext(pos);

		pIndex->GetType(&indexType);

        // the index for this type already exists, just sort accordingly
        if (indexType == SortType)
		{
			if (pIndex->IsAscending() != bAscending)
			{
				pIndex->SetAscending(bAscending);
				pIndex->Sort(pStart);
			}

			pProviderIndexInfo->m_posCurrentIndex = posLast;
		
			return hrOK;
		}
    }
    
    // to save memory, remove all old indicies, except the name index
    //CleanupIndicies();

    // if not, create one
    switch (SortType)
    {
        case INDEX_TYPE_NAME:
            pNewIndex = new CIndexName();
            break;

        case INDEX_TYPE_USERS:
            pNewIndex = new CIndexUsers();
            break;

        case INDEX_TYPE_STATUS:
            pNewIndex = new CIndexStatus();
            break;

        default:
            Panic1("Invalid sort type passed to IndexMgr::Sort %d\n", SortType);
            break;
    }

    Assert(pNewIndex);

    // name index is always the first in the list
    pNameIndex = pProviderIndexInfo->m_listIndicies.GetHead();

    Assert(pNameIndex);

    // copy the array from the named index
    pNewIndex->SetArray(pNameIndex->GetArray());

    pNewIndex->SetAscending(bAscending);
    pNewIndex->Sort(pStart);

	pProviderIndexInfo->m_posCurrentIndex = pProviderIndexInfo->m_listIndicies.AddTail(pNewIndex);

    return hr;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::CleanupIndicies
		Removes all indicies except the name index, and a filtered view
	Author: EricDav
 ---------------------------------------------------------------------------*/
void
CIndexMgr::CleanupIndicies()
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    INDEX_TYPE  indexType;

    CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);

    POSITION pos = pProviderIndexInfo->m_listIndicies.GetHeadPosition();
    while (pos)
    {
        POSITION posLast = pos;
        CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetNext(pos);
    
        pIndex->GetType(&indexType);

        if (indexType == INDEX_TYPE_NAME)
            continue;

        pProviderIndexInfo->m_listIndicies.RemoveAt(posLast);
        delete pIndex;
    }
}

/*!--------------------------------------------------------------------------
	CIndexMgr::GetHDevice
		Returns an hdevice based on an index into the current sorted list
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::GetHDevice(DWORD dwProviderID, int nIndex, LPHDEVICE phdevice)
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    SetCurrentProvider(dwProviderID);

    CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);
    CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex);

    Assert(pIndex);

    if (phdevice)
        *phdevice = pIndex->GetHDevice(nIndex);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::GetIndex
		Returns the index of an hlien from the current sorted list
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::GetIndex(DWORD dwProviderID, HDEVICE hdevice, int * pnIndex)
{
    CSingleLock cl(&m_cs);
    cl.Lock();

    SetCurrentProvider(dwProviderID);

    CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetAt(m_posCurrentProvider);
    CHDeviceIndex * pIndex = pProviderIndexInfo->m_listIndicies.GetAt(pProviderIndexInfo->m_posCurrentIndex);

    Assert(pIndex);

    if (pIndex)
        *pnIndex = pIndex->GetIndex(hdevice);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexMgr::SetCurrentProvider
		Sets the current provider for the index mgr, if it doesn't exist,
        it is created
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT
CIndexMgr::SetCurrentProvider(DWORD dwProviderID)
{
    HRESULT hr = hrOK;
    BOOL    bExists = FALSE;
    POSITION posLast;

    COM_PROTECT_TRY
    {
        POSITION pos = m_listProviderIndex.GetHeadPosition();
        while (pos)
        {
            posLast = pos;
            CProviderIndexInfo * pProviderIndexInfo = m_listProviderIndex.GetNext(pos);

            // is the the correct provider to add this to?
            if (pProviderIndexInfo->m_dwProviderID != dwProviderID)
                continue;
            
            m_posCurrentProvider = posLast;
            bExists = TRUE;
    	}

        if (!bExists)
        {   
            // no provider index exists for this.  Create one now.
            CProviderIndexInfo * pProviderIndexInfo = new CProviderIndexInfo;
            pProviderIndexInfo->m_dwProviderID = dwProviderID;
            
            CHDeviceIndex * pIndex = new CIndexName;
            pProviderIndexInfo->m_posCurrentIndex = pProviderIndexInfo->m_listIndicies.AddHead(pIndex);

            m_posCurrentProvider = m_listProviderIndex.AddTail(pProviderIndexInfo);
        }
    }
    COM_PROTECT_CATCH

    return hr;
}

/*!--------------------------------------------------------------------------
    Class CIndexName
 ---------------------------------------------------------------------------*/

/*!--------------------------------------------------------------------------
	CIndexName::BCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int
CIndexName::BCompare(const void * elem1, const void * elem2)
{
    int     nRet;
    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;

    LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1;
    LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2;

    nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset));
    if (nRet == 0)
    {
        // permanent device IDs should be unique
        if (pRec1->dwPermanentDeviceID > pRec2->dwPermanentDeviceID)
            nRet = 1;
        else
            nRet = -1;
    }

    return nRet;
}

/*!--------------------------------------------------------------------------
	CIndexName::Sort
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT 
CIndexName::Sort(LPBYTE pStart)
{
	// save the base pointer for later
	g_pStart = pStart;

    if (m_bAscending)
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA);
    else
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexName::QCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int __cdecl
CIndexName::QCompareA(const void * elem1, const void * elem2)
{
    int     nRet;
    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;
    
    LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1;
    LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2;
    
    nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset));
    if (nRet == 0)
    {
        // permanent device IDs should be unique
        if (pRec1->dwPermanentDeviceID > pRec2->dwPermanentDeviceID)
            nRet = 1;
        else
            nRet = -1;
    }

    return nRet;
}

int __cdecl
CIndexName::QCompareD(const void * elem1, const void * elem2)
{
    return -QCompareA(elem1, elem2);
}

/*!--------------------------------------------------------------------------
    Class CIndexUsers
 ---------------------------------------------------------------------------*/

/*!--------------------------------------------------------------------------
	CIndexUsers::BCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int
CIndexUsers::BCompare(const void * elem1, const void * elem2)
{
    int     nRet;
    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;
    
    LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1;
    LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2;
    
    nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDomainUserNamesOffset), (LPCTSTR) (g_pStart + pRec2->dwDomainUserNamesOffset));
    if (nRet == 0)
        nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset));
    
    return nRet;
}

/*!--------------------------------------------------------------------------
	CIndexUsers::Sort
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT 
CIndexUsers::Sort(LPBYTE pStart)
{
	// save the base pointer for later
	g_pStart = pStart;

    if (m_bAscending)
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA);
    else
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexUsers::QCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int __cdecl
CIndexUsers::QCompareA(const void * elem1, const void * elem2)
{
    int nRet;

    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;
    
    LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1;
    LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2;
    
    nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDomainUserNamesOffset), (LPCTSTR) (g_pStart + pRec2->dwDomainUserNamesOffset));
    if (nRet == 0)
        nRet = lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset));
    
    return nRet;
}

int __cdecl
CIndexUsers::QCompareD(const void * elem1, const void * elem2)
{
    return -QCompareA(elem1, elem2);
}

/*!--------------------------------------------------------------------------
    Class CIndexStatus
 ---------------------------------------------------------------------------*/

/*!--------------------------------------------------------------------------
	CIndexStatus::BCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int
CIndexStatus::BCompare(const void * elem1, const void * elem2)
{
    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;
    
    LPDEVICEINFO pRec1 = (LPDEVICEINFO) *phdevice1;
    LPDEVICEINFO pRec2 = (LPDEVICEINFO) *phdevice2;
    
    //return _mbscmp((const PUCHAR) &pRec1->szRecordName[0], (const PUCHAR) &pRec2->szRecordName[0]);
    return 0;
}

/*!--------------------------------------------------------------------------
	CIndexStatus::Sort
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
HRESULT 
CIndexStatus::Sort(LPBYTE pStart)
{
	// save the base pointer for later
	g_pStart = pStart;

    if (m_bAscending)
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareA);
    else
        qsort(m_hdeviceArray.GetData(), (size_t)m_hdeviceArray.GetSize(), sizeof(HDEVICE), QCompareD);

    return hrOK;
}

/*!--------------------------------------------------------------------------
	CIndexIpAddr::QCompare
		-
	Author: EricDav
 ---------------------------------------------------------------------------*/
int __cdecl
CIndexStatus::QCompareA(const void * elem1, const void * elem2)
{
    LPHDEVICE phdevice1 = (LPHDEVICE) elem1;
    LPHDEVICE phdevice2 = (LPHDEVICE) elem2;
    
    LPHDEVICE pRec1 = (LPHDEVICE) *phdevice1;
    LPHDEVICE pRec2 = (LPHDEVICE) *phdevice2;
    
    //return lstrcmp((LPCTSTR) (g_pStart + pRec1->dwDeviceNameOffset), (LPCTSTR) (g_pStart + pRec2->dwDeviceNameOffset));
    return 0;
}

int __cdecl
CIndexStatus::QCompareD(const void * elem1, const void * elem2)
{
    return -QCompareA(elem1, elem2);
}