xpmgr/BuildTools/Include/spddkhlp.h

1112 lines
27 KiB
C++

/*******************************************************************************
// Copyright Microsoft Corporation. All Rights Reserved.
* SPDDKHLP.h *
*------------*
* Description:
* This is the header file for core helper functions implementation.
*
*
*******************************************************************************/
#ifndef SPDDKHLP_h
#define SPDDKHLP_h
#include <tchar.h>
#ifndef SPHelper_h
#include <sphelper.h>
#endif
#include <sapiddk.h>
//=== Constants ==============================================================
#define sp_countof(x) ((sizeof(x) / sizeof(*(x))))
#define SP_IS_BAD_WRITE_PTR(p) ( !(p) || SPIsBadWritePtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_READ_PTR(p) ( !(p) || SPIsBadReadPtr( p, sizeof(*(p)) ))
#define SP_IS_BAD_CODE_PTR(p) ( (FARPROC)(p) == 0 )
#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))
#define SP_IS_BAD_READ_ARRAY(p,cElements) ( SPIsBadReadArray( p, cElements, sizeof(*p) ) )
#define SP_IS_BAD_WRITE_ARRAY(p,cElements) ( SPIsBadWriteArray( p, cElements, sizeof(*p) ) )
#define SP_DOES_PTR_ADDITION_WRAP(p) ( SPDoesPtrAdditionWrap( p, sizeof(*p) ) )
#define SP_IS_PTR_OUT_OF_BOUNDS(p,pBound) ( SPIsPtrOutOfBounds( p, sizeof(*p), pBound ) )
#define sp_sgn(x) ( (x) == 0 ? 0 : ( (x)>0 ? 1 : -1 ) )
//=== Class, Enum, Struct, Template, and Union Declarations ==================
//=== Inlines ================================================================
/*** Pointer validation functions
*/
inline BOOL SPIsBadStringPtr( const WCHAR * psz, ULONG cMaxChars = 0xFFFFF )
{
return ((psz == NULL) || (wcslen(psz) + 1 > cMaxChars));
}
inline BOOL SPIsBadReadPtr( __in_bcount(Size) const void* pMem, size_t Size )
{
return (pMem == NULL) && (Size != 0);
}
inline BOOL SPIsBadWritePtr( __in_bcount(Size) void* pMem, size_t Size )
{
return (pMem == NULL) && (Size != 0);
}
inline BOOL SPIsBadInterfacePtr( const IUnknown* pUnknown )
{
return (pUnknown == NULL);
}
inline BOOL SPIsBadVARIANTPtr( const VARIANT* pVar )
{
return (pVar == NULL);
}
inline BOOL SPDoesPtrAdditionWrap( __in_bcount(Size) const void* pMem, size_t Size )
{
return ((const BYTE*)pMem + Size) < (const BYTE*)pMem;
}
inline BOOL SPIsBadReadArray( const void* pMem, ULONG cElementCount, size_t cBytesPerElement)
{
size_t cByteCount = cBytesPerElement * cElementCount;
if ( // Does the multiplication operation overflow?
( ( cByteCount / cBytesPerElement ) != cElementCount ) ||
// Does the pointer addition wrap?
( SPDoesPtrAdditionWrap ( pMem, cByteCount ) ) ||
// Can we read from the pointer?
( SPIsBadReadPtr ( pMem, cByteCount ) ) )
{
// One of the preconditions didn't hold.
// YES, this IS a BAD Read array.
return TRUE;
}
else
{
// NO, this is NOT a BAD Read array.
return FALSE;
}
}
inline BOOL SPIsBadWriteArray( void* pMem, ULONG cElementCount, size_t cBytesPerElement)
{
size_t cByteCount = cBytesPerElement * cElementCount;
if ( // Did the multiplication operation overflow?
( ( cByteCount / cBytesPerElement ) != cElementCount ) ||
// Does the pointer addition wrap?
( SPDoesPtrAdditionWrap ( pMem, cByteCount ) ) ||
// Can we write to this pointer?
( SPIsBadWritePtr ( pMem, cByteCount ) ) )
{
// One of the preconditions didn't hold.
// YES, this IS a BAD Write array.
return TRUE;
}
else
{
// NO, this is NOT a BAD Write array.
return FALSE;
}
}
/************************************************************************
* SPIsPtrOutOfBounds *
* -------------------------------*
* Description:
* Ensures that ( n_pStart + n_cBytes ) doesn't wrap/overflow, and
* doesn't scroll up to or past n_pBound.
*
* Returns:
* FALSE Memory block is in bounds
* TRUE Pointer arithmetic overflow, or
* ( n_pStart + n_cBytes ) >= n_pBound
*
************************************************************** mishav ***/
inline BOOL SPIsPtrOutOfBounds(__in_bcount(n_cBytes) const void* n_pStart,
size_t n_cBytes,
const void* n_pBound)
{
const void* pEnd = (const BYTE*)n_pStart + n_cBytes;
// In order to be valid, the pointers MUST be arranged
// in the following order:
// n_pStart <= pEnd < n_pBound.
if ( ( n_pStart <= pEnd ) &&
( pEnd <= n_pBound) )
{
return FALSE;
}
else
{
return TRUE;
}
}
inline BOOL SPIsArrayOutOfBounds(const void* n_pStart,
ULONG n_cElements,
size_t n_cBytesPerElement,
const void* n_pBound)
{
// Perform and check the multiplication
size_t cBytesTotal = n_cElements * n_cBytesPerElement;
if ( ( cBytesTotal / n_cElements ) != n_cBytesPerElement )
{
return FALSE;
}
else
{
return SPIsPtrOutOfBounds(n_pStart, cBytesTotal, n_pBound);
}
}
inline BOOL SPIsStringOutOfBounds(const WCHAR* n_pwcszString,
const void* n_pBound = NULL,
const void* n_pLowerBound = NULL)
{
BOOL br = FALSE;
const WCHAR* pwcszBound = (const WCHAR*)n_pBound;
const WCHAR* pwcszLowerBound = (const WCHAR*)n_pLowerBound;
// Pointers must be in the following order:
// Lower bound, String, Upper bound
if ( (pwcszLowerBound && (pwcszLowerBound > n_pwcszString) ) ||
(pwcszBound && (n_pwcszString >= pwcszBound) ) ||
SP_IS_BAD_STRING_PTR(n_pwcszString) )
{
br = TRUE;
}
else if (pwcszBound)
{
const size_t cStrMaxLen = pwcszBound - n_pwcszString;
const size_t cStrActualLen = wcslen(n_pwcszString);
if (cStrActualLen > cStrMaxLen)
{
br = TRUE;
}
}
else
{
br = FALSE;
}
return br;
}
/************************************************************
* SpSafePtrAdd *
*----------------*
* Description:
* Advances the n_ppBase pointer by n_cBytes bytes.
* Returns E_INVALIDARG on pointer wraparound or if
* the pointer exceeds the bound (presuming the bound
* is specified).
******************************************* mishav *********/
template <class _C>
inline HRESULT SpSafePtrAdd (_C** n_ppBase, size_t n_cBytes, const void* n_pBound = NULL)
{
HRESULT hr = S_OK;
// Perform the addition
const BYTE* pByteCast = (const BYTE*)(*n_ppBase);
const BYTE* pByteAdded = pByteCast + n_cBytes;
// Check for wrapping
// Check for a bound having been specified, and make sure it doesn't exceed it.
if ( (pByteAdded < pByteCast) ||
(n_pBound!=NULL && pByteAdded>n_pBound) )
{
hr = E_INVALIDARG;
}
else
{
*n_ppBase = (_C*)(pByteAdded);
}
return hr;
}
/************************************************************
* SpSafePtrMultiplyAdd *
*---------------------*
* Description:
* Advances the n_ppBase pointer by (n_cElements * n_cBytesPerElement) bytes.
* Returns E_INVALIDARG on pointer wraparound or if
* the pointer exceeds the bound (presuming the bound
* is specified).
******************************************* mishav *********/
template <class _C>
inline HRESULT SpSafePtrMultiplyAdd (_C** n_ppBase,
ULONG n_cElements,
size_t n_cBytesPerElement,
const void* n_pBound = NULL)
{
HRESULT hr = S_OK;
// Perform and check the multiplication
ULONG cBytesTotal = n_cElements * n_cBytesPerElement;
if ( ( cBytesTotal / n_cElements ) != n_cBytesPerElement )
{
hr = E_INVALIDARG;
}
else
{
hr = SpSafePtrAdd(n_ppBase, cBytesTotal, n_pBound);
}
return hr;
}
#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
{
T * pNode = m_pHead;
for (; 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)
{
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();
}
return hr;
}
template<class T>
HRESULT SpCreateObjectFromSubToken(ISpObjectToken * pToken, const WCHAR * pszSubKeyName, T ** ppObject,
IUnknown * pUnkOuter = NULL, DWORD dwClsCtxt = CLSCTX_ALL)
{
HRESULT hr;
CComPtr<ISpObjectToken> cpSubToken;
hr = SpGetSubTokenFromToken(pToken, pszSubKeyName, &cpSubToken);
if (SUCCEEDED(hr))
{
hr = SpCreateObjectFromToken(cpSubToken, ppObject, pUnkOuter, dwClsCtxt);
}
return hr;
}
__inline HRESULT GetObjectToken(const WCHAR* pszTokenCat,
const WCHAR* pszTokenName,
CComPtr<ISpObjectToken> &cpToken)
{
cpToken = NULL;
CComPtr<IEnumSpObjectTokens> cpEnum;
ISpObjectToken* pToken = NULL;
if (SUCCEEDED(SpEnumTokens(pszTokenCat, NULL, NULL, &cpEnum)))
{
while (cpEnum->Next(1, &pToken, NULL) == S_OK)
{
CSpDynamicString dstrDesc;
if (SUCCEEDED(SpGetDescription(pToken, &dstrDesc)))
{
if (! wcscmp(dstrDesc.m_psz, pszTokenName))
{
cpToken = pToken;
goto Exit;
}
}
if (pToken)
{
pToken->Release();
pToken = NULL;
}
}
}
Exit:
if (pToken)
{
pToken->Release();
}
if (cpToken == NULL)
{
return E_FAIL;
}
return S_OK;
}
// Return a token enumerator containing all tokens that match the primary language
// of a particular language id. pszRequiredAttributes can be used to specify additional attributes all tokens must have.
inline HRESULT SpEnumTokensMatchingPrimaryLangID(const LPCWSTR pszCategoryId, LANGID priLangID, LPCWSTR pszRequiredAtts,
IEnumSpObjectTokens **ppEnum)
{
HRESULT hr = S_OK;
// First enumerate the tokens using pszRequiredAtts.
CComPtr<ISpObjectTokenCategory> cpCategory;
hr = SpGetCategoryFromId(pszCategoryId, &cpCategory);
CComPtr<IEnumSpObjectTokens> cpEnum;
if (SUCCEEDED(hr))
{
hr = cpCategory->EnumTokens(pszRequiredAtts, NULL, &cpEnum);
}
ULONG ulTokens;
if (SUCCEEDED(hr))
{
hr = cpEnum->GetCount(&ulTokens);
}
// Create enumerator to store new tokens.
CComPtr<ISpObjectTokenEnumBuilder> cpBuilder;
if (SUCCEEDED(hr))
{
hr = cpBuilder.CoCreateInstance(CLSID_SpObjectTokenEnum);
}
if (SUCCEEDED(hr))
{
hr = cpBuilder->SetAttribs(NULL, NULL);
}
// Now, for each token, check language string to see if it matches.
for (ULONG ul = 0; SUCCEEDED(hr) && ul < ulTokens; ul++)
{
LANGID tokenLangID;
CComPtr<ISpObjectToken> cpToken;
hr = cpEnum->Item(ul, &cpToken);
if (SUCCEEDED(hr))
{
// Just look at the first language id
hr = SpGetLanguageFromToken(cpToken, &tokenLangID);
}
if (SUCCEEDED(hr) && PRIMARYLANGID(tokenLangID) == PRIMARYLANGID(priLangID))
{
// Add to builder
hr = cpBuilder->AddTokens(1, &(cpToken.p));
}
}
if (SUCCEEDED(hr))
{
hr = cpBuilder->Reset();
}
if (SUCCEEDED(hr))
{
*ppEnum = cpBuilder.Detach();
}
return hr;
}
#endif /* This must be the last line in the file */