mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,854 @@
|
||||
/*******************************************************************************
|
||||
* 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 = 0xFFFF )
|
||||
{
|
||||
BOOL IsBad = false;
|
||||
__try
|
||||
{
|
||||
do
|
||||
{
|
||||
if( *psz++ == 0 ) return IsBad;
|
||||
}
|
||||
while( --cMaxChars );
|
||||
}
|
||||
__except( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION )
|
||||
{
|
||||
IsBad = true;
|
||||
}
|
||||
|
||||
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 */
|
||||
@@ -0,0 +1,636 @@
|
||||
/*******************************************************************************
|
||||
* SPDebug.h *
|
||||
*-----------*
|
||||
* Description:
|
||||
* This header file contains debug output services for SAPI5
|
||||
*-------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <TCHAR.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#ifdef ASSERT_WITH_STACK
|
||||
#include "AssertWithStack.h"
|
||||
#endif
|
||||
|
||||
const TCHAR g_szSpDebugKey[] = _T("SPDebug");
|
||||
const TCHAR g_szSpDebugFuncTraceReportMode[] = _T("FuncTraceMode");
|
||||
const TCHAR g_szSpDebugFuncTraceReportFile[] = _T("FuncTraceFile");
|
||||
const TCHAR g_szSpDebugParamInfoReportMode[] = _T("ParamInfoMode");
|
||||
const TCHAR g_szSpDebugParamInfoReportFile[] = _T("ParamInfoFile");
|
||||
const TCHAR g_szSpDebugDumpInfoReportMode[] = _T("DumpInfoMode");
|
||||
const TCHAR g_szSpDebugDumpInfoReportFile[] = _T("DumpInfoFile");
|
||||
const TCHAR g_szSpDebugAssertReportMode[] = _T("AssertMode");
|
||||
const TCHAR g_szSpDebugAssertReportFile[] = _T("AssertFile");
|
||||
const TCHAR g_szSpDebugHRFailReportMode[] = _T("HRFailMode");
|
||||
const TCHAR g_szSpDebugHRFailReportFile[] = _T("HRFailFile");
|
||||
|
||||
const TCHAR g_szSpDebugAssertSettingsReReadEachTime[] = _T("AssertSettingsReReadEachTime");
|
||||
const TCHAR g_szSpDebugServerOnStart[] = _T("DebugServerOnStart");
|
||||
const TCHAR g_szSpDebugClientOnStart[] = _T("DebugClientOnStart");
|
||||
|
||||
const TCHAR g_szSpDebugLog[] = _T("c:\\spdebug.log");
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
class CSpDebug
|
||||
{
|
||||
public:
|
||||
|
||||
CSpDebug()
|
||||
{
|
||||
m_mutex = NULL;
|
||||
m_reportModePrev = -1;
|
||||
m_hfilePrev = NULL;
|
||||
Read();
|
||||
}
|
||||
|
||||
~CSpDebug()
|
||||
{
|
||||
if (m_mutex != NULL)
|
||||
{
|
||||
CloseHandle(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL FuncTrace(BOOL fEnter = TRUE)
|
||||
{
|
||||
return fEnter
|
||||
? Enter(_CRT_WARN, m_FuncTraceMode, m_szFuncTraceFile)
|
||||
: Leave();
|
||||
}
|
||||
|
||||
BOOL ParamInfo(BOOL fEnter = TRUE)
|
||||
{
|
||||
return fEnter
|
||||
? Enter(_CRT_WARN, m_ParamInfoMode, m_szParamInfoFile)
|
||||
: Leave();
|
||||
}
|
||||
|
||||
BOOL DumpInfo(BOOL fEnter = TRUE)
|
||||
{
|
||||
return fEnter
|
||||
? Enter(_CRT_WARN, m_DumpInfoMode, m_szDumpInfoFile)
|
||||
: Leave();
|
||||
}
|
||||
|
||||
BOOL Assert(BOOL fEnter = TRUE)
|
||||
{
|
||||
if (m_fAssertSettingsReReadEachTime)
|
||||
Read();
|
||||
|
||||
return fEnter
|
||||
? Enter(_CRT_ASSERT, m_AssertMode, m_szAssertFile)
|
||||
: Leave();
|
||||
}
|
||||
|
||||
BOOL HRFail(BOOL fEnter = TRUE)
|
||||
{
|
||||
return fEnter
|
||||
? Enter(_CRT_WARN, m_HRFailMode, m_szHRFailFile)
|
||||
: Leave();
|
||||
}
|
||||
|
||||
BOOL DebugServerOnStart()
|
||||
{
|
||||
return m_fDebugServerOnStart;
|
||||
}
|
||||
|
||||
BOOL DebugClientOnStart()
|
||||
{
|
||||
return m_fDebugClientOnStart;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void Read()
|
||||
{
|
||||
HKEY hkeyDebug;
|
||||
RegCreateKeyEx(
|
||||
HKEY_CLASSES_ROOT,
|
||||
g_szSpDebugKey,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
KEY_READ | KEY_WRITE,
|
||||
NULL,
|
||||
&hkeyDebug,
|
||||
NULL);
|
||||
if (hkeyDebug == NULL)
|
||||
{
|
||||
RegCreateKeyEx(
|
||||
HKEY_CLASSES_ROOT,
|
||||
g_szSpDebugKey,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
KEY_READ,
|
||||
NULL,
|
||||
&hkeyDebug,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DWORD dw = sizeof(m_fAssertSettingsReReadEachTime);
|
||||
if (RegQueryValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugAssertSettingsReReadEachTime,
|
||||
NULL,
|
||||
NULL,
|
||||
LPBYTE(&m_fAssertSettingsReReadEachTime),
|
||||
&dw) != ERROR_SUCCESS)
|
||||
{
|
||||
m_fAssertSettingsReReadEachTime = FALSE;
|
||||
RegSetValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugAssertSettingsReReadEachTime,
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
LPBYTE(&m_fAssertSettingsReReadEachTime),
|
||||
sizeof(m_fAssertSettingsReReadEachTime));
|
||||
}
|
||||
|
||||
ReadFor(
|
||||
hkeyDebug,
|
||||
g_szSpDebugFuncTraceReportMode,
|
||||
g_szSpDebugFuncTraceReportFile,
|
||||
&m_FuncTraceMode,
|
||||
m_szFuncTraceFile,
|
||||
0,
|
||||
g_szSpDebugLog);
|
||||
ReadFor(
|
||||
hkeyDebug,
|
||||
g_szSpDebugParamInfoReportMode,
|
||||
g_szSpDebugParamInfoReportFile,
|
||||
&m_ParamInfoMode,
|
||||
m_szParamInfoFile,
|
||||
0,
|
||||
g_szSpDebugLog);
|
||||
ReadFor(
|
||||
hkeyDebug,
|
||||
g_szSpDebugDumpInfoReportMode,
|
||||
g_szSpDebugDumpInfoReportFile,
|
||||
&m_DumpInfoMode,
|
||||
m_szDumpInfoFile,
|
||||
_CRTDBG_MODE_DEBUG,
|
||||
g_szSpDebugLog);
|
||||
ReadFor(
|
||||
hkeyDebug,
|
||||
g_szSpDebugAssertReportMode,
|
||||
g_szSpDebugAssertReportFile,
|
||||
&m_AssertMode,
|
||||
m_szAssertFile,
|
||||
_CRTDBG_MODE_WNDW,
|
||||
g_szSpDebugLog);
|
||||
ReadFor(
|
||||
hkeyDebug,
|
||||
g_szSpDebugHRFailReportMode,
|
||||
g_szSpDebugHRFailReportFile,
|
||||
&m_HRFailMode,
|
||||
m_szHRFailFile,
|
||||
_CRTDBG_MODE_DEBUG,
|
||||
g_szSpDebugLog);
|
||||
|
||||
dw = sizeof(m_fDebugServerOnStart);
|
||||
if (RegQueryValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugServerOnStart,
|
||||
NULL,
|
||||
NULL,
|
||||
LPBYTE(&m_fDebugServerOnStart),
|
||||
&dw) != ERROR_SUCCESS)
|
||||
{
|
||||
m_fDebugServerOnStart = FALSE;
|
||||
RegSetValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugServerOnStart,
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
LPBYTE(&m_fDebugServerOnStart),
|
||||
sizeof(m_fDebugServerOnStart));
|
||||
}
|
||||
|
||||
dw = sizeof(m_fDebugClientOnStart);
|
||||
if (RegQueryValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugClientOnStart,
|
||||
NULL,
|
||||
NULL,
|
||||
LPBYTE(&m_fDebugClientOnStart),
|
||||
&dw) != ERROR_SUCCESS)
|
||||
{
|
||||
m_fDebugClientOnStart = FALSE;
|
||||
RegSetValueEx(
|
||||
hkeyDebug,
|
||||
g_szSpDebugClientOnStart,
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
LPBYTE(&m_fDebugClientOnStart),
|
||||
sizeof(m_fDebugClientOnStart));
|
||||
}
|
||||
|
||||
RegCloseKey(hkeyDebug);
|
||||
}
|
||||
|
||||
void ReadFor(
|
||||
HKEY hkey,
|
||||
const TCHAR * pszModeValueName,
|
||||
const TCHAR * pszFileValueName,
|
||||
DWORD * pdwModeValue,
|
||||
TCHAR * pszFileValue,
|
||||
DWORD dwDefaultModeValue,
|
||||
const TCHAR * pszDefaultFileValue)
|
||||
{
|
||||
DWORD dw = sizeof(*pdwModeValue);
|
||||
if (RegQueryValueEx(
|
||||
hkey,
|
||||
pszModeValueName,
|
||||
NULL,
|
||||
NULL,
|
||||
LPBYTE(pdwModeValue),
|
||||
&dw) != ERROR_SUCCESS)
|
||||
{
|
||||
*pdwModeValue = dwDefaultModeValue;
|
||||
RegSetValueEx(
|
||||
hkey,
|
||||
pszModeValueName,
|
||||
NULL,
|
||||
REG_DWORD,
|
||||
LPBYTE(pdwModeValue),
|
||||
sizeof(*pdwModeValue));
|
||||
}
|
||||
|
||||
dw = MAX_PATH;
|
||||
if (RegQueryValueEx(
|
||||
hkey,
|
||||
pszFileValueName,
|
||||
NULL,
|
||||
NULL,
|
||||
LPBYTE(pszFileValue),
|
||||
&dw) != ERROR_SUCCESS)
|
||||
{
|
||||
_tcscpy(pszFileValue, pszDefaultFileValue);
|
||||
RegSetValueEx(
|
||||
hkey,
|
||||
pszFileValueName,
|
||||
NULL,
|
||||
REG_SZ,
|
||||
LPBYTE(pszFileValue),
|
||||
MAX_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Enter(int reportType, DWORD &reportMode, TCHAR * pszFile)
|
||||
{
|
||||
if (reportMode != 0)
|
||||
{
|
||||
// We'll hold the mutex, until the caller also calls Leave
|
||||
if (m_mutex == NULL)
|
||||
{
|
||||
m_mutex = CreateMutex(NULL, FALSE, _T("SpDebug"));
|
||||
}
|
||||
WaitForSingleObject(m_mutex, INFINITE);
|
||||
|
||||
m_reportType = reportType;
|
||||
m_reportModePrev = _CrtSetReportMode(reportType, reportMode);
|
||||
if (reportMode & _CRTDBG_MODE_FILE)
|
||||
{
|
||||
HANDLE hfile = CreateFile(
|
||||
pszFile,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_ALWAYS,
|
||||
0,
|
||||
NULL);
|
||||
SetFilePointer(hfile, 0, NULL, FILE_END);
|
||||
m_hfilePrev = (_HFILE)_CrtSetReportFile(reportType, (_HFILE)hfile);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL Leave()
|
||||
{
|
||||
int reportMode = _CrtSetReportMode(m_reportType, m_reportModePrev);
|
||||
if (reportMode & _CRTDBG_MODE_FILE)
|
||||
{
|
||||
CloseHandle((_HFILE)_CrtSetReportFile(m_reportType, (_HFILE)m_hfilePrev));
|
||||
}
|
||||
|
||||
ReleaseMutex(m_mutex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
HANDLE m_mutex;
|
||||
|
||||
int m_reportType;
|
||||
int m_reportModePrev;
|
||||
_HFILE m_hfilePrev;
|
||||
|
||||
BOOL m_fAssertSettingsReReadEachTime;
|
||||
|
||||
DWORD m_FuncTraceMode;
|
||||
TCHAR m_szFuncTraceFile[MAX_PATH + 1];
|
||||
DWORD m_ParamInfoMode;
|
||||
TCHAR m_szParamInfoFile[MAX_PATH + 1];
|
||||
DWORD m_DumpInfoMode;
|
||||
TCHAR m_szDumpInfoFile[MAX_PATH + 1];
|
||||
DWORD m_AssertMode;
|
||||
TCHAR m_szAssertFile[MAX_PATH + 1];
|
||||
DWORD m_HRFailMode;
|
||||
TCHAR m_szHRFailFile[MAX_PATH + 1];
|
||||
|
||||
BOOL m_fDebugServerOnStart;
|
||||
BOOL m_fDebugClientOnStart;
|
||||
};
|
||||
|
||||
inline CSpDebug *PSpDebug()
|
||||
{
|
||||
static CSpDebug debug;
|
||||
return &debug;
|
||||
}
|
||||
|
||||
class CSpFuncTrace
|
||||
{
|
||||
public:
|
||||
|
||||
CSpFuncTrace(PCHAR pFuncName)
|
||||
{
|
||||
m_pFuncName = pFuncName;
|
||||
if (PSpDebug()->FuncTrace())
|
||||
{
|
||||
_RPT1( _CRT_WARN, "\nEntering Function: %s\n", m_pFuncName );
|
||||
PSpDebug()->FuncTrace(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
~CSpFuncTrace()
|
||||
{
|
||||
if (PSpDebug()->FuncTrace())
|
||||
{
|
||||
_RPT1( _CRT_WARN, "Leaving Function: %s\n", m_pFuncName );
|
||||
PSpDebug()->FuncTrace(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PCHAR m_pFuncName;
|
||||
};
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
//=== User macros ==============================================================
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#define SPDBG_FUNC(name) \
|
||||
CSpFuncTrace functrace(name)
|
||||
|
||||
#if defined(ASSERT_WITH_STACK) && !defined(_WIN64)
|
||||
#define SPDBG_REPORT_ON_FAIL(hr) \
|
||||
do \
|
||||
{ \
|
||||
HRESULT _hr = (hr); \
|
||||
if (FAILED(_hr) && PSpDebug()->HRFail()) \
|
||||
{ \
|
||||
SYSTEMTIME sysTime; \
|
||||
GetLocalTime(&sysTime); \
|
||||
CHAR pszHrWithTime[100]; \
|
||||
sprintf(pszHrWithTime, "%lX\n\n%d.%d.%d %02d:%02d:%02d", \
|
||||
_hr, \
|
||||
sysTime.wMonth,sysTime.wDay,sysTime.wYear, \
|
||||
sysTime.wHour,sysTime.wMinute,sysTime.wSecond); \
|
||||
PCHAR pszStack = \
|
||||
(PCHAR)_alloca( \
|
||||
cchMaxAssertStackLevelStringLen * \
|
||||
cfrMaxAssertStackLevels + 1); \
|
||||
GetStringFromStackLevels(0, 10, pszStack); \
|
||||
_RPT4(_CRT_WARN, \
|
||||
"%s(%d): Failed HR = %s\n\n%s\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
pszHrWithTime, \
|
||||
pszStack); \
|
||||
PSpDebug()->HRFail(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#else // ASSERT_WITH_STACK & !_WIN64
|
||||
#define SPDBG_REPORT_ON_FAIL(hr) \
|
||||
do \
|
||||
{ \
|
||||
HRESULT _hr = (hr); \
|
||||
if (FAILED(_hr) && PSpDebug()->HRFail()) \
|
||||
{ \
|
||||
_RPT3(_CRT_WARN, "%s(%d): Failed HR = %lX\n", __FILE__, __LINE__, (_hr) );\
|
||||
PSpDebug()->HRFail(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif // ASSERT_WITH_STACK
|
||||
|
||||
#define SPDBG_ASSERT(expr) \
|
||||
do \
|
||||
{ \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
if (PSpDebug()->Assert()) \
|
||||
{ \
|
||||
_ASSERTE( expr ); \
|
||||
PSpDebug()->Assert(FALSE); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SPDBG_VERIFY(expr) \
|
||||
SPDBG_ASSERT(expr)
|
||||
|
||||
#define SPDBG_PMSG0(format) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->ParamInfo()) \
|
||||
{ \
|
||||
_RPT0(_CRT_WARN, format); \
|
||||
PSpDebug()->ParamInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_PMSG1(format, arg1) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->ParamInfo()) \
|
||||
{ \
|
||||
_RPT1(_CRT_WARN, format, arg1); \
|
||||
PSpDebug()->ParamInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_PMSG2(format, arg1, arg2) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->ParamInfo()) \
|
||||
{ \
|
||||
_RPT2(_CRT_WARN, format, arg1, arg2); \
|
||||
PSpDebug()->ParamInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_PMSG3(format, arg1, arg2, arg3) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->ParamInfo()) \
|
||||
{ \
|
||||
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
|
||||
PSpDebug()->ParamInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->ParamInfo()) \
|
||||
{ \
|
||||
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
|
||||
PSpDebug()->ParamInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SPDBG_DMSG0(format) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->DumpInfo()) \
|
||||
{ \
|
||||
_RPT0(_CRT_WARN, format); \
|
||||
PSpDebug()->DumpInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_DMSG1(format, arg1) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->DumpInfo()) \
|
||||
{ \
|
||||
_RPT1(_CRT_WARN, format, arg1); \
|
||||
PSpDebug()->DumpInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_DMSG2(format, arg1, arg2) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->DumpInfo()) \
|
||||
{ \
|
||||
_RPT2(_CRT_WARN, format, arg1, arg2); \
|
||||
PSpDebug()->DumpInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_DMSG3(format, arg1, arg2, arg3) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->DumpInfo()) \
|
||||
{ \
|
||||
_RPT3(_CRT_WARN, format, arg1, arg2, arg3); \
|
||||
PSpDebug()->DumpInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4) \
|
||||
do \
|
||||
{ \
|
||||
if (PSpDebug()->DumpInfo()) \
|
||||
{ \
|
||||
_RPT4(_CRT_WARN, format, arg1, arg2, arg3, arg4); \
|
||||
PSpDebug()->DumpInfo(FALSE); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SPDBG_RETURN(hr) \
|
||||
{ \
|
||||
HRESULT __hr = (hr); \
|
||||
if (FAILED(__hr)) \
|
||||
{ \
|
||||
SPDBG_REPORT_ON_FAIL(__hr); \
|
||||
} \
|
||||
return __hr; \
|
||||
}
|
||||
|
||||
#define SPDBG_DEBUG_SERVER_ON_START() \
|
||||
{ \
|
||||
if (PSpDebug()->DebugServerOnStart()) \
|
||||
{ \
|
||||
if (MessageBox( \
|
||||
GetDesktopWindow(), \
|
||||
_T("Attach Debugger to the SAPI Server process?"), \
|
||||
_T("SAPI"), \
|
||||
MB_YESNO) == IDYES) \
|
||||
{ \
|
||||
USES_CONVERSION; \
|
||||
TCHAR szCommand[MAX_PATH + 1]; \
|
||||
wsprintf( \
|
||||
szCommand, \
|
||||
_T("msdev -p %d"), \
|
||||
GetCurrentProcessId()); \
|
||||
system(T2A(szCommand)); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SPDBG_DEBUG_CLIENT_ON_START() \
|
||||
{ \
|
||||
if (PSpDebug()->DebugClientOnStart()) \
|
||||
{ \
|
||||
TCHAR szModule[MAX_PATH + 1]; \
|
||||
szModule[0] = '\0'; \
|
||||
TCHAR * pszSapiServer = \
|
||||
_T("sapisvr.exe"); \
|
||||
GetModuleFileName( \
|
||||
NULL, \
|
||||
szModule, \
|
||||
MAX_PATH); \
|
||||
if ((_tcslen(szModule) <= \
|
||||
_tcslen(pszSapiServer) || \
|
||||
_tcsicmp( \
|
||||
szModule + \
|
||||
_tcslen(szModule) - \
|
||||
_tcslen(pszSapiServer), \
|
||||
pszSapiServer) != 0) && \
|
||||
MessageBox( \
|
||||
GetDesktopWindow(), \
|
||||
_T("Attach Debugger to the SAPI Client process?"), \
|
||||
_T("SAPI"), \
|
||||
MB_YESNO) == IDYES) \
|
||||
{ \
|
||||
USES_CONVERSION; \
|
||||
TCHAR szCommand[MAX_PATH + 1]; \
|
||||
wsprintf( \
|
||||
szCommand, \
|
||||
_T("msdev -p %d"), \
|
||||
GetCurrentProcessId()); \
|
||||
system(T2A(szCommand)); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#else // _DEBUG
|
||||
|
||||
#define SPDBG_FUNC(name)
|
||||
#define SPDBG_REPORT_ON_FAIL(hr)
|
||||
#define SPDBG_ASSERT(expr)
|
||||
#define SPDBG_VERIFY(expr) (expr)
|
||||
#define SPDBG_PMSG0(format)
|
||||
#define SPDBG_PMSG1(format, arg1)
|
||||
#define SPDBG_PMSG2(format, arg1, arg2)
|
||||
#define SPDBG_PMSG3(format, arg1, arg2, arg3)
|
||||
#define SPDBG_PMSG4(format, arg1, arg2, arg3, arg4)
|
||||
#define SPDBG_DMSG0(format)
|
||||
#define SPDBG_DMSG1(format, arg1)
|
||||
#define SPDBG_DMSG2(format, arg1, arg2)
|
||||
#define SPDBG_DMSG3(format, arg1, arg2, arg3)
|
||||
#define SPDBG_DMSG4(format, arg1, arg2, arg3, arg4)
|
||||
#define SPDBG_RETURN(hr) return (hr)
|
||||
#define SPDBG_DEBUG_SERVER_ON_START()
|
||||
#define SPDBG_DEBUG_CLIENT_ON_START()
|
||||
|
||||
#endif // _DEBUG
|
||||
@@ -0,0 +1,559 @@
|
||||
/*******************************************************************************
|
||||
* SPError.h *
|
||||
*-----------*
|
||||
* Description:
|
||||
* This header file contains the custom error codes specific to SAPI5
|
||||
*-------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*******************************************************************************/
|
||||
#ifndef SPError_h
|
||||
#define SPError_h
|
||||
|
||||
#ifndef _WINERROR_
|
||||
#include <winerror.h>
|
||||
#endif
|
||||
|
||||
#define FACILITY_SAPI FACILITY_ITF
|
||||
#define SAPI_ERROR_BASE 0x5000
|
||||
|
||||
#define MAKE_SAPI_HRESULT(sev, err) MAKE_HRESULT(sev, FACILITY_SAPI, err)
|
||||
#define MAKE_SAPI_ERROR(err) MAKE_SAPI_HRESULT(SEVERITY_ERROR, err + SAPI_ERROR_BASE)
|
||||
#define MAKE_SAPI_SCODE(scode) MAKE_SAPI_HRESULT(SEVERITY_SUCCESS, scode + SAPI_ERROR_BASE)
|
||||
|
||||
/*** SPERR_UNINITIALIZED 0x80045001 -2147201023
|
||||
* The object has not been properly initialized.
|
||||
*/
|
||||
#define SPERR_UNINITIALIZED MAKE_SAPI_ERROR(0x001)
|
||||
|
||||
/*** SPERR_ALREADY_INITIALIZED 0x80045002 -2147201022
|
||||
* The object has already been initialized.
|
||||
*/
|
||||
#define SPERR_ALREADY_INITIALIZED MAKE_SAPI_ERROR(0x002)
|
||||
|
||||
/*** SPERR_UNSUPPORTED_FORMAT 0x80045003 -2147201021
|
||||
* The caller has specified an unsupported format.
|
||||
*/
|
||||
#define SPERR_UNSUPPORTED_FORMAT MAKE_SAPI_ERROR(0x003)
|
||||
|
||||
/*** SPERR_INVALID_FLAGS 0x80045004 -2147201020
|
||||
* The caller has specified invalid flags for this operation.
|
||||
*/
|
||||
#define SPERR_INVALID_FLAGS MAKE_SAPI_ERROR(0x004)
|
||||
|
||||
/*** SP_END_OF_STREAM 0x00045005 282629
|
||||
* The operation has reached the end of stream.
|
||||
*/
|
||||
#define SP_END_OF_STREAM MAKE_SAPI_SCODE(0x005)
|
||||
|
||||
/*** SPERR_DEVICE_BUSY 0x80045006 -2147201018
|
||||
* The wave device is busy.
|
||||
*/
|
||||
#define SPERR_DEVICE_BUSY MAKE_SAPI_ERROR(0x006)
|
||||
|
||||
/*** SPERR_DEVICE_NOT_SUPPORTED 0x80045007 -2147201017
|
||||
* The wave device is not supported.
|
||||
*/
|
||||
#define SPERR_DEVICE_NOT_SUPPORTED MAKE_SAPI_ERROR(0x007)
|
||||
|
||||
/*** SPERR_DEVICE_NOT_ENABLED 0x80045008 -2147201016
|
||||
* The wave device is not enabled.
|
||||
*/
|
||||
#define SPERR_DEVICE_NOT_ENABLED MAKE_SAPI_ERROR(0x008)
|
||||
|
||||
/*** SPERR_NO_DRIVER 0x80045009 -2147201015
|
||||
* There is no wave driver installed.
|
||||
*/
|
||||
#define SPERR_NO_DRIVER MAKE_SAPI_ERROR(0x009)
|
||||
|
||||
/*** SPERR_FILEMUSTBEUNICODE 0x8004500a -2147201014
|
||||
* The file must be Unicode.
|
||||
*/
|
||||
#define SPERR_FILE_MUST_BE_UNICODE MAKE_SAPI_ERROR(0x00a)
|
||||
|
||||
/*** SP_INSUFFICIENTDATA 0x0004500b 282635
|
||||
*
|
||||
*/
|
||||
#define SP_INSUFFICIENT_DATA MAKE_SAPI_SCODE(0x00b)
|
||||
|
||||
/*** SPERR_INVALID_PHRASE_ID 0x8004500c -2147201012
|
||||
* The phrase ID specified does not exist or is out of range.
|
||||
*/
|
||||
#define SPERR_INVALID_PHRASE_ID MAKE_SAPI_ERROR(0x00c)
|
||||
|
||||
/*** SPERR_BUFFER_TOO_SMALL 0x8004500d -2147201011
|
||||
* The caller provided a buffer too small to return a result.
|
||||
*/
|
||||
#define SPERR_BUFFER_TOO_SMALL MAKE_SAPI_ERROR(0x00d)
|
||||
|
||||
/*** SPERR_FORMAT_NOT_SPECIFIED 0x8004500e -2147201010
|
||||
* Caller did not specify a format prior to opening a stream.
|
||||
*/
|
||||
#define SPERR_FORMAT_NOT_SPECIFIED MAKE_SAPI_ERROR(0x00e)
|
||||
|
||||
/*** SPERR_AUDIO_STOPPED 0x8004500f -2147201009
|
||||
* This method is deprecated. Use SP_AUDIO_STOPPED instead.
|
||||
*/
|
||||
#define SPERR_AUDIO_STOPPED MAKE_SAPI_ERROR(0x00f)
|
||||
|
||||
/*** SP_AUDIO_PAUSED 0x00045010 282640
|
||||
* This will be returned only on input (read) streams when the stream is paused. Reads on
|
||||
* paused streams will not block, and this return code indicates that all of the data has been
|
||||
* removed from the stream.
|
||||
*/
|
||||
#define SP_AUDIO_PAUSED MAKE_SAPI_SCODE(0x010)
|
||||
|
||||
/*** SPERR_RULE_NOT_FOUND 0x80045011 -2147201007
|
||||
* Invalid rule name passed to ActivateGrammar.
|
||||
*/
|
||||
#define SPERR_RULE_NOT_FOUND MAKE_SAPI_ERROR(0x011)
|
||||
|
||||
/*** SPERR_TTS_ENGINE_EXCEPTION 0x80045012 -2147201006
|
||||
* An exception was raised during a call to the current TTS driver.
|
||||
*/
|
||||
#define SPERR_TTS_ENGINE_EXCEPTION MAKE_SAPI_ERROR(0x012)
|
||||
|
||||
/*** SPERR_TTS_NLP_EXCEPTION 0x80045013 -2147201005
|
||||
* An exception was raised during a call to an application sentence filter.
|
||||
*/
|
||||
#define SPERR_TTS_NLP_EXCEPTION MAKE_SAPI_ERROR(0x013)
|
||||
|
||||
/*** SPERR_ENGINE_BUSY 0x80045014 -2147201004
|
||||
* In speech recognition, the current method can not be performed while
|
||||
* a grammar rule is active.
|
||||
*/
|
||||
#define SPERR_ENGINE_BUSY MAKE_SAPI_ERROR(0x014)
|
||||
|
||||
/*** SP_AUDIO_CONVERSION_ENABLED 0x00045015 282645
|
||||
* The operation was successful, but only with automatic stream format conversion.
|
||||
*/
|
||||
#define SP_AUDIO_CONVERSION_ENABLED MAKE_SAPI_SCODE(0x015)
|
||||
|
||||
/*** SP_NO_HYPOTHESIS_AVAILABLE 0x00045016 282646
|
||||
* There is currently no hypothesis recognition available.
|
||||
*/
|
||||
#define SP_NO_HYPOTHESIS_AVAILABLE MAKE_SAPI_SCODE(0x016)
|
||||
|
||||
/*** SPERR_CANT_CREATE 0x80045017 -2147201001
|
||||
* Can not create a new object instance for the specified object category.
|
||||
*/
|
||||
#define SPERR_CANT_CREATE MAKE_SAPI_ERROR(0x017)
|
||||
|
||||
/*** SP_ALREADY_IN_LEX 0x00045018 282648
|
||||
* The word, pronunciation, or POS pair being added is already in lexicon.
|
||||
*/
|
||||
#define SP_ALREADY_IN_LEX MAKE_SAPI_SCODE(0x018)
|
||||
|
||||
/*** SPERR_NOT_IN_LEX 0x80045019 -2147200999
|
||||
* The word does not exist in the lexicon.
|
||||
*/
|
||||
#define SPERR_NOT_IN_LEX MAKE_SAPI_ERROR(0x019)
|
||||
|
||||
/*** SP_LEX_NOTHING_TO_SYNC 0x0004501a 282650
|
||||
* The client is currently synced with the lexicon.
|
||||
*/
|
||||
#define SP_LEX_NOTHING_TO_SYNC MAKE_SAPI_SCODE(0x01a)
|
||||
|
||||
/*** SPERR_LEX_VERY_OUT_OF_SYNC 0x8004501b -2147200997
|
||||
* The client is excessively out of sync with the lexicon. Mismatches may not be incrementally sync'd.
|
||||
*/
|
||||
#define SPERR_LEX_VERY_OUT_OF_SYNC MAKE_SAPI_ERROR(0x01b)
|
||||
|
||||
/*** SPERR_UNDEFINED_FORWARD_RULE_REF 0x8004501c -2147200996
|
||||
* A rule reference in a grammar was made to a named rule that was never defined.
|
||||
*/
|
||||
#define SPERR_UNDEFINED_FORWARD_RULE_REF MAKE_SAPI_ERROR(0x01c)
|
||||
|
||||
/*** SPERR_EMPTY_RULE 0x8004501d -2147200995
|
||||
* A non-dynamic grammar rule that has no body.
|
||||
*/
|
||||
#define SPERR_EMPTY_RULE MAKE_SAPI_ERROR(0x01d)
|
||||
|
||||
/*** SPERR_GRAMMAR_COMPILER_INTERNAL_ERROR 0x8004501e -2147200994
|
||||
* The grammar compiler failed due to an internal state error.
|
||||
*/
|
||||
#define SPERR_GRAMMAR_COMPILER_INTERNAL_ERROR MAKE_SAPI_ERROR(0x01e)
|
||||
|
||||
|
||||
/*** SPERR_RULE_NOT_DYNAMIC 0x8004501f -2147200993
|
||||
* An attempt was made to modify a non-dynamic rule.
|
||||
*/
|
||||
#define SPERR_RULE_NOT_DYNAMIC MAKE_SAPI_ERROR(0x01f)
|
||||
|
||||
/*** SPERR_DUPLICATE_RULE_NAME 0x80045020 -2147200992
|
||||
* A rule name was duplicated.
|
||||
*/
|
||||
#define SPERR_DUPLICATE_RULE_NAME MAKE_SAPI_ERROR(0x020)
|
||||
|
||||
/*** SPERR_DUPLICATE_RESOURCE_NAME 0x80045021 -2147200991
|
||||
* A resource name was duplicated for a given rule.
|
||||
*/
|
||||
#define SPERR_DUPLICATE_RESOURCE_NAME MAKE_SAPI_ERROR(0x021)
|
||||
|
||||
|
||||
/*** SPERR_TOO_MANY_GRAMMARS 0x80045022 -2147200990
|
||||
* Too many grammars have been loaded.
|
||||
*/
|
||||
#define SPERR_TOO_MANY_GRAMMARS MAKE_SAPI_ERROR(0x022)
|
||||
|
||||
/*** SPERR_CIRCULAR_REFERENCE 0x80045023 -2147200989
|
||||
* Circular reference in import rules of grammars.
|
||||
*/
|
||||
#define SPERR_CIRCULAR_REFERENCE MAKE_SAPI_ERROR(0x023)
|
||||
|
||||
/*** SPERR_INVALID_IMPORT 0x80045024 -2147200988
|
||||
* A rule reference to an imported grammar that could not be resolved.
|
||||
*/
|
||||
#define SPERR_INVALID_IMPORT MAKE_SAPI_ERROR(0x024)
|
||||
|
||||
/*** SPERR_INVALID_WAV_FILE 0x80045025 -2147200987
|
||||
* The format of the WAV file is not supported.
|
||||
*/
|
||||
#define SPERR_INVALID_WAV_FILE MAKE_SAPI_ERROR(0x025)
|
||||
|
||||
/*** SP_REQUEST_PENDING 0x00045026 282662
|
||||
* This success code indicates that an SR method called with the SPRIF_ASYNC flag is
|
||||
* being processed. When it has finished processing, an SPFEI_ASYNC_COMPLETED event will be generated.
|
||||
*/
|
||||
#define SP_REQUEST_PENDING MAKE_SAPI_SCODE(0x026)
|
||||
|
||||
/*** SPERR_ALL_WORDS_OPTIONAL 0x80045027 -2147200985
|
||||
* A grammar rule was defined with a null path through the rule. That is, it is possible
|
||||
* to satisfy the rule conditions with no words.
|
||||
*/
|
||||
#define SPERR_ALL_WORDS_OPTIONAL MAKE_SAPI_ERROR(0x027)
|
||||
|
||||
/*** SPERR_INSTANCE_CHANGE_INVALID 0x80045028 -2147200984
|
||||
* It is not possible to change the current engine or input. This occurs in the
|
||||
* following cases:
|
||||
*
|
||||
* 1) SelectEngine called while a recognition context exists, or
|
||||
* 2) SetInput called in the shared instance case.
|
||||
*/
|
||||
#define SPERR_INSTANCE_CHANGE_INVALID MAKE_SAPI_ERROR(0x028)
|
||||
|
||||
/*** SPERR_RULE_NAME_ID_CONFLICT 0x80045029 -2147200983
|
||||
* A rule exists with matching IDs (names) but different names (IDs).
|
||||
*/
|
||||
#define SPERR_RULE_NAME_ID_CONFLICT MAKE_SAPI_ERROR(0x029)
|
||||
|
||||
/*** SPERR_NO_RULES 0x8004502a -2147200982
|
||||
* A grammar contains no top-level, dynamic, or exported rules. There is no possible
|
||||
* way to activate or otherwise use any rule in this grammar.
|
||||
*/
|
||||
#define SPERR_NO_RULES MAKE_SAPI_ERROR(0x02a)
|
||||
|
||||
/*** SPERR_CIRCULAR_RULE_REF 0x8004502b -2147200981
|
||||
* Rule 'A' refers to a second rule 'B' which, in turn, refers to rule 'A'.
|
||||
*/
|
||||
#define SPERR_CIRCULAR_RULE_REF MAKE_SAPI_ERROR(0x02b)
|
||||
|
||||
/*** SP_NO_PARSE_FOUND 0x0004502c 282668
|
||||
* Parse path cannot be parsed given the currently active rules.
|
||||
*/
|
||||
#define SP_NO_PARSE_FOUND MAKE_SAPI_SCODE(0x02c)
|
||||
|
||||
/*** SPERR_NO_PARSE_FOUND 0x8004502d -2147200979
|
||||
* Parse path cannot be parsed given the currently active rules.
|
||||
*/
|
||||
#define SPERR_INVALID_HANDLE MAKE_SAPI_ERROR(0x02d)
|
||||
|
||||
/*** SPERR_REMOTE_CALL_TIMED_OUT 0x8004502e -2147200978
|
||||
* A marshaled remote call failed to respond.
|
||||
*/
|
||||
#define SPERR_REMOTE_CALL_TIMED_OUT MAKE_SAPI_ERROR(0x02e)
|
||||
|
||||
/*** SPERR_AUDIO_BUFFER_OVERFLOW 0x8004502f -2147200977
|
||||
* This will only be returned on input (read) streams when the stream is paused because
|
||||
* the SR driver has not retrieved data recently.
|
||||
*/
|
||||
#define SPERR_AUDIO_BUFFER_OVERFLOW MAKE_SAPI_ERROR(0x02f)
|
||||
|
||||
|
||||
/*** SPERR_NO_AUDIO_DATA 0x80045030 -2147200976
|
||||
* The result does not contain any audio, nor does the portion of the element chain of the result
|
||||
* contain any audio.
|
||||
*/
|
||||
#define SPERR_NO_AUDIO_DATA MAKE_SAPI_ERROR(0x030)
|
||||
|
||||
/*** SPERR_DEAD_ALTERNATE 0x80045031 -2147200975
|
||||
* This alternate is no longer a valid alternate to the result it was obtained from.
|
||||
* Returned from ISpPhraseAlt methods.
|
||||
*/
|
||||
#define SPERR_DEAD_ALTERNATE MAKE_SAPI_ERROR(0x031)
|
||||
|
||||
/*** SPERR_HIGH_LOW_CONFIDENCE 0x80045032 -2147200974
|
||||
* The result does not contain any audio, nor does the portion of the element chain of the result
|
||||
* contain any audio. Returned from ISpResult::GetAudio and ISpResult::SpeakAudio.
|
||||
*/
|
||||
#define SPERR_HIGH_LOW_CONFIDENCE MAKE_SAPI_ERROR(0x032)
|
||||
|
||||
/*** SPERR_INVALID_FORMAT_STRING 0x80045033 -2147200973
|
||||
* The XML format string for this RULEREF is invalid, e.g. not a GUID or REFCLSID.
|
||||
*/
|
||||
#define SPERR_INVALID_FORMAT_STRING MAKE_SAPI_ERROR(0x033)
|
||||
|
||||
/*** SP_UNSUPPORTED_ON_STREAM_INPUT 0x00045034 282676
|
||||
* The operation is not supported for stream input.
|
||||
*/
|
||||
#define SP_UNSUPPORTED_ON_STREAM_INPUT MAKE_SAPI_SCODE(0x034)
|
||||
|
||||
/*** SPERR_APPLEX_READ_ONLY 0x80045035 -2147200971
|
||||
* The operation is invalid for all but newly created application lexicons.
|
||||
*/
|
||||
#define SPERR_APPLEX_READ_ONLY MAKE_SAPI_ERROR(0x035)
|
||||
|
||||
/*** SPERR_NO_TERMINATING_RULE_PATH 0x80045036 -2147200970
|
||||
*
|
||||
*/
|
||||
|
||||
#define SPERR_NO_TERMINATING_RULE_PATH MAKE_SAPI_ERROR(0x036)
|
||||
|
||||
/*** SP_WORD_EXISTS_WITHOUT_PRONUNCIATION 0x00045037 282679
|
||||
* The word exists but without pronunciation.
|
||||
*/
|
||||
#define SP_WORD_EXISTS_WITHOUT_PRONUNCIATION MAKE_SAPI_SCODE(0x037)
|
||||
|
||||
/*** SPERR_STREAM_CLOSED 0x80045038 -2147200968
|
||||
* An operation was attempted on a stream object that has been closed.
|
||||
*/
|
||||
#define SPERR_STREAM_CLOSED MAKE_SAPI_ERROR(0x038)
|
||||
|
||||
// --- The following error codes are taken directly from WIN32 ---
|
||||
|
||||
/*** SPERR_NO_MORE_ITEMS 0x80045039 -2147200967
|
||||
* When enumerating items, the requested index is greater than the count of items.
|
||||
*/
|
||||
#define SPERR_NO_MORE_ITEMS MAKE_SAPI_ERROR(0x039)
|
||||
|
||||
/*** SPERR_NOT_FOUND 0x8004503a -2147200966
|
||||
* The requested data item (data key, value, etc.) was not found.
|
||||
*/
|
||||
#define SPERR_NOT_FOUND MAKE_SAPI_ERROR(0x03a)
|
||||
|
||||
/*** SPERR_INVALID_AUDIO_STATE 0x8004503b -2147200965
|
||||
* Audio state passed to SetState() is invalid.
|
||||
*/
|
||||
#define SPERR_INVALID_AUDIO_STATE MAKE_SAPI_ERROR(0x03b)
|
||||
|
||||
/*** SPERR_GENERIC_MMSYS_ERROR 0x8004503c -2147200964
|
||||
* A generic MMSYS error not caught by _MMRESULT_TO_HRESULT.
|
||||
*/
|
||||
#define SPERR_GENERIC_MMSYS_ERROR MAKE_SAPI_ERROR(0x03c)
|
||||
|
||||
/*** SPERR_MARSHALER_EXCEPTION 0x8004503d -2147200963
|
||||
* An exception was raised during a call to the marshaling code.
|
||||
*/
|
||||
#define SPERR_MARSHALER_EXCEPTION MAKE_SAPI_ERROR(0x03d)
|
||||
|
||||
/*** SPERR_NOT_DYNAMIC_GRAMMAR 0x8004503e -2147200962
|
||||
* Attempt was made to manipulate a non-dynamic grammar.
|
||||
*/
|
||||
#define SPERR_NOT_DYNAMIC_GRAMMAR MAKE_SAPI_ERROR(0x03e)
|
||||
|
||||
/*** SPERR_AMBIGUOUS_PROPERTY 0x8004503f -2147200961
|
||||
* Cannot add ambiguous property.
|
||||
*/
|
||||
#define SPERR_AMBIGUOUS_PROPERTY MAKE_SAPI_ERROR(0x03f)
|
||||
|
||||
/*** SPERR_INVALID_REGISTRY_KEY 0x80045040 -2147200960
|
||||
* The key specified is invalid.
|
||||
*/
|
||||
#define SPERR_INVALID_REGISTRY_KEY MAKE_SAPI_ERROR(0x040)
|
||||
|
||||
/*** SPERR_INVALID_TOKEN_ID 0x80045041 -2147200959
|
||||
* The token specified is invalid.
|
||||
*/
|
||||
#define SPERR_INVALID_TOKEN_ID MAKE_SAPI_ERROR(0x041)
|
||||
|
||||
/*** SPERR_XML_BAD_SYNTAX 0x80045042 -2147200958
|
||||
* The xml parser failed due to bad syntax.
|
||||
*/
|
||||
#define SPERR_XML_BAD_SYNTAX MAKE_SAPI_ERROR(0x042)
|
||||
|
||||
/*** SPERR_XML_RESOURCE_NOT_FOUND 0x80045043 -2147200957
|
||||
* The xml parser failed to load a required resource (e.g., voice, phoneconverter, etc.).
|
||||
*/
|
||||
#define SPERR_XML_RESOURCE_NOT_FOUND MAKE_SAPI_ERROR(0x043)
|
||||
|
||||
/*** SPERR_TOKEN_IN_USE 0x80045044 -2147200956
|
||||
* Attempted to remove registry data from a token that is already in use elsewhere.
|
||||
*/
|
||||
#define SPERR_TOKEN_IN_USE MAKE_SAPI_ERROR(0x044)
|
||||
|
||||
/*** SPERR_TOKEN_DELETED 0x80045045 -2147200955
|
||||
* Attempted to perform an action on an object token that has had associated registry key deleted.
|
||||
*/
|
||||
#define SPERR_TOKEN_DELETED MAKE_SAPI_ERROR(0x045)
|
||||
|
||||
/*** SPERR_MULTI_LINGUAL_NOT_SUPPORTED 0x80045046 -2147200954
|
||||
* The selected voice was registered as multi-lingual. SAPI does not support multi-lingual registration.
|
||||
*/
|
||||
#define SPERR_MULTI_LINGUAL_NOT_SUPPORTED MAKE_SAPI_ERROR(0x046)
|
||||
|
||||
/*** SPERR_EXPORT_DYNAMIC_RULE 0x80045047 -2147200953
|
||||
* Exported rules cannot refer directly or indirectly to a dynamic rule.
|
||||
*/
|
||||
#define SPERR_EXPORT_DYNAMIC_RULE MAKE_SAPI_ERROR(0x047)
|
||||
|
||||
/*** SPERR_STGF_ERROR 0x80045048 -2147200952
|
||||
* Error parsing the SAPI Text Grammar Format (XML grammar).
|
||||
*/
|
||||
#define SPERR_STGF_ERROR MAKE_SAPI_ERROR(0x048)
|
||||
|
||||
/*** SPERR_WORDFORMAT_ERROR 0x80045049 -2147200951
|
||||
* Incorrect word format, probably due to incorrect pronunciation string.
|
||||
*/
|
||||
#define SPERR_WORDFORMAT_ERROR MAKE_SAPI_ERROR(0x049)
|
||||
|
||||
/*** SPERR_STREAM_NOT_ACTIVE 0x8004504a -2147200950
|
||||
* Methods associated with active audio stream cannot be called unless stream is active.
|
||||
*/
|
||||
#define SPERR_STREAM_NOT_ACTIVE MAKE_SAPI_ERROR(0x04a)
|
||||
|
||||
/*** SPERR_ENGINE_RESPONSE_INVALID 0x8004504b -2147200949
|
||||
* Arguments or data supplied by the engine are in an invalid format or are inconsistent.
|
||||
*/
|
||||
#define SPERR_ENGINE_RESPONSE_INVALID MAKE_SAPI_ERROR(0x04b)
|
||||
|
||||
/*** SPERR_SR_ENGINE_EXCEPTION 0x8004504c -2147200948
|
||||
* An exception was raised during a call to the current SR engine.
|
||||
*/
|
||||
#define SPERR_SR_ENGINE_EXCEPTION MAKE_SAPI_ERROR(0x04c)
|
||||
|
||||
/*** SPERR_STREAM_POS_INVALID 0x8004504d -2147200947
|
||||
* Stream position information supplied from engine is inconsistent.
|
||||
*/
|
||||
#define SPERR_STREAM_POS_INVALID MAKE_SAPI_ERROR(0x04d)
|
||||
|
||||
/*** SP_RECOGNIZER_INACTIVE 0x0004504e 282702
|
||||
* Operation could not be completed because the recognizer is inactive. It is inactive either
|
||||
* because the recognition state is currently inactive or because no rules are active .
|
||||
*/
|
||||
#define SP_RECOGNIZER_INACTIVE MAKE_SAPI_SCODE(0x04e)
|
||||
|
||||
/*** SPERR_REMOTE_CALL_ON_WRONG_THREAD 0x8004504f -2147200945
|
||||
* When making a remote call to the server, the call was made on the wrong thread.
|
||||
*/
|
||||
#define SPERR_REMOTE_CALL_ON_WRONG_THREAD MAKE_SAPI_ERROR(0x04f)
|
||||
|
||||
/*** SPERR_REMOTE_PROCESS_TERMINATED 0x80045050 -2147200944
|
||||
* The remote process terminated unexpectedly.
|
||||
*/
|
||||
#define SPERR_REMOTE_PROCESS_TERMINATED MAKE_SAPI_ERROR(0x050)
|
||||
|
||||
/*** SPERR_REMOTE_PROCESS_ALREADY_RUNNING 0x80045051 -2147200943
|
||||
* The remote process is already running; it cannot be started a second time.
|
||||
*/
|
||||
#define SPERR_REMOTE_PROCESS_ALREADY_RUNNING MAKE_SAPI_ERROR(0x051)
|
||||
|
||||
/*** SPERR_LANGID_MISMATCH 0x80045052 -2147200942
|
||||
* An attempt to load a CFG grammar with a LANGID different than other loaded grammars.
|
||||
*/
|
||||
#define SPERR_LANGID_MISMATCH MAKE_SAPI_ERROR(0x052)
|
||||
|
||||
/*** SP_PARTIAL_PARSE_FOUND 0x00045053 282707
|
||||
* A grammar-ending parse has been found that does not use all available words.
|
||||
*/
|
||||
#define SP_PARTIAL_PARSE_FOUND MAKE_SAPI_SCODE(0x053)
|
||||
|
||||
/*** SPERR_NOT_TOPLEVEL_RULE 0x80045054 -2147200940
|
||||
* An attempt to deactivate or activate a non-toplevel rule.
|
||||
*/
|
||||
#define SPERR_NOT_TOPLEVEL_RULE MAKE_SAPI_ERROR(0x054)
|
||||
|
||||
/*** SP_NO_RULE_ACTIVE 0x00045055 282709
|
||||
* An attempt to parse when no rule was active.
|
||||
*/
|
||||
#define SP_NO_RULE_ACTIVE MAKE_SAPI_SCODE(0x055)
|
||||
|
||||
/*** SPERR_LEX_REQUIRES_COOKIE 0x80045056 -2147200938
|
||||
* An attempt to ask a container lexicon for all words at once.
|
||||
*/
|
||||
#define SPERR_LEX_REQUIRES_COOKIE MAKE_SAPI_ERROR(0x056)
|
||||
|
||||
/*** SP_STREAM_UNINITIALIZED 0x00045057 282711
|
||||
* An attempt to activate a rule/dictation/etc without calling SetInput
|
||||
* first in the inproc case.
|
||||
*/
|
||||
#define SP_STREAM_UNINITIALIZED MAKE_SAPI_SCODE(0x057)
|
||||
|
||||
|
||||
// Error x058 is not used in SAPI 5.0
|
||||
|
||||
|
||||
/*** SPERR_UNSUPPORTED_LANG 0x80045059 -2147200935
|
||||
* The requested language is not supported.
|
||||
*/
|
||||
#define SPERR_UNSUPPORTED_LANG MAKE_SAPI_ERROR(0x059)
|
||||
|
||||
/*** SPERR_VOICE_PAUSED 0x8004505a -2147200934
|
||||
* The operation cannot be performed because the voice is currently paused.
|
||||
*/
|
||||
#define SPERR_VOICE_PAUSED MAKE_SAPI_ERROR(0x05a)
|
||||
|
||||
/*** SPERR_AUDIO_BUFFER_UNDERFLOW 0x8004505b -2147200933
|
||||
* This will only be returned on input (read) streams when the real time audio device
|
||||
* stops returning data for a long period of time.
|
||||
*/
|
||||
#define SPERR_AUDIO_BUFFER_UNDERFLOW MAKE_SAPI_ERROR(0x05b)
|
||||
|
||||
/*** SPERR_AUDIO_STOPPED_UNEXPECTEDLY 0x8004505c -2147200932
|
||||
* An audio device stopped returning data from the Read() method even though it was in
|
||||
* the run state. This error is only returned in the END_SR_STREAM event.
|
||||
*/
|
||||
#define SPERR_AUDIO_STOPPED_UNEXPECTEDLY MAKE_SAPI_ERROR(0x05c)
|
||||
|
||||
/*** SPERR_NO_WORD_PRONUNCIATION 0x8004505d -2147200931
|
||||
* The SR engine is unable to add this word to a grammar. The application may need to supply
|
||||
* an explicit pronunciation for this word.
|
||||
*/
|
||||
#define SPERR_NO_WORD_PRONUNCIATION MAKE_SAPI_ERROR(0x05d)
|
||||
|
||||
/*** SPERR_ALTERNATES_WOULD_BE_INCONSISTENT 0x8004505e -2147200930
|
||||
* An attempt to call ScaleAudio on a recognition result having previously
|
||||
* called GetAlternates. Allowing the call to succeed would result in
|
||||
* the previously created alternates located in incorrect audio stream positions.
|
||||
*/
|
||||
#define SPERR_ALTERNATES_WOULD_BE_INCONSISTENT MAKE_SAPI_ERROR(0x05e)
|
||||
|
||||
/*** SPERR_NOT_SUPPORTED_FOR_SHARED_RECOGNIZER 0x8004505f -2147200929
|
||||
* The method called is not supported for the shared recognizer.
|
||||
* For example, ISpRecognizer::GetInputStream().
|
||||
*/
|
||||
#define SPERR_NOT_SUPPORTED_FOR_SHARED_RECOGNIZER MAKE_SAPI_ERROR(0x05f)
|
||||
|
||||
/*** SPERR_TIMEOUT 0x80045060 -2147200928
|
||||
* A task could not complete because the SR engine had timed out.
|
||||
*/
|
||||
#define SPERR_TIMEOUT MAKE_SAPI_ERROR(0x060)
|
||||
|
||||
|
||||
/*** SPERR_REENTER_SYNCHRONIZE 0x80045061 -2147200927
|
||||
* A SR engine called synchronize while inside of a synchronize call.
|
||||
*/
|
||||
#define SPERR_REENTER_SYNCHRONIZE MAKE_SAPI_ERROR(0x061)
|
||||
|
||||
/*** SPERR_STATE_WITH_NO_ARCS 0x80045062 -2147200926
|
||||
* The grammar contains a node no arcs.
|
||||
*/
|
||||
#define SPERR_STATE_WITH_NO_ARCS MAKE_SAPI_ERROR(0x062)
|
||||
|
||||
/*** SPERR_NOT_ACTIVE_SESSION 0x80045063 -2147200925
|
||||
* Neither audio output and input is supported for non-active console sessions.
|
||||
*/
|
||||
#define SPERR_NOT_ACTIVE_SESSION MAKE_SAPI_ERROR(0x063)
|
||||
|
||||
/*** SPERR_ALREADY_DELETED 0x80045064 -2147200924
|
||||
* The object is a stale reference and is invalid to use.
|
||||
* For example having a ISpeechGrammarRule object reference and then calling
|
||||
* ISpeechRecoGrammar::Reset() will cause the rule object to be invalidated.
|
||||
* Calling any methods after this will result in this error.
|
||||
*/
|
||||
#define SPERR_ALREADY_DELETED MAKE_SAPI_ERROR(0x064)
|
||||
|
||||
/*** SP_AUDIO_STOPPED 0x00045065 282725
|
||||
* This can be returned from Read or Write calls audio streams when the stream is stopped.
|
||||
*/
|
||||
#define SP_AUDIO_STOPPED MAKE_SAPI_SCODE(0x065)
|
||||
|
||||
#endif //--- This must be the last line in the file
|
||||
@@ -0,0 +1,605 @@
|
||||
/*******************************************************************************
|
||||
* SPEventQ.h *
|
||||
*------------*
|
||||
* Description:
|
||||
* This is the header file for the SAPI5 event queue implementation.
|
||||
*-------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*******************************************************************************/
|
||||
#ifndef SPEventQ_h
|
||||
#define SPEventQ_h
|
||||
|
||||
#ifndef SPHelper_h
|
||||
#include <SPHelper.h>
|
||||
#endif
|
||||
|
||||
#ifndef SPCollec_h
|
||||
#include <SPCollec.h>
|
||||
#endif
|
||||
|
||||
//=== Inline helpers for copying and deleting events ============================
|
||||
|
||||
|
||||
//=== Class definition ==========================================================
|
||||
|
||||
class CSpEventNode : public CSpEvent
|
||||
{
|
||||
public:
|
||||
CSpEventNode * m_pNext;
|
||||
static LONG Compare(const CSpEventNode * p1, const CSpEventNode *p2)
|
||||
{
|
||||
// Assumes offsets DO or DO NOT reset when stream number changes
|
||||
if (p1->ulStreamNum < p2->ulStreamNum)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (p1->ulStreamNum > p2->ulStreamNum)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (p1->ullAudioStreamOffset < p2->ullAudioStreamOffset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (p1->ullAudioStreamOffset > p2->ullAudioStreamOffset)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef CSpBasicQueue<CSpEventNode, TRUE, TRUE> CSpEventList;
|
||||
|
||||
#define DECLARE_SPNOTIFYSOURCE_METHODS(T) \
|
||||
STDMETHODIMP SetNotifySink(ISpNotifySink * pNotifySink) \
|
||||
{ return T._SetNotifySink(pNotifySink); } \
|
||||
STDMETHODIMP SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) \
|
||||
{ return T._SetNotifyWindowMessage(hWnd, Msg, wParam, lParam); } \
|
||||
STDMETHODIMP SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam) \
|
||||
{ return T._SetNotifyCallbackFunction(pfnCallback, wParam, lParam); } \
|
||||
STDMETHODIMP SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam) \
|
||||
{ return T._SetNotifyCallbackInterface(pSpCallback, wParam, lParam); } \
|
||||
STDMETHODIMP SetNotifyWin32Event() \
|
||||
{ return T._SetNotifyWin32Event(); } \
|
||||
STDMETHODIMP WaitForNotifyEvent(DWORD dwMilliseconds) \
|
||||
{ return T._WaitForNotifyEvent(dwMilliseconds); } \
|
||||
STDMETHODIMP_(HANDLE) GetNotifyEventHandle() \
|
||||
{ return T._GetNotifyEventHandle(); }
|
||||
|
||||
#define DECLARE_SPEVENTSOURCE_METHODS(T) \
|
||||
DECLARE_SPNOTIFYSOURCE_METHODS(T) \
|
||||
STDMETHODIMP SetInterest(ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest) \
|
||||
{ return T._SetInterest(ullEventInterest, ullQueuedInterest); } \
|
||||
STDMETHODIMP GetEvents(ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched) \
|
||||
{ return T._GetEvents(ulCount, pEventArray, pulFetched); } \
|
||||
STDMETHODIMP GetInfo(SPEVENTSOURCEINFO *pInfo) \
|
||||
{ return T._GetInfo(pInfo); }
|
||||
|
||||
|
||||
|
||||
class CSpEventSource
|
||||
{
|
||||
public:
|
||||
CSpEventSource(CComObjectRootEx<CComMultiThreadModel> * pParent) :
|
||||
m_pParent(pParent)
|
||||
{
|
||||
m_ullEventInterest = 0; m_ullQueuedInterest = 0;
|
||||
m_ulStreamNum = 0;
|
||||
}
|
||||
HRESULT _SetNotifySink(ISpNotifySink * pNotifySink);
|
||||
HRESULT _SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
HRESULT _SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam);
|
||||
HRESULT _SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam);
|
||||
HRESULT _SetNotifyWin32Event();
|
||||
HRESULT _WaitForNotifyEvent(DWORD dwMilliseconds);
|
||||
HANDLE _GetNotifyEventHandle();
|
||||
|
||||
HRESULT _SetInterest(ULONGLONG ullEventInterest , ULONGLONG ullQueuedInterest);
|
||||
HRESULT _GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG * pulFetched );
|
||||
HRESULT _GetInfo(SPEVENTSOURCEINFO *pInfo );
|
||||
|
||||
/*--- Non interface methods ---*/
|
||||
HRESULT _CompleteEvents( ULONGLONG ullPos = 0xFFFFFFFFFFFFFFFF );
|
||||
inline void _MoveAllToFreeList(CSpEventList * pList);
|
||||
inline void _RemoveAllEvents();
|
||||
inline HRESULT _AddEvent(const SPEVENT & Event);
|
||||
inline HRESULT _AddEvents(const SPEVENT* pEventArray, ULONG ulCount);
|
||||
inline HRESULT _DeserializeAndAddEvent(const BYTE * pBuffer, ULONG * pcbUsed);
|
||||
inline HRESULT _GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum);
|
||||
//=== Data members ==============================
|
||||
public:
|
||||
ULONGLONG m_ullEventInterest;
|
||||
ULONGLONG m_ullQueuedInterest;
|
||||
ULONG m_ulStreamNum;
|
||||
CSpEventList m_PendingList;
|
||||
CSpEventList m_CompletedList;
|
||||
CSpEventList m_FreeList;
|
||||
CComPtr<ISpNotifySink> m_cpNotifySink;
|
||||
CComPtr<ISpNotifyTranslator> m_cpEventTranslator; // If non-NULL then Win32 events being used
|
||||
CComObjectRootEx<CComMultiThreadModel> * m_pParent;
|
||||
CComAutoCriticalSection m_NotifyObjChangeCrit; // Critical section used to make sure that
|
||||
// the notify object (m_cpNotifySink) not changed
|
||||
// while waiting on it.
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
//=== Inlines =========================================================
|
||||
//
|
||||
|
||||
//
|
||||
// WARNING: If this logic changes, you will need to change the logic in SetNotifyWin32Event also.
|
||||
//
|
||||
inline HRESULT CSpEventSource::_SetNotifySink(ISpNotifySink * pNotifySink)
|
||||
{
|
||||
if (SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pNotifySink))
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pParent->Lock();
|
||||
m_NotifyObjChangeCrit.Lock();
|
||||
m_cpEventTranslator.Release();
|
||||
m_cpNotifySink = pNotifySink;
|
||||
if (m_cpNotifySink && m_CompletedList.GetHead())
|
||||
{
|
||||
m_cpNotifySink->Notify();
|
||||
}
|
||||
m_NotifyObjChangeCrit.Unlock();
|
||||
m_pParent->Unlock();
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_SetNotifyWindowMessage *
|
||||
*-----------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HRESULT CSpEventSource::_SetNotifyWindowMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
SPDBG_FUNC("CSpEventSource::_SetNotifyWindowMessage");
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr<ISpNotifyTranslator> cpTranslator;
|
||||
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = cpTranslator->InitWindowMessage(hWnd, Msg, wParam, lParam);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _SetNotifySink(cpTranslator);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_SetNotifyCallbackFunction *
|
||||
*--------------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HRESULT CSpEventSource::_SetNotifyCallbackFunction(SPNOTIFYCALLBACK * pfnCallback, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackFunction");
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr<ISpNotifyTranslator> cpTranslator;
|
||||
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = cpTranslator->InitCallback(pfnCallback, wParam, lParam);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _SetNotifySink(cpTranslator);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_SetNotifyCallbackInterface *
|
||||
*---------------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HRESULT CSpEventSource::_SetNotifyCallbackInterface(ISpNotifyCallback * pSpCallback, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
SPDBG_FUNC("CSpEventSource::_SetNotifyCallbackInterface");
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr<ISpNotifyTranslator> cpTranslator;
|
||||
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = cpTranslator->InitSpNotifyCallback(pSpCallback, wParam, lParam);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _SetNotifySink(cpTranslator);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_SetNotifyWin32Event *
|
||||
*--------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HRESULT CSpEventSource::_SetNotifyWin32Event(void)
|
||||
{
|
||||
SPDBG_FUNC("CSpEventSource::_SetNotifyWin32Event");
|
||||
HRESULT hr = S_OK;
|
||||
CComPtr<ISpNotifyTranslator> cpTranslator;
|
||||
hr = cpTranslator.CoCreateInstance(CLSID_SpNotifyTranslator);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = cpTranslator->InitWin32Event(NULL, TRUE);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
//
|
||||
// In this case we do NOT call _SetNotify sink since we want to set the cpEventTranslator
|
||||
//
|
||||
m_pParent->Lock();
|
||||
m_NotifyObjChangeCrit.Lock();
|
||||
m_cpEventTranslator = cpTranslator;
|
||||
m_cpNotifySink = cpTranslator;
|
||||
if (m_cpNotifySink && m_CompletedList.GetHead())
|
||||
{
|
||||
m_cpNotifySink->Notify();
|
||||
}
|
||||
m_NotifyObjChangeCrit.Unlock();
|
||||
m_pParent->Unlock();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_WaitForNotifyEvent *
|
||||
*-------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HRESULT CSpEventSource::_WaitForNotifyEvent(DWORD dwMilliseconds)
|
||||
{
|
||||
SPDBG_FUNC("CSpEventSource::_WaitForNotifyEvent");
|
||||
HRESULT hr = S_OK;
|
||||
m_NotifyObjChangeCrit.Lock();
|
||||
if (m_cpEventTranslator)
|
||||
{
|
||||
hr = m_cpEventTranslator->Wait(dwMilliseconds);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_cpNotifySink)
|
||||
{
|
||||
hr = SPERR_ALREADY_INITIALIZED;
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = _SetNotifyWin32Event();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = m_cpEventTranslator->Wait(dwMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_NotifyObjChangeCrit.Unlock();
|
||||
return hr;
|
||||
}
|
||||
/****************************************************************************
|
||||
* CSpEventSource::_GetNotifyEventHandle *
|
||||
*---------------------------------------*
|
||||
* Description:
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
inline HANDLE CSpEventSource::_GetNotifyEventHandle()
|
||||
{
|
||||
HANDLE h = NULL;
|
||||
SPDBG_FUNC("CSpEventSource::_GetNotifyEventHandle");
|
||||
m_NotifyObjChangeCrit.Lock();
|
||||
if (!m_cpNotifySink)
|
||||
{
|
||||
_SetNotifyWin32Event();
|
||||
}
|
||||
if (m_cpEventTranslator)
|
||||
{
|
||||
h = m_cpEventTranslator->GetEventHandle();
|
||||
}
|
||||
m_NotifyObjChangeCrit.Unlock();
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
inline HRESULT CSpEventSource::_SetInterest( ULONGLONG ullEventInterest, ULONGLONG ullQueuedInterest )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
m_pParent->Lock();
|
||||
|
||||
if(ullEventInterest && SPFEI_FLAGCHECK != (ullEventInterest & SPFEI_FLAGCHECK))
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else if(ullQueuedInterest && SPFEI_FLAGCHECK != (ullQueuedInterest & SPFEI_FLAGCHECK))
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else if ((ullQueuedInterest | ullEventInterest) != ullEventInterest)
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ullEventInterest = ullEventInterest;
|
||||
m_ullQueuedInterest = ullQueuedInterest;
|
||||
}
|
||||
m_pParent->Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Same as AddEvents except: No param validation, and caller must take the critical section
|
||||
// prior to calling.
|
||||
//
|
||||
inline HRESULT CSpEventSource::_AddEvents( const SPEVENT* pEventArray, ULONG ulCount )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
for( ULONG i = 0; i < ulCount && SUCCEEDED(hr = _AddEvent(pEventArray[i])); ++i ) {}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT CSpEventSource::_AddEvent(const SPEVENT & Event)
|
||||
{
|
||||
SPDBG_ASSERT(Event.eEventId < 64);
|
||||
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_UNDEFINED ||
|
||||
Event.elParamType == SPET_LPARAM_IS_TOKEN ||
|
||||
Event.elParamType == SPET_LPARAM_IS_OBJECT ||
|
||||
Event.elParamType == SPET_LPARAM_IS_POINTER ||
|
||||
Event.elParamType == SPET_LPARAM_IS_STRING);
|
||||
#ifdef _DEBUG
|
||||
if (Event.eEventId == SPEI_VOICE_CHANGE)
|
||||
{
|
||||
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_TOKEN);
|
||||
}
|
||||
else if (Event.eEventId == SPEI_RECOGNITION || Event.eEventId == SPEI_FALSE_RECOGNITION || Event.eEventId == SPEI_HYPOTHESIS)
|
||||
{
|
||||
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_OBJECT);
|
||||
}
|
||||
else if (Event.eEventId ==SPEI_REQUEST_UI || Event.eEventId == SPEI_TTS_BOOKMARK)
|
||||
{
|
||||
SPDBG_ASSERT(Event.elParamType == SPET_LPARAM_IS_STRING);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (1i64 << Event.eEventId) & m_ullEventInterest )
|
||||
{
|
||||
CSpEventNode *pNode = m_FreeList.RemoveHead();
|
||||
if (pNode == NULL)
|
||||
{
|
||||
pNode = new CSpEventNode();
|
||||
if (pNode == NULL)
|
||||
{
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
pNode->CopyFrom(&Event);
|
||||
m_PendingList.InsertSorted(pNode);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
inline HRESULT CSpEventSource::
|
||||
_DeserializeAndAddEvent(const BYTE *pBuffer, ULONG * pcbUsed)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
const SPEVENT * pSrcEvent = (const SPEVENT *)pBuffer;
|
||||
SPDBG_ASSERT(pSrcEvent->eEventId < 64);
|
||||
if ( (1i64 << pSrcEvent->eEventId) & m_ullEventInterest )
|
||||
{
|
||||
CSpEventNode *pNode = m_FreeList.RemoveHead();
|
||||
if (pNode == NULL)
|
||||
{
|
||||
pNode = new CSpEventNode();
|
||||
if (pNode == NULL)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pNode->Deserialize(((const SPSERIALIZEDEVENT64 *)(pBuffer)), pcbUsed);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_PendingList.InsertSorted(pNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FreeList.InsertHead(pNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// WCE compiler does not work propertly with template
|
||||
#ifndef _WIN32_WCE
|
||||
*pcbUsed = SpEventSerializeSize<SPSERIALIZEDEVENT64>(pSrcEvent);
|
||||
#else
|
||||
*pcbUsed = SpEventSerializeSize(pSrcEvent, sizeof(SPSERIALIZEDEVENT64));
|
||||
#endif
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT CSpEventSource::_GetEvents( ULONG ulCount, SPEVENT* pEventArray, ULONG *pulFetched )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
m_pParent->Lock();
|
||||
if( SPIsBadWritePtr( pEventArray, sizeof( SPEVENT ) * ulCount ) ||
|
||||
SP_IS_BAD_OPTIONAL_WRITE_PTR(pulFetched) )
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONG ulCopied = 0;
|
||||
ULONG ulRemaining = ulCount;
|
||||
CSpEventNode * pCur = m_CompletedList.m_pHead;
|
||||
CSpEventNode * pLastCopied = NULL;
|
||||
while (ulRemaining && pCur)
|
||||
{
|
||||
pCur->Detach(pEventArray + ulCopied);
|
||||
pLastCopied = pCur;
|
||||
ulCopied++;
|
||||
pCur = pCur->m_pNext;
|
||||
ulRemaining--;
|
||||
}
|
||||
if (ulCopied)
|
||||
{
|
||||
if (m_FreeList.m_pHead == NULL)
|
||||
{
|
||||
m_FreeList.m_pTail = pLastCopied;
|
||||
}
|
||||
pLastCopied->m_pNext = m_FreeList.m_pHead;
|
||||
m_FreeList.m_pHead = m_CompletedList.m_pHead;
|
||||
m_CompletedList.m_pHead = pCur;
|
||||
m_CompletedList.m_cElements -= ulCopied;
|
||||
m_FreeList.m_cElements += ulCopied;
|
||||
}
|
||||
if (ulCopied < ulCount)
|
||||
{
|
||||
hr = S_FALSE;
|
||||
}
|
||||
if (pulFetched)
|
||||
{
|
||||
*pulFetched = ulCopied;
|
||||
}
|
||||
}
|
||||
m_pParent->Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
inline HRESULT CSpEventSource::_GetInfo( SPEVENTSOURCEINFO * pInfo )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
m_pParent->Lock();
|
||||
if( SP_IS_BAD_WRITE_PTR( pInfo ) )
|
||||
{
|
||||
hr = E_POINTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
pInfo->ulCount = m_CompletedList.GetCount();
|
||||
pInfo->ullEventInterest = m_ullEventInterest;
|
||||
pInfo->ullQueuedInterest= m_ullQueuedInterest;
|
||||
}
|
||||
m_pParent->Unlock();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// The caller must call this function with the critical section owned
|
||||
//
|
||||
inline HRESULT CSpEventSource::_CompleteEvents( ULONGLONG ullPos )
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if (m_PendingList.m_pHead && m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
|
||||
{
|
||||
BOOL bNotify = FALSE;
|
||||
while (m_PendingList.m_pHead &&
|
||||
m_PendingList.m_pHead->ullAudioStreamOffset <= ullPos)
|
||||
{
|
||||
CSpEventNode *pNode = m_PendingList.RemoveHead();
|
||||
if(pNode->ulStreamNum != m_ulStreamNum)
|
||||
{
|
||||
m_ulStreamNum = pNode->ulStreamNum;
|
||||
}
|
||||
if ( (1i64 << pNode->eEventId) & m_ullEventInterest )
|
||||
{
|
||||
bNotify = TRUE;
|
||||
//
|
||||
// NOTE: If we're forwarding events to an event sink then we'll only
|
||||
// pay attention to the Interest flags. If we're going to notify, then
|
||||
// we'll only queue completed events that the user has explicitly asked
|
||||
// us to store as completed events.
|
||||
//
|
||||
if ( (1i64 << pNode->eEventId) & m_ullQueuedInterest )
|
||||
{
|
||||
m_CompletedList.InsertSorted(pNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
pNode->Clear();
|
||||
m_FreeList.InsertHead(pNode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pNode->Clear();
|
||||
m_FreeList.InsertHead(pNode);
|
||||
}
|
||||
}
|
||||
if (bNotify && m_cpNotifySink)
|
||||
{
|
||||
hr = m_cpNotifySink->Notify();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
};
|
||||
|
||||
|
||||
inline void CSpEventSource::_MoveAllToFreeList(CSpEventList * pList)
|
||||
{
|
||||
CSpEventNode * pNode;
|
||||
while ((pNode = pList->RemoveHead()) != NULL)
|
||||
{
|
||||
pNode->Clear();
|
||||
m_FreeList.InsertHead(pNode);
|
||||
}
|
||||
}
|
||||
inline void CSpEventSource::_RemoveAllEvents( )
|
||||
{
|
||||
m_pParent->Lock();
|
||||
|
||||
_MoveAllToFreeList(&m_CompletedList);
|
||||
_MoveAllToFreeList(&m_PendingList);
|
||||
m_pParent->Unlock();
|
||||
}
|
||||
|
||||
inline HRESULT CSpEventSource::_GetStreamNumber(const ULONGLONG ullAudioOffset, ULONG *pulStreamNum)
|
||||
{
|
||||
CSpEventNode *pNode = m_PendingList.m_pHead;
|
||||
*pulStreamNum = m_ulStreamNum;
|
||||
for(;pNode && pNode->ullAudioStreamOffset <= ullAudioOffset; pNode = pNode->m_pNext)
|
||||
{
|
||||
*pulStreamNum = pNode->ulStreamNum;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //--- This must be the last line in this file
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,253 @@
|
||||
/*******************************************************************************
|
||||
* SPUIHelp.h *
|
||||
*------------*
|
||||
* Description:
|
||||
* This is the header file for user-interface helper functions. Note that
|
||||
* unlike SpHelper.H, this file requires the use of ATL.
|
||||
*-------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SPUIHelp_h
|
||||
#define SPUIHelp_h
|
||||
|
||||
#ifndef __sapi_h__
|
||||
#include <sapi.h>
|
||||
#endif
|
||||
|
||||
#ifndef SPError_h
|
||||
#include <SPError.h>
|
||||
#endif
|
||||
|
||||
#ifndef SPDebug_h
|
||||
#include <SPDebug.h>
|
||||
#endif
|
||||
|
||||
#ifndef SPHelper_h
|
||||
#include <SPHelper.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ATLBASE_H__
|
||||
#include <ATLBASE.h>
|
||||
#endif
|
||||
|
||||
#ifndef __ATLCONV_H__
|
||||
#include <ATLCONV.H>
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
********************************************************************* RAL ***/
|
||||
|
||||
//
|
||||
// Dont call this function directly. Use SpInitTokenComboBox or SpInitTokenListBox.
|
||||
//
|
||||
inline HRESULT SpInitTokenList(UINT MsgAddString, UINT MsgSetItemData, UINT MsgSetCurSel,
|
||||
HWND hwnd, const WCHAR * pszCatName,
|
||||
const WCHAR * pszRequiredAttrib, const WCHAR * pszOptionalAttrib)
|
||||
{
|
||||
HRESULT hr;
|
||||
ISpObjectToken * pToken; // NOTE: Not a CComPtr! Be Careful.
|
||||
CComPtr<IEnumSpObjectTokens> cpEnum;
|
||||
hr = SpEnumTokens(pszCatName, pszRequiredAttrib, pszOptionalAttrib, &cpEnum);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
bool fSetDefault = false;
|
||||
while (cpEnum->Next(1, &pToken, NULL) == S_OK)
|
||||
{
|
||||
CSpDynamicString dstrDesc;
|
||||
hr = SpGetDescription(pToken, &dstrDesc);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
USES_CONVERSION;
|
||||
LRESULT i = ::SendMessage(hwnd, MsgAddString, 0, (LPARAM)W2T(dstrDesc));
|
||||
if (i == CB_ERR || i == CB_ERRSPACE) // Note: CB_ and LB_ errors are identical values...
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
|
||||
if (!fSetDefault)
|
||||
{
|
||||
::SendMessage(hwnd, MsgSetCurSel, i, 0);
|
||||
fSetDefault = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FAILED(hr))
|
||||
{
|
||||
pToken->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = SPERR_NO_MORE_ITEMS;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT SpInitTokenComboBox(HWND hwnd, const WCHAR * pszCatName,
|
||||
const WCHAR * pszRequiredAttrib = NULL, const WCHAR * pszOptionalAttrib = NULL)
|
||||
{
|
||||
return SpInitTokenList(CB_ADDSTRING, CB_SETITEMDATA, CB_SETCURSEL, hwnd, pszCatName, pszRequiredAttrib, pszOptionalAttrib);
|
||||
}
|
||||
|
||||
inline HRESULT SpInitTokenListBox(HWND hwnd, const WCHAR * pszCatName,
|
||||
const WCHAR * pszRequiredAttrib = NULL, const WCHAR * pszOptionalAttrib = NULL)
|
||||
{
|
||||
return SpInitTokenList(LB_ADDSTRING, LB_SETITEMDATA, LB_SETCURSEL, hwnd, pszCatName, pszRequiredAttrib, pszOptionalAttrib);
|
||||
}
|
||||
|
||||
//
|
||||
// Dont call this function directly. Use SpDestoyTokenComboBox or SpDestroyTokenListBox.
|
||||
//
|
||||
inline void SpDestroyTokenList(UINT MsgGetCount, UINT MsgGetItemData, HWND hwnd)
|
||||
{
|
||||
LRESULT c = ::SendMessage(hwnd, MsgGetCount, 0, 0);
|
||||
for (LRESULT i = 0; i < c; i++)
|
||||
{
|
||||
IUnknown * pUnkObj = (IUnknown *)::SendMessage(hwnd, MsgGetItemData, i, 0);
|
||||
if (pUnkObj)
|
||||
{
|
||||
pUnkObj->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void SpDestroyTokenComboBox(HWND hwnd)
|
||||
{
|
||||
SpDestroyTokenList(CB_GETCOUNT, CB_GETITEMDATA, hwnd);
|
||||
}
|
||||
|
||||
inline void SpDestroyTokenListBox(HWND hwnd)
|
||||
{
|
||||
SpDestroyTokenList(LB_GETCOUNT, LB_GETITEMDATA, hwnd);
|
||||
}
|
||||
|
||||
|
||||
inline ISpObjectToken * SpGetComboBoxToken(HWND hwnd, WPARAM Index)
|
||||
{
|
||||
return (ISpObjectToken *)::SendMessage(hwnd, CB_GETITEMDATA, Index, 0);
|
||||
}
|
||||
|
||||
inline ISpObjectToken * SpGetListBoxToken(HWND hwnd, WPARAM Index)
|
||||
{
|
||||
return (ISpObjectToken *)::SendMessage(hwnd, LB_GETITEMDATA, Index, 0);
|
||||
}
|
||||
|
||||
inline ISpObjectToken * SpGetCurSelComboBoxToken(HWND hwnd)
|
||||
{
|
||||
LRESULT i = ::SendMessage(hwnd, CB_GETCURSEL, 0, 0);
|
||||
return (i == CB_ERR) ? NULL : SpGetComboBoxToken(hwnd, i);
|
||||
}
|
||||
|
||||
inline ISpObjectToken * SpGetCurSelListBoxToken(HWND hwnd)
|
||||
{
|
||||
LRESULT i = ::SendMessage(hwnd, LB_GETCURSEL, 0, 0);
|
||||
return (i == LB_ERR) ? NULL : SpGetListBoxToken(hwnd, i);
|
||||
}
|
||||
|
||||
//
|
||||
// Don't call this directly. Use SpUpdateCurSelComboBoxToken or SpUpdateCurSelListBoxToken
|
||||
//
|
||||
inline HRESULT SpUpdateCurSelToken(UINT MsgDelString, UINT MsgInsertString, UINT MsgGetItemData, UINT MsgSetItemData, UINT MsgGetCurSel, UINT MsgSetCurSel,
|
||||
HWND hwnd)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
LRESULT i = ::SendMessage(hwnd, MsgGetCurSel, 0, 0);
|
||||
if (i != CB_ERR)
|
||||
{
|
||||
ISpObjectToken * pToken = (ISpObjectToken *)::SendMessage(hwnd, MsgGetItemData, i, 0);
|
||||
CSpDynamicString dstrDesc;
|
||||
hr = SpGetDescription(pToken, &dstrDesc);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
USES_CONVERSION;
|
||||
::SendMessage(hwnd, MsgDelString, i, 0);
|
||||
::SendMessage(hwnd, MsgInsertString, i, (LPARAM)W2T(dstrDesc));
|
||||
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
|
||||
::SendMessage(hwnd, MsgSetCurSel, i, 0);
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT SpUpdateCurSelComboBoxToken(HWND hwnd)
|
||||
{
|
||||
return SpUpdateCurSelToken(CB_DELETESTRING, CB_INSERTSTRING, CB_GETITEMDATA, CB_SETITEMDATA, CB_GETCURSEL, CB_SETCURSEL, hwnd);
|
||||
}
|
||||
|
||||
inline HRESULT SpUpdateCurSelListBoxToken(HWND hwnd)
|
||||
{
|
||||
return SpUpdateCurSelToken(LB_DELETESTRING, LB_INSERTSTRING, LB_GETITEMDATA, LB_SETITEMDATA, LB_GETCURSEL, LB_SETCURSEL, hwnd);
|
||||
}
|
||||
|
||||
inline HRESULT SpAddTokenToList(UINT MsgAddString, UINT MsgSetItemData, UINT MsgSetCurSel, HWND hwnd, ISpObjectToken * pToken)
|
||||
{
|
||||
CSpDynamicString dstrDesc;
|
||||
HRESULT hr = SpGetDescription(pToken, &dstrDesc);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
USES_CONVERSION;
|
||||
LRESULT i = ::SendMessage(hwnd, MsgAddString, 0, (LPARAM)W2T(dstrDesc));
|
||||
if (i == CB_ERR || i == CB_ERRSPACE) // Note: CB_ and LB_ errors are identical values...
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
::SendMessage(hwnd, MsgSetItemData, i, (LPARAM)pToken);
|
||||
::SendMessage(hwnd, MsgSetCurSel, i, 0);
|
||||
pToken->AddRef();
|
||||
}
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT SpAddTokenToComboBox(HWND hwnd, ISpObjectToken * pToken)
|
||||
{
|
||||
return SpAddTokenToList(CB_ADDSTRING, CB_SETITEMDATA, CB_SETCURSEL, hwnd, pToken);
|
||||
}
|
||||
|
||||
inline HRESULT SpAddTokenToListBox(HWND hwnd, ISpObjectToken * pToken)
|
||||
{
|
||||
return SpAddTokenToList(LB_ADDSTRING, LB_SETITEMDATA, LB_SETCURSEL, hwnd, pToken);
|
||||
}
|
||||
|
||||
|
||||
inline HRESULT SpDeleteCurSelToken(UINT MsgGetCurSel, UINT MsgSetCurSel, UINT MsgGetItemData, UINT MsgDeleteString, HWND hwnd)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
LRESULT i = ::SendMessage(hwnd, MsgGetCurSel, 0, 0);
|
||||
if (i == CB_ERR)
|
||||
{
|
||||
hr = S_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ISpObjectToken * pToken = (ISpObjectToken *)::SendMessage(hwnd, MsgGetItemData, i, 0);
|
||||
if (pToken)
|
||||
{
|
||||
pToken->Release();
|
||||
}
|
||||
::SendMessage(hwnd, MsgDeleteString, i, 0);
|
||||
::SendMessage(hwnd, MsgSetCurSel, i, 0);
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT SpDeleteCurSelComboBoxToken(HWND hwnd)
|
||||
{
|
||||
return SpDeleteCurSelToken(CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_DELETESTRING, hwnd);
|
||||
}
|
||||
|
||||
inline HRESULT SpDeleteCurSelListBoxToken(HWND hwnd)
|
||||
{
|
||||
return SpDeleteCurSelToken(LB_GETCURSEL, CB_SETCURSEL, LB_GETITEMDATA, LB_DELETESTRING, hwnd);
|
||||
}
|
||||
|
||||
#endif /* #ifndef SPUIHelp_h -- This must be the last line in the file */
|
||||
Reference in New Issue
Block a user