You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4616 lines
109 KiB
4616 lines
109 KiB
/*++
|
|
|
|
Copyright (c) 1997 - 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
tapiobj.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of the TAPI object for TAPI 3.0.
|
|
|
|
The TAPI object represents the application's entry point
|
|
into TAPI - it is similar to the hLineApp / hPhoneApp.
|
|
|
|
Author:
|
|
|
|
mquinton - 4/17/97
|
|
|
|
Notes:
|
|
|
|
optional-notes
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
#include "common.h"
|
|
#include "atlwin.cpp"
|
|
#include "tapievt.h"
|
|
|
|
extern "C" {
|
|
#include "..\..\inc\tapihndl.h"
|
|
}
|
|
|
|
extern CRITICAL_SECTION gcsTapiObjectArray;
|
|
extern CRITICAL_SECTION gcsGlobalInterfaceTable;
|
|
|
|
//
|
|
// handle for heap for the handle table
|
|
//
|
|
// does not need to be exported, hence static
|
|
//
|
|
|
|
static HANDLE ghTapiHeap = 0;
|
|
|
|
|
|
//
|
|
// handle table handle
|
|
//
|
|
|
|
HANDLE ghHandleTable = 0;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FreeContextCallback
|
|
//
|
|
// callback function called by the handle table when a table entry
|
|
// is removed. No need to do anything in this case.
|
|
//
|
|
|
|
VOID
|
|
CALLBACK
|
|
FreeContextCallback(
|
|
LPVOID Context,
|
|
LPVOID Context2
|
|
)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AllocateAndInitializeHandleTable
|
|
//
|
|
// this function creates heap for handle table and the handle table itself
|
|
//
|
|
// Note: this function is not thread-safe. It is only called from
|
|
// ctapi::Initialize() from ghTapiInitShutdownSerializeMutex lock
|
|
//
|
|
|
|
HRESULT AllocateAndInitializeHandleTable()
|
|
{
|
|
|
|
LOG((TL_TRACE, "AllocateAndInitializeHandleTable - entered"));
|
|
|
|
|
|
//
|
|
// heap should not exist at this point
|
|
//
|
|
|
|
_ASSERTE(NULL == ghTapiHeap);
|
|
|
|
if (NULL != ghTapiHeap)
|
|
{
|
|
LOG((TL_ERROR, "AllocateAndInitializeHandleTable() heap already exists"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// handle table should not exist at this point
|
|
//
|
|
|
|
_ASSERTE(NULL == ghHandleTable);
|
|
|
|
if (NULL != ghHandleTable)
|
|
{
|
|
LOG((TL_ERROR, "AllocateAndInitializeHandleTable() handle table already exists"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// attempt to create heap
|
|
//
|
|
|
|
if (!(ghTapiHeap = HeapCreate (0, 0x10000, 0)))
|
|
{
|
|
|
|
//
|
|
// heap creation failed, use process's heap
|
|
//
|
|
|
|
LOG((TL_WARN, "AllocateAndInitializeHandleTable() failed to allocate private heap. using process's heap"));
|
|
|
|
|
|
ghTapiHeap = GetProcessHeap();
|
|
|
|
if (NULL == ghTapiHeap)
|
|
{
|
|
LOG((TL_ERROR, "AllocateAndInitializeHandleTable failed to get process's heap"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
} // HeapCreate()
|
|
|
|
|
|
//
|
|
// we have the heap. use it to create handle table
|
|
//
|
|
|
|
ghHandleTable = CreateHandleTable( ghTapiHeap,
|
|
FreeContextCallback,
|
|
1, // min handle value
|
|
MAX_DWORD // max handle value
|
|
);
|
|
|
|
|
|
if (NULL == ghHandleTable)
|
|
{
|
|
LOG((TL_ERROR, "AllocateAndInitializeHandleTable failed to create handle table"));
|
|
|
|
HeapDestroy (ghTapiHeap);
|
|
ghTapiHeap = NULL;
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// succeeded creating heap and handle table
|
|
//
|
|
|
|
LOG((TL_INFO, "AllocateAndInitializeHandleTable - succeeded"));
|
|
|
|
return S_OK;
|
|
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ShutdownAndDeallocateHandleTable
|
|
//
|
|
// this function deletes handle table, and destroys heap on which it was
|
|
// allocated (if not process heap)
|
|
//
|
|
// Note: this function is not thread-safe. It is only called from
|
|
// ctapi::Initialize() and Shutdown() from ghTapiInitShutdownSerializeMutex lock
|
|
//
|
|
|
|
HRESULT ShutdownAndDeallocateHandleTable()
|
|
{
|
|
|
|
LOG((TL_TRACE, "ShutdownAndDeallocateHandleTable - entered"));
|
|
|
|
|
|
//
|
|
// heap should exist at this point
|
|
//
|
|
|
|
_ASSERTE(NULL != ghTapiHeap);
|
|
|
|
if (NULL == ghTapiHeap)
|
|
{
|
|
LOG((TL_ERROR, "ShutdownAndDeallocateHandleTable heap does not exist"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// handle table should exist at this point
|
|
//
|
|
|
|
_ASSERTE(NULL != ghHandleTable);
|
|
|
|
if (NULL == ghHandleTable)
|
|
{
|
|
LOG((TL_ERROR, "ShutdownAndDeallocateHandleTable handle table does not exist"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// delete handle table
|
|
//
|
|
|
|
DeleteHandleTable (ghHandleTable);
|
|
ghHandleTable = NULL;
|
|
|
|
|
|
//
|
|
// if we created heap for it, destroy it
|
|
//
|
|
|
|
if (ghTapiHeap != GetProcessHeap())
|
|
{
|
|
LOG((TL_INFO, "ShutdownAndDeallocateHandleTable destroying heap"));
|
|
|
|
HeapDestroy (ghTapiHeap);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "ShutdownAndDeallocateHandleTable not destroyng current heap -- used process's heap"));
|
|
}
|
|
|
|
|
|
//
|
|
// in any case, loose reference to the heap.
|
|
//
|
|
|
|
ghTapiHeap = NULL;
|
|
|
|
|
|
LOG((TL_INFO, "ShutdownAndDeallocateHandleTable - succeeded"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
IGlobalInterfaceTable * gpGIT = NULL;
|
|
|
|
LONG
|
|
WINAPI
|
|
AllocClientResources(
|
|
DWORD dwErrorClass
|
|
);
|
|
|
|
extern HRESULT mapTAPIErrorCode(long lErrorCode);
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTAPI
|
|
//
|
|
|
|
// Static data members
|
|
|
|
TAPIObjectArrayNR CTAPI::m_sTAPIObjectArray;
|
|
|
|
extern HANDLE ghTapiInitShutdownSerializeMutex;
|
|
|
|
extern ULONG_PTR GenerateHandleAndAddToHashTable( ULONG_PTR Element);
|
|
extern void RemoveHandleFromHashTable(ULONG_PTR dwHandle);
|
|
extern CHashTable * gpHandleHashTable;
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::ReleaseGIT
|
|
//
|
|
// releases Global Interface Table
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CTAPI::ReleaseGIT()
|
|
{
|
|
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
|
|
|
|
if ( NULL != gpGIT )
|
|
{
|
|
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
|
|
}
|
|
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::AllocateInitializeAllCaches
|
|
//
|
|
// allocates and initializes cache objects (address, line, phone).
|
|
//
|
|
// returns S_OK on success or E_OUTOFMEMORY on failure
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT CTAPI::AllocateInitializeAllCaches()
|
|
{
|
|
|
|
LOG((TL_TRACE, "AllocateInitializeAllCaches - enter"));
|
|
|
|
|
|
//
|
|
// all caches already initialized?
|
|
//
|
|
|
|
if ( (NULL != m_pAddressCapCache) &&
|
|
(NULL != m_pLineCapCache) &&
|
|
(NULL != m_pPhoneCapCache) )
|
|
{
|
|
LOG((TL_TRACE, "AllocateInitializeAllCaches - already initialized. nothing to do"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// only some caches are initialized? that's a bug!
|
|
//
|
|
|
|
if ( (NULL != m_pAddressCapCache) ||
|
|
(NULL != m_pLineCapCache) ||
|
|
(NULL != m_pPhoneCapCache) )
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - already initialized"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
|
|
//
|
|
// we could try to complete cleanup and continue, but this would be too
|
|
// risky since we don't really know how we got here to begin with.
|
|
// simply failing is much safer.
|
|
//
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
////////////////////////
|
|
|
|
//
|
|
// allocate address cache
|
|
//
|
|
|
|
try
|
|
{
|
|
m_pAddressCapCache = new CStructCache;
|
|
}
|
|
catch(...)
|
|
{
|
|
// Initialize critical section in the constructor most likely threw this exception
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - m_pAddressCapCache constructor threw an exception"));
|
|
m_pAddressCapCache = NULL;
|
|
}
|
|
|
|
if (NULL == m_pAddressCapCache)
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to allocate m_pAddressCapCache"));
|
|
|
|
FreeAllCaches();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// attempt to initialize address cache
|
|
//
|
|
|
|
|
|
HRESULT hr = m_pAddressCapCache->Initialize(5,
|
|
sizeof(LINEADDRESSCAPS) + 500,
|
|
BUFFERTYPE_ADDRCAP
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to initialize m_pAddressCapCache. hr = %lx", hr));
|
|
|
|
FreeAllCaches();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
////////////////////////
|
|
|
|
//
|
|
// allocate line cache
|
|
//
|
|
|
|
try
|
|
{
|
|
m_pLineCapCache = new CStructCache;
|
|
}
|
|
catch(...)
|
|
{
|
|
// Initialize critical section in the constructor most likely threw this exception
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - m_pLineCapCache constructor threw an exception"));
|
|
m_pLineCapCache = NULL;
|
|
}
|
|
|
|
if (NULL == m_pLineCapCache )
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to allocate m_pLineCapCache"));
|
|
|
|
FreeAllCaches();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// attempt to initialize line cache
|
|
//
|
|
|
|
hr = m_pLineCapCache->Initialize(5,
|
|
sizeof(LINEDEVCAPS) + 500,
|
|
BUFFERTYPE_LINEDEVCAP
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to initialize m_pLineCapCache. hr = %lx", hr));
|
|
|
|
FreeAllCaches();
|
|
|
|
return hr;
|
|
}
|
|
|
|
////////////////////////
|
|
|
|
//
|
|
// allocate phone cache
|
|
//
|
|
|
|
try
|
|
{
|
|
m_pPhoneCapCache = new CStructCache;
|
|
}
|
|
catch(...)
|
|
{
|
|
// Initialize critical section in the constructor most likely threw this exception
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - m_pPhoneCapCache constructor threw an exception"));
|
|
m_pPhoneCapCache = NULL;
|
|
}
|
|
|
|
//
|
|
// succeeded?
|
|
//
|
|
|
|
if (NULL == m_pPhoneCapCache)
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to allocate m_pPhoneCapCache"));
|
|
|
|
FreeAllCaches();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize phone cache
|
|
//
|
|
|
|
hr = m_pPhoneCapCache->Initialize(5,
|
|
sizeof(PHONECAPS) + 500,
|
|
BUFFERTYPE_PHONECAP
|
|
);
|
|
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "AllocateInitializeAllCaches - failed to initialize m_pPhoneCapCache. hr = %lx", hr));
|
|
|
|
FreeAllCaches();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, "AllocateInitializeAllCaches - finish"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::FreeAllCaches
|
|
//
|
|
// shuts down and deletes all allocated cache objects (address, line, phone)
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CTAPI::FreeAllCaches()
|
|
{
|
|
LOG((TL_TRACE, "FreeAllCaches - enter"));
|
|
|
|
|
|
//
|
|
// Note: it is safe to shutdown a cache that failed initialization or was
|
|
// not initialized at all
|
|
//
|
|
|
|
if (NULL != m_pAddressCapCache)
|
|
{
|
|
LOG((TL_TRACE, "FreeAllCaches - freeing AddressCapCache"));
|
|
|
|
m_pAddressCapCache->Shutdown();
|
|
delete m_pAddressCapCache;
|
|
m_pAddressCapCache = NULL;
|
|
}
|
|
|
|
|
|
if (NULL != m_pLineCapCache)
|
|
{
|
|
LOG((TL_TRACE, "FreeAllCaches - freeing LineCapCache"));
|
|
|
|
m_pLineCapCache->Shutdown();
|
|
delete m_pLineCapCache;
|
|
m_pLineCapCache = NULL;
|
|
}
|
|
|
|
|
|
if (NULL != m_pPhoneCapCache)
|
|
{
|
|
LOG((TL_TRACE, "FreeAllCaches - freeing PhoneCapCache"));
|
|
|
|
m_pPhoneCapCache->Shutdown();
|
|
delete m_pPhoneCapCache;
|
|
m_pPhoneCapCache = NULL;
|
|
}
|
|
|
|
LOG((TL_TRACE, "FreeAllCaches - exit"));
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::Initialize
|
|
//
|
|
// Intialize the TAPI object
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::Initialize(
|
|
void
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
int tapiObjectArraySize=0;
|
|
|
|
LOG((TL_TRACE, "Initialize[%p] enter", this ));
|
|
|
|
|
|
//Serialize the Init and Shutdown code
|
|
WaitForSingleObject( ghTapiInitShutdownSerializeMutex, INFINITE );
|
|
|
|
//
|
|
// if we're already initialized
|
|
// just return
|
|
//
|
|
Lock();
|
|
|
|
if ( m_dwFlags & TAPIFLAG_INITIALIZED )
|
|
{
|
|
LOG((TL_TRACE, "Already initialized - return S_FALSE"));
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// start up TAPI if we haven't already
|
|
//
|
|
EnterCriticalSection( &gcsTapiObjectArray );
|
|
|
|
tapiObjectArraySize = m_sTAPIObjectArray.GetSize();
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
|
|
//
|
|
// create handle table
|
|
//
|
|
|
|
hr = AllocateAndInitializeHandleTable();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "Initialize failed to create handle table"));
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
hr = mapTAPIErrorCode( AllocClientResources (1) );
|
|
|
|
if ( 0 != hr )
|
|
{
|
|
LOG((TL_ERROR, "AllocClientResources failed - %lx", hr));
|
|
|
|
ShutdownAndDeallocateHandleTable();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
//
|
|
// get/create the global interface table
|
|
//
|
|
hr = CoCreateInstance(
|
|
CLSID_StdGlobalInterfaceTable,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IGlobalInterfaceTable,
|
|
(void **)&gpGIT
|
|
);
|
|
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "Initialize - cocreate git failed - %lx", hr));
|
|
|
|
ShutdownAndDeallocateHandleTable();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// allocate and initialize all caches
|
|
//
|
|
// note: if something fails in Initialize later on, we don't really need
|
|
// to clean caches in initialize itself, because the caches will be freed
|
|
// in CTAPI::FinalRelease when the tapi object is destroyed.
|
|
//
|
|
|
|
hr = AllocateInitializeAllCaches();
|
|
|
|
if ( FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "Initialize - failed to create and initialize caches"));
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// Call LineInitialize
|
|
//
|
|
hr = NewInitialize();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - NewInitialize returned %lx", hr));
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
|
|
FreeAllCaches();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// create the address objects
|
|
//
|
|
hr = CreateAllAddressesOnAllLines();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_INFO, "Initialize - CreateAddresses returned %lx", hr));
|
|
|
|
NewShutdown();
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
|
|
FreeAllCaches();
|
|
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// create the phone objects
|
|
//
|
|
hr = CreateAllPhones();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_INFO, "Initialize - CreateAllPhones returned %lx", hr));
|
|
|
|
NewShutdown();
|
|
|
|
m_AddressArray.Shutdown ();
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
|
|
FreeAllCaches();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// create the connectionpoint object
|
|
//
|
|
CComObject< CTAPIConnectionPoint > * p;
|
|
hr = CComObject< CTAPIConnectionPoint >::CreateInstance( &p );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "new CTAPIConnectionPoint failed"));
|
|
|
|
|
|
NewShutdown();
|
|
|
|
m_AddressArray.Shutdown ();
|
|
m_PhoneArray.Shutdown ();
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
|
|
FreeAllCaches();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// init the connection point
|
|
//
|
|
hr = p->Initialize(
|
|
(IConnectionPointContainer *)this,
|
|
IID_ITTAPIEventNotification
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "initialize CTAPIConnectionPoint failed"));
|
|
|
|
delete p;
|
|
|
|
NewShutdown();
|
|
|
|
m_AddressArray.Shutdown ();
|
|
m_PhoneArray.Shutdown ();
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
if ( NULL != gpGIT )
|
|
{
|
|
LOG((TL_TRACE, "Shutdown - release GIT"));
|
|
gpGIT->Release();
|
|
|
|
gpGIT = NULL;
|
|
}
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
ShutdownAndDeallocateHandleTable();
|
|
}
|
|
|
|
|
|
FreeAllCaches();
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return hr;
|
|
}
|
|
|
|
m_pCP = p;
|
|
|
|
//
|
|
// this object is initialized
|
|
//
|
|
|
|
m_dwFlags = TAPIFLAG_INITIALIZED;
|
|
|
|
//
|
|
// save object in global list
|
|
//
|
|
CTAPI * pTapi = this;
|
|
|
|
EnterCriticalSection( &gcsTapiObjectArray );
|
|
|
|
m_sTAPIObjectArray.Add( pTapi );
|
|
|
|
// Set the event filter mask
|
|
// Always ask for
|
|
// TE_CALLSTATE,
|
|
// TE_CALLNOTIFICATION,
|
|
// TE_PHONEVENET,
|
|
// TE_CALLHUB,
|
|
// TE_CALLINFOCHANGE
|
|
// events. These events are used internally by Tapi3
|
|
|
|
ULONG64 ulMask =
|
|
EM_LINE_CALLSTATE | // TE_CALLSTATE
|
|
EM_LINE_APPNEWCALL | // TE_CALLNOTIFICATION
|
|
EM_PHONE_CLOSE | // TE_PHONEEVENT
|
|
EM_PHONE_STATE | // TE_PHONEEVENT
|
|
EM_PHONE_BUTTONMODE | // TE_PHONEEVENT
|
|
EM_PHONE_BUTTONSTATE | // TE_PHONEVENT
|
|
EM_LINE_APPNEWCALLHUB | // TE_CALLHUB
|
|
EM_LINE_CALLHUBCLOSE | // TE_CALLHUB
|
|
EM_LINE_CALLINFO | // TE_CALLINFOCHANGE
|
|
EM_LINE_CREATE | // TE_TAPIOBJECT
|
|
EM_LINE_REMOVE | // TE_TAPIOBJECT
|
|
EM_LINE_CLOSE | // TE_TAPIOBJECT
|
|
EM_PHONE_CREATE | // TE_TAPIOBJECT
|
|
EM_PHONE_REMOVE | // TE_TAPIOBJECT
|
|
EM_LINE_DEVSPECIFICEX | // TE_ADDRESSDEVSPECIFIC
|
|
EM_LINE_DEVSPECIFIC | // TE_ADDRESSDEVSPECIFIC
|
|
EM_PHONE_DEVSPECIFIC; // TE_PHONEDEVSPECIFIC
|
|
|
|
|
|
DWORD dwLineDevStateSubMasks =
|
|
LINEDEVSTATE_REINIT | // TE_TAPIOBJECT
|
|
LINEDEVSTATE_TRANSLATECHANGE ; // TE_TAPIOBJECT
|
|
|
|
|
|
tapiSetEventFilterMasks (
|
|
TAPIOBJ_NULL,
|
|
NULL,
|
|
ulMask
|
|
);
|
|
|
|
tapiSetEventFilterSubMasks (
|
|
TAPIOBJ_NULL,
|
|
NULL,
|
|
EM_LINE_LINEDEVSTATE,
|
|
dwLineDevStateSubMasks
|
|
);
|
|
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
|
|
LOG((TL_TRACE, "Initialize exit - return SUCCESS"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::get_Addresses
|
|
//
|
|
// Creates & returns the collection of address objects
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::get_Addresses(VARIANT * pVariant)
|
|
{
|
|
LOG((TL_TRACE, "get_Addresses enter"));
|
|
LOG((TL_TRACE, " pVariant ------->%p", pVariant));
|
|
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
Unlock();
|
|
|
|
if (TAPIIsBadWritePtr( pVariant, sizeof (VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
CComObject< CTapiCollection< ITAddress > > * p;
|
|
CComObject< CTapiCollection< ITAddress > >::CreateInstance( &p );
|
|
|
|
if (NULL == p)
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
Lock();
|
|
|
|
// initialize
|
|
hr = p->Initialize( m_AddressArray );
|
|
|
|
Unlock();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not initialize collection" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
// get the IDispatch interface
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
// put it in the variant
|
|
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Addressess exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::EnumerateAddresses
|
|
//
|
|
// Create & return an address enumerator
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::EnumerateAddresses(
|
|
IEnumAddress ** ppEnumAddresses
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> > * pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateAddresses enter"));
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_REINIT;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumAddresses, sizeof (IEnumAddress *) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
// create the object
|
|
hr = CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> >::CreateInstance( &pEnum );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - could not create enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
// initialize
|
|
Lock();
|
|
hr = pEnum->Initialize( m_AddressArray );
|
|
Unlock();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
pEnum->Release();
|
|
|
|
LOG((TL_ERROR, "EnumerateAddresses - could not initialize enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppEnumAddresses = pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateAddresses exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::GetPhoneArray
|
|
//
|
|
// Fill a phone array. The array will have references to all
|
|
// of the phone objects it contains.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::GetPhoneArray(
|
|
PhoneArray *pPhoneArray
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG((TL_TRACE, "GetPhoneArray enter"));
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneArray - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
if ( IsBadReadPtr( pPhoneArray, sizeof (PhoneArray) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneArray - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
// initialize the array
|
|
for(int iCount = 0; iCount < m_PhoneArray.GetSize(); iCount++)
|
|
{
|
|
pPhoneArray->Add(m_PhoneArray[iCount]);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "GetPhoneArray exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CTAPI::RegisterCallHubNotifications
|
|
//
|
|
// This method is used to tell TAPI that the application is interested in
|
|
// receiving callhub events.
|
|
//
|
|
// RETURNS
|
|
//
|
|
// S_OK
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::RegisterCallHubNotifications(
|
|
VARIANT_BOOL bNotify
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "RegisterCallHubNotifications - enter"));
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "RCHN - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( bNotify )
|
|
{
|
|
LOG((TL_INFO, "RCHN - callhub notify on"));
|
|
m_dwFlags |= TAPIFLAG_CALLHUBNOTIFY;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO, "RCHN - callhub notify off"));
|
|
m_dwFlags &= ~TAPIFLAG_CALLHUBNOTIFY;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "RegisterCallHubNotifications - exit - success"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// SetCallHubTracking
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::SetCallHubTracking(
|
|
VARIANT pAddresses,
|
|
VARIANT_BOOL bSet
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SAFEARRAY * pAddressArray;
|
|
LONG llBound, luBound;
|
|
int iCount;
|
|
|
|
|
|
LOG((TL_TRACE, "SetCallHubTracking - enter"));
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "SCHT - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
hr = VerifyAndGetArrayBounds(
|
|
pAddresses,
|
|
&pAddressArray,
|
|
&llBound,
|
|
&luBound
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "SCHT - invalid address array - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// all addresses
|
|
//
|
|
if (NULL == pAddressArray)
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// go through all the addresses
|
|
//
|
|
for (iCount = 0; iCount < m_AddressArray.GetSize(); iCount++ )
|
|
{
|
|
CAddress * pCAddress;
|
|
|
|
//
|
|
// register
|
|
//
|
|
pCAddress = dynamic_cast<CAddress *>(m_AddressArray[iCount]);
|
|
|
|
if (NULL == pCAddress)
|
|
{
|
|
LOG((TL_ERROR, "SCHT - out of memory"));
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = (pCAddress)->SetCallHubTracking( bSet );
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_WARN,
|
|
"SCHT failed %lx on address %lx",
|
|
hr,
|
|
iCount
|
|
));
|
|
|
|
}
|
|
}
|
|
|
|
m_dwFlags |= TAPIFLAG_ALLCALLHUBTRACKING;
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// if here, only registering addresses
|
|
// from array
|
|
|
|
//
|
|
// go through array
|
|
//
|
|
for ( ; llBound <=luBound; llBound++ )
|
|
{
|
|
ITAddress * pAddress;
|
|
CAddress * pCAddress;
|
|
|
|
|
|
hr = SafeArrayGetElement(
|
|
pAddressArray,
|
|
&llBound,
|
|
&pAddress
|
|
);
|
|
|
|
if ( (!SUCCEEDED(hr)) || (NULL == pAddress) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pCAddress = dynamic_cast<CAddress *>(pAddress);
|
|
|
|
hr = pCAddress->SetCallHubTracking( bSet );
|
|
|
|
//
|
|
// safearragetelement addrefs
|
|
//
|
|
pAddress->Release();
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((
|
|
TL_WARN,
|
|
"SCHT failed %lx on address %p",
|
|
hr,
|
|
pAddress
|
|
));
|
|
|
|
return hr;
|
|
}
|
|
|
|
}
|
|
|
|
LOG((TL_TRACE, "SetCallHubTracking - exit - success"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CTAPI::RegisterCallNotifications
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::RegisterCallNotifications(
|
|
ITAddress * pAddress,
|
|
VARIANT_BOOL fMonitor,
|
|
VARIANT_BOOL fOwner,
|
|
long lMediaTypes,
|
|
long lCallbackInstance,
|
|
long * plRegister
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PVOID pRegister;
|
|
DWORD dwMediaModes = 0, dwPrivs = 0;
|
|
REGISTERITEM * pRegisterItem;
|
|
CAddress * pCAddress;
|
|
|
|
LOG((TL_TRACE, "RegisterCallNotifications - enter"));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
Unlock();
|
|
|
|
if (TAPIIsBadWritePtr( plRegister, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - invalid plRegister"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
try
|
|
{
|
|
pCAddress = dynamic_cast<CAddress *>(pAddress);
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
|
|
if ( ( NULL == pCAddress ) || !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - bad address"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// determine the privileges
|
|
//
|
|
if (fOwner)
|
|
{
|
|
dwPrivs |= LINECALLPRIVILEGE_OWNER;
|
|
}
|
|
if (fMonitor)
|
|
{
|
|
dwPrivs |= LINECALLPRIVILEGE_MONITOR;
|
|
}
|
|
|
|
if ( 0 == dwPrivs )
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - fMonitor and/or fOwner must be true"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (! (pCAddress->GetMediaMode(
|
|
lMediaTypes,
|
|
&dwMediaModes
|
|
) ) )
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - bad mediamodes"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
pRegisterItem = (REGISTERITEM *)ClientAlloc( sizeof(REGISTERITEM) );
|
|
|
|
if ( NULL == pRegisterItem )
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - Alloc registrationarray failed"));
|
|
|
|
Unlock();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pCAddress->AddCallNotification(
|
|
dwPrivs,
|
|
dwMediaModes,
|
|
lCallbackInstance,
|
|
&pRegister
|
|
);
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "RegisterCallNotifications - AddCallNotification failed"));
|
|
|
|
ClientFree( pRegisterItem );
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
pRegisterItem->dwType = RA_ADDRESS;
|
|
pRegisterItem->pInterface = (PVOID)pCAddress;
|
|
pRegisterItem->pRegister = pRegister;
|
|
|
|
try
|
|
{
|
|
m_RegisterItemPtrList.push_back( (PVOID)pRegisterItem );
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
LOG((TL_ERROR, "RegisterCallNotifications- failed - because of alloc failure"));
|
|
ClientFree( pRegisterItem );
|
|
}
|
|
|
|
#if DBG
|
|
if (m_dwEventFilterMask == 0)
|
|
{
|
|
LOG((TL_WARN, "RegisterCallNotifications - no Event Mask set !!!"));
|
|
}
|
|
#endif
|
|
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// return registration cookie
|
|
//
|
|
|
|
if( S_OK == hr )
|
|
{
|
|
|
|
|
|
//
|
|
// create a 32-bit handle for the RegisterItem pointer
|
|
//
|
|
|
|
DWORD dwCookie = CreateHandleTableEntry((ULONG_PTR)pRegisterItem);
|
|
|
|
if (0 == dwCookie)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
LOG((TL_ERROR, "RegisterCallNotifications - failed to create a handle for REGISTERITEM object %p", pRegisterItem));
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_INFO,
|
|
"RegisterCallNotifications - Mapped handle %lx (to be returned as cookie) to REGISTERITEM object %p",
|
|
dwCookie, pRegisterItem ));
|
|
|
|
// register the cookie with the address object, so address can remove it if
|
|
// the address is deallocated before the call to CTAPI::UnregisterNotifications
|
|
|
|
pCAddress->RegisterNotificationCookie(dwCookie);
|
|
|
|
*plRegister = dwCookie;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, "RegisterCallNotifications - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDMETHODIMP
|
|
CTAPI::UnregisterNotifications(
|
|
long ulRegister
|
|
)
|
|
{
|
|
DWORD dwType;
|
|
HRESULT hr = S_OK;
|
|
REGISTERITEM * pRegisterItem = NULL;
|
|
|
|
LOG((TL_TRACE, "UnregisterNotifications - enter. Cookie %lx", ulRegister));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "UnregNot - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// convert cookie to registration object pointer
|
|
//
|
|
|
|
pRegisterItem = (REGISTERITEM*) GetHandleTableEntry(ulRegister);
|
|
|
|
|
|
//
|
|
// remove cookie from the table
|
|
//
|
|
|
|
DeleteHandleTableEntry(ulRegister);
|
|
|
|
|
|
Unlock();
|
|
|
|
|
|
if ( NULL != pRegisterItem )
|
|
{
|
|
LOG((TL_INFO, "UnregisterNotifications - Matched cookie %lx to REGISTERITEM object %p", ulRegister, pRegisterItem ));
|
|
|
|
|
|
if (IsBadReadPtr( pRegisterItem, sizeof(REGISTERITEM) ) )
|
|
{
|
|
LOG((TL_ERROR, "UnregNot - invalid pRegisterItem returned from the handle table search"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "UnregisterNotifications - invalid lRegister"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
|
|
dwType = pRegisterItem->dwType;
|
|
|
|
//
|
|
// switch on the type of notification
|
|
//
|
|
switch ( dwType )
|
|
{
|
|
case RA_ADDRESS:
|
|
|
|
CAddress * pCAddress;
|
|
ITAddress * pAddress;
|
|
|
|
pCAddress = (CAddress *) (pRegisterItem->pInterface);
|
|
|
|
//
|
|
// try to get the address
|
|
//
|
|
try
|
|
{
|
|
hr = pCAddress->QueryInterface(
|
|
IID_ITAddress,
|
|
(void **)&pAddress
|
|
);
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "Invalid interface in unregisternotifications"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// tell the address
|
|
//
|
|
pCAddress->RemoveCallNotification( pRegisterItem->pRegister );
|
|
|
|
//
|
|
// tell the address to remove a cookie from its list
|
|
//
|
|
pCAddress->RemoveNotificationCookie(ulRegister);
|
|
|
|
pAddress->Release();
|
|
|
|
Lock();
|
|
|
|
//
|
|
// remove array from our list
|
|
//
|
|
m_RegisterItemPtrList.remove( pRegisterItem );
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// free structure
|
|
//
|
|
ClientFree( pRegisterItem );
|
|
|
|
break;
|
|
|
|
case RA_CALLHUB:
|
|
|
|
break;
|
|
}
|
|
|
|
LOG((TL_TRACE, "UnregisterNotifications - exit - success"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::get_CallHubs(
|
|
VARIANT * pVariant
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_CallHubs enter"));
|
|
LOG((TL_TRACE, " pVariant ------->%p", pVariant));
|
|
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ) )
|
|
{
|
|
LOG((TL_ERROR, "get_CallHubs - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( pVariant, sizeof(VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_CallHubs - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
CComObject< CTapiCollection< ITCallHub > > * p;
|
|
CComObject< CTapiCollection< ITCallHub > >::CreateInstance( &p );
|
|
|
|
if (NULL == p)
|
|
{
|
|
LOG((TL_ERROR, "get_CallHubs - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = p->Initialize( m_CallHubArray );
|
|
|
|
Unlock();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_CallHubs - could not initialize collection" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch interface
|
|
//
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_CallHubs - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// put it in the variant
|
|
//
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_CallHubss exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// EnumerateCallHubs
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::EnumerateCallHubs(
|
|
IEnumCallHub ** ppEnumCallHub
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CComObject< CTapiEnum<IEnumCallHub, ITCallHub, &IID_IEnumCallHub> > * pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateCallHubs enter"));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "EnumerateCallHubs - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumCallHub, sizeof( IEnumCallHub *) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateCallHubs - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// create the object
|
|
//
|
|
hr = CComObject< CTapiEnum<IEnumCallHub, ITCallHub, &IID_IEnumCallHub> >::CreateInstance( &pEnum );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "EnumerateCallHubs - could not create enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
Lock();
|
|
hr = pEnum->Initialize( m_CallHubArray );
|
|
Unlock();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
pEnum->Release();
|
|
|
|
LOG((TL_ERROR, "EnumerateCallHubs - could not initialize enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppEnumCallHub = pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateCallHubs exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::EnumConnectionPoints
|
|
//
|
|
// Standard IConnectionPoint method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
__stdcall
|
|
CTAPI::EnumConnectionPoints(
|
|
IEnumConnectionPoints **ppEnum
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "EnumConnectionPoints enter"));
|
|
|
|
hr = E_NOTIMPL;
|
|
|
|
LOG((TL_TRACE, "EnumConnectionPointer exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// FindConnectionPoint
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
__stdcall
|
|
CTAPI::FindConnectionPoint(
|
|
REFIID riid,
|
|
IConnectionPoint **ppCP
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "FindConnectionPoint enter"));
|
|
|
|
#if DBG
|
|
{
|
|
WCHAR guidName[100];
|
|
|
|
StringFromGUID2(riid, (LPOLESTR)&guidName, 100);
|
|
LOG((TL_INFO, "FindConnectionPoint - RIID : %S", guidName));
|
|
}
|
|
#endif
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "FindConnectionPoint - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_NOT_INITIALIZED;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( ppCP, sizeof(IConnectionPoint *) ) )
|
|
{
|
|
LOG((TL_ERROR, "FindConnectionPoint - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// is this the right interface?
|
|
//
|
|
if ( (IID_ITTAPIEventNotification != riid ) && (DIID_ITTAPIDispatchEventNotification != riid ) )
|
|
{
|
|
* ppCP = NULL;
|
|
|
|
LOG((TL_ERROR, "FindConnectionPoint - do not support this riid"));
|
|
|
|
return CONNECT_E_NOCONNECTION;
|
|
}
|
|
|
|
//
|
|
// if it's the right interface, create a new connection point
|
|
// and return it
|
|
//
|
|
Lock();
|
|
|
|
*ppCP = m_pCP;
|
|
(*ppCP)->AddRef();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// success
|
|
//
|
|
LOG((TL_TRACE, "FindConnectionPoint - Success"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CreateAllAddressesOnAllLines
|
|
// This is called when the first TAPI object is created.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::CreateAllAddressesOnAllLines(
|
|
void
|
|
)
|
|
{
|
|
DWORD dwCount;
|
|
|
|
LOG((TL_TRACE, "CreateAllAddressesOnAllLines enter"));
|
|
|
|
Lock();
|
|
|
|
// go through all line devs
|
|
for (dwCount = 0; dwCount < m_dwLineDevs; dwCount++)
|
|
{
|
|
CreateAddressesOnSingleLine( dwCount, FALSE );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CreateAddressesOnSingleLine
|
|
//
|
|
// assumed called in lock!
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::CreateAddressesOnSingleLine( DWORD dwDeviceID, BOOL bFireEvent )
|
|
{
|
|
DWORD dwRealAddresses = 0, dwAddress;
|
|
DWORD dwAPIVersion;
|
|
HRESULT hr;
|
|
LPLINEDEVCAPS pDevCaps = NULL;
|
|
LPLINEADDRESSCAPS pAddressCaps = NULL;
|
|
|
|
LOG((TL_TRACE, "CreateAddressesOnSingleLine: entered."));
|
|
|
|
hr = LineNegotiateAPIVersion(
|
|
(HLINEAPP)m_dwLineInitDataHandle,
|
|
dwDeviceID,
|
|
&dwAPIVersion
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_WARN, "CreateAddressesOnSingleLine: LineNegotiateAPIVersion failed on device %d", dwDeviceID));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "CreateAddressesOnSingleLine: LineNegotiateAPIVersion returned version %lx", dwAPIVersion));
|
|
|
|
hr = LineGetDevCapsWithAlloc(
|
|
(HLINEAPP)m_dwLineInitDataHandle,
|
|
dwDeviceID,
|
|
dwAPIVersion,
|
|
&pDevCaps
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_WARN, "CreateAddressesOnSingleLine: LineGetDevCaps failed for device %d", dwDeviceID));
|
|
|
|
if ( NULL != pDevCaps )
|
|
{
|
|
ClientFree( pDevCaps );
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
if (pDevCaps->dwNumAddresses == 0)
|
|
{
|
|
LOG((TL_WARN, "CreateAddressesOnSingleLine: Device %d has no addressess - will assume 1 address", dwDeviceID));
|
|
|
|
pDevCaps->dwNumAddresses = 1;
|
|
}
|
|
|
|
LPVARSTRING pVarString;
|
|
DWORD dwProviderID;
|
|
|
|
|
|
//
|
|
// get the permanent provider ID for this line.
|
|
//
|
|
hr = LineGetID(
|
|
NULL,
|
|
dwDeviceID,
|
|
NULL,
|
|
LINECALLSELECT_DEVICEID,
|
|
&pVarString,
|
|
L"tapi/providerid"
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
if (NULL != pVarString)
|
|
{
|
|
ClientFree( pVarString);
|
|
}
|
|
|
|
if ( NULL != pDevCaps )
|
|
{
|
|
ClientFree( pDevCaps );
|
|
}
|
|
|
|
LOG((TL_ERROR, "CreateAddressesOnSingleLine: get_ServiceProviderName - LineGetID returned %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// get the id DWORD at the end of the structure
|
|
//
|
|
dwProviderID = *((LPDWORD) (((LPBYTE) pVarString) + pVarString->dwStringOffset));
|
|
|
|
ClientFree( pVarString );
|
|
|
|
|
|
// go through all the addresses on each line, and
|
|
// create an address object.
|
|
for (dwAddress = 0; dwAddress < pDevCaps->dwNumAddresses; dwAddress++)
|
|
{
|
|
CComObject<CAddress> * pAddress;
|
|
ITAddress * pITAddress;
|
|
|
|
try
|
|
{
|
|
|
|
hr = CComObject<CAddress>::CreateInstance( &pAddress );
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_ERROR, "CreateAddressesOnSingleLine: CreateInstance - Address - threw"));
|
|
|
|
continue;
|
|
}
|
|
|
|
if ( !SUCCEEDED(hr) || (NULL == pAddress) )
|
|
{
|
|
LOG((TL_ERROR, "CreateAddressesOnSingleLine: CreateInstance - Address - failed - %lx", hr));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// initialize the address
|
|
// if there are no phone devices,
|
|
// give NULL for the hPhoneApp, so the address
|
|
// doesn't think that there may be a phone device
|
|
//
|
|
hr = pAddress->Initialize(
|
|
this,
|
|
(HLINEAPP)m_dwLineInitDataHandle,
|
|
#ifdef USE_PHONEMSP
|
|
(m_dwPhoneDevs)?((HPHONEAPP)m_dwPhoneInitDataHandle):NULL,
|
|
#endif USE_PHONEMSP
|
|
dwAPIVersion,
|
|
dwDeviceID,
|
|
dwAddress,
|
|
dwProviderID,
|
|
pDevCaps,
|
|
m_dwEventFilterMask
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "CreateAddressesOnSingleLine: failed for device %d, address %d", dwDeviceID, dwAddress));
|
|
|
|
delete pAddress;
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// add to list
|
|
//
|
|
pITAddress = dynamic_cast<ITAddress *>(pAddress);
|
|
|
|
m_AddressArray.Add( pITAddress );
|
|
|
|
pAddress->Release();
|
|
|
|
if ( bFireEvent )
|
|
{
|
|
CTapiObjectEvent::FireEvent(
|
|
this,
|
|
TE_ADDRESSCREATE,
|
|
pAddress,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
if ( NULL != pDevCaps )
|
|
{
|
|
ClientFree( pDevCaps );
|
|
}
|
|
|
|
LOG((TL_INFO, "CreateAddressesOnSingleLine: completed."));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CreateAllPhones
|
|
// This is called when the first TAPI object is created.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::CreateAllPhones(
|
|
void
|
|
)
|
|
{
|
|
DWORD dwCount;
|
|
|
|
LOG((TL_TRACE, "CreateAllPhones enter"));
|
|
|
|
Lock();
|
|
|
|
// go through all phone devs
|
|
for (dwCount = 0; dwCount < m_dwPhoneDevs; dwCount++)
|
|
{
|
|
CreatePhone( dwCount, FALSE );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// CreatePhone
|
|
//
|
|
// assumed called in lock!
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::CreatePhone( DWORD dwDeviceID, BOOL bFireEvent )
|
|
{
|
|
DWORD dwAPIVersion;
|
|
HRESULT hr;
|
|
|
|
hr = PhoneNegotiateAPIVersion(
|
|
(HPHONEAPP)m_dwPhoneInitDataHandle,
|
|
dwDeviceID,
|
|
&dwAPIVersion
|
|
);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_WARN, "CreatePhone - phoneNegotiateAPIVersion failed on device %d", dwDeviceID));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "CreatePhone - phoneNegotiateAPIVersion returned version %lx", dwAPIVersion));
|
|
|
|
// create a phone object.
|
|
|
|
CComObject<CPhone> * pPhone;
|
|
ITPhone * pITPhone;
|
|
|
|
__try
|
|
{
|
|
hr = CComObject<CPhone>::CreateInstance( &pPhone );
|
|
}
|
|
__except( (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ?
|
|
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
|
|
{
|
|
LOG((TL_ERROR, "CreatePhone - CreateInstancefailed - because of alloc failure"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( !SUCCEEDED(hr) || (NULL == pPhone) )
|
|
{
|
|
LOG((TL_ERROR, "CreatePhone - CreateInstance failed - %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize the phone
|
|
//
|
|
hr = pPhone->Initialize(
|
|
this,
|
|
(HLINEAPP)m_dwPhoneInitDataHandle,
|
|
dwAPIVersion,
|
|
dwDeviceID
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreatePhone failed for device %d", dwDeviceID));
|
|
|
|
delete pPhone;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// add to list
|
|
//
|
|
pITPhone = dynamic_cast<ITPhone *>(pPhone);
|
|
|
|
m_PhoneArray.Add( pITPhone );
|
|
|
|
pPhone->Release();
|
|
|
|
if ( bFireEvent )
|
|
{
|
|
CTapiObjectEvent::FireEvent(this,
|
|
TE_PHONECREATE,
|
|
NULL,
|
|
0,
|
|
pITPhone
|
|
);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// Shutdown
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
STDMETHODCALLTYPE
|
|
CTAPI::Shutdown()
|
|
{
|
|
PtrList::iterator iter, end;
|
|
int iCount;
|
|
DWORD dwSignalled;
|
|
int tapiObjectArraySize=0;
|
|
CTAPI *pTapi;
|
|
|
|
LOG((TL_TRACE, "Shutdown[%p] - enter", this));
|
|
LOG((TL_TRACE, "Shutdown - enter"));
|
|
|
|
CoWaitForMultipleHandles (0,
|
|
INFINITE,
|
|
1,
|
|
&ghTapiInitShutdownSerializeMutex,
|
|
&dwSignalled
|
|
);
|
|
|
|
Lock();
|
|
|
|
if ( (!( m_dwFlags & TAPIFLAG_INITIALIZED )) &&
|
|
(!( m_dwFlags & TAPIFLAG_REINIT)))
|
|
{
|
|
|
|
LOG((TL_WARN, "Shutdown - already shutdown - return S_FALSE"));
|
|
|
|
Unlock();
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
return S_FALSE;
|
|
}
|
|
|
|
m_dwFlags &= ~TAPIFLAG_INITIALIZED;
|
|
m_dwFlags &= ~TAPIFLAG_REINIT;
|
|
pTapi = this;
|
|
|
|
//
|
|
// close all the phones
|
|
//
|
|
|
|
for(iCount = 0; iCount < m_PhoneArray.GetSize(); iCount++)
|
|
{
|
|
CPhone *pCPhone = NULL;
|
|
|
|
try
|
|
{
|
|
pCPhone = dynamic_cast<CPhone *>(m_PhoneArray[iCount]);
|
|
}
|
|
catch(...)
|
|
{
|
|
|
|
LOG((TL_ERROR, "Shutdown - phone array contains a bad phone pointer"));
|
|
|
|
pCPhone = NULL;
|
|
}
|
|
|
|
if (NULL != pCPhone)
|
|
{
|
|
pCPhone->ForceClose();
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection( &gcsTapiObjectArray );
|
|
|
|
m_sTAPIObjectArray.Remove ( pTapi );
|
|
|
|
tapiObjectArraySize = m_sTAPIObjectArray.GetSize();
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
m_AgentHandlerArray.Shutdown();
|
|
|
|
gpLineHashTable->Flush(this);
|
|
gpCallHashTable->Flush(this);
|
|
gpCallHubHashTable->Flush(this);
|
|
gpPhoneHashTable->Flush(this);
|
|
|
|
|
|
//
|
|
// tell each address in the array that it is time to toss all
|
|
// the cookies
|
|
//
|
|
|
|
int nAddressArraySize = m_AddressArray.GetSize();
|
|
|
|
for (int i = 0; i < nAddressArraySize; i++)
|
|
{
|
|
|
|
//
|
|
// we need a pointer to CAddress to unregister cookies
|
|
//
|
|
|
|
CAddress *pAddress = NULL;
|
|
|
|
|
|
//
|
|
// in case address array contains a pointer to nonreadable memory,
|
|
// do dynamic cast inside try/catch
|
|
//
|
|
|
|
try
|
|
{
|
|
|
|
pAddress = dynamic_cast<CAddress*>(m_AddressArray[i]);
|
|
}
|
|
catch(...)
|
|
{
|
|
|
|
LOG((TL_ERROR, "Shutdown - address array contains a bad address pointer"));
|
|
|
|
pAddress = NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// attempt to unregister address' notifications
|
|
//
|
|
|
|
if (NULL != pAddress)
|
|
{
|
|
|
|
//
|
|
// unregister all notification cookies
|
|
//
|
|
|
|
pAddress->UnregisterAllCookies();
|
|
|
|
|
|
//
|
|
// notify address that tapi is being shutdown, so it can do
|
|
// whatever clean up is necessary
|
|
//
|
|
|
|
pAddress->AddressOnTapiShutdown();
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we have an address that is not an address. debug!
|
|
//
|
|
|
|
LOG((TL_ERROR,
|
|
"Shutdown - address array contains a bad address pointer."));
|
|
|
|
_ASSERTE(FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
m_AddressArray.Shutdown();
|
|
|
|
|
|
|
|
m_PhoneArray.Shutdown();
|
|
|
|
m_CallHubArray.Shutdown();
|
|
|
|
Unlock();
|
|
|
|
NewShutdown();
|
|
|
|
Lock();
|
|
if ( NULL != m_pCP )
|
|
{
|
|
m_pCP->Release();
|
|
m_pCP = NULL;
|
|
}
|
|
|
|
|
|
iter = m_RegisterItemPtrList.begin();
|
|
end = m_RegisterItemPtrList.end();
|
|
|
|
while (iter != end)
|
|
{
|
|
ClientFree( *iter );
|
|
iter ++;
|
|
}
|
|
|
|
m_RegisterItemPtrList.clear();
|
|
|
|
Unlock();
|
|
|
|
if ( 0 == tapiObjectArraySize )
|
|
{
|
|
|
|
FinalTapiCleanup();
|
|
|
|
EnterCriticalSection( &gcsGlobalInterfaceTable );
|
|
|
|
ReleaseGIT();
|
|
|
|
LeaveCriticalSection( &gcsGlobalInterfaceTable );
|
|
|
|
|
|
//
|
|
// no longer need handle table.
|
|
//
|
|
|
|
ShutdownAndDeallocateHandleTable();
|
|
|
|
}
|
|
|
|
ReleaseMutex( ghTapiInitShutdownSerializeMutex );
|
|
|
|
LOG((TL_TRACE, "Shutdown - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// finalrelease of tapi object
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::FinalRelease()
|
|
{
|
|
LOG((TL_TRACE, "FinalRelease - enter"));
|
|
|
|
Lock();
|
|
|
|
FreeAllCaches();
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "FinalRelease - exit"));
|
|
}
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// VerifyAndGetArrayBounds
|
|
//
|
|
// Helper function for variant/safearrays
|
|
//
|
|
// Array
|
|
// IN Variant that contains a safearray
|
|
//
|
|
// ppsa
|
|
// OUT safearray returned here
|
|
//
|
|
// pllBound
|
|
// OUT array lower bound returned here
|
|
//
|
|
// pluBound
|
|
// OUT array upper boudn returned here
|
|
//
|
|
// RETURNS
|
|
//
|
|
// verifies that Array contains an array, and returns the array, upper
|
|
// and lower bounds.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
VerifyAndGetArrayBounds(
|
|
VARIANT Array,
|
|
SAFEARRAY ** ppsa,
|
|
long * pllBound,
|
|
long * pluBound
|
|
)
|
|
{
|
|
UINT uDims;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// see if the variant & safearray are valid
|
|
//
|
|
try
|
|
{
|
|
if (!(V_ISARRAY(&Array)))
|
|
{
|
|
if ( VT_NULL ==Array.vt )
|
|
{
|
|
//
|
|
// null is usually valid
|
|
//
|
|
|
|
*ppsa = NULL;
|
|
|
|
LOG((TL_INFO, "Returning NULL array"));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
LOG((TL_ERROR, "Array - not an array"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( NULL == Array.parray )
|
|
{
|
|
//
|
|
// null is usually valide
|
|
//
|
|
*ppsa = NULL;
|
|
|
|
LOG((TL_INFO, "Returning NULL array"));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
*ppsa = V_ARRAY(&Array);
|
|
|
|
uDims = SafeArrayGetDim( *ppsa );
|
|
|
|
}
|
|
catch(...)
|
|
{
|
|
hr = E_POINTER;
|
|
}
|
|
|
|
|
|
if (!SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_ERROR, "Array - invalid array"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// verify array
|
|
//
|
|
if (1 != uDims)
|
|
{
|
|
if (0 == uDims)
|
|
{
|
|
LOG((TL_ERROR, "Array - has 0 dim"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "Array - has > 1 dim - will only use 1"));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get array bounds
|
|
//
|
|
SafeArrayGetUBound(
|
|
*ppsa,
|
|
1,
|
|
pluBound
|
|
);
|
|
|
|
SafeArrayGetLBound(
|
|
*ppsa,
|
|
1,
|
|
pllBound
|
|
);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
BOOL QueueCallbackEvent(CTAPI * pTapi, TAPI_EVENT te, IDispatch * pEvent);
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::Event(
|
|
TAPI_EVENT te,
|
|
IDispatch * pEvent
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwEventFilterMask;
|
|
|
|
LOG((TL_TRACE, "Event[%p] - enter. Event[0x%x]", this, te));
|
|
|
|
|
|
Lock();
|
|
dwEventFilterMask = m_dwEventFilterMask;
|
|
Unlock();
|
|
|
|
if( (te != TE_ADDRESS) &&
|
|
(te != TE_CALLHUB) &&
|
|
(te != TE_CALLINFOCHANGE) &&
|
|
(te != TE_CALLMEDIA) &&
|
|
(te != TE_CALLNOTIFICATION) &&
|
|
(te != TE_CALLSTATE) &&
|
|
(te != TE_FILETERMINAL) &&
|
|
(te != TE_PRIVATE) &&
|
|
(te != TE_QOSEVENT) &&
|
|
(te != TE_TAPIOBJECT) &&
|
|
(te != TE_ADDRESSDEVSPECIFIC) &&
|
|
(te != TE_PHONEDEVSPECIFIC) )
|
|
{
|
|
if( (te & dwEventFilterMask) == 0)
|
|
{
|
|
//
|
|
// Don't fire the event
|
|
//
|
|
hr = S_FALSE;
|
|
LOG((TL_INFO, "Event - This Event not Enabled %x", te));
|
|
return hr;
|
|
}
|
|
}
|
|
|
|
//
|
|
// It's an event from the event filtering mechanism
|
|
// TE_ADDRESS, TE_CALLHUB, TE_CALLINFOCHANGE, TE_CALLMEDIA,
|
|
// TE_CALLNOTIFICATION, TE_CALLSTATE, TE_FILETERMINAL,
|
|
// TE_PRIVATE, TE_QOSEVENT, TE_TAPIOBJECT
|
|
//
|
|
|
|
AddRef();
|
|
pEvent->AddRef();
|
|
|
|
if(QueueCallbackEvent(this, te, pEvent) == TRUE)
|
|
{
|
|
LOG((TL_INFO, "Event queued"));
|
|
}
|
|
else
|
|
{
|
|
Release();
|
|
pEvent->Release();
|
|
LOG((TL_INFO, "Event queuing Failed"));
|
|
}
|
|
|
|
LOG((TL_TRACE, "Event - exit"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::EventFire(
|
|
TAPI_EVENT te,
|
|
IDispatch * pEvent
|
|
)
|
|
{
|
|
|
|
ITTAPIEventNotification * pCallback = NULL;
|
|
IDispatch * pDispatch = NULL;
|
|
HRESULT hr = S_OK;
|
|
CTAPIConnectionPoint * pCP;
|
|
|
|
LOG((TL_TRACE, "EventFire - enter"));
|
|
|
|
Lock();
|
|
|
|
if( NULL != m_pCP )
|
|
{
|
|
m_pCP->AddRef();
|
|
}
|
|
|
|
pCP = m_pCP;
|
|
|
|
Unlock();
|
|
|
|
if ( NULL != pCP )
|
|
{
|
|
pDispatch = (IDispatch *)pCP->GrabEventCallback();
|
|
|
|
if ( NULL != pDispatch )
|
|
{
|
|
hr = pDispatch->QueryInterface(IID_ITTAPIEventNotification,
|
|
(void **)&pCallback
|
|
);
|
|
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
if ( NULL != pCallback )
|
|
{
|
|
LOG((TL_TRACE, "EventFire - fire on ITTAPIEventNotification"));
|
|
pCallback->Event( te, pEvent );
|
|
pCallback->Release();
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
LOG((TL_WARN, "EventFire - can't fire event on ITTAPIEventNotification - no callback"));
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
|
|
CComVariant varResult;
|
|
CComVariant* pvars = new CComVariant[2];
|
|
|
|
LOG((TL_TRACE, "EventFire - fire on IDispatch"));
|
|
|
|
VariantClear(&varResult);
|
|
pvars[1] = te;
|
|
pvars[0] = pEvent;
|
|
DISPPARAMS disp = { pvars, NULL, 2, 0 };
|
|
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
|
|
delete[] pvars;
|
|
|
|
hr = varResult.scode;
|
|
|
|
}
|
|
|
|
pDispatch->Release();
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
LOG((TL_WARN, "Event - can't fire event on IDispatch - no callback"));
|
|
}
|
|
#endif
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
LOG((TL_WARN, "Event - can't fire event - no m_pCP"));
|
|
}
|
|
#endif
|
|
|
|
if(NULL != pCP)
|
|
{
|
|
pCP->Release();
|
|
}
|
|
|
|
pEvent->Release();
|
|
|
|
LOG((TL_TRACE, "EventFire - exit"));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// AddCallHub
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::AddCallHub( CCallHub * pCallHub )
|
|
{
|
|
ITCallHub * pITCallHub;
|
|
|
|
Lock();
|
|
|
|
pITCallHub = dynamic_cast<ITCallHub *>(pCallHub);
|
|
|
|
m_CallHubArray.Add( pITCallHub );
|
|
|
|
Unlock();
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// RemoveCallHub
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::RemoveCallHub( CCallHub * pCallHub )
|
|
{
|
|
ITCallHub * pITCallHub;
|
|
|
|
Lock();
|
|
|
|
pITCallHub = dynamic_cast<ITCallHub *>(pCallHub);
|
|
|
|
m_CallHubArray.Remove( pITCallHub );
|
|
|
|
Unlock();
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::get_PrivateTAPIObjects(VARIANT*)
|
|
{
|
|
LOG((TL_TRACE, "get_PrivateTAPIObjects - enter"));
|
|
|
|
LOG((TL_ERROR, "get_PrivateTAPIObjects - exit E_NOTIMPL"));
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// former EnumeratePrivateTAPIObjects
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::EnumeratePrivateTAPIObjects(IEnumUnknown**)
|
|
{
|
|
LOG((TL_TRACE, "EnumeratePrivateTAPIObjects - enter"));
|
|
|
|
LOG((TL_ERROR, "EnumeratePrivateTAPIObjects - return E_NOTIMPL"));
|
|
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// RegisterRequestRecipient
|
|
//
|
|
// simply call LineRegisterRequestRecipient - registers as assisted
|
|
// telephony application
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::RegisterRequestRecipient(
|
|
long lRegistrationInstance,
|
|
long lRequestMode,
|
|
#ifdef NEWREQUEST
|
|
long lAddressTypes,
|
|
#endif
|
|
VARIANT_BOOL fEnable
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "RegisterRequestRecipient - enter"));
|
|
|
|
Lock();
|
|
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ))
|
|
{
|
|
LOG((TL_ERROR, "RegisterRequestRecipient - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
hr = LineRegisterRequestRecipient(
|
|
(HLINEAPP)m_dwLineInitDataHandle,
|
|
lRegistrationInstance,
|
|
lRequestMode,
|
|
#ifdef NEWREQUEST
|
|
lAddressTypes,
|
|
#endif
|
|
fEnable?TRUE : FALSE
|
|
);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SetAssistedTelephonyPriority
|
|
//
|
|
// set the app priority for assisted telephony
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::SetAssistedTelephonyPriority(
|
|
BSTR pAppFilename,
|
|
VARIANT_BOOL fPriority
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "SetAssistedTelephonyPriority - enter"));
|
|
|
|
hr = LineSetAppPriority(
|
|
pAppFilename,
|
|
0,
|
|
LINEREQUESTMODE_MAKECALL,
|
|
fPriority?1:0
|
|
);
|
|
|
|
LOG((TL_TRACE, "SetAssistedTelephonyPriority - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// SetApplicationPriority
|
|
//
|
|
// sets the app priority for incoming calls and handoff.
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::SetApplicationPriority(
|
|
BSTR pAppFilename,
|
|
long lMediaType,
|
|
VARIANT_BOOL fPriority
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "SetApplicationPriority - enter"));
|
|
|
|
hr = LineSetAppPriority(
|
|
pAppFilename,
|
|
lMediaType,
|
|
0,
|
|
fPriority?1:0
|
|
);
|
|
|
|
LOG((TL_TRACE, "SetApplicationPriority - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// put_EventFilter
|
|
//
|
|
// sets the Event filter mask
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::put_EventFilter(long lFilterMask)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwOldFilterMask;
|
|
ULONG64 ulEventMasks;
|
|
DWORD dwLineDevStateSubMasks;
|
|
DWORD dwAddrStateSubMasks;
|
|
|
|
|
|
LOG((TL_TRACE, "put_EventFilter - enter"));
|
|
|
|
if (~ALL_EVENT_FILTER_MASK & lFilterMask)
|
|
{
|
|
LOG((TL_ERROR, "put_EventFilter - Unknown Event type in mask %x", lFilterMask ));
|
|
hr = E_INVALIDARG;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// Event Filtering, we should pass the mask
|
|
// to all addresses
|
|
//
|
|
|
|
HRESULT hr = E_FAIL;
|
|
hr = SetEventFilterToAddresses( lFilterMask );
|
|
if( FAILED(hr) )
|
|
{
|
|
Unlock();
|
|
LOG((TL_ERROR, "put_EventFilter - exit"
|
|
"CopyEventFilterMaskToAddresses failed. Returns 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set the event filter
|
|
//
|
|
dwOldFilterMask = m_dwEventFilterMask;
|
|
m_dwEventFilterMask = lFilterMask;
|
|
|
|
Unlock();
|
|
|
|
// Convert lFilterMask to server side 64 bit masks
|
|
// we alway should receive:
|
|
// TE_CALLSTATE,
|
|
// TE_CALLNOTIFICATION,
|
|
// TE_PHONEEVENT
|
|
// TE_CALLHUB
|
|
// TE_CALLINFOCHANGE
|
|
// TE_TAPIOBJECT
|
|
// events because these events are used internally
|
|
// by Tapi3 objets
|
|
|
|
ulEventMasks = EM_LINE_CALLSTATE // TE_CALLSTATE
|
|
| EM_LINE_APPNEWCALL // TE_CALLNOTIFICATION
|
|
| EM_PHONE_CLOSE // TE_PHONEEVENT
|
|
| EM_PHONE_STATE // TE_PHONEEVENT
|
|
| EM_PHONE_BUTTONMODE // TE_PHONEEVENT
|
|
| EM_PHONE_BUTTONSTATE // TE_PHONEVENT
|
|
| EM_LINE_APPNEWCALLHUB // TE_CALLHUB
|
|
| EM_LINE_CALLHUBCLOSE // TE_CALLHUB
|
|
| EM_LINE_CALLINFO // TE_CALLINFOCHANGE
|
|
| EM_LINE_CREATE // TE_TAPIOBJECT
|
|
| EM_LINE_REMOVE // TE_TAPIOBJECT
|
|
| EM_LINE_CLOSE // TE_TAPIOBJECT
|
|
| EM_PHONE_CREATE // TE_TAPIOBJECT
|
|
| EM_PHONE_REMOVE // TE_TAPIOBJECT
|
|
;
|
|
|
|
dwLineDevStateSubMasks = LINEDEVSTATE_REINIT // TE_TAPIOBJECT
|
|
| LINEDEVSTATE_TRANSLATECHANGE; // TE_TAPIOBJECT
|
|
|
|
dwAddrStateSubMasks = 0;
|
|
|
|
if (lFilterMask & TE_ADDRESS)
|
|
{
|
|
// AE_STATE
|
|
dwLineDevStateSubMasks |=
|
|
LINEDEVSTATE_CONNECTED |
|
|
LINEDEVSTATE_INSERVICE |
|
|
LINEDEVSTATE_OUTOFSERVICE |
|
|
LINEDEVSTATE_MAINTENANCE |
|
|
LINEDEVSTATE_REMOVED |
|
|
LINEDEVSTATE_DISCONNECTED |
|
|
LINEDEVSTATE_LOCK;
|
|
|
|
// AE_MSGWAITON, AAE_MSGWAITOFF
|
|
dwLineDevStateSubMasks |=
|
|
LINEDEVSTATE_MSGWAITON |
|
|
LINEDEVSTATE_MSGWAITOFF ;
|
|
|
|
// AE_CAPSCHANGE
|
|
dwAddrStateSubMasks |=
|
|
LINEADDRESSSTATE_CAPSCHANGE;
|
|
dwLineDevStateSubMasks |=
|
|
LINEDEVSTATE_CAPSCHANGE;
|
|
|
|
dwLineDevStateSubMasks |=
|
|
LINEDEVSTATE_RINGING | // AE_RINGING
|
|
LINEDEVSTATE_CONFIGCHANGE; // AE_CONFIGCHANGE
|
|
|
|
dwAddrStateSubMasks |=
|
|
LINEADDRESSSTATE_FORWARD; // AE_FORWARD
|
|
|
|
// AE_NEWTERMINAL : ignore private MSP events
|
|
// AE_REMOVETERMINAL : ignore private MSP events
|
|
|
|
}
|
|
if (lFilterMask & TE_CALLMEDIA)
|
|
{
|
|
// Skil media event
|
|
}
|
|
if (lFilterMask & TE_PRIVATE)
|
|
{
|
|
// skip MSP private event
|
|
}
|
|
if (lFilterMask & TE_REQUEST)
|
|
{
|
|
// LINE_REQUEST is not masked by the server
|
|
}
|
|
if (lFilterMask & TE_AGENT)
|
|
{
|
|
ulEventMasks |= EM_LINE_AGENTSTATUSEX | EM_LINE_AGENTSTATUS;
|
|
}
|
|
if (lFilterMask & TE_AGENTSESSION)
|
|
{
|
|
ulEventMasks |= EM_LINE_AGENTSESSIONSTATUS;
|
|
}
|
|
if (lFilterMask & TE_QOSEVENT)
|
|
{
|
|
ulEventMasks |= EM_LINE_QOSINFO;
|
|
}
|
|
if (lFilterMask & TE_AGENTHANDLER)
|
|
{
|
|
// TAPI 3 client side only?
|
|
}
|
|
if (lFilterMask & TE_ACDGROUP)
|
|
{
|
|
ulEventMasks |= EM_LINE_GROUPSTATUS;
|
|
}
|
|
if (lFilterMask & TE_QUEUE)
|
|
{
|
|
ulEventMasks |= EM_LINE_QUEUESTATUS;
|
|
}
|
|
if (lFilterMask & TE_DIGITEVENT)
|
|
{
|
|
// LINE_MONITORDIGITS not controled by event filtering
|
|
}
|
|
if (lFilterMask & TE_GENERATEEVENT)
|
|
{
|
|
// LINE_GENERATE not controled by event filtering
|
|
}
|
|
if (lFilterMask & TE_TONEEVENT)
|
|
{
|
|
// LINE_MONITORTONE not controled by event filtering
|
|
}
|
|
if (lFilterMask & TE_GATHERDIGITS)
|
|
{
|
|
// LINE_GATHERDIGITS not controled by event filtering
|
|
}
|
|
|
|
if (lFilterMask & TE_ADDRESSDEVSPECIFIC)
|
|
{
|
|
ulEventMasks |= EM_LINE_DEVSPECIFICEX | EM_LINE_DEVSPECIFIC;
|
|
}
|
|
|
|
if (lFilterMask & TE_PHONEDEVSPECIFIC)
|
|
{
|
|
ulEventMasks |= EM_PHONE_DEVSPECIFIC;
|
|
}
|
|
|
|
|
|
hr = tapiSetEventFilterMasks (
|
|
TAPIOBJ_NULL,
|
|
NULL,
|
|
ulEventMasks
|
|
);
|
|
if (hr == 0)
|
|
{
|
|
hr = tapiSetEventFilterSubMasks (
|
|
TAPIOBJ_NULL,
|
|
NULL,
|
|
EM_LINE_LINEDEVSTATE,
|
|
dwLineDevStateSubMasks
|
|
);
|
|
}
|
|
if (hr == 0)
|
|
{
|
|
hr = tapiSetEventFilterSubMasks (
|
|
TAPIOBJ_NULL,
|
|
NULL,
|
|
EM_LINE_ADDRESSSTATE,
|
|
dwAddrStateSubMasks
|
|
);
|
|
}
|
|
|
|
if (hr != 0)
|
|
{
|
|
hr = mapTAPIErrorCode(hr);
|
|
}
|
|
|
|
LOG((TL_INFO, "put_EventFilter - mask changed %x to %x", dwOldFilterMask, lFilterMask ));
|
|
|
|
}
|
|
|
|
LOG((TL_TRACE,hr, "put_EventFilter - exit "));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// get_EventFilter
|
|
//
|
|
// gets the Event filter mask
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::get_EventFilter(long * plFilterMask)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
LOG((TL_TRACE, "get_EventFilter - enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plFilterMask, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_EventFilter - bad plFilterMask pointer"));
|
|
hr = E_POINTER;
|
|
}
|
|
else
|
|
{
|
|
Lock();
|
|
*plFilterMask = m_dwEventFilterMask;
|
|
Unlock();
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, hr, "get_EventFilter - exit "));
|
|
return hr;
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Interface : ITTAPI2
|
|
// Method : get_Phones
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::get_Phones(
|
|
VARIANT * pPhones
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Phones enter"));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Phones - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_NOT_INITIALIZED;
|
|
}
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( pPhones, sizeof( VARIANT ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Phones - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
CComObject< CTapiCollection< ITPhone > > * p;
|
|
CComObject< CTapiCollection< ITPhone > >::CreateInstance( &p );
|
|
|
|
if (NULL == p)
|
|
{
|
|
LOG((TL_ERROR, "get_Phones - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// get the IDispatch interface
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_Phones - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
Lock();
|
|
|
|
// initialize
|
|
hr = p->Initialize( m_PhoneArray );
|
|
|
|
Unlock();
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "get_Phones - could not initialize collection" ));
|
|
|
|
pDisp->Release();
|
|
return hr;
|
|
}
|
|
|
|
// put it in the variant
|
|
|
|
VariantInit(pPhones);
|
|
pPhones->vt = VT_DISPATCH;
|
|
pPhones->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Phones - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Interface : ITTAPI2
|
|
// Method : EnumeratePhones
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CTAPI::EnumeratePhones(
|
|
IEnumPhone ** ppEnumPhone
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "EnumeratePhones - enter"));
|
|
LOG((TL_TRACE, " ppEnumPhone----->%p", ppEnumPhone ));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_INITIALIZED ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePhones - tapi object must be initialized first" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_NOT_INITIALIZED;
|
|
}
|
|
Unlock();
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumPhone, sizeof( IEnumPhone * ) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePhones - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// create the enumerator
|
|
//
|
|
CComObject< CTapiEnum< IEnumPhone, ITPhone, &IID_IEnumPhone > > * p;
|
|
hr = CComObject< CTapiEnum< IEnumPhone, ITPhone, &IID_IEnumPhone > >
|
|
::CreateInstance( &p );
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePhones - could not create enum" ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
Lock();
|
|
|
|
// initialize it with our phone list, initialize adds a reference to p
|
|
p->Initialize( m_PhoneArray );
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// return it
|
|
//
|
|
*ppEnumPhone = p;
|
|
|
|
LOG((TL_TRACE, "EnumeratePhones - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
// Interface : ITTAPI2
|
|
// Method : CreateEmptyCollectionObject
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTAPI::CreateEmptyCollectionObject(
|
|
ITCollection2 ** ppCollection
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "CreateEmptyCollectionObject enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( ppCollection, sizeof( ITCollection2 * ) ) )
|
|
{
|
|
LOG((TL_ERROR, "CreateEmptyCollectionObject - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
// Initialize the return value in case we fail
|
|
*ppCollection = NULL;
|
|
|
|
CComObject< CTapiCollection< IDispatch > > * p;
|
|
hr = CComObject< CTapiCollection< IDispatch > >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr )
|
|
{
|
|
LOG((TL_ERROR, "CreateEmptyCollectionObject - could not create CTapiCollection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// get the ITCollection2 interface
|
|
hr = p->QueryInterface( IID_ITCollection2, (void **) ppCollection );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "CreateEmptyCollectionObject - could not get ITCollection2 interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_TRACE, "CreateEmptyCollectionObject - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// DoLineCreate
|
|
//
|
|
// handles line_create message. basically, creates a new
|
|
// address object
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::DoLineCreate( DWORD dwDeviceID )
|
|
{
|
|
HRESULT hr;
|
|
|
|
Lock();
|
|
|
|
CreateAddressesOnSingleLine( dwDeviceID, TRUE );
|
|
|
|
Unlock();
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// DoLineRemove( DWORD dwDeviceID )
|
|
//
|
|
// tapisrv has sent a LINE_REMOVE message. find the corresponding
|
|
// address object(s), remove them from our list, and send a
|
|
// message to the app
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::DoLineRemove( DWORD dwDeviceID )
|
|
{
|
|
HRESULT hr;
|
|
ITAddress * pAddress;
|
|
CAddress * pCAddress;
|
|
int iCount;
|
|
#if DBG
|
|
BOOL bFound = FALSE;
|
|
#endif
|
|
|
|
LOG((TL_TRACE, "DoLineRemove - enter - dwDeviceID %d", dwDeviceID));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// go through the addresses
|
|
//
|
|
for(iCount = 0; iCount < m_AddressArray.GetSize(); iCount++)
|
|
{
|
|
pAddress = m_AddressArray[iCount];
|
|
|
|
pCAddress = dynamic_cast<CAddress *>(pAddress);
|
|
|
|
if (pCAddress != NULL)
|
|
{
|
|
//
|
|
// does the device ID match?
|
|
//
|
|
if ( dwDeviceID == pCAddress->GetDeviceID() )
|
|
{
|
|
LOG((TL_INFO, "DoLineRemove - found matching address - %p", pAddress));
|
|
|
|
//
|
|
// make sure the address is in the correct state
|
|
//
|
|
pCAddress->OutOfService(LINEDEVSTATE_REMOVED);
|
|
|
|
//
|
|
// fire event
|
|
//
|
|
CTapiObjectEvent::FireEvent(
|
|
this,
|
|
TE_ADDRESSREMOVE,
|
|
pAddress,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// remove from our list
|
|
//
|
|
LOG((TL_INFO, "DoLineRemove - removing address %p", pAddress));
|
|
m_AddressArray.RemoveAt(iCount);
|
|
|
|
iCount--;
|
|
#if DBG
|
|
bFound = TRUE;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if ( !bFound )
|
|
{
|
|
LOG((TL_WARN, "Receive LINE_REMOVE but couldn't find address object"));
|
|
}
|
|
#endif
|
|
|
|
LOG((TL_TRACE, "DoLineRemove - exiting"));
|
|
Unlock();
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// DoPhoneCreate
|
|
//
|
|
// handles PHONE_CREATE message. basically, creates a new
|
|
// phone object
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::DoPhoneCreate( DWORD dwDeviceID )
|
|
{
|
|
HRESULT hr;
|
|
|
|
Lock();
|
|
|
|
CreatePhone( dwDeviceID, TRUE );
|
|
|
|
Unlock();
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// DoPhoneRemove( DWORD dwDeviceID )
|
|
//
|
|
// tapisrv has sent a PHONE_REMOVE message. find the corresponding
|
|
// phone object(s), remove them from our list, and send a
|
|
// message to the app
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTAPI::DoPhoneRemove( DWORD dwDeviceID )
|
|
{
|
|
HRESULT hr;
|
|
ITPhone * pPhone;
|
|
CPhone * pCPhone;
|
|
int iPhoneCount;
|
|
int iAddressCount;
|
|
#if DBG
|
|
BOOL bFound;
|
|
#endif
|
|
|
|
LOG((TL_TRACE, "DoPhoneRemove - enter - dwDeviceID %d", dwDeviceID));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// go through the phones
|
|
//
|
|
for(iPhoneCount = 0; iPhoneCount < m_PhoneArray.GetSize(); iPhoneCount++)
|
|
{
|
|
pPhone = m_PhoneArray[iPhoneCount];
|
|
|
|
pCPhone = dynamic_cast<CPhone *>(pPhone);
|
|
|
|
if (NULL == pCPhone)
|
|
{
|
|
//
|
|
// something went terribly wrong
|
|
//
|
|
|
|
LOG((TL_ERROR, "DoPhoneRemove - failed to cast ptr %p to a phone object", pPhone));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// does the device ID match?
|
|
//
|
|
if ( dwDeviceID == pCPhone->GetDeviceID() )
|
|
{
|
|
LOG((TL_INFO, "DoPhoneRemove - found matching phone - %p", pPhone));
|
|
|
|
//
|
|
// fire event
|
|
//
|
|
CTapiObjectEvent::FireEvent(this,
|
|
TE_PHONEREMOVE,
|
|
NULL,
|
|
0,
|
|
pPhone
|
|
);
|
|
|
|
//
|
|
// remove from our list
|
|
//
|
|
LOG((TL_INFO, "DoPhoneRemove - removing phone %p", pPhone));
|
|
m_PhoneArray.RemoveAt(iPhoneCount);
|
|
|
|
iPhoneCount--;
|
|
#if DBG
|
|
bFound = TRUE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if ( !bFound )
|
|
{
|
|
LOG((TL_WARN, "Receive PHONE_REMOVE but couldn't find phone object"));
|
|
}
|
|
#endif
|
|
|
|
LOG((TL_TRACE, "DoPhoneRemove - exiting"));
|
|
Unlock();
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
BOOL
|
|
CTAPI::FindTapiObject( CTAPI * pTapi )
|
|
{
|
|
PtrList::iterator iter, end;
|
|
BOOL bFound = FALSE;
|
|
int iReturn = -1;
|
|
|
|
EnterCriticalSection( &gcsTapiObjectArray );
|
|
|
|
//
|
|
// go through the list
|
|
//
|
|
iReturn = m_sTAPIObjectArray.Find( pTapi );
|
|
|
|
if (iReturn != -1)
|
|
{
|
|
pTapi->AddRef();
|
|
bFound = TRUE;
|
|
}
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
return bFound;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetTapiObjectFromAsyncEventMSG
|
|
//
|
|
// this method attempts to get tapi object pointer from PASYNCEVENTMSG
|
|
//
|
|
// it returns NULL on failure or addref'ed tapi object on success
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
CTAPI *GetTapiObjectFromAsyncEventMSG(PASYNCEVENTMSG pParams)
|
|
{
|
|
LOG((TL_TRACE, "GetTapiObjectFromAsyncEventMSG - entered"));
|
|
|
|
|
|
//
|
|
// get pInitData from the structure we have
|
|
//
|
|
|
|
PT3INIT_DATA pInitData = (PT3INIT_DATA) GetHandleTableEntry(pParams->InitContext);
|
|
|
|
if (IsBadReadPtr(pInitData, sizeof(T3INIT_DATA)))
|
|
{
|
|
LOG((TL_WARN, "GetTapiObjectFromAsyncEventMSG - could not recover pInitData"));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// get tapi object from pInitData
|
|
//
|
|
|
|
CTAPI *pTapi = pInitData->pTAPI;
|
|
|
|
|
|
//
|
|
// is it any good?
|
|
//
|
|
|
|
if (IsBadReadPtr(pTapi, sizeof(CTAPI)))
|
|
{
|
|
|
|
LOG((TL_WARN,
|
|
"GetTapiObjectFromAsyncEventMSG - tapi pointer [%p] does not point to readable memory",
|
|
pTapi));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// double check that this is a known tapi object...
|
|
//
|
|
|
|
if (!CTAPI::FindTapiObject(pTapi))
|
|
{
|
|
|
|
//
|
|
// the object is not in the list of tapi objects
|
|
//
|
|
|
|
LOG((TL_WARN,
|
|
"GetTapiObjectFromAsyncEventMSG - CTAPI::FindTapiObject did not find the tapi object [%p]",
|
|
pTapi));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, "GetTapiObjectFromAsyncEventMSG - exit. pTapi %p", pTapi));
|
|
|
|
return pTapi;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
HandleLineCreate( PASYNCEVENTMSG pParams )
|
|
{
|
|
LOG((TL_TRACE, "HandleLineCreate - enter"));
|
|
|
|
|
|
//
|
|
// get tapi object
|
|
//
|
|
|
|
CTAPI *pTapi = GetTapiObjectFromAsyncEventMSG(pParams);
|
|
|
|
if (NULL == pTapi)
|
|
{
|
|
LOG((TL_WARN,
|
|
"HandleLineCreate - tapi object not present [%p]",
|
|
pTapi));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// we have tapi object, do what we have to do.
|
|
//
|
|
|
|
pTapi->DoLineCreate( pParams->Param1 );
|
|
|
|
|
|
//
|
|
// GetTapiObjectFromAsyncEventMSG returned a addref'ed tapi object. release
|
|
//
|
|
|
|
pTapi->Release();
|
|
pTapi = NULL;
|
|
|
|
LOG((TL_TRACE, "HandleLineCreate - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
HandleLineRemove( PASYNCEVENTMSG pParams )
|
|
{
|
|
|
|
LOG((TL_TRACE, "HandleLineRemove - enter"));
|
|
|
|
|
|
//
|
|
// get tapi object
|
|
//
|
|
|
|
CTAPI *pTapi = GetTapiObjectFromAsyncEventMSG(pParams);
|
|
|
|
if (NULL == pTapi)
|
|
{
|
|
LOG((TL_WARN,
|
|
"HandleLineRemove - tapi object not present [%p]",
|
|
pTapi));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// we have tapi object, do what we have to do.
|
|
//
|
|
|
|
pTapi->DoLineRemove( pParams->Param1 );
|
|
|
|
|
|
//
|
|
// GetTapiObjectFromAsyncEventMSG returned a addref'ed tapi object. release
|
|
//
|
|
|
|
pTapi->Release();
|
|
pTapi = NULL;
|
|
|
|
LOG((TL_TRACE, "HandleLineRemove - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
HandlePhoneCreate( PASYNCEVENTMSG pParams )
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneCreate - enter"));
|
|
|
|
|
|
//
|
|
// get tapi object
|
|
//
|
|
|
|
CTAPI *pTapi = GetTapiObjectFromAsyncEventMSG(pParams);
|
|
|
|
if (NULL == pTapi)
|
|
{
|
|
LOG((TL_WARN,
|
|
"HandlePhoneCreate - tapi object not present [%p]",
|
|
pTapi));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// we have tapi object, do what we have to do.
|
|
//
|
|
|
|
pTapi->DoPhoneCreate( pParams->Param1 );
|
|
|
|
|
|
//
|
|
// GetTapiObjectFromAsyncEventMSG returned a addref'ed tapi object. release
|
|
//
|
|
|
|
pTapi->Release();
|
|
pTapi = NULL;
|
|
|
|
LOG((TL_TRACE, "HandlePhoneCreate - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
HandlePhoneRemove( PASYNCEVENTMSG pParams )
|
|
{
|
|
|
|
LOG((TL_TRACE, "HandlePhoneRemove - enter"));
|
|
|
|
|
|
//
|
|
// get tapi object
|
|
//
|
|
|
|
CTAPI *pTapi = GetTapiObjectFromAsyncEventMSG(pParams);
|
|
|
|
if (NULL == pTapi)
|
|
{
|
|
LOG((TL_WARN,
|
|
"HandlePhoneRemove - tapi object not present [%p]",
|
|
pTapi));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// we have tapi object, do what we have to do.
|
|
//
|
|
|
|
pTapi->DoPhoneRemove(pParams->Param1);
|
|
|
|
|
|
//
|
|
// GetTapiObjectFromAsyncEventMSG returned a addref'ed tapi object. release
|
|
//
|
|
|
|
pTapi->Release();
|
|
pTapi = NULL;
|
|
|
|
LOG((TL_TRACE, "HandlePhoneRemove - exit"));
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTapiObjectEvent::FireEvent(
|
|
CTAPI * pTapi,
|
|
TAPIOBJECT_EVENT Event,
|
|
ITAddress * pAddress,
|
|
long lCallbackInstance,
|
|
ITPhone * pPhone
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComObject<CTapiObjectEvent> * p;
|
|
IDispatch * pDisp;
|
|
|
|
//
|
|
// Check the event filter mask
|
|
// This event is not filtered by TapiSrv because is
|
|
// related with TE_TAPIOBJECT, a specific TAPI3 event.
|
|
//
|
|
|
|
DWORD dwEventFilterMask = Event;
|
|
long nTapiEventFilter = 0;
|
|
pTapi->get_EventFilter( &nTapiEventFilter );
|
|
|
|
STATICLOG((TL_INFO, " TapiObjectEventMask ---> %ld", dwEventFilterMask ));
|
|
|
|
if( !( nTapiEventFilter & TE_TAPIOBJECT))
|
|
{
|
|
STATICLOG((TL_WARN, "FireEvent - filtering out this event [%lx]", Event));
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// create event
|
|
//
|
|
hr = CComObject<CTapiObjectEvent>::CreateInstance( &p );
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR, "Could not create TapiObjectEvent object - %lx", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
p->m_Event = Event;
|
|
p->m_pTapi = dynamic_cast<ITTAPI *>(pTapi);
|
|
p->m_pTapi->AddRef();
|
|
p->m_pAddress = pAddress;
|
|
p->m_lCallbackInstance = lCallbackInstance;
|
|
p->m_pPhone = pPhone;
|
|
|
|
if ( NULL != pAddress )
|
|
{
|
|
pAddress->AddRef();
|
|
}
|
|
|
|
if ( NULL != pPhone )
|
|
{
|
|
pPhone->AddRef();
|
|
}
|
|
|
|
#if DBG
|
|
p->m_pDebug = (PWSTR) ClientAlloc( 1 );
|
|
#endif
|
|
|
|
//
|
|
// get idisp interface
|
|
//
|
|
hr = p->QueryInterface(
|
|
IID_IDispatch,
|
|
(void **)&pDisp
|
|
);
|
|
|
|
if ( !SUCCEEDED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR, "Could not get disp interface of TapiObjectEvent object %lx", hr));
|
|
|
|
delete p;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// fire event
|
|
//
|
|
pTapi->Event(
|
|
TE_TAPIOBJECT,
|
|
pDisp
|
|
);
|
|
|
|
//
|
|
// release stuff
|
|
//
|
|
pDisp->Release();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void
|
|
CTapiObjectEvent::FinalRelease(void)
|
|
{
|
|
m_pTapi->Release();
|
|
|
|
if ( NULL != m_pAddress )
|
|
{
|
|
m_pAddress->Release();
|
|
}
|
|
|
|
if ( NULL != m_pPhone )
|
|
{
|
|
m_pPhone->Release();
|
|
}
|
|
|
|
#if DBG
|
|
|
|
ClientFree( m_pDebug );
|
|
|
|
#endif
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTapiObjectEvent::get_TAPIObject( ITTAPI ** ppTapi )
|
|
{
|
|
if ( TAPIIsBadWritePtr( ppTapi, sizeof( ITTAPI *) ) )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppTapi = m_pTapi;
|
|
(*ppTapi)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTapiObjectEvent::get_Event( TAPIOBJECT_EVENT * pEvent )
|
|
{
|
|
if ( TAPIIsBadWritePtr( pEvent, sizeof( TAPIOBJECT_EVENT ) ) )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pEvent = m_Event;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTapiObjectEvent::get_Address( ITAddress ** ppAddress )
|
|
{
|
|
if ( TAPIIsBadWritePtr( ppAddress, sizeof( ITAddress *) ) )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ((m_Event != TE_ADDRESSCREATE) && (m_Event != TE_ADDRESSREMOVE) &&
|
|
(m_Event != TE_ADDRESSCLOSE))
|
|
{
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*ppAddress = m_pAddress;
|
|
|
|
if ( NULL != m_pAddress )
|
|
{
|
|
m_pAddress->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP
|
|
CTapiObjectEvent::get_CallbackInstance( long * plCallbackInstance )
|
|
{
|
|
if ( TAPIIsBadWritePtr( plCallbackInstance, sizeof( long ) ) )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
*plCallbackInstance = m_lCallbackInstance;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Phone
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CTapiObjectEvent::get_Phone(
|
|
ITPhone ** ppPhone
|
|
)
|
|
{
|
|
if ( TAPIIsBadWritePtr( ppPhone , sizeof(ITPhone *) ) )
|
|
{
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ((m_Event != TE_PHONECREATE) && (m_Event != TE_PHONEREMOVE))
|
|
{
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*ppPhone = m_pPhone;
|
|
|
|
if ( NULL != m_pPhone )
|
|
{
|
|
m_pPhone->AddRef();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// HandleReinit
|
|
//
|
|
// we got a reinit message, so go through all the tapi objects, and
|
|
// fire the event
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void
|
|
CTAPI::HandleReinit()
|
|
{
|
|
|
|
LOG((TL_TRACE, "HandleReinit - enter"));
|
|
|
|
//
|
|
// Fire the event
|
|
//
|
|
CTapiObjectEvent::FireEvent(
|
|
this,
|
|
TE_REINIT,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
Lock();
|
|
|
|
m_dwFlags |= TAPIFLAG_REINIT;
|
|
|
|
Unlock();
|
|
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::GetBuffer(
|
|
DWORD dwType,
|
|
UINT_PTR pObject,
|
|
LPVOID * ppBuffer
|
|
)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case BUFFERTYPE_ADDRCAP:
|
|
return m_pAddressCapCache->GetBuffer(
|
|
pObject,
|
|
ppBuffer
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_LINEDEVCAP:
|
|
return m_pLineCapCache->GetBuffer(
|
|
pObject,
|
|
ppBuffer
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_PHONECAP:
|
|
return m_pPhoneCapCache->GetBuffer(
|
|
pObject,
|
|
ppBuffer
|
|
);
|
|
break;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::SetBuffer(
|
|
DWORD dwType,
|
|
UINT_PTR pObject,
|
|
LPVOID pBuffer
|
|
)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case BUFFERTYPE_ADDRCAP:
|
|
return m_pAddressCapCache->SetBuffer(
|
|
pObject,
|
|
pBuffer
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_LINEDEVCAP:
|
|
return m_pLineCapCache->SetBuffer(
|
|
pObject,
|
|
pBuffer
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_PHONECAP:
|
|
return m_pPhoneCapCache->SetBuffer(
|
|
pObject,
|
|
pBuffer
|
|
);
|
|
break;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT
|
|
CTAPI::InvalidateBuffer(
|
|
DWORD dwType,
|
|
UINT_PTR pObject
|
|
)
|
|
{
|
|
switch (dwType)
|
|
{
|
|
case BUFFERTYPE_ADDRCAP:
|
|
return m_pAddressCapCache->InvalidateBuffer(
|
|
pObject
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_LINEDEVCAP:
|
|
return m_pLineCapCache->InvalidateBuffer(
|
|
pObject
|
|
);
|
|
break;
|
|
|
|
case BUFFERTYPE_PHONECAP:
|
|
return m_pPhoneCapCache->InvalidateBuffer(
|
|
pObject
|
|
);
|
|
break;
|
|
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
BOOL
|
|
CTAPI::FindRegistration( PVOID pRegistration )
|
|
{
|
|
PtrList::iterator iter, end;
|
|
|
|
|
|
Lock();
|
|
|
|
iter = m_RegisterItemPtrList.begin();
|
|
end = m_RegisterItemPtrList.end();
|
|
|
|
for ( ; iter != end; iter++ )
|
|
{
|
|
REGISTERITEM * pItem;
|
|
|
|
pItem = (REGISTERITEM *)(*iter);
|
|
|
|
if ( pRegistration == pItem->pRegister )
|
|
{
|
|
Unlock();
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatch implementation
|
|
//
|
|
typedef IDispatchImpl<ITapi2Vtbl<CTAPI>, &IID_ITTAPI2, &LIBID_TAPI3Lib> TapiType;
|
|
typedef IDispatchImpl<ICallCenterVtbl<CTAPI>, &IID_ITTAPICallCenter, &LIBID_TAPI3Lib> CallCenterType;
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::GetIDsOfNames
|
|
//
|
|
// Overide if IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CTAPI::GetIDsOfNames(REFIID riid,
|
|
LPOLESTR* rgszNames,
|
|
UINT cNames,
|
|
LCID lcid,
|
|
DISPID* rgdispid
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_UNKNOWNNAME;
|
|
|
|
|
|
// See if the requsted method belongs to the default interface
|
|
hr = TapiType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITTAPI", *rgszNames));
|
|
rgdispid[0] |= IDISPTAPI;
|
|
return hr;
|
|
}
|
|
|
|
|
|
// If not, then try the Call Center interface
|
|
hr = CallCenterType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_TRACE, "GetIDsOfNames - found %S on ITTAPICallCenter", *rgszNames));
|
|
|
|
Lock();
|
|
if (!( m_dwFlags & TAPIFLAG_CALLCENTER_INITIALIZED ) )
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - Call Center not initialized" ));
|
|
UpdateAgentHandlerArray();
|
|
m_dwFlags |= TAPIFLAG_CALLCENTER_INITIALIZED;
|
|
|
|
LOG((TL_INFO, "GetIDsOfNames - Call Center initialized" ));
|
|
}
|
|
|
|
Unlock();
|
|
rgdispid[0] |= IDISPTAPICALLCENTER;
|
|
return hr;
|
|
}
|
|
|
|
|
|
LOG((TL_INFO, "GetIDsOfNames - Didn't find %S on our iterfaces", *rgszNames));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::Invoke
|
|
//
|
|
// Overide if IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CTAPI::Invoke(DISPID dispidMember,
|
|
REFIID riid,
|
|
LCID lcid,
|
|
WORD wFlags,
|
|
DISPPARAMS* pdispparams,
|
|
VARIANT* pvarResult,
|
|
EXCEPINFO* pexcepinfo,
|
|
UINT* puArgErr
|
|
)
|
|
{
|
|
HRESULT hr = DISP_E_MEMBERNOTFOUND;
|
|
DWORD dwInterface = (dispidMember & INTERFACEMASK);
|
|
|
|
|
|
LOG((TL_TRACE, "Invoke - dispidMember %X", dispidMember));
|
|
|
|
// Call invoke for the required interface
|
|
switch (dwInterface)
|
|
{
|
|
case IDISPTAPI:
|
|
{
|
|
hr = TapiType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
case IDISPTAPICALLCENTER:
|
|
{
|
|
hr = CallCenterType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
|
|
} // end switch (dwInterface)
|
|
|
|
|
|
LOG((TL_TRACE, hr, "Invoke - exit" ));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CTAPI::SetEventFilterToAddresses
|
|
//
|
|
// Copy the event filter down to all addresses
|
|
// It's called by put_EventFilter() method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
HRESULT CTAPI::SetEventFilterToAddresses(
|
|
DWORD dwEventFilterMask
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "CopyEventFilterMaskToAddresses enter"));
|
|
|
|
CAddress* pAddress = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Enumerate the addresses
|
|
//
|
|
for ( int iAddress = 0; iAddress < m_AddressArray.GetSize(); iAddress++ )
|
|
{
|
|
pAddress = dynamic_cast<CAddress *>(m_AddressArray[iAddress]);
|
|
|
|
if( pAddress != NULL )
|
|
{
|
|
hr = pAddress->SetEventFilterMask(
|
|
dwEventFilterMask
|
|
);
|
|
|
|
if( FAILED(hr) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "CopyEventFilterMaskToAddresses exit 0x%08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CTAPI::IsValidTapiObject
|
|
//
|
|
// a helper static function that checks if it was passed a valid tapi object
|
|
//
|
|
// if the object is valid, the function addrefs it and returns TRUE
|
|
// if the object is not valid, the function returns true
|
|
//
|
|
// static
|
|
BOOL CTAPI::IsValidTapiObject(CTAPI *pTapiObject)
|
|
{
|
|
|
|
STATICLOG((TL_TRACE, "CTAPI::IsValidTapiObject enter[%p]", pTapiObject));
|
|
|
|
|
|
//
|
|
// before we go into trouble of checking tapi object array see if the ptr
|
|
// is readable at all
|
|
//
|
|
|
|
if ( IsBadReadPtr(pTapiObject, sizeof(CTAPI) ) )
|
|
{
|
|
STATICLOG((TL_WARN, "CTAPI::IsValidTapiObject - object not readabe"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// see if this object is in the array of tapi objects
|
|
//
|
|
|
|
EnterCriticalSection( &gcsTapiObjectArray );
|
|
|
|
if (-1 == m_sTAPIObjectArray.Find(pTapiObject) )
|
|
{
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
STATICLOG((TL_WARN, "CTAPI::IsValidTapiObject - object not in the array"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// the object is in the array, so it must be valid, addref it
|
|
//
|
|
|
|
try
|
|
{
|
|
|
|
//
|
|
// inside try, in case something else went bad
|
|
//
|
|
|
|
pTapiObject->AddRef();
|
|
|
|
}
|
|
catch(...)
|
|
{
|
|
|
|
|
|
//
|
|
// the object is in the array, but we had problems addrefing.
|
|
// something's not kosher.
|
|
//
|
|
|
|
STATICLOG((TL_ERROR,
|
|
"CTAPI::IsValidTapiObject - object in in the array but addref threw"));
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
LeaveCriticalSection ( &gcsTapiObjectArray );
|
|
|
|
STATICLOG((TL_TRACE, "CTAPI::IsValidTapiObject -- finish. the object is valid"));
|
|
|
|
return TRUE;
|
|
}
|