/*++ 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 > * 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 >::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(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(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(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 > * 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 >::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 * pAddress; ITAddress * pITAddress; try { hr = CComObject::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(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 * pPhone; ITPhone * pITPhone; __try { hr = CComObject::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(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(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(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(pCallHub); m_CallHubArray.Add( pITCallHub ); Unlock(); } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= // // RemoveCallHub // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= void CTAPI::RemoveCallHub( CCallHub * pCallHub ) { ITCallHub * pITCallHub; Lock(); pITCallHub = dynamic_cast(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(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(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 * 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::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(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, &IID_ITTAPI2, &LIBID_TAPI3Lib> TapiType; typedef IDispatchImpl, &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(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; }