|
|
/*******************************************************************************
* SPDDKHLP.h * *------------* * Description: * This is the header file for core helper functions implementation. * * Copyright (c) Microsoft Corporation. All rights reserved. * *******************************************************************************/ #ifndef SPDDKHLP_h
#define SPDDKHLP_h
#ifndef SPHelper_h
#include <sphelper.h>
#endif
#include <sapiddk.h>
#ifndef SPError_h
#include <SPError.h>
#endif
#ifndef SPDebug_h
#include <SPDebug.h>
#endif
#ifndef _INC_LIMITS
#include <limits.h>
#endif
#ifndef _INC_CRTDBG
#include <crtdbg.h>
#endif
#ifndef _INC_MALLOC
#include <malloc.h>
#endif
#ifndef _INC_MMSYSTEM
#include <mmsystem.h>
#endif
#ifndef __comcat_h__
#include <comcat.h>
#endif
//=== Constants ==============================================================
#define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
#define SP_IS_BAD_WRITE_PTR(p) ( SPIsBadWritePtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_READ_PTR(p) ( SPIsBadReadPtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_CODE_PTR(p) ( ::IsBadCodePtr((FARPROC)(p) )
#define SP_IS_BAD_INTERFACE_PTR(p) ( SPIsBadInterfacePtr( (p) ) )
#define SP_IS_BAD_VARIANT_PTR(p) ( SPIsBadVARIANTPtr( (p) ) )
#define SP_IS_BAD_STRING_PTR(p) ( SPIsBadStringPtr( (p) ) )
#define SP_IS_BAD_OPTIONAL_WRITE_PTR(p) ((p) && SPIsBadWritePtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_OPTIONAL_READ_PTR(p) ((p) && SPIsBadReadPtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && SPIsBadInterfacePtr(p))
#define SP_IS_BAD_OPTIONAL_STRING_PTR(p) ((p) && SPIsBadStringPtr(p))
//=== Class, Enum, Struct, Template, and Union Declarations ==================
//=== Inlines ================================================================
/*** Pointer validation functions
*/
// TODO: Add decent debug output for bad parameters
inline BOOL SPIsBadStringPtr( const WCHAR * psz, ULONG cMaxChars = 0xFFFFF ) { BOOL IsBad = false; __try { do { if( *psz++ == 0 ) return IsBad; } while( --cMaxChars ); } __except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ) { IsBad = true; }
if(!cMaxChars) { IsBad = true; // Only strings of max 0xFFFFF chars long including terminating zero are valid
}
return IsBad; }
inline BOOL SPIsBadReadPtr( const void* pMem, UINT Size ) { #ifdef _DEBUG
BOOL bIsBad = ::IsBadReadPtr( pMem, Size ); SPDBG_ASSERT(!bIsBad); return bIsBad; #else
return ::IsBadReadPtr( pMem, Size ); #endif
}
inline BOOL SPIsBadWritePtr( void* pMem, UINT Size ) { #ifdef _DEBUG
BOOL bIsBad = ::IsBadWritePtr( pMem, Size ); SPDBG_ASSERT(!bIsBad); return bIsBad; #else
return ::IsBadWritePtr( pMem, Size ); #endif
}
inline BOOL SPIsBadInterfacePtr( const IUnknown* pUnknown ) { #ifdef _DEBUG
BOOL bIsBad = ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) || ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))? (true):(false); SPDBG_ASSERT(!bIsBad); return bIsBad; #else
return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) || ::IsBadCodePtr( (FARPROC)((void**)pUnknown)[0] ))? (true):(false); #endif
}
inline BOOL SPIsBadVARIANTPtr( const VARIANT* pVar ) { #ifdef _DEBUG
BOOL bIsBad = ::IsBadReadPtr( pVar, sizeof( *pVar ) ); SPDBG_ASSERT(!bIsBad); return bIsBad; #else
return ::IsBadReadPtr( pVar, sizeof( *pVar ) ); #endif
}
#ifdef __ATLCOM_H__ //--- Only enable these if ATL is being used
//
// Helper functions can be used to implement GetObjectToken/SetObjectToken for objects that
// support ISpObjectWithToken
//
inline HRESULT SpGenericSetObjectToken(ISpObjectToken * pCallersToken, CComPtr<ISpObjectToken> & cpObjToken) { HRESULT hr = S_OK; if (SP_IS_BAD_INTERFACE_PTR(pCallersToken)) { hr = E_INVALIDARG; } else { if (cpObjToken) { hr = SPERR_ALREADY_INITIALIZED; } else { cpObjToken = pCallersToken; } } return hr; }
inline HRESULT SpGenericGetObjectToken(ISpObjectToken ** ppCallersToken, CComPtr<ISpObjectToken> & cpObjToken) { HRESULT hr = S_OK; if (SP_IS_BAD_WRITE_PTR(ppCallersToken)) { hr = E_POINTER; } else { *ppCallersToken = cpObjToken; if (*ppCallersToken) { (*ppCallersToken)->AddRef(); } else { hr = S_FALSE; } } return hr; }
#endif // __ATLCOM_H__
//
// Helper class for SPSTATEINFO sturcture automatically initializes and cleans up
// the structure + provides a few helper functions.
//
class CSpStateInfo : public SPSTATEINFO { public: CSpStateInfo() { cAllocatedEntries = NULL; pTransitions = NULL; } ~CSpStateInfo() { ::CoTaskMemFree(pTransitions); } SPTRANSITIONENTRY * FirstEpsilon() { return pTransitions; } SPTRANSITIONENTRY * FirstRule() { return pTransitions + cEpsilons; } SPTRANSITIONENTRY * FirstWord() { return pTransitions + cEpsilons + cRules; } SPTRANSITIONENTRY * FirstSpecialTransition() { return pTransitions + cEpsilons + cRules + cWords; } };
//
// This basic queue implementation can be used to maintin linked lists of classes. The class T
// must contain the member m_pNext which is used by this template to point to the next element.
// If the bPurgeWhenDeleted is TRUE then all of the elements in the queue will be deleted
// when the queue is deleted, otherwise they will not.
// If bMaintainCount is TRUE then a running count will be maintained, and GetCount() will be
// efficent. If it is FALSE then a running count will not be maintained, and GetCount() will
// be an order N operation. If you do not require a count, then
//
template <class T, BOOL bPurgeWhenDeleted> class CSpBasicList;
template <class T, BOOL bPurgeWhenDeleted = TRUE, BOOL bMaintainCount = FALSE> class CSpBasicQueue { public: T * m_pHead; T * m_pTail; ULONG m_cElements; // Warning! Use GetCount() -- Not maintained if bMaintainCount is FALSE.
CSpBasicQueue() { m_pHead = NULL; if (bMaintainCount) { m_cElements = 0; } }
~CSpBasicQueue() { if (bPurgeWhenDeleted) { Purge(); } }
HRESULT CreateNode(T ** ppNode) { *ppNode = new T; if (*ppNode) { return S_OK; } else { return E_OUTOFMEMORY; } }
T * GetNext(const T * pNode) { return pNode->m_pNext; }
T * Item(ULONG i) { T * pNode = m_pHead; while (pNode && i) { i--; pNode = pNode->m_pNext; } return pNode; }
void InsertAfter(T * pPrev, T * pNewNode) { if (pPrev) { pNewNode->m_pNext = pPrev->m_pNext; pPrev->m_pNext = pNewNode; if (pNewNode->m_pNext == NULL) { m_pTail = pNewNode; } if (bMaintainCount) ++m_cElements; } else { InsertHead(pNewNode); } }
void InsertTail(T * pNode) { pNode->m_pNext = NULL; if (m_pHead) { m_pTail->m_pNext = pNode; } else { m_pHead = pNode; } m_pTail = pNode; if (bMaintainCount) ++m_cElements; }
void InsertHead(T * pNode) { pNode->m_pNext = m_pHead; if (m_pHead == NULL) { m_pTail = pNode; } m_pHead = pNode; if (bMaintainCount) ++m_cElements; }
T * RemoveHead() { T * pNode = m_pHead; if (pNode) { m_pHead = pNode->m_pNext; if (bMaintainCount) --m_cElements; } return pNode; }
T * RemoveTail() { T * pNode = m_pHead; if (pNode) { if (pNode == m_pTail) { m_pHead = NULL; } else { T * pPrev; do { pPrev = pNode; pNode = pNode->m_pNext; } while ( pNode != m_pTail ); pPrev->m_pNext = NULL; m_pTail = pPrev; } if (bMaintainCount) --m_cElements; } return pNode; }
void Purge() { while (m_pHead) { T * pDie = m_pHead; m_pHead = pDie->m_pNext; delete pDie; } if (bMaintainCount) m_cElements = 0; }
void ExplicitPurge() { T * pDie; BYTE * pb;
while (m_pHead) { pDie = m_pHead; m_pHead = pDie->m_pNext;
pDie->~T();
pb = reinterpret_cast<BYTE *>(pDie); delete [] pb; } if (bMaintainCount) m_cElements = 0; }
T * GetTail() const { if (m_pHead) { return m_pTail; } return NULL; }
T * GetHead() const { return m_pHead; }
BOOL IsEmpty() const { return m_pHead == NULL; }
BOOL Remove(T * pNode) { if (m_pHead == pNode) { m_pHead = pNode->m_pNext; if (bMaintainCount) --m_cElements; return TRUE; } else { T * pCur = m_pHead; while (pCur) { T * pNext = pCur->m_pNext; if (pNext == pNode) { if ((pCur->m_pNext = pNode->m_pNext) == NULL) { m_pTail = pCur; } if (bMaintainCount) --m_cElements; return TRUE; } pCur = pNext; } } return FALSE; }
void MoveAllToHeadOf(CSpBasicQueue & DestQueue) { if (m_pHead) { m_pTail->m_pNext = DestQueue.m_pHead; if (DestQueue.m_pHead == NULL) { DestQueue.m_pTail = m_pTail; } DestQueue.m_pHead = m_pHead; m_pHead = NULL; if (bMaintainCount) { DestQueue.m_cElements += m_cElements; m_cElements = 0; } } }
void MoveAllToList(CSpBasicList<T, bPurgeWhenDeleted> & List) { if (m_pHead) { m_pTail->m_pNext = List.m_pFirst; List.m_pFirst = m_pHead; m_pHead = NULL; } if (bMaintainCount) { m_cElements = 0; } }
BOOL MoveToList(T * pNode, CSpBasicList<T, bPurgeWhenDeleted> & List) { BOOL bFound = Remove(pNode); if (bFound) { List.AddNode(pNode); } return bFound; }
ULONG GetCount() const { if (bMaintainCount) { return m_cElements; } else { ULONG c = 0; for (T * pNode = m_pHead; pNode; pNode = pNode->m_pNext, c++) {} return c; } }
//
// The following functions require the class T to implement a static function:
//
// LONG Compare(const T * pElem1, const T * pElem2)
//
// which returns < 0 if pElem1 is less than pElem2, 0 if they are equal, and > 0 if
// pElem1 is greater than pElem2.
//
void InsertSorted(T * pNode) { if (m_pHead) { if (T::Compare(pNode, m_pTail) >= 0) { pNode->m_pNext = NULL; m_pTail->m_pNext = pNode; m_pTail = pNode; } else { //
// We don't have to worry about walking off of the end of the list here since
// we have already checked the tail.
//
T ** ppNext = &m_pHead; while (T::Compare(pNode, *ppNext) >= 0) { ppNext = &((*ppNext)->m_pNext); } pNode->m_pNext = *ppNext; *ppNext = pNode; } } else { pNode->m_pNext = NULL; m_pHead = m_pTail = pNode; } if (bMaintainCount) ++m_cElements; }
HRESULT InsertSortedUnique(T * pNode) { HRESULT hr = S_OK; if (m_pHead) { if (T::Compare(pNode, m_pTail) > 0) { pNode->m_pNext = NULL; m_pTail->m_pNext = pNode; m_pTail = pNode; } else { //
// We don't have to worry about walking off of the end of the list here since
// we have already checked the tail.
//
T ** ppNext = &m_pHead; while (T::Compare(pNode, *ppNext) > 0) { ppNext = &((*ppNext)->m_pNext); } if (T::Compare(pNode, *ppNext) != 0) { pNode->m_pNext = *ppNext; *ppNext = pNode; } else { delete pNode; hr = S_FALSE; } } } else { pNode->m_pNext = NULL; m_pHead = m_pTail = pNode; } if (bMaintainCount) ++m_cElements; return hr; }
//
// These functions must support the "==" operator for the TFIND type.
//
template <class TFIND> T * Find(TFIND & FindVal) const { for (T * pNode = m_pHead; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext) {} return pNode; }
template <class TFIND> T * FindNext(const T * pCurNode, TFIND & FindVal) const { for (T * pNode = pCurNode->m_pNext; pNode && (!(*pNode == FindVal)); pNode = pNode->m_pNext) {} return pNode; }
//
// Searches for and removes a single list element
//
template <class TFIND> T * FindAndRemove(TFIND & FindVal) { T * pNode = m_pHead; if (pNode) { if (*pNode == FindVal) { m_pHead = pNode->m_pNext; if (bMaintainCount) --m_cElements; } else { T * pPrev = pNode; for (pNode = pNode->m_pNext; pNode; pPrev = pNode, pNode = pNode->m_pNext) { if (*pNode == FindVal) { pPrev->m_pNext = pNode->m_pNext; if (pNode->m_pNext == NULL) { m_pTail = pPrev; } if (bMaintainCount) --m_cElements; break; } } } } return pNode; }
//
// Searches for and deletes all list elements that match
//
template <class TFIND> void FindAndDeleteAll(TFIND & FindVal) { T * pNode = m_pHead; while (pNode && *pNode == FindVal) { m_pHead = pNode->m_pNext; delete pNode; if (bMaintainCount) --m_cElements; pNode = m_pHead; } T * pPrev = pNode; while (pNode) { T * pNext = pNode->m_pNext; if (*pNode == FindVal) { pPrev->m_pNext = pNext; delete pNode; if (bMaintainCount) --m_cElements; } else { pPrev = pNode; } pNode = pNext; } m_pTail = pPrev; // Just always set it in case we removed the tail.
}
};
template <class T, BOOL bPurgeWhenDeleted = TRUE> class CSpBasicList { public: T * m_pFirst; CSpBasicList() : m_pFirst(NULL) {} ~CSpBasicList() { if (bPurgeWhenDeleted) { Purge(); } }
void Purge() { while (m_pFirst) { T * pNext = m_pFirst->m_pNext; delete m_pFirst; m_pFirst = pNext; } }
void ExplicitPurge() { T * pDie; BYTE * pb;
while (m_pFirst) { pDie = m_pFirst; m_pFirst = pDie->m_pNext;
pDie->~T();
pb = reinterpret_cast<BYTE *>(pDie); delete [] pb; } }
HRESULT RemoveFirstOrAllocateNew(T ** ppNode) { if (m_pFirst) { *ppNode = m_pFirst; m_pFirst = m_pFirst->m_pNext; } else { *ppNode = new T; if (*ppNode == NULL) { return E_OUTOFMEMORY; } } return S_OK; }
void AddNode(T * pNode) { pNode->m_pNext = m_pFirst; m_pFirst = pNode; } T * GetFirst() { return m_pFirst; } T * RemoveFirst() { T * pNode = m_pFirst; if (pNode) { m_pFirst = pNode->m_pNext; } return pNode; } };
#define STACK_ALLOC(TYPE, COUNT) (TYPE *)_alloca(sizeof(TYPE) * (COUNT))
#define STACK_ALLOC_AND_ZERO(TYPE, COUNT) (TYPE *)memset(_alloca(sizeof(TYPE) * (COUNT)), 0, (sizeof(TYPE) * (COUNT)))
#define STACK_ALLOC_AND_COPY(TYPE, COUNT, SOURCE) (TYPE *)memcpy(_alloca(sizeof(TYPE) * (COUNT)), (SOURCE), (sizeof(TYPE) * (COUNT)))
inline HRESULT SpGetSubTokenFromToken( ISpObjectToken * pToken, const WCHAR * pszSubKeyName, ISpObjectToken ** ppToken, BOOL fCreateIfNotExist = FALSE) { SPDBG_FUNC("SpGetTokenFromDataKey"); HRESULT hr = S_OK;
if (SP_IS_BAD_INTERFACE_PTR(pToken) || SP_IS_BAD_STRING_PTR(pszSubKeyName) || SP_IS_BAD_WRITE_PTR(ppToken)) { hr = E_POINTER; }
// First, either create or open the datakey for the new token
CComPtr<ISpDataKey> cpDataKeyForNewToken; if (SUCCEEDED(hr)) { if (fCreateIfNotExist) { hr = pToken->CreateKey(pszSubKeyName, &cpDataKeyForNewToken); } else { hr = pToken->OpenKey(pszSubKeyName, &cpDataKeyForNewToken); } }
// The sub token's category will be the token id of it's parent token
CSpDynamicString dstrCategoryId; if (SUCCEEDED(hr)) { hr = pToken->GetId(&dstrCategoryId); }
// The sub token's token id will be it's category id + "\\" the key name
CSpDynamicString dstrTokenId; if (SUCCEEDED(hr)) { dstrTokenId = dstrCategoryId; dstrTokenId.Append2(L"\\", pszSubKeyName); }
// Now create the token and initalize it
CComPtr<ISpObjectTokenInit> cpTokenInit; if (SUCCEEDED(hr)) { hr = cpTokenInit.CoCreateInstance(CLSID_SpObjectToken); }
if (SUCCEEDED(hr)) { hr = cpTokenInit->InitFromDataKey(dstrCategoryId, dstrTokenId, cpDataKeyForNewToken); }
if (SUCCEEDED(hr)) { *ppToken = cpTokenInit.Detach(); }
SPDBG_REPORT_ON_FAIL(hr); return hr; }
template<class T> HRESULT SpCreateObjectFromSubToken(ISpObjectToken * pToken, const WCHAR * pszSubKeyName, T ** ppObject, IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL) { SPDBG_FUNC("SpCreateObjectFromSubToken"); HRESULT hr;
CComPtr<ISpObjectToken> cpSubToken; hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken); if (SUCCEEDED(hr)) { hr = SpCreateObjectFromToken(cpSubToken, ppObject, pUnkOuter, dwClsCtxt); }
SPDBG_REPORT_ON_FAIL(hr); return hr; }
#endif /* This must be the last line in the file */
|