/*++ 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_