625 lines
12 KiB
C++
625 lines
12 KiB
C++
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
handles
|
|
|
|
Abstract:
|
|
|
|
This header file describes the handle management service.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 5/9/1996
|
|
|
|
Environment:
|
|
|
|
Win32, C++ w/ Exceptions
|
|
|
|
Notes:
|
|
|
|
?Notes?
|
|
|
|
--*/
|
|
|
|
#ifndef _HANDLES_H_
|
|
#define _HANDLES_H_
|
|
|
|
#ifndef HANDLE_TYPE
|
|
#define HANDLE_TYPE DWORD_PTR
|
|
#endif
|
|
|
|
#if defined(_WIN64) || defined(WIN64)
|
|
static const DWORD_PTR
|
|
HANDLE_INDEX_MASK = 0x000000007fffffff,
|
|
HANDLE_COUNT_MASK = 0x00ffffff00000000,
|
|
HANDLE_ID_MASK = 0xff00000000000000;
|
|
static const DWORD
|
|
HANDLE_INDEX_OFFSET = 0,
|
|
HANDLE_COUNT_OFFSET = 32,
|
|
HANDLE_ID_OFFSET = 56;
|
|
#elif defined(_WIN32) || defined(WIN32)
|
|
static const DWORD_PTR
|
|
HANDLE_INDEX_MASK = 0x0000ffff,
|
|
HANDLE_COUNT_MASK = 0x00ff0000,
|
|
HANDLE_ID_MASK = 0xff000000;
|
|
static const DWORD
|
|
HANDLE_INDEX_OFFSET = 0,
|
|
HANDLE_COUNT_OFFSET = 16,
|
|
HANDLE_ID_OFFSET = 24;
|
|
#else
|
|
#error "Unsupported handle type length"
|
|
#endif
|
|
|
|
class CHandleList;
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CCritSect
|
|
//
|
|
|
|
class CCritSect
|
|
{
|
|
public:
|
|
CCritSect(LPCRITICAL_SECTION pCritSect)
|
|
{
|
|
m_pCritSect = pCritSect;
|
|
EnterCriticalSection(m_pCritSect);
|
|
};
|
|
|
|
~CCritSect()
|
|
{
|
|
LeaveCriticalSection(m_pCritSect);
|
|
};
|
|
|
|
protected:
|
|
LPCRITICAL_SECTION m_pCritSect;
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CHandle
|
|
//
|
|
|
|
class CHandle
|
|
{
|
|
public:
|
|
BOOL IsBad(void)
|
|
{ return m_fIsBad;};
|
|
|
|
protected:
|
|
// Constructors & Destructor
|
|
|
|
CHandle()
|
|
{
|
|
m_dwCount = 0;
|
|
m_dwIndex = (DWORD)(HANDLE_INDEX_MASK >> HANDLE_INDEX_OFFSET);
|
|
m_fIsBad = FALSE;
|
|
};
|
|
|
|
virtual ~CHandle() { /* Mandatory Base Class Destructor */ };
|
|
|
|
|
|
// Properties
|
|
|
|
DWORD m_dwCount;
|
|
DWORD m_dwIndex;
|
|
BOOL m_fIsBad;
|
|
|
|
|
|
// Methods
|
|
|
|
virtual void Cancel(void) {};
|
|
virtual void MarkAsBad(BOOL fCancel)
|
|
{
|
|
m_fIsBad = TRUE;
|
|
if (fCancel)
|
|
Cancel();
|
|
};
|
|
|
|
friend class CHandleList;
|
|
};
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CHandleList
|
|
//
|
|
|
|
class CHandleList
|
|
{
|
|
public:
|
|
|
|
// Constructors & Destructor
|
|
|
|
CHandleList(DWORD dwHandleId)
|
|
{
|
|
m_dwId = dwHandleId;
|
|
m_Max = m_Mac = 0;
|
|
m_phList = NULL;
|
|
m_fInitFailed = FALSE;
|
|
|
|
try {
|
|
if (! InitializeCriticalSectionAndSpinCount(
|
|
&m_critSect, 0x80000000))
|
|
m_fInitFailed = TRUE;
|
|
}
|
|
catch (HRESULT hr) {
|
|
m_fInitFailed = TRUE;
|
|
}
|
|
};
|
|
|
|
virtual ~CHandleList()
|
|
{
|
|
if (m_fInitFailed)
|
|
return;
|
|
|
|
Clear();
|
|
DeleteCriticalSection(&m_critSect);
|
|
};
|
|
|
|
|
|
// Properties
|
|
// Methods
|
|
|
|
DWORD Count(void)
|
|
{
|
|
CCritSect csLock(&m_critSect);
|
|
return m_Mac;
|
|
};
|
|
|
|
void
|
|
Clear(void)
|
|
{
|
|
CCritSect csLock(&m_critSect);
|
|
if (NULL != m_phList)
|
|
{
|
|
for (DWORD index = 0; index < m_Mac; index += 1)
|
|
if (NULL != m_phList[index].phObject)
|
|
delete m_phList[index].phObject;
|
|
delete[] m_phList;
|
|
m_phList = NULL;
|
|
m_Max = 0;
|
|
m_Mac = 0;
|
|
}
|
|
};
|
|
|
|
CHandle *
|
|
Close(
|
|
IN HANDLE_TYPE hItem);
|
|
|
|
HANDLE_TYPE
|
|
Add(
|
|
IN CHandle *phItem);
|
|
|
|
CHandle * const
|
|
GetQuietly(
|
|
IN HANDLE_TYPE hItem);
|
|
|
|
CHandle * const
|
|
Get(
|
|
IN HANDLE_TYPE hItem);
|
|
|
|
HANDLE_TYPE
|
|
IndexHandle(
|
|
DWORD nItem);
|
|
|
|
BOOL
|
|
InitFailed(void)
|
|
{ return m_fInitFailed; }
|
|
|
|
|
|
// Operators
|
|
|
|
CHandle * const
|
|
operator[](HANDLE_TYPE hItem)
|
|
{ return Get(hItem); };
|
|
|
|
void MarkContentAsBad(BOOL fCancel)
|
|
{
|
|
CCritSect csLock(&m_critSect);
|
|
if (NULL != m_phList)
|
|
{
|
|
for (DWORD index = 0; index < m_Mac; index += 1)
|
|
{
|
|
if (NULL != m_phList[index].phObject)
|
|
m_phList[index].phObject->MarkAsBad(fCancel);
|
|
}
|
|
}
|
|
}
|
|
|
|
CHandle *
|
|
GetFirst()
|
|
{
|
|
DWORD index = 0;
|
|
|
|
while (index < m_Mac)
|
|
{
|
|
if (NULL != m_phList[index].phObject)
|
|
return (m_phList[index].phObject);
|
|
|
|
index++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CHandle *
|
|
GetNext(
|
|
IN CHandle * phObject)
|
|
{
|
|
DWORD index = 0;
|
|
|
|
while (index < m_Mac)
|
|
{
|
|
if (phObject == m_phList[index].phObject)
|
|
break;
|
|
|
|
index++;
|
|
}
|
|
|
|
if (index < m_Mac)
|
|
{
|
|
index++;
|
|
|
|
while (index < m_Mac)
|
|
{
|
|
if (NULL != m_phList[index].phObject)
|
|
return (m_phList[index].phObject);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
protected:
|
|
|
|
struct HandlePtr
|
|
{
|
|
CHandle *phObject;
|
|
DWORD dwCount;
|
|
};
|
|
|
|
// Properties
|
|
|
|
|
|
DWORD
|
|
m_dwId; // Id number of handle list.
|
|
DWORD
|
|
m_Max, // Number of element slots available.
|
|
m_Mac; // Number of element slots used.
|
|
HandlePtr *
|
|
m_phList; // The elements.
|
|
CRITICAL_SECTION
|
|
m_critSect; // Handle list access control.
|
|
BOOL
|
|
m_fInitFailed; // InitCritSec failed in constructor
|
|
|
|
// Methods
|
|
|
|
HandlePtr *
|
|
GetHandlePtr(
|
|
IN HANDLE_TYPE hItem)
|
|
const;
|
|
};
|
|
|
|
|
|
/*++
|
|
|
|
Close:
|
|
|
|
This routine closes an item in the handle array.
|
|
|
|
Arguments:
|
|
|
|
hItem - Supplies the handle to the object to be closed.
|
|
|
|
Throws:
|
|
|
|
ERROR_INVALID_HANDLE - The supplied handle value is invalid.
|
|
|
|
|
|
Return Value:
|
|
|
|
The referenced object.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/13/1995
|
|
|
|
--*/
|
|
|
|
inline CHandle *
|
|
CHandleList::Close(
|
|
IN HANDLE_TYPE hItem)
|
|
{
|
|
CHandle *phItem;
|
|
CCritSect csLock(&m_critSect);
|
|
HandlePtr *pHandlePtr = GetHandlePtr(hItem);
|
|
if (NULL == pHandlePtr)
|
|
throw (DWORD)ERROR_INVALID_HANDLE;
|
|
|
|
phItem = pHandlePtr->phObject;
|
|
if (NULL == phItem)
|
|
throw (DWORD)ERROR_INVALID_HANDLE;
|
|
pHandlePtr->phObject = NULL;
|
|
pHandlePtr->dwCount += 1;
|
|
return phItem;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Add:
|
|
|
|
This method adds an item to the Handle list.
|
|
|
|
Arguments:
|
|
|
|
pvItem - Supplies the value to be added to the list.
|
|
|
|
Return Value:
|
|
|
|
The resultant handle of the Add operation.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/10/1995
|
|
|
|
--*/
|
|
|
|
inline HANDLE_TYPE
|
|
CHandleList::Add(
|
|
IN CHandle *phItem)
|
|
{
|
|
DWORD index;
|
|
HandlePtr * pHndl = NULL;
|
|
|
|
|
|
//
|
|
// Look for a vacant handle slot. We look through m_Max instead of m_Mac,
|
|
// so that if all the official ones are used, we fall into unused territory.
|
|
//
|
|
|
|
CCritSect csLock(&m_critSect);
|
|
for (index = 0; index < m_Max; index += 1)
|
|
{
|
|
pHndl = &m_phList[index];
|
|
if (NULL == pHndl->phObject)
|
|
break;
|
|
pHndl = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure the array was big enough.
|
|
//
|
|
|
|
if (NULL == pHndl)
|
|
{
|
|
DWORD newSize = (0 == m_Max ? 4 : m_Max * 2);
|
|
if ((HANDLE_INDEX_MASK >> HANDLE_INDEX_OFFSET) < newSize)
|
|
throw (DWORD)ERROR_OUTOFMEMORY;
|
|
pHndl = new HandlePtr[newSize];
|
|
if (NULL == pHndl)
|
|
throw (DWORD)ERROR_OUTOFMEMORY;
|
|
if (NULL != m_phList)
|
|
{
|
|
CopyMemory(pHndl, m_phList, sizeof(HandlePtr) * m_Mac);
|
|
delete[] m_phList;
|
|
}
|
|
ZeroMemory(&pHndl[m_Mac], sizeof(HandlePtr) * (newSize - m_Mac));
|
|
m_phList = pHndl;
|
|
m_Max = (DWORD)newSize;
|
|
index = m_Mac++;
|
|
pHndl = &m_phList[index];
|
|
}
|
|
else
|
|
{
|
|
if (m_Mac <= index)
|
|
m_Mac = index + 1;
|
|
}
|
|
|
|
|
|
//
|
|
// Cross index the list element and the object.
|
|
//
|
|
|
|
ASSERT(NULL == pHndl->phObject);
|
|
pHndl->phObject = phItem;
|
|
if (0 == pHndl->dwCount)
|
|
pHndl->dwCount = 1;
|
|
phItem->m_dwCount = (DWORD)(pHndl->dwCount
|
|
& (HANDLE_COUNT_MASK >> HANDLE_COUNT_OFFSET));
|
|
phItem->m_dwIndex = index;
|
|
return (HANDLE_TYPE)(
|
|
((((HANDLE_TYPE)m_dwId) << HANDLE_ID_OFFSET) & HANDLE_ID_MASK)
|
|
| ((((HANDLE_TYPE)pHndl->dwCount) << HANDLE_COUNT_OFFSET) & HANDLE_COUNT_MASK)
|
|
| ((((HANDLE_TYPE)index) << HANDLE_INDEX_OFFSET) & HANDLE_INDEX_MASK));
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
GetQuietly:
|
|
|
|
This method returns the element at the given handle. If the handle is
|
|
invalid, it returns NULL. It does not expand the array.
|
|
|
|
Arguments:
|
|
|
|
hItem - Supplies the index into the list.
|
|
|
|
Return Value:
|
|
|
|
The value stored at that handle in the list, or NULL if the handle is
|
|
invalid.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/13/1995
|
|
|
|
--*/
|
|
|
|
inline CHandle * const
|
|
CHandleList::GetQuietly(
|
|
HANDLE_TYPE hItem)
|
|
{
|
|
CCritSect csLock(&m_critSect);
|
|
HandlePtr *pHandlePtr = GetHandlePtr(hItem);
|
|
if (NULL == pHandlePtr)
|
|
return NULL;
|
|
return pHandlePtr->phObject;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Get:
|
|
|
|
This method returns the element at the given handle. If the handle is
|
|
invalid, it throws an error. It does not expand the array.
|
|
|
|
Arguments:
|
|
|
|
hItem - Supplies the index into the list.
|
|
|
|
Return Value:
|
|
|
|
The value stored at that handle in the list.
|
|
|
|
Throws:
|
|
|
|
ERROR_INVALID_HANDLE - Invalid handle value.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 7/13/1995
|
|
|
|
--*/
|
|
|
|
inline CHandle * const
|
|
CHandleList::Get(
|
|
HANDLE_TYPE hItem)
|
|
{
|
|
CCritSect csLock(&m_critSect);
|
|
HandlePtr *pHandlePtr = GetHandlePtr(hItem);
|
|
if (NULL == pHandlePtr)
|
|
throw (DWORD)ERROR_INVALID_HANDLE;
|
|
return pHandlePtr->phObject;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
GetHandlePtr:
|
|
|
|
This routine finds the HandlePtr structure corresponding to a given handle.
|
|
|
|
Arguments:
|
|
|
|
hItem supplies the handle to look up.
|
|
|
|
Return Value:
|
|
|
|
The address of the HandlePtr structure corresponding to the handle, or NULL
|
|
if none exists.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 5/9/1996
|
|
|
|
--*/
|
|
|
|
inline CHandleList::HandlePtr *
|
|
CHandleList::GetHandlePtr(
|
|
HANDLE_TYPE hItem)
|
|
const
|
|
{
|
|
try
|
|
{
|
|
HandlePtr *pHandlePtr;
|
|
DWORD_PTR dwItem = (DWORD_PTR)hItem;
|
|
DWORD dwId = (DWORD)((dwItem & HANDLE_ID_MASK) >> HANDLE_ID_OFFSET);
|
|
DWORD dwCount = (DWORD)((dwItem & HANDLE_COUNT_MASK) >> HANDLE_COUNT_OFFSET);
|
|
DWORD dwIndex = (DWORD)((dwItem & HANDLE_INDEX_MASK) >> HANDLE_INDEX_OFFSET);
|
|
|
|
if (dwId != (m_dwId & (HANDLE_ID_MASK >> HANDLE_ID_OFFSET))
|
|
|| (m_Mac <= dwIndex))
|
|
return NULL;
|
|
|
|
pHandlePtr = &m_phList[dwIndex];
|
|
if (dwCount
|
|
!= (pHandlePtr->dwCount
|
|
& (HANDLE_ID_MASK >> HANDLE_ID_OFFSET)))
|
|
return NULL;
|
|
|
|
return pHandlePtr;
|
|
}
|
|
catch (...)
|
|
{
|
|
// Swallow the error.
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
IndexHandle:
|
|
|
|
This method converts an index into a handle. The handle is NULL if there is
|
|
no element stored at that index.
|
|
|
|
Arguments:
|
|
|
|
nItem supplies the index of the object to reference.
|
|
|
|
Return Value:
|
|
|
|
The handle of the object, or NULL if there is no object at that index.
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 1/3/1997
|
|
|
|
--*/
|
|
|
|
inline HANDLE_TYPE
|
|
CHandleList::IndexHandle(
|
|
DWORD nItem)
|
|
{
|
|
HANDLE_TYPE hItem = NULL;
|
|
HandlePtr * pHndl;
|
|
|
|
CCritSect csLock(&m_critSect);
|
|
if (m_Mac > nItem)
|
|
{
|
|
pHndl = &m_phList[nItem];
|
|
if (NULL != pHndl->phObject)
|
|
{
|
|
hItem =
|
|
((((HANDLE_TYPE)m_dwId) << HANDLE_ID_OFFSET) & HANDLE_ID_MASK)
|
|
| ((((HANDLE_TYPE)pHndl->dwCount) << HANDLE_COUNT_OFFSET) & HANDLE_COUNT_MASK)
|
|
| ((((HANDLE_TYPE)nItem) << HANDLE_INDEX_OFFSET) & HANDLE_INDEX_MASK);
|
|
}
|
|
}
|
|
return hItem;
|
|
}
|
|
|
|
#endif // _HANDLES_H_
|
|
|