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.
10596 lines
273 KiB
10596 lines
273 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
phone.cpp
|
|
|
|
Abstract:
|
|
|
|
Implementation of phone object for TAPI 3.1
|
|
|
|
Notes:
|
|
|
|
optional-notes
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#define TIMER_KEEP_ALIVE 0x0FFFFFFF
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IDispatch implementation
|
|
//
|
|
|
|
typedef IDispatchImpl<ITPhoneVtbl<CPhone>,
|
|
&IID_ITPhone,
|
|
&LIBID_TAPI3Lib>
|
|
PhoneType;
|
|
|
|
typedef IDispatchImpl<ITAutomatedPhoneControlVtbl<CPhone>,
|
|
&IID_ITAutomatedPhoneControl,
|
|
&LIBID_TAPI3Lib>
|
|
AutomatedPhoneControlType;
|
|
|
|
|
|
|
|
extern HRESULT mapTAPIErrorCode(long lErrorCode);
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CPhone::GetIDsOfNames
|
|
//
|
|
// Overidden IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP CPhone::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 = PhoneType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITPhone", *rgszNames));
|
|
rgdispid[0] |= IDISPPHONE;
|
|
return hr;
|
|
}
|
|
|
|
// If not, then try the ITAutomatedPhoneControl interface
|
|
hr = AutomatedPhoneControlType::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LOG((TL_INFO, "GetIDsOfNames - found %S on ITAutomatedPhoneControl", *rgszNames));
|
|
rgdispid[0] |= IDISPAPC;
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_INFO, "GetIDsOfNames - Didn't find %S on our iterfaces", *rgszNames));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CPhone::Invoke
|
|
//
|
|
// Overide if IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP CPhone::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 IDISPPHONE:
|
|
{
|
|
hr = PhoneType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
case IDISPAPC:
|
|
{
|
|
hr = AutomatedPhoneControlType::Invoke(dispidMember,
|
|
riid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
break;
|
|
}
|
|
|
|
} // end switch (dwInterface)
|
|
|
|
|
|
LOG((TL_TRACE, hr, "Invoke - exit" ));
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CPhone::InternalAddRef
|
|
//
|
|
// Overidden IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP_(ULONG) CPhone::InternalAddRef()
|
|
{
|
|
DWORD dwR;
|
|
|
|
dwR = InterlockedIncrement(&m_dwRef);
|
|
|
|
LOG((TL_INFO, "InternalAddRef - dwR %d",dwR ));
|
|
|
|
#if DBG
|
|
LogDebugAddRef(m_dwRef);
|
|
#endif
|
|
|
|
return dwR;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// CPhone::InternalRelease
|
|
//
|
|
// Overidden IDispatch method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
STDMETHODIMP_(ULONG) CPhone::InternalRelease()
|
|
{
|
|
DWORD dwR;
|
|
PtrList::iterator iter, end;
|
|
T3LINE * pt3Line;
|
|
|
|
LOG((TL_INFO, "InternalRelease - m_dwRef %d",m_dwRef ));
|
|
Lock();
|
|
|
|
gpPhoneHashTable->Lock();
|
|
|
|
dwR = InterlockedDecrement(&m_dwRef);
|
|
|
|
// if ref count is 0 (means we entered function with 1) then we final release
|
|
if (0 == dwR)
|
|
{
|
|
// remove from the hash table, so any more messages
|
|
// from tapisrv are ignored
|
|
//
|
|
|
|
if (m_hPhone)
|
|
{
|
|
if(FAILED(gpPhoneHashTable->Remove( (ULONG_PTR)(m_hPhone) ) ))
|
|
{
|
|
LOG((TL_INFO, "InternalRelease - pLineHashTable->Remove failed" ));
|
|
}
|
|
}
|
|
|
|
gpPhoneHashTable->Unlock();
|
|
|
|
dwR = m_dwRef = 0;
|
|
|
|
Unlock();
|
|
LOG((TL_INFO, "InternalRelease - final OK dwR %d",dwR ));
|
|
}
|
|
else
|
|
{
|
|
gpPhoneHashTable->Unlock();
|
|
Unlock();
|
|
LOG((TL_INFO, "InternalRelease - not final dwR %d",dwR ));
|
|
}
|
|
|
|
#if DBG
|
|
LogDebugRelease( dwR );
|
|
#endif
|
|
|
|
return dwR;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ITPhone methods
|
|
//
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Open
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::Open(
|
|
PHONE_PRIVILEGE Privilege
|
|
)
|
|
{
|
|
DWORD dwPrivilege;
|
|
T3PHONE t3Phone;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "Open - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// We cannot be opened multiple time simultaneously
|
|
// return TAPI_E_INUSE if someone else has us open
|
|
//
|
|
if (m_hPhone)
|
|
{
|
|
LOG((TL_TRACE, "Open - phone in use" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_INUSE;
|
|
}
|
|
|
|
switch(Privilege)
|
|
{
|
|
case PP_OWNER:
|
|
dwPrivilege = PHONEPRIVILEGE_OWNER;
|
|
break;
|
|
case PP_MONITOR:
|
|
dwPrivilege = PHONEPRIVILEGE_MONITOR;
|
|
break;
|
|
default:
|
|
{
|
|
LOG((TL_TRACE, "Open - invalid privilege" ));
|
|
|
|
Unlock();
|
|
return TAPI_E_INVALPRIVILEGE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
t3Phone.hPhone = NULL;
|
|
t3Phone.pPhone = this;
|
|
|
|
hr = PhoneOpen(m_hPhoneApp, m_dwDeviceID, &t3Phone, m_dwAPIVersion, dwPrivilege);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
|
|
hr = PhoneSetStatusMessages(&t3Phone,
|
|
PHONESTATE_CAPSCHANGE |
|
|
PHONESTATE_HANDSETHOOKSWITCH |
|
|
PHONESTATE_HEADSETHOOKSWITCH |
|
|
PHONESTATE_LAMP |
|
|
PHONESTATE_RINGMODE |
|
|
PHONESTATE_RINGVOLUME |
|
|
PHONESTATE_SPEAKERHOOKSWITCH |
|
|
PHONESTATE_DISPLAY,
|
|
PHONEBUTTONMODE_CALL |
|
|
PHONEBUTTONMODE_DISPLAY |
|
|
PHONEBUTTONMODE_DUMMY |
|
|
PHONEBUTTONMODE_FEATURE |
|
|
PHONEBUTTONMODE_KEYPAD |
|
|
PHONEBUTTONMODE_LOCAL,
|
|
PHONEBUTTONSTATE_UP |
|
|
PHONEBUTTONSTATE_DOWN |
|
|
PHONEBUTTONSTATE_UNKNOWN |
|
|
PHONEBUTTONSTATE_UNAVAIL);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
m_hPhone = t3Phone.hPhone;
|
|
|
|
m_dwPrivilege = dwPrivilege;
|
|
}
|
|
else
|
|
{
|
|
PhoneClose(t3Phone.hPhone);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Defaults for phone automation settings
|
|
//
|
|
|
|
m_fPhoneHandlingEnabled = FALSE;
|
|
m_dwAutoEndOfNumberTimeout = APC_DEFAULT_AEONT;
|
|
m_fAutoDialtone = TRUE;
|
|
m_fAutoStopTonesOnOnHook = TRUE;
|
|
m_fAutoStopRingOnOffHook = TRUE;
|
|
m_fAutoKeypadTones = TRUE;
|
|
m_dwAutoKeypadTonesMinimumDuration = APC_DEFAULT_AKTMD;
|
|
m_fAutoVolumeControl = TRUE;
|
|
m_dwAutoVolumeControlStep = APC_DEFAULT_VCS;
|
|
m_dwAutoVolumeControlRepeatDelay = APC_DEFAULT_VCRD;
|
|
m_dwAutoVolumeControlRepeatPeriod = APC_DEFAULT_VCRP;
|
|
|
|
Unlock();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_TRACE, "Open - PhoneOpen returned failure - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_TRACE, "Open - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Close
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::Close()
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "Close - enter" ));
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_WARN, "Close - phone not open - return S_OK"));
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
if (m_dwPrivilege == PHONEPRIVILEGE_OWNER)
|
|
{
|
|
//
|
|
// Turn off automatic phone handling
|
|
//
|
|
|
|
m_fPhoneHandlingEnabled = FALSE;
|
|
|
|
//
|
|
// Stop any ringers or tones
|
|
//
|
|
|
|
if (m_fRinger == TRUE)
|
|
{
|
|
StopRinger();
|
|
}
|
|
|
|
if (m_Tone != PT_SILENCE)
|
|
{
|
|
StopTone();
|
|
}
|
|
|
|
CloseWaveDevice();
|
|
|
|
//
|
|
// Unselect any calls
|
|
//
|
|
|
|
if (m_pCall != NULL)
|
|
{
|
|
InternalUnselectCall(m_pCall);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Finally, actually close the phone
|
|
//
|
|
|
|
hr = PhoneClose(m_hPhone);
|
|
|
|
m_hPhone = NULL;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "Close - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Addresses
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_Addresses(
|
|
VARIANT *pAddresses
|
|
)
|
|
{
|
|
IEnumAddress * pEnum;
|
|
ITAddress * pAddress;
|
|
AddressArray aAddresses;
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Addresses - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pAddresses, sizeof (VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// get the addresses from tapi
|
|
//
|
|
hr = m_pTAPI->EnumerateAddresses( &pEnum );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not enumerate addresses from tapi - return %lx", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// choose only addresses that this phone is on
|
|
//
|
|
while ( S_OK == pEnum->Next( 1, &pAddress, NULL ) )
|
|
{
|
|
if (IsPhoneOnAddress( pAddress ))
|
|
{
|
|
if ( !aAddresses.Add( pAddress ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could add address to array"));
|
|
}
|
|
}
|
|
|
|
pAddress->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the collection
|
|
//
|
|
CComObject< CTapiCollection< ITAddress > > * p;
|
|
hr = CComObject< CTapiCollection< ITAddress > >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch interface
|
|
//
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
hr = p->Initialize( aAddresses );
|
|
|
|
aAddresses.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_Addresses - could not initialize collection" ));
|
|
|
|
pDisp->Release();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// put it in the variant
|
|
//
|
|
|
|
VariantInit(pAddresses);
|
|
pAddresses->vt = VT_DISPATCH;
|
|
pAddresses->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Addresses - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// EnumerateAddresses
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::EnumerateAddresses(
|
|
IEnumAddress ** ppEnumAddress
|
|
)
|
|
{
|
|
IEnumAddress * pEnumAddress;
|
|
ITAddress * pAddress;
|
|
AddressArray aAddresses;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "EnumerateAddresses - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumAddress, sizeof (IEnumAddress *) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// get the addresses from tapi
|
|
//
|
|
hr = m_pTAPI->EnumerateAddresses( &pEnumAddress );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - could not enumerate addresses from tapi - return %lx", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// choose only addresses that this phone is on
|
|
//
|
|
while ( S_OK == pEnumAddress->Next( 1, &pAddress, NULL ) )
|
|
{
|
|
if (IsPhoneOnAddress( pAddress ))
|
|
{
|
|
if ( !aAddresses.Add( pAddress ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - could add address to array"));
|
|
}
|
|
}
|
|
|
|
pAddress->Release();
|
|
}
|
|
|
|
pEnumAddress->Release();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the enum
|
|
//
|
|
CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> > * pEnum;
|
|
hr = CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> >::CreateInstance( &pEnum );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "EnumerateAddresses - could not create enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = pEnum->Initialize( aAddresses );
|
|
|
|
aAddresses.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
pEnum->Release();
|
|
|
|
LOG((TL_ERROR, "EnumerateAddresses - could not initialize enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppEnumAddress = pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateAddresses - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_PreferredAddresses
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_PreferredAddresses(
|
|
VARIANT *pAddresses
|
|
)
|
|
{
|
|
IEnumAddress * pEnum;
|
|
ITAddress * pAddress;
|
|
AddressArray aAddresses;
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
|
|
LOG((TL_TRACE, "get_PreferredAddresses - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pAddresses, sizeof (VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// get the addresses from tapi
|
|
//
|
|
hr = m_pTAPI->EnumerateAddresses( &pEnum );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - could not enumerate addresses from tapi - return %lx", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// choose only addresses that this phone is on
|
|
//
|
|
while ( S_OK == pEnum->Next( 1, &pAddress, NULL ) )
|
|
{
|
|
if (IsPhoneOnPreferredAddress( pAddress ))
|
|
{
|
|
if ( !aAddresses.Add( pAddress ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - could add address to array"));
|
|
}
|
|
}
|
|
|
|
pAddress->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the collection
|
|
//
|
|
CComObject< CTapiCollection< ITAddress > > * p;
|
|
hr = CComObject< CTapiCollection< ITAddress > >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch interface
|
|
//
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
hr = p->Initialize( aAddresses );
|
|
|
|
aAddresses.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_PreferredAddresses - could not initialize collection" ));
|
|
|
|
pDisp->Release();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// put it in the variant
|
|
//
|
|
|
|
VariantInit(pAddresses);
|
|
pAddresses->vt = VT_DISPATCH;
|
|
pAddresses->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_PreferredAddresses - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// EnumeratePreferredAddresses
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::EnumeratePreferredAddresses(
|
|
IEnumAddress ** ppEnumAddress
|
|
)
|
|
{
|
|
IEnumAddress * pEnumAddress;
|
|
ITAddress * pAddress;
|
|
AddressArray aAddresses;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "EnumeratePreferredAddresses - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumAddress, sizeof (IEnumAddress *) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePreferredAddresses - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// get the addresses from tapi
|
|
//
|
|
hr = m_pTAPI->EnumerateAddresses( &pEnumAddress );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePreferredAddresses - could not enumerate addresses from tapi - return %lx", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// choose only addresses that this phone is on
|
|
//
|
|
while ( S_OK == pEnumAddress->Next( 1, &pAddress, NULL ) )
|
|
{
|
|
if (IsPhoneOnPreferredAddress( pAddress ))
|
|
{
|
|
if ( !aAddresses.Add( pAddress ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePreferredAddresses - could add address to array"));
|
|
}
|
|
}
|
|
|
|
pAddress->Release();
|
|
}
|
|
|
|
pEnumAddress->Release();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the enum
|
|
//
|
|
CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> > * pEnum;
|
|
hr = CComObject< CTapiEnum<IEnumAddress, ITAddress, &IID_IEnumAddress> >::CreateInstance( &pEnum );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "EnumeratePreferredAddresses - could not create enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = pEnum->Initialize( aAddresses );
|
|
|
|
aAddresses.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
pEnum->Release();
|
|
|
|
LOG((TL_ERROR, "EnumeratePreferredAddresses - could not initialize enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppEnumAddress = pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumeratePreferredAddresses - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_PhoneCapsLong
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_PhoneCapsLong(
|
|
PHONECAPS_LONG pclCap,
|
|
long * plCapability
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( TAPIIsBadWritePtr( plCapability, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsLong - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
LOG((TL_TRACE, "get_PhoneCapsLong - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Update the cache
|
|
//
|
|
hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsLong - could not get phonecaps"));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
switch (pclCap)
|
|
{
|
|
case PCL_HOOKSWITCHES:
|
|
*plCapability = m_pPhoneCaps->dwHookSwitchDevs;
|
|
break;
|
|
|
|
case PCL_HANDSETHOOKSWITCHMODES:
|
|
*plCapability = m_pPhoneCaps->dwHandsetHookSwitchModes;
|
|
break;
|
|
|
|
case PCL_HEADSETHOOKSWITCHMODES:
|
|
*plCapability = m_pPhoneCaps->dwHeadsetHookSwitchModes;
|
|
break;
|
|
|
|
case PCL_SPEAKERPHONEHOOKSWITCHMODES:
|
|
*plCapability = m_pPhoneCaps->dwSpeakerHookSwitchModes;
|
|
break;
|
|
|
|
case PCL_DISPLAYNUMROWS:
|
|
*plCapability = m_pPhoneCaps->dwDisplayNumRows;
|
|
break;
|
|
|
|
case PCL_DISPLAYNUMCOLUMNS:
|
|
*plCapability = m_pPhoneCaps->dwDisplayNumColumns;
|
|
break;
|
|
|
|
case PCL_NUMRINGMODES:
|
|
*plCapability = m_pPhoneCaps->dwNumRingModes;
|
|
break;
|
|
|
|
case PCL_NUMBUTTONLAMPS:
|
|
*plCapability = m_pPhoneCaps->dwNumButtonLamps;
|
|
break;
|
|
|
|
case PCL_GENERICPHONE:
|
|
if( m_dwAPIVersion >= TAPI_VERSION2_0 )
|
|
{
|
|
*plCapability = (m_pPhoneCaps->dwPhoneFeatures & PHONEFEATURE_GENERICPHONE) ? 1:0;
|
|
}
|
|
else
|
|
{
|
|
*plCapability = 0;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_PhoneCapsLong - bad pclCap"));
|
|
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_PhoneCapsLong - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_PhoneCapsString
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_PhoneCapsString(
|
|
PHONECAPS_STRING pcsCap,
|
|
BSTR * ppCapability
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if ( TAPIIsBadWritePtr( ppCapability, sizeof(BSTR) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsString - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
LOG((TL_TRACE, "get_PhoneCapsString - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Update the cache
|
|
//
|
|
hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsString - could not get phonecaps - %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
DWORD dwSize;
|
|
DWORD dwOffset;
|
|
|
|
//
|
|
// Get the size and offset of the string in the phone caps
|
|
//
|
|
switch (pcsCap)
|
|
{
|
|
case PCS_PHONENAME:
|
|
dwSize = m_pPhoneCaps->dwPhoneNameSize;
|
|
dwOffset = m_pPhoneCaps->dwPhoneNameOffset;
|
|
break;
|
|
|
|
case PCS_PHONEINFO:
|
|
dwSize = m_pPhoneCaps->dwPhoneInfoSize;
|
|
dwOffset = m_pPhoneCaps->dwPhoneInfoOffset;
|
|
break;
|
|
|
|
case PCS_PROVIDERINFO:
|
|
dwSize = m_pPhoneCaps->dwProviderInfoSize;
|
|
dwOffset = m_pPhoneCaps->dwProviderInfoOffset;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_PhoneCapsString - bad pcsCap"));
|
|
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Allocate the BSTR
|
|
//
|
|
if ( dwSize != 0 )
|
|
{
|
|
*ppCapability = SysAllocString( (LPWSTR)(((LPBYTE)(m_pPhoneCaps)) + dwOffset) );
|
|
|
|
if ( NULL == *ppCapability )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsString - SysAllocString failed - E_OUTOFMEMORY"));
|
|
|
|
Unlock();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_PhoneCapsString - exit - return S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Terminals
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_Terminals(
|
|
ITAddress * pAddress,
|
|
VARIANT * pTerminals
|
|
)
|
|
{
|
|
IEnumTerminal * pEnumTerminal;
|
|
ITTerminal * pTerminal;
|
|
ITStaticAudioTerminal * pStaticAudioTerminal;
|
|
TerminalArray aTerminals;
|
|
HRESULT hr;
|
|
IDispatch * pDisp;
|
|
ITTerminalSupport * pTerminalSupport;
|
|
LONG lMediaType;
|
|
TERMINAL_DIRECTION nDir;
|
|
|
|
LOG((TL_TRACE, "get_Terminals - enter" ));
|
|
|
|
if ( IsBadReadPtr( pAddress, sizeof (ITAddress) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( TAPIIsBadWritePtr( pTerminals, sizeof (VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Get the ITTerminalSupport interface
|
|
//
|
|
hr = pAddress->QueryInterface(IID_ITTerminalSupport, (void **) &pTerminalSupport);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// Get all the terminals on this address
|
|
//
|
|
hr = pTerminalSupport->EnumerateStaticTerminals( &pEnumTerminal );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
while ( S_OK == pEnumTerminal->Next( 1, &pTerminal, NULL ) )
|
|
{
|
|
hr = pTerminal->get_MediaType(&lMediaType);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = pTerminal->get_Direction(&nDir);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// we only care about audio terminals
|
|
//
|
|
|
|
if (lMediaType == TAPIMEDIATYPE_AUDIO)
|
|
{
|
|
//
|
|
// we only care about terminals which implement ITStaticAudioTerminal
|
|
// because we need to get the wave ID
|
|
//
|
|
|
|
hr = pTerminal->QueryInterface(IID_ITStaticAudioTerminal,
|
|
(void **) &pStaticAudioTerminal);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LONG lWaveId;
|
|
|
|
hr = pStaticAudioTerminal->get_WaveId(&lWaveId);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_INFO, "get_Terminals - got terminal wave id %d", lWaveId));
|
|
|
|
if (IsPhoneUsingWaveID( lWaveId, nDir ))
|
|
{
|
|
if ( !aTerminals.Add( pTerminal ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - could add terminal to array"));
|
|
}
|
|
}
|
|
}
|
|
pStaticAudioTerminal->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "get_Terminals - could not get terminal direction - %lx", hr));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "get_Terminals - could not get terminal media type - %lx", hr));
|
|
}
|
|
|
|
pTerminal->Release();
|
|
}
|
|
pEnumTerminal->Release();
|
|
}
|
|
pTerminalSupport->Release();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the collection
|
|
//
|
|
CComObject< CTapiCollection< ITTerminal > > * p;
|
|
hr = CComObject< CTapiCollection< ITTerminal > >::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - could not create collection" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// get the IDispatch interface
|
|
//
|
|
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = p->Initialize( aTerminals );
|
|
|
|
aTerminals.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - could not initialize collection" ));
|
|
|
|
pDisp->Release();
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// put it in the variant
|
|
//
|
|
|
|
VariantInit(pTerminals);
|
|
pTerminals->vt = VT_DISPATCH;
|
|
pTerminals->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_Terminals - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// EnumerateTerminals
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::EnumerateTerminals(
|
|
ITAddress * pAddress,
|
|
IEnumTerminal ** ppEnumTerminal
|
|
)
|
|
{
|
|
IEnumTerminal * pEnumTerminal;
|
|
ITTerminal * pTerminal;
|
|
ITStaticAudioTerminal * pStaticAudioTerminal;
|
|
TerminalArray aTerminals;
|
|
HRESULT hr;
|
|
ITTerminalSupport * pTerminalSupport;
|
|
LONG lMediaType;
|
|
TERMINAL_DIRECTION nDir;
|
|
|
|
LOG((TL_TRACE, "EnumerateTerminals - enter" ));
|
|
|
|
if ( IsBadReadPtr( pAddress, sizeof (ITAddress) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( TAPIIsBadWritePtr( ppEnumTerminal, sizeof (IEnumTerminal *) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateTerminals - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Get the ITTerminalSupport interface
|
|
//
|
|
hr = pAddress->QueryInterface(IID_ITTerminalSupport, (void **) &pTerminalSupport);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// Get all the terminals on this address
|
|
//
|
|
hr = pTerminalSupport->EnumerateStaticTerminals( &pEnumTerminal );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
while ( S_OK == pEnumTerminal->Next( 1, &pTerminal, NULL ) )
|
|
{
|
|
hr = pTerminal->get_MediaType(&lMediaType);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = pTerminal->get_Direction(&nDir);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// we only care about audio terminals
|
|
//
|
|
|
|
if (lMediaType == TAPIMEDIATYPE_AUDIO)
|
|
{
|
|
//
|
|
// we only care about terminals which implement ITStaticAudioTerminal
|
|
// because we need to get the wave ID
|
|
//
|
|
|
|
hr = pTerminal->QueryInterface(IID_ITStaticAudioTerminal,
|
|
(void **) &pStaticAudioTerminal);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LONG lWaveId;
|
|
|
|
hr = pStaticAudioTerminal->get_WaveId(&lWaveId);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_INFO, "get_Terminals - got terminal wave id %d", lWaveId));
|
|
|
|
if (IsPhoneUsingWaveID( lWaveId, nDir ))
|
|
{
|
|
if ( !aTerminals.Add( pTerminal ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Terminals - could add terminal to array"));
|
|
}
|
|
}
|
|
}
|
|
pStaticAudioTerminal->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "get_Terminals - could not get terminal direction - %lx", hr));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_WARN, "get_Terminals - could not get terminal media type - %lx", hr));
|
|
}
|
|
|
|
pTerminal->Release();
|
|
}
|
|
pEnumTerminal->Release();
|
|
}
|
|
pTerminalSupport->Release();
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// create the enum
|
|
//
|
|
CComObject< CTapiEnum<IEnumTerminal, ITTerminal, &IID_IEnumTerminal> > * pEnum;
|
|
hr = CComObject< CTapiEnum<IEnumTerminal, ITTerminal, &IID_IEnumTerminal> >::CreateInstance( &pEnum );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "EnumerateTerminals - could not create enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
hr = pEnum->Initialize( aTerminals );
|
|
|
|
aTerminals.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
pEnum->Release();
|
|
|
|
LOG((TL_ERROR, "EnumerateTerminals - could not initialize enum - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
*ppEnumTerminal = pEnum;
|
|
|
|
LOG((TL_TRACE, "EnumerateTerminals - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_ButtonMode(
|
|
long lButtonID,
|
|
PHONE_BUTTON_MODE * pButtonMode
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwNumButtons;
|
|
LPPHONEBUTTONINFO pButtonInfo;
|
|
|
|
LOG((TL_TRACE, "get_ButtonMode - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pButtonMode, sizeof(PHONE_BUTTON_MODE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonMode - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonMode - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// Get the ButtonInfo buffer
|
|
//
|
|
hr = PhoneGetButtonInfo(
|
|
m_hPhone,
|
|
lButtonID,
|
|
&pButtonInfo
|
|
);
|
|
|
|
Unlock();
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch ( pButtonInfo->dwButtonMode )
|
|
{
|
|
case PHONEBUTTONMODE_CALL:
|
|
*pButtonMode = PBM_CALL;
|
|
break;
|
|
|
|
case PHONEBUTTONMODE_DISPLAY:
|
|
*pButtonMode = PBM_DISPLAY;
|
|
break;
|
|
|
|
case PHONEBUTTONMODE_DUMMY:
|
|
*pButtonMode = PBM_DUMMY;
|
|
break;
|
|
|
|
case PHONEBUTTONMODE_FEATURE:
|
|
*pButtonMode = PBM_FEATURE;
|
|
break;
|
|
|
|
case PHONEBUTTONMODE_KEYPAD:
|
|
*pButtonMode = PBM_KEYPAD;
|
|
break;
|
|
|
|
case PHONEBUTTONMODE_LOCAL:
|
|
*pButtonMode = PBM_LOCAL;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_ButtonMode - bad button mode"));
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Free the ButtonInfo buffer
|
|
//
|
|
ClientFree( pButtonInfo );
|
|
}
|
|
|
|
LOG((TL_TRACE, "get_ButtonMode - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_ButtonMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_ButtonMode(
|
|
long lButtonID,
|
|
PHONE_BUTTON_MODE ButtonMode
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "put_ButtonMode - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonMode - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonMode - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// get info for this button
|
|
//
|
|
|
|
PHONEBUTTONINFO *pButtonInfo = NULL;
|
|
|
|
hr = PhoneGetButtonInfo(m_hPhone, lButtonID, &pButtonInfo);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonMode - failed to get button info"));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// make sure the memory we got back is writeable
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(pButtonInfo, sizeof(PHONEBUTTONINFO)))
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonMode - PhoneGetButtonInfo returned a bad memory block"));
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
|
|
//
|
|
// set the appropriate button mode in the structure that we have. leave everything else unchanged
|
|
//
|
|
|
|
switch (ButtonMode)
|
|
{
|
|
case PBM_DUMMY:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_DUMMY;
|
|
break;
|
|
|
|
case PBM_CALL:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_CALL;
|
|
break;
|
|
|
|
case PBM_FEATURE:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_FEATURE;
|
|
break;
|
|
|
|
case PBM_KEYPAD:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_KEYPAD;
|
|
break;
|
|
|
|
case PBM_LOCAL:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_LOCAL;
|
|
break;
|
|
|
|
case PBM_DISPLAY:
|
|
pButtonInfo->dwButtonMode = PHONEBUTTONMODE_DISPLAY;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "put_ButtonMode - bad ButtonMode"));
|
|
|
|
Unlock();
|
|
|
|
ClientFree(pButtonInfo);
|
|
pButtonInfo = NULL;
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// set the new button mode
|
|
//
|
|
|
|
hr = PhoneSetButtonInfo(m_hPhone, lButtonID, pButtonInfo);
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// free memory returned to us by PhoneGetButtonInfo
|
|
//
|
|
|
|
ClientFree(pButtonInfo);
|
|
pButtonInfo = NULL;
|
|
|
|
LOG((TL_TRACE, "put_ButtonMode - put_ButtonMode - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_ButtonText
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_ButtonText(
|
|
long lButtonID,
|
|
BSTR bstrButtonText
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "put_ButtonText - enter" ));
|
|
|
|
if ( IsBadStringPtrW(bstrButtonText, -1) )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - invalid parameter",
|
|
"exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// get info for this button
|
|
//
|
|
|
|
PHONEBUTTONINFO *pButtonInfo = NULL;
|
|
|
|
hr = PhoneGetButtonInfo(m_hPhone, lButtonID, &pButtonInfo);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - failed to get button info"));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// make sure the memory we got back is writeable
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr(pButtonInfo, sizeof(PHONEBUTTONINFO)) )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - PhoneGetButtonInfo returned a bad memory block"));
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
DWORD dwButtonTextLength = SysStringByteLen(bstrButtonText);
|
|
|
|
//
|
|
// add the string to the structure we have. if the new string fits in
|
|
// place of the old string, put it in there. otherwise, allocate a bigger
|
|
// structure and append the new string at the end
|
|
//
|
|
|
|
if ( dwButtonTextLength <= pButtonInfo->dwButtonTextSize )
|
|
{
|
|
CopyMemory((BYTE*)pButtonInfo + pButtonInfo->dwButtonTextOffset,
|
|
bstrButtonText,
|
|
dwButtonTextLength);
|
|
|
|
pButtonInfo->dwButtonTextSize = dwButtonTextLength;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// create the new structure that will have everything the old one does + the new string
|
|
//
|
|
|
|
DWORD dwBiggerStructureSize = pButtonInfo->dwTotalSize + dwButtonTextLength;
|
|
|
|
//
|
|
// allocate the new, bigger structure
|
|
//
|
|
|
|
PHONEBUTTONINFO *pBiggerButtonInfo = (PHONEBUTTONINFO *)ClientAlloc(dwBiggerStructureSize);
|
|
|
|
if ( NULL == pBiggerButtonInfo )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonText - failed to allocate memory for the new structure"));
|
|
|
|
ClientFree(pButtonInfo);
|
|
|
|
Unlock();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// copy the old data into the bigger structure
|
|
//
|
|
|
|
CopyMemory(pBiggerButtonInfo, pButtonInfo, pButtonInfo->dwTotalSize);
|
|
|
|
//
|
|
// append the new structure with the new string (the new text starts after the old data)
|
|
//
|
|
|
|
//
|
|
// set the offset and size for the text in the new structure
|
|
//
|
|
|
|
pBiggerButtonInfo->dwButtonTextOffset = pButtonInfo->dwTotalSize;
|
|
pBiggerButtonInfo->dwButtonTextSize = dwButtonTextLength;
|
|
|
|
//
|
|
// copy the text to the end of the new structure
|
|
//
|
|
|
|
CopyMemory((BYTE*)pBiggerButtonInfo + pBiggerButtonInfo->dwButtonTextOffset,
|
|
bstrButtonText,
|
|
dwButtonTextLength);
|
|
|
|
//
|
|
// set the size of the new structure
|
|
//
|
|
|
|
pBiggerButtonInfo->dwTotalSize = dwBiggerStructureSize;
|
|
|
|
//
|
|
// free memory allocated by the old structure
|
|
//
|
|
|
|
ClientFree(pButtonInfo);
|
|
|
|
//
|
|
// pButtonInfo will now point to the new structure
|
|
//
|
|
|
|
pButtonInfo = pBiggerButtonInfo;
|
|
pBiggerButtonInfo = NULL;
|
|
}
|
|
|
|
//
|
|
// set the new button text
|
|
//
|
|
|
|
hr = PhoneSetButtonInfo(m_hPhone, lButtonID, pButtonInfo);
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// free memory returned to us by PhoneGetButtonInfo
|
|
//
|
|
|
|
ClientFree(pButtonInfo);
|
|
pButtonInfo = NULL;
|
|
|
|
LOG((TL_TRACE, "put_ButtonText - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_PhoneCapsBuffer
|
|
//
|
|
// returns the requested buffer from phone capapabilities array --
|
|
// the scriptable version
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_PhoneCapsBuffer(
|
|
IN PHONECAPS_BUFFER pcbCaps,
|
|
OUT VARIANT *pVarBuffer
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_PhoneCapsBuffer[%p] - enter", this ));
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr( pVarBuffer, sizeof(VARIANT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsBuffer - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// get the buffer
|
|
//
|
|
|
|
DWORD dwBufferSize = 0;
|
|
|
|
BYTE *pBuffer = NULL;
|
|
|
|
|
|
HRESULT hr = GetPhoneCapsBuffer(pcbCaps, &dwBufferSize, &pBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsBuffer - failed to get phone caps buffer"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
VariantInit(pVarBuffer);
|
|
|
|
//
|
|
// fill the variant with the data buffer
|
|
//
|
|
|
|
hr = FillVariantFromBuffer(dwBufferSize, pBuffer, pVarBuffer);
|
|
|
|
//
|
|
// no longer need the buffer -- we hope that now have all the data in the variant
|
|
//
|
|
|
|
CoTaskMemFree(pBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneCapsBuffer - failed to copy phone caps buffer to a variant"));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((TL_TRACE, "get_PhoneCapsBuffer - exit - return S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// GetPhoneCapsBuffer
|
|
//
|
|
// returns the requested buffer from phone capapabilities array
|
|
//
|
|
// on success, the caller must call CoTaskMemFree to free the buffer that is
|
|
// returned by this method
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::GetPhoneCapsBuffer(
|
|
IN PHONECAPS_BUFFER pcbCaps,
|
|
OUT DWORD *pdwSize,
|
|
OUT BYTE **ppPhoneCapsBuffer
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "GetPhoneCapsBuffer - enter" ));
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr( ppPhoneCapsBuffer, sizeof(BYTE*) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneCapsBuffer - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppPhoneCapsBuffer = NULL;
|
|
|
|
if ( TAPIIsBadWritePtr( pdwSize, sizeof(DWORD) ) )
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneCapsBuffer - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pdwSize = 0;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// update phone capabilities cache
|
|
//
|
|
|
|
HRESULT hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneCapsBuffer - could not get phonecaps"));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
switch (pcbCaps)
|
|
{
|
|
|
|
case PCB_DEVSPECIFICBUFFER:
|
|
{
|
|
//
|
|
// allocate the buffer for device-specific caps
|
|
//
|
|
|
|
*pdwSize = m_pPhoneCaps->dwDevSpecificSize;
|
|
|
|
*ppPhoneCapsBuffer = static_cast<BYTE*>(CoTaskMemAlloc(*pdwSize));
|
|
|
|
if (NULL == *ppPhoneCapsBuffer)
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneCapsBuffer - could not allocate memory for the output buffer"));
|
|
|
|
Unlock();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// copy data to the buffer to be returned to the caller
|
|
//
|
|
|
|
CopyMemory( *ppPhoneCapsBuffer,
|
|
(BYTE*)m_pPhoneCaps + m_pPhoneCaps->dwDevSpecificOffset,
|
|
*pdwSize);
|
|
|
|
break;
|
|
}
|
|
default:
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "GetPhoneCapsBuffer - unknown capability type %x", pcbCaps));
|
|
|
|
return E_INVALIDARG;
|
|
|
|
break;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "GetPhoneCapsBuffer - exit - return S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Display
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_Display(
|
|
BSTR *pbstrDisplay
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LONG lResult;
|
|
LPVARSTRING pVarString = NULL;
|
|
|
|
LOG((TL_TRACE, "get_Display - enter" ));
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr( pbstrDisplay, sizeof(BSTR) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Display - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_Display - phone not open"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
hr = PhoneGetDisplay(m_hPhone, &pVarString);
|
|
|
|
Unlock();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to get display. hr = %lx", hr));
|
|
|
|
if (NULL != pVarString)
|
|
{
|
|
ClientFree(pVarString);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// succeeded. extract display information and place it in the the output bstr
|
|
//
|
|
|
|
hr = S_OK;
|
|
|
|
switch (pVarString->dwStringFormat)
|
|
{
|
|
|
|
case STRINGFORMAT_ASCII:
|
|
{
|
|
int nWCHARSNeeded = MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
(char*)((BYTE*)pVarString + pVarString->dwStringOffset),
|
|
pVarString->dwStringSize,
|
|
NULL,
|
|
0);
|
|
|
|
if (0 == nWCHARSNeeded)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to get the size of the buffer needed for the display. LastError = %lx", GetLastError()));
|
|
|
|
hr = E_FAIL;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// allocate the buffer required for conversion
|
|
//
|
|
|
|
LPWSTR lpWideCharStr = (LPWSTR)ClientAlloc(sizeof(WCHAR) * nWCHARSNeeded);
|
|
|
|
if (NULL == lpWideCharStr)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to allocate memory for lpWideCharStr" ));
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// perform conversion
|
|
//
|
|
|
|
int nResult = MultiByteToWideChar(CP_ACP,
|
|
0,
|
|
(char*)((BYTE*)pVarString + pVarString->dwStringOffset),
|
|
pVarString->dwStringSize,
|
|
lpWideCharStr,
|
|
nWCHARSNeeded);
|
|
|
|
if (0 == nResult)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to convert string to wchar. last error %lx", GetLastError()));
|
|
|
|
ClientFree(lpWideCharStr);
|
|
|
|
hr = E_FAIL;
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// allocate bstr and initialize it with the converted string
|
|
//
|
|
|
|
*pbstrDisplay = SysAllocString(lpWideCharStr);
|
|
|
|
//
|
|
// no longer need the wchar string -- we hope the data is in bstr
|
|
//
|
|
|
|
ClientFree(lpWideCharStr);
|
|
|
|
if (NULL == *pbstrDisplay)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to allocate memory for bstr"));
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case STRINGFORMAT_BINARY:
|
|
|
|
//
|
|
// allocate bstr and copy data as is
|
|
//
|
|
|
|
*pbstrDisplay = SysAllocStringByteLen(NULL, pVarString->dwStringSize);
|
|
|
|
if (NULL == *pbstrDisplay)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to allocate memory for bstr"));
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
|
|
CopyMemory(*pbstrDisplay, ((BYTE*)pVarString + pVarString->dwStringOffset), pVarString->dwStringSize);
|
|
|
|
break;
|
|
|
|
case STRINGFORMAT_DBCS:
|
|
|
|
LOG((TL_ERROR, "get_Display - unsupported string format"));
|
|
|
|
hr = E_FAIL;
|
|
|
|
break;
|
|
|
|
case STRINGFORMAT_UNICODE:
|
|
{
|
|
WCHAR *pwcDisplay = (WCHAR*)((BYTE*)pVarString + pVarString->dwStringOffset);
|
|
|
|
*pbstrDisplay = SysAllocString(pwcDisplay);
|
|
|
|
|
|
if (NULL == *pbstrDisplay)
|
|
{
|
|
LOG((TL_ERROR, "get_Display - failed to allocate memory for bstr"));
|
|
|
|
hr = E_OUTOFMEMORY;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ClientFree(pVarString);
|
|
pVarString = NULL;
|
|
|
|
LOG((TL_ERROR, "get_Display - tapisrv returned unrecognized string type %lx", pVarString->dwStringFormat));
|
|
|
|
hr = E_FAIL;
|
|
|
|
break;
|
|
}
|
|
|
|
ClientFree(pVarString);
|
|
pVarString = NULL;
|
|
|
|
LOG((TL_TRACE, "get_Display - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// SetDisplay
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::SetDisplay(
|
|
long lRow,
|
|
long lColumn,
|
|
BSTR bstrDisplay
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "SetDisplay - enter" ));
|
|
|
|
if (bstrDisplay == NULL)
|
|
{
|
|
LOG((TL_ERROR, "SetDisplay - invalid parameter",
|
|
"exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "SetDisplay - phone not open"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// pass the text to tapisrv
|
|
//
|
|
|
|
hr = PhoneSetDisplay(
|
|
m_hPhone,
|
|
lRow,
|
|
lColumn,
|
|
(char*)bstrDisplay,
|
|
SysStringByteLen(bstrDisplay));
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "SetDisplay - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonFunction
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_ButtonFunction(
|
|
long lButtonID,
|
|
PHONE_BUTTON_FUNCTION * pButtonFunction
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwNumButtons;
|
|
LPPHONEBUTTONINFO pButtonInfo;
|
|
|
|
LOG((TL_TRACE, "get_ButtonFunction - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pButtonFunction, sizeof(PHONE_BUTTON_FUNCTION) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonFunction - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonFunction - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// get the ButtonInfo buffer
|
|
//
|
|
hr = PhoneGetButtonInfo(
|
|
m_hPhone,
|
|
lButtonID,
|
|
&pButtonInfo
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch ( pButtonInfo->dwButtonFunction )
|
|
{
|
|
case PHONEBUTTONFUNCTION_ABBREVDIAL:
|
|
*pButtonFunction = PBF_ABBREVDIAL;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_BUSY:
|
|
*pButtonFunction = PBF_BUSY;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_BRIDGEDAPP:
|
|
*pButtonFunction = PBF_BRIDGEDAPP;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_CALLAPP:
|
|
*pButtonFunction = PBF_CALLAPP;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_CALLID:
|
|
*pButtonFunction = PBF_CALLID;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_CAMPON:
|
|
*pButtonFunction = PBF_CAMPON;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_COVER:
|
|
*pButtonFunction = PBF_COVER;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_CONFERENCE:
|
|
*pButtonFunction = PBF_CONFERENCE;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_CONNECT:
|
|
*pButtonFunction = PBF_CONNECT;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DATAOFF:
|
|
*pButtonFunction = PBF_DATAOFF;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DATAON:
|
|
*pButtonFunction = PBF_DATAON;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DATETIME:
|
|
*pButtonFunction = PBF_DATETIME;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DIRECTORY:
|
|
*pButtonFunction = PBF_DIRECTORY;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DISCONNECT:
|
|
*pButtonFunction = PBF_DISCONNECT;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DONOTDISTURB:
|
|
*pButtonFunction = PBF_DONOTDISTURB;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_DROP:
|
|
*pButtonFunction = PBF_DROP;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_FLASH:
|
|
*pButtonFunction = PBF_FLASH;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_FORWARD:
|
|
*pButtonFunction = PBF_FORWARD;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_HOLD:
|
|
*pButtonFunction = PBF_HOLD;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_INTERCOM:
|
|
*pButtonFunction = PBF_INTERCOM;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_LASTNUM:
|
|
*pButtonFunction = PBF_LASTNUM;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_MSGINDICATOR:
|
|
*pButtonFunction = PBF_MSGINDICATOR;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_MSGWAITOFF:
|
|
*pButtonFunction = PBF_MSGWAITOFF;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_MSGWAITON:
|
|
*pButtonFunction = PBF_MSGWAITON;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_MUTE:
|
|
*pButtonFunction = PBF_MUTE;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_NIGHTSRV:
|
|
*pButtonFunction = PBF_NIGHTSRV;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_NONE:
|
|
*pButtonFunction = PBF_NONE;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_PARK:
|
|
*pButtonFunction = PBF_PARK;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_PICKUP:
|
|
*pButtonFunction = PBF_PICKUP;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_QUEUECALL:
|
|
*pButtonFunction = PBF_QUEUECALL;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_RECALL:
|
|
*pButtonFunction = PBF_RECALL;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_REDIRECT:
|
|
*pButtonFunction = PBF_REDIRECT;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_REJECT:
|
|
*pButtonFunction = PBF_REJECT;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_REPDIAL:
|
|
*pButtonFunction = PBF_REPDIAL;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_RINGAGAIN:
|
|
*pButtonFunction = PBF_RINGAGAIN;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SAVEREPEAT:
|
|
*pButtonFunction = PBF_SAVEREPEAT;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SELECTRING:
|
|
*pButtonFunction = PBF_SELECTRING;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SETREPDIAL:
|
|
*pButtonFunction = PBF_SETREPDIAL;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SENDCALLS:
|
|
*pButtonFunction = PBF_SENDCALLS;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SPEAKEROFF:
|
|
*pButtonFunction = PBF_SPEAKEROFF;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SPEAKERON:
|
|
*pButtonFunction = PBF_SPEAKERON;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_STATIONSPEED:
|
|
*pButtonFunction = PBF_STATIONSPEED;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SYSTEMSPEED:
|
|
*pButtonFunction = PBF_SYSTEMSPEED;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_TRANSFER:
|
|
*pButtonFunction = PBF_TRANSFER;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_UNKNOWN:
|
|
*pButtonFunction = PBF_UNKNOWN;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_VOLUMEDOWN:
|
|
*pButtonFunction = PBF_VOLUMEDOWN;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_VOLUMEUP:
|
|
*pButtonFunction = PBF_VOLUMEUP;
|
|
break;
|
|
|
|
case PHONEBUTTONFUNCTION_SEND:
|
|
*pButtonFunction = PBF_SEND;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_ButtonFunction - bad button function"));
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Free the ButtonInfo buffer
|
|
//
|
|
ClientFree( pButtonInfo );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_ButtonFunction - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_ButtonFunction
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_ButtonFunction(
|
|
IN long lButtonID,
|
|
IN PHONE_BUTTON_FUNCTION ButtonFunction
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "put_ButtonFunction - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonFunction - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonFunction - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// get info for this button
|
|
//
|
|
|
|
PHONEBUTTONINFO *pButtonInfo = NULL;
|
|
|
|
hr = PhoneGetButtonInfo(m_hPhone, lButtonID, &pButtonInfo);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonFunction - failed to get button info - %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// make sure the memory we got back is writeable
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(pButtonInfo, sizeof(PHONEBUTTONINFO)))
|
|
{
|
|
LOG((TL_ERROR, "put_ButtonFunction - PhoneGetButtonInfo returned a bad memory block"));
|
|
|
|
Unlock();
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
//
|
|
// translate PHONE_BUTTON_FUNCTION to a DWORD value understood by tapisrv
|
|
//
|
|
|
|
DWORD dwButtonFunction = 0;
|
|
|
|
switch ( ButtonFunction )
|
|
{
|
|
case PBF_ABBREVDIAL:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_ABBREVDIAL;
|
|
break;
|
|
|
|
case PBF_BUSY:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_BUSY;
|
|
break;
|
|
|
|
case PBF_BRIDGEDAPP:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_BRIDGEDAPP;
|
|
break;
|
|
|
|
case PBF_CALLAPP:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_CALLAPP;
|
|
break;
|
|
|
|
case PBF_CALLID:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_CALLID;
|
|
break;
|
|
|
|
case PBF_CAMPON:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_CAMPON;
|
|
break;
|
|
|
|
case PBF_COVER:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_COVER;
|
|
break;
|
|
|
|
case PBF_CONFERENCE:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_CONFERENCE;
|
|
break;
|
|
|
|
case PBF_CONNECT:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_CONNECT;
|
|
break;
|
|
|
|
case PBF_DATAOFF:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DATAOFF;
|
|
break;
|
|
|
|
case PBF_DATAON:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DATAON;
|
|
break;
|
|
|
|
case PBF_DATETIME:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DATETIME;
|
|
break;
|
|
|
|
case PBF_DIRECTORY:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DIRECTORY;
|
|
break;
|
|
|
|
case PBF_DISCONNECT:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DISCONNECT;
|
|
break;
|
|
|
|
case PBF_DONOTDISTURB:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DONOTDISTURB;
|
|
break;
|
|
|
|
case PBF_DROP:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_DROP;
|
|
break;
|
|
|
|
case PBF_FLASH:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_FLASH;
|
|
break;
|
|
|
|
case PBF_FORWARD:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_FORWARD;
|
|
break;
|
|
|
|
case PBF_HOLD:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_HOLD;
|
|
break;
|
|
|
|
case PBF_INTERCOM:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_INTERCOM;
|
|
break;
|
|
|
|
case PBF_LASTNUM:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_LASTNUM;
|
|
break;
|
|
|
|
case PBF_MSGINDICATOR:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_MSGINDICATOR;
|
|
break;
|
|
|
|
case PBF_MSGWAITOFF:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_MSGWAITOFF;
|
|
break;
|
|
|
|
case PBF_MSGWAITON:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_MSGWAITON;
|
|
break;
|
|
|
|
case PBF_MUTE:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_MUTE;
|
|
break;
|
|
|
|
case PBF_NIGHTSRV:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_NIGHTSRV;
|
|
break;
|
|
|
|
case PBF_NONE:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_NONE;
|
|
break;
|
|
|
|
case PBF_PARK:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_PARK;
|
|
break;
|
|
|
|
case PBF_PICKUP:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_PICKUP;
|
|
break;
|
|
|
|
case PBF_QUEUECALL:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_QUEUECALL;
|
|
break;
|
|
|
|
case PBF_RECALL:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_RECALL;
|
|
break;
|
|
|
|
case PBF_REDIRECT:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_REDIRECT;
|
|
break;
|
|
|
|
case PBF_REJECT:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_REJECT;
|
|
break;
|
|
|
|
case PBF_REPDIAL:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_REPDIAL;
|
|
break;
|
|
|
|
case PBF_RINGAGAIN:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_RINGAGAIN;
|
|
break;
|
|
|
|
case PBF_SAVEREPEAT:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SAVEREPEAT;
|
|
break;
|
|
|
|
case PBF_SELECTRING:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SELECTRING;
|
|
break;
|
|
|
|
case PBF_SETREPDIAL:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SETREPDIAL;
|
|
break;
|
|
|
|
case PBF_SENDCALLS:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SENDCALLS;
|
|
break;
|
|
|
|
case PBF_SPEAKEROFF:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SPEAKEROFF;
|
|
break;
|
|
|
|
case PBF_SPEAKERON:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SPEAKERON;
|
|
break;
|
|
|
|
case PBF_STATIONSPEED:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_STATIONSPEED;
|
|
break;
|
|
|
|
case PBF_SYSTEMSPEED:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SYSTEMSPEED;
|
|
break;
|
|
|
|
case PBF_TRANSFER:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_TRANSFER;
|
|
break;
|
|
|
|
case PBF_UNKNOWN:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_UNKNOWN;
|
|
break;
|
|
|
|
case PBF_VOLUMEDOWN:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_VOLUMEDOWN;
|
|
break;
|
|
|
|
case PBF_VOLUMEUP:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_VOLUMEUP;
|
|
break;
|
|
|
|
case PBF_SEND:
|
|
dwButtonFunction = PHONEBUTTONFUNCTION_SEND;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "put_ButtonFunction - bad ButtonFunction"));
|
|
|
|
Unlock();
|
|
|
|
ClientFree(pButtonInfo);
|
|
pButtonInfo = NULL;
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// put the value into the structure to be passed to tapisrv
|
|
//
|
|
|
|
pButtonInfo->dwButtonFunction = dwButtonFunction;
|
|
|
|
//
|
|
// set the new button function
|
|
//
|
|
|
|
hr = PhoneSetButtonInfo(m_hPhone, lButtonID, pButtonInfo);
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// free memory returned to us by PhoneGetButtonInfo
|
|
//
|
|
|
|
ClientFree(pButtonInfo);
|
|
pButtonInfo = NULL;
|
|
|
|
LOG((TL_TRACE, "put_ButtonFunction - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonText
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_ButtonText(
|
|
long lButtonID,
|
|
BSTR * ppButtonText
|
|
)
|
|
{
|
|
LPPHONEBUTTONINFO pButtonInfo;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "get_ButtonText - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( ppButtonText, sizeof(BSTR) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonText - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonText - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// Get the ButtonInfo buffer
|
|
//
|
|
hr = PhoneGetButtonInfo(
|
|
m_hPhone,
|
|
lButtonID,
|
|
&pButtonInfo
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( pButtonInfo->dwButtonTextSize != 0 )
|
|
{
|
|
//
|
|
// Allocate the BSTR
|
|
//
|
|
*ppButtonText = SysAllocString( (LPWSTR)(((LPBYTE)(pButtonInfo)) + pButtonInfo->dwButtonTextOffset) );
|
|
|
|
if ( NULL == *ppButtonText )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonText - SysAllocString Failed"));
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonText - button has no text"));
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Free the ButtonInfo buffer
|
|
//
|
|
ClientFree( pButtonInfo );
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_ButtonText - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonState
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_ButtonState(
|
|
long lButtonID,
|
|
PHONE_BUTTON_STATE * pButtonState
|
|
)
|
|
{
|
|
LPPHONEBUTTONINFO pButtonInfo;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "get_ButtonState - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pButtonState, sizeof(PHONE_BUTTON_STATE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonState - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonState - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// Get the ButtonInfo buffer
|
|
//
|
|
hr = PhoneGetButtonInfo(
|
|
m_hPhone,
|
|
lButtonID,
|
|
&pButtonInfo
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonState - failed to get get button info"));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
switch (pButtonInfo->dwButtonState)
|
|
{
|
|
case PHONEBUTTONSTATE_UP:
|
|
*pButtonState = PBS_UP;
|
|
break;
|
|
case PHONEBUTTONSTATE_DOWN:
|
|
*pButtonState = PBS_DOWN;
|
|
break;
|
|
case PHONEBUTTONSTATE_UNKNOWN:
|
|
*pButtonState = PBS_UNKNOWN;
|
|
break;
|
|
case PHONEBUTTONSTATE_UNAVAIL:
|
|
*pButtonState = PBS_UNAVAIL;
|
|
break;
|
|
default:
|
|
LOG((TL_ERROR, "get_ButtonState - bad button state"));
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
//
|
|
// Free the ButtonInfo buffer
|
|
//
|
|
ClientFree( pButtonInfo );
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_ButtonState - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_LampMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_LampMode(
|
|
long lLampID,
|
|
PHONE_LAMP_MODE* pLampMode
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_LampMode - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pLampMode, sizeof(PHONE_LAMP_MODE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_LampMode - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_LampMode - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// get lamp mode from tapisrv
|
|
//
|
|
|
|
DWORD dwLampMode = 0;
|
|
|
|
HRESULT hr = PhoneGetLamp(m_hPhone, lLampID, &dwLampMode);
|
|
|
|
Unlock();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_ERROR, "get_LampMode - failed to get lamp mode - %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// map the value returned by tapisrv to tapi3.x value
|
|
//
|
|
|
|
switch (dwLampMode)
|
|
{
|
|
case PHONELAMPMODE_DUMMY:
|
|
*pLampMode = LM_DUMMY;
|
|
break;
|
|
|
|
case PHONELAMPMODE_BROKENFLUTTER:
|
|
*pLampMode = LM_BROKENFLUTTER;
|
|
break;
|
|
|
|
case PHONELAMPMODE_FLASH:
|
|
*pLampMode = LM_FLASH;
|
|
break;
|
|
|
|
case PHONELAMPMODE_FLUTTER:
|
|
*pLampMode = LM_FLUTTER;
|
|
break;
|
|
|
|
case PHONELAMPMODE_OFF:
|
|
*pLampMode = LM_OFF;
|
|
break;
|
|
|
|
case PHONELAMPMODE_STEADY:
|
|
*pLampMode = LM_STEADY;
|
|
break;
|
|
|
|
case PHONELAMPMODE_UNKNOWN:
|
|
*pLampMode = LM_UNKNOWN;
|
|
break;
|
|
|
|
case PHONELAMPMODE_WINK :
|
|
*pLampMode = LM_WINK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_LampMode - bad lamp mode received from tapisrv"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
LOG((TL_TRACE, "get_LampMode - exit - return S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_LampMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_LampMode(
|
|
long lLampID,
|
|
PHONE_LAMP_MODE enLampMode
|
|
)
|
|
{
|
|
|
|
LOG((TL_TRACE, "put_LampMode - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_LampMode - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_LampMode - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// map PHONE_LAMP_MODE to the dword value understood by tapisrv
|
|
//
|
|
|
|
DWORD dwLampMode = 0;
|
|
|
|
switch (enLampMode)
|
|
{
|
|
case LM_DUMMY:
|
|
dwLampMode = PHONELAMPMODE_DUMMY;
|
|
break;
|
|
|
|
case LM_BROKENFLUTTER:
|
|
dwLampMode = PHONELAMPMODE_BROKENFLUTTER;
|
|
break;
|
|
|
|
case LM_FLASH:
|
|
dwLampMode = PHONELAMPMODE_FLASH;
|
|
break;
|
|
|
|
case LM_FLUTTER:
|
|
dwLampMode = PHONELAMPMODE_FLUTTER;
|
|
break;
|
|
|
|
case LM_OFF:
|
|
dwLampMode = PHONELAMPMODE_OFF;
|
|
break;
|
|
|
|
case LM_STEADY:
|
|
dwLampMode = PHONELAMPMODE_STEADY;
|
|
break;
|
|
|
|
case LM_UNKNOWN:
|
|
dwLampMode = PHONELAMPMODE_UNKNOWN;
|
|
break;
|
|
|
|
case LM_WINK:
|
|
dwLampMode = PHONELAMPMODE_WINK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "put_LampMode - unknown lamp mode"));
|
|
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// make a call to tapisrv to set lamp mode
|
|
//
|
|
|
|
HRESULT hr = PhoneSetLamp(m_hPhone, lLampID, dwLampMode);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_LampMode - exit - return %lx", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_HookSwitchState
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_HookSwitchState(
|
|
PHONE_HOOK_SWITCH_DEVICE HookSwitchDevice,
|
|
PHONE_HOOK_SWITCH_STATE * pHookSwitchState
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
LPPHONESTATUS pPhoneStatus;
|
|
DWORD dwHookSwitchMode;
|
|
|
|
LOG((TL_TRACE, "get_HookSwitchState - enter" ));
|
|
|
|
if ( 0 == HookSwitchDevice )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - invalid hookswitch"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( TAPIIsBadWritePtr( pHookSwitchState, sizeof(PHONE_HOOK_SWITCH_STATE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// Update the phone caps cache
|
|
//
|
|
hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - could not get phonecaps - %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( !(m_pPhoneCaps->dwHookSwitchDevs & HookSwitchDevice) )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - invalid hookswitch"));
|
|
Unlock();
|
|
|
|
return TAPI_E_RESOURCEUNAVAIL;
|
|
}
|
|
|
|
//
|
|
// Get the PhoneStatus buffer
|
|
//
|
|
hr = PhoneGetStatusWithAlloc(m_hPhone, &pPhoneStatus);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// get the proper hookswitch mode from the phone status struct
|
|
//
|
|
switch (HookSwitchDevice)
|
|
{
|
|
case PHSD_HANDSET:
|
|
dwHookSwitchMode = pPhoneStatus->dwHandsetHookSwitchMode;
|
|
break;
|
|
case PHSD_SPEAKERPHONE:
|
|
dwHookSwitchMode = pPhoneStatus->dwSpeakerHookSwitchMode;
|
|
break;
|
|
case PHSD_HEADSET:
|
|
dwHookSwitchMode = pPhoneStatus->dwHeadsetHookSwitchMode;
|
|
break;
|
|
default:
|
|
LOG((TL_ERROR, "get_HookSwitchState - bad HookSwitchDevice"));
|
|
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
if ( pPhoneStatus != NULL )
|
|
{
|
|
//
|
|
// Free the PhoneStatusBuffer
|
|
//
|
|
ClientFree( pPhoneStatus );
|
|
}
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
//
|
|
// translate the hookswitch mode to a tapi3 value
|
|
//
|
|
switch (dwHookSwitchMode)
|
|
{
|
|
case PHONEHOOKSWITCHMODE_ONHOOK:
|
|
*pHookSwitchState = PHSS_ONHOOK;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MIC:
|
|
*pHookSwitchState = PHSS_OFFHOOK_MIC_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_SPEAKER:
|
|
*pHookSwitchState = PHSS_OFFHOOK_SPEAKER_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MICSPEAKER:
|
|
*pHookSwitchState = PHSS_OFFHOOK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "get_HookSwitchState - bad dwHookSwitchMode"));
|
|
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_HookSwitchState - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_HookSwitchState
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_HookSwitchState(
|
|
PHONE_HOOK_SWITCH_DEVICE HookSwitchDevice,
|
|
PHONE_HOOK_SWITCH_STATE HookSwitchState
|
|
)
|
|
{
|
|
DWORD dwHookSwitchMode;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "put_HookSwitchState - enter" ));
|
|
|
|
if ( 0 == HookSwitchDevice )
|
|
{
|
|
LOG((TL_ERROR, "put_HookSwitchState - invalid hookswitch"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_HookSwitchState - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_HookSwitchState - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Update the phone caps cache
|
|
//
|
|
hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_HookSwitchState - could not get phonecaps - %lx", hr));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( !(m_pPhoneCaps->dwHookSwitchDevs & HookSwitchDevice) )
|
|
{
|
|
LOG((TL_ERROR, "put_HookSwitchState - invalid hookswitch"));
|
|
Unlock();
|
|
|
|
return TAPI_E_RESOURCEUNAVAIL;
|
|
}
|
|
|
|
//
|
|
// Translate the hookswithstate from tapi3 to tapi2 values
|
|
//
|
|
switch (HookSwitchState)
|
|
{
|
|
case PHSS_ONHOOK:
|
|
dwHookSwitchMode = PHONEHOOKSWITCHMODE_ONHOOK;
|
|
break;
|
|
|
|
case PHSS_OFFHOOK_MIC_ONLY:
|
|
dwHookSwitchMode = PHONEHOOKSWITCHMODE_MIC;
|
|
break;
|
|
|
|
case PHSS_OFFHOOK_SPEAKER_ONLY:
|
|
dwHookSwitchMode = PHONEHOOKSWITCHMODE_SPEAKER;
|
|
break;
|
|
|
|
case PHSS_OFFHOOK:
|
|
dwHookSwitchMode = PHONEHOOKSWITCHMODE_MICSPEAKER;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "put_HookSwitchState - bad HookSwitchMode"));
|
|
Unlock();
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Set the proper hookswitch
|
|
//
|
|
switch (HookSwitchDevice)
|
|
{
|
|
case PHSD_HANDSET:
|
|
hr = PhoneSetHookSwitch(m_hPhone, PHONEHOOKSWITCHDEV_HANDSET, dwHookSwitchMode);
|
|
break;
|
|
|
|
case PHSD_SPEAKERPHONE:
|
|
hr = PhoneSetHookSwitch(m_hPhone, PHONEHOOKSWITCHDEV_SPEAKER, dwHookSwitchMode);
|
|
break;
|
|
|
|
case PHSD_HEADSET:
|
|
hr = PhoneSetHookSwitch(m_hPhone, PHONEHOOKSWITCHDEV_HEADSET, dwHookSwitchMode);
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "put_HookSwitchState - bad HookSwitchDevice"));
|
|
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_HookSwitchState - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_RingMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_RingMode(
|
|
long lRingMode
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_TRACE, "put_RingMode - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_RingMode - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_RingMode - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
hr = PhoneGetRing(m_hPhone, &dwDummy, &dwVolume);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_RingMode - PhoneGetRing failed"));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = PhoneSetRing(m_hPhone, lRingMode, dwVolume );
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_RingMode - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_RingMode
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_RingMode(
|
|
long * plRingMode
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
|
|
LOG((TL_TRACE, "get_RingMode - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( plRingMode, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_RingMode - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_RingMode - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
hr = PhoneGetRing(m_hPhone, (LPDWORD)plRingMode, &dwDummy);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_RingMode - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// put_RingVolume
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::put_RingVolume(
|
|
long lRingVolume
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
DWORD dwMode;
|
|
|
|
LOG((TL_TRACE, "put_RingVolume - enter" ));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_RingVolume - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_RingVolume - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
hr = PhoneGetRing(m_hPhone, &dwMode, &dwDummy);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "put_RingVolume - PhoneGetRing failed"));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = PhoneSetRing(m_hPhone, dwMode, lRingVolume );
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_RingVolume - exit" ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_RingVolume
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_RingVolume(
|
|
long * plRingVolume
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
|
|
LOG((TL_TRACE, "get_RingVolume - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( plRingVolume, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_RingVolume - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_RingVolume - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
hr = PhoneGetRing(m_hPhone, &dwDummy, (LPDWORD)plRingVolume );
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_RingVolume - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Privilege
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhone::get_Privilege(
|
|
PHONE_PRIVILEGE * pPrivilege
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG((TL_TRACE, "get_Privilege - enter" ));
|
|
|
|
if ( TAPIIsBadWritePtr( pPrivilege, sizeof(PHONE_PRIVILEGE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Privilege - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_Privilege - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
switch(m_dwPrivilege)
|
|
{
|
|
case PHONEPRIVILEGE_OWNER:
|
|
*pPrivilege = PP_OWNER;
|
|
break;
|
|
case PHONEPRIVILEGE_MONITOR:
|
|
*pPrivilege = PP_MONITOR;
|
|
break;
|
|
default:
|
|
_ASSERTE(FALSE);
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Privilege - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Initialize
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CPhone::Initialize(
|
|
ITTAPI * pTAPI,
|
|
HPHONEAPP hPhoneApp,
|
|
DWORD dwAPIVersion,
|
|
DWORD dwDeviceID
|
|
)
|
|
{
|
|
LPVARSTRING pVarString = NULL;
|
|
LONG lResult;
|
|
T3PHONE t3Phone;
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "Initialize - enter" ));
|
|
LOG((TL_INFO, " hPhoneApp --------->%lx", hPhoneApp ));
|
|
LOG((TL_INFO, " dwAPIVersion ------>%lx", dwAPIVersion ));
|
|
LOG((TL_INFO, " dwDeviceID -------->%lx", dwDeviceID ));
|
|
|
|
|
|
Lock();
|
|
|
|
//
|
|
// save relevant info
|
|
//
|
|
m_pTAPI = NULL;
|
|
m_dwDeviceID = dwDeviceID;
|
|
m_hPhoneApp = hPhoneApp;
|
|
m_dwAPIVersion = dwAPIVersion;
|
|
m_pPhoneCaps = NULL;
|
|
m_hPhone = NULL;
|
|
m_pdwLineDeviceIDs = NULL;
|
|
m_dwNumLineDeviceIDs = 0;
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection( &m_csAutomatedPhoneState );
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - out of memory" ));
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection( &m_csToneTimer );
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - out of memory" ));
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
try
|
|
{
|
|
InitializeCriticalSection( &m_csRingTimer );
|
|
}
|
|
catch(...)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - out of memory" ));
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// allocate a buffer for the numbers gathered
|
|
//
|
|
m_wszNumbersGathered = (LPWSTR)ClientAlloc( (APC_MAX_NUMBERS_GATHERED + 1) * sizeof( WCHAR ) );
|
|
|
|
if (m_wszNumbersGathered == NULL)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - out of memory" ));
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// get line device ids associated with this phone
|
|
// we need to open the phone device to do this
|
|
//
|
|
|
|
t3Phone.hPhone = NULL;
|
|
t3Phone.pPhone = this;
|
|
|
|
hr = PhoneOpen(m_hPhoneApp, m_dwDeviceID, &t3Phone, m_dwAPIVersion, PHONEPRIVILEGE_MONITOR);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = PhoneGetID(
|
|
t3Phone.hPhone,
|
|
&pVarString,
|
|
L"tapi/line"
|
|
);
|
|
|
|
PhoneClose(t3Phone.hPhone);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
m_pdwLineDeviceIDs = (DWORD *)ClientAlloc( pVarString->dwUsedSize );
|
|
|
|
if (m_pdwLineDeviceIDs == NULL)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - out of memory" ));
|
|
|
|
ClientFree( pVarString );
|
|
|
|
ClientFree( m_wszNumbersGathered );
|
|
m_wszNumbersGathered = NULL;
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
CopyMemory(
|
|
m_pdwLineDeviceIDs,
|
|
((LPBYTE)pVarString)+pVarString->dwStringOffset,
|
|
pVarString->dwStringSize
|
|
);
|
|
|
|
m_dwNumLineDeviceIDs = pVarString->dwStringSize / sizeof(DWORD);
|
|
|
|
LOG((TL_INFO, " dwNumLineDeviceIDs -->%lx", m_dwNumLineDeviceIDs ));
|
|
}
|
|
|
|
if ( NULL != pVarString )
|
|
{
|
|
ClientFree( pVarString );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "Initialize - PhoneOpen failed %lx", hr ));
|
|
|
|
ClientFree( m_wszNumbersGathered );
|
|
m_wszNumbersGathered = NULL;
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
Unlock();
|
|
return hr;
|
|
}
|
|
|
|
m_hTimerQueue = CreateTimerQueue();
|
|
|
|
if (m_hTimerQueue == NULL)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - CreateTimerQueue failed %lx", hr ));
|
|
|
|
ClientFree( m_wszNumbersGathered );
|
|
m_wszNumbersGathered = NULL;
|
|
|
|
if (m_pdwLineDeviceIDs != NULL)
|
|
{
|
|
ClientFree( m_pdwLineDeviceIDs );
|
|
m_pdwLineDeviceIDs = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
m_hTimerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
if (m_hTimerEvent == NULL)
|
|
{
|
|
LOG((TL_ERROR, "Initialize - CreateEvent failed %lx", hr ));
|
|
|
|
ClientFree( m_wszNumbersGathered );
|
|
m_wszNumbersGathered = NULL;
|
|
|
|
if (m_pdwLineDeviceIDs != NULL)
|
|
{
|
|
ClientFree( m_pdwLineDeviceIDs );
|
|
m_pdwLineDeviceIDs = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
DeleteTimerQueue( m_hTimerQueue );
|
|
m_hTimerQueue = NULL;
|
|
|
|
Unlock();
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
AddRef();
|
|
|
|
//
|
|
// Save a pointer to TAPI
|
|
//
|
|
m_pTAPI = pTAPI;
|
|
m_pTAPI->AddRef();
|
|
|
|
m_fInitialized = TRUE;
|
|
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, S_OK, "Initialize - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// FinalRelease
|
|
// Clean up anything in the phone object.
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
void CPhone::FinalRelease()
|
|
{
|
|
LOG((TL_TRACE, "FinalRelease enter, this %p", this ));
|
|
|
|
Lock();
|
|
|
|
if (m_fInitialized == TRUE)
|
|
{
|
|
//
|
|
// Deallocate the phone caps cache
|
|
//
|
|
InvalidatePhoneCaps();
|
|
|
|
//
|
|
// Close the phone if it is open
|
|
//
|
|
if ( m_hPhone != NULL )
|
|
{
|
|
if (m_dwPrivilege == PHONEPRIVILEGE_OWNER)
|
|
{
|
|
if (m_fRinger == TRUE)
|
|
{
|
|
StopRinger();
|
|
}
|
|
|
|
if (m_Tone != PT_SILENCE)
|
|
{
|
|
StopTone();
|
|
}
|
|
|
|
CloseWaveDevice();
|
|
}
|
|
|
|
PhoneClose(m_hPhone);
|
|
}
|
|
|
|
//
|
|
// Delete timers
|
|
//
|
|
if (m_hTimerQueue != NULL)
|
|
{
|
|
DeleteTimerQueue(m_hTimerQueue);
|
|
m_hTimerQueue = NULL;
|
|
}
|
|
|
|
if (m_hTimerEvent != NULL)
|
|
{
|
|
CloseHandle( m_hTimerEvent );
|
|
m_hTimerEvent = NULL;
|
|
}
|
|
|
|
//
|
|
// Deallocate memory
|
|
//
|
|
if (m_wszNumbersGathered != NULL)
|
|
{
|
|
ClientFree( m_wszNumbersGathered );
|
|
m_wszNumbersGathered = NULL;
|
|
}
|
|
|
|
if (m_pdwLineDeviceIDs != NULL)
|
|
{
|
|
ClientFree( m_pdwLineDeviceIDs );
|
|
m_pdwLineDeviceIDs = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection( &m_csAutomatedPhoneState );
|
|
DeleteCriticalSection( &m_csToneTimer );
|
|
DeleteCriticalSection( &m_csRingTimer );
|
|
|
|
if ( m_pCall != NULL )
|
|
{
|
|
m_pCall->Release();
|
|
m_pCall = NULL;
|
|
}
|
|
|
|
//
|
|
// Release our refernece to the Tapi object
|
|
//
|
|
if (m_pTAPI != NULL)
|
|
{
|
|
m_pTAPI->Release();
|
|
m_pTAPI = NULL;
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "FinalRelease - exit, this %p", this ));
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// SetPhoneCapsBuffer
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
void
|
|
CPhone::SetPhoneCapBuffer( LPVOID pBuf )
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// This allow the phone caps cache to notify us that our phone
|
|
// caps buffer has changed (or more likely it will pass us NULL
|
|
// to say out buffer has been destroyed)
|
|
//
|
|
m_pPhoneCaps = (LPPHONECAPS)pBuf;
|
|
|
|
Unlock();
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// UpdatePhoneCaps
|
|
//
|
|
// must be called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT
|
|
CPhone::UpdatePhoneCaps()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Only do something if we don't have a current phone caps buffer
|
|
//
|
|
if ( NULL == m_pPhoneCaps )
|
|
{
|
|
LPPHONECAPS pTemp;
|
|
CTAPI * pCTapi;
|
|
|
|
pCTapi = GetTapi();
|
|
|
|
if( NULL == pCTapi )
|
|
{
|
|
LOG((TL_ERROR, "UpdatePhoneCaps - dynamic cast operation failed"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get a new buffer from the cache
|
|
//
|
|
hr = pCTapi->GetBuffer( BUFFERTYPE_PHONECAP,
|
|
(UINT_PTR)this,
|
|
(LPVOID*)&m_pPhoneCaps
|
|
);
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UpdatePhoneCaps - GetBuffer failed - %lx", hr));
|
|
m_pPhoneCaps = NULL;
|
|
|
|
return hr;
|
|
}
|
|
|
|
pTemp = m_pPhoneCaps;
|
|
|
|
//
|
|
// Get the phone caps from tapi2
|
|
//
|
|
hr = PhoneGetDevCaps(
|
|
m_hPhoneApp,
|
|
m_dwDeviceID,
|
|
m_dwAPIVersion,
|
|
&m_pPhoneCaps
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UpdatePhoneCaps - PhoneGetDevCaps failed - %lx", hr));
|
|
|
|
//
|
|
// Invalidate our buffer which is no good
|
|
//
|
|
|
|
InvalidatePhoneCaps();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// PhoneGetDevsCaps may have reallocated our buffer. If so, tell the tapiobject
|
|
// cache mechanism what our new buffer is.
|
|
//
|
|
|
|
if ( m_pPhoneCaps != pTemp )
|
|
{
|
|
pCTapi->SetBuffer( BUFFERTYPE_PHONECAP, (UINT_PTR)this, (LPVOID)m_pPhoneCaps );
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// InvalidatePhoneCaps
|
|
//
|
|
// must be called in lock
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT
|
|
CPhone::InvalidatePhoneCaps()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( NULL != m_pPhoneCaps )
|
|
{
|
|
CTAPI * pCTapi;
|
|
|
|
pCTapi = GetTapi();
|
|
|
|
if( NULL == pCTapi )
|
|
{
|
|
LOG((TL_ERROR, "InvalidatePhoneCaps - dynamic cast operation failed"));
|
|
|
|
_ASSERTE(FALSE);
|
|
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
pCTapi->InvalidateBuffer( BUFFERTYPE_PHONECAP, (UINT_PTR)this );
|
|
}
|
|
|
|
m_pPhoneCaps = NULL;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// IsPhoneOnAddress
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
BOOL
|
|
CPhone::IsPhoneOnAddress(ITAddress *pAddress)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
ITTerminalSupport * pTerminalSupport;
|
|
ITMediaSupport * pMediaSupport;
|
|
LONG lMediaType;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Update phone caps cache
|
|
//
|
|
|
|
hr = UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "IsPhoneOnAddress - UpdatePhoneCaps failed %lx", hr ));
|
|
return FALSE;
|
|
}
|
|
|
|
if ( (m_dwAPIVersion >= TAPI_VERSION2_0) && (m_pPhoneCaps->dwPhoneFeatures & PHONEFEATURE_GENERICPHONE) )
|
|
{
|
|
//
|
|
// We are a generic phone, therefore we
|
|
// are on any address that has a MSP and audio media types.
|
|
//
|
|
|
|
//
|
|
// get the terminal support interface
|
|
//
|
|
|
|
hr = pAddress->QueryInterface(
|
|
IID_ITTerminalSupport,
|
|
(void **)&pTerminalSupport
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "IsPhoneOnAddress - QueryInterface IID_ITTerminalSupport failed %lx", hr ));
|
|
return FALSE;
|
|
}
|
|
|
|
pTerminalSupport->Release();
|
|
|
|
//
|
|
// get the media support interface
|
|
//
|
|
hr = pAddress->QueryInterface(
|
|
IID_ITMediaSupport,
|
|
(void **)&pMediaSupport
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "IsPhoneOnAddress - QueryInterface IID_ITMediaSupport failed %lx", hr ));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// get the mediatype
|
|
//
|
|
hr = pMediaSupport->get_MediaTypes(&lMediaType);
|
|
|
|
pMediaSupport->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "IsPhoneOnAddress - get_MediaTypes failed %lx", hr ));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// make sure address supports audio
|
|
//
|
|
if (lMediaType & (LINEMEDIAMODE_INTERACTIVEVOICE | LINEMEDIAMODE_AUTOMATEDVOICE))
|
|
{
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we haven't already decided that we support this address
|
|
// check to see if this a preferred address.
|
|
//
|
|
|
|
if ( bResult == FALSE )
|
|
{
|
|
bResult = IsPhoneOnPreferredAddress(pAddress);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// IsPhoneOnPreferredAddress
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
BOOL
|
|
CPhone::IsPhoneOnPreferredAddress(ITAddress *pAddress)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
CAddress * pCAddress;
|
|
|
|
Lock();
|
|
|
|
if ( m_dwNumLineDeviceIDs > 0 )
|
|
{
|
|
//
|
|
// Check out list of line device IDs to see if we are
|
|
// preferred on this address
|
|
//
|
|
|
|
pCAddress = dynamic_cast<CAddress *>(pAddress);
|
|
|
|
if (NULL == pCAddress)
|
|
{
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "IsPhoneOnPreferredAddress - dynamic cast failed" ));
|
|
return FALSE;
|
|
}
|
|
|
|
for (int i = 0; i < m_dwNumLineDeviceIDs; i++ )
|
|
{
|
|
if ( m_pdwLineDeviceIDs[i] == pCAddress->GetDeviceID() )
|
|
{
|
|
//
|
|
// Yes, we matched this device ID to one in our list
|
|
//
|
|
bResult = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// IsPhoneUsingWaveID
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
BOOL CPhone::IsPhoneUsingWaveID(DWORD dwWaveID, TERMINAL_DIRECTION nDir)
|
|
{
|
|
T3PHONE t3Phone;
|
|
BOOL bResult = FALSE;
|
|
HRESULT hr;
|
|
LPVARSTRING pVarString = NULL;
|
|
DWORD dwPhoneWaveID;
|
|
|
|
//
|
|
// get wave device ids associated with this phone
|
|
// we need to open the phone device to do this
|
|
// Must use monitor privilege, because owner privilege open will
|
|
// fail if anyone happens to have the phone open as owner.
|
|
//
|
|
|
|
t3Phone.hPhone = NULL;
|
|
t3Phone.pPhone = this;
|
|
|
|
Lock();
|
|
|
|
hr = PhoneOpen(m_hPhoneApp, m_dwDeviceID, &t3Phone, m_dwAPIVersion, PHONEPRIVILEGE_MONITOR);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch(nDir)
|
|
{
|
|
case TD_CAPTURE:
|
|
{
|
|
hr = PhoneGetID(
|
|
t3Phone.hPhone,
|
|
&pVarString,
|
|
L"wave/in"
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (pVarString->dwStringSize == sizeof(DWORD))
|
|
{
|
|
CopyMemory(
|
|
&dwPhoneWaveID,
|
|
((LPBYTE)pVarString)+pVarString->dwStringOffset,
|
|
pVarString->dwStringSize
|
|
);
|
|
|
|
if ( dwWaveID == dwPhoneWaveID )
|
|
{
|
|
LOG((TL_INFO, "IsPhoneUsingWaveID - matched phone wave capture id %d", dwPhoneWaveID ));
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case TD_RENDER:
|
|
{
|
|
hr = PhoneGetID(
|
|
t3Phone.hPhone,
|
|
&pVarString,
|
|
L"wave/out"
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (pVarString->dwStringSize == sizeof(DWORD))
|
|
{
|
|
CopyMemory(
|
|
&dwPhoneWaveID,
|
|
((LPBYTE)pVarString)+pVarString->dwStringOffset,
|
|
pVarString->dwStringSize
|
|
);
|
|
|
|
if ( dwWaveID == dwPhoneWaveID )
|
|
{
|
|
LOG((TL_INFO, "IsPhoneUsingWaveID - matched phone wave render id %d", dwPhoneWaveID ));
|
|
bResult = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( NULL != pVarString )
|
|
{
|
|
ClientFree( pVarString );
|
|
}
|
|
|
|
PhoneClose(t3Phone.hPhone);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "IsPhoneUsingWaveID - PhoneOpen failed %lx", hr ));
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return bResult;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// GetTapi
|
|
//
|
|
// private method to get the tapi object
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
CTAPI *
|
|
CPhone::GetTapi()
|
|
{
|
|
CTAPI * p = NULL;
|
|
|
|
Lock();
|
|
|
|
if( m_pTAPI != NULL )
|
|
{
|
|
p = dynamic_cast<CTAPI *>(m_pTAPI);
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
//
|
|
// handle dev specific message
|
|
//
|
|
|
|
void HandlePhoneDevSpecificMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
|
|
LOG((TL_INFO, "HandlePhoneDevSpecificMessage - enter"));
|
|
|
|
|
|
//
|
|
// find the phone corresponding to this event
|
|
//
|
|
|
|
CPhone *pPhone = NULL;
|
|
|
|
if (!FindPhoneObject((HPHONE)pParams->hDevice, &pPhone))
|
|
{
|
|
LOG((TL_WARN, "HandlePhoneDevSpecificMessage - FindPhoneObject failed to find matching phone."));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// fire event
|
|
//
|
|
|
|
CPhoneDevSpecificEvent::FireEvent(
|
|
pPhone,
|
|
pParams->Param1,
|
|
pParams->Param2,
|
|
pParams->Param3
|
|
);
|
|
|
|
//
|
|
// undo findphoneobject's addref
|
|
//
|
|
|
|
pPhone->Release();
|
|
pPhone = NULL;
|
|
|
|
|
|
LOG((TL_INFO, "HandlePhoneDevSpecificMessage - exit. "));
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandlePhoneButtonMessage
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT HandlePhoneButtonMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneButtonMessage - enter"));
|
|
|
|
CPhone * pCPhone;
|
|
|
|
if (!FindPhoneObject((HPHONE)pParams->hDevice, &pCPhone))
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneButtonMessage - bad phone handle"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
switch ( pParams->Param3 )
|
|
{
|
|
case PHONEBUTTONSTATE_DOWN:
|
|
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_ButtonDown( pParams->Param1 );
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_BUTTON,
|
|
PBS_DOWN,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
pParams->Param1,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONEBUTTONSTATE_UNAVAIL:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_BUTTON,
|
|
PBS_UNAVAIL,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
pParams->Param1,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONEBUTTONSTATE_UNKNOWN:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_BUTTON,
|
|
PBS_UNKNOWN,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
pParams->Param1,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONEBUTTONSTATE_UP:
|
|
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_ButtonUp( pParams->Param1 );
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_BUTTON,
|
|
PBS_UP,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
pParams->Param1,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
}
|
|
|
|
pCPhone->Release();
|
|
|
|
LOG((TL_TRACE, "HandlePhoneButtonMessage - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandlePhoneStateMessage
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT HandlePhoneStateMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneStateMessage - enter"));
|
|
|
|
CPhone * pCPhone;
|
|
PHONE_HOOK_SWITCH_STATE HookSwitchState;
|
|
|
|
if (!FindPhoneObject((HPHONE)pParams->hDevice, &pCPhone))
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneStateMessage - bad phone handle"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
switch( pParams->Param1 ) // PhoneState
|
|
{
|
|
case PHONESTATE_CAPSCHANGE:
|
|
|
|
pCPhone->Lock();
|
|
|
|
//
|
|
// Phone caps have changed, so invalidate out cache
|
|
//
|
|
pCPhone->InvalidatePhoneCaps();
|
|
|
|
pCPhone->Unlock();
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_CAPSCHANGE,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_HANDSETHOOKSWITCH:
|
|
|
|
if ( pParams->Param2 == PHONEHOOKSWITCHMODE_ONHOOK )
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OnHook( PHSD_HANDSET );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OffHook( PHSD_HANDSET );
|
|
}
|
|
|
|
switch (pParams->Param2)
|
|
{
|
|
case PHONEHOOKSWITCHMODE_ONHOOK:
|
|
HookSwitchState = PHSS_ONHOOK;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MIC:
|
|
HookSwitchState = PHSS_OFFHOOK_MIC_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_SPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK_SPEAKER_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MICSPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "HandlePhoneStateMessage - bad HookSwitchMode"));
|
|
pCPhone->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_HOOKSWITCH,
|
|
(PHONE_BUTTON_STATE)0,
|
|
HookSwitchState,
|
|
PHSD_HANDSET,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_HEADSETHOOKSWITCH:
|
|
|
|
if ( pParams->Param2 == PHONEHOOKSWITCHMODE_ONHOOK )
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OnHook( PHSD_HEADSET );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OffHook( PHSD_HEADSET );
|
|
}
|
|
|
|
switch (pParams->Param2)
|
|
{
|
|
case PHONEHOOKSWITCHMODE_ONHOOK:
|
|
HookSwitchState = PHSS_ONHOOK;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MIC:
|
|
HookSwitchState = PHSS_OFFHOOK_MIC_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_SPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK_SPEAKER_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MICSPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "HandlePhoneStateMessage - bad HookSwitchMode"));
|
|
pCPhone->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_HOOKSWITCH,
|
|
(PHONE_BUTTON_STATE)0,
|
|
HookSwitchState,
|
|
PHSD_HEADSET,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_LAMP:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_LAMPMODE,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
pParams->Param2,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_RINGMODE:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_RINGMODE,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
pParams->Param2,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_RINGVOLUME:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_RINGVOLUME,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_SPEAKERHOOKSWITCH:
|
|
|
|
if ( pParams->Param2 == PHONEHOOKSWITCHMODE_ONHOOK )
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OnHook( PHSD_SPEAKERPHONE );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Automation event hook
|
|
//
|
|
pCPhone->Automation_OffHook( PHSD_SPEAKERPHONE );
|
|
}
|
|
|
|
switch (pParams->Param2)
|
|
{
|
|
case PHONEHOOKSWITCHMODE_ONHOOK:
|
|
HookSwitchState = PHSS_ONHOOK;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MIC:
|
|
HookSwitchState = PHSS_OFFHOOK_MIC_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_SPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK_SPEAKER_ONLY;
|
|
break;
|
|
case PHONEHOOKSWITCHMODE_MICSPEAKER:
|
|
HookSwitchState = PHSS_OFFHOOK;
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_ERROR, "HandlePhoneStateMessage - bad HookSwitchMode"));
|
|
pCPhone->Release();
|
|
return E_FAIL;
|
|
}
|
|
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_HOOKSWITCH,
|
|
(PHONE_BUTTON_STATE)0,
|
|
HookSwitchState,
|
|
PHSD_SPEAKERPHONE,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
case PHONESTATE_DISPLAY:
|
|
CPhoneEvent::FireEvent(
|
|
pCPhone,
|
|
PE_DISPLAY,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
|
|
default:
|
|
LOG((TL_INFO, "HandlePhoneStateMessage - PHONE_STATE %lx event not handled", pParams->Param1));
|
|
}
|
|
|
|
pCPhone->Release();
|
|
|
|
LOG((TL_TRACE, "HandlePhoneStateMessage - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// HandlePhoneCloseMessage
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT HandlePhoneCloseMessage( PASYNCEVENTMSG pParams )
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneCloseMessage - enter"));
|
|
|
|
CPhone * pCPhone;
|
|
|
|
if (!FindPhoneObject((HPHONE)pParams->hDevice, &pCPhone))
|
|
{
|
|
LOG((TL_TRACE, "HandlePhoneCloseMessage - bad phone handle"));
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
pCPhone->ForceClose();
|
|
|
|
pCPhone->Release();
|
|
|
|
LOG((TL_TRACE, "HandlePhoneCloseMessage - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// ForceClose
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::ForceClose()
|
|
{
|
|
Lock();
|
|
|
|
//
|
|
// If phone isn't open then get out of here
|
|
//
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
Unlock();
|
|
|
|
return;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// Close the phone
|
|
//
|
|
Close();
|
|
|
|
//
|
|
// Fire a PE_CLOSE event
|
|
//
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_CLOSE,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// ITAutomatedPhoneControl implementation
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// Automation_CallState
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void CPhone::Automation_CallState( ITCallInfo * pCall, CALL_STATE cs, CALL_STATE_EVENT_CAUSE cause )
|
|
{
|
|
LOG((TL_TRACE, "Automation_CallState - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_INFO, "Automation_CallState - phone[%p]",
|
|
this));
|
|
LOG((TL_INFO, "Automation_CallState - selected call [%p]",
|
|
m_pCall));
|
|
LOG((TL_INFO, "Automation_CallState - current phone state [%d]",
|
|
m_AutomatedPhoneState));
|
|
LOG((TL_INFO, "Automation_CallState - phone control enabled [%s]",
|
|
m_fPhoneHandlingEnabled ? "TRUE" : "FALSE"));
|
|
LOG((TL_INFO, "Automation_CallState - new call state [%d]",
|
|
cs));
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
if ( pCall == m_pCall )
|
|
{
|
|
switch( cs )
|
|
{
|
|
|
|
case CS_IDLE:
|
|
LOG((TL_INFO, "Automation_CallState - CS_IDLE"));
|
|
break;
|
|
|
|
case CS_INPROGRESS:
|
|
LOG((TL_INFO, "Automation_CallState - CS_INPROGRESS"));
|
|
switch(m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_IDLE:
|
|
case APS_ONHOOK_RINGING_IN:
|
|
{
|
|
StartRinger( 0, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_RINGING_OUT;
|
|
}
|
|
break;
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_DIALING:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
{
|
|
StartTone( PT_RINGBACK, 0);
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_RINGING_OUT;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CS_CONNECTED:
|
|
LOG((TL_INFO, "Automation_CallState - CS_CONNECTED"));
|
|
switch(m_AutomatedPhoneState)
|
|
{
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
{
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
{
|
|
// stop ringback
|
|
StopTone();
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
{
|
|
m_AutomatedPhoneState = APS_ONHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
case APS_ONHOOK_IDLE:
|
|
{
|
|
StartRinger( 0, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
case APS_ONHOOK_RINGING_IN:
|
|
{
|
|
m_AutomatedPhoneState = APS_ONHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_DIALING:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
{
|
|
// An app shouldn't do this to us, but stop the
|
|
// tone and move to the connected state
|
|
StopTone();
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CONNECTED;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CS_DISCONNECTED:
|
|
LOG((TL_INFO, "Automation_CallState - CS_DISCONNECTED"));
|
|
switch(m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_RINGING_IN:
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
case APS_ONHOOK_CONNECTED:
|
|
{
|
|
//
|
|
// Stop the ringer
|
|
//
|
|
|
|
if (m_fRinger == TRUE)
|
|
{
|
|
StopRinger();
|
|
}
|
|
|
|
// unselect the call
|
|
InternalUnselectCall( pCall );
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_IDLE;
|
|
}
|
|
break;
|
|
case APS_ONHOOK_IDLE:
|
|
{
|
|
// unselect the call
|
|
InternalUnselectCall( pCall );
|
|
}
|
|
break;
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_DIALING:
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_CONNECTED:
|
|
{
|
|
switch( cause )
|
|
{
|
|
case CEC_DISCONNECT_BUSY:
|
|
{
|
|
// start busy tone
|
|
StartTone( PT_BUSY, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_BUSY_TONE;
|
|
}
|
|
break;
|
|
case CEC_DISCONNECT_NORMAL:
|
|
{
|
|
// stop any playing tone
|
|
StopTone();
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_DEAD_LINE;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
// start error tone
|
|
StartTone( PT_ERRORTONE, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_WARNING;
|
|
}
|
|
}
|
|
|
|
// unselect the call
|
|
InternalUnselectCall( pCall );
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CS_OFFERING:
|
|
LOG((TL_INFO, "Automation_CallState - CS_OFFERING"));
|
|
switch(m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_IDLE:
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
{
|
|
StartRinger( 0, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_RINGING_IN;
|
|
}
|
|
break;
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_DIALING:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
{
|
|
StopTone();
|
|
|
|
ITBasicCallControl * pCallBCC;
|
|
ITCallInfo * pCall;
|
|
|
|
HRESULT hr;
|
|
|
|
pCall = m_pCall;
|
|
pCall->AddRef();
|
|
|
|
hr = pCall->QueryInterface( IID_ITBasicCallControl,
|
|
(void **) & pCallBCC );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
hr = pCallBCC->Answer();
|
|
|
|
pCallBCC->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "Automation_CallState - Answer failed %08x", hr ));
|
|
}
|
|
else
|
|
{
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_ANSWER,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
pCall
|
|
);
|
|
}
|
|
|
|
pCall->Release();
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CALL_INIT;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CS_HOLD:
|
|
LOG((TL_INFO, "Automation_CallState - CS_HOLD"));
|
|
break;
|
|
|
|
case CS_QUEUED:
|
|
LOG((TL_INFO, "Automation_CallState - CS_QUEUED"));
|
|
break;
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LOG((TL_INFO, "Automation_CallState - new phone state [%d]",
|
|
m_AutomatedPhoneState));
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_CallState - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// Automation_EndOfNumberTimeout
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
void CPhone::Automation_EndOfNumberTimeout()
|
|
{
|
|
LOG((TL_TRACE, "Automation_EndOfNumberTimeout - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled && m_dwAutoEndOfNumberTimeout)
|
|
{
|
|
if (m_hAutoEndOfNumberTimer) // make sure the timer hasn't been cancelled
|
|
// while waiting for the critical section
|
|
{
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_OFFHOOK_DIALING:
|
|
{
|
|
//
|
|
// We need to fire and event with the number we have
|
|
// collected
|
|
//
|
|
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_NUMBERGATHERED,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
m_wszNumbersGathered,
|
|
NULL
|
|
);
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CALL_INIT;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_EndOfNumberTimeout - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// Automation_ButtonDown
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::Automation_ButtonDown( DWORD dwButtonId )
|
|
{
|
|
PHONE_BUTTON_MODE ButtonMode;
|
|
WCHAR wszNumber[11]; // enough to hold a big number in case dwButtonId is bad
|
|
HRESULT hr;
|
|
BOOL fResult;
|
|
|
|
LOG((TL_TRACE, "Automation_ButtonDown - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
hr = get_ButtonMode((LONG)dwButtonId, &ButtonMode);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (ButtonMode == PBM_KEYPAD)
|
|
{
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_OFFHOOK_DIALTONE:
|
|
{
|
|
if (m_fAutoDialtone)
|
|
{
|
|
// Stop the dial tone
|
|
StopTone();
|
|
}
|
|
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_DIALING,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_DIALING;
|
|
}
|
|
// Fall Thru
|
|
|
|
case APS_OFFHOOK_DIALING:
|
|
{
|
|
// Kill auto end of number timer
|
|
if (m_hAutoEndOfNumberTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hAutoEndOfNumberTimer,
|
|
m_hTimerEvent // non-blocking
|
|
);
|
|
|
|
m_hAutoEndOfNumberTimer = NULL;
|
|
}
|
|
|
|
if ( dwButtonId <= 10 ) // digit key
|
|
{
|
|
//
|
|
// We have a dialed digit. Append it to the phone
|
|
// number we have so far.
|
|
//
|
|
|
|
if ( dwButtonId == 10) // star
|
|
{
|
|
wsprintfW(wszNumber, L"*");
|
|
}
|
|
else // regular digit
|
|
{
|
|
wsprintfW(wszNumber, L"%d", dwButtonId);
|
|
}
|
|
|
|
if ( (lstrlenW(m_wszNumbersGathered) + lstrlenW(wszNumber)) < APC_MAX_NUMBERS_GATHERED )
|
|
{
|
|
lstrcatW(m_wszNumbersGathered, wszNumber);
|
|
}
|
|
|
|
LOG((TL_INFO, "Automation_ButtonDown - '%s'", wszNumber));
|
|
}
|
|
else if ( dwButtonId == 11 ) // pound key
|
|
{
|
|
LOG((TL_INFO, "Automation_ButtonDown - '#'"));
|
|
|
|
// Kill auto end of number timer
|
|
if (m_hAutoEndOfNumberTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hAutoEndOfNumberTimer,
|
|
m_hTimerEvent // non-blocking
|
|
);
|
|
|
|
m_hAutoEndOfNumberTimer = NULL;
|
|
}
|
|
|
|
//
|
|
// We have dialed a #. Send a number gathered event
|
|
//
|
|
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_NUMBERGATHERED,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
m_wszNumbersGathered,
|
|
NULL
|
|
);
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CALL_INIT;
|
|
}
|
|
}
|
|
// Fall Thru
|
|
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_CONNECTED:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
{
|
|
if (m_fAutoKeypadTones)
|
|
{
|
|
// Kill DTMF timer
|
|
if (m_hDTMFTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hDTMFTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hDTMFTimer = NULL;
|
|
}
|
|
|
|
// Stop the old DTMF tone
|
|
if (m_DTMF != PT_SILENCE)
|
|
{
|
|
m_WavePlayer.StopTone( (long) m_DTMF);
|
|
}
|
|
|
|
// Play the DTMF tone
|
|
m_WavePlayer.StartTone( (long) dwButtonId );
|
|
m_DTMF = (PHONE_TONE) dwButtonId;
|
|
m_dwDTMFStart = GetTickCount();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if ( ButtonMode == PBM_FEATURE )
|
|
{
|
|
PHONE_BUTTON_FUNCTION ButtonFunction;
|
|
|
|
hr = get_ButtonFunction((LONG)dwButtonId, &ButtonFunction);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch (ButtonFunction)
|
|
{
|
|
case PBF_VOLUMEUP:
|
|
{
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_INFO, "Automation_ButtonDown - VOLUMEUP"));
|
|
|
|
if (m_fAutoVolumeControl)
|
|
{
|
|
// Kill volume timer
|
|
if (m_hVolumeTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hVolumeTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hVolumeTimer = NULL;
|
|
}
|
|
|
|
hr = m_WavePlayer.GetVolume( &dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
dwVolume += m_dwAutoVolumeControlStep;
|
|
|
|
if (dwVolume > 0xFFFF) dwVolume = 0xFFFF;
|
|
|
|
hr = m_WavePlayer.SetVolume( dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_INFO, "Automation_ButtonDown - Volume: %d", dwVolume));
|
|
|
|
m_fVolumeUp = TRUE;
|
|
|
|
fResult = CreateTimerQueueTimer(&m_hVolumeTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::VolumeTimerCallback,
|
|
(PVOID)this,
|
|
max(m_dwAutoVolumeControlRepeatDelay,m_dwAutoVolumeControlRepeatPeriod),
|
|
m_dwAutoVolumeControlRepeatPeriod,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, not much to do but log the error
|
|
LOG((TL_ERROR, "Automation_ButtonDown - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PBF_VOLUMEDOWN:
|
|
{
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_INFO, "Automation_ButtonDown - VOLUMEDOWN"));
|
|
|
|
if (m_fAutoVolumeControl)
|
|
{
|
|
// Kill volume timer
|
|
if (m_hVolumeTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hVolumeTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hVolumeTimer = NULL;
|
|
}
|
|
|
|
hr = m_WavePlayer.GetVolume( &dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
dwVolume -= m_dwAutoVolumeControlStep;
|
|
|
|
if (dwVolume > 0xFFFF) dwVolume = 0x0000;
|
|
|
|
hr = m_WavePlayer.SetVolume( dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_INFO, "Automation_ButtonDown - Volume: %d", dwVolume));
|
|
|
|
m_fVolumeUp = FALSE;
|
|
|
|
fResult = CreateTimerQueueTimer(&m_hVolumeTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::VolumeTimerCallback,
|
|
(PVOID)this,
|
|
max(m_dwAutoVolumeControlRepeatDelay,m_dwAutoVolumeControlRepeatPeriod),
|
|
m_dwAutoVolumeControlRepeatPeriod,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, not much to do but log the error
|
|
LOG((TL_ERROR, "Automation_ButtonDown - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PBF_SEND:
|
|
{
|
|
LOG((TL_INFO, "Automation_ButtonDown - PBF_SEND"));
|
|
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_OFFHOOK_DIALING:
|
|
{
|
|
// Kill auto end of number timer
|
|
if (m_hAutoEndOfNumberTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hAutoEndOfNumberTimer,
|
|
m_hTimerEvent // non-blocking
|
|
);
|
|
|
|
m_hAutoEndOfNumberTimer = NULL;
|
|
}
|
|
|
|
//
|
|
// We have pressed send. Send a number gathered event.
|
|
//
|
|
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_NUMBERGATHERED,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
m_wszNumbersGathered,
|
|
NULL
|
|
);
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CALL_INIT;
|
|
}
|
|
break;
|
|
} // switch (m_AutomatedPhoneState)
|
|
}
|
|
break;
|
|
} // switch (ButtonFunction)
|
|
}
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_ButtonDown - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::Automation_ButtonUp( DWORD dwButtonId )
|
|
{
|
|
PHONE_BUTTON_MODE ButtonMode;
|
|
HRESULT hr;
|
|
BOOL fResult;
|
|
|
|
LOG((TL_TRACE, "Automation_ButtonUp - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
hr = get_ButtonMode((LONG)dwButtonId, &ButtonMode);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( ButtonMode == PBM_KEYPAD )
|
|
{
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_OFFHOOK_DIALING:
|
|
{
|
|
if ( dwButtonId <= 10 ) // digit key
|
|
{
|
|
if (m_dwAutoEndOfNumberTimeout)
|
|
{
|
|
fResult = CreateTimerQueueTimer(&m_hAutoEndOfNumberTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::AutoEndOfNumberTimerCallback,
|
|
(PVOID)this,
|
|
m_dwAutoEndOfNumberTimeout,
|
|
0,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, not much to do but log the error
|
|
LOG((TL_ERROR, "Automation_ButtonUp - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Fall Thru
|
|
|
|
case APS_OFFHOOK_CONNECTED:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
{
|
|
if (m_fAutoKeypadTones)
|
|
{
|
|
if ((PHONE_TONE)dwButtonId == m_DTMF)
|
|
{
|
|
DWORD dwElapsed = GetTickCount() - m_dwDTMFStart;
|
|
|
|
if ( dwElapsed > m_dwAutoKeypadTonesMinimumDuration )
|
|
{
|
|
// Stop the DTMF tone
|
|
m_WavePlayer.StopTone( (long) m_DTMF);
|
|
m_DTMF = PT_SILENCE;
|
|
}
|
|
else
|
|
{
|
|
// Limit the DTMF tone
|
|
fResult = CreateTimerQueueTimer(&m_hDTMFTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::DTMFTimerCallback,
|
|
(PVOID)this,
|
|
m_dwAutoKeypadTonesMinimumDuration - dwElapsed,
|
|
0,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, not much to do but log the error
|
|
LOG((TL_ERROR, "Automation_ButtonUp - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if ( ButtonMode == PBM_FEATURE )
|
|
{
|
|
PHONE_BUTTON_FUNCTION ButtonFunction;
|
|
|
|
hr = get_ButtonFunction((LONG)dwButtonId, &ButtonFunction);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch (ButtonFunction)
|
|
{
|
|
case PBF_VOLUMEUP:
|
|
{
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_INFO, "Automation_ButtonUp - VOLUMEUP"));
|
|
|
|
if (m_fAutoVolumeControl)
|
|
{
|
|
// Kill volume timer
|
|
if (m_hVolumeTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hVolumeTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hVolumeTimer = NULL;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PBF_VOLUMEDOWN:
|
|
{
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_INFO, "Automation_ButtonUp - VOLUMEDOWN"));
|
|
|
|
if (m_fAutoVolumeControl)
|
|
{
|
|
// Kill volume timer
|
|
if (m_hVolumeTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hVolumeTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hVolumeTimer = NULL;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_ButtonUp - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::Automation_OnHook( PHONE_HOOK_SWITCH_DEVICE phsd )
|
|
{
|
|
LOG((TL_TRACE, "Automation_OnHook - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
if (m_dwOffHookCount > 0) m_dwOffHookCount--;
|
|
|
|
if (m_dwOffHookCount == 0)
|
|
{
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_IDLE:
|
|
case APS_ONHOOK_RINGING_IN:
|
|
case APS_ONHOOK_CONNECTED:
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
{
|
|
//
|
|
// Something is wrong!! Most likely this phone was offhook on startup, but told
|
|
// us it was onhook. Lets clean up the best we can
|
|
//
|
|
|
|
LOG((TL_WARN, "Automation_OnHook - Phone is already in onhook state!" ));
|
|
|
|
if (m_fAutoStopTonesOnOnHook)
|
|
{
|
|
// Kill DTMF timer
|
|
if (m_hDTMFTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hDTMFTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hDTMFTimer = NULL;
|
|
}
|
|
|
|
// Stop any DTMF that may be playing
|
|
if (m_DTMF != PT_SILENCE)
|
|
{
|
|
// Stop the DTMF tone
|
|
m_WavePlayer.StopTone( (long) m_DTMF );
|
|
m_DTMF = PT_SILENCE;
|
|
}
|
|
|
|
// Stop any tone that may be playing
|
|
StopTone();
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_IDLE;
|
|
}
|
|
break;
|
|
|
|
case APS_OFFHOOK_DIALTONE:
|
|
case APS_OFFHOOK_WARNING:
|
|
case APS_OFFHOOK_DEAD_LINE:
|
|
case APS_OFFHOOK_DIALING:
|
|
case APS_OFFHOOK_CONNECTED:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_BUSY_TONE:
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
{
|
|
if (m_fAutoStopTonesOnOnHook)
|
|
{
|
|
// Kill DTMF timer
|
|
if (m_hDTMFTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hDTMFTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hDTMFTimer = NULL;
|
|
}
|
|
|
|
// Stop any DTMF that may be playing
|
|
if (m_DTMF != PT_SILENCE)
|
|
{
|
|
// Stop the DTMF tone
|
|
m_WavePlayer.StopTone( (long) m_DTMF );
|
|
m_DTMF = PT_SILENCE;
|
|
}
|
|
|
|
// Stop any tone that may be playing
|
|
StopTone();
|
|
}
|
|
|
|
// Kill automated end of number timer
|
|
if (m_hAutoEndOfNumberTimer)
|
|
{
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hAutoEndOfNumberTimer,
|
|
m_hTimerEvent // non-blocking
|
|
);
|
|
|
|
m_hAutoEndOfNumberTimer = NULL;
|
|
}
|
|
|
|
if (m_pCall)
|
|
{
|
|
CALL_STATE cs;
|
|
HRESULT hr;
|
|
|
|
hr = m_pCall->get_CallState( &cs );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( cs != CS_DISCONNECTED )
|
|
{
|
|
ITBasicCallControl * pCallBCC;
|
|
ITCallInfo * pCall;
|
|
|
|
pCall = m_pCall;
|
|
pCall->AddRef();
|
|
|
|
hr = pCall->QueryInterface( IID_ITBasicCallControl,
|
|
(void **) & pCallBCC );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
hr = pCallBCC->Disconnect( DC_NORMAL );
|
|
|
|
pCallBCC->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "Automation_OnHook - Disconnect failed %08x", hr ));
|
|
}
|
|
else
|
|
{
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_DISCONNECT,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
pCall
|
|
);
|
|
}
|
|
|
|
pCall->Release();
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we are already disconnected we can unselect the call, otherwise
|
|
// the CS_DISCONNECT event will do it for us.
|
|
InternalUnselectCall( m_pCall );
|
|
}
|
|
}
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_IDLE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_OnHook - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::Automation_OffHook( PHONE_HOOK_SWITCH_DEVICE phsd )
|
|
{
|
|
LOG((TL_TRACE, "Automation_OffHook - enter"));
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
m_dwOffHookCount++;
|
|
|
|
// We just went offhook
|
|
if (m_dwOffHookCount == 1)
|
|
{
|
|
switch (m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_IDLE:
|
|
{
|
|
if (m_fAutoStopRingOnOffHook)
|
|
{
|
|
// Stop incoming ring
|
|
StopRinger();
|
|
}
|
|
|
|
if (m_fAutoDialtone)
|
|
{
|
|
// Start the dialtone
|
|
StartTone( PT_NORMALDIALTONE, 0 );
|
|
}
|
|
|
|
// Clear the numbers gathered
|
|
lstrcpyW(m_wszNumbersGathered, L"");
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_DIALTONE;
|
|
}
|
|
break;
|
|
|
|
case APS_ONHOOK_RINGING_IN:
|
|
{
|
|
if (m_fAutoStopRingOnOffHook)
|
|
{
|
|
// Stop incoming ring
|
|
StopRinger();
|
|
}
|
|
|
|
if (m_pCall)
|
|
{
|
|
CALL_STATE cs;
|
|
HRESULT hr;
|
|
|
|
hr = m_pCall->get_CallState( &cs );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( cs == CS_OFFERING )
|
|
{
|
|
ITBasicCallControl * pCallBCC;
|
|
ITCallInfo * pCall;
|
|
|
|
pCall = m_pCall;
|
|
pCall->AddRef();
|
|
|
|
hr = pCall->QueryInterface( IID_ITBasicCallControl,
|
|
(void **) & pCallBCC );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
hr = pCallBCC->Answer();
|
|
|
|
pCallBCC->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "Automation_OffHook - Answer failed %08x", hr ));
|
|
}
|
|
else
|
|
{
|
|
CPhoneEvent::FireEvent(
|
|
this,
|
|
PE_ANSWER,
|
|
(PHONE_BUTTON_STATE)0,
|
|
(PHONE_HOOK_SWITCH_STATE)0,
|
|
(PHONE_HOOK_SWITCH_DEVICE)0,
|
|
0,
|
|
0,
|
|
NULL,
|
|
pCall
|
|
);
|
|
}
|
|
|
|
pCall->Release();
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CALL_INIT;
|
|
}
|
|
break;
|
|
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
{
|
|
if (m_fAutoStopRingOnOffHook)
|
|
{
|
|
// Stop incoming ring
|
|
StopRinger();
|
|
}
|
|
|
|
if (m_pCall)
|
|
{
|
|
CALL_STATE cs;
|
|
HRESULT hr;
|
|
|
|
hr = m_pCall->get_CallState( &cs );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
switch( cs )
|
|
{
|
|
case CS_INPROGRESS:
|
|
{
|
|
StartTone( PT_RINGBACK, 0 );
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_RINGING_OUT;
|
|
}
|
|
break;
|
|
|
|
case CS_CONNECTED:
|
|
{
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case APS_ONHOOK_CONNECTED:
|
|
{
|
|
if (m_fAutoStopRingOnOffHook)
|
|
{
|
|
// Stop incoming ring
|
|
StopRinger();
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_CONNECTED;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "Automation_OffHook - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
VOID CALLBACK CPhone::ToneTimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
CPhone * pCPhone = (CPhone *)(lpParameter);
|
|
|
|
STATICLOG((TL_TRACE, "ToneTimerCallback - enter"));
|
|
|
|
BOOL Stopped = TRUE;
|
|
|
|
if (pCPhone != NULL)
|
|
{
|
|
if (TryEnterCriticalSection( &pCPhone->m_csToneTimer ))
|
|
{
|
|
if (pCPhone->m_WavePlayer.PlayingTone( (long) pCPhone->m_Tone ))
|
|
{
|
|
//
|
|
// Tone was on
|
|
//
|
|
|
|
pCPhone->m_WavePlayer.StopTone( (long) pCPhone->m_Tone );
|
|
|
|
if (pCPhone->m_dwTonePeriodOn > 0)
|
|
{
|
|
//
|
|
// Tone is periodic
|
|
//
|
|
|
|
if (pCPhone->m_dwToneDuration > 0)
|
|
{
|
|
//
|
|
// Tone is periodic with limited duration
|
|
//
|
|
|
|
if ( pCPhone->m_dwToneDuration > pCPhone->m_dwTonePeriodOn )
|
|
{
|
|
pCPhone->m_dwToneDuration -= pCPhone->m_dwTonePeriodOn;
|
|
|
|
if ( pCPhone->m_dwTonePeriodOff < pCPhone->m_dwToneDuration )
|
|
{
|
|
//
|
|
// Remaining duration is greater than the period
|
|
//
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwTonePeriodOff,
|
|
TIMER_KEEP_ALIVE
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remaining duration is less than the period
|
|
//
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwToneDuration,
|
|
0
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Tone is periodic with infinite duration
|
|
//
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwTonePeriodOff,
|
|
TIMER_KEEP_ALIVE
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Tone was off
|
|
//
|
|
|
|
if (pCPhone->m_dwTonePeriodOff > 0)
|
|
{
|
|
//
|
|
// Tone is periodic
|
|
//
|
|
|
|
if (pCPhone->m_dwToneDuration > 0)
|
|
{
|
|
//
|
|
// Tone is periodic with limited duration
|
|
//
|
|
|
|
if ( pCPhone->m_dwToneDuration > pCPhone->m_dwTonePeriodOff )
|
|
{
|
|
pCPhone->m_dwToneDuration -= pCPhone->m_dwTonePeriodOff;
|
|
|
|
if ( pCPhone->m_dwTonePeriodOn < pCPhone->m_dwToneDuration )
|
|
{
|
|
//
|
|
// Remaining duration is greater than the period
|
|
//
|
|
|
|
pCPhone->m_WavePlayer.StartTone( (long) pCPhone->m_Tone );
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwTonePeriodOn,
|
|
TIMER_KEEP_ALIVE
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remaining duration is less than the period
|
|
//
|
|
|
|
pCPhone->m_WavePlayer.StartTone( (long) pCPhone->m_Tone );
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwToneDuration,
|
|
0
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Tone is periodic with infinite duration
|
|
//
|
|
|
|
pCPhone->m_WavePlayer.StartTone( (long) pCPhone->m_Tone );
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hToneTimer,
|
|
pCPhone->m_dwTonePeriodOn,
|
|
TIMER_KEEP_ALIVE
|
|
);
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Stopped) pCPhone->m_Tone = PT_SILENCE;
|
|
|
|
LeaveCriticalSection( &pCPhone->m_csToneTimer );
|
|
}
|
|
}
|
|
|
|
STATICLOG((TL_TRACE, "ToneTimerCallback - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
VOID CALLBACK CPhone::DTMFTimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
CPhone * pCPhone = (CPhone *)(lpParameter);
|
|
|
|
STATICLOG((TL_TRACE, "DTMFTimerCallback - enter"));
|
|
|
|
if (pCPhone != NULL)
|
|
{
|
|
pCPhone->m_WavePlayer.StopTone( (long) pCPhone->m_DTMF );
|
|
pCPhone->m_DTMF = PT_SILENCE;
|
|
}
|
|
|
|
STATICLOG((TL_TRACE, "DTMFTimerCallback - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
VOID CALLBACK CPhone::RingTimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
DWORD dwVolume;
|
|
CPhone * pCPhone = (CPhone *)(lpParameter);
|
|
|
|
STATICLOG((TL_TRACE, "RingTimerCallback - enter"));
|
|
|
|
BOOL Stopped = TRUE;
|
|
|
|
if (pCPhone != NULL)
|
|
{
|
|
if ( TryEnterCriticalSection( &pCPhone->m_csRingTimer ))
|
|
{
|
|
if ( pCPhone->m_fUseWaveForRinger )
|
|
{
|
|
//
|
|
// Using wave player for ring
|
|
//
|
|
|
|
if ( pCPhone->m_dwRingDuration > 0 )
|
|
{
|
|
//
|
|
// Ring has a limited duration
|
|
//
|
|
|
|
if ( pCPhone->m_dwRingDuration > pCPhone->m_dwRingPeriod )
|
|
{
|
|
pCPhone->m_dwRingDuration -= pCPhone->m_dwRingPeriod;
|
|
|
|
if ( pCPhone->m_dwRingPeriod < pCPhone->m_dwRingDuration )
|
|
{
|
|
//
|
|
// Remaining duration is greater than period
|
|
//
|
|
|
|
hr = pCPhone->m_WavePlayer.StartRing();
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remaining duration is less than period
|
|
//
|
|
|
|
ChangeTimerQueueTimer(
|
|
pCPhone->m_hTimerQueue,
|
|
pCPhone->m_hRingTimer,
|
|
pCPhone->m_dwRingDuration,
|
|
0
|
|
);
|
|
|
|
hr = pCPhone->m_WavePlayer.StartRing();
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Ring has an infinite duration
|
|
//
|
|
|
|
hr = pCPhone->m_WavePlayer.StartRing();
|
|
|
|
Stopped = FALSE;
|
|
}
|
|
|
|
//
|
|
// Stop the ring if needed
|
|
//
|
|
|
|
if (Stopped)
|
|
{
|
|
hr = pCPhone->m_WavePlayer.StopRing();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Using phone's ringer, duration must have elapsed because
|
|
// this is not periodic
|
|
//
|
|
hr = PhoneGetRing(pCPhone->m_hPhone, &dwDummy, &dwVolume);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
STATICLOG((TL_TRACE, "RingTimerCallback - PhoneGetRing failed - %lx", hr));
|
|
|
|
LeaveCriticalSection( &pCPhone->m_csRingTimer );
|
|
|
|
return;
|
|
}
|
|
|
|
hr = PhoneSetRing(pCPhone->m_hPhone, 0, dwVolume );
|
|
}
|
|
|
|
if (Stopped)
|
|
{
|
|
pCPhone->m_fRinger = FALSE;
|
|
}
|
|
|
|
LeaveCriticalSection( &pCPhone->m_csRingTimer );
|
|
}
|
|
}
|
|
|
|
STATICLOG((TL_TRACE, "RingTimerCallback - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
VOID CALLBACK CPhone::VolumeTimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwVolume;
|
|
CPhone * pCPhone = (CPhone *)(lpParameter);
|
|
|
|
STATICLOG((TL_TRACE, "VolumeTimerCallback - enter"));
|
|
|
|
if (pCPhone != NULL)
|
|
{
|
|
hr = pCPhone->m_WavePlayer.GetVolume( &dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (pCPhone->m_fVolumeUp)
|
|
{
|
|
dwVolume += pCPhone->m_dwAutoVolumeControlStep;
|
|
|
|
if (dwVolume > 0xFFFF)
|
|
{
|
|
dwVolume = 0xFFFF;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwVolume -= pCPhone->m_dwAutoVolumeControlStep;
|
|
|
|
if (dwVolume > 0xFFFF)
|
|
{
|
|
dwVolume = 0x0000;
|
|
}
|
|
}
|
|
|
|
hr = pCPhone->m_WavePlayer.SetVolume( dwVolume );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
STATICLOG((TL_INFO, "VolumeTimerCallback - Volume: %lx", dwVolume));
|
|
}
|
|
else
|
|
{
|
|
STATICLOG((TL_INFO, "VolumeTimerCallback - SetVolume failed - %lx", hr));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
STATICLOG((TL_INFO, "VolumeTimerCallback - GetVolume failed - %lx", hr));
|
|
}
|
|
}
|
|
|
|
STATICLOG((TL_TRACE, "VolumeTimerCallback - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
VOID CALLBACK CPhone::AutoEndOfNumberTimerCallback(
|
|
PVOID lpParameter,
|
|
BOOLEAN TimerOrWaitFired
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
CPhone * pCPhone = (CPhone *)(lpParameter);
|
|
|
|
STATICLOG((TL_TRACE, "AutoEndOfNumberTimerCallback - enter"));
|
|
|
|
if (pCPhone != NULL)
|
|
{
|
|
pCPhone->Automation_EndOfNumberTimeout();
|
|
}
|
|
|
|
STATICLOG((TL_TRACE, "AutoEndOfNumberTimerCallback - exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// GetPhoneWaveRenderID
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT CPhone::GetPhoneWaveRenderID(DWORD * pdwWaveID)
|
|
{
|
|
T3PHONE t3Phone;
|
|
HRESULT hr;
|
|
LPVARSTRING pVarString = NULL;
|
|
DWORD dwPhoneWaveID;
|
|
|
|
//
|
|
// get wave device ids associated with this phone
|
|
// we need to open the phone device to do this
|
|
// Must use monitor privilege, because owner privilege open will
|
|
// fail if anyone happens to have the phone open as owner.
|
|
//
|
|
|
|
t3Phone.hPhone = NULL;
|
|
t3Phone.pPhone = this;
|
|
|
|
Lock();
|
|
|
|
hr = PhoneOpen(m_hPhoneApp,
|
|
m_dwDeviceID,
|
|
&t3Phone,
|
|
m_dwAPIVersion,
|
|
PHONEPRIVILEGE_MONITOR
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = PhoneGetID(
|
|
t3Phone.hPhone,
|
|
&pVarString,
|
|
L"wave/out"
|
|
);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (pVarString->dwStringSize == sizeof(DWORD))
|
|
{
|
|
CopyMemory(
|
|
pdwWaveID,
|
|
((LPBYTE)pVarString)+pVarString->dwStringOffset,
|
|
pVarString->dwStringSize
|
|
);
|
|
|
|
LOG((TL_INFO, "GetPhoneWaveRenderID - got phone wave "
|
|
"render id %d", *pdwWaveID ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneRenderWaveID - PhoneGetID failed %08x", hr ));
|
|
}
|
|
|
|
if ( NULL != pVarString )
|
|
{
|
|
ClientFree( pVarString );
|
|
}
|
|
|
|
PhoneClose(t3Phone.hPhone);
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "GetPhoneRenderWaveID - PhoneOpen failed %08x", hr ));
|
|
}
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::OpenWaveDevice(
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "OpenWaveDevice - enter" ));
|
|
|
|
if (!m_WavePlayer.IsInitialized())
|
|
{
|
|
hr = m_WavePlayer.Initialize();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "OpenWaveDevice - Initialize failed %08x", hr ));
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!m_WavePlayer.IsInUse())
|
|
{
|
|
if (m_fUseWaveForRinger)
|
|
{
|
|
hr = m_WavePlayer.OpenWaveDeviceForRing( WAVE_MAPPER );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "OpenWaveDevice - OpenWaveDeviceForRing failed %08x", hr ));
|
|
}
|
|
}
|
|
|
|
long lWaveId;
|
|
|
|
hr = GetPhoneWaveRenderID( (DWORD *) & lWaveId );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "OpenWaveDevice - GetPhoneWaveRenderID failed %08x", hr ));
|
|
|
|
return;
|
|
}
|
|
|
|
hr = m_WavePlayer.OpenWaveDeviceForTone( lWaveId );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "OpenWaveDevice - OpenWaveDeviceForTone failed %08x", hr ));
|
|
}
|
|
|
|
hr = m_WavePlayer.OpenMixerDevice( lWaveId );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "OpenWaveDevice - OpenMixerDevice failed %08x", hr ));
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "OpenWaveDevice - exit" ));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void CPhone::CloseWaveDevice(
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "CloseWaveDevice - enter" ));
|
|
|
|
if (m_WavePlayer.IsInUse())
|
|
{
|
|
if (m_fUseWaveForRinger)
|
|
{
|
|
m_WavePlayer.CloseWaveDeviceForRing();
|
|
}
|
|
|
|
m_WavePlayer.CloseWaveDeviceForTone();
|
|
|
|
m_WavePlayer.CloseMixerDevice();
|
|
}
|
|
|
|
LOG((TL_TRACE, "CloseWaveDevice - exit" ));
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// ITAutomatedPhoneControlQI
|
|
// Don't give out the ITAutomatedPhoneControl interface
|
|
// if the application does not have the phone open.
|
|
// Also, open the wave devices if owner.
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT
|
|
WINAPI
|
|
CPhone::ITAutomatedPhoneControlQI(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw)
|
|
{
|
|
STATICLOG((TL_TRACE,"AutomatedPhoneControlQI - enter"));
|
|
|
|
*ppv = NULL;
|
|
|
|
CPhone * pPhone = ((CPhone *)pv);
|
|
|
|
pPhone->Lock();
|
|
|
|
if (pPhone->m_hPhone == NULL)
|
|
{
|
|
STATICLOG((TL_WARN,"The application does not have this phone open"));
|
|
STATICLOG((TL_WARN,"so it cannot access the AutomatedPhoneControl interface"));
|
|
|
|
pPhone->Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if (pPhone->m_dwPrivilege != PHONEPRIVILEGE_OWNER)
|
|
{
|
|
STATICLOG((TL_WARN,"The application does not have owner privilege"));
|
|
STATICLOG((TL_WARN,"so it cannot access the AutomatedPhoneControl interface"));
|
|
|
|
pPhone->Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
HRESULT hr = pPhone->UpdatePhoneCaps();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR,"UpdatePhoneCaps failed 0x%lx", hr));
|
|
|
|
pPhone->Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( ( pPhone->GetAPIVersion() < TAPI_VERSION2_0 ) ||
|
|
!(pPhone->m_pPhoneCaps->dwPhoneFeatures & PHONEFEATURE_GENERICPHONE) )
|
|
{
|
|
STATICLOG((TL_TRACE,"The phone does not have PCL_GENERICPHONE capability"));
|
|
STATICLOG((TL_TRACE,"so it cannot access the AutomatedPhoneControl interface"));
|
|
|
|
pPhone->Unlock();
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
if ( pPhone->m_pPhoneCaps->dwNumRingModes == 0)
|
|
{
|
|
//
|
|
// The hardware doesn't have a ringer, so use the wave
|
|
// device as a ringer
|
|
//
|
|
|
|
pPhone->m_fUseWaveForRinger = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Use the hardware ringer
|
|
//
|
|
|
|
pPhone->m_fUseWaveForRinger = FALSE;
|
|
}
|
|
|
|
pPhone->OpenWaveDevice();
|
|
|
|
pPhone->Unlock();
|
|
|
|
//
|
|
// S_FALSE tells atl to continue querying for the interface
|
|
//
|
|
|
|
STATICLOG((TL_TRACE, "AutomatedPhoneControlQI - exit"));
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::StartTone(
|
|
IN PHONE_TONE Tone,
|
|
IN long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fResult;
|
|
|
|
LOG((TL_TRACE, "StartTone - enter"));
|
|
|
|
//
|
|
// Check arguments.
|
|
//
|
|
|
|
if ( ( Tone < PT_KEYPADZERO) || ( Tone > PT_SILENCE ) )
|
|
{
|
|
LOG((TL_ERROR, "StartTone - "
|
|
"invalid tone type - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( lDuration < 0 )
|
|
{
|
|
LOG((TL_ERROR, "StartTone - "
|
|
"negative argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "StartTone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "StartTone - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Kill the tone timer
|
|
//
|
|
|
|
if (m_hToneTimer)
|
|
{
|
|
EnterCriticalSection( &m_csToneTimer );
|
|
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hToneTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hToneTimer = NULL;
|
|
|
|
LeaveCriticalSection( &m_csToneTimer );
|
|
}
|
|
|
|
//
|
|
// Stop the old tone if there was one
|
|
//
|
|
|
|
if (m_Tone != PT_SILENCE)
|
|
{
|
|
m_WavePlayer.StopTone( (long) m_Tone );
|
|
m_Tone = PT_SILENCE;
|
|
}
|
|
|
|
//
|
|
// Start the new tone if needed
|
|
//
|
|
|
|
if ( Tone != PT_SILENCE )
|
|
{
|
|
//
|
|
// Set duration and period
|
|
//
|
|
|
|
m_dwToneDuration = lDuration;
|
|
|
|
switch ( Tone )
|
|
{
|
|
case PT_BUSY:
|
|
m_dwTonePeriodOn = 500;
|
|
m_dwTonePeriodOff = 500;
|
|
break;
|
|
|
|
case PT_RINGBACK:
|
|
m_dwTonePeriodOn = 2000;
|
|
m_dwTonePeriodOff = 4000;
|
|
break;
|
|
|
|
case PT_ERRORTONE:
|
|
m_dwTonePeriodOn = 100;
|
|
m_dwTonePeriodOff = 100;
|
|
break;
|
|
|
|
default: // not periodic
|
|
m_dwTonePeriodOn = 0;
|
|
m_dwTonePeriodOff = 0;
|
|
break;
|
|
}
|
|
|
|
hr = m_WavePlayer.StartTone( (long) Tone );
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( (m_dwTonePeriodOn > 0) &&
|
|
((m_dwTonePeriodOn < m_dwToneDuration) || (m_dwToneDuration == 0)) )
|
|
{
|
|
//
|
|
// Tone is periodic and duration is greater than the period
|
|
//
|
|
|
|
fResult = CreateTimerQueueTimer(&m_hToneTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::ToneTimerCallback,
|
|
(PVOID)this,
|
|
m_dwTonePeriodOn,
|
|
TIMER_KEEP_ALIVE,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, lets stop the tone and bail out
|
|
LOG((TL_ERROR, "StartTone - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
m_WavePlayer.StopTone( (long) Tone );
|
|
}
|
|
}
|
|
else if (m_dwToneDuration > 0)
|
|
{
|
|
//
|
|
// Tone is not periodic, or duration is less than the period
|
|
//
|
|
|
|
fResult = CreateTimerQueueTimer(&m_hToneTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::ToneTimerCallback,
|
|
(PVOID)this,
|
|
m_dwToneDuration,
|
|
0,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, lets stop the tone and bail out
|
|
LOG((TL_ERROR, "StartTone - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
|
|
m_WavePlayer.StopTone( (long) Tone );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "StartTone - exit 0x%08x", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
m_Tone = Tone;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "StartTone - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::StopTone()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG((TL_TRACE, "StopTone - enter"));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "StopTone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "StopTone - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Kill the tone timer
|
|
//
|
|
|
|
if (m_hToneTimer)
|
|
{
|
|
EnterCriticalSection( &m_csToneTimer );
|
|
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hToneTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hToneTimer = NULL;
|
|
|
|
LeaveCriticalSection( &m_csToneTimer );
|
|
}
|
|
|
|
//
|
|
// Stop the old tone if there was one
|
|
//
|
|
|
|
if (m_Tone != PT_SILENCE)
|
|
{
|
|
hr = m_WavePlayer.StopTone( (long) m_Tone );
|
|
m_Tone = PT_SILENCE;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_ERROR, "StopTone - exit - return %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_Tone(
|
|
OUT PHONE_TONE * pTone
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_Tone - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pTone, sizeof( PHONE_TONE ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Tone - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_Tone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
*pTone = m_Tone;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Tone - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::StartRinger(
|
|
IN long lRingMode,
|
|
IN long lDuration
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
DWORD dwVolume;
|
|
BOOL fResult;
|
|
|
|
LOG((TL_TRACE, "StartRinger - enter"));
|
|
|
|
if ( lDuration < 0 )
|
|
{
|
|
LOG((TL_ERROR, "StartRinger - "
|
|
"negative argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "StartRinger - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "StartRinger - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Kill ring timer
|
|
//
|
|
|
|
if (m_hRingTimer)
|
|
{
|
|
EnterCriticalSection( &m_csRingTimer );
|
|
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hRingTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hRingTimer = NULL;
|
|
|
|
LeaveCriticalSection( &m_csRingTimer );
|
|
}
|
|
|
|
//
|
|
// Start ring and set duration and period
|
|
//
|
|
|
|
m_dwRingDuration = lDuration;
|
|
|
|
if (lRingMode == 0)
|
|
{
|
|
if (m_fUseWaveForRinger)
|
|
{
|
|
m_dwRingPeriod = 4000;
|
|
|
|
hr = m_WavePlayer.StartRing();
|
|
}
|
|
else
|
|
{
|
|
m_dwRingPeriod = 0;
|
|
|
|
hr = put_RingMode(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_dwRingPeriod = 0;
|
|
|
|
hr = put_RingMode(lRingMode);
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "StartRinger - exit 0x%08x", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( (m_dwRingPeriod > 0) &&
|
|
((m_dwRingPeriod < m_dwRingDuration) || (m_dwRingDuration == 0)) )
|
|
{
|
|
//
|
|
// Ring is periodic (wave generated) and duration is greater than the period
|
|
//
|
|
fResult = CreateTimerQueueTimer(&m_hRingTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::RingTimerCallback,
|
|
(PVOID)this,
|
|
m_dwRingPeriod,
|
|
m_dwRingPeriod,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, lets stop the ring and bail out
|
|
LOG((TL_ERROR, "StartRinger - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else if (m_dwRingDuration > 0)
|
|
{
|
|
//
|
|
// Ring is not periodic (ringer generated), or duration is less than period
|
|
//
|
|
fResult = CreateTimerQueueTimer(&m_hRingTimer,
|
|
m_hTimerQueue,
|
|
&CPhone::RingTimerCallback,
|
|
(PVOID)this,
|
|
m_dwRingDuration,
|
|
0,
|
|
WT_EXECUTEINIOTHREAD
|
|
);
|
|
|
|
if (fResult == FALSE)
|
|
{
|
|
// CreateTimerQueueTimer failed, lets stop the ring and bail out
|
|
LOG((TL_ERROR, "StartRinger - CreateTimerQueueTimer failed - %lx", GetLastError()));
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
if (m_fUseWaveForRinger)
|
|
{
|
|
m_WavePlayer.StopRing();
|
|
}
|
|
else
|
|
{
|
|
put_RingMode(0);
|
|
}
|
|
|
|
LOG((TL_ERROR, "StartRinger - exit 0x%08x", hr));
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
m_fRinger = TRUE;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "StartRinger - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::StopRinger()
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwDummy;
|
|
DWORD dwVolume;
|
|
|
|
LOG((TL_TRACE, "StopRinger - enter"));
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "StopRinger - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "StopRinger - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Kill ring timer
|
|
//
|
|
|
|
if (m_hRingTimer)
|
|
{
|
|
EnterCriticalSection( &m_csRingTimer );
|
|
|
|
DeleteTimerQueueTimer(m_hTimerQueue,
|
|
m_hRingTimer,
|
|
INVALID_HANDLE_VALUE // blocking
|
|
);
|
|
|
|
m_hRingTimer = NULL;
|
|
|
|
LeaveCriticalSection( &m_csRingTimer );
|
|
}
|
|
|
|
if (m_fUseWaveForRinger)
|
|
{
|
|
hr = m_WavePlayer.StopRing();
|
|
}
|
|
else
|
|
{
|
|
hr = put_RingMode( 0 );
|
|
}
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "StopRinger - exit 0x%08x", hr));
|
|
|
|
Unlock();
|
|
return hr;
|
|
}
|
|
|
|
m_fRinger = FALSE;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "StopRinger - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_Ringer(
|
|
OUT VARIANT_BOOL * pfRinging
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_Ringer - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfRinging, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Ringer - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_Ringer - phone not open"));
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
*pfRinging = m_fRinger ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_Ringer - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_PhoneHandlingEnabled(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_PhoneHandlingEnabled - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_PhoneHandlingEnabled - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_PhoneHandlingEnabled - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// Make sure there is no call selected on the phone
|
|
//
|
|
|
|
if ( m_pCall != NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_PhoneHandlingEnabled - a call is "
|
|
"selected - exit TAPI_E_INUSE"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_INUSE;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fPhoneHandlingEnabled = fEnabled ? TRUE : FALSE;
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwHookSwitchDevs;
|
|
|
|
m_dwOffHookCount = 0;
|
|
|
|
hr = PhoneGetHookSwitch(m_hPhone, &dwHookSwitchDevs);
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if (dwHookSwitchDevs & PHONEHOOKSWITCHDEV_HANDSET) m_dwOffHookCount++;
|
|
if (dwHookSwitchDevs & PHONEHOOKSWITCHDEV_SPEAKER) m_dwOffHookCount++;
|
|
if (dwHookSwitchDevs & PHONEHOOKSWITCHDEV_HEADSET) m_dwOffHookCount++;
|
|
|
|
if (m_dwOffHookCount > 0)
|
|
{
|
|
// phone is off hook
|
|
m_AutomatedPhoneState = APS_OFFHOOK_DEAD_LINE;
|
|
}
|
|
else
|
|
{
|
|
// phone is on hook
|
|
m_AutomatedPhoneState = APS_ONHOOK_IDLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG((TL_ERROR, "put_PhoneHandlingEnabled - PhoneGetHookSwitch failed - %lx", hr));
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_PhoneHandlingEnabled - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_PhoneHandlingEnabled(
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_PhoneHandlingEnabled - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneHandlingEnabled - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_PhoneHandlingEnabled - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fPhoneHandlingEnabled ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_PhoneHandlingEnabled - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoEndOfNumberTimeout(
|
|
IN long lTimeout
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoEndOfNumberTimeout - "
|
|
"enter"));
|
|
|
|
if ( lTimeout < 0 )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoEndOfNumberTimeout - "
|
|
"negative argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoEndOfNumberTimeout - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoEndOfNumberTimeout - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_dwAutoEndOfNumberTimeout = lTimeout;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoEndOfNumberTimeout - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoEndOfNumberTimeout(
|
|
OUT long * plTimeout
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoEndOfNumberTimeout - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plTimeout, sizeof( long ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoEndOfNumberTimeout - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoEndOfNumberTimeout - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*plTimeout = m_dwAutoEndOfNumberTimeout;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoEndOfNumberTimeout - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoDialtone(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoDialtone - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoDialtone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoDialtone - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fAutoDialtone = fEnabled ? TRUE : FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoDialtone - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoDialtone(
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoDialtone - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoDialtone - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoDialtone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fAutoDialtone ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoDialtone - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoStopTonesOnOnHook(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoStopTonesOnOnHook - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoStopTonesOnOnHook - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoStopTonesOnOnHook - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fAutoStopTonesOnOnHook = fEnabled ? TRUE : FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoStopTonesOnOnHook - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoStopTonesOnOnHook(
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoStopTonesOnOnHook - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoStopTonesOnOnHook - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoDialtone - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fAutoStopTonesOnOnHook ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoStopTonesOnOnHook - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoStopRingOnOffHook(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoStopRingOnOffHook - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoStopRingOnOffHook - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoStopRingOnOffHook - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fAutoStopRingOnOffHook = fEnabled ? TRUE : FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoStopRingOnOffHook - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoStopRingOnOffHook(
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoStopRingOnOffHook - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoStopRingOnOffHook - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoStopRingOnOffHook - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fAutoStopRingOnOffHook ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoStopRingOnOffHook - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoKeypadTones(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoKeypadTones - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoKeypadTones - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoKeypadTones - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fAutoKeypadTones = fEnabled ? TRUE : FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoKeypadTones - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoKeypadTones (
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoKeypadTones - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoKeypadTones - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoKeypadTones - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fAutoKeypadTones ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoKeypadTones - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoKeypadTonesMinimumDuration(
|
|
IN long lDuration
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoKeypadTonesMinimumDuration - "
|
|
"enter"));
|
|
|
|
if ( lDuration < 0 )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoKeypadTonesMinimumDuration - "
|
|
"negative argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoKeypadTonesMinimumDuration - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoKeypadTonesMinimumDuration - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_dwAutoKeypadTonesMinimumDuration = lDuration;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoKeypadTonesMinimumDuration - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoKeypadTonesMinimumDuration(
|
|
OUT long * plDuration
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoKeypadTonesMinimumDuration - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plDuration, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoKeypadTonesMinimumDuration - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoKeypadTonesMinimumDuration - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*plDuration = m_dwAutoKeypadTonesMinimumDuration;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoKeypadTonesMinimumDuration - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoVolumeControl(
|
|
IN VARIANT_BOOL fEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoVolumeControl - "
|
|
"enter"));
|
|
|
|
//
|
|
// Translate from VARIANT_BOOL to BOOL. If someone mistakenly
|
|
// passes in TRUE instead of VARIANT_TRUE, we are still ok.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControl - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControl - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_fAutoVolumeControl = fEnabled ? TRUE : FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoVolumeControl - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoVolumeControl (
|
|
OUT VARIANT_BOOL * pfEnabled
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoVolumeControl - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( pfEnabled, sizeof( VARIANT_BOOL ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControl - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Translate from BOOL to VARIANT_BOOL.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControl - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*pfEnabled = m_fAutoVolumeControl ? VARIANT_TRUE : VARIANT_FALSE;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoVolumeControl - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoVolumeControlStep(
|
|
IN long lStepSize
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoVolumeControlStep - "
|
|
"enter"));
|
|
|
|
if ( (lStepSize < 0) || (lStepSize > 0xFFFF) )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlStep - "
|
|
"invalid argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlStep - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlStep - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_dwAutoVolumeControlStep = lStepSize;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoVolumeControlStep - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoVolumeControlStep(
|
|
OUT long * plStepSize
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoVolumeControlStep - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plStepSize, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlStep - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlStep - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*plStepSize = m_dwAutoVolumeControlStep;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoVolumeControlStep - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoVolumeControlRepeatDelay(
|
|
IN long lDelay
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoVolumeControlRepeatDelay - "
|
|
"enter"));
|
|
|
|
if ( lDelay < 0 )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatDelay - "
|
|
"invalid argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatDelay - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatDelay - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_dwAutoVolumeControlRepeatDelay = lDelay;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoVolumeControlRepeatDelay - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoVolumeControlRepeatDelay(
|
|
OUT long * plDelay
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoVolumeControlRepeatDelay - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plDelay, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlRepeatDelay - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlRepeatDelay - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*plDelay = m_dwAutoVolumeControlRepeatDelay;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoVolumeControlRepeatDelay - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::put_AutoVolumeControlRepeatPeriod(
|
|
IN long lPeriod
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "put_AutoVolumeControlRepeatPeriod - "
|
|
"enter"));
|
|
|
|
if ( lPeriod < 0 )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatPeriod - "
|
|
"invalid argument - exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatPeriod - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "put_AutoVolumeControlRepeatPeriod - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
m_dwAutoVolumeControlRepeatPeriod = lPeriod;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "put_AutoVolumeControlRepeatPeriod - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_AutoVolumeControlRepeatPeriod(
|
|
OUT long * plPeriod
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_AutoVolumeControlRepeatPeriod - "
|
|
"enter"));
|
|
|
|
if ( TAPIIsBadWritePtr( plPeriod, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlRepeatPeriod - "
|
|
"bad parameter - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_AutoVolumeControlRepeatPeriod - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
*plPeriod = m_dwAutoVolumeControlRepeatPeriod;
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
Unlock();
|
|
|
|
LOG((TL_TRACE, "get_AutoVolumeControlRepeatPeriod - "
|
|
"exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
// UnselectAllPreviouslySelectedTerminals
|
|
//
|
|
// pCallBCC2 -- the call on which we started to select terminals
|
|
// pTerminal -- the last terminal we tried to select; it failed
|
|
// pEnum -- the enumerator that gave us the terminals we tried to select
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
void
|
|
CPhone::UnselectAllPreviouslySelectedTerminals(
|
|
IN ITBasicCallControl2 * pCall,
|
|
IN ITTerminal * pTerminalThatFailed,
|
|
IN IEnumTerminal * pEnum
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "UnselectAllPreviouslySelectedTerminals - "
|
|
"enter"));
|
|
|
|
//
|
|
// Reset the enumerator. If this fails, stop -- we don't want to risk
|
|
// unselecting terminals that were selected independently of SelectCall().
|
|
//
|
|
|
|
hr = pEnum->Reset();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN,
|
|
"UnselectAllPreviouslySelectedTerminals - "
|
|
"failed to reset enumerator %p - "
|
|
"hr = 0x%08x. Not unselecting terminals.", pEnum, hr ));
|
|
|
|
return;
|
|
}
|
|
|
|
ITTerminal * pTerminal;
|
|
BOOL fDone = FALSE;
|
|
|
|
while ( S_OK == pEnum->Next( 1, & pTerminal, NULL ) )
|
|
{
|
|
if ( pTerminal == pTerminalThatFailed )
|
|
{
|
|
fDone = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Try to unselect the terminal. If it fails to unselect, there's
|
|
// nothing more we can do... just continue trying to unselect the
|
|
// rest of the terminals.
|
|
//
|
|
|
|
hr = pCall->UnselectTerminalOnCall( pTerminal );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_WARN,
|
|
"UnselectAllPreviouslySelectedTerminals - "
|
|
"cannot unselect terminal %p on ITBCC2 %p - "
|
|
"hr = 0x%08x. Continuing...", pTerminal, pCall, hr ));
|
|
}
|
|
}
|
|
|
|
pTerminal->Release();
|
|
|
|
if ( fDone == TRUE )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
LOG((TL_TRACE, "UnselectAllPreviouslySelectedTerminals - "
|
|
"normal exit"));
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT
|
|
CPhone::SelectDefaultTerminalsOnCall(
|
|
IN ITCallInfo * pCall
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "SelectDefaultTerminalsOnCall - enter" ));
|
|
|
|
//
|
|
// Get the address for the call
|
|
//
|
|
|
|
HRESULT hr;
|
|
ITAddress * pAddress;
|
|
|
|
hr = pCall->get_Address( & pAddress );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectDefaultTerminalsOnCall - "
|
|
"cannot get call's "
|
|
"address - exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Find the default terminals for this phone.
|
|
//
|
|
|
|
IEnumTerminal * pEnum;
|
|
|
|
hr = EnumerateTerminals( pAddress, & pEnum );
|
|
|
|
pAddress->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectDefaultTerminalsOnCall - "
|
|
"cannot enum phone's "
|
|
"terminals - exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the terminal selection interface on the call.
|
|
//
|
|
|
|
ITBasicCallControl2 * pCallBCC2;
|
|
|
|
hr = pCall->QueryInterface( IID_ITBasicCallControl2,
|
|
(void **) & pCallBCC2 );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectDefaultTerminalsOnCall - "
|
|
"cannot get call's "
|
|
"ITBasicCallControl2 interface - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
pEnum->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Select each of the default terminals on the call.
|
|
//
|
|
|
|
ITTerminal * pTerminal;
|
|
|
|
while ( S_OK == pEnum->Next( 1, & pTerminal, NULL ) )
|
|
{
|
|
//
|
|
// Select each terminal on the call.
|
|
// If one selection fails, unselect all the terminals
|
|
// that were successfully selected.
|
|
//
|
|
|
|
hr = pCallBCC2->SelectTerminalOnCall( pTerminal );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectDefaultTerminalsOnCall - "
|
|
"cannot select "
|
|
"terminal %p on ITBCC2 %p - "
|
|
"unselecting other terminals",
|
|
pTerminal, pCallBCC2 ));
|
|
|
|
UnselectAllPreviouslySelectedTerminals(pCallBCC2,
|
|
pTerminal,
|
|
pEnum);
|
|
|
|
LOG((TL_ERROR, "SelectDefaultTerminalsOnCall - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
pTerminal->Release();
|
|
|
|
pEnum->Release();
|
|
|
|
pCallBCC2->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
pTerminal->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
pCallBCC2->Release();
|
|
|
|
LOG((TL_TRACE, "SelectDefaultTerminalsOnCall - exit S_OK" ));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT
|
|
CPhone::UnselectDefaultTerminalsOnCall(
|
|
IN ITCallInfo * pCall
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "UnselectDefaultTerminalsOnCall - enter" ));
|
|
|
|
//
|
|
// Get the address for the call
|
|
//
|
|
|
|
HRESULT hr;
|
|
ITAddress * pAddress;
|
|
|
|
hr = pCall->get_Address( & pAddress );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectDefaultTerminalsOnCall - "
|
|
"cannot get call's "
|
|
"address - exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Find the default terminals for this phone.
|
|
//
|
|
|
|
IEnumTerminal * pEnum;
|
|
|
|
hr = EnumerateTerminals( pAddress, & pEnum );
|
|
|
|
pAddress->Release();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectDefaultTerminalsOnCall - "
|
|
"cannot enum phone's "
|
|
"terminals - exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the terminal selection interface on the call.
|
|
//
|
|
|
|
ITBasicCallControl2 * pCallBCC2;
|
|
|
|
hr = pCall->QueryInterface( IID_ITBasicCallControl2,
|
|
(void **) & pCallBCC2 );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectDefaultTerminalsOnCall - "
|
|
"cannot get call's "
|
|
"ITBasicCallControl2 interface - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
pEnum->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Unselect each of the default terminals on the call.
|
|
//
|
|
|
|
ITTerminal * pTerminal;
|
|
|
|
while ( S_OK == pEnum->Next( 1, & pTerminal, NULL ) )
|
|
{
|
|
//
|
|
// Unselect each terminal on the call.
|
|
// If one unselection fails, keep on going
|
|
//
|
|
|
|
hr = pCallBCC2->UnselectTerminalOnCall( pTerminal );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectDefaultTerminalsOnCall - "
|
|
"cannot unselect "
|
|
"terminal %p on ITBCC2 %p",
|
|
pTerminal, pCallBCC2 ));
|
|
}
|
|
|
|
pTerminal->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
|
|
pCallBCC2->Release();
|
|
|
|
LOG((TL_TRACE, "UnselectDefaultTerminalsOnCall - exit S_OK" ));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::SelectCall(
|
|
IN ITCallInfo * pCall,
|
|
IN VARIANT_BOOL fSelectDefaultTerminals
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
CALL_STATE cs;
|
|
CALL_PRIVILEGE priv;
|
|
|
|
LOG((TL_TRACE, "SelectCall - enter"));
|
|
|
|
//
|
|
// check argument
|
|
//
|
|
|
|
if ( IsBadReadPtr( pCall, sizeof( ITCallInfo ) ) )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - exit E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Check if the app has owner privilege on this call.
|
|
//
|
|
|
|
hr = pCall->get_Privilege( & priv );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - cannot get call privilege - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( priv != CP_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - wrong call privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// check to make sure the call state isn't disconnected
|
|
//
|
|
|
|
hr = pCall->get_CallState( & cs );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - cannot get call state - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
if ( cs == CS_DISCONNECTED )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - call is disconnected - "
|
|
"exit TAPI_E_INVALCALLSTATE"));
|
|
|
|
return TAPI_E_INVALCALLSTATE;
|
|
}
|
|
|
|
//
|
|
// check if another call already selected
|
|
//
|
|
|
|
Lock();
|
|
|
|
if ( m_pCall != NULL )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - another call already "
|
|
"selected - exit TAPI_E_INUSE"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_INUSE;
|
|
}
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege.
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
m_fDefaultTerminalsSelected = FALSE;
|
|
|
|
//
|
|
// Perform default terminal selection if the invoker wants it.
|
|
//
|
|
|
|
if ( fSelectDefaultTerminals != VARIANT_FALSE )
|
|
{
|
|
hr = SelectDefaultTerminalsOnCall( pCall );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - failed to select "
|
|
"terminals - exit 0x%08x", hr ));
|
|
|
|
Unlock();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Set this flag so that we know to unselect the terminals from the call when
|
|
// the call is unselected
|
|
//
|
|
|
|
m_fDefaultTerminalsSelected = TRUE;
|
|
}
|
|
|
|
m_pCall = pCall;
|
|
m_pCall->AddRef();
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// Now that the call is selected, get the callstate
|
|
// so we can call Automation_CallState
|
|
//
|
|
|
|
hr = pCall->get_CallState( & cs );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "SelectCall - cannot get call state - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
Automation_CallState( pCall, cs, CEC_NONE );
|
|
|
|
LOG((TL_TRACE, "SelectCall - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
HRESULT
|
|
CPhone::InternalUnselectCall(
|
|
IN ITCallInfo * pCall
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "InternalUnselectCall - enter"));
|
|
|
|
Lock();
|
|
|
|
if ( pCall != m_pCall )
|
|
{
|
|
LOG((TL_ERROR, "InternalUnselectCall - call was not selected; "
|
|
"exit TAPI_E_CALLNOTSELECTED"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_CALLNOTSELECTED;
|
|
}
|
|
|
|
//
|
|
// Make sure the phone is open with owner privilege
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "InternalUnselectCall - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_dwPrivilege != PHONEPRIVILEGE_OWNER )
|
|
{
|
|
LOG((TL_ERROR, "InternalUnselectCall - wrong phone privilege - "
|
|
"exit TAPI_E_NOTOWNER"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_NOTOWNER;
|
|
}
|
|
|
|
//
|
|
// If we selected the default terminals on the call when the call was selected on this phone,
|
|
// then we need to unselect the default terminals from the call.
|
|
//
|
|
|
|
if ( m_fDefaultTerminalsSelected == TRUE )
|
|
{
|
|
hr = UnselectDefaultTerminalsOnCall( pCall );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "InternalUnselectCall - UnselectDefaultTerminalsOnCall %p failed - %lx", pCall, hr ));
|
|
|
|
// If we fail here then maybe the app already unselected the terminals. In any case
|
|
// just continue...
|
|
}
|
|
|
|
m_fDefaultTerminalsSelected = FALSE;
|
|
}
|
|
|
|
//
|
|
// Release our reference to the call.
|
|
//
|
|
|
|
m_pCall->Release();
|
|
m_pCall = NULL;
|
|
|
|
LOG((TL_TRACE, "InternalUnselectCall - exit S_OK"));
|
|
|
|
Unlock();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::UnselectCall(
|
|
IN ITCallInfo * pCall
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
LOG((TL_TRACE, "UnselectCall - enter"));
|
|
|
|
//
|
|
// Check arguments.
|
|
//
|
|
|
|
if (IsBadReadPtr(pCall, sizeof( ITCallInfo ) ) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectCall - "
|
|
"returning E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
hr = InternalUnselectCall( pCall );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "UnselectCall - "
|
|
"InternalUnselectCall failed 0x%lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
EnterCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
if (m_fPhoneHandlingEnabled)
|
|
{
|
|
switch(m_AutomatedPhoneState)
|
|
{
|
|
case APS_ONHOOK_RINGING_IN:
|
|
case APS_ONHOOK_RINGING_OUT:
|
|
case APS_ONHOOK_CONNECTED:
|
|
{
|
|
//
|
|
// Stop the ringer
|
|
//
|
|
|
|
if (m_fRinger == TRUE)
|
|
{
|
|
StopRinger();
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_ONHOOK_IDLE;
|
|
}
|
|
break;
|
|
|
|
case APS_OFFHOOK_RINGING_OUT:
|
|
case APS_OFFHOOK_CALL_INIT:
|
|
case APS_OFFHOOK_CONNECTED:
|
|
{
|
|
//
|
|
// Stop any playing tone
|
|
//
|
|
|
|
if (m_Tone != PT_SILENCE)
|
|
{
|
|
StopTone();
|
|
}
|
|
|
|
m_AutomatedPhoneState = APS_OFFHOOK_DEAD_LINE;
|
|
}
|
|
break;
|
|
}
|
|
} //m_fPhoneHandlingEnabled
|
|
|
|
LeaveCriticalSection(&m_csAutomatedPhoneState);
|
|
|
|
LOG((TL_TRACE, "UnselectCall - exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::EnumerateSelectedCalls(
|
|
OUT IEnumCall ** ppCallEnum
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG((TL_TRACE, "EnumerateSelectedCalls enter" ));
|
|
LOG((TL_TRACE, " ppCallEnum----->%p", ppCallEnum ));
|
|
|
|
//
|
|
// Check arguments.
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(ppCallEnum, sizeof( IEnumCall * ) ) )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateSelectedCalls - "
|
|
"returning E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Create and initialize the enumerator.
|
|
//
|
|
|
|
CComObject< CTapiEnum< IEnumCall, ITCallInfo, &IID_IEnumCall > > * p;
|
|
hr = CComObject< CTapiEnum< IEnumCall, ITCallInfo, &IID_IEnumCall > >
|
|
::CreateInstance( &p );
|
|
|
|
if ( hr != S_OK ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "EnumerateSelectedCalls - "
|
|
"could not create enum - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Initialize adds a reference to p
|
|
hr = p->Initialize( );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
delete p;
|
|
|
|
LOG((TL_ERROR, "EnumerateSelectedCalls - "
|
|
"could not init enum - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// Add our single call to the enumerator, if we have one.
|
|
//
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "EnumerateSelectedCalls - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
p->Release();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_pCall != NULL )
|
|
{
|
|
hr = p->Add( m_pCall );
|
|
}
|
|
else
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
//
|
|
// Return the enum if we succeeded, else throw it away.
|
|
//
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
*ppCallEnum = p;
|
|
|
|
LOG((TL_TRACE, "EnumerateSelectedCalls exit - "
|
|
"hr = 0x%08x", hr ));
|
|
}
|
|
else
|
|
{
|
|
p->Release();
|
|
|
|
LOG((TL_ERROR, "EnumerateSelectedCalls - "
|
|
"could not add call to enum - "
|
|
"exit 0x%08x", hr ));
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
//
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
|
|
|
|
STDMETHODIMP
|
|
CPhone::get_SelectedCalls(
|
|
OUT VARIANT * pVariant
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
LOG((TL_TRACE, "get_SelectedCalls enter" ));
|
|
LOG((TL_TRACE, " pVariant----->%p", pVariant ));
|
|
|
|
//
|
|
// Check arguments.
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr(pVariant, sizeof( pVariant ) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - "
|
|
"returning E_POINTER"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Create an array containing no calls or our single call. This
|
|
// type of array does not keep any COM refcounts. We will pass this
|
|
// array into the collection object initialization, and then we will
|
|
// shut down the array.
|
|
//
|
|
|
|
CTArray<ITCallInfo *> aCalls;
|
|
BOOL fResult;
|
|
|
|
Lock();
|
|
|
|
//
|
|
// Make sure the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - phone is not open - "
|
|
"exit TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
aCalls.Shutdown();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
if ( m_pCall != NULL )
|
|
{
|
|
fResult = aCalls.Add( m_pCall );
|
|
}
|
|
else
|
|
{
|
|
fResult = TRUE;
|
|
}
|
|
|
|
Unlock();
|
|
|
|
if ( fResult == FALSE )
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - "
|
|
"could not add call to array; "
|
|
"exit E_OUTOFMEMORY" ));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Create and initialize the Collection.
|
|
//
|
|
|
|
CComObject< CTapiCollection< ITCallInfo > > * p;
|
|
|
|
hr = CComObject< CTapiCollection< ITCallInfo > >
|
|
::CreateInstance( &p );
|
|
|
|
if ( hr != S_OK ) // CreateInstance deleted object on S_FALSE
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - "
|
|
"could not create Collection - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
aCalls.Shutdown();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the collection object's IDispatch interface.
|
|
//
|
|
|
|
IDispatch * pDisp;
|
|
|
|
hr = p->_InternalQueryInterface( IID_IDispatch,
|
|
(void **) & pDisp );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - "
|
|
"could not get IDispatch interface" ));
|
|
|
|
delete p;
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = p->Initialize( aCalls );
|
|
|
|
aCalls.Shutdown();
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((TL_ERROR, "get_SelectedCalls - "
|
|
"could not init Collection - "
|
|
"exit 0x%08x", hr ));
|
|
|
|
pDisp->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Put the collection object's IDispatch pointer into the variant.
|
|
//
|
|
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = pDisp;
|
|
|
|
LOG((TL_TRACE, "get_SelectedCalls exit - "
|
|
"hr = 0x%08x", hr ));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CPhone
|
|
// Interface : ITPhone
|
|
// Method : DeviceSpecific
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT CPhone::DeviceSpecific(
|
|
IN BYTE *pbDataArray,
|
|
IN DWORD dwSize
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "DeviceSpecific - enter"));
|
|
|
|
|
|
//
|
|
// check if arguments are any good
|
|
//
|
|
|
|
if ( NULL == pbDataArray )
|
|
{
|
|
LOG((TL_ERROR, "DeviceSpecific - pbDataArray is NULL. E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if ( 0 == dwSize )
|
|
{
|
|
LOG((TL_ERROR, "DeviceSpecific - dwSize is 0. E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
//
|
|
// check if the buffer is valid
|
|
//
|
|
|
|
if ( IsBadReadPtr(pbDataArray, dwSize) )
|
|
{
|
|
LOG((TL_ERROR, "DeviceSpecific - bad array passed in [%p] of size %ld", pbDataArray, dwSize));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// starting to access data members. lock.
|
|
//
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// see if the phone is open
|
|
//
|
|
|
|
if ( m_hPhone == NULL )
|
|
{
|
|
LOG((TL_ERROR,
|
|
"DeviceSpecific - phone not open. TAPI_E_PHONENOTOPEN"));
|
|
|
|
Unlock();
|
|
|
|
return TAPI_E_PHONENOTOPEN;
|
|
}
|
|
|
|
|
|
//
|
|
// keep the phone handle
|
|
//
|
|
|
|
HPHONE hPhone = m_hPhone;
|
|
|
|
|
|
Unlock();
|
|
|
|
|
|
//
|
|
// make the tapisrv call. if hPhone becomes invalid, the call will simply
|
|
// fail. this is ok.
|
|
//
|
|
|
|
HRESULT hr = phoneDevSpecific(hPhone, pbDataArray, dwSize);
|
|
|
|
|
|
|
|
LOG((TL_TRACE, "DeviceSpecific - exit. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CPhone
|
|
// Interface : ITPhone
|
|
// Method : DeviceSpecificVariant
|
|
//
|
|
// this is the scriptable version of DeviceSpecific
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT CPhone::DeviceSpecificVariant(
|
|
IN VARIANT varDevSpecificByteArray
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "DeviceSpecificVariant - enter"));
|
|
|
|
|
|
//
|
|
// extract buffer from the variant
|
|
//
|
|
|
|
DWORD dwByteArraySize = 0;
|
|
BYTE *pBuffer = NULL;
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hr = MakeBufferFromVariant(varDevSpecificByteArray, &dwByteArraySize, &pBuffer);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((TL_TRACE, "DeviceSpecificVariant - MakeBufferFromVariant failed. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// call the non-scriptable version and pass it the nonscriptable implementation
|
|
//
|
|
|
|
hr = DeviceSpecific(pBuffer, dwByteArraySize);
|
|
|
|
|
|
//
|
|
// success or failure, free the buffer allocated by MakeBufferFromVariant
|
|
//
|
|
|
|
ClientFree(pBuffer);
|
|
pBuffer = NULL;
|
|
|
|
|
|
//
|
|
// log rc and exit
|
|
//
|
|
|
|
LOG((TL_TRACE, "DeviceSpecificVariant - exit. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
// Class : CPhone
|
|
// Interface : ITPhone
|
|
// Method : NegotiateExtVersion
|
|
//
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT CPhone::NegotiateExtVersion (
|
|
IN long lLowVersion,
|
|
IN long lHighVersion,
|
|
OUT long *plExtVersion
|
|
)
|
|
{
|
|
|
|
LOG((TL_TRACE, "NegotiateExtVersion - enter"));
|
|
|
|
|
|
//
|
|
// make sure the out parameter is writable
|
|
//
|
|
|
|
if (IsBadWritePtr(plExtVersion, sizeof(long)) )
|
|
{
|
|
LOG((TL_ERROR, "NegotiateExtVersion - output arg [%p] not writeable", plExtVersion));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
Lock();
|
|
|
|
|
|
//
|
|
// make a call to tapisrv
|
|
//
|
|
|
|
DWORD dwNegotiatedVersion = 0;
|
|
|
|
LONG lResult = phoneNegotiateExtVersion(m_hPhoneApp,
|
|
m_dwDeviceID,
|
|
m_dwAPIVersion,
|
|
lLowVersion,
|
|
lHighVersion,
|
|
&dwNegotiatedVersion );
|
|
|
|
Unlock();
|
|
|
|
|
|
HRESULT hr = mapTAPIErrorCode(lResult);
|
|
|
|
|
|
//
|
|
// return the value on success
|
|
//
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
LOG((TL_TRACE, "NegotiateExtVersion - negotiated version %ld", dwNegotiatedVersion));
|
|
|
|
*plExtVersion = dwNegotiatedVersion;
|
|
}
|
|
|
|
|
|
LOG((TL_TRACE, "NegotiateExtVersion - exit. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ITPhoneEvent methods
|
|
//
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// FireEvent
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
HRESULT
|
|
CPhoneEvent::FireEvent(
|
|
CPhone * pCPhone,
|
|
PHONE_EVENT Event,
|
|
PHONE_BUTTON_STATE ButtonState,
|
|
PHONE_HOOK_SWITCH_STATE HookSwitchState,
|
|
PHONE_HOOK_SWITCH_DEVICE HookSwitchDevice,
|
|
DWORD dwRingMode,
|
|
DWORD dwButtonLampId,
|
|
PWSTR pNumber,
|
|
ITCallInfo * pCallInfo
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CComObject<CPhoneEvent> * p;
|
|
IDispatch * pDisp;
|
|
|
|
STATICLOG((TL_TRACE, "FireEvent enter" ));
|
|
|
|
//
|
|
// We have to filter Phoneevents because
|
|
// Tapisrv doesn't. Tapi3 receive always phone events
|
|
// and use them to keep alive the Phone object
|
|
//
|
|
|
|
CTAPI* pTapi = pCPhone->GetTapi();
|
|
if( pTapi == NULL )
|
|
{
|
|
STATICLOG((TL_ERROR, "Tapi object is invalid - %lx", E_UNEXPECTED));
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
long nFilterMask = 0;
|
|
pTapi->get_EventFilter( &nFilterMask );
|
|
if( (nFilterMask & TE_PHONEEVENT) == 0 )
|
|
{
|
|
//
|
|
// The user didn't set the mask for TE_PHONEEVENT
|
|
// so we don't fire the event to the application
|
|
//
|
|
STATICLOG((TL_INFO, "The user didn't set the mask for TE_PHONEEVENT."
|
|
" Don't fire the event to app - %lx", S_OK));
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// create event
|
|
//
|
|
hr = CComObject<CPhoneEvent>::CreateInstance( &p );
|
|
|
|
if ( S_OK != hr ) // CreateInstance deletes object on S_FALSE
|
|
{
|
|
STATICLOG((TL_ERROR, "Could not create PhoneEvent object - %lx", hr));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// get idisp interface
|
|
//
|
|
hr = p->QueryInterface(
|
|
IID_IDispatch,
|
|
(void **)&pDisp
|
|
);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR, "Could not get disp interface of PhoneEvent object - %lx", hr));
|
|
|
|
delete p;
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// initialize
|
|
//
|
|
|
|
if (pNumber != NULL)
|
|
{
|
|
p->m_pNumber = SysAllocString( pNumber );
|
|
|
|
if (p->m_pNumber == NULL)
|
|
{
|
|
STATICLOG((TL_ERROR, "Out of memory allocating phone number"));
|
|
|
|
pDisp->Release();
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
p->m_pNumber = NULL;
|
|
}
|
|
|
|
p->m_Event = Event;
|
|
p->m_pPhone = dynamic_cast<ITPhone *>(pCPhone);
|
|
p->m_pPhone->AddRef();
|
|
p->m_ButtonState = ButtonState;
|
|
p->m_HookSwitchState = HookSwitchState;
|
|
p->m_HookSwitchDevice = HookSwitchDevice;
|
|
p->m_dwRingMode = dwRingMode;
|
|
p->m_dwButtonLampId = dwButtonLampId;
|
|
p->m_pCallInfo = pCallInfo;
|
|
if (p->m_pCallInfo != NULL)
|
|
{
|
|
p->m_pCallInfo->AddRef();
|
|
}
|
|
|
|
#if DBG
|
|
p->m_pDebug = (PWSTR) ClientAlloc( 1 );
|
|
#endif
|
|
|
|
//
|
|
// get callback
|
|
//
|
|
//
|
|
// fire event
|
|
//
|
|
(pCPhone->GetTapi())->Event(
|
|
TE_PHONEEVENT,
|
|
pDisp
|
|
);
|
|
|
|
//
|
|
// release stuff
|
|
//
|
|
pDisp->Release();
|
|
|
|
STATICLOG((TL_TRACE, "FireEvent exit - return S_OK" ));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// finalrelease
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void
|
|
CPhoneEvent::FinalRelease()
|
|
{
|
|
LOG((TL_INFO, "CPhoneEvent - FinalRelease"));
|
|
|
|
m_pPhone->Release();
|
|
m_pPhone = NULL;
|
|
|
|
if (m_pCallInfo != NULL)
|
|
{
|
|
m_pCallInfo->Release();
|
|
m_pCallInfo = NULL;
|
|
}
|
|
|
|
if (m_pNumber != NULL)
|
|
{
|
|
SysFreeString(m_pNumber);
|
|
m_pNumber = NULL;
|
|
}
|
|
|
|
#if DBG
|
|
ClientFree( m_pDebug );
|
|
m_pDebug = NULL;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Phone
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_Phone(
|
|
ITPhone ** ppPhone
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(ppPhone , sizeof(ITPhone *) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Phone - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppPhone = m_pPhone;
|
|
(*ppPhone)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Event
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_Event(
|
|
PHONE_EVENT * pEvent
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(pEvent , sizeof(PHONE_EVENT) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Event - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pEvent = m_Event;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonState
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_ButtonState(
|
|
PHONE_BUTTON_STATE * pState
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(pState , sizeof(PHONE_BUTTON_STATE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonState - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_Event != PE_BUTTON)
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonState - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*pState = m_ButtonState;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_HookSwitchState
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_HookSwitchState(
|
|
PHONE_HOOK_SWITCH_STATE * pState
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(pState , sizeof(PHONE_HOOK_SWITCH_STATE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_Event != PE_HOOKSWITCH)
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchState - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*pState = m_HookSwitchState;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_HookSwitchDevice
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_HookSwitchDevice(
|
|
PHONE_HOOK_SWITCH_DEVICE * pDevice
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(pDevice , sizeof(PHONE_HOOK_SWITCH_DEVICE) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchDevice - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_Event != PE_HOOKSWITCH)
|
|
{
|
|
LOG((TL_ERROR, "get_HookSwitchDevice - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*pDevice = m_HookSwitchDevice;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_RingMode
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_RingMode(
|
|
long * plRingMode
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(plRingMode , sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_RingMode - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_Event != PE_RINGMODE)
|
|
{
|
|
LOG((TL_ERROR, "get_RingMode - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*plRingMode = m_dwRingMode;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_ButtonLampId
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_ButtonLampId(
|
|
long *plButtonLampId
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(plButtonLampId , sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonLampId - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ((m_Event != PE_LAMPMODE) && (m_Event != PE_BUTTON))
|
|
{
|
|
LOG((TL_ERROR, "get_ButtonLampId - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*plButtonLampId = m_dwButtonLampId;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_NumberGathered
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_NumberGathered(
|
|
BSTR * ppNumber
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(ppNumber , sizeof(BSTR) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_NumberGathered - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if (m_Event != PE_NUMBERGATHERED)
|
|
{
|
|
LOG((TL_ERROR, "get_NumberGathered - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
*ppNumber = SysAllocString(m_pNumber);
|
|
|
|
if (*ppNumber == NULL)
|
|
{
|
|
LOG((TL_ERROR, "get_NumberGathered - out of memory"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Call
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneEvent::get_Call(
|
|
ITCallInfo ** ppCallInfo
|
|
)
|
|
{
|
|
if (TAPIIsBadWritePtr(ppCallInfo , sizeof(ITCallInfo *) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Call - bad pointer"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ((m_Event != PE_ANSWER) &&
|
|
(m_Event != PE_DISCONNECT))
|
|
{
|
|
LOG((TL_ERROR, "get_Call - wrong event"));
|
|
|
|
return TAPI_E_WRONGEVENT;
|
|
}
|
|
|
|
if ( m_pCallInfo == NULL )
|
|
{
|
|
LOG((TL_ERROR, "get_Call - NULL call pointer"));
|
|
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
*ppCallInfo = m_pCallInfo;
|
|
(*ppCallInfo)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CPhoneDevSpecificEvent
|
|
//
|
|
|
|
// static
|
|
HRESULT CPhoneDevSpecificEvent::FireEvent( CPhone * pCPhone,
|
|
long l1,
|
|
long l2,
|
|
long l3
|
|
)
|
|
{
|
|
STATICLOG((TL_INFO, "CPhoneDevSpecificEvent::FireEvent - enter"));
|
|
|
|
|
|
//
|
|
// try to create the event
|
|
//
|
|
|
|
CComObject<CPhoneDevSpecificEvent> *pEventObject = NULL;
|
|
|
|
HRESULT hr = CComObject<CPhoneDevSpecificEvent>::CreateInstance(&pEventObject);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR,
|
|
"CPhoneDevSpecificEvent::FireEvent - failed to create CPhoneDevSpecificEvent. hr = %lx",
|
|
hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// initialize the event with the data we received
|
|
//
|
|
|
|
|
|
//
|
|
// get ITPhone from CPhone we received
|
|
//
|
|
|
|
hr = pCPhone->_InternalQueryInterface(IID_ITPhone, (void**)(&(pEventObject->m_pPhone)) );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
STATICLOG((TL_ERROR,
|
|
"CPhoneDevSpecificEvent::FireEvent - failed to get ITPhone interface from phone. hr = %lx",
|
|
hr));
|
|
|
|
delete pEventObject;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// keep the actual data
|
|
//
|
|
|
|
pEventObject->m_l1 = l1;
|
|
pEventObject->m_l2 = l2;
|
|
pEventObject->m_l3 = l3;
|
|
|
|
|
|
#if DBG
|
|
pEventObject->m_pDebug = (PWSTR) ClientAlloc( 1 );
|
|
#endif
|
|
|
|
|
|
//
|
|
// get event's idispatch interface
|
|
//
|
|
|
|
IDispatch *pDispatch = NULL;
|
|
|
|
hr = pEventObject->QueryInterface( IID_IDispatch,
|
|
(void **)&pDispatch );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
STATICLOG((TL_ERROR,
|
|
"CPhoneDevSpecificEvent::FireEvent - Could not get disp interface of AddressEvent object %lx",
|
|
hr));
|
|
|
|
|
|
//
|
|
// undo the QI we have performed earlier
|
|
//
|
|
|
|
pEventObject->m_pPhone->Release();
|
|
pEventObject->m_pPhone = NULL;
|
|
|
|
|
|
//
|
|
// delete the event object
|
|
//
|
|
|
|
delete pEventObject;
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//
|
|
// from this point on, we will be using events pDispatch
|
|
//
|
|
|
|
pEventObject = NULL;
|
|
|
|
|
|
//
|
|
// get callback
|
|
//
|
|
//
|
|
// fire event to tapi
|
|
//
|
|
|
|
hr = (pCPhone->GetTapi())->Event( TE_PHONEDEVSPECIFIC, pDispatch);
|
|
|
|
|
|
//
|
|
// succeeded or not, we no longer need a reference to the event object
|
|
//
|
|
|
|
pDispatch->Release();
|
|
pDispatch = NULL;
|
|
|
|
STATICLOG((TL_INFO, "CPhoneDevSpecificEvent::FireEvent - exit. hr = %lx", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
CPhoneDevSpecificEvent::CPhoneDevSpecificEvent()
|
|
:m_pPhone(NULL)
|
|
{
|
|
LOG((TL_INFO, "CPhoneDevSpecificEvent - enter"));
|
|
|
|
#if DBG
|
|
|
|
m_pDebug = NULL;
|
|
|
|
#endif
|
|
|
|
LOG((TL_INFO, "CPhoneDevSpecificEvent - exit"));
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// finalrelease
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
void CPhoneDevSpecificEvent::FinalRelease()
|
|
{
|
|
LOG((TL_INFO, "FinalRelease - enter"));
|
|
|
|
|
|
if (NULL != m_pPhone)
|
|
{
|
|
m_pPhone->Release();
|
|
m_pPhone = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we must have a phone -- if not, there is a bug in our code
|
|
//
|
|
|
|
_ASSERTE(FALSE);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
ClientFree( m_pDebug );
|
|
#endif
|
|
|
|
LOG((TL_INFO, "FinalRelease - exit"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_Phone
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
STDMETHODIMP
|
|
CPhoneDevSpecificEvent::get_Phone(
|
|
ITPhone ** ppPhone
|
|
)
|
|
{
|
|
LOG((TL_TRACE, "get_Phone - enter"));
|
|
|
|
|
|
//
|
|
// good out pointer?
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(ppPhone , sizeof(ITPhone *) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_Phone - bad pointer at [%p]", ppPhone));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// return addreff'd address
|
|
//
|
|
|
|
*ppPhone = m_pPhone;
|
|
(*ppPhone)->AddRef();
|
|
|
|
|
|
LOG((TL_TRACE, "get_Phone- enter. phone[%p]", (*ppPhone) ));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_lParam1
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
STDMETHODIMP CPhoneDevSpecificEvent::get_lParam1( long *pl1 )
|
|
{
|
|
LOG((TL_TRACE, "get_lParam1 - enter"));
|
|
|
|
|
|
//
|
|
// good out pointer?
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(pl1, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_lParam1 - bad pointer at %p", pl1));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// log and return the value
|
|
//
|
|
|
|
*pl1 = m_l1;
|
|
|
|
LOG((TL_TRACE, "get_lParam1 - exit. p1[%ld]", *pl1));
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_lParam2
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
STDMETHODIMP CPhoneDevSpecificEvent::get_lParam2( long *pl2 )
|
|
{
|
|
LOG((TL_TRACE, "get_lParam2 - enter"));
|
|
|
|
|
|
//
|
|
// good out pointer?
|
|
//
|
|
|
|
if (TAPIIsBadWritePtr(pl2, sizeof(long) ) )
|
|
{
|
|
LOG((TL_ERROR, "get_lParam2 - bad pointer at %p", pl2));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// log and return the value
|
|
//
|
|
|
|
*pl2 = m_l2;
|
|
|
|
LOG((TL_TRACE, "get_lParam2 - exit. p2[%ld]", *pl2));
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// get_lParam3
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
STDMETHODIMP CPhoneDevSpecificEvent::get_lParam3( long *pl3 )
|
|
{
|
|
LOG((TL_TRACE, "get_lParam3 - enter"));
|
|
|
|
|
|
//
|
|
// good out pointer?
|
|
//
|
|
|
|
if ( TAPIIsBadWritePtr(pl3, sizeof(long)) )
|
|
{
|
|
LOG((TL_ERROR, "get_lParam3 - bad pointer at %p", pl3));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
|
|
//
|
|
// log and return the value
|
|
//
|
|
|
|
*pl3 = m_l3;
|
|
|
|
LOG((TL_TRACE, "get_lParam3 - exit. p3[%ld]", *pl3));
|
|
|
|
|
|
return S_OK;
|
|
}
|
|
|