985 lines
27 KiB
C++
985 lines
27 KiB
C++
/*++
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.h
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
mquinton 06-30-98
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#ifndef __UTILS_H__
|
|
#define __UTILS_H__
|
|
|
|
#ifdef TRACELOG
|
|
|
|
#include <rtutils.h>
|
|
//#include <windef.h>
|
|
//#include <winnt.h>
|
|
|
|
extern BOOL g_bLoggingEnabled;
|
|
|
|
#define MAXDEBUGSTRINGLENGTH 1024
|
|
|
|
#define TL_ERROR ((DWORD)0x00010000 | TRACE_USE_MASK)
|
|
#define TL_WARN ((DWORD)0x00020000 | TRACE_USE_MASK)
|
|
#define TL_INFO ((DWORD)0x00040000 | TRACE_USE_MASK)
|
|
#define TL_TRACE ((DWORD)0x00080000 | TRACE_USE_MASK)
|
|
#define TL_EVENT ((DWORD)0x00100000 | TRACE_USE_MASK)
|
|
|
|
BOOL TRACELogRegister(LPCTSTR szName);
|
|
void TRACELogDeRegister();
|
|
void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR DbgMessage, IN ...);
|
|
void TRACELogPrint(IN DWORD dwDbgLevel, HRESULT hr, IN LPCSTR lpszFormat, IN ...);
|
|
|
|
extern char *TraceLevel(DWORD dwDbgLevel);
|
|
extern void TAPIFormatMessage(HRESULT hr, LPVOID lpMsgBuf);
|
|
|
|
#define TRACELOGREGISTER(arg) TRACELogRegister(arg)
|
|
#define TRACELOGDEREGISTER() g_bLoggingEnabled?TRACELogDeRegister():0
|
|
#define LOG(arg) g_bLoggingEnabled?TRACELogPrint arg:0
|
|
#define STATICLOG(arg) g_bLoggingEnabled?StaticTRACELogPrint arg:0
|
|
|
|
extern char sg_szTraceName[100];
|
|
extern DWORD sg_dwTracingToDebugger;
|
|
extern DWORD sg_dwDebuggerMask;
|
|
extern DWORD sg_dwTraceID;
|
|
|
|
#define DECLARE_DEBUG_ADDREF_RELEASE(x) \
|
|
void LogDebugAddRef(DWORD dw) \
|
|
{ TRACELogPrint(TL_INFO, "%s::AddRef() = %d - this %lx", _T(#x), dw, this); } \
|
|
void LogDebugRelease(DWORD dw) \
|
|
{ TRACELogPrint(TL_INFO, "%s::Release() = %d - this %lx", _T(#x), dw, this); }
|
|
|
|
|
|
#define DECLARE_TRACELOG_CLASS(x) \
|
|
void TRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \
|
|
{ \
|
|
char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \
|
|
va_list arglist; \
|
|
\
|
|
if ( ( sg_dwTracingToDebugger > 0 ) && \
|
|
( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \
|
|
{ \
|
|
SYSTEMTIME SystemTime; \
|
|
GetLocalTime(&SystemTime); \
|
|
\
|
|
wsprintfA(szTraceBuf, \
|
|
"%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \
|
|
sg_szTraceName, \
|
|
SystemTime.wHour, \
|
|
SystemTime.wMinute, \
|
|
SystemTime.wSecond, \
|
|
SystemTime.wMilliseconds, \
|
|
GetCurrentThreadId(), \
|
|
TraceLevel(dwDbgLevel), \
|
|
this, \
|
|
_T(#x)); \
|
|
\
|
|
va_list ap; \
|
|
va_start(ap, lpszFormat); \
|
|
\
|
|
_vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \
|
|
lpszFormat, \
|
|
ap \
|
|
); \
|
|
\
|
|
lstrcatA (szTraceBuf, "\n"); \
|
|
\
|
|
OutputDebugStringA (szTraceBuf); \
|
|
\
|
|
va_end(ap); \
|
|
} \
|
|
\
|
|
if (sg_dwTraceID != INVALID_TRACEID) \
|
|
{ \
|
|
wsprintfA(szTraceBuf, "[%s] (%p) %s::%s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat); \
|
|
\
|
|
va_start(arglist, lpszFormat); \
|
|
TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \
|
|
va_end(arglist); \
|
|
} \
|
|
} \
|
|
\
|
|
void TRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \
|
|
{ \
|
|
char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \
|
|
LPVOID lpMsgBuf = NULL; \
|
|
va_list arglist; \
|
|
\
|
|
TAPIFormatMessage(hr, &lpMsgBuf); \
|
|
\
|
|
if ( ( sg_dwTracingToDebugger > 0 ) && \
|
|
( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \
|
|
{ \
|
|
SYSTEMTIME SystemTime; \
|
|
GetLocalTime(&SystemTime); \
|
|
\
|
|
wsprintfA(szTraceBuf, \
|
|
"%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] (%p) %s::", \
|
|
sg_szTraceName, \
|
|
SystemTime.wHour, \
|
|
SystemTime.wMinute, \
|
|
SystemTime.wSecond, \
|
|
SystemTime.wMilliseconds, \
|
|
GetCurrentThreadId(), \
|
|
TraceLevel(dwDbgLevel), \
|
|
this, \
|
|
_T(#x) \
|
|
); \
|
|
\
|
|
va_list ap; \
|
|
va_start(ap, lpszFormat); \
|
|
\
|
|
_vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \
|
|
lpszFormat, \
|
|
ap \
|
|
); \
|
|
\
|
|
wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
" Returned[%lx] %s\n", \
|
|
hr, \
|
|
lpMsgBuf); \
|
|
\
|
|
OutputDebugStringA (szTraceBuf); \
|
|
\
|
|
va_end(ap); \
|
|
} \
|
|
\
|
|
if (sg_dwTraceID != INVALID_TRACEID) \
|
|
{ \
|
|
wsprintfA(szTraceBuf, "[%s] (%p) %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), this, _T(#x), lpszFormat,hr, lpMsgBuf ); \
|
|
\
|
|
va_start(arglist, lpszFormat); \
|
|
TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \
|
|
va_end(arglist); \
|
|
} \
|
|
\
|
|
if(lpMsgBuf != NULL) \
|
|
{ \
|
|
LocalFree( lpMsgBuf ); \
|
|
} \
|
|
} \
|
|
\
|
|
static void StaticTRACELogPrint(IN DWORD dwDbgLevel, IN LPCSTR lpszFormat, IN ...) \
|
|
{ \
|
|
char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \
|
|
va_list arglist; \
|
|
\
|
|
if ( ( sg_dwTracingToDebugger > 0 ) && \
|
|
( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \
|
|
{ \
|
|
SYSTEMTIME SystemTime; \
|
|
GetLocalTime(&SystemTime); \
|
|
\
|
|
wsprintfA(szTraceBuf, \
|
|
"%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \
|
|
sg_szTraceName, \
|
|
SystemTime.wHour, \
|
|
SystemTime.wMinute, \
|
|
SystemTime.wSecond, \
|
|
SystemTime.wMilliseconds, \
|
|
GetCurrentThreadId(), \
|
|
TraceLevel(dwDbgLevel), \
|
|
_T(#x)); \
|
|
\
|
|
va_list ap; \
|
|
va_start(ap, lpszFormat); \
|
|
\
|
|
_vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \
|
|
lpszFormat, \
|
|
ap \
|
|
); \
|
|
\
|
|
lstrcatA (szTraceBuf, "\n"); \
|
|
\
|
|
OutputDebugStringA (szTraceBuf); \
|
|
\
|
|
va_end(ap); \
|
|
} \
|
|
\
|
|
if (sg_dwTraceID != INVALID_TRACEID) \
|
|
{ \
|
|
wsprintfA(szTraceBuf, "[%s] %s::%s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat); \
|
|
\
|
|
va_start(arglist, lpszFormat); \
|
|
TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \
|
|
va_end(arglist); \
|
|
} \
|
|
} \
|
|
\
|
|
static void StaticTRACELogPrint(IN DWORD dwDbgLevel,IN HRESULT hr, IN LPCSTR lpszFormat, IN ...) \
|
|
{ \
|
|
char szTraceBuf[MAXDEBUGSTRINGLENGTH + 1]; \
|
|
LPVOID lpMsgBuf = NULL; \
|
|
va_list arglist; \
|
|
\
|
|
TAPIFormatMessage(hr, &lpMsgBuf); \
|
|
\
|
|
if ( ( sg_dwTracingToDebugger > 0 ) && \
|
|
( 0 != ( dwDbgLevel & sg_dwDebuggerMask ) ) ) \
|
|
{ \
|
|
SYSTEMTIME SystemTime; \
|
|
GetLocalTime(&SystemTime); \
|
|
\
|
|
wsprintfA(szTraceBuf, \
|
|
"%s:[%02u:%02u:%02u.%03u,tid=%x:] [%s] %s::", \
|
|
sg_szTraceName, \
|
|
SystemTime.wHour, \
|
|
SystemTime.wMinute, \
|
|
SystemTime.wSecond, \
|
|
SystemTime.wMilliseconds, \
|
|
GetCurrentThreadId(), \
|
|
TraceLevel(dwDbgLevel), \
|
|
_T(#x) \
|
|
); \
|
|
\
|
|
va_list ap; \
|
|
va_start(ap, lpszFormat); \
|
|
\
|
|
_vsnprintf(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
MAXDEBUGSTRINGLENGTH - lstrlenA(szTraceBuf), \
|
|
lpszFormat, \
|
|
ap \
|
|
); \
|
|
\
|
|
wsprintfA(&szTraceBuf[lstrlenA(szTraceBuf)], \
|
|
" Returned[%lx] %s\n", \
|
|
hr, \
|
|
lpMsgBuf); \
|
|
\
|
|
OutputDebugStringA (szTraceBuf); \
|
|
\
|
|
va_end(ap); \
|
|
} \
|
|
\
|
|
if (sg_dwTraceID != INVALID_TRACEID) \
|
|
{ \
|
|
wsprintfA(szTraceBuf, "[%s] %s::%s Returned[%lx] %s", TraceLevel(dwDbgLevel), _T(#x), lpszFormat,hr, lpMsgBuf ); \
|
|
\
|
|
va_start(arglist, lpszFormat); \
|
|
TraceVprintfExA(sg_dwTraceID, dwDbgLevel | TRACE_USE_MSEC, szTraceBuf, arglist); \
|
|
va_end(arglist); \
|
|
} \
|
|
\
|
|
if(lpMsgBuf != NULL) \
|
|
{ \
|
|
LocalFree( lpMsgBuf ); \
|
|
} \
|
|
}
|
|
|
|
#else // TRACELOG not defined
|
|
|
|
#define TRACELOGREGISTER(arg)
|
|
#define TRACELOGDEREGISTER()
|
|
#define LOG(arg)
|
|
#define STATICLOG(arg)
|
|
#define DECLARE_DEBUG_ADDREF_RELEASE(x)
|
|
#define DECLARE_TRACELOG_CLASS(x)
|
|
|
|
#endif // TRACELOG
|
|
|
|
class CAsyncRequestReply
|
|
{
|
|
private:
|
|
HANDLE hRepliedSemaphore;
|
|
DWORD dwID;
|
|
BOOL bReply;
|
|
HRESULT hResult;
|
|
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CAsyncRequestReply)
|
|
CAsyncRequestReply(DWORD id, BOOL b, HRESULT hr)
|
|
{
|
|
if( (hRepliedSemaphore = CreateSemaphore(NULL,0,1,NULL)) == NULL )
|
|
{
|
|
LOG((TL_INFO, "create CAsyncRequest - CreateSemaphore failed"));
|
|
hResult = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
dwID = id;
|
|
bReply = b;
|
|
hResult = hr;
|
|
LOG((TL_INFO, "create CAsyncRequest %d ",dwID));
|
|
}
|
|
}
|
|
|
|
~CAsyncRequestReply()
|
|
{
|
|
LOG((TL_INFO, "delete CAsyncRequest %d ",dwID));
|
|
|
|
if( NULL != hRepliedSemaphore )
|
|
{
|
|
CloseHandle(hRepliedSemaphore);
|
|
}
|
|
}
|
|
|
|
inline DWORD getID() {return dwID;};
|
|
inline BOOL IsReply() {return bReply;};
|
|
inline HRESULT getResult() {return hResult;};
|
|
inline void setResult(HRESULT hr) {hResult = hr;};
|
|
|
|
HRESULT wait()
|
|
{
|
|
LOG((TL_INFO, "wait CAsyncRequest %d ",dwID));
|
|
|
|
extern DWORD gdwTapi2AsynchronousCallTimeout;
|
|
|
|
DWORD rc = WaitForSingleObject(hRepliedSemaphore, gdwTapi2AsynchronousCallTimeout);
|
|
|
|
switch (rc)
|
|
{
|
|
case WAIT_ABANDONED:
|
|
LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_ABANDONED",dwID));
|
|
hResult = TAPIERR_REQUESTFAILED;
|
|
break;
|
|
|
|
case WAIT_OBJECT_0:
|
|
break;
|
|
|
|
case WAIT_TIMEOUT:
|
|
LOG((TL_WARN, "wait CAsyncRequest %d WaitForSingle object returned WAIT_TIMEOUT",dwID));
|
|
// -1 won't overlap with any value that may be returned from tapi2 calls.
|
|
hResult = -1;
|
|
break;
|
|
|
|
case WAIT_FAILED:
|
|
{
|
|
DWORD nLastError = GetLastError();
|
|
LOG((TL_ERROR, "wait CAsyncRequest %d WaitForSingle object returned WAIT_FAILED, LastError = %d", dwID, nLastError));
|
|
hResult = TAPIERR_REQUESTFAILED;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
void signal()
|
|
{
|
|
LOG((TL_INFO, "signal CAsyncRequest %d ",dwID));
|
|
ReleaseSemaphore(hRepliedSemaphore, 1, NULL);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
typedef list<CAsyncRequestReply *> RequestReplyList;
|
|
|
|
class CAsyncReplyList
|
|
{
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CAsyncReplyList)
|
|
private:
|
|
RequestReplyList replyList;
|
|
CRITICAL_SECTION csReply;
|
|
|
|
CAsyncRequestReply *find(DWORD dwID)
|
|
{
|
|
RequestReplyList::iterator i;
|
|
CAsyncRequestReply *pResult = NULL;
|
|
|
|
// walk list searching for match
|
|
i = replyList.begin();
|
|
// iterate over current replies
|
|
while ( i != replyList.end() )
|
|
{
|
|
// found it
|
|
if ((*i)->getID() == dwID )
|
|
{
|
|
pResult = *i;
|
|
break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
//returning pointer to matching entry or NULL
|
|
return pResult;
|
|
}
|
|
|
|
public:
|
|
CAsyncReplyList() {InitializeCriticalSection( &csReply );};
|
|
|
|
~CAsyncReplyList()
|
|
{
|
|
FreeList();
|
|
DeleteCriticalSection( &csReply );
|
|
}
|
|
|
|
void FreeList()
|
|
{
|
|
RequestReplyList::iterator i;
|
|
|
|
EnterCriticalSection( &csReply );
|
|
// walk list deleting entries
|
|
i = replyList.begin();
|
|
while ( i != replyList.end() )
|
|
delete *i++;
|
|
|
|
replyList.clear();
|
|
LeaveCriticalSection( &csReply );
|
|
};
|
|
|
|
|
|
void remove(CAsyncRequestReply *a)
|
|
{
|
|
EnterCriticalSection( &csReply );
|
|
replyList.remove(a);
|
|
LeaveCriticalSection( &csReply );
|
|
}
|
|
|
|
CAsyncRequestReply *addRequest(DWORD id)
|
|
{
|
|
CAsyncRequestReply *pReply;
|
|
|
|
EnterCriticalSection( &csReply );
|
|
|
|
// Check list to see if we're already on the list ( i.e. the response LINE_REPLY got here before us)
|
|
pReply = find(id);
|
|
if (pReply == NULL || !pReply->IsReply())
|
|
{
|
|
// No so we got here before the reply, create a new request entry on the list
|
|
pReply = new CAsyncRequestReply(id, FALSE, 0);
|
|
|
|
if (NULL == pReply)
|
|
{
|
|
LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply"));
|
|
}
|
|
else if( pReply->getResult() == E_OUTOFMEMORY )
|
|
{
|
|
delete pReply;
|
|
pReply = NULL;
|
|
LOG((TL_ERROR, "addRequest - Create Semaphore failed"));
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
replyList.push_back(pReply);
|
|
}
|
|
catch(...)
|
|
{
|
|
delete pReply;
|
|
pReply = NULL;
|
|
LOG((TL_ERROR, "addRequest- failed - because of alloc failure"));
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
// Else, the reply comes before me, remove it from the list
|
|
else
|
|
{
|
|
replyList.remove (pReply);
|
|
}
|
|
|
|
LeaveCriticalSection( &csReply );
|
|
return pReply;
|
|
}
|
|
|
|
CAsyncRequestReply *addReply(DWORD id, HRESULT hr)
|
|
{
|
|
CAsyncRequestReply *pReply;
|
|
|
|
EnterCriticalSection( &csReply );
|
|
|
|
// Check list to see if we have a matching entry
|
|
pReply = find(id);
|
|
if (pReply == NULL || pReply->IsReply())
|
|
{
|
|
// No so we got here before the request returned, create a new entry on the list
|
|
pReply = new CAsyncRequestReply(id, TRUE, hr);
|
|
if (NULL == pReply)
|
|
{
|
|
LOG((TL_ERROR, "Could not alloc for CAsyncRequestReply"));
|
|
}
|
|
else if( pReply->getResult() == E_OUTOFMEMORY )
|
|
{
|
|
delete pReply;
|
|
pReply = NULL;
|
|
LOG((TL_ERROR, "addReply - Create Semaphore failed"));
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
replyList.push_back(pReply);
|
|
}
|
|
catch(...)
|
|
{
|
|
delete pReply;
|
|
pReply = NULL;
|
|
LOG((TL_ERROR, "addReply- failed - because of alloc failure"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Use the existing entry, set its return code & signal to the waiting request code
|
|
pReply->setResult(hr);
|
|
replyList.remove (pReply);
|
|
}
|
|
|
|
LeaveCriticalSection( &csReply );
|
|
return pReply;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Class CRetryQueue
|
|
// Maintains queue of Async messages for retry.
|
|
// Typically these relate to calls not yet entered in the call hash-
|
|
// table, such that findCallObject failed. These are reprocessed
|
|
// once the call is entered & the ghAsyncRetryQueueEvent event is
|
|
// signalled.
|
|
//
|
|
// Added criticalsection - thread safe now
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
class CRetryQueue
|
|
{
|
|
typedef struct _tagRetryQueueEntry
|
|
{
|
|
DWORD dwRetryCount;
|
|
PASYNCEVENTMSG pMessage;
|
|
} RETRY_QUEUE_ENTRY, *PRETRY_QUEUE_ENTRY;
|
|
typedef list<RETRY_QUEUE_ENTRY *> RetryQueueListType;
|
|
|
|
#define MAX_REQUEUE_TRIES 3
|
|
|
|
private:
|
|
|
|
RetryQueueListType m_RetryQueueList;
|
|
CRITICAL_SECTION m_cs;
|
|
|
|
|
|
//
|
|
// is the queue open for new entries?
|
|
//
|
|
|
|
BOOL m_bAcceptNewEntries;
|
|
|
|
|
|
private:
|
|
|
|
//
|
|
// requeue the entry that failed processing. don't do this if the queue is
|
|
// closed.
|
|
//
|
|
|
|
void RequeueEvent(PRETRY_QUEUE_ENTRY pQueueEntry);
|
|
|
|
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CRetryQueue)
|
|
|
|
CRetryQueue()
|
|
:m_bAcceptNewEntries(FALSE)
|
|
{
|
|
InitializeCriticalSection( &m_cs );
|
|
}
|
|
|
|
~CRetryQueue();
|
|
|
|
void Lock(){ EnterCriticalSection( &m_cs ); }
|
|
void Unlock(){ LeaveCriticalSection( &m_cs ); }
|
|
|
|
BOOL QueueEvent(PASYNCEVENTMSG pEvent);
|
|
BOOL DequeueEvent(PRETRY_QUEUE_ENTRY * ppEvent);
|
|
void ProcessQueue();
|
|
void RemoveNewCallHub(DWORD);
|
|
inline BOOL ItemsInQueue()
|
|
{
|
|
BOOL bReturn;
|
|
|
|
Lock();
|
|
bReturn = !m_RetryQueueList.empty();
|
|
Unlock();
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
//
|
|
// after this function returns, the queue will accept new entries
|
|
//
|
|
|
|
void OpenForNewEntries();
|
|
|
|
|
|
//
|
|
// new entries will be denied after this function returns
|
|
//
|
|
|
|
void CloseForNewEntries();
|
|
|
|
};
|
|
|
|
|
|
#define MAXCACHEENTRIES 5
|
|
#define BUFFERTYPE_ADDRCAP 1
|
|
#define BUFFERTYPE_LINEDEVCAP 2
|
|
#define BUFFERTYPE_PHONECAP 3
|
|
|
|
typedef struct
|
|
{
|
|
UINT_PTR pObject;
|
|
LPVOID pBuffer;
|
|
|
|
} CACHEENTRY;
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CStructCache
|
|
//
|
|
// A simple class to cache TAPI structures in tapi3.dll
|
|
//
|
|
// This implementation has an array of CACHEENTRY structures. Each
|
|
// CACHEENTRY structure has 2 member:
|
|
// pObject - the object that currently owns the buffer
|
|
// pBuffer - the buffer
|
|
//
|
|
// The array is a fixed size, which is set when the class is initialized
|
|
// The memory for the buffers is allocated during initialization as
|
|
// well. It is possible that a buffer gets realloced (replaced)
|
|
// at some time.
|
|
//
|
|
// This implementation assumes that the object that owns the buffer
|
|
// uses it's critical sections correctly. That is, it is locked when
|
|
// SetXxxBuffer is called, and it is locked when getting and using
|
|
// a buffer If not, the buffer can disapper from the object at any time.
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
class CStructCache
|
|
{
|
|
private:
|
|
CRITICAL_SECTION m_cs;
|
|
DWORD m_dwType;
|
|
DWORD m_dwMaxEntries;
|
|
DWORD m_dwUsedEntries;
|
|
CACHEENTRY m_aEntries[MAXCACHEENTRIES];
|
|
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CStructCache)
|
|
|
|
CStructCache()
|
|
{
|
|
int iCount;
|
|
|
|
InitializeCriticalSection( &m_cs );
|
|
|
|
for( iCount=0; iCount<MAXCACHEENTRIES; iCount++)
|
|
{
|
|
m_aEntries[iCount].pObject = NULL;
|
|
m_aEntries[iCount].pBuffer = NULL;
|
|
}
|
|
|
|
m_dwType = 0;
|
|
m_dwMaxEntries = 0;
|
|
m_dwUsedEntries = 0;
|
|
}
|
|
|
|
~CStructCache()
|
|
{
|
|
DeleteCriticalSection( &m_cs );
|
|
}
|
|
|
|
void Lock()
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
}
|
|
void Unlock()
|
|
{
|
|
LeaveCriticalSection( &m_cs );
|
|
}
|
|
|
|
HRESULT Initialize( DWORD dwMaxEntries, DWORD dwSize, DWORD dwType );
|
|
HRESULT Shutdown();
|
|
HRESULT GetBuffer( UINT_PTR pNewObject, LPVOID * ppReturnStruct );
|
|
HRESULT SetBuffer( UINT_PTR pObject, LPVOID pNewStruct );
|
|
HRESULT InvalidateBuffer( UINT_PTR pObject );
|
|
};
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CArray - based on from CSimpleArray from atl
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
template <class T>
|
|
class CTObjectArray
|
|
{
|
|
private:
|
|
|
|
T * m_aT;
|
|
int m_nSize;
|
|
int m_nUsed;
|
|
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CTObjectArray)
|
|
CTObjectArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){}
|
|
|
|
~CTObjectArray()
|
|
{}
|
|
|
|
int GetSize() const
|
|
{
|
|
return m_nUsed;
|
|
}
|
|
|
|
BOOL Add(T& t)
|
|
{
|
|
if(m_nSize == m_nUsed)
|
|
{
|
|
T * aT;
|
|
int nNewSize;
|
|
|
|
nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2);
|
|
|
|
aT = (T*) ClientAlloc (nNewSize * sizeof(T));
|
|
|
|
if(aT == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory(
|
|
aT,
|
|
m_aT,
|
|
m_nUsed * sizeof(T)
|
|
);
|
|
|
|
ClientFree( m_aT );
|
|
|
|
m_aT = aT;
|
|
|
|
m_nSize = nNewSize;
|
|
}
|
|
|
|
m_aT[m_nUsed] = t;
|
|
|
|
t->AddRef();
|
|
|
|
m_nUsed++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Remove(T& t)
|
|
{
|
|
int nIndex = Find(t);
|
|
|
|
if(nIndex == -1)
|
|
return FALSE;
|
|
|
|
return RemoveAt(nIndex);
|
|
}
|
|
|
|
BOOL RemoveAt(int nIndex)
|
|
{
|
|
m_aT[nIndex]->Release();
|
|
|
|
if(nIndex != (m_nUsed - 1))
|
|
{
|
|
MoveMemory(
|
|
(void*)&m_aT[nIndex],
|
|
(void*)&m_aT[nIndex + 1],
|
|
(m_nUsed - (nIndex + 1)) * sizeof(T)
|
|
);
|
|
}
|
|
|
|
|
|
m_nUsed--;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void Shutdown()
|
|
{
|
|
if( NULL != m_aT )
|
|
{
|
|
int index;
|
|
|
|
for (index = 0; index < m_nUsed; index++)
|
|
{
|
|
m_aT[index]->Release();
|
|
}
|
|
|
|
ClientFree(m_aT);
|
|
|
|
m_aT = NULL;
|
|
m_nUsed = 0;
|
|
m_nSize = 0;
|
|
}
|
|
}
|
|
|
|
T& operator[] (int nIndex) const
|
|
{
|
|
_ASSERTE(nIndex >= 0 && nIndex < m_nUsed);
|
|
return m_aT[nIndex];
|
|
}
|
|
|
|
int Find(T& t) const
|
|
{
|
|
for(int i = 0; i < m_nUsed; i++)
|
|
{
|
|
if(m_aT[i] == t)
|
|
return i;
|
|
}
|
|
return -1; // not found
|
|
}
|
|
};
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CArray - based on from CSimpleArray from atl
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
template <class T>
|
|
class CTArray
|
|
{
|
|
private:
|
|
|
|
T * m_aT;
|
|
int m_nSize;
|
|
int m_nUsed;
|
|
|
|
public:
|
|
DECLARE_TRACELOG_CLASS(CTArray)
|
|
|
|
CTArray() : m_aT(NULL), m_nSize(0), m_nUsed(0){}
|
|
|
|
~CTArray()
|
|
{}
|
|
|
|
int GetSize() const
|
|
{
|
|
return m_nUsed;
|
|
}
|
|
|
|
BOOL Add(T& t)
|
|
{
|
|
if(m_nSize == m_nUsed)
|
|
{
|
|
T * aT;
|
|
int nNewSize;
|
|
|
|
nNewSize = (m_nSize == 0) ? 1 : (m_nSize * 2);
|
|
|
|
aT = (T*) ClientAlloc (nNewSize * sizeof(T));
|
|
|
|
if(aT == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
CopyMemory(
|
|
aT,
|
|
m_aT,
|
|
m_nUsed * sizeof(T)
|
|
);
|
|
|
|
ClientFree( m_aT );
|
|
|
|
m_aT = aT;
|
|
|
|
m_nSize = nNewSize;
|
|
}
|
|
|
|
m_aT[m_nUsed] = t;
|
|
|
|
m_nUsed++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Remove(T& t)
|
|
{
|
|
int nIndex = Find(t);
|
|
|
|
if(nIndex == -1)
|
|
return FALSE;
|
|
|
|
return RemoveAt(nIndex);
|
|
}
|
|
|
|
BOOL RemoveAt(int nIndex)
|
|
{
|
|
if(nIndex != (m_nUsed - 1))
|
|
{
|
|
MoveMemory(
|
|
(void*)&m_aT[nIndex],
|
|
(void*)&m_aT[nIndex + 1],
|
|
(m_nUsed - (nIndex + 1)) * sizeof(T)
|
|
);
|
|
}
|
|
|
|
m_nUsed--;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void Shutdown()
|
|
{
|
|
if( NULL != m_aT )
|
|
{
|
|
int index;
|
|
|
|
ClientFree(m_aT);
|
|
|
|
m_aT = NULL;
|
|
m_nUsed = 0;
|
|
m_nSize = 0;
|
|
}
|
|
}
|
|
|
|
T& operator[] (int nIndex) const
|
|
{
|
|
_ASSERTE(nIndex >= 0 && nIndex < m_nUsed);
|
|
return m_aT[nIndex];
|
|
}
|
|
|
|
int Find(T& t) const
|
|
{
|
|
for(int i = 0; i < m_nUsed; i++)
|
|
{
|
|
if(m_aT[i] == t)
|
|
return i;
|
|
}
|
|
return -1; // not found
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#endif // __UTILS_H__
|
|
|
|
|
|
|