780 lines
10 KiB
C++
780 lines
10 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1994-1998 Microsoft Corporation
|
||
|
|
||
|
Module Name :
|
||
|
|
||
|
objplus.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Base object classes
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ronald Meijer (ronaldm)
|
||
|
|
||
|
Project:
|
||
|
|
||
|
Internet Services Manager
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Include Files
|
||
|
//
|
||
|
#include "stdafx.h"
|
||
|
#include "comprop.h"
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <memory.h>
|
||
|
#include <ctype.h>
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#undef THIS_FILE
|
||
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
CObjHelper::CObjHelper()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Constructor for super object help class
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
: m_ctor_err(ERROR_SUCCESS),
|
||
|
m_api_err(ERROR_SUCCESS),
|
||
|
m_fDirty(FALSE),
|
||
|
m_time_created(::GetCurrentTime())
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CObjHelper::ReportError(
|
||
|
IN LONG errInConstruction
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Set the constructor error code, and dump the error message to
|
||
|
the debugging context.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LONG errInConstruction : Error code
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
TRACEEOLID("CObjectPlus construction failure, error = "
|
||
|
<< errInConstruction);
|
||
|
|
||
|
m_ctor_err = errInConstruction;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LONG
|
||
|
CObjHelper::SetApiErr(
|
||
|
IN LONG errApi
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Set the API error code.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LONG errApi : API error code
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The API error code
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return m_api_err = errApi;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CObjHelper::IsValid() const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Determine if the object is in a valid state
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
LONG errApi : API error code
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if the the object is in a valid state, FALSE otherwise
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return QueryError() == 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
DWORD
|
||
|
CObjHelper::QueryAge() const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Determine the age of the object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
time_t value indicating the age of the object.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD dwTime = ::GetCurrentTime(),
|
||
|
dwDiff;
|
||
|
|
||
|
if (dwTime < m_time_created)
|
||
|
{
|
||
|
dwDiff = dwTime + (((DWORD)-1) - (m_time_created - 1));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwDiff = dwTime - m_time_created;
|
||
|
}
|
||
|
|
||
|
return dwDiff;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CObjHelper::AssertValid() const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Assert the object if the object is in a valid state
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ASSERT(IsValid());
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#endif // _DEBUG
|
||
|
|
||
|
|
||
|
|
||
|
CObjectPlus::CObjectPlus()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Constructor of extended object
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
CObjectPlus::Compare(
|
||
|
IN const CObjectPlus * pob
|
||
|
) const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Compare one object with another: default implementation orders objects
|
||
|
by creation time. Return -1, 0 or 1.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const CObjectPlus * pob : Object to be compared against
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
-1 if this object is < than the compared object
|
||
|
0 if this object is == to the compared object
|
||
|
+1 if this object is > than the compared object
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return QueryCreationTime() < pob->QueryCreationTime()
|
||
|
? -1
|
||
|
: QueryCreationTime() != pob->QueryCreationTime();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CObListPlus::CObListPlus(
|
||
|
IN int nBlockSize
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Subclass of CObList whose default behavior is to destroy its
|
||
|
contents during its own destruction
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
int nBlockSize : Initial block size
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
: CObList(nBlockSize),
|
||
|
m_fOwned(TRUE)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CObListPlus::~CObListPlus()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Destructor. If the objects are owned, clean them up.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
RemoveAll();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CObListPlus::RemoveAll()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Remove all the objects in the list if the list owns its objects
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if (m_fOwned)
|
||
|
{
|
||
|
//
|
||
|
// Remove and discard all the objects
|
||
|
//
|
||
|
while (!IsEmpty())
|
||
|
{
|
||
|
CObject * pob = RemoveHead();
|
||
|
delete pob ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Just remove the object pointers
|
||
|
//
|
||
|
CObList::RemoveAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CObject *
|
||
|
CObListPlus::Index(
|
||
|
IN int index
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Get object by index
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
int index : The index of the object to be returned
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The object, or NULL if the index is invalid
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CObListIter obli(*this);
|
||
|
|
||
|
CObject * pob = NULL;
|
||
|
|
||
|
for (int i = 0; (pob = obli.Next()) && i++ < index; /**/ );
|
||
|
|
||
|
return pob;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CObListPlus::RemoveIndex(
|
||
|
IN int index
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Remove object by index
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
int index : The index of the object to be removed
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The object, or NULL if the index is invalid
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
int i;
|
||
|
POSITION pos;
|
||
|
CObListIter obli(*this);
|
||
|
CObject * pob;
|
||
|
|
||
|
for (i = 0, pos = obli.QueryPosition();
|
||
|
(pob = obli.Next()) && i < index;
|
||
|
i++, pos = obli.QueryPosition());
|
||
|
|
||
|
if (pob && i == index)
|
||
|
{
|
||
|
RemoveAt(pos);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CObListPlus::Remove(
|
||
|
IN CObject * pob
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Remove the first (and hopefully only) occurrence of an object
|
||
|
pointer from this list.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CObject * pob : The object to be removed
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if the object was found and succesfully removed, FALSE otherwise
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
POSITION pos = Find(pob);
|
||
|
|
||
|
if (pos == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
RemoveAt(pos);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CObListPlus::RemoveAt(
|
||
|
IN POSITION & pos
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Override of RemoveAt to delete the pointer at the position
|
||
|
given
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
POSITION pos : Position of item to delete
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
The item will only be deleted if this is an "owned" list.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CObject * pItem = GetAt(pos);
|
||
|
|
||
|
CObList::RemoveAt(pos);
|
||
|
|
||
|
if (m_fOwned)
|
||
|
{
|
||
|
delete pItem;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CObListPlus::SetAll(
|
||
|
IN BOOL fDirty
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Set all elements to dirty or clean. Return TRUE if any element was dirty.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
BOOL fDirty : Dirty flag to set the objects with
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if any element was dirty.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
int cDirtyItems = 0;
|
||
|
CObjectPlus * pob;
|
||
|
CObListIter obli(*this);
|
||
|
|
||
|
while (pob = (CObjectPlus *)obli.Next())
|
||
|
{
|
||
|
cDirtyItems += pob->IsDirty();
|
||
|
pob->SetDirty(fDirty);
|
||
|
}
|
||
|
|
||
|
SetDirty(fDirty);
|
||
|
|
||
|
return cDirtyItems > 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int
|
||
|
CObListPlus::FindElement(
|
||
|
IN CObject * pobSought
|
||
|
) const
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Find the object in the list.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CObject * pobSought : Object to be looked for
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The index of the object, or -1 if it wasn't found.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CObject * pob;
|
||
|
CObListIter obli(*this);
|
||
|
|
||
|
for (int i = 0;
|
||
|
(pob = obli.Next()) && pob != pobSought;
|
||
|
i++);
|
||
|
|
||
|
return pob
|
||
|
? i
|
||
|
: -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Sorting structure
|
||
|
//
|
||
|
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
CObjectPlus * pObj; // Pointer to object to be sorted
|
||
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pFunc; // Pointer to ordering function
|
||
|
} CBOWNEDLIST_SORT_HELPER;
|
||
|
|
||
|
|
||
|
|
||
|
int _cdecl
|
||
|
CObListPlus::SortHelper(
|
||
|
IN const void * pa,
|
||
|
IN const void * pb
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This static member function is used to quick sort an array of structures
|
||
|
as declared above. Each element contains the object pointer and a
|
||
|
pointer to the object's member function to be invoked for comparison.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const void * pa : Sorting help struct 1
|
||
|
const void * pb : Sorting help struct 2
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Sort return code
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
CBOWNEDLIST_SORT_HELPER *pHelp1 = (CBOWNEDLIST_SORT_HELPER *)pa,
|
||
|
*pHelp2 = (CBOWNEDLIST_SORT_HELPER *)pb;
|
||
|
|
||
|
return (pHelp1->pObj->*pHelp1->pFunc)(pHelp2->pObj);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* INTRINSA suppress=null_pointers, uninitialized */
|
||
|
DWORD
|
||
|
CObListPlus::Sort(
|
||
|
IN CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Sort the list by recreating it entirely.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
CObjectPlus::PCOBJPLUS_ORDER_FUNC pOrderFunc : Ordering function
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Error code
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD err = ERROR_SUCCESS;
|
||
|
int cItems = (int)GetCount();
|
||
|
|
||
|
if (cItems < 2)
|
||
|
{
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
CObjectPlus * pObNext;
|
||
|
CObListIter obli(*this);
|
||
|
BOOL fOwned = SetOwnership(FALSE);
|
||
|
int i;
|
||
|
|
||
|
CBOWNEDLIST_SORT_HELPER * paSortHelpers = NULL;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
//
|
||
|
// Allocate the helper array
|
||
|
//
|
||
|
paSortHelpers = AllocMemByType(cItems, CBOWNEDLIST_SORT_HELPER);
|
||
|
|
||
|
//
|
||
|
// Fill the helper array.
|
||
|
//
|
||
|
for (i = 0; pObNext = (CObjectPlus *)obli.Next(); i++)
|
||
|
{
|
||
|
paSortHelpers[i].pFunc = pOrderFunc;
|
||
|
paSortHelpers[i].pObj = pObNext;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Release all object pointer references. Note that we
|
||
|
// forced "owned" to FALSE above.
|
||
|
//
|
||
|
RemoveAll();
|
||
|
ASSERT(GetCount() == 0);
|
||
|
|
||
|
//
|
||
|
// Sort the helper array
|
||
|
//
|
||
|
::qsort( (void *) paSortHelpers,
|
||
|
cItems,
|
||
|
sizeof(paSortHelpers[0]),
|
||
|
SortHelper
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Refill the list from the helper array.
|
||
|
//
|
||
|
for (i = 0; i < cItems; i++ )
|
||
|
{
|
||
|
AddTail(paSortHelpers[i].pObj);
|
||
|
}
|
||
|
|
||
|
ASSERT(GetCount() == cItems);
|
||
|
}
|
||
|
catch(CMemoryException * e)
|
||
|
{
|
||
|
err = ERROR_NOT_ENOUGH_MEMORY;
|
||
|
e->Delete();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Delete the working array
|
||
|
//
|
||
|
FreeMem(paSortHelpers);
|
||
|
|
||
|
//
|
||
|
// Restore the object ownership state
|
||
|
//
|
||
|
SetOwnership(fOwned);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CObListIter::CObListIter(
|
||
|
IN const CObListPlus & obList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Constructor of ObOwnedList iterator
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
const CObListPlus & obList : List to be iterated
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
N/A
|
||
|
|
||
|
--*/
|
||
|
: m_obList(obList)
|
||
|
{
|
||
|
Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void
|
||
|
CObListIter::Reset()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Reset the iterator
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
m_pos = m_obList.GetCount()
|
||
|
? m_obList.GetHeadPosition()
|
||
|
: NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
CObject * CObListIter::Next()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Get the next object in the list, or NULL
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The next object in the list, or NULL
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
return m_pos == NULL
|
||
|
? NULL
|
||
|
: m_obList.GetNext(m_pos);
|
||
|
}
|