/*++ BUILD Version: 0000 // Increment this if a change has global effects Copyright (c) 1996 - 1999 Microsoft Corporation Module Name: client.c Abstract: This module contains the tapi.dll implementation (client-side tapi) Author: Dan Knudson (DanKn) 01-Apr-1995 Revision History: Notes: 1. Make all funcArg structs STATIC, & just do whatever mov's necessary for the params (saves mov's for flags, pfnPostProcess, funcName, & argTypes) --*/ #include "stdafx.h" #include "windows.h" #include "wownt32.h" #include "stdarg.h" #include "stdio.h" #include "private.h" #include "tapsrv.h" #include "loc_comn.h" #include "prsht.h" #include "shellapi.h" #include "tapiperf.h" #include "tlnklist.h" #include "tapievt.h" #include #include extern "C" { #include "tapihndl.h" } #ifdef _WIN64 #define TALIGN_MASK 0xfffffff8 #define TALIGN_COUNT 7 #else #define TALIGN_MASK 0xfffffffc #define TALIGN_COUNT 3 #endif #define ALIGN(a) (((a)+TALIGN_COUNT)&TALIGN_MASK) #define TAPILoadLibraryW LoadLibraryW CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_TAPI, CTAPI) OBJECT_ENTRY(CLSID_DispatchMapper, CDispatchMapper) OBJECT_ENTRY(CLSID_RequestMakeCall, CRequest) END_OBJECT_MAP() typedef LONG (PASCAL *PQCSPROC)(HANDLE, DWORD, DWORD, LPOVERLAPPED); typedef LONG (PASCAL *TUIGDDPROC)(HTAPIDIALOGINSTANCE, LPVOID, DWORD); typedef LONG (PASCAL *TUIGDPROC)(TUISPIDLLCALLBACK, HTAPIDIALOGINSTANCE, LPVOID, DWORD, HANDLE); typedef LONG (PASCAL *TUIPROVPROC)(TUISPIDLLCALLBACK, HWND, DWORD); static PQCSPROC gpPostQueuedCompletionStatus = NULL; typedef LONG (PASCAL *TUILINECONFIGPROC)(TUISPIDLLCALLBACK, DWORD, HWND, LPCSTR); typedef LONG (PASCAL *TUILINECONFIGEDITPROC)(TUISPIDLLCALLBACK, DWORD, HWND, LPCSTR, LPVOID, DWORD, LPVARSTRING); typedef LONG (PASCAL *TUIPHONECONFIGPROC)(TUISPIDLLCALLBACK, DWORD, HWND, LPCSTR); typedef BOOL (PASCAL *ShellExecutePROC)(LPSHELLEXECUTEINFOW); HRESULT mapTAPIErrorCode(long lErrorCode); char *eventName(TAPI_EVENT event); // // messge handlers // void HandleLineDevStateMessage( CTAPI * pTapi, PASYNCEVENTMSG pParams ); void HandleAddressStateMessage( PASYNCEVENTMSG pParams ); void HandlePrivateChannelDataMessage( PASYNCEVENTMSG pParams ); void HandleAgentStatusMessage(PASYNCEVENTMSG pParams); void HandleAgentSessionStatusMessage(PASYNCEVENTMSG pParams); void HandleQueueStatusMessage(PASYNCEVENTMSG pParams); void handleGroupStatusMessage(PASYNCEVENTMSG pParams); void handleProxyStatusMessage( CTAPI * pTapi, PASYNCEVENTMSG pParams); void HandleLineDevSpecificMessage( PASYNCEVENTMSG pParams ); void HandlePhoneDevSpecificMessage( PASYNCEVENTMSG pParams ); void HandleDevSpecificFeatureMessage( PASYNCEVENTMSG pParams ); void HandleMonitorMediaMessage( PASYNCEVENTMSG pParams ); void HandlePrivateUnadviseMessage( PASYNCEVENTMSG pParams ); void HandlePrivateCallhubMessage( PASYNCEVENTMSG pParams ); HRESULT HandleCallStateMessage( PASYNCEVENTMSG pParams ); HRESULT HandleCallInfoMessage( PASYNCEVENTMSG pParams ); HRESULT HandleMonitorDigitsMessage( PASYNCEVENTMSG pParams ); HRESULT HandleMonitorToneMessage( PASYNCEVENTMSG pParams ); HRESULT HandleGatherDigitsMessage( PASYNCEVENTMSG pParams ); HRESULT HandleSendMSPDataMessage( PASYNCEVENTMSG pParams ); HRESULT HandleLineQOSInfoMessage( PASYNCEVENTMSG pParams ); void HandleLineCreate( PASYNCEVENTMSG pParams ); void HandleLineRemove( PASYNCEVENTMSG pParams ); void HandleLineRequest( CTAPI * pTapi, PASYNCEVENTMSG pParams ); void HandleCallHubClose( PASYNCEVENTMSG pParams ); void HandlePrivateMSPEvent( PASYNCEVENTMSG pParams ); void HandleAcceptToAlert( PASYNCEVENTMSG pParams ); HRESULT HandleLineGenerateMessage( PASYNCEVENTMSG pParams ); HRESULT HandleLineCloseMessage( PASYNCEVENTMSG pParams ); void HandlePhoneCreate( PASYNCEVENTMSG pParams ); void HandlePhoneRemove( PASYNCEVENTMSG pParams ); HRESULT HandlePhoneButtonMessage( PASYNCEVENTMSG pParams ); HRESULT HandlePhoneStateMessage( PASYNCEVENTMSG pParams ); HRESULT HandlePhoneCloseMessage( PASYNCEVENTMSG pParams ); LONG WINAPI AllocClientResources( DWORD dwErrorClass ); CAsyncReplyList * gpLineAsyncReplyList; CAsyncReplyList * gpPhoneAsyncReplyList; // The global retry queue CRetryQueue *gpRetryQueue; // // // #define ASNYC_MSG_BUF_SIZE 1024 typedef struct _ASYNC_EVENTS_THREAD_PARAMS { BOOL bExitThread; DWORD dwBufSize; HANDLE hTapi32; HANDLE hWow32; HANDLE hThreadStartupEvent; LPBYTE pBuf; } ASYNC_EVENTS_THREAD_PARAMS, *PASYNC_EVENTS_THREAD_PARAMS; // // N.B. This structure MUST be a multiple of 8 bytes in size. // #if DBG typedef struct _MYMEMINFO { struct _MYMEMINFO * pNext; struct _MYMEMINFO * pPrev; DWORD dwSize; DWORD dwLine; PSTR pszFile; DWORD dwAlign; // LPTSTR pName; } MYMEMINFO, *PMYMEMINFO; PMYMEMINFO gpMemFirst = NULL, gpMemLast = NULL; CRITICAL_SECTION csMemoryList; BOOL gbBreakOnLeak = FALSE; void DumpMemoryList(); #endif // // Global vars // BOOL gbExitThread = FALSE; HANDLE ghCallbackThread = NULL; HANDLE ghAsyncEventsThread = NULL; DWORD gdwTlsIndex; DWORD gdwNumLineDevices = 0; DWORD gdwNumPhoneDevices = 0; HANDLE ghAsyncEventsEvent = NULL; HANDLE ghAsyncRetryQueueEvent = NULL; HANDLE ghCallbackThreadEvent= NULL; HANDLE ghTapiInitShutdownSerializeMutex; // // handle table handle // extern HANDLE ghHandleTable; #if DBG DWORD gdwDebugLevel = 0; #endif typedef LONG (PASCAL *TAPIREQUESTMAKECALLPROC)(LPWSTR, LPWSTR, LPWSTR, LPWSTR); typedef LONG (PASCAL *LINETRANSLATEDIALOGPROC)(HLINEAPP, DWORD, DWORD, HWND, LPWSTR); typedef LONG (PASCAL *LINEINITIALIZEPROC)(LPHLINEAPP, HINSTANCE, LINECALLBACK, LPWSTR, LPDWORD, LPDWORD,LPLINEINITIALIZEEXPARAMS); typedef LONG (PASCAL *LINESHUTDOWNPROC)(HLINEAPP); HINSTANCE ghTapi32 = NULL; HLINEAPP ghLineApp = NULL; LINEINITIALIZEPROC gpInitialize = NULL; LINESHUTDOWNPROC gpShutdown = NULL; CHashTable * gpCallHashTable = NULL; CHashTable * gpLineHashTable = NULL; CHashTable * gpCallHubHashTable = NULL; CHashTable * gpPrivateObjectHashTable = NULL; CHashTable * gpAgentHandlerHashTable = NULL; CHashTable * gpPhoneHashTable = NULL; CHashTable * gpHandleHashTable = NULL; PtrList gCallbackEventPtrList; HINSTANCE ghInst; PASYNC_EVENTS_THREAD_PARAMS gpAsyncEventsThreadParams = NULL; const CHAR gszTapi32MaxNumRequestRetries[] = "Tapi32MaxNumRequestRetries"; const CHAR gszTapi32RequestRetryTimeout[] = "Tapi32RequestRetryTimeout"; const CHAR gszTapi2AsynchronousCallTimeout[] = "AsynchronousCallTimeout"; const CHAR gszTapi3RetryProcessingSleep[] = "Tapi3RetryProcessingSleep"; const CHAR gszTapi3SyncWaitTimeOut[] = "Tapi3SyncWaitTimeOut"; // "Tapi3BlockingCallSleep"; DWORD gdwMaxNumRequestRetries; DWORD gdwRequestRetryTimeout; DWORD gdwTapi2AsynchronousCallTimeout; static const DWORD DEFAULT_TAPI2_ASYNCRONOUS_CALL_TIMEOUT = 120000; static const DWORD DEFAULT_TAPI3_RETRY_PROCESSING_SLEEP = 0; static const DWORD DEFAULT_TAPI3_BLOCKING_CALL_SLEEP = 60000; DWORD gdwTapi3RetryProcessingSleep = DEFAULT_TAPI3_RETRY_PROCESSING_SLEEP; DWORD gdwTapi3SyncWaitTimeOut = DEFAULT_TAPI3_BLOCKING_CALL_SLEEP; const char szTapi32WndClass[] = "Tapi32WndClass"; const CHAR gszTUISPI_providerConfig[] = "TUISPI_providerConfig"; const CHAR gszTUISPI_providerGenericDialog[] = "TUISPI_providerGenericDialog"; const CHAR gszTUISPI_providerGenericDialogData[] = "TUISPI_providerGenericDialogData"; const CHAR gszTUISPI_providerInstall[] = "TUISPI_providerInstall"; const CHAR gszTUISPI_providerRemove[] = "TUISPI_providerRemove"; const CHAR gszTUISPI_lineConfigDialog[] = "TUISPI_lineConfigDialog"; const CHAR gszTUISPI_lineConfigDialogEdit[] = "TUISPI_lineConfigDialogEdit"; const CHAR gszTUISPI_phoneConfigDialog[] = "TUISPI_phoneConfigDialog"; const CHAR gszTelephonyKey[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Telephony"; const CHAR gszNumEntries[] = "NumEntries"; const CHAR gszLocations[] = "Locations"; const WCHAR gszTAPI3[] = L"TAPI3"; BOOL gbTranslateSimple = FALSE; BOOL gbTranslateSilent = FALSE; HINSTANCE ghWow32Dll = NULL; PUITHREADDATA gpUIThreadInstances = NULL; CRITICAL_SECTION gcsTapisrvCommunication; CRITICAL_SECTION gcsCallbackQueue; CRITICAL_SECTION gcsTapi32; CRITICAL_SECTION gcsGlobalInterfaceTable; /*This is the CRITICAL_SECTION to protect m_sTapiObjectArray*/ CRITICAL_SECTION gcsTapiObjectArray; //This is the CRITICAL_SECTION to serialize access to functions //AllocClientResources and FreeClientResources CRITICAL_SECTION gcsClientResources; PCONTEXT_HANDLE_TYPE gphCx = (PCONTEXT_HANDLE_TYPE) NULL; LIST_ENTRY gTlsListHead; CRITICAL_SECTION gTlsCriticalSection; BOOL gbCriticalSectionsInitialized = FALSE; #if DBG const char *aszMsgs[] = { "LINE_ADDRESSSTATE", "LINE_CALLINFO", "LINE_CALLSTATE", "LINE_CLOSE", "LINE_DEVSPECIFIC", "LINE_DEVSPECIFICFEATURE", "LINE_GATHERDIGITS", "LINE_GENERATE", "LINE_LINEDEVSTATE", "LINE_MONITORDIGITS", "LINE_MONITORMEDIA", "LINE_MONITORTONE", "LINE_REPLY", "LINE_REQUEST", "PHONE_BUTTON", "PHONE_CLOSE", "PHONE_DEVSPECIFIC", "PHONE_REPLY", "PHONE_STATE", "LINE_CREATE", "PHONE_CREATE", "LINE_AGENTSPECIFIC", "LINE_AGENTSTATUS", "LINE_APPNEWCALL", "LINE_PROXYREQUEST", "LINE_REMOVE", "PHONE_REMOVE" }; #endif LONG gaNoMemErrors[3] = { TAPIERR_REQUESTFAILED, LINEERR_NOMEM, PHONEERR_NOMEM }; LONG gaInvalHwndErrors[3] = { TAPIERR_INVALWINDOWHANDLE, LINEERR_INVALPARAM, PHONEERR_INVALPARAM }; LONG gaInvalPtrErrors[3] = { TAPIERR_INVALPOINTER, LINEERR_INVALPOINTER, PHONEERR_INVALPOINTER }; LONG gaOpFailedErrors[3] = { TAPIERR_REQUESTFAILED, LINEERR_OPERATIONFAILED, PHONEERR_OPERATIONFAILED }; LONG gaStructTooSmallErrors[3] = { TAPIERR_REQUESTFAILED, LINEERR_STRUCTURETOOSMALL, PHONEERR_STRUCTURETOOSMALL }; LONG gaServiceNotRunningErrors[3] = { TAPIERR_REQUESTFAILED, LINEERR_SERVICE_NOT_RUNNING, PHONEERR_SERVICE_NOT_RUNNING }; #define AllInitExOptions2_0 \ (LINEINITIALIZEEXOPTION_USEHIDDENWINDOW | \ LINEINITIALIZEEXOPTION_USEEVENT | \ LINEINITIALIZEEXOPTION_USECOMPLETIONPORT) // // Function prototypes // void PASCAL lineMakeCallPostProcess( PASYNCEVENTMSG pMsg ); #ifdef __cplusplus extern "C" { #endif BOOL WINAPI _CRT_INIT( HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved ); #ifdef __cplusplus } #endif void FreeInitData( PT3INIT_DATA pInitData ); LONG WINAPI FreeClientResources( void ); LONG CALLBACK TUISPIDLLCallback( ULONG_PTR dwObjectID, DWORD dwObjectType, LPVOID lpParams, DWORD dwSize ); BOOL CALLBACK TranslateDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ); void UIThread( LPVOID pParams ); char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult ); void PASCAL lineDevSpecificPostProcess( PASYNCEVENTMSG pMsg ); BOOL WaveStringIdToDeviceId( LPWSTR pwszStringID, LPCWSTR pwszDeviceType, LPDWORD pdwDeviceId ); HRESULT ProcessMessage( PT3INIT_DATA, PASYNCEVENTMSG ); // // The code... // #if DBG //////////////////////////////////////////////////////////////////////////// // // DWORD_CAST // // casts the argument from type ULONG_PTR to DWORD. provides verification // to make sure no data is lost during the cast. these casts are currently // unavoidable due to the way some of our tapisrv communication logic is // implemented. // // note that casts produce lvalues as long as the size of result does not // exceed the size of the value that is being cast (this is ms-specific // compiler extension that can be disabled by /Za). To be consistent with this // compiler cast behavior, this function returns result by reference. // DWORD DWORD_CAST(ULONG_PTR v) { DWORD dwReturnValue = (DWORD)v; if (v > dwReturnValue) { LOG((TL_ERROR, "DWORD_CAST: information will be lost during cast from %p to %lx", v, dwReturnValue)); DebugBreak(); } return dwReturnValue; } #endif /////////////////////////////////////////////////////////////////////////////// // // DWORD CreateHandleTableEntry(ULONG_PTR nEntry) // // indended to be used to map ULONG_PTR-sized values to 32-bit handles. // // CreateHandleTableEntry creates an entry in the handle table and returns a // 32-bit handle corresponding to it. the handle can later be used to retrieve // the original ULONG_PTR-sized value by calling GetHandleTableEntry or to // remove the entry in handle table by calling DeleteHandleTableEntry // // returns 0 if handle table entry creation failed. // DWORD CreateHandleTableEntry(ULONG_PTR nEntry) { LOG((TL_INFO, "CreateHandleTableEntry - enter. nEntry %p", nEntry)); if (0 == ghHandleTable) { LOG((TL_ERROR, "CreateHandleTableEntry - handle table does not exist.")); // // debug to see why this happened // _ASSERTE(FALSE); return 0; } // // get a 32-bit handle from the (up to) 64-bit pAddressLine. this // is needed to avoid marshaling/passing 64-bit values to tapisrv // (to preserve backward compatibility with older clients and servers) // DWORD dwHandle = NewObject(ghHandleTable, (LPVOID)nEntry, NULL); LOG((TL_INFO, "CreateHandleTableEntry - completed. returning [0x%lx]", dwHandle)); return dwHandle; } ////////////////////////////////////////////////////////////////////////////// // // void DeleteHandleTableEntry(DWORD dwHandle) // // DeleteHandleTableEntry function removes the specified entry from the // handle table. // void DeleteHandleTableEntry(DWORD dwHandle) { LOG((TL_INFO, "DeleteHandleTableEntry - enter. dwHandle 0x%lx", dwHandle )); if (0 == ghHandleTable) { LOG((TL_ERROR, "DeleteHandleTableEntry - handle table does not exist.")); return; } // // handle 0 is a non-handle. deleting handle 0 is analogous to deleting NULL // if (0 == dwHandle) { LOG((TL_INFO, "DeleteHandleTableEntry - the handle is 0. Returning.")); return; } // // if there are no other outstanding references to the handle (and there // should not be any), this will remove the entry from the handle table. // DereferenceObject(ghHandleTable, dwHandle, 1); LOG((TL_TRACE, "DeleteHandleTableEntry - finished.")); return; } ////////////////////////////////////////////////////////////////////////////// // // ULONG_PTR GetHandleTableEntry(DWORD dwHandle) // // this function uses the supplied 32-bit value to get the corresponding // ULONG_PTR entry from the handle table. This is used under 64-bit to // recover the original 64-bit value from the handle // ULONG_PTR GetHandleTableEntry(DWORD dwHandle) { LOG((TL_TRACE, "GetHandleTableEntry - enter. dwHandle 0x%lx", dwHandle)); if (0 == ghHandleTable) { LOG((TL_ERROR, "GetHandleTableEntry - handle table does not exist.")); return NULL; } // // get the pointer-sized value from the table // ULONG_PTR nValue = (ULONG_PTR)ReferenceObject(ghHandleTable, dwHandle, 0); // // we don't really need to keep a reference to it. // so don't -- this will simplify client logic // DereferenceObject(ghHandleTable, dwHandle, 1); LOG((TL_TRACE, "GetHandleTableEntry - succeeded. returning 0x%p", nValue)); return nValue; } //*************************************************************************** //*************************************************************************** //*************************************************************************** PWSTR PASCAL NotSoWideStringToWideString( LPCSTR lpStr, DWORD dwLength ) { DWORD dwSize; PWSTR pwStr; if (IsBadStringPtrA (lpStr, dwLength)) { return NULL; } dwSize = MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpStr, dwLength, NULL, 0 ); pwStr = (PWSTR)ClientAlloc( dwSize * sizeof(WCHAR) ); if (NULL != pwStr) { MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpStr, dwLength, pwStr, dwSize ); } return pwStr; } //*************************************************************************** //*************************************************************************** //*************************************************************************** // //NOTE: This function requires that lpBase is a pointer to the start of // a TAPI struct that has dwTotalSize as the first DWORD // void PASCAL WideStringToNotSoWideString( LPBYTE lpBase, LPDWORD lpdwXxxSize ) { DWORD dwSize; DWORD dwNewSize; DWORD dwOffset; DWORD dwTotalSize; DWORD dwUsedSize; PWSTR pString; PSTR lpszStringA; if ((dwSize = *lpdwXxxSize) != 0) { dwTotalSize = *((LPDWORD) lpBase); dwUsedSize = *(((LPDWORD) lpBase)+2); dwOffset = *(lpdwXxxSize + 1); pString = (PWSTR)(lpBase + dwOffset); if (IsBadStringPtrW (pString, dwSize)) { LOG((TL_ERROR, "The service provider returned an invalid field in the structure 0x%p : 0x%p", lpBase, lpdwXxxSize)); *lpdwXxxSize = 0; *(lpdwXxxSize+1) = 0; return; } // // Did we get enough chars? // if (dwUsedSize > dwOffset ) { dwNewSize = WideCharToMultiByte( GetACP(), 0, pString, ( dwUsedSize >= (dwOffset+dwSize)) ? (dwSize/sizeof(WCHAR)) : (dwUsedSize - dwOffset) / sizeof(WCHAR), NULL, 0, NULL, NULL ); lpszStringA = (PSTR)ClientAlloc( dwNewSize ); if ( NULL == lpszStringA ) { LOG((TL_ERROR, "Memory alloc failed - alloc(0x%08lx)", dwSize)); LOG((TL_ERROR, "The service provider returned an invalid field size in the structure 0x08lx : 0x08lx", dwSize)); *lpdwXxxSize = 0; *(lpdwXxxSize+1) = 0; return; } // lpszStringA[dwNewSize] = '\0'; WideCharToMultiByte( GetACP(), 0, pString, // dwSize, ( dwUsedSize >= (dwOffset+dwSize)) ? (dwSize/sizeof(WCHAR)) : (dwUsedSize - dwOffset) / sizeof(WCHAR), lpszStringA, dwNewSize, NULL, NULL ); // // Copy the new ANSI string back to where the Unicode string was // // and write out NULL terminator if possible. // CopyMemory ( (LPBYTE) pString, lpszStringA, dwNewSize // + ( // ((dwNewSize + dwOffset) < dwUsedSize ) ? // 1 : // 0 // ) ); ClientFree (lpszStringA); // // Update the number of bytes // *lpdwXxxSize = dwNewSize; } } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // ReadRegistryValues // // During initialization, reads various values from the registry // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ BOOL ReadRegistryValues() { HKEY hKey; #if DBG gdwDebugLevel = 0; #endif gdwMaxNumRequestRetries = 40; gdwRequestRetryTimeout = 250; // milliseconds gdwTapi2AsynchronousCallTimeout = DEFAULT_TAPI2_ASYNCRONOUS_CALL_TIMEOUT; // // open the telephony key // if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszTelephonyKey, 0, KEY_READ, &hKey ) == ERROR_SUCCESS) { DWORD dwDataSize, dwDataType; // // get the rpc max num of retries // dwDataSize = sizeof(DWORD); RegQueryValueEx( hKey, gszTapi32MaxNumRequestRetries, 0, &dwDataType, (LPBYTE) &gdwMaxNumRequestRetries, &dwDataSize ); // // get the retry timeout // dwDataSize = sizeof(DWORD); RegQueryValueEx( hKey, gszTapi32RequestRetryTimeout, 0, &dwDataType, (LPBYTE) &gdwRequestRetryTimeout, &dwDataSize ); // // get the timeout for asynchronous calls to tapi2 // dwDataSize = sizeof(DWORD); LONG rc = RegQueryValueEx( hKey, gszTapi2AsynchronousCallTimeout, 0, &dwDataType, (LPBYTE) &gdwTapi2AsynchronousCallTimeout, &dwDataSize ); if (rc != ERROR_SUCCESS) { gdwTapi2AsynchronousCallTimeout = DEFAULT_TAPI2_ASYNCRONOUS_CALL_TIMEOUT; } LOG((TL_INFO, "AsynchronousCallTimeout initialized to %d", gdwTapi2AsynchronousCallTimeout)); // // get sleep time for retry processing // dwDataSize = sizeof(DWORD); rc = RegQueryValueEx( hKey, gszTapi3RetryProcessingSleep, 0, &dwDataType, (LPBYTE) &gdwTapi3RetryProcessingSleep, &dwDataSize ); if (rc != ERROR_SUCCESS) { gdwTapi3RetryProcessingSleep = DEFAULT_TAPI3_RETRY_PROCESSING_SLEEP; } LOG((TL_INFO, "gdwTapi3RetryProcessingSleep initialized to %ld", gdwTapi3RetryProcessingSleep)); // // get sleep time for blocking call timeout // dwDataSize = sizeof(DWORD); rc = RegQueryValueEx( hKey, gszTapi3SyncWaitTimeOut, 0, &dwDataType, (LPBYTE) &gdwTapi3SyncWaitTimeOut, &dwDataSize ); if (rc != ERROR_SUCCESS) { gdwTapi3SyncWaitTimeOut = DEFAULT_TAPI3_BLOCKING_CALL_SLEEP; } LOG((TL_INFO, "gdwTapi3SyncWaitTimeOut initialized to %ld", gdwTapi3SyncWaitTimeOut)); RegCloseKey (hKey); } return TRUE; } //*************************************************************************** //*************************************************************************** //*************************************************************************** extern "C" BOOL WINAPI DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved ) { switch (dwReason) { case DLL_PROCESS_ATTACH: { gbCriticalSectionsInitialized = FALSE; #if DBG _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); #endif ghInst = (HINSTANCE)hDLL; // // ATL initialization // #ifdef _MERGE_PROXYSTUB if (!PrxDllMain(ghInst, dwReason, lpReserved)) { return FALSE; } #endif _Module.Init(ObjectMap, ghInst); // // Init CRT // if (!_CRT_INIT (ghInst, dwReason, lpReserved)) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, _CRT_INIT() failed" )); return FALSE; } // Register for trace output. TRACELOGREGISTER(_T("tapi3")); LOG((TL_INFO, "DLL_PROCESS_ATTACH")); // // initialize stuff from the registry // ReadRegistryValues(); // // Alloc a Tls index // if ((gdwTlsIndex = TlsAlloc()) == 0xffffffff) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, TlsAlloc() failed")); return FALSE; } // // Initialize Tls to NULL for this thread // TlsSetValue (gdwTlsIndex, NULL); // // Create mutex // ghTapiInitShutdownSerializeMutex = CreateMutex(NULL, FALSE, NULL); // // init critical sections // try { InitializeCriticalSection (&gcsTapisrvCommunication); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); return FALSE; } try { InitializeCriticalSection (&gTlsCriticalSection); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); return FALSE; } try { InitializeCriticalSection (&gcsCallbackQueue); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); return FALSE; } try { InitializeCriticalSection (&gcsTapi32); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); return FALSE; } try { InitializeCriticalSection (&gcsGlobalInterfaceTable); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); DeleteCriticalSection (&gcsTapi32); return FALSE; } try { InitializeCriticalSection (&gcsClientResources); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); DeleteCriticalSection (&gcsTapi32); DeleteCriticalSection (&gcsGlobalInterfaceTable); return FALSE; } try { InitializeCriticalSection (&gcsTapiObjectArray); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); DeleteCriticalSection (&gcsTapi32); DeleteCriticalSection (&gcsGlobalInterfaceTable); DeleteCriticalSection (&gcsClientResources); return FALSE; } #if DBG try { InitializeCriticalSection( &csMemoryList); } catch(...) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, InitializeCriticalSection failed")); DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); DeleteCriticalSection (&gcsTapi32); DeleteCriticalSection (&gcsGlobalInterfaceTable); DeleteCriticalSection (&gcsClientResources); DeleteCriticalSection (&gcsTapiObjectArray); return FALSE; } #endif gbCriticalSectionsInitialized = TRUE; InitializeListHead (&gTlsListHead); HRESULT hr; // // gpCallHashTable // try { gpCallHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpCallHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHashTable alloc failed")); return FALSE; } hr = gpCallHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHashTable init failed")); return FALSE; } // // gpLineHashTable // try { gpLineHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpLineHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpLineHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpLineHashTable alloc failed")); return FALSE; } hr = gpLineHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpLineHashTable init failed")); return FALSE; } // // gpCallHubHashTable // try { gpCallHubHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHubHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpCallHubHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHubHashTable alloc failed")); return FALSE; } hr = gpCallHubHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpCallHubHashTable init failed")); return FALSE; } // // gpAgentHandlerHashTable // try { gpAgentHandlerHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpAgentHandlerHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpAgentHandlerHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpAgentHandlerHashTable alloc failed")); return FALSE; } hr = gpAgentHandlerHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpAgentHandlerHashTable init failed")); return FALSE; } // // gpPhoneHashTable // try { gpPhoneHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpPhoneHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpPhoneHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpPhoneHashTable alloc failed")); return FALSE; } hr = gpPhoneHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpPhoneHashTable init failed")); return FALSE; } // // gpHandleHashTable // try { gpHandleHashTable = new CHashTable; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpHandleHashTable constructor threw an exception")); return FALSE; } if ( NULL == gpHandleHashTable ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpHandleHashTable alloc failed")); return FALSE; } hr = gpHandleHashTable->Initialize( 1 ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpHandleHashTable init failed")); return FALSE; } // // gpLineAsyncReplyList // try { gpLineAsyncReplyList = new CAsyncReplyList; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpLineAsyncReplyList constructor threw an exception")); return FALSE; } if ( NULL == gpLineAsyncReplyList ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH - gpLineAsyncReplyList alloc failed")); return FALSE; } // // gpPhoneAsyncReplyList // try { gpPhoneAsyncReplyList = new CAsyncReplyList; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpPhoneAsyncReplyList constructor threw an exception")); return FALSE; } if ( NULL == gpPhoneAsyncReplyList ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH - gpPhoneAsyncReplyList alloc failed")); return FALSE; } // // gpRetryQueue // try { gpRetryQueue = new CRetryQueue; } catch(...) { // Initialize critical section in the constructor most likely threw this exception LOG((TL_ERROR, "DLL_PROCESS_ATTACH, gpRetryQueue constructor threw an exception")); return FALSE; } if ( NULL == gpRetryQueue ) { LOG((TL_ERROR, "DLL_PROCESS_ATTACH - gpRetryQueue alloc failed")); return FALSE; } break; } case DLL_PROCESS_DETACH: { PCLIENT_THREAD_INFO pTls; LOG((TL_INFO, "DLL_PROCESS_DETACH")); if (gpCallHashTable != NULL) { gpCallHashTable->Shutdown(); delete gpCallHashTable; } if (gpLineHashTable != NULL) { gpLineHashTable->Shutdown(); delete gpLineHashTable; } if (gpCallHubHashTable != NULL) { gpCallHubHashTable->Shutdown(); delete gpCallHubHashTable; } if (gpAgentHandlerHashTable != NULL) { gpAgentHandlerHashTable->Shutdown(); delete gpAgentHandlerHashTable; } if (gpPhoneHashTable != NULL) { gpPhoneHashTable->Shutdown(); delete gpPhoneHashTable; } if (gpHandleHashTable != NULL) { gpHandleHashTable->Shutdown(); delete gpHandleHashTable; } CTAPI::m_sTAPIObjectArray.Shutdown(); delete gpLineAsyncReplyList; delete gpPhoneAsyncReplyList; delete gpRetryQueue; // // Clean up any Tls (no need to enter crit sec since process detaching) // while (!IsListEmpty (&gTlsListHead)) { LIST_ENTRY *pEntry = RemoveHeadList (&gTlsListHead); pTls = CONTAINING_RECORD (pEntry, CLIENT_THREAD_INFO, TlsList); ClientFree (pTls->pBuf); ClientFree (pTls); } // // ATL shutdown // _Module.Term(); TlsFree( gdwTlsIndex ); if (!_CRT_INIT (ghInst, dwReason, lpReserved)) { LOG((TL_ERROR, "_CRT_INIT() failed")); } // // delete all our critical sections // if (gbCriticalSectionsInitialized) { DeleteCriticalSection (&gcsTapisrvCommunication); DeleteCriticalSection (&gTlsCriticalSection); DeleteCriticalSection (&gcsCallbackQueue); DeleteCriticalSection (&gcsTapi32); DeleteCriticalSection (&gcsGlobalInterfaceTable); DeleteCriticalSection (&gcsClientResources); DeleteCriticalSection (&gcsTapiObjectArray); } #if DBG DumpMemoryList(); _CrtDumpMemoryLeaks(); if (gbCriticalSectionsInitialized) { DeleteCriticalSection( &csMemoryList ); } #endif // // Close our mutex // CloseHandle( ghTapiInitShutdownSerializeMutex ); // // do not deregister if the process is terminating -- working around // bugs in rtutils that could cause a "deadlock" if DeregisterTracing // is called from DllMain on process termination. // also we want to delay unregistering until the end so that debugger // output gets logged up to this point, if it is configured. // if (NULL == lpReserved) { TRACELOGDEREGISTER(); } break; } case DLL_THREAD_ATTACH: // // First must init CRT // if (!_CRT_INIT (ghInst, dwReason, lpReserved)) { LOG((TL_ERROR, "_CRT_INIT() failed")); return FALSE; } // // Initialize Tls to NULL for this thread // TlsSetValue (gdwTlsIndex, NULL); break; case DLL_THREAD_DETACH: { PCLIENT_THREAD_INFO pTls; // // Clean up any Tls // if ((pTls = (PCLIENT_THREAD_INFO) TlsGetValue (gdwTlsIndex))) { EnterCriticalSection (&gTlsCriticalSection); RemoveEntryList (&pTls->TlsList); LeaveCriticalSection (&gTlsCriticalSection); if (pTls->pBuf) { ClientFree (pTls->pBuf); } ClientFree (pTls); } // // Finally, alert CRT // if (!_CRT_INIT (ghInst, dwReason, lpReserved)) { LOG((TL_ERROR, "_CRT_INIT() failed")); } break; } } // switch return TRUE; } //////////////////////////////////////////////////////////////////// // QueueCallbackEvent // // Queues a raw async message that will be processed in the // CallbackThread. //////////////////////////////////////////////////////////////////// void QueueCallbackEvent( PASYNCEVENTMSG pParams ) { PTAPICALLBACKEVENT pNew; DWORD dwSize; // = sizeof (ASYNCEVENTMSG); LOG((TL_TRACE, "QueueCallbackEvent - enter")); LOG((TL_INFO, " hDevice ----> %lx", pParams->hDevice)); LOG((TL_INFO, " Msg ----> %lx", pParams->Msg)); LOG((TL_INFO, " Param1 ---> %lx", pParams->Param1)); LOG((TL_INFO, " Param2 ---> %lx", pParams->Param2)); LOG((TL_INFO, " Param3 ---> %lx", pParams->Param3)); dwSize = pParams->TotalSize; pNew = (PTAPICALLBACKEVENT)ClientAlloc( sizeof(TAPICALLBACKEVENT) + (dwSize-sizeof(ASYNCEVENTMSG) ) ); if ( pNew != NULL) { pNew->type = CALLBACKTYPE_RAW_ASYNC_MESSAGE; pNew->pTapi = NULL; CopyMemory( &pNew->data.asyncMessage, pParams, dwSize ); // add to list EnterCriticalSection( &gcsCallbackQueue ); try { gCallbackEventPtrList.push_back( (PVOID)pNew ); } catch(...) { LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); ClientFree( pNew ); } LeaveCriticalSection( &gcsCallbackQueue ); SetEvent( ghCallbackThreadEvent ); LOG((TL_INFO, "QueueCallbackEvent - New pParams is ----> %p", pNew )); } else { LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); return; } } //////////////////////////////////////////////////////////////////// // QueueCallbackEvent // // Queues a raw async message that will be processed in the // CallbackThread. //////////////////////////////////////////////////////////////////// void QueueCallbackEvent( CTAPI *pTapi, PASYNCEVENTMSG pParams ) { PTAPICALLBACKEVENT pNew; DWORD dwSize; // = sizeof (ASYNCEVENTMSG); LOG((TL_TRACE, "QueueCallbackEvent - enter")); LOG((TL_INFO, " hDevice ----> %lx", pParams->hDevice)); LOG((TL_INFO, " Msg ----> %lx", pParams->Msg)); LOG((TL_INFO, " Param1 ---> %lx", pParams->Param1)); LOG((TL_INFO, " Param2 ---> %lx", pParams->Param2)); LOG((TL_INFO, " Param3 ---> %lx", pParams->Param3)); dwSize = pParams->TotalSize; pNew = (PTAPICALLBACKEVENT)ClientAlloc( sizeof(TAPICALLBACKEVENT) + (dwSize-sizeof(ASYNCEVENTMSG) ) ); if ( pNew != NULL) { pNew->type = CALLBACKTYPE_RAW_ASYNC_MESSAGE; pNew->pTapi = pTapi; CopyMemory( &pNew->data.asyncMessage, pParams, dwSize ); // add to list EnterCriticalSection( &gcsCallbackQueue ); try { gCallbackEventPtrList.push_back( (PVOID)pNew ); } catch(...) { LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); ClientFree( pNew ); } LeaveCriticalSection( &gcsCallbackQueue ); SetEvent( ghCallbackThreadEvent ); LOG((TL_INFO, "QueueCallbackEvent - New pParams is ----> %p", pNew )); } else { LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); return; } } //////////////////////////////////////////////////////////////////// // QueueCallbackEvent // // Queues a TAPI event message object that will be processed in the // CallbackThread. //////////////////////////////////////////////////////////////////// BOOL QueueCallbackEvent( CTAPI * pTapi, TAPI_EVENT te, IDispatch * pEvent ) { BOOL bResult = TRUE; PTAPICALLBACKEVENT pNew; LOG((TL_TRACE, "QueueCallbackEvent - enter")); #if DBG LOG((TL_INFO, "QueueCallbackEvent - TAPI Event -> %lx %s", te, eventName(te) )); #endif pNew = (PTAPICALLBACKEVENT)ClientAlloc( sizeof(TAPICALLBACKEVENT) ); if ( pNew != NULL) { pNew->type = CALLBACKTYPE_TAPI_EVENT_OBJECT; pNew->pTapi = pTapi; pNew->data.tapiEvent.te = te; pNew->data.tapiEvent.pEvent = pEvent; // add to list EnterCriticalSection( &gcsCallbackQueue ); try { gCallbackEventPtrList.push_back( (PVOID)pNew ); } catch(...) { bResult = FALSE; LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); ClientFree( pNew ); } LeaveCriticalSection( &gcsCallbackQueue ); if( bResult ) { SetEvent( ghCallbackThreadEvent ); } LOG((TL_INFO, "QueueCallbackEvent - New pParams is ----> %p", pNew )); } else { LOG((TL_ERROR, "QueueCallbackEvent - out of memory - losing message")); bResult = FALSE; } return bResult; } //////////////////////////////////////////////////////////////////// // DequeueCallbackEvent // // Pulls an event from the queue for the CallbackThread //////////////////////////////////////////////////////////////////// BOOL DequeueCallbackEvent( PTAPICALLBACKEVENT * ppCallBackEvent ) { BOOL bResult = TRUE; LOG((TL_TRACE, "DequeueCallbackEvent - enter")); EnterCriticalSection( &gcsCallbackQueue ); if (gCallbackEventPtrList.size() > 0) { *ppCallBackEvent = (PTAPICALLBACKEVENT) gCallbackEventPtrList.front(); try { gCallbackEventPtrList.pop_front(); } catch(...) { LOG((TL_ERROR, "DequeueCallbackEvent - failed to pop from gCallbackEventPtrList")); bResult = FALSE; } if( bResult ) { if(IsBadReadPtr(*ppCallBackEvent, sizeof( TAPICALLBACKEVENT )) ) { bResult = FALSE; LOG((TL_ERROR, "DequeueCallbackEvent - IsBadReadPtr *ppCallBackEvent")); } } } else { // return false if there are no more messages LOG((TL_ERROR, "DequeueCallbackEvent - no more messages")); bResult = FALSE; } LeaveCriticalSection( &gcsCallbackQueue ); #if DBG if (bResult) { LOG((TL_INFO, "DequeueCallbackEvent - returning %p", *ppCallBackEvent)); } else { LOG((TL_INFO, "DequeueCallbackEvent - no event")); } #endif return bResult; } BOOL WaitWithMessageLoop(HANDLE hEvent) { DWORD dwRet; MSG msg; while(1) { dwRet = MsgWaitForMultipleObjects( 1, // One event to wait for &hEvent, // The array of events FALSE, // Wait for 1 event INFINITE, // Timeout value QS_ALLINPUT ); // Any message wakes up // There is a window message available. Dispatch it. while(PeekMessage(&msg,NULL,0,0xFFFFFFFF,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (dwRet == WAIT_OBJECT_0) { return TRUE; } } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= // // CallbackThread // // Thread proc used to call application's callback routines. // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= void CallbackThread( LPVOID pv ) { HINSTANCE hLib; LOG((TL_TRACE, "CallbackThread: enter")); // // make sure we're CoInitialized // if ( !(SUCCEEDED( CoInitializeEx(NULL, COINIT_MULTITHREADED) ) ) ) { LOG((TL_ERROR, "CallbackThread: CoInitialize failed")); } hLib = LoadLibrary("tapi3.dll"); while (TRUE) { // // put the break here, so when the // flag is set, we still flush the callbackevent // queue in the while(TRUE) loop below // if (gbExitThread) { LOG((TL_TRACE, "CallbackThread: gbExitThread")); break; } LOG((TL_INFO, "CallbackThread: Wait for event")); DWORD dwSignalled; CoWaitForMultipleHandles (COWAIT_ALERTABLE, INFINITE, 1, &ghCallbackThreadEvent, &dwSignalled); /* WaitForSingleObject( ghCallbackThreadEvent, INFINITE ); */ while (TRUE) { PTAPICALLBACKEVENT pCallBackEvent; HRESULT hr = S_OK; // // get the event // if (!DequeueCallbackEvent(&pCallBackEvent ) ) { LOG((TL_ERROR, "CallbackThread: The DequeueCallbackEvent returned a wrong value")); break; } if(pCallBackEvent->type == CALLBACKTYPE_RAW_ASYNC_MESSAGE) { PASYNCEVENTMSG pParams; LOG((TL_INFO, "CallbackThread: event type is CALLBACKTYPE_RAW_ASYNC_MESSAGE")); pParams = &pCallBackEvent->data.asyncMessage; // // call the handler // switch( pParams->Msg ) { #ifdef USE_PHONEMSP case PRIVATE_PHONESETHOOKSWITCH: { CPhoneMSPCall::HandlePrivateHookSwitch( pParams ); break; } #endif USE_PHONEMSP case LINE_CREATE: { HandleLineCreate( pParams ); break; } case LINE_REMOVE: { HandleLineRemove( pParams ); break; } case PHONE_STATE: { HandlePhoneStateMessage( pParams ); break; } case PHONE_CREATE: { HandlePhoneCreate( pParams ); break; } case PHONE_REMOVE: { HandlePhoneRemove( pParams ); break; } case PRIVATE_ISDN__ACCEPTTOALERT: { HandleAcceptToAlert( pParams ); break; } case LINE_PROXYSTATUS: { handleProxyStatusMessage(pCallBackEvent->pTapi, pParams); break; } default: LOG((TL_WARN, "CallbackThread: asyncevent type not handled %x", pParams->Msg )); break; } } else { // // fire the event // CTAPI * pTapi = pCallBackEvent->pTapi; LOG((TL_INFO, "CallbackThread: event type is CALLBACKTYPE_TAPI_EVENT_OBJECT")); #if DBG LOG((TL_INFO, "CallbackThread: firing event event -> %lx %s tapi[%p]", pCallBackEvent->data.tapiEvent.te, eventName(pCallBackEvent->data.tapiEvent.te), pTapi)); #endif pTapi->EventFire( pCallBackEvent->data.tapiEvent.te, pCallBackEvent->data.tapiEvent.pEvent ); pTapi->Release(); } // // free the message // ClientFree( pCallBackEvent ); } } CoUninitialize(); if (hLib != NULL) { FreeLibraryAndExitThread ((HINSTANCE)hLib, 0); } else { ExitThread(0); } LOG((TL_TRACE, "CallbackThread: exit")); } void PASCAL lineCompleteCallPostProcess( PASYNCEVENTMSG pMsg ); void PASCAL lineGatherDigitsWPostProcess( PASYNCEVENTMSG pMsg ); void PASCAL lineSetupConferencePostProcess( PASYNCEVENTMSG pMsg ); void PASCAL phoneDevSpecificPostProcess( PASYNCEVENTMSG pMsg ); /////////////////////////////////////////////////////////////////////////////// // // array of functions. function index is passed to tapisrv when we make an // asynchronous tapisrv call. in LINE_REPLY, we get this index back, and call // the appropriate function. we need to do this because we cannot pass function // address to tapisrv // POSTPROCESSPROC gPostProcessingFunctions[] = { NULL, lineDevSpecificPostProcess, lineCompleteCallPostProcess, lineMakeCallPostProcess, lineGatherDigitsWPostProcess, lineSetupConferencePostProcess, phoneDevSpecificPostProcess }; ///////////////////////////////////// // // GetFunctionIndex // // find the array index of the function. // // returns 0 if the function was not found in the array // DWORD GetFunctionIndex(POSTPROCESSPROC Function) { const int nArraySize = sizeof(gPostProcessingFunctions)/sizeof(POSTPROCESSPROC); for (int i = 0; i < nArraySize; i++) { if (Function == gPostProcessingFunctions[i]) { break; } } // // the function that is passed in had better be in the array. if not -- this should be caught in testing! // _ASSERTE( (0 != i) && (i < nArraySize) ); if (i == nArraySize) { LOG((TL_ERROR, "GetFunctionIndex: function %p is not found in the array of functions!", Function)); i = 0; } LOG((TL_INFO, "GetFunctionIndex: function %p mapped to index %d.", Function, i)); return i; } //************************************************************************** //************************************************************************** //************************************************************************** void AsyncEventsThread( PASYNC_EVENTS_THREAD_PARAMS pAsyncEventsThreadParams ) { BOOL *pbExitThread = &pAsyncEventsThreadParams->bExitThread, bRetry; HANDLE hStartupEvent = pAsyncEventsThreadParams->hThreadStartupEvent; DWORD dwBufSize = pAsyncEventsThreadParams->dwBufSize; LPBYTE pBuf = pAsyncEventsThreadParams->pBuf; PTAPI32_MSG pMsg = (PTAPI32_MSG) pBuf; HANDLE ahWaitForTheseEvents[]={ ghAsyncRetryQueueEvent, ghAsyncEventsEvent }; LOG((TL_TRACE, "AsyncEventsThread: enter")); if ( !(SUCCEEDED( CoInitializeEx(NULL, COINIT_MULTITHREADED) ) ) ) { LOG((TL_ERROR, "AsyncEventsThread: CoInitialize failed ")); } // // mark retryqueue as open for new entries // gpRetryQueue->OpenForNewEntries(); // // it is now ok for events to be posted to the retry queue // BOOL bSetStartuptEvent = SetEvent(hStartupEvent); if (!bSetStartuptEvent) { LOG((TL_ERROR, "AsyncEventsThread - failed to signal hStartupEvent event. LastError = 0x%lx", GetLastError())); return; } // // we will never need this event again. the creator of the thread will // release it // hStartupEvent = NULL; // // Just loop reading async events/completions from server & // handling them // while (1) { DWORD dwUsedSize, dwNeededSize; PASYNCEVENTMSG pAsyncEventMsg; // // Check to see if xxxShutdown or FreeClientResources // is signaling us to exit (we need to check both before // & after the wait to dela with a event setting/resetting // race condition between FreeClientResources & Tapisrv) // if (*pbExitThread) { LOG((TL_INFO, "AsyncEventsThread: exit requested")); break; } // // Block until tapisrv signals us that it has some event data for us // { DWORD dwSignalled; CoWaitForMultipleHandles (COWAIT_ALERTABLE, INFINITE, sizeof(ahWaitForTheseEvents)/sizeof(HANDLE), ahWaitForTheseEvents, &dwSignalled); /* dwSignalled = WaitForMultipleObjects( sizeof(ahWaitForTheseEvents)/sizeof(HANDLE), ahWaitForTheseEvents, FALSE, INFINITE ); */ // // map for dwSignalled: // // 0 == ghAsyncRetryQueueEvent, // 1 == ghAsyncEventsEvent, // dwSignalled = dwSignalled - WAIT_OBJECT_0; if( 0 == dwSignalled ) { // // Now lets process the Re-try Queue // LOG((TL_INFO, "AsyncEventsThread: Retry Queue signalled")); gpRetryQueue->ProcessQueue(); // // Don't want to process RPC so... // continue; } } // // Check to see if xxxShutdown or FreeClientResources // is signaling us to exit // if (*pbExitThread) { LOG((TL_INFO, "AsyncEventsThread: exit requested.")); break; } // // Retrieve the data from tapisrv // AsyncEventsThread_clientRequest: do { pMsg->u.Req_Func = xGetAsyncEvents; pMsg->Params[0] = dwBufSize - sizeof (TAPI32_MSG); dwUsedSize = sizeof (TAPI32_MSG); RpcTryExcept { ClientRequest (gphCx, (unsigned char *) pMsg, dwBufSize, (LONG *)&dwUsedSize); bRetry = FALSE; } RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) { bRetry = !(*pbExitThread); LOG(( TL_WARN, "AsyncEventsThread: rpc exception %d handled", RpcExceptionCode() )); Sleep (10); } RpcEndExcept } while (bRetry); #if DBG if ( ( dwUsedSize > dwBufSize ) || ( pMsg->Params[2] > dwBufSize ) ) { LOG((TL_ERROR, "OVERFLOW!!!")); LOG((TL_ERROR, "Watch this...")); ClientFree( ClientAlloc( 0x10000 ) ); } #endif if ((dwUsedSize = pMsg->Params[2]) == 0 && (dwNeededSize = pMsg->Params[1]) != 0) { // // There's a msg waiting for us that is bigger than our buffer, // so alloc a larger buffer & try again // dwNeededSize += sizeof (TAPI32_MSG) + 128; LOG(( TL_INFO, "AsyncEventsThread: allocating larger event buf (size=x%x)", dwNeededSize )); // // deallocate buffer that we currently have // ClientFree(pBuf); pBuf = NULL; dwBufSize = 0; // // allocate a bigger memory chunk. try until successful or exit is requested. // while (!(*pbExitThread)) { // // attempt to allocate a bigger memory chunk // pBuf = (LPBYTE)ClientAlloc (dwNeededSize); if ((NULL == pBuf)) { // // no memory. log a message and yeld, giving other apps/ // threads a chance to free up some memory // LOG((TL_ERROR, "AsyncEventsThread: failed to allocate memory for a larger event buffer" )); Sleep(10); } else { // // we got our memory. break out of allocation attempt cycle // break; } } // // did we have any luck allocating memory? // if (NULL == pBuf) { // // we tried hard but did not get the memory. we did our best. // now break out of message processing loop. // LOG((TL_ERROR, "AsyncEventsThread: failed to allocate memory." )); break; } // // reallocated memory to get a larger buffer. try to get the message again. // dwBufSize = dwNeededSize; pMsg = (PTAPI32_MSG) pBuf; goto AsyncEventsThread_clientRequest; } // // Handle the events // pAsyncEventMsg = (PASYNCEVENTMSG) (pBuf + sizeof (TAPI32_MSG)); while (dwUsedSize) { // // pAsyncEventMsg->InitContext the 32-bit handle. recover the // pointer value for pInitData from the handle. // PT3INIT_DATA pInitData = (PT3INIT_DATA) GetHandleTableEntry(pAsyncEventMsg->InitContext); DWORD dwNumInits; LOG(( TL_INFO, "AsyncEventsThread: msg=%ld, hDevice=x%x, OpenContext =x%lx, p1=x%lx, p2=x%lx, p3=x%lx, pInitData=%p", pAsyncEventMsg->Msg, pAsyncEventMsg->hDevice, pAsyncEventMsg->OpenContext, pAsyncEventMsg->Param1, pAsyncEventMsg->Param2, pAsyncEventMsg->Param3, pInitData )); // // Special case for UI msgs (not fwd'd to client) // switch (pAsyncEventMsg->Msg) { case LINE_CREATEDIALOGINSTANCE: { LOG((TL_INFO, "AsyncEventsThread: LINE_CREATEDIALOGINSTANCE")); DWORD dwThreadID, dwDataOffset = pAsyncEventMsg->Param1, dwDataSize = pAsyncEventMsg->Param2, dwUIDllNameOffset = pAsyncEventMsg->Param3; PUITHREADDATA pUIThreadData; if (!(pUIThreadData = (PUITHREADDATA)ClientAlloc (sizeof (UITHREADDATA)))) { goto LINE_CREATEDIALOGINSTANCE_error; } if ((pUIThreadData->dwSize = dwDataSize) != 0) { if (!(pUIThreadData->pParams = ClientAlloc (dwDataSize))) { goto LINE_CREATEDIALOGINSTANCE_error; } CopyMemory( pUIThreadData->pParams, ((LPBYTE)pAsyncEventMsg) + dwDataOffset, dwDataSize ); } if (!(pUIThreadData->hUIDll = TAPILoadLibraryW( (PWSTR)(((LPBYTE) pAsyncEventMsg) + dwUIDllNameOffset) ))) { LOG(( TL_ERROR, "LoadLibraryW(%ls) failed, err=%d", ((LPBYTE) pAsyncEventMsg) + dwUIDllNameOffset, GetLastError() )); goto LINE_CREATEDIALOGINSTANCE_error; } if (!(pUIThreadData->pfnTUISPI_providerGenericDialog = (TUISPIPROC) GetProcAddress( pUIThreadData->hUIDll, (LPCSTR) gszTUISPI_providerGenericDialog ))) { LOG(( TL_INFO, "GetProcAddr(TUISPI_providerGenericDialog) failed" )); goto LINE_CREATEDIALOGINSTANCE_error; } pUIThreadData->pfnTUISPI_providerGenericDialogData = (TUISPIPROC) GetProcAddress( pUIThreadData->hUIDll, (LPCSTR) gszTUISPI_providerGenericDialogData ); if (!(pUIThreadData->hEvent = CreateEvent( (LPSECURITY_ATTRIBUTES) NULL, TRUE, // manual reset FALSE, // non-signaled NULL // unnamed ))) { goto LINE_CREATEDIALOGINSTANCE_error; } pUIThreadData->htDlgInst = (HTAPIDIALOGINSTANCE) pAsyncEventMsg->hDevice; // // Safely add this instance to the global list // (check if dwNumInits == 0, & if so fail) // EnterCriticalSection( &gcsTapiObjectArray ); dwNumInits = CTAPI::m_sTAPIObjectArray.GetSize(); LeaveCriticalSection ( &gcsTapiObjectArray ); EnterCriticalSection (&gcsTapisrvCommunication); if (dwNumInits != 0) { if ((pUIThreadData->pNext = gpUIThreadInstances)) { pUIThreadData->pNext->pPrev = pUIThreadData; } gpUIThreadInstances = pUIThreadData; LeaveCriticalSection (&gcsTapisrvCommunication); } else { LeaveCriticalSection (&gcsTapisrvCommunication); goto LINE_CREATEDIALOGINSTANCE_error; } if ((pUIThreadData->hThread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) UIThread, (LPVOID) pUIThreadData, 0, &dwThreadID ))) { goto AsyncEventsThread_decrUsedSize; } // // If here an error occured, so safely remove the ui // thread data struct from the global list // EnterCriticalSection (&gcsTapisrvCommunication); if (pUIThreadData->pNext) { pUIThreadData->pNext->pPrev = pUIThreadData->pPrev; } if (pUIThreadData->pPrev) { pUIThreadData->pPrev->pNext = pUIThreadData->pNext; } else { gpUIThreadInstances = pUIThreadData->pNext; } LeaveCriticalSection (&gcsTapisrvCommunication); LINE_CREATEDIALOGINSTANCE_error: if (pUIThreadData) { if (pUIThreadData->pParams) { ClientFree (pUIThreadData->pParams); } if (pUIThreadData->hUIDll) { FreeLibrary (pUIThreadData->hUIDll); } if (pUIThreadData->hEvent) { CloseHandle (pUIThreadData->hEvent); } ClientFree (pUIThreadData); } { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, xFreeDialogInstance), { pAsyncEventMsg->hDevice }, { Dword } }; DOFUNC (&funcArgs, "FreeDialogInstance"); } goto AsyncEventsThread_decrUsedSize; } case LINE_SENDDIALOGINSTANCEDATA: { LOG((TL_INFO, "AsyncEventsThread: LINE_SENDDIALOGINSTANCEDATA")); PUITHREADDATA pUIThreadData = gpUIThreadInstances; HTAPIDIALOGINSTANCE htDlgInst = (HTAPIDIALOGINSTANCE) pAsyncEventMsg->hDevice; EnterCriticalSection (&gcsTapisrvCommunication); while (pUIThreadData) { if (pUIThreadData->htDlgInst == htDlgInst) { WaitForSingleObject (pUIThreadData->hEvent, INFINITE); ((TUIGDDPROC)(*pUIThreadData->pfnTUISPI_providerGenericDialogData))( htDlgInst, ((LPBYTE) pAsyncEventMsg) + pAsyncEventMsg->Param1, // data offset pAsyncEventMsg->Param2 // data size ); break; } pUIThreadData = pUIThreadData->pNext; } LeaveCriticalSection (&gcsTapisrvCommunication); goto AsyncEventsThread_decrUsedSize; } } // // Enter the critical section so we've exclusive access // to the init data, & verify it // EnterCriticalSection (&gcsTapisrvCommunication); // // see if pInitData is null // if (NULL == pInitData) { LOG((TL_WARN, "AsyncEventsThread: pInitInst is NULL. discarding msg")); goto AsyncEventsThread_leaveCritSec; } // // properly aligned? // if ((ULONG_PTR) pInitData & 0x7) { LOG((TL_ERROR, "AsyncEventsThread: misaligned pInitInst[%p]. discarding msg", pInitData)); goto AsyncEventsThread_leaveCritSec; } // // points to unreadeable memory? // if ( IsBadReadPtr(pInitData, sizeof(T3INIT_DATA)) ) { LOG((TL_ERROR, "AsyncEventsThread: pInitData[%p] points to unreadable memory. discarding msg", pInitData)); goto AsyncEventsThread_leaveCritSec; } // // appears to have valid data? // // just in case the pointer became invalid since we checked, do // this in try/catch // __try { if (pInitData->dwKey != INITDATA_KEY ) { LOG((TL_ERROR, "AsyncEventsThread: Bad pInitInst[%p], key[%ld] discarding msg", pInitData, pInitData->dwKey)); goto AsyncEventsThread_leaveCritSec; } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_ERROR, "AsyncEventsThread: exception. bad pInitData[%p]", pInitData )); goto AsyncEventsThread_leaveCritSec; } // // Special case for PROXYREQUEST // if (pAsyncEventMsg->Msg == LINE_PROXYREQUEST) { LOG((TL_INFO, "AsyncEventsThread: LINE_PROXYREQUEST")); PPROXYREQUESTHEADER pProxyRequestHeader; LPLINEPROXYREQUEST pProxyRequest = (LPLINEPROXYREQUEST) (pAsyncEventMsg + 1), pProxyRequestApp; switch (pProxyRequest->dwRequestType) { case LINEPROXYREQUEST_SETAGENTGROUP: case LINEPROXYREQUEST_SETAGENTSTATE: case LINEPROXYREQUEST_SETAGENTACTIVITY: case LINEPROXYREQUEST_AGENTSPECIFIC: case LINEPROXYREQUEST_CREATEAGENT: case LINEPROXYREQUEST_CREATEAGENTSESSION: case LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD: case LINEPROXYREQUEST_SETAGENTSESSIONSTATE: case LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD: case LINEPROXYREQUEST_SETAGENTSTATEEX: // // For these msgs the proxy request as received from // the tapisrv already contains the exact bits we want // to pass on to the app, so we just alloc a buffer of // the same size (plus a little extra for the key at // the head of the buffer) and copy the data to it // if (!(pProxyRequestHeader = (PPROXYREQUESTHEADER)ClientAlloc( sizeof (PROXYREQUESTHEADER) + pProxyRequest->dwSize ))) { // // if we could not allocate memory, log a message and break out. // LOG((TL_ERROR, "AsyncEventsThread: failed to allocate memory for proxy request")); goto AsyncEventsThread_leaveCritSec; } pProxyRequestApp = (LPLINEPROXYREQUEST) (pProxyRequestHeader + 1); CopyMemory( pProxyRequestApp, pProxyRequest, pProxyRequest->dwSize ); break; case LINEPROXYREQUEST_GETAGENTCAPS: case LINEPROXYREQUEST_GETAGENTSTATUS: case LINEPROXYREQUEST_GETAGENTACTIVITYLIST: case LINEPROXYREQUEST_GETAGENTGROUPLIST: case LINEPROXYREQUEST_GETQUEUEINFO: case LINEPROXYREQUEST_GETGROUPLIST: case LINEPROXYREQUEST_GETQUEUELIST: case LINEPROXYREQUEST_GETAGENTINFO: case LINEPROXYREQUEST_GETAGENTSESSIONINFO: case LINEPROXYREQUEST_GETAGENTSESSIONLIST: // // For these msgs tapisrv only embedded the dwTotalSize // field of the corresponding structure (to save having // to send us a bunch of unused bits), so we want to // increase the pProxyRequest->dwSize by the dwTotalSize // - sizeof (DWORD), alloc a buffer (including a little // extra space for the key at the head of the buffer), // and rebuild the request // if ( pProxyRequest->dwRequestType == LINEPROXYREQUEST_GETGROUPLIST ) { pProxyRequest->dwSize += pProxyRequest->GetGroupList.GroupList.dwTotalSize; } else if ( pProxyRequest->dwRequestType == LINEPROXYREQUEST_GETQUEUELIST ) { pProxyRequest->dwSize += pProxyRequest->GetQueueList.QueueList.dwTotalSize; } else { // // all of the rest of the structures have the // same format // pProxyRequest->dwSize += pProxyRequest->GetAgentCaps.AgentCaps.dwTotalSize; } if (!(pProxyRequestHeader = (PROXYREQUESTHEADER *)ClientAlloc( sizeof (PROXYREQUESTHEADER) + pProxyRequest->dwSize ))) { // // if we could not allocate memory, log a message and break out. // LOG((TL_ERROR, "AsyncEventsThread: failed to allocate memory for proxy request.")); goto AsyncEventsThread_leaveCritSec; } pProxyRequestApp = (LPLINEPROXYREQUEST) (pProxyRequestHeader + 1); // // The following will copy the non-union fields in the // proxy message, as well as the first two DWORD in the // union (which currently are the dwAddressID and the // dwTotalSize field of the corresponding structure) // if ( pProxyRequest->dwRequestType == LINEPROXYREQUEST_GETGROUPLIST ) { CopyMemory( pProxyRequestApp, pProxyRequest, 8 * sizeof (DWORD) ); } else if ( pProxyRequest->dwRequestType == LINEPROXYREQUEST_GETQUEUELIST ) { CopyMemory( pProxyRequestApp, pProxyRequest, 8 * sizeof (DWORD) + sizeof(GUID) ); } else { CopyMemory( pProxyRequestApp, pProxyRequest, 9 * sizeof (DWORD) ); } // // Relocate the machine & user names to the end of the // structure // pProxyRequestApp->dwClientMachineNameOffset = pProxyRequest->dwSize - pProxyRequest->dwClientMachineNameSize; wcscpy( (WCHAR *)(((LPBYTE) pProxyRequestApp) + pProxyRequestApp->dwClientMachineNameOffset), (WCHAR *)(((LPBYTE) pProxyRequest) + pProxyRequest->dwClientMachineNameOffset) ); pProxyRequestApp->dwClientUserNameOffset = pProxyRequestApp->dwClientMachineNameOffset - pProxyRequest->dwClientUserNameSize; wcscpy( (WCHAR *)(((LPBYTE) pProxyRequestApp) + pProxyRequestApp->dwClientUserNameOffset), (WCHAR *)(((LPBYTE) pProxyRequest) + pProxyRequest->dwClientUserNameOffset) ); break; } pProxyRequestHeader->dwKey = TPROXYREQUESTHEADER_KEY; pProxyRequestHeader->dwInstance = pAsyncEventMsg->Param1; pAsyncEventMsg->Param1 = (ULONG_PTR) pProxyRequestApp; } // // Call the post processing proc if there is one // if (pAsyncEventMsg->fnPostProcessProcHandle) { LOG((TL_INFO, "AsyncEventsThread: calling postprocessing function," "function index (pAsyncEventMsg->fnPostProcessProcHandle) = " "[%d]", pAsyncEventMsg->fnPostProcessProcHandle)); (*(gPostProcessingFunctions[ pAsyncEventMsg->fnPostProcessProcHandle]))(pAsyncEventMsg); } LOG((TL_INFO, "AsyncEventsThread: calling ProcessMessage()")); if FAILED(ProcessMessage( pInitData, pAsyncEventMsg ) ) { LOG((TL_INFO, "AsyncEventsThread: ProcessMessage()" " did not succeed. requeueing...")); BOOL bQueueSuccess = gpRetryQueue->QueueEvent(pAsyncEventMsg); if (!bQueueSuccess) { // // QueueEvent failed to allocate resources needed to queue // the message. other than log a message, there is nothing // much we can do. // LOG((TL_ERROR, "AsyncEventsThread: ProcessMessage() - " "failed to requeue item")); } } AsyncEventsThread_leaveCritSec: // LOG((TL_INFO, "AsyncEventsThread: releasing critical section (0x%08lx)", gcsTapisrvCommunication)); LeaveCriticalSection (&gcsTapisrvCommunication); AsyncEventsThread_decrUsedSize: dwUsedSize -= pAsyncEventMsg->TotalSize; pAsyncEventMsg = (PASYNCEVENTMSG) ((LPBYTE) pAsyncEventMsg + pAsyncEventMsg->TotalSize); #if DBG if ( (LONG)dwUsedSize < 0 ) { LOG((TL_ERROR, "dwUsedSize went negative!!!")); } #endif } // END while (dwUsedSize) // LOG((TL_INFO, "AsyncEventsThread: Done processing TAPISRV message block")); // We've now processed all the messages in the last RPC block from TAPISRV // Now lets process the Re-try Queue gpRetryQueue->ProcessQueue(); } // end of message reading/processing loop // // the thread is about to exit, we don't want to leave anything behind in // the retry queue, so close the queue for new entries and process all the // entries that are already in there // // // mark the queue as closed for new entries // gpRetryQueue->CloseForNewEntries(); // // process elements still remaining in the queue // gpRetryQueue->ProcessQueue(); { // // Free our resources, and then exit // HANDLE hTapi32 = pAsyncEventsThreadParams->hTapi32; if (pAsyncEventsThreadParams->hWow32) { FreeLibrary ((HINSTANCE)(pAsyncEventsThreadParams->hWow32)); } ClientFree (pBuf); ClientFree (pAsyncEventsThreadParams); CoUninitialize(); LOG((TL_TRACE, "AsyncEventsThread: exit")); FreeLibraryAndExitThread ((HINSTANCE)hTapi32, 0); } } BOOL PASCAL IsBadDwordPtr( LPDWORD p ) { DWORD dwError; __try { *p = *p + 1; } __except ((((dwError = GetExceptionCode()) == EXCEPTION_ACCESS_VIOLATION) || dwError == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return TRUE; } *p = *p - 1; return FALSE; } BOOL WINAPI GrowBuf( LPBYTE *ppBuf, LPDWORD pdwBufSize, DWORD dwCurrValidBytes, DWORD dwBytesToAdd ) { DWORD dwCurrBufSize, dwNewBufSize; LPBYTE pNewBuf; // // Try to get a new buffer big enough to hold everything // for( dwNewBufSize = 2 * (dwCurrBufSize = *pdwBufSize); dwNewBufSize < (dwCurrBufSize + dwBytesToAdd); dwNewBufSize *= 2 ); if (!(pNewBuf = (LPBYTE)ClientAlloc (dwNewBufSize))) { return FALSE; } // // Copy the "valid" bytes in the old buf to the new buf, // then free the old buf // CopyMemory (pNewBuf, *ppBuf, dwCurrValidBytes); ClientFree (*ppBuf); // // Reset the pointers to the new buf & buf size // *ppBuf = pNewBuf; *pdwBufSize = dwNewBufSize; return TRUE; } PCLIENT_THREAD_INFO WINAPI GetTls( void ) { PCLIENT_THREAD_INFO pClientThreadInfo; if (!(pClientThreadInfo = (PCLIENT_THREAD_INFO)TlsGetValue (gdwTlsIndex))) { pClientThreadInfo = (PCLIENT_THREAD_INFO) ClientAlloc (sizeof(CLIENT_THREAD_INFO)); if (!pClientThreadInfo) { return NULL; } pClientThreadInfo->pBuf = (unsigned char *)ClientAlloc (INITIAL_CLIENT_THREAD_BUF_SIZE); if (!pClientThreadInfo->pBuf) { ClientFree (pClientThreadInfo); return NULL; } pClientThreadInfo->dwBufSize = INITIAL_CLIENT_THREAD_BUF_SIZE; TlsSetValue (gdwTlsIndex, (LPVOID) pClientThreadInfo); EnterCriticalSection (&gTlsCriticalSection); InsertHeadList (&gTlsListHead, &pClientThreadInfo->TlsList); LeaveCriticalSection (&gTlsCriticalSection); } return pClientThreadInfo; } #if DBG LONG WINAPI DoFunc( PFUNC_ARGS pFuncArgs, char *pszFuncName ) #else LONG WINAPI DoFunc( PFUNC_ARGS pFuncArgs ) #endif { DWORD dwFuncClassErrorIndex = (pFuncArgs->Flags & 0x00000030) >> 4; LONG lResult; BOOL bCopyOnSuccess = FALSE; DWORD i, j, dwUsedSize, dwNeededSize; ULONG_PTR Value; PCLIENT_THREAD_INFO pTls; #if DBG LOG((TL_INFO, "About to call %s", pszFuncName)); #endif // // Get the tls // if (!(pTls = GetTls())) { lResult = gaNoMemErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } // // The first arg of all async msg blocks is a remote request id; set // this to zero to indicate that we are a local client (not remotesp) // if (pFuncArgs->Flags & ASYNC) { ((PTAPI32_MSG) pTls->pBuf)->Params[0] = 0; } // // Validate all the func args // dwNeededSize = dwUsedSize = ALIGN (sizeof (TAPI32_MSG)); for( i = 0, j = (pFuncArgs->Flags & ASYNC ? 1 : 0); i < (pFuncArgs->Flags & NUM_ARGS_MASK); i++, j++ ) { // // extract the ptr-sized value from the arguments // Value = pFuncArgs->Args[i]; ((PTAPI32_MSG) pTls->pBuf)->Params[j] = pFuncArgs->Args[i]; switch (pFuncArgs->ArgTypes[i]) { case Dword: // // make sure the data is 32bit at most // ((PTAPI32_MSG) pTls->pBuf)->Params[j] = DWORD_CAST(pFuncArgs->Args[i]); continue; case lpDword: if (IsBadDwordPtr ((LPDWORD) Value)) { LOG((TL_ERROR, "Bad lpdword in dofunc")); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } // // we don't need to send the actual pointer. but send the value we point to. // ((PTAPI32_MSG) pTls->pBuf)->Params[j] = *((DWORD*)Value); bCopyOnSuccess = TRUE; continue; case hXxxApp_NULLOK: case hXxxApp: { // // Verify that the hXxxApp is a pointer to a valid InitData // struct, then retrieve the real hXxxApp from that struct. // If the hXxxApp is bad, pass the server 0xffffffff so that // it can figure out whether to return an UNINITIALIZED error // or a INVALAPPHANDLE error. // DWORD dwError; if ( (0 == pFuncArgs->Args[i]) && (hXxxApp_NULLOK == pFuncArgs->ArgTypes[i]) ) { // // Looks good to me... // continue; } __try { // // Value contains the 32-bit handle to be passed to tapisrv // // recover the pointer corresponding to the 32-bit handle in Value // PT3INIT_DATA pInitData = (PT3INIT_DATA) GetHandleTableEntry(Value); if (pInitData->dwKey != INITDATA_KEY) { LOG((TL_ERROR, "DoFunc: Bad hxxxapp [%p] in dofunc", pInitData)); ((PTAPI32_MSG) pTls->pBuf)->Params[j] = 0xffffffff; } else { ((PTAPI32_MSG) pTls->pBuf)->Params[j] = pInitData->hXxxApp; } } __except ((((dwError = GetExceptionCode()) == EXCEPTION_ACCESS_VIOLATION) || dwError == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_ERROR, "DoFunc: Bad hxxxapp2 in dofunc (0x%08lx)", dwError)); ((PTAPI32_MSG) pTls->pBuf)->Params[j] = 0xffffffff; } continue; } case Hwnd: if (!IsWindow ((HWND) Value)) { LOG((TL_ERROR, "DoFunc: Bad hWnd in dofunc")); lResult = gaInvalHwndErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } continue; // case lpsz: case lpszW: // // Check if Value is a valid string ptr and if so // copy the contents of the string to the extra data // buffer passed to the server // __try { DWORD n = (lstrlenW((WCHAR *) Value) + 1) * sizeof(WCHAR), nAligned = ALIGN (n); if ((nAligned + dwUsedSize) > pTls->dwBufSize) { if (!GrowBuf( &pTls->pBuf, &pTls->dwBufSize, dwUsedSize, nAligned )) { lResult = gaNoMemErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } } CopyMemory (pTls->pBuf + dwUsedSize, (LPBYTE) Value, n); // // Pass the server the offset of the string in the var data // portion of the buffer // ((PTAPI32_MSG) pTls->pBuf)->Params[j] = dwUsedSize - sizeof (TAPI32_MSG); // // Increment the total number of data bytes // dwUsedSize += nAligned; dwNeededSize += nAligned; } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } continue; case lpGet_Struct: case lpGet_SizeToFollow: { BOOL bSizeToFollow = (pFuncArgs->ArgTypes[i]==lpGet_SizeToFollow); DWORD dwSize; if (bSizeToFollow) { #if DBG // // Check to make sure the following arg is of type Size // if ((i == ((pFuncArgs->Flags & NUM_ARGS_MASK) - 1)) || (pFuncArgs->ArgTypes[i + 1] != Size)) { LOG(( TL_ERROR, "DoFunc: error, lpGet_SizeToFollow !followed by Size" )); lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } #endif dwSize = pFuncArgs->Args[i + 1]; } else { DWORD dwError; __try { dwSize = *((LPDWORD) Value); } __except ((((dwError = GetExceptionCode()) == EXCEPTION_ACCESS_VIOLATION) || dwError == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_ERROR, "Bad get struct/size in dofunc")); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } } if (TAPIIsBadWritePtr ((LPVOID) Value, dwSize)) { LOG((TL_ERROR, "Bad get size/struct2 in dofunc")); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } if (bSizeToFollow) { ((PTAPI32_MSG) pTls->pBuf)->Params[j] = TAPI_NO_DATA; ((PTAPI32_MSG) pTls->pBuf)->Params[++j] = pFuncArgs->Args[++i]; } else { ((PTAPI32_MSG) pTls->pBuf)->Params[j] = dwSize; } // // Now set the bCopyOnSuccess flag to indicate that we've data // to copy back on successful completion, and add to the // dwNeededSize field // bCopyOnSuccess = TRUE; dwNeededSize += ALIGN (dwSize); continue; } case lpSet_Struct: case lpSet_SizeToFollow: { BOOL bSizeToFollow = (pFuncArgs->ArgTypes[i]==lpSet_SizeToFollow); DWORD dwSize, dwError, dwSizeAligned; #if DBG // // Check to make sure the following arg is of type Size // if (bSizeToFollow && ((i == ((pFuncArgs->Flags & NUM_ARGS_MASK) - 1)) || (pFuncArgs->ArgTypes[i + 1] != Size))) { LOG(( TL_ERROR, "DoFunc: error, lpSet_SizeToFollow !followed by Size" )); lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } #endif __try { // // First determine the data size & if the ptr is bad // dwSize = (bSizeToFollow ? pFuncArgs->Args[i + 1] : *((LPDWORD) Value)); if (IsBadReadPtr ((LPVOID) Value, dwSize)) { LOG((TL_ERROR, "Bad set size/struct in dofunc")); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } dwSizeAligned = ALIGN (dwSize); // // Special case if the size isn't even big enough to pass // over a complete DWORD for the dwTotalSize field // if (!bSizeToFollow && (dwSize < sizeof (DWORD))) { static DWORD dwZeroTotalSize = 0; dwSize = dwSizeAligned = sizeof (DWORD); Value = (ULONG_PTR) &dwZeroTotalSize; // LOG((TL_1, "Bad set size/struct2 in dofunc")); // lResult = gaStructTooSmallErrors[dwFuncClassErrorIndex]; // goto DoFunc_return; } // // Grow the buffer if necessary, & do the copy // if ((dwSizeAligned + dwUsedSize) > pTls->dwBufSize) { if (!GrowBuf( &pTls->pBuf, &pTls->dwBufSize, dwUsedSize, dwSizeAligned )) { LOG((TL_ERROR, "Nomem set size/struct in dofunc")); lResult = gaNoMemErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } } CopyMemory (pTls->pBuf + dwUsedSize, (LPBYTE) Value, dwSize); } __except ((((dwError = GetExceptionCode()) == EXCEPTION_ACCESS_VIOLATION) || dwError == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_ERROR, "Bad pointer in get size/struct in dofunc")); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } // // Pass the server the offset of the data in the var data // portion of the buffer // if (dwSize) { ((PTAPI32_MSG) pTls->pBuf)->Params[j] = dwUsedSize - sizeof (TAPI32_MSG); } else { ((PTAPI32_MSG) pTls->pBuf)->Params[j] = TAPI_NO_DATA; } // // Increment the dwXxxSize vars appropriately // dwUsedSize += dwSizeAligned; dwNeededSize += dwSizeAligned; // // Since we already know the next arg (Size) just handle // it here so we don't have to run thru the loop again // if (bSizeToFollow) { ((PTAPI32_MSG) pTls->pBuf)->Params[++j] = pFuncArgs->Args[++i]; } continue; } #if DBG case Size: LOG((TL_ERROR, "DoFunc: error, hit case Size")); continue; default: LOG((TL_ERROR, "DoFunc: error, unknown arg type")); continue; #endif } // switch } // for // // Now make the request // if (dwNeededSize > pTls->dwBufSize) { if (!GrowBuf( &pTls->pBuf, &pTls->dwBufSize, dwUsedSize, dwNeededSize - pTls->dwBufSize )) { lResult = gaNoMemErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } } ((PTAPI32_MSG) pTls->pBuf)->u.Req_Func = (DWORD)HIWORD(pFuncArgs->Flags); { DWORD dwRetryCount = 0; BOOL bReinitResource; do { bReinitResource = FALSE; RpcTryExcept { ClientRequest (gphCx, pTls->pBuf, dwNeededSize, (LONG *)&dwUsedSize); lResult = ((PTAPI32_MSG) pTls->pBuf)->u.Ack_ReturnValue; if (lResult == TAPIERR_INVALRPCCONTEXT) { if (dwRetryCount ++ >= gdwMaxNumRequestRetries) { bReinitResource = FALSE; lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; dwRetryCount = 0; } else { bReinitResource = TRUE; } } else { bReinitResource = FALSE; dwRetryCount = 0; } } RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) { unsigned long rpcException = RpcExceptionCode(); if (rpcException == RPC_S_SERVER_TOO_BUSY) { if (dwRetryCount++ < gdwMaxNumRequestRetries) { Sleep (gdwRequestRetryTimeout); } else { dwRetryCount = 0; lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; } } else if ((rpcException == RPC_S_SERVER_UNAVAILABLE) || (rpcException == RPC_S_CALL_FAILED_DNE)) { if (dwRetryCount ++ >= gdwMaxNumRequestRetries) { bReinitResource = FALSE; lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; dwRetryCount = 0; } else { bReinitResource = TRUE; } } else { LOG((TL_ERROR, "DoFunc: rpcException # %d", rpcException)); lResult = gaOpFailedErrors[dwFuncClassErrorIndex]; dwRetryCount = 0; } } RpcEndExcept if (bReinitResource) { FreeClientResources(); AllocClientResources(dwFuncClassErrorIndex); } } while (dwRetryCount != 0); } // note: 99.99% of the time this result dump will == the one at end of the // func (only when ptrs have gone bad will the result differ), no reason // to dump 2x unless doing internal dbgging // LOG((TL_INFO, "DoFunc: back from srv- return code=0x%08lx", lResult)); // // If request completed successfully and the bCopyOnSuccess flag // is set then we need to copy data back to client buffer(s) // if ((lResult == TAPI_SUCCESS) && bCopyOnSuccess) { for (i = 0, j = 0; i < (pFuncArgs->Flags & NUM_ARGS_MASK); i++, j++) { PTAPI32_MSG pMsg = (PTAPI32_MSG) pTls->pBuf; DWORD dwServerData = pMsg->Params[j]; switch (pFuncArgs->ArgTypes[i]) { case Dword: case Hwnd: // case lpsz: case lpszW: case lpSet_Struct: continue; case lpDword: __try { // // Fill in the pointer with the return value // *((LPDWORD) pFuncArgs->Args[i]) = dwServerData; } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { // // this should really never happen -- the memory was // checked before the call to tapisrv ws made // _ASSERTE(FALSE); lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } continue; case lpGet_SizeToFollow: __try { // // Fill in the pointer with the return value // CopyMemory( (LPBYTE) pFuncArgs->Args[i], pTls->pBuf + dwServerData + sizeof(TAPI32_MSG), pMsg->Params[j+1] ); } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_ERROR, "DoFunc: lpGet_SizeToFollow MemCopy failed")); // // we made sure the memory was writeable before the call to tapisrv // if we catch an exception here, that means that tapisrv did not // return us proper information. in which case we cannot make any // assumtions about its state, so we are not responsible // for cleaning it up. // lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } // // Increment i (and j, since Size passed as arg in msg) // to skip following Size arg in pFuncArgs->Args // i++; j++; continue; case lpSet_SizeToFollow: // // Increment i (and j, since Size passed as arg in msg) // to skip following Size arg in pFuncArgs->Args // i++; j++; continue; case lpGet_Struct: __try { // // Params[j] contains the offset in the var data // portion of pTls->pBuf of some TAPI struct. // Get the dwUsedSize value from this struct & // copy that many bytes from pTls->pBuf to client buf // if (dwServerData != TAPI_NO_DATA) { LPDWORD pStruct; pStruct = (LPDWORD) (pTls->pBuf + sizeof(TAPI32_MSG) + dwServerData); CopyMemory( (LPBYTE) pFuncArgs->Args[i], (LPBYTE) pStruct, *(pStruct + 2) // ptr to dwUsedSize field ); } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_WARN, "DoFunc: lpGet_Struct MemCopy failed")); // // we made sure the memory of the size of the struct was // writeable before the call to tapisrv if we catch an // exception here, that most likely means that tapisrv // did not return us proper information. in which case // we cannot make any assumtions about its state, or // make an effort clean up tapisrv's state. // lResult = gaInvalPtrErrors[dwFuncClassErrorIndex]; goto DoFunc_return; } continue; default: continue; } } } // else if ((pFuncArgs->Flags & ASYNC) && (lResult < TAPI_SUCCESS)) // { // } DoFunc_return: #if DBG { char szResult[32]; LOG(( TL_INFO, "%s: result = %s", pszFuncName, MapResultCodeToText (lResult, szResult) )); } #endif return lResult; } HRESULT CreateMSPObject( DWORD dwDeviceID, IUnknown * pUnk, IUnknown ** ppMSPAggAddress ) { HRESULT hr; CLSID clsid; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lMSPIdentify), { (ULONG_PTR) dwDeviceID, (ULONG_PTR) &clsid, (ULONG_PTR) sizeof(clsid) }, { Dword, lpGet_SizeToFollow, Size } }; if ((hr = DOFUNC (&funcArgs, "lineMSPIdentify")) == 0) { hr = CoCreateInstance( clsid, pUnk, CLSCTX_ALL, IID_IUnknown, (void **) ppMSPAggAddress ); if (!SUCCEEDED(hr)) { LOG(( TL_ERROR, "CoCreate failed for MSP on dwDeviceID %ld - error %lx", dwDeviceID, hr )); } } else { LOG((TL_ERROR, "GetMSPClsid failed on dwDeviceID %l", dwDeviceID)); } return hr; } HRESULT LineReceiveMSPData( HLINE hLine, HCALL hCall, PBYTE pBuffer, DWORD dwSize ) { HRESULT hr = S_OK; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lReceiveMSPData), { (ULONG_PTR) hLine, (ULONG_PTR) hCall, (ULONG_PTR) pBuffer, (ULONG_PTR) dwSize }, { Dword, Dword, lpSet_SizeToFollow, Size } }; hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "LineReceiveMSPData") ); return hr; } LONG LoadUIDll( HWND hwndOwner, DWORD dwWidgetID, DWORD dwWidgetType, HANDLE *phDll, const CHAR *pszTUISPI_xxx, TUISPIPROC *ppfnTUISPI_xxx ) { LONG lResult; HANDLE hDll = NULL; WCHAR szUIDllName[MAX_PATH]; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, xGetUIDllName), { (ULONG_PTR) dwWidgetID, (ULONG_PTR) dwWidgetType, (ULONG_PTR) szUIDllName, (ULONG_PTR) MAX_PATH }, { Dword, Dword, lpGet_SizeToFollow, Size } }; if (hwndOwner && !IsWindow (hwndOwner)) { lResult = (dwWidgetType == TUISPIDLL_OBJECT_PHONEID ? PHONEERR_INVALPARAM : LINEERR_INVALPARAM); goto LoadUIDll_return; } if ((lResult = DOFUNC (&funcArgs, "GetUIDllName")) == 0) { if (hDll = TAPILoadLibraryW(szUIDllName)) { if ((*ppfnTUISPI_xxx = (TUISPIPROC) GetProcAddress( (HINSTANCE)hDll, pszTUISPI_xxx ))) { *phDll = hDll; lResult = 0; } else { LOG(( TL_ERROR, "LoadUIDll: GetProcAddress(%ls,%s) failed, err=%d", szUIDllName, pszTUISPI_xxx, GetLastError() )); FreeLibrary ((HINSTANCE)hDll); lResult = (dwWidgetType == TUISPIDLL_OBJECT_PHONEID ? PHONEERR_OPERATIONUNAVAIL : LINEERR_OPERATIONUNAVAIL); } } else { LOG(( TL_ERROR, "LoadLibraryW(%ls) failed, err=%d", szUIDllName, GetLastError() )); lResult = (dwWidgetType == TUISPIDLL_OBJECT_PHONEID ? PHONEERR_OPERATIONFAILED : LINEERR_OPERATIONFAILED); } } LoadUIDll_return: return lResult; } LONG PASCAL lineXxxProvider( const CHAR *pszTUISPI_providerXxx, LPCSTR lpszProviderFilename, HWND hwndOwner, DWORD dwPermProviderID, LPDWORD lpdwPermProviderID ) { BOOL bAddProvider = (pszTUISPI_providerXxx == gszTUISPI_providerInstall); WCHAR szUIDllName[MAX_PATH]; LONG lResult; HINSTANCE hDll; TUISPIPROC pfnTUISPI_providerXxx; HTAPIDIALOGINSTANCE htDlgInst; #ifndef _WIN64 if ( (GetVersion() & 0x80000000) && ( 0xffff0000 == ( (DWORD)hwndOwner & 0xffff0000) ) ) { // // Yeah. It don't play no ffff. // hwndOwner = (HWND) ( (DWORD)hwndOwner & 0x0000ffff ); } #endif if (bAddProvider && IsBadDwordPtr (lpdwPermProviderID)) { LOG((TL_ERROR, "Bad lpdwPermProviderID pointer")); return LINEERR_INVALPOINTER; } else if (hwndOwner && !IsWindow (hwndOwner)) { LOG((TL_ERROR, "hwndOwner is not a window")); return LINEERR_INVALPARAM; } { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, xGetUIDllName), { (ULONG_PTR) (bAddProvider ? (ULONG_PTR) &dwPermProviderID : dwPermProviderID), (ULONG_PTR) TUISPIDLL_OBJECT_PROVIDERID, (ULONG_PTR) szUIDllName, (ULONG_PTR) MAX_PATH, (ULONG_PTR) (bAddProvider ? (ULONG_PTR) lpszProviderFilename : TAPI_NO_DATA), (ULONG_PTR) (pszTUISPI_providerXxx==gszTUISPI_providerRemove ?1:0), (ULONG_PTR) &htDlgInst }, { (bAddProvider ? lpDword : Dword), Dword, lpGet_SizeToFollow, Size, (bAddProvider ? lpszW : Dword), Dword, lpDword } }; if ((lResult = DOFUNC (&funcArgs,"lineXxxProvider/GetUIDllName")) != 0) { if (lResult == TAPI16BITSUCCESS) { // 16 bit sp success // set result correctly, and return here lResult = 0; } return lResult; } } if ((hDll = TAPILoadLibraryW(szUIDllName))) { if ((pfnTUISPI_providerXxx = (TUISPIPROC) GetProcAddress( hDll, pszTUISPI_providerXxx ))) { LOG((TL_INFO, "Calling %ls...", pszTUISPI_providerXxx)); lResult = ((TUIPROVPROC)(*pfnTUISPI_providerXxx))( TUISPIDLLCallback, hwndOwner, dwPermProviderID ); #if DBG { char szResult[32]; LOG(( TL_INFO, "%ls: result = %s", pszTUISPI_providerXxx, MapResultCodeToText (lResult, szResult) )); } #endif } else { LOG(( TL_ERROR, "lineXxxProvider: GetProcAddr(%ls,%ls) failed, err=%d", szUIDllName, pszTUISPI_providerXxx, GetLastError() )); lResult = LINEERR_OPERATIONUNAVAIL; } FreeLibrary (hDll); } else { LOG(( TL_ERROR, "lineXxxProvider: LoadLibraryW('%ls') failed, err=%d", szUIDllName, GetLastError() )); lResult = LINEERR_OPERATIONFAILED; } { LONG lResult2; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, xFreeDialogInstance), { (ULONG_PTR) htDlgInst, (ULONG_PTR) lResult }, { Dword, Dword } }; // // If TUISPI_providerXxx failed then we want to pass that error back // to the app, else if it succeeded & FreeDlgInst failed then pass // that error back to the app // if ((lResult2 = DOFUNC( &funcArgs, "lineXxxProvider/FreeDialogInstance" )) == 0) { if (bAddProvider) { *lpdwPermProviderID = dwPermProviderID; } } else if (lResult == 0) { lResult = lResult2; } } return lResult; } LONG PASCAL ValidateXxxInitializeParams( DWORD dwAPIVersion, BOOL bLine, LPLINEINITIALIZEEXPARAMS pXxxInitExParams, LINECALLBACK pfnCallback ) { DWORD dwError; __try { DWORD dwTotalSize = pXxxInitExParams->dwTotalSize; if (dwTotalSize < sizeof (LINEINITIALIZEEXPARAMS)) { return (bLine ? LINEERR_STRUCTURETOOSMALL : PHONEERR_STRUCTURETOOSMALL); } if (TAPIIsBadWritePtr (pXxxInitExParams, dwTotalSize)) { return (bLine ? LINEERR_INVALPOINTER : PHONEERR_INVALPOINTER); } // // When checking the dwOptions field be careful about compatibility // with future vers, so we only look at the currently valid bits // switch ((pXxxInitExParams->dwOptions & 0xf)) { case 0: case LINEINITIALIZEEXOPTION_USEHIDDENWINDOW: if (IsBadCodePtr ((FARPROC) pfnCallback)) { return (bLine ? LINEERR_INVALPOINTER : PHONEERR_INVALPOINTER); } break; case LINEINITIALIZEEXOPTION_USECOMPLETIONPORT: if ( !gpPostQueuedCompletionStatus ) { HINSTANCE hInst; hInst = GetModuleHandle( "Kernel32.dll" ); #ifdef MEMPHIS { FARPROC pfn; BOOL fResult; DWORD dw; OVERLAPPED o; pfn = GetProcAddress( hInst, "GetCompletionPortStatus" ); if ( NULL == pfn ) { LOG((TL_ERROR, "It would seem CompletionPorts are not supported on this platform(1)")); return (bLine ? LINEERR_INVALFEATURE : PHONEERR_OPERATIONFAILED); } fResult = pfn( -1, &dw, &dw, &o, 0 ); } if ( ERROR_NOT_SUPPORTED != GetLastError() ) #endif { gpPostQueuedCompletionStatus = (PQCSPROC)GetProcAddress( hInst, "PostQueuedCompletionStatus" ); if ( NULL == gpPostQueuedCompletionStatus ) { LOG((TL_ERROR, "It would seem CompletionPorts are not supported on this platform")); return (bLine ? LINEERR_INVALFEATURE : PHONEERR_OPERATIONFAILED); } } } break; case LINEINITIALIZEEXOPTION_USEEVENT: break; default: if ( (TAPI_VERSION2_0 == dwAPIVersion) || (TAPI_VERSION2_1 == dwAPIVersion) ) { // // This 2.x app is nuts. // return (bLine ? LINEERR_INVALPARAM : PHONEERR_INVALPARAM); } else { // // This >2.0 app is asking for something we can't do. // return (bLine ? LINEERR_INCOMPATIBLEAPIVERSION : PHONEERR_INCOMPATIBLEAPIVERSION); } } pXxxInitExParams->dwNeededSize = pXxxInitExParams->dwUsedSize = sizeof (LINEINITIALIZEEXPARAMS); } __except ((((dwError = GetExceptionCode()) == EXCEPTION_ACCESS_VIOLATION) || dwError == EXCEPTION_DATATYPE_MISALIGNMENT) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { return (bLine ? LINEERR_INVALPOINTER : PHONEERR_INVALPOINTER); } return 0; } LONG GetTheModuleFileName( WCHAR ** ppName ) { DWORD dwSize = MAX_PATH, dwLength; WCHAR * pszModuleNamePathW; alloc_module_name_buf: if (!(pszModuleNamePathW = (WCHAR *)ClientAlloc (dwSize*sizeof(WCHAR)))) { return LINEERR_NOMEM; } if (GetVersion() & 0x80000000) { PSTR pTemp; // // We're on Win9x - do ANSI // pTemp = (PSTR) ClientAlloc( dwSize ); if ( NULL == pTemp ) { LOG(( TL_ERROR, "Mem alloc failed (for mod name) size:0x%08lx", dwSize )); return LINEERR_NOMEM; } if ((dwLength = GetModuleFileName( NULL, pTemp, dwSize )) == 0) { LOG(( TL_ERROR, "GetModuleFileNameA failed, err=%d", GetLastError() )); ClientFree( pTemp ); return LINEERR_INVALPARAM; } else if (dwLength >= dwSize) { ClientFree (pTemp); ClientFree (pszModuleNamePathW); dwSize *= 2; goto alloc_module_name_buf; } MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, pTemp, dwLength, pszModuleNamePathW, dwSize ); ClientFree( pTemp ); } else { // // We're on WinNT - do Unicode // if ((dwLength = GetModuleFileNameW( NULL, pszModuleNamePathW, dwSize )) == 0) { LOG(( TL_ERROR, "GetModuleFileNameW failed, err=%d", GetLastError() )); return LINEERR_INVALPARAM; } else if (dwLength >= dwSize) { ClientFree (pszModuleNamePathW); dwSize *= 2; goto alloc_module_name_buf; } } *ppName = pszModuleNamePathW; return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // CreateThreadsAndStuff // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LONG CreateThreadsAndStuff() { DWORD dwThreadID; LOG((TL_TRACE, "CreateThreadsAndStuff: enter")); // // Alloc resources for a new async events thread, then // create the thread // gpAsyncEventsThreadParams = (PASYNC_EVENTS_THREAD_PARAMS) ClientAlloc( sizeof (ASYNC_EVENTS_THREAD_PARAMS)); if (NULL == gpAsyncEventsThreadParams) { LOG((TL_ERROR, "CreateThreadsAndStuff: failed to allocate gpAsyncEventsThreadParams")); return LINEERR_OPERATIONFAILED; } // // we don't want the thread to exit as soon as it starts // gpAsyncEventsThreadParams->bExitThread = FALSE; // // Create the initial buffer the thread will use for // retreiving async events // gpAsyncEventsThreadParams->dwBufSize = ASNYC_MSG_BUF_SIZE; gpAsyncEventsThreadParams->pBuf = (LPBYTE) ClientAlloc( gpAsyncEventsThreadParams->dwBufSize); if (NULL == gpAsyncEventsThreadParams->pBuf) { LOG((TL_ERROR, "CreateThreadsAndStuff: failed to allocate gpAsyncEventsThreadParams->pBuf")); ClientFree( gpAsyncEventsThreadParams ); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } ghAsyncRetryQueueEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if (NULL == ghAsyncRetryQueueEvent) { LOG((TL_ERROR, "CreateThreadsAndStuff - failed to create ghAsyncRetryQueueEvent event")); ClientFree(gpAsyncEventsThreadParams->pBuf); ClientFree( gpAsyncEventsThreadParams ); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } // // create startup event -- the thread will signal it when it is up and // ready to do stuff // gpAsyncEventsThreadParams->hThreadStartupEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (NULL == gpAsyncEventsThreadParams->hThreadStartupEvent) { LOG((TL_ERROR, "CreateThreadsAndStuff - failed to create hThreadStartupEvent event. LastError= 0x%lx", GetLastError())); CloseHandle(ghAsyncRetryQueueEvent); ghAsyncRetryQueueEvent = NULL; ClientFree(gpAsyncEventsThreadParams->pBuf); ClientFree( gpAsyncEventsThreadParams ); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } // // Now that we've allocated all the resources try to exec // the thread // ghAsyncEventsThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) AsyncEventsThread, (LPVOID) gpAsyncEventsThreadParams, 0, &dwThreadID ); if (NULL == ghAsyncEventsThread) { LOG((TL_ERROR, "CreateThreadsAndStuff: failed to allocate AsyncEventsThread")); CloseHandle(ghAsyncRetryQueueEvent); ghAsyncRetryQueueEvent = NULL; CloseHandle(gpAsyncEventsThreadParams->hThreadStartupEvent); ClientFree(gpAsyncEventsThreadParams->pBuf); ClientFree(gpAsyncEventsThreadParams); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } // // wait for the thread to have completed initialization or for the thread // to exit. if the thread exited, it had an error, so return an error. // // this is needed so msp's do not initialize and start posting events // before asynceventsthread opens up RetryQueue to accept these events. // // it would be more efficient to wait for these events immediately before // creating address objects, but the code would be much more complex and // the performance gain would be for tapi initialization only, so we won't // bother. // HANDLE ahAsyncThreadEvents[] = { gpAsyncEventsThreadParams->hThreadStartupEvent, ghAsyncEventsThread }; DWORD dwWaitResult = WaitForMultipleObjectsEx( sizeof(ahAsyncThreadEvents)/sizeof(HANDLE), ahAsyncThreadEvents, FALSE, INFINITE, FALSE); // // succeeded or failed, this event is no longer needed // CloseHandle(gpAsyncEventsThreadParams->hThreadStartupEvent); gpAsyncEventsThreadParams->hThreadStartupEvent = NULL; // // did we unblock because the thread exited? // if (dwWaitResult == WAIT_OBJECT_0 + 1) { // // thread exited // LOG((TL_ERROR, "CreateThreadsAndStuff: AsyncEventsThread exited")); CloseHandle(ghAsyncRetryQueueEvent); ghAsyncRetryQueueEvent = NULL; CloseHandle(ghAsyncEventsThread); ClientFree(gpAsyncEventsThreadParams->pBuf); ClientFree(gpAsyncEventsThreadParams); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } // // did we unblock for any reason other than thread exited or success? // if (dwWaitResult != WAIT_OBJECT_0) { LOG((TL_ERROR, "CreateThreadsAndStuff: failed waiting tor AsyncEventsThread initialization")); // // we had an error waiting for the thread to signal its successful // startup. // // // if the thread is still up, tell it to stop. // gpAsyncEventsThreadParams->bExitThread = TRUE; // // we could wait for the thread to exit... but we got here because wait // failed, so there is little benefit in retrying. so take our chances // and clean up. // CloseHandle(ghAsyncRetryQueueEvent); ghAsyncRetryQueueEvent = NULL; CloseHandle(ghAsyncEventsThread); ghAsyncEventsThread = NULL; ClientFree(gpAsyncEventsThreadParams->pBuf); ClientFree(gpAsyncEventsThreadParams); gpAsyncEventsThreadParams = NULL; return LINEERR_OPERATIONFAILED; } // // if we got here, async events thread initialized and is running // ghCallbackThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); gbExitThread = FALSE; ghCallbackThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE) CallbackThread, (LPVOID) NULL, 0, &dwThreadID ); if (NULL == ghCallbackThread) { // don't free these buffers. The other thread // is already running at this point, the these // buffers will be cleaned up during normal // shutdown //ClientFree(gpAsyncEventsThreadParams->pBuf); //ClientFree(gpAsyncEventsThreadParams); LOG((TL_ERROR, "CreateThreadsAndStuff: failed to create CallbackThread")); return LINEERR_OPERATIONFAILED; } LOG((TL_TRACE, "CreateThreadsAndStuff: exit")); return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // NewInitialize // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HRESULT CTAPI::NewInitialize() { LOG((TL_INFO, "NewInitialize - enter")); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lInitialize), { (ULONG_PTR) &m_hLineApp, // tapisrv ignores this argument, so pass 0 and save on HINSTANCE<->32bit conversion 0, 0, (ULONG_PTR) gszTAPI3, (ULONG_PTR) &m_dwLineDevs, 0, // pszModuleName TAPI_CURRENT_VERSION }, { lpDword, Dword, Dword, lpszW, lpDword, lpszW, Dword } }; WCHAR * pszModuleNamePathW = NULL; LONG lResult = (LONG)S_OK; int tapiObjectArraySize=0; lResult = GetTheModuleFileName( &pszModuleNamePathW ); if ( 0!= lResult ) { goto xxxInitialize_return; } funcArgs.Args[5] = (ULONG_PTR) wcsrchr (pszModuleNamePathW, '\\') + sizeof(WCHAR); _ASSERTE(m_pLineInitData == NULL); m_pLineInitData = (PT3INIT_DATA) ClientAlloc (sizeof(T3INIT_DATA)); if (NULL == m_pLineInitData) { LOG((TL_ERROR, "NewInitialize: failed to allocate m_pLineInitData")); lResult = LINEERR_NOMEM; goto xxxInitialize_return; } m_pLineInitData->dwInitOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW | LINEINITIALIZEEXOPTION_CALLHUBTRACKING; m_pLineInitData->bPendingAsyncEventMsg = FALSE; m_pLineInitData->dwKey = INITDATA_KEY; m_pLineInitData->pTAPI = this; // // We want to pass TAPISRV pInitData so that later when it does async // completion/event notification it can pass pInitData along too so // we know which init instance to talk to // // // convert the pointer into a 32-bit handle, so we don't need to pass a // 64-bit value between tapi3.dll and tapisrv // _ASSERTE(m_dwLineInitDataHandle == 0); m_dwLineInitDataHandle = CreateHandleTableEntry((ULONG_PTR)m_pLineInitData); LOG((TL_INFO, "NewInitialize: handle for m_pLineInitData = [0x%lx]", m_dwLineInitDataHandle)); if (0 == m_dwLineInitDataHandle) { LOG((TL_ERROR, "NewInitialize: failed to create handle")); ClientFree(m_pLineInitData); m_pLineInitData = NULL; lResult = LINEERR_NOMEM; goto xxxInitialize_return; } funcArgs.Args[2] = m_dwLineInitDataHandle; // // call lineInitialize // lResult = DOFUNC (&funcArgs, "lineInitialize"); if (lResult == 0) { LOG((TL_INFO, "NewInitialize: lineInitialize succeeded. m_hLineApp %p", m_hLineApp)); } else { LOG((TL_ERROR, "NewInitialize: lineInitialize failed. ")); // // undo the deed // ClientFree(m_pLineInitData); m_pLineInitData = NULL; DeleteHandleTableEntry(m_dwLineInitDataHandle); m_dwLineInitDataHandle = NULL; goto xxxInitialize_return; } // // Save the hLineApp returned by TAPISRV in our InitData struct, // and give the app back a pointer to the InitData struct instead // m_pLineInitData->hXxxApp = m_hLineApp; // // now setup for phoneinitialize // funcArgs.Args[0] = (ULONG_PTR)&m_hPhoneApp; funcArgs.Args[4] = (ULONG_PTR)&m_dwPhoneDevs; funcArgs.Flags = MAKELONG (PHONE_FUNC | SYNC | 7, pInitialize); _ASSERTE(m_pPhoneInitData == NULL); m_pPhoneInitData = (PT3INIT_DATA) ClientAlloc (sizeof(T3INIT_DATA)); if ( NULL == m_pPhoneInitData ) { LOG((TL_ERROR, "NewInitialize: failed to allocate m_pPhoneInitData")); lResult = LINEERR_NOMEM; goto xxxInitialize_return; } m_pPhoneInitData->dwInitOptions = LINEINITIALIZEEXOPTION_USEHIDDENWINDOW; m_pPhoneInitData->bPendingAsyncEventMsg = FALSE; m_pPhoneInitData->dwKey = INITDATA_KEY; m_pPhoneInitData ->pTAPI = this; // // We want to pass TAPISRV pInitData so that later when it does async // completion/event notification it can pass pInitData along too so // we know which init instance to talk to // // // convert the pointer into a 32-bit handle, so we don't need to pass a // 64-bit value between tapi3.dll and tapisrv // _ASSERTE(m_dwPhoneInitDataHandle == 0); m_dwPhoneInitDataHandle = CreateHandleTableEntry((ULONG_PTR)m_pPhoneInitData ); LOG((TL_INFO, "NewInitialize: handle for m_pPhoneInitData = [0x%lx]", m_dwPhoneInitDataHandle)); if (0 == m_dwPhoneInitDataHandle) { LOG((TL_ERROR, "NewInitialize: failed to create handle")); // // free the phone-related resources that we have already allocated // ClientFree(m_pPhoneInitData); m_pPhoneInitData = NULL; lResult = LINEERR_NOMEM; goto xxxInitialize_return; } funcArgs.Args[2] = m_dwPhoneInitDataHandle; lResult = DOFUNC (&funcArgs, "phoneInitialize"); if (lResult == 0) { LOG((TL_INFO, "NewInitialize: phoneInitialize succeeded. m_hPhoneApp %p", m_hPhoneApp)); } else { LOG((TL_ERROR, "NewInitialize: phoneInitialize failed. ")); // // deallocate whatever resources we have allocated for the phone // ClientFree(m_pPhoneInitData); m_pPhoneInitData = NULL; DeleteHandleTableEntry(m_dwPhoneInitDataHandle); m_dwPhoneInitDataHandle = 0; goto xxxInitialize_return; } m_pPhoneInitData ->hXxxApp = m_hPhoneApp; // // If total number of init instances is 0 we need to start a // new async events thread // EnterCriticalSection( &gcsTapiObjectArray ); tapiObjectArraySize = m_sTAPIObjectArray.GetSize(); LeaveCriticalSection ( &gcsTapiObjectArray ); if ( 0 == tapiObjectArraySize ) { lResult = CreateThreadsAndStuff(); if ( 0 != lResult ) { goto xxxInitialize_return; } } xxxInitialize_return: if (pszModuleNamePathW) { ClientFree (pszModuleNamePathW); } if ( 0 != lResult ) { // // cleanup all line- and phone-related resources. // NewShutdown(); } #if DBG { char szResult[32]; LOG(( TL_INFO, "Initialize exit, result=%s", MapResultCodeToText (lResult, szResult) )); } #else // // we may want to know what happened even with non-debug build // LOG((TL_INFO, "NewInitialize - exit, result=0x%lx", lResult)); #endif return mapTAPIErrorCode( lResult ); } // // --------------------------------- lineXxx ---------------------------------- // HRESULT LineAccept( HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lAccept), { (ULONG_PTR) hCall, (ULONG_PTR) lpsUserUserInfo, dwSize }, { Dword, lpSet_SizeToFollow, Size } }; if (!lpsUserUserInfo) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } return mapTAPIErrorCode( (DOFUNC (&funcArgs, "lineAccept")) ); } HRESULT LineAddToConference( HCALL hConfCall, HCALL hConsultCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 2, lAddToConference), { (ULONG_PTR) hConfCall, (ULONG_PTR) hConsultCall }, { Dword, Dword } }; return mapTAPIErrorCode( (DOFUNC (&funcArgs, "LineAddToConference")) ); } LONG WINAPI lineAgentSpecific( HLINE hLine, DWORD dwAddressID, DWORD dwAgentExtensionIDIndex, LPVOID lpParams, DWORD dwSize ) { DWORD hpParams = CreateHandleTableEntry((ULONG_PTR) lpParams); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 7, lAgentSpecific), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, (ULONG_PTR) dwAgentExtensionIDIndex, hpParams, (ULONG_PTR) lpParams, (ULONG_PTR) dwSize }, { Dword, Dword, Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; LONG lResult = DOFUNC (&funcArgs, "lineAgentSpecific"); // // in case of failure or synchronous call, delete the entry from the table // otherwise, the callback will do that // if (lResult <= 0) { DeleteHandleTableEntry(hpParams); } return lResult; } HRESULT LineAnswer( HCALL hCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lAnswer), { (ULONG_PTR) hCall, (ULONG_PTR) 0, 0 }, { Dword, Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineAnswer") ); } HRESULT LineBlindTransfer( HCALL hCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lBlindTransfer), { (ULONG_PTR) hCall, (ULONG_PTR) lpszDestAddress, dwCountryCode }, { Dword, lpszW, Dword } }; if ( IsBadStringPtrW( lpszDestAddress, (UINT)-1 ) ) { LOG((TL_ERROR, "LineBlindTransfer: bad lpszDestAddress: 0x%p", lpszDestAddress)); return mapTAPIErrorCode(LINEERR_INVALPOINTER); } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineBlindTransfer") ); } HRESULT LineClose( T3LINE * pt3Line ) { LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, lClose), { (ULONG_PTR) pt3Line->hLine }, { Dword } }; gpLineHashTable->Lock(); lResult = DOFUNC (&funcArgs, "lineClose"); LOG((TL_INFO, "lineClose: line - %lx lResult %lx", pt3Line->hLine, lResult)); gpLineHashTable->Remove( (ULONG_PTR)(pt3Line->hLine) ); gpLineHashTable->Unlock(); // // remove the corresponding entry from the callback instance handle table // if (0 != pt3Line->dwAddressLineStructHandle) { LOG((TL_INFO, "lineClose: removing address line handle [%lx] from the handle table", pt3Line->dwAddressLineStructHandle)); DeleteHandleTableEntry(pt3Line->dwAddressLineStructHandle); pt3Line->dwAddressLineStructHandle = 0; } return mapTAPIErrorCode( lResult ); } void PASCAL lineCompleteCallPostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "lineCompleteCallPostProcess: enter")); LOG(( TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param2 == 0) { DWORD dwCompletionID = pMsg->Param3; LPDWORD lpdwCompletionID = (LPDWORD)GetHandleTableEntry(pMsg->Param4); DeleteHandleTableEntry(pMsg->Param4); __try { { *lpdwCompletionID = dwCompletionID; } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_WARN, "lineCompleteCallPostProcess: failed " "to write to [%p]: LINEERR_INVALPOINTER", lpdwCompletionID)); pMsg->Param2 = LINEERR_INVALPOINTER; } } } LONG WINAPI lineCompleteCall( HCALL hCall, LPDWORD lpdwCompletionID, DWORD dwCompletionMode, DWORD dwMessageID ) { DWORD hpdwCompletionID = CreateHandleTableEntry((ULONG_PTR)lpdwCompletionID); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lCompleteCall), { GetFunctionIndex(lineCompleteCallPostProcess), (ULONG_PTR) hCall, hpdwCompletionID, dwCompletionMode, dwMessageID }, { Dword, Dword, lpDword, Dword, Dword } }; LONG lResult = (DOFUNC (&funcArgs, "lineCompleteCall")); // // in case of failure or synchronous call, delete the entry from the table // otherwise, the callback will do that // if (lResult <= 0) { DeleteHandleTableEntry(hpdwCompletionID); } return lResult; } HRESULT LineCompleteTransfer( HCALL hCall, HCALL hConsultCall, T3CALL * pt3ConfCall, DWORD dwTransferMode ) { DWORD hpCallHandle = CreateHandleTableEntry((ULONG_PTR) &(pt3ConfCall->hCall)); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lCompleteTransfer), { GetFunctionIndex(lineMakeCallPostProcess), hCall, hConsultCall, hpCallHandle, dwTransferMode, }, { Dword, Dword, Dword, Dword, Dword, } }; if (dwTransferMode == LINETRANSFERMODE_TRANSFER) { funcArgs.Args[0] = 0; // // hpCallHandle should be ignored // funcArgs.Args[3] = 0; DeleteHandleTableEntry(hpCallHandle); hpCallHandle = 0; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineCompleteTransfer") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpCallHandle); hpCallHandle = 0; } return hr ; } HRESULT LineConfigDialogW( DWORD dwDeviceID, HWND hwndOwner, LPCWSTR lpszDeviceClass ) { LONG lResult; HANDLE hDll; TUISPIPROC pfnTUISPI_lineConfigDialog; if (lpszDeviceClass && IsBadStringPtrW (lpszDeviceClass, 256)) { return E_POINTER; } if ((lResult = LoadUIDll( hwndOwner, dwDeviceID, TUISPIDLL_OBJECT_LINEID, &hDll, gszTUISPI_lineConfigDialog, &pfnTUISPI_lineConfigDialog )) == 0) { LOG((TL_INFO, "Calling TUISPI_lineConfigDialog...")); lResult = ((TUILINECONFIGPROC)(*pfnTUISPI_lineConfigDialog))( TUISPIDLLCallback, dwDeviceID, (HWND)hwndOwner, (LPCSTR)lpszDeviceClass ); #if DBG { char szResult[32]; LOG((TL_INFO, "TUISPI_lineConfigDialog: result = %s", MapResultCodeToText (lResult, szResult) )); } #endif FreeLibrary ((HINSTANCE)hDll); } return mapTAPIErrorCode(lResult); } HRESULT LineConfigDialogEditW( DWORD dwDeviceID, HWND hwndOwner, LPCWSTR lpszDeviceClass, LPVOID const lpDeviceConfigIn, DWORD dwSizeIn, LPVARSTRING * ppDeviceConfigOut ) { LONG lResult; HANDLE hDll; TUISPIPROC pfnTUISPI_lineConfigDialogEdit; if (lpszDeviceClass && IsBadStringPtrW (lpszDeviceClass, (UINT) -1)) { return E_POINTER; } if (IsBadReadPtr (lpDeviceConfigIn, dwSizeIn)) { return E_POINTER; } DWORD dwSize = sizeof (VARSTRING) + 500; *ppDeviceConfigOut = (LPVARSTRING) ClientAlloc( dwSize ); if (NULL == *ppDeviceConfigOut) { LOG((TL_ERROR, "LineConfigDialogEditW exit - return E_OUTOFMEMORY")); return E_OUTOFMEMORY; } (*ppDeviceConfigOut)->dwTotalSize = dwSize; if ((lResult = LoadUIDll( hwndOwner, dwDeviceID, TUISPIDLL_OBJECT_LINEID, &hDll, gszTUISPI_lineConfigDialogEdit, &pfnTUISPI_lineConfigDialogEdit )) == 0) { while (TRUE) { LOG((TL_INFO, "Calling TUISPI_lineConfigDialogEdit...")); lResult = ((TUILINECONFIGEDITPROC)(*pfnTUISPI_lineConfigDialogEdit))( TUISPIDLLCallback, dwDeviceID, (HWND)hwndOwner, (char *)lpszDeviceClass, lpDeviceConfigIn, dwSizeIn, *ppDeviceConfigOut ); #if DBG { char szResult[32]; LOG((TL_INFO, "TUISPI_lineConfigDialogEdit: result = %s", MapResultCodeToText (lResult, szResult) )); } #endif if ((lResult == 0) && ((*ppDeviceConfigOut)->dwNeededSize > (*ppDeviceConfigOut)->dwTotalSize)) { dwSize = (*ppDeviceConfigOut)->dwNeededSize; ClientFree(*ppDeviceConfigOut); *ppDeviceConfigOut = (LPVARSTRING)ClientAlloc(dwSize); if (NULL == *ppDeviceConfigOut) { LOG((TL_ERROR, "LineConfigDialogEditW exit - return E_OUTOFMEMORY")); return E_OUTOFMEMORY; } (*ppDeviceConfigOut)->dwTotalSize = dwSize; } else { break; } } FreeLibrary ((HINSTANCE)hDll); } return mapTAPIErrorCode(lResult); } LONG WINAPI lineConfigProvider( HWND hwndOwner, DWORD dwPermanentProviderID ) { return (lineXxxProvider( gszTUISPI_providerConfig, // func name NULL, // lpszProviderFilename hwndOwner, // hwndOwner dwPermanentProviderID, // dwPermProviderID NULL // lpdwPermProviderID )); } HRESULT LineDeallocateCall( HCALL hCall ) { HRESULT hr; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, lDeallocateCall), { (ULONG_PTR) hCall }, { Dword } }; LOG((TL_INFO, "lineDeallocateCall - hCall = 0x%08lx", hCall)); hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineDeallocateCall") ); return hr; } void PASCAL lineDevSpecificPostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "lineDevSpecificPostProcess: enter")); LOG((TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param2 == 0) { DWORD dwSize = pMsg->Param4; LPBYTE pParams = (LPBYTE) GetHandleTableEntry(pMsg->Param3); // // no longer need the handle table entry for this handle // DeleteHandleTableEntry(pMsg->Param3); __try { { CopyMemory (pParams, (LPBYTE) (pMsg + 1), dwSize); } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { pMsg->Param2 = LINEERR_INVALPOINTER; LOG((TL_INFO, "lineDevSpecificPostProcess: failed to copy memory to " "[%p] from [%p]: LINEERR_INVALPOINTER", pParams, (LPBYTE) (pMsg + 1))); } } LOG((TL_TRACE, "lineDevSpecificPostProcess: exit")); } HRESULT WINAPI lineDevSpecific( HLINE hLine, DWORD dwAddressID, HCALL hCall, LPVOID lpParams, DWORD dwSize ) { // // convert the pointer to a handle. the table entry will be removed in // the callback // DWORD hpParams = CreateHandleTableEntry((ULONG_PTR)lpParams); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 7, lDevSpecific), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, dwAddressID, (ULONG_PTR) hCall, hpParams, // pass the handle to actual pointer (for post processing) (ULONG_PTR) lpParams, // pass data dwSize }, { Dword, Dword, Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; LONG lResult = DOFUNC (&funcArgs, "lineDevSpecific"); // // if failed, or synchronous call, remove the handle table entry. otherwise // the callback will do this. // HRESULT hr = E_FAIL; if (lResult <= 0) { DeleteHandleTableEntry(hpParams); hpParams = 0; hr = mapTAPIErrorCode(lResult); } else { // // block to see if the operation succeeds // hr = WaitForReply(lResult); } return hr; } LONG WINAPI lineDevSpecificFeature( HLINE hLine, DWORD dwFeature, LPVOID lpParams, DWORD dwSize ) { DWORD hpParams = CreateHandleTableEntry((ULONG_PTR)lpParams); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 6, lDevSpecificFeature), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, dwFeature, hpParams, // pass the actual pointer (for post processing) (ULONG_PTR) lpParams, // pass data dwSize }, { Dword, Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; LONG lResult = DOFUNC (&funcArgs, "lineDevSpecificFeature"); // // if failed, or synchronous call, remove the handle table entry. // otherwise the callback will do this. // if (lResult <= 0) { DeleteHandleTableEntry(hpParams); } return lResult; } HRESULT LineDial( HCALL hCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lDial), { (ULONG_PTR) hCall, (ULONG_PTR) lpszDestAddress, dwCountryCode }, { Dword, lpszW, Dword } }; if ( IsBadStringPtrW(lpszDestAddress, (UINT)-1) ) { LOG((TL_ERROR, "Bad lpszDestAddress in lineDial")); return mapTAPIErrorCode( LINEERR_INVALPOINTER ); } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineDial") ); } LONG LineDrop( HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lDrop), { (ULONG_PTR) hCall, (ULONG_PTR) lpsUserUserInfo, dwSize }, { Dword, lpSet_SizeToFollow, Size } }; if (!lpsUserUserInfo) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } return (DOFUNC (&funcArgs, "lineDrop")); } HRESULT LineForward( T3LINE * pt3Line, DWORD dwAddressID, LPLINEFORWARDLIST const lpForwardList, DWORD dwNumRingsNoAnswer, LPHCALL lphConsultCall ) { DWORD hpCallHandle = CreateHandleTableEntry((ULONG_PTR)lphConsultCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 9, lForward), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) pt3Line->hLine, FALSE, dwAddressID, (ULONG_PTR) lpForwardList, dwNumRingsNoAnswer, hpCallHandle, TAPI_NO_DATA, (ULONG_PTR) 0xffffffff // dwAsciiCallParamsCodePage }, { Dword, Dword, Dword, Dword, lpSet_Struct, Dword, Dword, Dword, Dword } }; if (!lpForwardList) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[4] = Dword; funcArgs.Args[4] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineForwardW") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpCallHandle); } return hr; } void PASCAL lineGatherDigitsWPostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "lineGatherDigitsWPostProcess: enter")); LOG((TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param1 & (LINEGATHERTERM_BUFFERFULL | LINEGATHERTERM_CANCEL | LINEGATHERTERM_TERMDIGIT | LINEGATHERTERM_INTERTIMEOUT)) { LPSTR lpsDigits = (LPSTR) GetHandleTableEntry(pMsg->Param2); // // no longer need the handle table entry // DeleteHandleTableEntry(pMsg->Param2); DWORD dwNumDigits = pMsg->Param4; LPWSTR pBuffer = (LPWSTR) (((ULONG_PTR *)(pMsg + 1)) + 2); __try { { CopyMemory (lpsDigits, pBuffer, dwNumDigits * sizeof(WCHAR)); } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { // // Don't do anything if we GPF // LOG((TL_WARN, "lineGatherDigitsWPostProcess: " "failed to write %lx digits to memory [%p]", dwNumDigits, lpsDigits)); } } pMsg->Param2 = pMsg->Param3 = 0; } HRESULT LineGatherDigits( HCALL hCall, DWORD dwDigitModes, LPWSTR lpsDigits, DWORD dwNumDigits, LPCWSTR lpszTerminationDigits, DWORD dwFirstDigitTimeout, DWORD dwInterDigitTimeout ) { // // Note: we do the ptr check here rather than in DOFUNC because we're // not passing any digits data within the context of this func // if (lpsDigits && TAPIIsBadWritePtr (lpsDigits, dwNumDigits * sizeof (WCHAR))) { return LINEERR_INVALPOINTER; } // // this entry will be cleared in the callback (lineGatherDigitsWPostProcess) // DWORD hpOutputBuffer = CreateHandleTableEntry((ULONG_PTR)lpsDigits); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 9, lGatherDigits), { GetFunctionIndex(lineGatherDigitsWPostProcess), (ULONG_PTR) hCall, (ULONG_PTR) 0, // this is the dwendtoendid for remotesp dwDigitModes, hpOutputBuffer, dwNumDigits, (ULONG_PTR) lpszTerminationDigits, dwFirstDigitTimeout, dwInterDigitTimeout }, { Dword, Dword, Dword, Dword, Dword, Dword, lpszW, Dword, Dword } }; if (lpszTerminationDigits == (LPCWSTR) NULL) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[6] = Dword; funcArgs.Args[6] = TAPI_NO_DATA; } else { if ( IsBadStringPtrW(lpszTerminationDigits, (UINT)-1) ) { DeleteHandleTableEntry(hpOutputBuffer); hpOutputBuffer = 0; LOG((TL_ERROR, "Bad lpszDestAddress in lineGatherDigitsW")); return( LINEERR_INVALPOINTER ); } } LONG lResult = DOFUNC (&funcArgs, "lineGatherDigits"); if (lResult < 0) { DeleteHandleTableEntry(hpOutputBuffer); hpOutputBuffer = 0; } return mapTAPIErrorCode(lResult); } HRESULT LineGenerateDigits( HCALL hCall, DWORD dwDigitMode, LPCWSTR lpszDigits, DWORD dwDuration ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 5, lGenerateDigits), { (ULONG_PTR) hCall, dwDigitMode, (ULONG_PTR) lpszDigits, dwDuration, 0 // dwEndToEndID, remotesp only }, { Dword, Dword, lpszW, Dword, Dword } }; if (!lpszDigits) { funcArgs.Args[2] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGenerateDigits") ); } HRESULT LineGenerateTone( HCALL hCall, DWORD dwToneMode, DWORD dwDuration, DWORD dwNumTones, LPLINEGENERATETONE const lpTones ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lGenerateTone), { (ULONG_PTR) hCall, dwToneMode, dwDuration, dwNumTones, TAPI_NO_DATA, // (DWORD) lpTones, 0, // dwNumTones * sizeof(LINEGENERATETONE) 0 // dwEndToEndID, remotesp only }, { Dword, Dword, Dword, Dword, Dword, // lpSet_SizeToFollow, Dword, // Size Dword } }; if (dwToneMode == LINETONEMODE_CUSTOM) { // // Set lpTones (& following Size arg) since in this case // they are valid args // funcArgs.ArgTypes[4] = lpSet_SizeToFollow; funcArgs.Args[4] = (ULONG_PTR) lpTones; funcArgs.ArgTypes[5] = Size; funcArgs.Args[5] = dwNumTones * sizeof(LINEGENERATETONE); } return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGenerateTone")); } HRESULT LineGetCallHubTracking( DWORD dwDeviceID, LINECALLHUBTRACKINGINFO ** ppTrackingInfo ) { return E_NOTIMPL; } HRESULT LineGetHubRelatedCalls( HCALLHUB hCallHub, HCALL hCall, LINECALLLIST ** ppCallHubList ) { DWORD dwSize = sizeof(LINECALLLIST) + sizeof(DWORD) * 20; HRESULT hr; *ppCallHubList = (LINECALLLIST *)ClientAlloc( dwSize ); if (NULL == *ppCallHubList) { return E_OUTOFMEMORY; } (*ppCallHubList)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetHubRelatedCalls), { (ULONG_PTR) hCallHub, (ULONG_PTR) hCall, (ULONG_PTR) *ppCallHubList }, { Dword, Dword, lpGet_Struct } }; while (TRUE) { hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGetHubRelatedCalls") ); if (!SUCCEEDED(hr)) { ClientFree( *ppCallHubList ); *ppCallHubList = NULL; return hr; } if ((*ppCallHubList)->dwNeededSize > (*ppCallHubList)->dwTotalSize) { dwSize = (*ppCallHubList)->dwNeededSize; ClientFree( *ppCallHubList ); *ppCallHubList = (LINECALLLIST *)ClientAlloc( dwSize ); if (NULL == *ppCallHubList) { return E_OUTOFMEMORY; } (*ppCallHubList)->dwTotalSize = dwSize; funcArgs.Args[2] = (ULONG_PTR) *ppCallHubList; } else { break; } } return hr; } HRESULT LineGetCallHub( HCALL hCall, HCALLHUB * pCallHub ) { DWORD dwSize = sizeof(LINECALLLIST) + sizeof(DWORD); HRESULT hr; LINECALLLIST * pCallList; pCallList = (LINECALLLIST *)ClientAlloc( dwSize ); if (NULL == pCallList) { return E_OUTOFMEMORY; } pCallList->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetHubRelatedCalls), { (ULONG_PTR) 0, (ULONG_PTR) hCall, (ULONG_PTR) pCallList }, { Dword, Dword, lpGet_Struct } }; hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGetHubRelatedCalls") ); if (SUCCEEDED(hr)) { *pCallHub = *(LPHCALLHUB)(((LPBYTE)pCallList) + pCallList->dwCallsOffset); } ClientFree( pCallList ); return hr; } HRESULT LineGetAddressCaps( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAddressID, DWORD dwAPIVersion, LPLINEADDRESSCAPS * ppAddressCaps ) { LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, lGetAddressCaps), { (ULONG_PTR) hLineApp, dwDeviceID, dwAddressID, dwAPIVersion, 0, (ULONG_PTR) *ppAddressCaps }, { hXxxApp, Dword, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetAddressCaps"); if ((0 == lResult) && ((*ppAddressCaps)->dwNeededSize > (*ppAddressCaps)->dwTotalSize)) { DWORD dwSize; dwSize = (*ppAddressCaps)->dwNeededSize; ClientFree(*ppAddressCaps); *ppAddressCaps = (LPLINEADDRESSCAPS) ClientAlloc( dwSize ); if (NULL == (*ppAddressCaps)) { return E_OUTOFMEMORY; } (*ppAddressCaps)->dwTotalSize = dwSize; funcArgs.Args[5] = (ULONG_PTR) *ppAddressCaps; } else { break; } } return mapTAPIErrorCode( lResult ); } LONG WINAPI lineGetAddressIDW( HLINE hLine, LPDWORD lpdwAddressID, DWORD dwAddressMode, LPCWSTR lpsAddress, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 5, lGetAddressID), { (ULONG_PTR) hLine, (ULONG_PTR) lpdwAddressID, dwAddressMode, (ULONG_PTR) lpsAddress, dwSize }, { Dword, lpDword, Dword, lpSet_SizeToFollow, Size } }; return (DOFUNC (&funcArgs, "lineGetAddressID")); } HRESULT LineGetAddressStatus( T3LINE * pt3Line, DWORD dwAddressID, LPLINEADDRESSSTATUS * ppAddressStatus ) { HRESULT hr; DWORD dwSize; dwSize = sizeof( LINEADDRESSSTATUS ) + 500; *ppAddressStatus = (LINEADDRESSSTATUS *)ClientAlloc( dwSize ); if ( NULL == *ppAddressStatus ) { LOG((TL_ERROR, "Alloc failed in LineGetAddressStatus")); return E_OUTOFMEMORY; } (*ppAddressStatus)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetAddressStatus), { (ULONG_PTR) pt3Line->hLine, dwAddressID, (ULONG_PTR) *ppAddressStatus }, { Dword, Dword, lpGet_Struct } }; while (TRUE) { hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGetAddressStatus") ); if ( 0 != hr ) { ClientFree( *ppAddressStatus ); *ppAddressStatus = NULL; return hr; } if ((0 == hr) && ((*ppAddressStatus)->dwNeededSize > (*ppAddressStatus)->dwTotalSize)) { dwSize = (*ppAddressStatus)->dwNeededSize; ClientFree( *ppAddressStatus ); *ppAddressStatus = (LPLINEADDRESSSTATUS) ClientAlloc( dwSize ); if (NULL == *ppAddressStatus) { LOG((TL_ERROR, "Alloc failed 2 in LineGetAddressStatus")); return E_OUTOFMEMORY; } (*ppAddressStatus)->dwTotalSize = dwSize; funcArgs.Args[2] = (ULONG_PTR)*ppAddressStatus; } else { break; } } return hr; } LONG WINAPI lineGetAgentActivityListW( HLINE hLine, DWORD dwAddressID, LPLINEAGENTACTIVITYLIST lpAgentActivityList ) { DWORD hpAgentActivityList = CreateHandleTableEntry((ULONG_PTR)lpAgentActivityList); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentActivityList), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, (ULONG_PTR) hpAgentActivityList, // pass the actual ptr (for ppproc) (ULONG_PTR) lpAgentActivityList // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct, } }; LONG lResult = DOFUNC (&funcArgs, "lineGetAgentActivityListW"); // // if failed, or synchronous call, remove the handle table entry. // otherwise the callback will do this. // if (lResult <= 0) { DeleteHandleTableEntry(hpAgentActivityList); } return lResult; } HRESULT LineGetAgentCaps( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAddressID, DWORD dwAppAPIVersion, LPLINEAGENTCAPS *ppAgentCaps ) { HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof(LINEAGENTCAPS) + 500; *ppAgentCaps = (LPLINEAGENTCAPS) ClientAlloc( dwSize ); if (NULL == *ppAgentCaps) { return E_OUTOFMEMORY; } (*ppAgentCaps)->dwTotalSize = dwSize; DWORD hpAgentCaps = CreateHandleTableEntry((ULONG_PTR)*ppAgentCaps); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 7, lGetAgentCaps), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLineApp, (ULONG_PTR) dwDeviceID, (ULONG_PTR) dwAddressID, (ULONG_PTR) dwAppAPIVersion, hpAgentCaps, // pass the actual ptr (for ppproc) (ULONG_PTR) *ppAgentCaps // pass data }, { Dword, hXxxApp, Dword, Dword, Dword, Dword, lpGet_Struct, } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "LineGetAgentCaps"); if (lResult > 0) // async reply { hr = WaitForReply( lResult ); if ((hr == S_OK) ) { if (((*ppAgentCaps)->dwNeededSize > (*ppAgentCaps)->dwTotalSize)) { // didnt Work , adjust buffer size & try again DeleteHandleTableEntry(hpAgentCaps); hpAgentCaps = 0; LOG((TL_INFO, "LineGetAgentCaps failed - buffer to small")); dwSize = (*ppAgentCaps)->dwNeededSize; ClientFree( *ppAgentCaps ); *ppAgentCaps = NULL; *ppAgentCaps = (LPLINEAGENTCAPS) ClientAlloc( dwSize ); if (*ppAgentCaps == NULL) { LOG((TL_ERROR, "LineGetAgentCaps - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { (*ppAgentCaps)->dwTotalSize = dwSize; hpAgentCaps = CreateHandleTableEntry((ULONG_PTR)*ppAgentCaps); funcArgs.Args[5] = hpAgentCaps; funcArgs.Args[6] = (ULONG_PTR)*ppAgentCaps; } } // buffer too small else { // WaitForReply succeeded and the buffer was big enough. // break out of the loop break; } } // waitforreply succeeded else { // waitforreply failed. not likely to receive a callback. // clear handle table entries. LOG((TL_ERROR, "LineGetAgentCaps - WaitForReply failed")); DeleteHandleTableEntry(hpAgentCaps); hpAgentCaps = 0; } } else // failed sync { LOG((TL_ERROR, "LineGetAgentCaps - failed sync")); DeleteHandleTableEntry(hpAgentCaps); hpAgentCaps = 0; hr = mapTAPIErrorCode( lResult ); break; } } // end while(TRUE) return hr; } LONG WINAPI lineGetAgentGroupListW( HLINE hLine, DWORD dwAddressID, LPLINEAGENTGROUPLIST lpAgentGroupList ) { DWORD hpAgentGroupList = CreateHandleTableEntry((ULONG_PTR)lpAgentGroupList); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentGroupList), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, hpAgentGroupList, // pass the actual ptr (for ppproc) (ULONG_PTR) lpAgentGroupList // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct, } }; LONG lResult = DOFUNC (&funcArgs, "lineGetAgentGroupListW"); // // if failed, or synchronous call, remove the handle table entry. // otherwise the callback will do this. // if (lResult <= 0) { DeleteHandleTableEntry(hpAgentGroupList); } return lResult; } LONG WINAPI lineGetAgentStatusW( HLINE hLine, DWORD dwAddressID, LPLINEAGENTSTATUS lpAgentStatus ) { DWORD hpAgentStatus = CreateHandleTableEntry((ULONG_PTR)lpAgentStatus); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentStatus), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, hpAgentStatus, // pass the actual ptr (for ppproc) (ULONG_PTR) lpAgentStatus // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct, } }; LONG lResult = DOFUNC(&funcArgs, "lineGetAgentStatusW"); if (lResult <= 0) { DeleteHandleTableEntry(hpAgentStatus); } return lResult; } LONG WINAPI lineGetAppPriorityW( LPCWSTR lpszAppName, DWORD dwMediaMode, LPLINEEXTENSIONID lpExtensionID, DWORD dwRequestMode, LPVARSTRING lpExtensionName, LPDWORD lpdwPriority ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lGetAppPriority), { (ULONG_PTR) lpszAppName, dwMediaMode, 0, 0, dwRequestMode, 0, (ULONG_PTR) lpdwPriority }, { lpszW, // app name Dword, // media mode Dword, // ext id (offset) Dword, // ext id (size) Dword, // request mode Dword, // ext name total size lpDword // lp pri } }; if (dwMediaMode & 0xff000000) { if ((LPVOID) lpExtensionName == (LPVOID) lpdwPriority) { return LINEERR_INVALPOINTER; } // // We have to do some arg list munging here (adding an extra arg) // // // Set lpExtensionID, the following Size arg, // lpExtensionName, and the following MinSize // Type's and Value appropriately since they're // valid args in this case // funcArgs.ArgTypes[2] = lpSet_SizeToFollow; funcArgs.Args[2] = (ULONG_PTR) lpExtensionID; funcArgs.ArgTypes[3] = Size; funcArgs.Args[3] = sizeof (LINEEXTENSIONID); funcArgs.ArgTypes[5] = lpGet_Struct; funcArgs.Args[5] = (ULONG_PTR) lpExtensionName; } if ( IsBadStringPtrW(lpszAppName, (UINT)-1) ) { LOG((TL_ERROR, "Bad lpszDestAddress in lineGetAppPriorityW")); return( LINEERR_INVALPOINTER ); } return (DOFUNC (&funcArgs, "lineGetAppPriority")); } HRESULT LineGetCallIDs( HCALL hCall, LPDWORD lpdwAddressID, LPDWORD lpdwCallID, LPDWORD lpdwRelatedCallID ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetCallIDs), { (ULONG_PTR) hCall, (ULONG_PTR) lpdwAddressID, (ULONG_PTR) lpdwCallID, (ULONG_PTR) lpdwRelatedCallID }, { Dword, lpDword, lpDword, lpDword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetCallIDs")); } HRESULT LineGetCallInfo( HCALL hCall, LPLINECALLINFO * ppCallInfo ) { if ( NULL == hCall ) { LOG((TL_WARN, "LineGetCallInfo: NULL hCall")); *ppCallInfo = NULL; return TAPI_E_INVALCALLSTATE; } *ppCallInfo = (LPLINECALLINFO) ClientAlloc( sizeof(LINECALLINFO) + 500 ); if (NULL == *ppCallInfo) { return E_OUTOFMEMORY; } (*ppCallInfo)->dwTotalSize = sizeof(LINECALLINFO) + 500; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lGetCallInfo), { (ULONG_PTR) hCall, (ULONG_PTR) *ppCallInfo }, { Dword, lpGet_Struct } }; HRESULT hr = E_FAIL; while (TRUE) { hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetCallInfo")); // // if we fail, free alloc // if ( FAILED(hr) ) { ClientFree( *ppCallInfo ); *ppCallInfo = NULL; return hr; } // // do we need to realloc? // if ((*ppCallInfo)->dwNeededSize > (*ppCallInfo)->dwTotalSize) { DWORD dwSize = (*ppCallInfo)->dwNeededSize; ClientFree( *ppCallInfo ); *ppCallInfo = (LPLINECALLINFO) ClientAlloc( dwSize ); if (NULL == *ppCallInfo) { // return LINEERR_NOMEM; return E_OUTOFMEMORY; } (*ppCallInfo)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR)*ppCallInfo; } else { break; } } return hr; } HRESULT LineGetCallStatus( HCALL hCall, LPLINECALLSTATUS * ppCallStatus ) { *ppCallStatus = (LPLINECALLSTATUS) ClientAlloc( sizeof(LINECALLSTATUS) + 500 ); if (NULL == *ppCallStatus) { return E_OUTOFMEMORY; } (*ppCallStatus)->dwTotalSize = sizeof(LINECALLSTATUS) + 500; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lGetCallStatus), { (ULONG_PTR) hCall, (ULONG_PTR) *ppCallStatus }, { Dword, lpGet_Struct } }; HRESULT hr = E_FAIL; while (TRUE) { hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetCallStatus")); // // if we fail, free alloc // if ( FAILED(hr) ) { ClientFree( *ppCallStatus ); *ppCallStatus = NULL; return hr; } // // do we need to realloc? // if ((*ppCallStatus)->dwNeededSize > (*ppCallStatus)->dwTotalSize) { DWORD dwSize = (*ppCallStatus)->dwNeededSize; ClientFree( *ppCallStatus ); *ppCallStatus = (LPLINECALLSTATUS) ClientAlloc( dwSize ); if (NULL == *ppCallStatus) { return mapTAPIErrorCode( LINEERR_NOMEM ); } (*ppCallStatus)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR)*ppCallStatus; } else { break; } } return hr; } HRESULT LineGetConfRelatedCalls( HCALL hCall, LINECALLLIST ** ppCallList ) { DWORD dwSize = sizeof(LINECALLLIST) + sizeof(DWORD) * 20; LONG lResult; HRESULT hr; *ppCallList = (LINECALLLIST *)ClientAlloc( dwSize ); if (NULL == *ppCallList) { return E_OUTOFMEMORY; } (*ppCallList)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC| 2, lGetConfRelatedCalls), { (ULONG_PTR) hCall, (ULONG_PTR) *ppCallList }, { Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetConfRelatedCalls") ; if ( (0 == lResult) && ((*ppCallList)->dwNeededSize > (*ppCallList)->dwTotalSize) ) { dwSize = (*ppCallList)->dwNeededSize; ClientFree( *ppCallList ); *ppCallList = (LINECALLLIST *)ClientAlloc( dwSize ); if (NULL == *ppCallList) { hr = E_OUTOFMEMORY; break; } (*ppCallList)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR) *ppCallList; } else { hr = mapTAPIErrorCode( lResult ); break; } } return hr; } LONG WINAPI lineGetCountryW( DWORD dwCountryID, DWORD dwAPIVersion, LPLINECOUNTRYLIST lpLineCountryList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetCountry), { dwCountryID, dwAPIVersion, 0, (ULONG_PTR) lpLineCountryList }, { Dword, Dword, Dword, lpGet_Struct } }; if ( ( TAPI_CURRENT_VERSION != dwAPIVersion ) && ( 0x00020000 != dwAPIVersion ) && ( 0x00010004 != dwAPIVersion ) && ( 0x00010003 != dwAPIVersion ) ) { LOG((TL_ERROR, "lineGetCountryW - bad API version 0x%08lx", dwAPIVersion)); return LINEERR_INCOMPATIBLEAPIVERSION; } return (DOFUNC (&funcArgs, "lineGetCountry")); } HRESULT LineGetDevCapsWithAlloc( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPLINEDEVCAPS * ppLineDevCaps ) { LONG lResult; *ppLineDevCaps = (LPLINEDEVCAPS) ClientAlloc( sizeof(LINEDEVCAPS) + 500 ); if (NULL == *ppLineDevCaps) { return E_OUTOFMEMORY; } (*ppLineDevCaps)->dwTotalSize = sizeof(LINEDEVCAPS) + 500; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 5, lGetDevCaps), { (ULONG_PTR) hLineApp, dwDeviceID, dwAPIVersion, 0, (ULONG_PTR) *ppLineDevCaps }, { hXxxApp, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetDevCaps"); if ((0 == lResult) && ((*ppLineDevCaps)->dwNeededSize > (*ppLineDevCaps)->dwTotalSize)) { DWORD dwSize = (*ppLineDevCaps)->dwNeededSize; ClientFree( *ppLineDevCaps ); *ppLineDevCaps = (LPLINEDEVCAPS) ClientAlloc( dwSize ); if (NULL == *ppLineDevCaps) { // return LINEERR_NOMEM; return E_OUTOFMEMORY; } (*ppLineDevCaps)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppLineDevCaps; } else { break; } } return mapTAPIErrorCode( lResult ); } HRESULT LineGetDevCaps( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPLINEDEVCAPS * ppLineDevCaps ) { LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 5, lGetDevCaps), { (ULONG_PTR) hLineApp, dwDeviceID, dwAPIVersion, 0, (ULONG_PTR) *ppLineDevCaps }, { hXxxApp, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetDevCaps"); if ((0 == lResult) && ((*ppLineDevCaps)->dwNeededSize > (*ppLineDevCaps)->dwTotalSize)) { DWORD dwSize = (*ppLineDevCaps)->dwNeededSize; ClientFree( *ppLineDevCaps ); *ppLineDevCaps = (LPLINEDEVCAPS) ClientAlloc( dwSize ); if (NULL == *ppLineDevCaps) { // return LINEERR_NOMEM; return E_OUTOFMEMORY; } (*ppLineDevCaps)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppLineDevCaps; } else { break; } } return mapTAPIErrorCode( lResult ); } HRESULT LineGetDevConfig( DWORD dwDeviceID, LPVARSTRING * ppDeviceConfig, LPCWSTR lpszDeviceClass ) { LONG lResult; DWORD dwSize = sizeof (VARSTRING) + 500; *ppDeviceConfig = (LPVARSTRING) ClientAlloc( dwSize ); if (NULL == *ppDeviceConfig) { return E_OUTOFMEMORY; } (*ppDeviceConfig)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetDevConfig), { dwDeviceID, (ULONG_PTR) *ppDeviceConfig, (ULONG_PTR) lpszDeviceClass }, { Dword, lpGet_Struct, lpszW } }; while ( TRUE ) { lResult = DOFUNC (&funcArgs, "lineGetDevConfig"); if ((lResult == 0) && ((*ppDeviceConfig)->dwNeededSize > (*ppDeviceConfig)->dwTotalSize)) { dwSize = (*ppDeviceConfig)->dwNeededSize; ClientFree(*ppDeviceConfig); *ppDeviceConfig = (LPVARSTRING)ClientAlloc(dwSize); if (NULL == *ppDeviceConfig) { LOG((TL_ERROR, "LineGetDevConfig exit - return E_OUTOFMEMORY")); return E_OUTOFMEMORY; } (*ppDeviceConfig)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR)*ppDeviceConfig; } else { break; } } LOG((TL_TRACE, "LineGetDevConfig exit - return %lx", lResult)); return mapTAPIErrorCode( lResult ); } LONG WINAPI lineGetIconW( DWORD dwDeviceID, LPCWSTR lpszDeviceClass, LPHICON lphIcon ) { HICON hIcon; LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetIcon), { dwDeviceID, (ULONG_PTR) lpszDeviceClass, (ULONG_PTR) &hIcon }, { Dword, lpszW, lpDword } }; if (IsBadDwordPtr ((LPDWORD) lphIcon)) { LOG((TL_ERROR, "lphIcon is an invalid pointer!")); return LINEERR_INVALPOINTER; } if (lpszDeviceClass == (LPCWSTR) NULL) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; } if ((lResult = DOFUNC (&funcArgs, "lineGetIcon")) == 0) { *lphIcon = hIcon; } return lResult; } HRESULT LineGetID( HLINE hLine, DWORD dwID, HCALL hCall, DWORD dwSelect, LPVARSTRING * ppDeviceID, LPCWSTR lpszDeviceClass ) { LONG lResult; DWORD dwNumDevices; DWORD dwDeviceId1, dwDeviceId2; BOOL bWaveDevice = FALSE; *ppDeviceID = (LPVARSTRING) ClientAlloc( sizeof (VARSTRING) + 500 ); if (NULL == *ppDeviceID) { return E_OUTOFMEMORY; } (*ppDeviceID)->dwTotalSize = sizeof (VARSTRING) + 500; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, lGetID), { (ULONG_PTR) hLine, dwID, (ULONG_PTR) hCall, dwSelect, (ULONG_PTR) *ppDeviceID, (ULONG_PTR) lpszDeviceClass }, { Dword, Dword, Dword, Dword, lpGet_Struct, lpszW } }; LOG((TL_TRACE, "LineGetID - enter")); LOG((TL_INFO, " hLine --------->%lx", hLine)); LOG((TL_INFO, " hCall ----------->%lx", hCall)); LOG((TL_INFO, " dwSelect -------->%lx", dwSelect)); LOG((TL_INFO, " ppDeviceID ------>%p", ppDeviceID)); LOG((TL_INFO, " lpszDeviceClass ->%p", lpszDeviceClass)); // // If the request is for a wave device, call LGetIDEx. // This will return a device string ID which is guaranteed to be unique across // all processes. // Then we will convert the string ID to the correct device ID in the client process context. // if (!_wcsicmp(lpszDeviceClass, L"wave/in") || !_wcsicmp(lpszDeviceClass, L"wave/out") || !_wcsicmp(lpszDeviceClass, L"midi/in") || !_wcsicmp(lpszDeviceClass, L"midi/out") || !_wcsicmp(lpszDeviceClass, L"wave/in/out") ) { bWaveDevice = TRUE; dwNumDevices = _wcsicmp(lpszDeviceClass, L"wave/in/out") ? 1 : 2; funcArgs.Flags = MAKELONG (LINE_FUNC | SYNC | 6, lGetIDEx); } while ( TRUE ) { lResult = DOFUNC (&funcArgs, bWaveDevice ? "lineGetIDEx" : "lineGetID"); if ((lResult == 0) && ((*ppDeviceID)->dwNeededSize > (*ppDeviceID)->dwTotalSize)) { DWORD dwSize = (*ppDeviceID)->dwNeededSize; ClientFree(*ppDeviceID); *ppDeviceID = (LPVARSTRING)ClientAlloc(dwSize); if (NULL == *ppDeviceID) { LOG((TL_ERROR, "LineGetID exit - return LINEERR_NOMEM")); // return LINEERR_NOMEM; return E_OUTOFMEMORY; } (*ppDeviceID)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppDeviceID; } else { if (lResult != 0) { ClientFree (*ppDeviceID); *ppDeviceID = NULL; } break; } } if (bWaveDevice && lResult == 0) { // // We got the string ID(s), now we need to convert them to numeric device ID(s) // BOOL bConversionOk; if ( dwNumDevices == 1 ) { bConversionOk = WaveStringIdToDeviceId ( (LPWSTR)((LPBYTE)(*ppDeviceID) + (*ppDeviceID)->dwStringOffset), lpszDeviceClass, &dwDeviceId1); } else { _ASSERTE(dwNumDevices == 2); // // for "wave/in/out", we get back two devices from tapisrv -> convert both // LPWSTR szString1 = (LPWSTR)((LPBYTE)(*ppDeviceID) + (*ppDeviceID)->dwStringOffset); // first convert the wave/in device bConversionOk = WaveStringIdToDeviceId ( szString1, L"wave/in", &dwDeviceId1); // next convert the wave/out device bConversionOk = bConversionOk && WaveStringIdToDeviceId ( szString1 + wcslen(szString1), L"wave/out", &dwDeviceId2); } if (!bConversionOk) { LOG((TL_ERROR, "LineGetID - WaveStringIdToDeviceId failed")); ClientFree(*ppDeviceID); *ppDeviceID = NULL; lResult = LINEERR_OPERATIONFAILED; } else { // // conversion succeeded, now fill the VARSTRING to be returned to the caller // (*ppDeviceID)->dwNeededSize = (*ppDeviceID)->dwUsedSize = sizeof(VARSTRING) + sizeof(DWORD) * dwNumDevices; (*ppDeviceID)->dwStringFormat = STRINGFORMAT_BINARY; (*ppDeviceID)->dwStringSize = sizeof(DWORD) * dwNumDevices; (*ppDeviceID)->dwStringOffset = sizeof(VARSTRING); *(DWORD *)((*ppDeviceID) + 1) = dwDeviceId1; if (dwNumDevices == 2) *((DWORD *)((*ppDeviceID) + 1) + 1) = dwDeviceId2; } } LOG((TL_TRACE, "LineGetID exit - return %lx", lResult)); return mapTAPIErrorCode( lResult ); } HRESULT LineGetLineDevStatus( HLINE hLine, LPLINEDEVSTATUS * ppDevStatus ) { HRESULT hr; DWORD dwSize = sizeof(LINEDEVSTATUS) + 500; *ppDevStatus = ( LPLINEDEVSTATUS ) ClientAlloc( dwSize ); if ( NULL == *ppDevStatus ) { LOG((TL_ERROR, "LineGetLineDevStatus - alloc failed")); return E_OUTOFMEMORY; } (*ppDevStatus)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lGetLineDevStatus), { (ULONG_PTR) hLine, (ULONG_PTR) *ppDevStatus }, { Dword, lpGet_Struct } }; while (TRUE) { hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGetLineDevStatus") ); if ( 0 != hr ) { ClientFree( *ppDevStatus ); *ppDevStatus = NULL; return hr; } if ((0 == hr) && ((*ppDevStatus)->dwNeededSize > (*ppDevStatus)->dwTotalSize)) { dwSize = (*ppDevStatus)->dwNeededSize; ClientFree( *ppDevStatus ); *ppDevStatus = (LPLINEDEVSTATUS) ClientAlloc( dwSize ); if (NULL == *ppDevStatus) { return E_OUTOFMEMORY; } (*ppDevStatus)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR)*ppDevStatus; } else { break; } } return hr; } HRESULT LineGetProxyStatus( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAppAPIVersion, LPLINEPROXYREQUESTLIST * ppLineProxyReqestList ) { HRESULT hr; DWORD dwSize = sizeof(LINEPROXYREQUESTLIST) + 100; *ppLineProxyReqestList = ( LPLINEPROXYREQUESTLIST ) ClientAlloc( dwSize ); if ( NULL == *ppLineProxyReqestList ) { LOG((TL_ERROR, "LineGetProxyStatus - alloc failed")); return E_OUTOFMEMORY; } (*ppLineProxyReqestList)->dwTotalSize = dwSize; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetProxyStatus), { (ULONG_PTR)hLineApp, dwDeviceID, dwAppAPIVersion, (ULONG_PTR) *ppLineProxyReqestList }, { hXxxApp, Dword, Dword, lpGet_Struct } }; while (TRUE) { hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineGetProxyStatus") ); if ( FAILED(hr) ) { ClientFree( *ppLineProxyReqestList ); *ppLineProxyReqestList = NULL; return hr; } // // succeeded, but need a bigger buffer? // if ( (*ppLineProxyReqestList)->dwNeededSize > (*ppLineProxyReqestList)->dwTotalSize ) { dwSize = (*ppLineProxyReqestList)->dwNeededSize; ClientFree( *ppLineProxyReqestList ); *ppLineProxyReqestList = (LPLINEPROXYREQUESTLIST) ClientAlloc( dwSize ); if (NULL == *ppLineProxyReqestList) { return E_OUTOFMEMORY; } (*ppLineProxyReqestList)->dwTotalSize = dwSize; funcArgs.Args[3] = (ULONG_PTR)*ppLineProxyReqestList; } else { // // plain success // break; } } return hr; } LONG WINAPI lineGetNewCalls( HLINE hLine, DWORD dwAddressID, DWORD dwSelect, LPLINECALLLIST lpCallList ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetNewCalls), { (ULONG_PTR) hLine, dwAddressID, dwSelect, (ULONG_PTR) lpCallList }, { Dword, Dword, Dword, lpGet_Struct } }; return (DOFUNC (&funcArgs, "lineGetNewCalls")); } LONG WINAPI lineGetNumRings( HLINE hLine, DWORD dwAddressID, LPDWORD lpdwNumRings ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetNumRings), { (ULONG_PTR) hLine, dwAddressID, (ULONG_PTR) lpdwNumRings }, { Dword, Dword, lpDword } }; return (DOFUNC (&funcArgs, "lineGetNumRings")); } HRESULT LineGetProviderList( LPLINEPROVIDERLIST * ppProviderList ) { LONG lResult; *ppProviderList = (LPLINEPROVIDERLIST) ClientAlloc( sizeof (LINEPROVIDERLIST) + 5*sizeof(LINEPROVIDERENTRY)); if (NULL == *ppProviderList) { return E_OUTOFMEMORY; } (*ppProviderList)->dwTotalSize = sizeof(LINEPROVIDERLIST) + 5*sizeof(LINEPROVIDERENTRY); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lGetProviderList), { TAPI_CURRENT_VERSION, (ULONG_PTR) *ppProviderList }, { Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetProviderList"); if ((0 == lResult) && ((*ppProviderList)->dwNeededSize > (*ppProviderList)->dwTotalSize)) { DWORD dwSize; dwSize = (*ppProviderList)->dwNeededSize; ClientFree(*ppProviderList); *ppProviderList = (LPLINEPROVIDERLIST) ClientAlloc( dwSize ); if (NULL == (*ppProviderList)) { return E_OUTOFMEMORY; } (*ppProviderList)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR) *ppProviderList; } else if ( 0 != lResult ) { ClientFree( *ppProviderList ); *ppProviderList = NULL; break; } else { break; } } return mapTAPIErrorCode( lResult ); } HRESULT LineGetRequest( HLINEAPP hLineApp, DWORD dwRequestMode, LPLINEREQMAKECALLW * ppReqMakeCall ) { *ppReqMakeCall = (LPLINEREQMAKECALLW)ClientAlloc( sizeof(LINEREQMAKECALLW) ); if ( NULL == *ppReqMakeCall ) { return E_OUTOFMEMORY; } FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lGetRequest), { (ULONG_PTR) hLineApp, dwRequestMode, (ULONG_PTR) *ppReqMakeCall, 0 }, { hXxxApp, Dword, lpGet_SizeToFollow, Size } }; if (dwRequestMode == LINEREQUESTMODE_MAKECALL) { // // Set the size param appropriately // funcArgs.Args[3] = sizeof(LINEREQMAKECALLW); } else if (dwRequestMode == LINEREQUESTMODE_MEDIACALL) { // // Set the size param appropriately // funcArgs.Args[3] = sizeof(LINEREQMEDIACALLW); } return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetRequest")); } LONG WINAPI lineGetStatusMessages( HLINE hLine, LPDWORD lpdwLineStates, LPDWORD lpdwAddressStates ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lGetStatusMessages), { (ULONG_PTR) hLine, (ULONG_PTR) lpdwLineStates, (ULONG_PTR) lpdwAddressStates }, { Dword, lpDword, lpDword } }; if (lpdwLineStates == lpdwAddressStates) { return LINEERR_INVALPOINTER; } return (DOFUNC (&funcArgs, "lineGetStatusMessages")); } HRESULT LineHandoff( HCALL hCall, LPCWSTR lpszFileName, DWORD dwMediaMode ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lHandoff), { (ULONG_PTR) hCall, (ULONG_PTR) lpszFileName, dwMediaMode }, { Dword, lpszW, Dword } }; if (lpszFileName == (LPCWSTR) NULL) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineHandoff") ); } HRESULT LineHold( HCALL hCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 1, lHold), { (ULONG_PTR) hCall }, { Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineHold")); } PWSTR PASCAL MultiToWide( LPCSTR lpStr ) { DWORD dwSize; PWSTR szTempPtr; dwSize = MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpStr, -1, NULL, 0 ); if ((szTempPtr = (PWSTR) ClientAlloc ((dwSize + 1) * sizeof (WCHAR)))) { MultiByteToWideChar( GetACP(), MB_PRECOMPOSED, lpStr, -1, szTempPtr, dwSize + 1 ); } return szTempPtr; } void PASCAL lineMakeCallPostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "lineMakeCallPostProcess: enter")); LOG((TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param2 == 0) { HCALL hCall = (HCALL) pMsg->Param3; LPHCALL lphCall = (LPHCALL)GetHandleTableEntry(pMsg->Param4); DeleteHandleTableEntry(pMsg->Param4); __try { { *lphCall = NULL; *lphCall = hCall; } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { LOG((TL_WARN, "lineMakeCallPostProcess: failed to write handle %lx to memory" " location %p. returning LINEERR_INVALPOINTER", hCall, lphCall)); pMsg->Param2 = LINEERR_INVALPOINTER; // // tapisrv has allocated a call handle for us. deallocate it. // LineDeallocateCall(hCall); } } } HRESULT LineMakeCall( T3LINE * pt3Line, HCALL * phCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams ) { DWORD hpCallHandle = CreateHandleTableEntry((ULONG_PTR)phCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 7, lMakeCall), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) pt3Line->hLine, hpCallHandle, (ULONG_PTR) lpszDestAddress, (ULONG_PTR) dwCountryCode, (ULONG_PTR) lpCallParams, (ULONG_PTR) 0xffffffff // dwAsciiCallParamsCodePage }, { Dword, Dword, Dword, lpszW, Dword, lpSet_Struct, Dword } }; if (!lpszDestAddress) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[3] = Dword; funcArgs.Args[3] = TAPI_NO_DATA; } if (!lpCallParams) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[5] = Dword; funcArgs.Args[5] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineMakeCall") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpCallHandle); } return hr; } HRESULT LineMonitorDigits( HCALL hCall, DWORD dwDigitModes ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lMonitorDigits), { (ULONG_PTR) hCall, dwDigitModes }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineMonitorDigits") ); } LONG WINAPI lineMonitorMedia( HCALL hCall, DWORD dwMediaModes ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lMonitorMedia), { (ULONG_PTR) hCall, dwMediaModes }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineMonitorMedia") ); } HRESULT LineMonitorTones( HCALL hCall, LPLINEMONITORTONE const lpToneList, DWORD dwNumEntries ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lMonitorTones), { (ULONG_PTR) hCall, (ULONG_PTR) lpToneList, dwNumEntries * sizeof(LINEMONITORTONE), 0 // dwToneListID, remotesp only }, { Dword, lpSet_SizeToFollow, Size, Dword } }; if (!lpToneList) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineMonitorTones")); } HRESULT LineNegotiateAPIVersion( HLINEAPP hLineApp, DWORD dwDeviceID, LPDWORD lpdwAPIVersion ) { LINEEXTENSIONID LED; LOG((TL_INFO, "LineNegotiateAPIVersion: hLineApp %p", hLineApp)); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lNegotiateAPIVersion), { (ULONG_PTR) hLineApp, dwDeviceID, TAPI_VERSION1_0, TAPI_VERSION_CURRENT, (ULONG_PTR) lpdwAPIVersion, (ULONG_PTR) &LED, (ULONG_PTR) sizeof(LINEEXTENSIONID) }, { hXxxApp, Dword, Dword, Dword, lpDword, lpGet_SizeToFollow, Size } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineNegotiateAPIVersion") ); } LONG WINAPI lineNegotiateExtVersion( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwExtLowVersion, DWORD dwExtHighVersion, LPDWORD lpdwExtVersion ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, lNegotiateExtVersion), { (ULONG_PTR) hLineApp, dwDeviceID, dwAPIVersion, dwExtLowVersion, dwExtHighVersion, (ULONG_PTR) lpdwExtVersion }, { hXxxApp, Dword, Dword, Dword, Dword, lpDword } }; return (DOFUNC (&funcArgs, "lineNegotiateExtVersion")); } HRESULT LineOpen( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAddressID, T3LINE * pt3Line, DWORD dwAPIVersion, DWORD dwPrivileges, DWORD dwMediaModes, AddressLineStruct * pAddressLine, LPLINECALLPARAMS const lpCallParams, CAddress * pAddress, CTAPI * pTapiObj, BOOL bAddToHashTable ) { LONG lResult; LINECALLPARAMS lcp; LINECALLPARAMS * plcp; if (IsBadReadPtr(pt3Line, sizeof(T3LINE))) { LOG((TL_ERROR, "LineOpen: pt3Line %p -- invalid ptr ", pt3Line)); // // if we are getting an invalid ptr, we need to see why // _ASSERTE(FALSE); return E_POINTER; } if (NULL == lpCallParams) { memset( &lcp, 0, sizeof(lcp) ); lcp.dwTotalSize = sizeof(lcp); lcp.dwAddressMode = LINEADDRESSMODE_ADDRESSID; lcp.dwAddressID = dwAddressID; plcp = &lcp; } else { plcp = lpCallParams; } dwPrivileges|= LINEOPENOPTION_SINGLEADDRESS; // // if we were passed a pAddressLine pointer, create a corresponding // DWORD-sized handle, and keep it around in the T3LINE structure. // we need this so we can remove the handle table entry on LineClose. // _ASSERTE(0 == pt3Line->dwAddressLineStructHandle); if (NULL != pAddressLine) { pt3Line->dwAddressLineStructHandle = CreateHandleTableEntry((UINT_PTR)pAddressLine); } FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 11, lOpen), { (ULONG_PTR) hLineApp, dwDeviceID, (ULONG_PTR) &(pt3Line->hLine), dwAPIVersion, 0, pt3Line->dwAddressLineStructHandle, dwPrivileges, //| LINEOPENOPTION_SINGLEADDRESS), dwMediaModes, (ULONG_PTR) plcp, (ULONG_PTR) 0xffffffff, // dwAsciiCallParamsCodePage 0 // LINEOPEN_PARAMS.hRemoteLine }, { hXxxApp, Dword, lpDword, Dword, Dword, Dword, Dword, Dword, lpSet_Struct, Dword, Dword } }; if (!(dwPrivileges & (LINEOPENOPTION_PROXY|LINEOPENOPTION_SINGLEADDRESS))) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[8] = Dword; funcArgs.Args[8] = TAPI_NO_DATA; } gpLineHashTable->Lock(); lResult = (DOFUNC (&funcArgs, "lineOpen")); #if DBG LOG((TL_INFO, "Returning from lineOpenW, *lphLine = 0x%08lx", pt3Line->hLine)); LOG((TL_INFO, "Returning from lineOpenW, retcode = 0x%08lx", lResult)); #endif if ( 0 == lResult && bAddToHashTable) { gpLineHashTable->Insert( (ULONG_PTR)(pt3Line->hLine), (ULONG_PTR)pAddress, pTapiObj ); } gpLineHashTable->Unlock(); // // if an address line handle was created, but the call failed, remove the // entry from the handle table // if ( (0 != lResult) && (0 != pt3Line->dwAddressLineStructHandle)) { DeleteHandleTableEntry(pt3Line->dwAddressLineStructHandle); pt3Line->dwAddressLineStructHandle = 0; } return mapTAPIErrorCode( lResult ); } HRESULT LinePark( HCALL hCall, DWORD dwParkMode, LPCWSTR lpszDirAddress, LPVARSTRING * ppNonDirAddress ) { HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof (VARSTRING) + 500; LOG((TL_TRACE, "LinePark - enter")); if ( NULL != ppNonDirAddress ) { *ppNonDirAddress = (LPVARSTRING) ClientAlloc(dwSize); if (NULL == *ppNonDirAddress) { return E_OUTOFMEMORY; } (*ppNonDirAddress)->dwTotalSize = dwSize; } FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 6, lPark), { (ULONG_PTR) 0, // post process proc (ULONG_PTR) hCall, (ULONG_PTR) dwParkMode, (ULONG_PTR) TAPI_NO_DATA, //lpszDirAddress, (ULONG_PTR) 0, // pass ptr as Dword for post processing (ULONG_PTR) TAPI_NO_DATA, //lpNonDirAddress // pass ptr as lpGet_Xx for IsValPtr chk }, { Dword, Dword, Dword, Dword, // lpszW, Dword, Dword, // lpGet_Struct } }; DWORD hpNonDirAddress = 0; if (dwParkMode == LINEPARKMODE_DIRECTED) { funcArgs.ArgTypes[3] = lpszW; funcArgs.Args[3] = (ULONG_PTR) lpszDirAddress; } else if (dwParkMode == LINEPARKMODE_NONDIRECTED) { if ( NULL == ppNonDirAddress ) { return E_POINTER; } // // Set post process proc // funcArgs.Args[0] = GetFunctionIndex(lineDevSpecificPostProcess), hpNonDirAddress = CreateHandleTableEntry((ULONG_PTR)*ppNonDirAddress); funcArgs.ArgTypes[4] = Dword; funcArgs.Args[4] = hpNonDirAddress; funcArgs.ArgTypes[5] = lpGet_Struct; funcArgs.Args[5] = (ULONG_PTR) *ppNonDirAddress; } while (TRUE) { lResult = DOFUNC (&funcArgs, "LinePark"); if (lResult == LINEERR_STRUCTURETOOSMALL) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "LinePark failed - buffer too small")); dwSize = (*ppNonDirAddress)->dwNeededSize; // // no longer need the handle // DeleteHandleTableEntry(hpNonDirAddress); hpNonDirAddress = 0; ClientFree( *ppNonDirAddress ); *ppNonDirAddress = (LPVARSTRING) ClientAlloc( dwSize ); if (*ppNonDirAddress == NULL) { LOG((TL_ERROR, "LinePark - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { // // get a handle corresponding to the new *ppNonDirAddress and // use it to pass to DoFunc // hpNonDirAddress = CreateHandleTableEntry((ULONG_PTR)*ppNonDirAddress); if (0 == hpNonDirAddress) { LOG((TL_ERROR, "LinePark - repeat CreateHandleTableEntry failed")); hr = E_OUTOFMEMORY; ClientFree(*ppNonDirAddress); *ppNonDirAddress = NULL; break; } funcArgs.Args[4] = hpNonDirAddress; (*ppNonDirAddress)->dwTotalSize = dwSize; } } else if (lResult < 0) { if ( NULL != ppNonDirAddress ) { ClientFree( *ppNonDirAddress ); } hr = mapTAPIErrorCode( lResult ); break; } else { hr = lResult; break; } } // end while(TRUE) // // if we failed, remove the handle table entry because it will not be cleared by the callback // if (FAILED(hr) && (0 != hpNonDirAddress)) { DeleteHandleTableEntry(hpNonDirAddress); hpNonDirAddress = 0; } LOG((TL_TRACE, hr, "LinePark - exit")); return hr; } HRESULT LinePickup( HLINE hLine, DWORD dwAddressID, HCALL *phCall, LPCWSTR lpszDestAddress, LPCWSTR lpszGroupID ) { DWORD hpCallHandle = CreateHandleTableEntry((ULONG_PTR)phCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 6, lPickup), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, hpCallHandle, (ULONG_PTR) lpszDestAddress, (ULONG_PTR) lpszGroupID }, { Dword, Dword, Dword, Dword, lpszW, lpszW } }; if (!lpszDestAddress) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[4] = Dword; funcArgs.Args[4] = TAPI_NO_DATA; } if (!lpszGroupID) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[5] = Dword; funcArgs.Args[5] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "linePickup") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpCallHandle); hpCallHandle = 0; } return hr; } HRESULT LinePrepareAddToConference( HCALL hConfCall, HCALL * phConsultCall, LPLINECALLPARAMS const lpCallParams ) { DWORD hpConsultCallHandle = CreateHandleTableEntry((ULONG_PTR)phConsultCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lPrepareAddToConference), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) hConfCall, hpConsultCallHandle, (ULONG_PTR) lpCallParams, (ULONG_PTR) 0xffffffff // dwAsciiCallParamsCodePage }, { Dword, Dword, Dword, lpSet_Struct, Dword } }; if (!lpCallParams) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[3] = Dword; funcArgs.Args[3] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "LinePrepareAddToConference") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpConsultCallHandle); } return hr; } LONG WINAPI lineProxyMessage( HLINE hLine, HCALL hCall, DWORD dwMsg, DWORD Param1, DWORD Param2, DWORD Param3 ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, lProxyMessage), { (ULONG_PTR) hLine, (ULONG_PTR) hCall, dwMsg, Param1, Param2, Param3 }, { Dword, Dword, Dword, Dword, Dword, Dword, } }; return (DOFUNC (&funcArgs, "lineProxyMessage")); } LONG WINAPI lineProxyResponse( HLINE hLine, LPLINEPROXYREQUEST lpProxyRequest, DWORD dwResult ) { LONG lResult = 0; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lProxyResponse), { (ULONG_PTR) hLine, (ULONG_PTR) 0, (ULONG_PTR) lpProxyRequest, (ULONG_PTR) dwResult }, { Dword, Dword, lpSet_Struct, Dword } }; PPROXYREQUESTHEADER pProxyRequestHeader; // // The following is not the most thorough checking, but it's close // enough that a client app won't get a totally unexpected value // back // if (dwResult != 0 && (dwResult < LINEERR_ALLOCATED || dwResult > LINEERR_DIALVOICEDETECT)) { return LINEERR_INVALPARAM; } // // Backtrack a little bit to get the pointer to what ought to be // the proxy header, and then make sure we're dealing with a valid // proxy request // pProxyRequestHeader = (PPROXYREQUESTHEADER) (((LPBYTE) lpProxyRequest) - sizeof (PROXYREQUESTHEADER)); __try { // // Make sure we've a valid pProxyRequestHeader, then invalidate // the key so subsequent attempts to call lineProxyResponse with // the same lpProxyRequest fail // // if ((DWORD) pProxyRequestHeader & 0x7 || if(pProxyRequestHeader->dwKey != TPROXYREQUESTHEADER_KEY) { lResult = LINEERR_INVALPOINTER; } pProxyRequestHeader->dwKey = 0xefefefef; funcArgs.Args[1] = pProxyRequestHeader->dwInstance; // // See if this is one of the requests that don't require // any data to get passed back & reset the appropriate // params if so // switch (lpProxyRequest->dwRequestType) { case LINEPROXYREQUEST_SETAGENTGROUP: case LINEPROXYREQUEST_SETAGENTSTATE: case LINEPROXYREQUEST_SETAGENTACTIVITY: case LINEPROXYREQUEST_SETAGENTMEASUREMENTPERIOD: case LINEPROXYREQUEST_SETAGENTSESSIONSTATE: case LINEPROXYREQUEST_SETQUEUEMEASUREMENTPERIOD: case LINEPROXYREQUEST_SETAGENTSTATEEX: funcArgs.Args[2] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; break; } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { lResult = LINEERR_INVALPOINTER; } if (lResult == 0) { lResult = DOFUNC (&funcArgs, "lineProxyResponse"); // // If we've gotten this far we want to free the buffer // unconditionally // ClientFree (pProxyRequestHeader); } return lResult; } LONG WINAPI lineRedirectW( HCALL hCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lRedirect), { (ULONG_PTR) hCall, (ULONG_PTR) lpszDestAddress, dwCountryCode }, { Dword, lpszW, Dword } }; return (DOFUNC (&funcArgs, "lineRedirect")); } HRESULT LineRegisterRequestRecipient( HLINEAPP hLineApp, DWORD dwRegistrationInstance, DWORD dwRequestMode, #ifdef NEWREQUEST DWORD dwAddressTypes, #endif DWORD bEnable ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lRegisterRequestRecipient), { (ULONG_PTR) hLineApp, dwRegistrationInstance, dwRequestMode, bEnable }, { hXxxApp, Dword, Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineRegisterRequestRecipient")); } HRESULT LineReleaseUserUserInfo( HCALL hCall ) { if ( !hCall ) { return TAPI_E_INVALCALLSTATE; } FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 1, lReleaseUserUserInfo), { (ULONG_PTR) hCall }, { Dword, } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineReleaseUserUserInfo") ); } HRESULT LineRemoveFromConference( HCALL hCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 1, lRemoveFromConference), { (ULONG_PTR) hCall }, { Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "LineRemoveFromConference") ); } LONG WINAPI lineRemoveProvider( DWORD dwPermanentProviderID, HWND hwndOwner ) { return (lineXxxProvider( gszTUISPI_providerRemove, // func name NULL, // lpszProviderFilename hwndOwner, // hwndOwner dwPermanentProviderID, // dwPermProviderID NULL // lpdwPermProviderID )); } LONG WINAPI lineSecureCall( HCALL hCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 1, lSecureCall), { (ULONG_PTR) hCall }, { Dword } }; return (DOFUNC (&funcArgs, "lineSecureCall")); } HRESULT LineSendUserUserInfo( HCALL hCall, LPCSTR lpsUserUserInfo, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSendUserUserInfo), { (ULONG_PTR) hCall, (ULONG_PTR) lpsUserUserInfo, dwSize }, { Dword, lpSet_SizeToFollow, Size } }; if (!lpsUserUserInfo) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSendUserUserInfo") ); } LONG WINAPI lineSetAgentActivity( HLINE hLine, DWORD dwAddressID, DWORD dwActivityID ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetAgentActivity), { (ULONG_PTR) hLine, dwAddressID, dwActivityID }, { Dword, Dword, Dword } }; return (DOFUNC (&funcArgs, "lineSetAgentActivity")); } LONG WINAPI lineSetAgentGroup( HLINE hLine, DWORD dwAddressID, LPLINEAGENTGROUPLIST lpAgentGroupList ) { static LINEAGENTGROUPLIST EmptyGroupList = { sizeof (LINEAGENTGROUPLIST), // dwTotalSize sizeof (LINEAGENTGROUPLIST), // dwNeededSize sizeof (LINEAGENTGROUPLIST), // dwUsedSize 0, // dwNumEntries 0, // dwListSize 0 // dwListOffset }; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetAgentGroup), { (ULONG_PTR) hLine, (ULONG_PTR) dwAddressID, (ULONG_PTR) lpAgentGroupList }, { Dword, Dword, lpSet_Struct } }; if (!lpAgentGroupList) { funcArgs.Args[2] = (ULONG_PTR) &EmptyGroupList; } return (DOFUNC (&funcArgs, "lineSetAgentGroup")); } LONG WINAPI lineSetAgentState( HLINE hLine, DWORD dwAddressID, DWORD dwAgentState, DWORD dwNextAgentState ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 4, lSetAgentState), { (ULONG_PTR) hLine, dwAddressID, dwAgentState, dwNextAgentState }, { Dword, Dword, Dword, Dword } }; return (DOFUNC (&funcArgs, "lineSetAgentState")); } LONG WINAPI lineSetAgentStateEx( HLINE hLine, HAGENT hAgent, DWORD dwAgentState, DWORD dwNextAgentState ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 4, lSetAgentStateEx), { (ULONG_PTR) hLine, (ULONG_PTR) hAgent, dwAgentState, dwNextAgentState }, { Dword, Dword, Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetAgentStateEx")); } HRESULT LineSetAppPriority( LPCWSTR lpszAppName, DWORD dwMediaMode, DWORD dwRequestMode, DWORD dwPriority ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lSetAppPriority), { (ULONG_PTR) lpszAppName, dwMediaMode, (ULONG_PTR) TAPI_NO_DATA, // (ULONG_PTR) lpExtensionID, 0, // (ULONG_PTR) sizeof(LINEEXTENSIONID), dwRequestMode, (ULONG_PTR) TAPI_NO_DATA, // (ULONG_PTR) lpszExtensionName, dwPriority }, { lpszW, Dword, Dword, // lpSet_SizeToFollow, Dword, // Size, Dword, Dword, // lpsz, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetAppPriority")); } HRESULT LineSetAppSpecific( HCALL hCall, DWORD dwAppSpecific ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lSetAppSpecific), { (ULONG_PTR) hCall, dwAppSpecific }, { Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetAppSpecific")); } HRESULT LineSetCallData( HCALL hCall, LPVOID lpCallData, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetCallData), { (ULONG_PTR) hCall, (ULONG_PTR) lpCallData, dwSize }, { Dword, lpSet_SizeToFollow, Size } }; if (dwSize == 0) { funcArgs.Args[1] = TAPI_NO_DATA; funcArgs.ArgTypes[1] = funcArgs.ArgTypes[2] = Dword; } return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetCallData")); } HRESULT WINAPI LineSetCallHubTracking( T3LINE * pt3Line, LINECALLHUBTRACKINGINFO * plchti ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lSetCallHubTracking), { (ULONG_PTR) (pt3Line->hLine), (ULONG_PTR) plchti }, { Dword, lpSet_Struct } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetCallHubTracking") ); } HRESULT LineSetCallParams( HCALL hCall, DWORD dwBearerMode, DWORD dwMinRate, DWORD dwMaxRate, LPLINEDIALPARAMS const lpDialParams ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 6, lSetCallParams), { (ULONG_PTR) hCall, dwBearerMode, dwMinRate, dwMaxRate, (ULONG_PTR) lpDialParams, sizeof(LINEDIALPARAMS) }, { Dword, Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; if (!lpDialParams) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[4] = Dword; funcArgs.Args[4] = TAPI_NO_DATA; funcArgs.ArgTypes[5] = Dword; } return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetCallParams") ); } LONG WINAPI lineSetCallPrivilege( HCALL hCall, DWORD dwCallPrivilege ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lSetCallPrivilege), { (ULONG_PTR) hCall, dwCallPrivilege }, { Dword, Dword } }; return (DOFUNC (&funcArgs, "lineSetCallPrivilege")); } HRESULT LineSetCallQualityOfService( HCALL hCall, QOS_SERVICE_LEVEL ServiceLevel, DWORD dwMediaType ) { LINECALLQOSINFO * plqi; DWORD dwSize; HRESULT hr; dwSize = sizeof(LINECALLQOSINFO); plqi = (LINECALLQOSINFO *)ClientAlloc( dwSize ); if ( NULL == plqi ) { return E_OUTOFMEMORY; } plqi->dwKey = LINEQOSSTRUCT_KEY; plqi->dwTotalSize = dwSize; if ( 0 != ServiceLevel ) { plqi->dwQOSRequestType = LINEQOSREQUESTTYPE_SERVICELEVEL; plqi->SetQOSServiceLevel.dwNumServiceLevelEntries = 1; plqi->SetQOSServiceLevel.LineQOSServiceLevel[0].dwMediaMode = dwMediaType; plqi->SetQOSServiceLevel.LineQOSServiceLevel[0].dwQOSServiceLevel = ServiceLevel; } FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lSetCallQualityOfService), { (ULONG_PTR) hCall, (ULONG_PTR) TAPI_NO_DATA, (ULONG_PTR) 0, (ULONG_PTR) plqi, (ULONG_PTR) dwSize }, { Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetCallQualityOfService") ); ClientFree( plqi ); return hr; } HRESULT LineSetCallTreatment( HCALL hCall, DWORD dwTreatment ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 2, lSetCallTreatment), { (ULONG_PTR) hCall, (ULONG_PTR) dwTreatment }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetCallTreatment") ); } LONG WINAPI lineSetDevConfigW( DWORD dwDeviceID, LPVOID const lpDeviceConfig, DWORD dwSize, LPCWSTR lpszDeviceClass ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 4, lSetDevConfig), { dwDeviceID, (ULONG_PTR) lpDeviceConfig, dwSize, (ULONG_PTR) lpszDeviceClass }, { Dword, lpSet_SizeToFollow, Size, lpszW } }; return (DOFUNC (&funcArgs, "lineSetDevConfig")); } HRESULT LineSetLineDevStatus( T3LINE *pt3Line, DWORD dwStatusToChange, DWORD fStatus ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetLineDevStatus), { (ULONG_PTR) pt3Line->hLine, dwStatusToChange, fStatus }, { Dword, Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetLineDevStatus") ); } LONG WINAPI lineSetMediaControl( HLINE hLine, DWORD dwAddressID, HCALL hCall, DWORD dwSelect, LPLINEMEDIACONTROLDIGIT const lpDigitList, DWORD dwDigitNumEntries, LPLINEMEDIACONTROLMEDIA const lpMediaList, DWORD dwMediaNumEntries, LPLINEMEDIACONTROLTONE const lpToneList, DWORD dwToneNumEntries, LPLINEMEDIACONTROLCALLSTATE const lpCallStateList, DWORD dwCallStateNumEntries ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 12, lSetMediaControl), { (ULONG_PTR) hLine, dwAddressID, (ULONG_PTR) hCall, dwSelect, TAPI_NO_DATA, dwDigitNumEntries * sizeof(LINEMEDIACONTROLDIGIT), TAPI_NO_DATA, dwMediaNumEntries * sizeof(LINEMEDIACONTROLMEDIA), TAPI_NO_DATA, dwToneNumEntries * sizeof(LINEMEDIACONTROLTONE), TAPI_NO_DATA, dwCallStateNumEntries * sizeof(LINEMEDIACONTROLCALLSTATE) }, { Dword, Dword, Dword, Dword, Dword, Dword, Dword, Dword, Dword, Dword, Dword, Dword } }; // // If lpXxxList is non-NULL reset Arg & ArgType, and check // to see that dwXxxNumEntries is not unacceptably large // if (lpDigitList) { if (dwDigitNumEntries > (0x1000000 / sizeof (LINEMEDIACONTROLDIGIT))) { return LINEERR_INVALPOINTER; } funcArgs.ArgTypes[4] = lpSet_SizeToFollow; funcArgs.Args[4] = (ULONG_PTR) lpDigitList; funcArgs.ArgTypes[5] = Size; } if (lpMediaList) { if (dwMediaNumEntries > (0x1000000 / sizeof (LINEMEDIACONTROLMEDIA))) { return LINEERR_INVALPOINTER; } funcArgs.ArgTypes[6] = lpSet_SizeToFollow; funcArgs.Args[6] = (ULONG_PTR) lpMediaList; funcArgs.ArgTypes[7] = Size; } if (lpToneList) { if (dwToneNumEntries > (0x1000000 / sizeof (LINEMEDIACONTROLTONE))) { return LINEERR_INVALPOINTER; } funcArgs.ArgTypes[8] = lpSet_SizeToFollow; funcArgs.Args[8] = (ULONG_PTR) lpToneList; funcArgs.ArgTypes[9] = Size; } if (lpCallStateList) { if (dwCallStateNumEntries > (0x1000000 / sizeof (LINEMEDIACONTROLCALLSTATE))) { return LINEERR_INVALPOINTER; } funcArgs.ArgTypes[10] = lpSet_SizeToFollow; funcArgs.Args[10] = (ULONG_PTR) lpCallStateList; funcArgs.ArgTypes[11] = Size; } return (DOFUNC (&funcArgs, "lineSetMediaControl")); } HRESULT LineSetMediaMode( HCALL hCall, DWORD dwMediaModes ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lSetMediaMode), { (ULONG_PTR) hCall, dwMediaModes }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetMediaMode") ); } LONG WINAPI lineSetNumRings( HLINE hLine, DWORD dwAddressID, DWORD dwNumRings ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lSetNumRings), { (ULONG_PTR) hLine, dwAddressID, dwNumRings }, { Dword, Dword, Dword } }; return (DOFUNC (&funcArgs, "lineSetNumRings")); } HRESULT LineSetStatusMessages( T3LINE * pt3Line, DWORD dwLineStates, DWORD dwAddressStates ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, lSetStatusMessages), { (ULONG_PTR) pt3Line->hLine, dwLineStates, dwAddressStates }, { Dword, Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetStatusMessages") ); } LONG WINAPI lineSetTerminal( HLINE hLine, DWORD dwAddressID, HCALL hCall, DWORD dwSelect, DWORD dwTerminalModes, DWORD dwTerminalID, DWORD bEnable ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 7, lSetTerminal), { (ULONG_PTR) hLine, dwAddressID, (ULONG_PTR) hCall, dwSelect, dwTerminalModes, dwTerminalID, bEnable }, { Dword, Dword, Dword, Dword, Dword, Dword, Dword } }; return (DOFUNC (&funcArgs, "lineSetTerminal")); } void PASCAL lineSetupConferencePostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "lineSetupConfPostProcess: enter")); LOG((TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param2 == 0) { HCALL hConfCall = (HCALL) pMsg->Param3, hConsultCall = (HCALL) (*(&pMsg->Param4 + 1)); LPHCALL lphConfCall = (LPHCALL) GetHandleTableEntry(pMsg->Param4); LPHCALL lphConsultCall = (LPHCALL) GetHandleTableEntry(*(&pMsg->Param4 + 2)); LOG((TL_INFO, "lineSetupConfPostProcess: hConfCall [%lx] hConsultCall [%lx] lphConfCall [%p] lphConsultCall [%p]", hConfCall, hConsultCall, lphConfCall, lphConsultCall)); __try { { *lphConfCall = NULL; *lphConsultCall = NULL; *lphConfCall = hConfCall; *lphConsultCall = hConsultCall; } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { pMsg->Param2 = LINEERR_INVALPOINTER; LOG((TL_WARN, "lineSetupConfPostProcess: failed to set memory at %p or at %p", lphConfCall, lphConsultCall)); // // tapisrv has allocated call handles for us. deallocate them. // LineDeallocateCall(hConfCall); LineDeallocateCall(hConsultCall); } } } HRESULT LineSetupConference( HCALL hCall, T3LINE * pt3Line, HCALL * phConfCall, HCALL * phConsultCall, DWORD dwNumParties, LPLINECALLPARAMS const lpCallParams ) { if ( phConfCall == phConsultCall ) { return E_POINTER; } DWORD hpConfCallHandle = CreateHandleTableEntry((ULONG_PTR) phConfCall); DWORD hpConsultCallHandle = CreateHandleTableEntry((ULONG_PTR) phConsultCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 8, lSetupConference), { GetFunctionIndex(lineSetupConferencePostProcess), (ULONG_PTR) hCall, (ULONG_PTR) pt3Line->hLine, hpConfCallHandle, hpConsultCallHandle, (ULONG_PTR) dwNumParties, (ULONG_PTR) lpCallParams, (ULONG_PTR) 0xffffffff // dwAsciiCallParamsCodePage }, { Dword, Dword, Dword, Dword, Dword, Dword, lpSet_Struct, Dword } }; if (!lpCallParams) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[6] = Dword; funcArgs.Args[6] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "LineSetupConference") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpConfCallHandle); DeleteHandleTableEntry(hpConsultCallHandle); } return hr; } HRESULT LineSetupTransfer( HCALL hCall, HCALL *phConsultCall, LPLINECALLPARAMS const lpCallParams ) { DWORD hpConsultCallHandle = CreateHandleTableEntry((ULONG_PTR)phConsultCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lSetupTransfer), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) hCall, hpConsultCallHandle, (ULONG_PTR) lpCallParams, 0xffffffff // dwAsciiCallParamsCodePage }, { Dword, Dword, Dword, lpSet_Struct, Dword } }; if (!lpCallParams) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[3] = Dword; funcArgs.Args[3] = TAPI_NO_DATA; } HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSetupTransferW") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpConsultCallHandle); hpConsultCallHandle = 0; } return hr; } HRESULT LineSwapHold( HCALL hActiveCall, HCALL hHeldCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 2, lSwapHold), { (ULONG_PTR) hActiveCall, (ULONG_PTR) hHeldCall }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineSwapHold") ); } LONG WINAPI lineUncompleteCall( HLINE hLine, DWORD dwCompletionID ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 2, lUncompleteCall), { (ULONG_PTR) hLine, dwCompletionID }, { Dword, Dword } }; return (DOFUNC (&funcArgs, "lineUncompleteCall")); } HRESULT LineUnhold( HCALL hCall ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 1, lUnhold), { (ULONG_PTR) hCall }, { Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineUnhold") ); } HRESULT LineUnpark( HLINE hLine, DWORD dwAddressID, HCALL *phCall, LPCWSTR lpszDestAddress ) { DWORD hpCallHandle = CreateHandleTableEntry((ULONG_PTR)phCall); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lUnpark), { GetFunctionIndex(lineMakeCallPostProcess), (ULONG_PTR) hLine, dwAddressID, hpCallHandle, (ULONG_PTR) lpszDestAddress }, { Dword, Dword, Dword, Dword, lpszW } }; HRESULT hr = mapTAPIErrorCode( DOFUNC (&funcArgs, "LineUnpark") ); if (FAILED(hr)) { DeleteHandleTableEntry(hpCallHandle); } return hr; } // // ------------------------------- phoneXxx ----------------------------------- // /////////////////////////////////////////////////////////////////////////////// // // PhoneClose // // // Closes the phone specified by hPhone, the mode of hash table clean up is // described by bCleanHashTableOnFailure // // Arguments: // // HPHONE hPhone -- handle of the phone to close // // BOOL bCleanHashTableOnFailure -- boolean that specifies how phone // hash table should be cleaned: // // FALSE -- remove hash table entry only if the call succeeds. The caller // function will then have the opportunity to perform transaction-like // error handling -- it could recover the state from before the function // was called, so it could return an error which would mean that the state // remained unchanged // // TRUE -- clean table even if tapisrv call fails. The caller will not be // able to recover the original state in case of failure. this is ok for // the functions that do not provide full error handling for PhoneClose // HRESULT PhoneClose( HPHONE hPhone, BOOL bCleanHashTableOnFailure // = TRUE ) { LOG((TL_INFO, "PhoneClose - enter. hPhone[%p] CleanOnError[%d]", hPhone, bCleanHashTableOnFailure)); LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 1, pClose), { (ULONG_PTR) hPhone }, { Dword } }; gpPhoneHashTable->Lock(); lResult = (DOFUNC (&funcArgs, "phoneClose")); // // clean hash table entry if needed // if ( (0 == lResult) || bCleanHashTableOnFailure ) { LOG((TL_INFO, "PhoneClose - removing phone's hash table entry")); gpPhoneHashTable->Remove( (ULONG_PTR)(hPhone) ); } gpPhoneHashTable->Unlock(); // // get hr error code // HRESULT hr = mapTAPIErrorCode( lResult ); LOG((TL_INFO, "PhoneClose - exit. hr = %lx", hr)); return hr; } LONG WINAPI phoneConfigDialogW( DWORD dwDeviceID, HWND hwndOwner, LPCWSTR lpszDeviceClass ) { LONG lResult; HANDLE hDll; TUISPIPROC pfnTUISPI_phoneConfigDialog; if (lpszDeviceClass && IsBadStringPtrW (lpszDeviceClass, (UINT) -1)) { return PHONEERR_INVALPOINTER; } if ((lResult = LoadUIDll( hwndOwner, dwDeviceID, TUISPIDLL_OBJECT_PHONEID, &hDll, gszTUISPI_phoneConfigDialog, &pfnTUISPI_phoneConfigDialog )) == 0) { LOG((TL_INFO, "Calling TUISPI_phoneConfigDialog...")); lResult = ((TUIPHONECONFIGPROC)(*pfnTUISPI_phoneConfigDialog))( TUISPIDLLCallback, dwDeviceID, (HWND)hwndOwner, (char *)lpszDeviceClass ); #if DBG { char szResult[32]; LOG((TL_INFO, "TUISPI_phoneConfigDialog: result = %s", MapResultCodeToText (lResult, szResult) )); } #endif FreeLibrary ((HINSTANCE)hDll); } return lResult; } void PASCAL phoneDevSpecificPostProcess( PASYNCEVENTMSG pMsg ) { LOG((TL_TRACE, "phoneDevSpecificPostProcess: enter")); LOG((TL_INFO, "\t\tdwP1=x%lx, dwP2=x%lx, dwP3=x%lx, dwP4=x%lx", pMsg->Param1, pMsg->Param2, pMsg->Param3, pMsg->Param4 )); if (pMsg->Param2 == 0) { DWORD dwSize = pMsg->Param4; LPBYTE pParams = (LPBYTE) GetHandleTableEntry(pMsg->Param3); __try { { CopyMemory (pParams, (LPBYTE) (pMsg + 1), dwSize); } } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { pMsg->Param2 = PHONEERR_INVALPOINTER; LOG((TL_WARN, "phoneDevSpecificPostProcess: failed to copy %ld(10) bytes, %p -> %p." "PHONEERR_INVALPOINTER", dwSize, (LPBYTE) (pMsg + 1), pParams)); } } } HRESULT WINAPI phoneDevSpecific( HPHONE hPhone, LPVOID lpParams, DWORD dwSize ) { DWORD hpParams = CreateHandleTableEntry((ULONG_PTR)lpParams); FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 5, pDevSpecific), { GetFunctionIndex(phoneDevSpecificPostProcess), (ULONG_PTR) hPhone, hpParams, // passed as Dword for post processing (ULONG_PTR) lpParams, // passed as LpSet_Xxx for IsValidPtr chk dwSize }, { Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; LONG lResult = DOFUNC (&funcArgs, "phoneDevSpecific"); // // remove the handle table entry if failed. otherwise the LINE_REPLY will // do this. // HRESULT hr = E_FAIL; if (lResult <= 0) { DeleteHandleTableEntry(hpParams); hpParams = 0; hr = mapTAPIErrorCode(lResult); } else { // // block to see if the operation succeeds // hr = WaitForPhoneReply(lResult); } return hr; } HRESULT PhoneSetStatusMessages( T3PHONE * pt3Phone, DWORD dwPhoneStates, DWORD dwButtonModes, DWORD dwButtonStates ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 4, pSetStatusMessages), { (ULONG_PTR) pt3Phone->hPhone, dwPhoneStates, dwButtonModes, dwButtonStates }, { Dword, Dword, Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "phoneSetStatusMessages") ); } HRESULT PhoneGetButtonInfo( HPHONE hPhone, DWORD dwButtonLampID, LPPHONEBUTTONINFO * ppButtonInfo ) { LONG lResult; *ppButtonInfo = (LPPHONEBUTTONINFO) ClientAlloc( sizeof(PHONEBUTTONINFO) + 500 ); if (NULL == *ppButtonInfo) { return E_OUTOFMEMORY; } (*ppButtonInfo)->dwTotalSize = sizeof(PHONEBUTTONINFO) + 500; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetButtonInfo), { (ULONG_PTR) hPhone, dwButtonLampID, (ULONG_PTR) *ppButtonInfo }, { Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "phoneGetButtonInfo"); if ((0 == lResult) && ((*ppButtonInfo)->dwNeededSize > (*ppButtonInfo)->dwTotalSize)) { DWORD dwSize = (*ppButtonInfo)->dwNeededSize; ClientFree( *ppButtonInfo ); *ppButtonInfo = (LPPHONEBUTTONINFO) ClientAlloc( dwSize ); if (NULL == *ppButtonInfo) { return E_OUTOFMEMORY; } (*ppButtonInfo)->dwTotalSize = dwSize; funcArgs.Args[2] = (ULONG_PTR)*ppButtonInfo; } else { break; } } return mapTAPIErrorCode(lResult); } LONG WINAPI phoneGetData( HPHONE hPhone, DWORD dwDataID, LPVOID lpData, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 4, pGetData), { (ULONG_PTR) hPhone, dwDataID, (ULONG_PTR) lpData, dwSize }, { Dword, Dword, lpGet_SizeToFollow, Size } }; return (DOFUNC (&funcArgs, "phoneGetData")); } HRESULT PhoneGetDevCapsWithAlloc( HPHONEAPP hPhoneApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPPHONECAPS * ppPhoneCaps ) { LONG lResult; *ppPhoneCaps = (LPPHONECAPS) ClientAlloc( sizeof(PHONECAPS) + 500 ); if (NULL == *ppPhoneCaps) { return E_OUTOFMEMORY; } (*ppPhoneCaps)->dwTotalSize = sizeof(PHONECAPS) + 500; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 5, pGetDevCaps), { (ULONG_PTR) hPhoneApp, dwDeviceID, dwAPIVersion, 0, (ULONG_PTR) *ppPhoneCaps }, { hXxxApp, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "phoneGetDevCaps"); if ((0 == lResult) && ((*ppPhoneCaps)->dwNeededSize > (*ppPhoneCaps)->dwTotalSize)) { DWORD dwSize = (*ppPhoneCaps)->dwNeededSize; ClientFree( *ppPhoneCaps ); *ppPhoneCaps = (LPPHONECAPS) ClientAlloc( dwSize ); if (NULL == *ppPhoneCaps) { return E_OUTOFMEMORY; } (*ppPhoneCaps)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppPhoneCaps; } else { break; } } return mapTAPIErrorCode(lResult); } HRESULT PhoneGetDevCaps( HPHONEAPP hPhoneApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPPHONECAPS * ppPhoneCaps ) { LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 5, pGetDevCaps), { (ULONG_PTR) hPhoneApp, dwDeviceID, dwAPIVersion, 0, (ULONG_PTR) *ppPhoneCaps }, { hXxxApp, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "phoneGetDevCaps"); if ((0 == lResult) && ((*ppPhoneCaps)->dwNeededSize > (*ppPhoneCaps)->dwTotalSize)) { DWORD dwSize = (*ppPhoneCaps)->dwNeededSize; ClientFree( *ppPhoneCaps ); *ppPhoneCaps = (LPPHONECAPS) ClientAlloc( dwSize ); if (NULL == *ppPhoneCaps) { return E_OUTOFMEMORY; } (*ppPhoneCaps)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppPhoneCaps; } else { break; } } return mapTAPIErrorCode(lResult); } HRESULT PhoneGetDisplay( HPHONE hPhone, LPVARSTRING * ppDisplay ) { LONG lResult; *ppDisplay = (LPVARSTRING) ClientAlloc( sizeof (VARSTRING) + 500 ); if (NULL == *ppDisplay) { return E_OUTOFMEMORY; } (*ppDisplay)->dwTotalSize = sizeof (VARSTRING) + 500; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 2, pGetDisplay), { (ULONG_PTR) hPhone, (ULONG_PTR) *ppDisplay }, { Dword, lpGet_Struct } }; LOG((TL_TRACE, "PhoneGetDisplay - enter")); LOG((TL_INFO, " hPhone ---------->%lx", hPhone)); LOG((TL_INFO, " ppDisplay ------->%p", ppDisplay)); while ( TRUE ) { lResult = DOFUNC (&funcArgs, "phoneGetDisplay"); if ((lResult == 0) && ((*ppDisplay)->dwNeededSize > (*ppDisplay)->dwTotalSize)) { DWORD dwSize = (*ppDisplay)->dwNeededSize; ClientFree(*ppDisplay); *ppDisplay = (LPVARSTRING)ClientAlloc(dwSize); if (NULL == *ppDisplay) { LOG((TL_ERROR, "PhoneGetDisplay exit - return E_OUTOFMEMORY")); return E_OUTOFMEMORY; } (*ppDisplay)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppDisplay; } else { break; } } LOG((TL_TRACE, "PhoneGetDisplay exit")); return mapTAPIErrorCode( lResult ); } HRESULT PhoneGetGain( HPHONE hPhone, DWORD dwHookSwitchDev, LPDWORD lpdwGain ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetGain), { (ULONG_PTR) hPhone, dwHookSwitchDev, (ULONG_PTR) lpdwGain }, { Dword, Dword, lpDword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "phoneGetGain")); } HRESULT PhoneGetHookSwitch( HPHONE hPhone, LPDWORD lpdwHookSwitchDevs ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 2, pGetHookSwitch), { (ULONG_PTR) hPhone, (ULONG_PTR) lpdwHookSwitchDevs }, { Dword, lpDword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "phoneGetHookSwitch")); } LONG WINAPI phoneGetIconW( DWORD dwDeviceID, LPCWSTR lpszDeviceClass, LPHICON lphIcon ) { HICON hIcon; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetIcon), { dwDeviceID, (ULONG_PTR) lpszDeviceClass, (ULONG_PTR) &hIcon }, { Dword, lpszW, lpDword } }; LONG lResult; if (IsBadDwordPtr ((LPDWORD) lphIcon)) { return PHONEERR_INVALPOINTER; } if (lpszDeviceClass == (LPCWSTR) NULL) { // // Reset Arg & ArgType so no inval ptr err, & TAPI_NO_DATA is indicated // funcArgs.ArgTypes[1] = Dword; funcArgs.Args[1] = TAPI_NO_DATA; } if ((lResult = DOFUNC (&funcArgs, "phoneGetIcon")) == 0) { *lphIcon = hIcon; } return lResult; } HRESULT PhoneGetID( HPHONE hPhone, LPVARSTRING * ppDeviceID, LPCWSTR lpszDeviceClass ) { LONG lResult; DWORD dwNumDevices; DWORD dwDeviceId1, dwDeviceId2; BOOL bWaveDevice = FALSE; *ppDeviceID = (LPVARSTRING) ClientAlloc( sizeof (VARSTRING) + 500 ); if (NULL == *ppDeviceID) { return E_OUTOFMEMORY; } (*ppDeviceID)->dwTotalSize = sizeof (VARSTRING) + 500; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetID), { (ULONG_PTR) hPhone, (ULONG_PTR) *ppDeviceID, (ULONG_PTR) lpszDeviceClass }, { Dword, lpGet_Struct, lpszW } }; LOG((TL_TRACE, "PhoneGetID - enter")); LOG((TL_INFO, " hPhone ---------->%lx", hPhone)); LOG((TL_INFO, " ppDeviceID ------>%p", ppDeviceID)); LOG((TL_INFO, " lpszDeviceClass ->%p", lpszDeviceClass)); // // If the request is for a wave device, call PGetIDEx. // This will return a device string ID which is guaranteed to be unique across // all processes. // Then we will convert the string ID to the correct device ID in the client process context. // if (!_wcsicmp(lpszDeviceClass, L"wave/in") || !_wcsicmp(lpszDeviceClass, L"wave/out") || !_wcsicmp(lpszDeviceClass, L"midi/in") || !_wcsicmp(lpszDeviceClass, L"midi/out") || !_wcsicmp(lpszDeviceClass, L"wave/in/out") ) { bWaveDevice = TRUE; dwNumDevices = _wcsicmp(lpszDeviceClass, L"wave/in/out") ? 1 : 2; funcArgs.Flags = MAKELONG (PHONE_FUNC | SYNC | 3, pGetIDEx); } while ( TRUE ) { lResult = DOFUNC (&funcArgs, bWaveDevice ? "phoneGetIDEx" : "phoneGetID"); if ((lResult == 0) && ((*ppDeviceID)->dwNeededSize > (*ppDeviceID)->dwTotalSize)) { DWORD dwSize = (*ppDeviceID)->dwNeededSize; ClientFree(*ppDeviceID); *ppDeviceID = (LPVARSTRING)ClientAlloc(dwSize); if (NULL == *ppDeviceID) { LOG((TL_ERROR, "PhoneGetID exit - return LINEERR_NOMEM")); return E_OUTOFMEMORY; } (*ppDeviceID)->dwTotalSize = dwSize; funcArgs.Args[1] = (ULONG_PTR)*ppDeviceID; } else { break; } } if (bWaveDevice && lResult == 0) { // // We got the string ID(s), now we need to convert them to numeric device ID(s) // BOOL bConversionOk; if ( dwNumDevices == 1 ) { bConversionOk = WaveStringIdToDeviceId ( (LPWSTR)((LPBYTE)(*ppDeviceID) + (*ppDeviceID)->dwStringOffset), lpszDeviceClass, &dwDeviceId1); } else { _ASSERTE(dwNumDevices == 2); // // for "wave/in/out", we get back two devices from tapisrv -> convert both // LPWSTR szString1 = (LPWSTR)((LPBYTE)(*ppDeviceID) + (*ppDeviceID)->dwStringOffset); // first convert the wave/in device bConversionOk = WaveStringIdToDeviceId ( szString1, L"wave/in", &dwDeviceId1); // next convert the wave/out device bConversionOk = bConversionOk && WaveStringIdToDeviceId ( szString1 + wcslen(szString1), L"wave/out", &dwDeviceId2); } if (!bConversionOk) { LOG((TL_ERROR, "PhoneGetID - WaveStringIdToDeviceId failed")); ClientFree(*ppDeviceID); *ppDeviceID = NULL; lResult = LINEERR_OPERATIONFAILED; } else { // // conversion succeeded, now fill the VARSTRING to be returned to the caller // (*ppDeviceID)->dwNeededSize = (*ppDeviceID)->dwUsedSize = sizeof(VARSTRING) + sizeof(DWORD) * dwNumDevices; (*ppDeviceID)->dwStringFormat = STRINGFORMAT_BINARY; (*ppDeviceID)->dwStringSize = sizeof(DWORD) * dwNumDevices; (*ppDeviceID)->dwStringOffset = sizeof(VARSTRING); *(DWORD *)((*ppDeviceID) + 1) = dwDeviceId1; if (dwNumDevices == 2) *((DWORD *)((*ppDeviceID) + 1) + 1) = dwDeviceId2; } } LOG((TL_TRACE, "PhoneGetID exit - return %lx", lResult)); return mapTAPIErrorCode( lResult ); } HRESULT PhoneGetLamp( HPHONE hPhone, DWORD dwButtonLampID, LPDWORD lpdwLampMode ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetLamp), { (ULONG_PTR) hPhone, dwButtonLampID, (ULONG_PTR) lpdwLampMode }, { Dword, Dword, lpDword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "phoneGetLamp")); } HRESULT PhoneGetRing( HPHONE hPhone, LPDWORD lpdwRingMode, LPDWORD lpdwVolume ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetRing), { (ULONG_PTR) hPhone, (ULONG_PTR) lpdwRingMode, (ULONG_PTR) lpdwVolume }, { Dword, lpDword, lpDword } }; if (lpdwRingMode == lpdwVolume) { return E_POINTER; } return mapTAPIErrorCode(DOFUNC (&funcArgs, "phoneGetRing")); } HRESULT PhoneGetStatusWithAlloc( HPHONE hPhone, LPPHONESTATUS *ppPhoneStatus ) { LONG lResult; *ppPhoneStatus = (LPPHONESTATUS) ClientAlloc( sizeof(PHONESTATUS) + 500 ); if (NULL == *ppPhoneStatus) { return E_OUTOFMEMORY; } (*ppPhoneStatus)->dwTotalSize = sizeof(PHONESTATUS) + 500; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 2, pGetStatus), { (ULONG_PTR) hPhone, (ULONG_PTR) *ppPhoneStatus }, { Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "phoneGetStatus"); if ((0 == lResult) && ((*ppPhoneStatus)->dwNeededSize > (*ppPhoneStatus)->dwTotalSize)) { DWORD dwSize = (*ppPhoneStatus)->dwNeededSize; ClientFree( *ppPhoneStatus ); *ppPhoneStatus = (LPPHONESTATUS) ClientAlloc( dwSize ); if (NULL == *ppPhoneStatus) { return E_OUTOFMEMORY; } (*ppPhoneStatus)->dwTotalSize = dwSize; funcArgs.Args[4] = (ULONG_PTR)*ppPhoneStatus; } else { break; } } return mapTAPIErrorCode(lResult); } LONG WINAPI phoneGetStatusMessages( HPHONE hPhone, LPDWORD lpdwPhoneStates, LPDWORD lpdwButtonModes, LPDWORD lpdwButtonStates ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 4, pGetStatusMessages), { (ULONG_PTR) hPhone, (ULONG_PTR) lpdwPhoneStates, (ULONG_PTR) lpdwButtonModes, (ULONG_PTR) lpdwButtonStates }, { Dword, lpDword, lpDword, lpDword } }; if (lpdwPhoneStates == lpdwButtonModes || lpdwPhoneStates == lpdwButtonStates || lpdwButtonModes == lpdwButtonStates) { return PHONEERR_INVALPOINTER; } return (DOFUNC (&funcArgs, "phoneGetStatusMessages")); } HRESULT PhoneGetVolume( HPHONE hPhone, DWORD dwHookSwitchDev, LPDWORD lpdwVolume ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 3, pGetVolume), { (ULONG_PTR) hPhone, dwHookSwitchDev, (ULONG_PTR) lpdwVolume }, { Dword, Dword, lpDword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "phoneGetVolume")); } HRESULT PhoneNegotiateAPIVersion( HPHONEAPP hPhoneApp, DWORD dwDeviceID, LPDWORD lpdwAPIVersion ) { PHONEEXTENSIONID PED; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 7, pNegotiateAPIVersion), { (ULONG_PTR) hPhoneApp, dwDeviceID, TAPI_VERSION1_0, TAPI_VERSION_CURRENT, (ULONG_PTR) lpdwAPIVersion, (ULONG_PTR) &PED, (ULONG_PTR) sizeof(PHONEEXTENSIONID) }, { hXxxApp, Dword, Dword, Dword, lpDword, lpGet_SizeToFollow, Size } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "phoneNegotiateAPIVersion") ); } LONG WINAPI phoneNegotiateExtVersion( HPHONEAPP hPhoneApp, DWORD dwDeviceID, DWORD dwAPIVersion, DWORD dwExtLowVersion, DWORD dwExtHighVersion, LPDWORD lpdwExtVersion ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 6, pNegotiateExtVersion), { (ULONG_PTR) hPhoneApp, dwDeviceID, dwAPIVersion, dwExtLowVersion, dwExtHighVersion, (ULONG_PTR) lpdwExtVersion }, { hXxxApp, Dword, Dword, Dword, Dword, lpDword } }; return (DOFUNC (&funcArgs, "phoneNegotiateExtVersion")); } HRESULT PhoneOpen( HPHONEAPP hPhoneApp, DWORD dwDeviceID, T3PHONE * pt3Phone, DWORD dwAPIVersion, DWORD dwPrivilege ) { HRESULT hr; FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 8, pOpen), { (ULONG_PTR) hPhoneApp, dwDeviceID, (ULONG_PTR) &(pt3Phone->hPhone), dwAPIVersion, 0, 0, dwPrivilege, 0, // PHONEOPEN_PARAMS.hRemotePhone }, { hXxxApp, Dword, lpDword, Dword, Dword, Dword, Dword, Dword } }; gpPhoneHashTable->Lock(); hr = ( DOFUNC (&funcArgs, "phoneOpen") ); if ( 0 == hr ) { #ifdef USE_PHONEMSP gpPhoneHashTable->Insert( (ULONG_PTR)(pt3Phone->hPhone), (ULONG_PTR)(pt3Phone->pMSPCall) ); #else gpPhoneHashTable->Insert( (ULONG_PTR)(pt3Phone->hPhone), (ULONG_PTR)(pt3Phone->pPhone) ); #endif USE_PHONEMSP } gpPhoneHashTable->Unlock(); return mapTAPIErrorCode( hr ); } HRESULT PhoneSetButtonInfo( HPHONE hPhone, DWORD dwButtonLampID, LPPHONEBUTTONINFO const pButtonInfo ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetButtonInfo), { (ULONG_PTR) hPhone, dwButtonLampID, (ULONG_PTR) pButtonInfo }, { Dword, Dword, lpSet_Struct } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetButtonInfo"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } LONG WINAPI phoneSetData( HPHONE hPhone, DWORD dwDataID, LPVOID const lpData, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 4, pSetData), { (ULONG_PTR) hPhone, dwDataID, (ULONG_PTR) lpData, dwSize }, { Dword, Dword, lpSet_SizeToFollow, Size } }; return (DOFUNC (&funcArgs, "phoneSetData")); } HRESULT PhoneSetDisplay( HPHONE hPhone, DWORD dwRow, DWORD dwColumn, LPCSTR lpsDisplay, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 5, pSetDisplay), { (ULONG_PTR) hPhone, dwRow, dwColumn, (ULONG_PTR) lpsDisplay, dwSize }, { Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetDisplay"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } HRESULT PhoneSetGain( HPHONE hPhone, DWORD dwHookSwitchDev, DWORD dwGain ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetGain), { (ULONG_PTR) hPhone, dwHookSwitchDev, dwGain }, { Dword, Dword, Dword } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetGain"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } HRESULT PhoneSetHookSwitch( HPHONE hPhone, DWORD dwHookSwitchDevs, DWORD dwHookSwitchMode ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetHookSwitch), { (ULONG_PTR) hPhone, dwHookSwitchDevs, dwHookSwitchMode }, { Dword, Dword, Dword } }; if (!(dwHookSwitchDevs & AllHookSwitchDevs) || (dwHookSwitchDevs & (~AllHookSwitchDevs))) { return mapTAPIErrorCode( PHONEERR_INVALHOOKSWITCHDEV ); } if (!IsOnlyOneBitSetInDWORD (dwHookSwitchMode) || (dwHookSwitchMode & ~AllHookSwitchModes)) { return mapTAPIErrorCode( PHONEERR_INVALHOOKSWITCHMODE ); } LONG lResult = DOFUNC (&funcArgs, "phoneSetHookSwitch"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } HRESULT PhoneSetLamp( HPHONE hPhone, DWORD dwButtonLampID, DWORD dwLampMode ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetLamp), { (ULONG_PTR) hPhone, dwButtonLampID, dwLampMode }, { Dword, Dword, Dword } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetRing"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } HRESULT PhoneSetRing( HPHONE hPhone, DWORD dwRingMode, DWORD dwVolume ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetRing), { (ULONG_PTR) hPhone, dwRingMode, dwVolume }, { Dword, Dword, Dword } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetRing"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } LONG WINAPI phoneSetStatusMessages( HPHONE hPhone, DWORD dwPhoneStates, DWORD dwButtonModes, DWORD dwButtonStates ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | SYNC | 4, pSetStatusMessages), { (ULONG_PTR) hPhone, dwPhoneStates, dwButtonModes, dwButtonStates }, { Dword, Dword, Dword, Dword } }; return (DOFUNC (&funcArgs, "phoneSetStatusMessages")); } HRESULT PhoneSetVolume( HPHONE hPhone, DWORD dwHookSwitchDev, DWORD dwVolume ) { FUNC_ARGS funcArgs = { MAKELONG (PHONE_FUNC | ASYNC | 3, pSetVolume), { (ULONG_PTR) hPhone, dwHookSwitchDev, dwVolume }, { Dword, Dword, Dword } }; LONG lResult = DOFUNC (&funcArgs, "phoneSetVolume"); if (lResult > 0) // async reply { return WaitForPhoneReply( lResult ); } else { return mapTAPIErrorCode( lResult ); } } HRESULT ProviderPrivateFactoryIdentify( DWORD dwDeviceID, GUID * pguid ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 3, xPrivateFactoryIdentify), { (ULONG_PTR) dwDeviceID, (ULONG_PTR) pguid, (ULONG_PTR) sizeof(GUID) }, { Dword, lpGet_SizeToFollow, Size } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "ProviderPrivateFactoryIdentify") ); } HRESULT ProviderPrivateChannelData( DWORD dwDeviceID, DWORD dwAddressID, HCALL hCall, HCALLHUB hCallHub, DWORD dwType, BYTE * pBuffer, DWORD dwSize ) { HRESULT hr; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 7, lDevSpecificEx), { dwDeviceID, dwAddressID, (ULONG_PTR)hCall, (ULONG_PTR)hCallHub, dwType, (ULONG_PTR)pBuffer, dwSize }, { Dword, Dword, Dword, Dword, Dword, lpSet_SizeToFollow, Size } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "ProviderPrivateChannelData") ); } // // ----------------------- Private support routines --------------------------- // void FreeInitData( PT3INIT_DATA pInitData ) { EnterCriticalSection (&gcsTapisrvCommunication); if (pInitData && ( pInitData->dwKey != 0xefefefef ) ) { pInitData->dwKey = 0xefefefef; LeaveCriticalSection (&gcsTapisrvCommunication); ClientFree (pInitData); } else { LeaveCriticalSection (&gcsTapisrvCommunication); } } ////////////////////////////////////////////////////////////////// // Wait for a reply for async stuff // ////////////////////////////////////////////////////////////////// HRESULT WaitForReply( DWORD dwID ) { HRESULT hr = S_OK; CAsyncRequestReply *pReply; // Create a new request entry on the list pReply = gpLineAsyncReplyList->addRequest( dwID ); if( NULL == pReply ) { LOG((TL_INFO, "gpLineAsyncReplyList->addRequest failed")); hr = E_OUTOFMEMORY; } else { // Now we wait to be signalled hr = pReply->wait(); if (-1 == hr) { gpLineAsyncReplyList->remove (pReply); } // Cleanup delete pReply; // if we we didn't wait long enough for the asycnronous call to succeed. if (-1 == hr) return TAPI_E_TIMEOUT; } return mapTAPIErrorCode( hr ); } HRESULT WaitForPhoneReply( DWORD dwID ) { HRESULT hr = S_OK; CAsyncRequestReply *pReply; // Create a new request entry on the list pReply = gpPhoneAsyncReplyList->addRequest( dwID ); if( NULL == pReply ) { LOG((TL_INFO, "gpPhoneAsyncReplyList->addRequest failed")); hr = E_OUTOFMEMORY; } else { // Now we wait to be signalled hr = pReply->wait(); if (-1 == hr) { gpPhoneAsyncReplyList->remove (pReply); } // Cleanup delete pReply; // if we we didn't wait long enough for the asycnronous call to succeed. if (-1 == hr) return TAPI_E_TIMEOUT; } return mapTAPIErrorCode( hr ); } ///////////////////////////////////////////////////////////////////// // FindCallObject // // Finds the call object associated with an HCALL // // Returns TRUE if the call object is found, FALSE if not. ////////////////////////////////////////////////////////////////////// BOOL FindCallObject( HCALL hCall, CCall ** ppCall ) { HRESULT hr; gpCallHashTable->Lock(); hr = gpCallHashTable->Find( (ULONG_PTR)hCall, (ULONG_PTR *)ppCall ); if (SUCCEEDED(hr)) { (*ppCall)->AddRef(); gpCallHashTable->Unlock(); return TRUE; } gpCallHashTable->Unlock(); return FALSE; } ///////////////////////////////////////////////////////////////////// // FindAddressObject // // Finds the address object associated with an HLINE // // Returns TRUE if the line object is found, FALSE if not. ////////////////////////////////////////////////////////////////////// BOOL FindAddressObject( HLINE hLine, CAddress ** ppAddress ) { HRESULT hr; gpLineHashTable->Lock(); hr = gpLineHashTable->Find( (ULONG_PTR)hLine, (ULONG_PTR *)ppAddress ); if ( SUCCEEDED(hr) ) { (*ppAddress)->AddRef(); gpLineHashTable->Unlock(); return TRUE; } gpLineHashTable->Unlock(); return FALSE; } BOOL FindAddressObjectWithDeviceID( HLINE hLine, DWORD dwAddressID, CAddress ** ppAddress ) { HRESULT hr; gpLineHashTable->Lock(); hr = gpLineHashTable->Find( (ULONG_PTR)hLine, (ULONG_PTR *)ppAddress ); if ( SUCCEEDED(hr) ) { if ((*ppAddress)->GetAddressID() == dwAddressID) { (*ppAddress)->AddRef(); gpLineHashTable->Unlock(); return TRUE; } } gpLineHashTable->Unlock(); return FALSE; } ///////////////////////////////////////////////////////////////////// // FindPhoneObject // // Finds the phone object associated with an HPHONE // // Returns TRUE if the phone object is found, FALSE if not. ////////////////////////////////////////////////////////////////////// BOOL FindPhoneObject( HPHONE hPhone, CPhone ** ppPhone ) { HRESULT hr; gpPhoneHashTable->Lock(); hr = gpPhoneHashTable->Find( (ULONG_PTR)hPhone, (ULONG_PTR *)ppPhone ); if ( SUCCEEDED(hr) ) { (*ppPhone)->AddRef(); gpPhoneHashTable->Unlock(); return TRUE; } gpPhoneHashTable->Unlock(); return FALSE; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // FindAgentHandlerObject // // Finds the Agent Handler object associated with an HLINE // // Returns TRUE if the line object is found, FALSE if not. // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ BOOL FindAgentHandlerObject( HLINE hLine, CAgentHandler ** ppAgentHandler ) { HRESULT hr = FALSE; gpAgentHandlerHashTable->Lock(); hr = gpAgentHandlerHashTable->Find( (ULONG_PTR)hLine, (ULONG_PTR *)ppAgentHandler ); if ( SUCCEEDED(hr) ) { (*ppAgentHandler)->AddRef(); hr = TRUE; } else { hr = FALSE; } gpAgentHandlerHashTable->Unlock(); return hr; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // FindCallHubObject // // Finds the CallHub object based on the hCallHub // // Returns TRUE if the line object is found, FALSE if not. // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ BOOL FindCallHubObject( HCALLHUB hCallHub, CCallHub ** ppCallHub ) { HRESULT hr = FALSE; gpCallHubHashTable->Lock(); hr = gpCallHubHashTable->Find( (ULONG_PTR)hCallHub, (ULONG_PTR *)ppCallHub ); if ( SUCCEEDED(hr) ) { try { (*ppCallHub)->AddRef(); hr = TRUE; } catch(...) { hr = FALSE; } } else { hr = FALSE; } gpCallHubHashTable->Unlock(); return hr; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // CheckTapisrvCallhub // // Checks that at least one hCall that TAPISRV supports for a CallHub exists // as a Call Objects. // This is to ensure that we have one call obect to reference the hub, otherwise // it can be released prematurely // // Returns S_OK if one exists, E_FAIL if all are missing // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HRESULT CheckTapisrvCallhub(HCALLHUB hCallHub) { LINECALLLIST * pCallHubList; HCALL * phCalls; DWORD dwCount; CCall * pCall = NULL; HRESULT hr = E_FAIL; LOG((TL_INFO, "CheckTapisrvCallhub - hCallHub: %lx",hCallHub)); // // get the list of hcalls // related to this callhub // hr = LineGetHubRelatedCalls( hCallHub, 0, &pCallHubList ); if ( SUCCEEDED(hr) ) { // Assume the worst.. hr = E_FAIL; // // get to the list of calls // phCalls = (HCALL *)(((LPBYTE)pCallHubList) + pCallHubList->dwCallsOffset); // // the first call is actually the callhub // check it against the handle we gave... // if (hCallHub == (HCALLHUB)(phCalls[0])) { // // go through the call handles and try to find call objects // for (dwCount = 1; dwCount < pCallHubList->dwCallsNumEntries; dwCount++) { // // get the tapi3 call object // if ( FindCallObject(phCalls[dwCount], &pCall) ) { // Found it - findcallobject addrefs, so release pCall->Release(); LOG((TL_INFO, "CheckTapisrvCallhub - found hCall %lx", phCalls[dwCount])); hr = S_OK; break; } } } else { LOG((TL_INFO, "CheckTapisrvCallhub - returned callhub doesn't match")); _ASSERTE(0); hr = E_FAIL; } ClientFree( pCallHubList ); // Clean up } else { LOG((TL_INFO, "CheckTapisrvCallhub - LineGetHubRelatedCallsfailed")); } LOG((TL_TRACE, hr, "CheckTapisrvCallhub - exit")); return hr; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= // // ProcessEvent // This processes messages from tapisrv // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= HRESULT ProcessMessage( PT3INIT_DATA pInitData, PASYNCEVENTMSG pParams ) { HRESULT hResult = S_OK; LOG((TL_INFO, "In ProcessMessage - MsgType:%x", pParams->Msg)); switch( pParams->Msg ) { case LINE_CALLSTATE: { hResult = HandleCallStateMessage( pParams ); break; } case LINE_CALLINFO: { hResult = HandleCallInfoMessage( pParams ); break; } case LINE_MONITORDIGITS: { hResult = HandleMonitorDigitsMessage( pParams ); break; } case LINE_SENDMSPDATA: { hResult = HandleSendMSPDataMessage( pParams ); break; } case LINE_DEVSPECIFICEX: { //HandlePrivateEventMessage( pParams ); break; } case LINE_LINEDEVSTATE: { CTAPI *pTapi = NULL; if (!IsBadReadPtr(pInitData, sizeof(pInitData))) { pTapi = pInitData->pTAPI; } HandleLineDevStateMessage( pTapi, pParams ); break; } case LINE_ADDRESSSTATE: { HandleAddressStateMessage( pParams ); break; } case LINE_DEVSPECIFIC: { HandleLineDevSpecificMessage( pParams ); break; } case LINE_DEVSPECIFICFEATURE: { //HandleDevSpecificFeatureMessage( pParams ); break; } case LINE_GATHERDIGITS: { hResult = HandleGatherDigitsMessage( pParams ); break; } case LINE_GENERATE: { hResult = HandleLineGenerateMessage( pParams ); break; } case LINE_MONITORMEDIA: { HandleMonitorMediaMessage( pParams ); break; } case LINE_MONITORTONE: { HandleMonitorToneMessage( pParams ); break; } case LINE_CLOSE: { HandleLineCloseMessage( pParams ); break; } case LINE_AGENTSTATUS: { break; } case LINE_AGENTSTATUSEX: { HandleAgentStatusMessage(pParams); break; } case LINE_AGENTSESSIONSTATUS: { HandleAgentSessionStatusMessage(pParams); break; } case LINE_QUEUESTATUS: { HandleQueueStatusMessage(pParams); break; } case LINE_QOSINFO: { hResult = HandleLineQOSInfoMessage( pParams ); break; } case LINE_APPNEWCALLHUB: { HRESULT hr; CCallHub * pCallHub; BOOL fAllCallsDisconnected; hResult = CheckTapisrvCallhub((HCALLHUB)pParams->Param1); if (SUCCEEDED(hResult)) { CTAPI *pTapi = NULL; // // pInitData seems good? // if (!IsBadReadPtr(pInitData, sizeof(pInitData))) { // // check the tapi object, and get an addref'ed copy if it is // valid // if ( CTAPI::IsValidTapiObject(pInitData->pTAPI) ) { // // got a good, addref'ed object. keep it. // pTapi = pInitData->pTAPI; } } hr = CCallHub::CreateTapisrvCallHub( pTapi, (HCALLHUB)pParams->Param1, &pCallHub ); if (!SUCCEEDED(hr)) { LOG((TL_ERROR, "CreateTapisrvCallHub failed in LINE_APPNEWCALLHUB")); } else { //Send CHE_CALLHUBIDLE message if all the calls in the callhub are disconnected. hr = pCallHub -> FindCallsDisconnected( &fAllCallsDisconnected ); if( hr == S_OK ) { if( fAllCallsDisconnected == TRUE ) { // // tell the app // pCallHub -> SetState(CHS_IDLE); } } pCallHub->Release(); } // // if we we got a good tapi object, we must release it now. // if (NULL != pTapi) { pTapi->Release(); pTapi = NULL; } } break; } case LINE_GROUPSTATUS: { handleGroupStatusMessage(pParams); break; } case LINE_PROXYSTATUS: { CTAPI *pTapi = NULL; if (!IsBadReadPtr(pInitData, sizeof(pInitData))) { pTapi = pInitData->pTAPI; } QueueCallbackEvent( pTapi, pParams ); break; } case LINE_REPLY: { CAsyncRequestReply *pReply; LOG((TL_INFO, "LINE_REPLY")); // Add (or complete existing) response entry on the list pReply = gpLineAsyncReplyList->addReply( pParams->Param1, (HRESULT) pParams->Param2 ); if(pReply==NULL) { LOG((TL_INFO, "gpLineAsyncReplyList->addReply failed")); hResult = E_OUTOFMEMORY; } else { // Signal it to say we're done. pReply->signal(); } break; } case PHONE_REPLY: { CAsyncRequestReply *pReply; LOG((TL_INFO, "PHONE_REPLY")); // Add (or complete existing) response entry on the list pReply = gpPhoneAsyncReplyList->addReply( pParams->Param1, (HRESULT) pParams->Param2 ); // Signal it to say we're done. if(pReply == NULL ) { LOG((TL_INFO, "gpPhoneAsyncReplyList->addReply failed")); hResult = E_OUTOFMEMORY; } else { pReply->signal(); } break; } case LINE_APPNEWCALL: { // LINE_APPNEWCALL is the first notification we get of // a new call object. Create the call here, but // don't notify the app until we get the first // message about it. CAddress * pAddress; CCall * pCall = NULL; if (FindAddressObjectWithDeviceID( (HLINE) pParams->hDevice, pParams->Param1, &pAddress )) { HRESULT hr; LINECALLINFO * pCallInfo = NULL; hr = LineGetCallInfo( pParams->Param2, &pCallInfo ); if ( SUCCEEDED(hr) ) { BOOL callExposeAndNotify = TRUE; if ( pCallInfo->dwMediaMode & LINEMEDIAMODE_INTERACTIVEVOICE ) { pCallInfo->dwMediaMode |= LINEMEDIAMODE_AUTOMATEDVOICE; pCallInfo->dwMediaMode &= ~((DWORD)LINEMEDIAMODE_INTERACTIVEVOICE); } pCallInfo->dwMediaMode &= ~((DWORD)LINEMEDIAMODE_UNKNOWN); //Check if the new call is a conference controller call. BOOL fConfContCall = *(&pParams->Param4 + 3); //Don't expose if a conference controller call LOG(( TL_ERROR, "conference controller call:%d.", *(&pParams->Param4 + 3) )); if( fConfContCall == TRUE ) { LOG(( TL_ERROR, "conference controller call." )); callExposeAndNotify = FALSE; } pAddress->InternalCreateCall( NULL, 0, pCallInfo->dwMediaMode, (pParams->Param3 == LINECALLPRIVILEGE_OWNER) ? CP_OWNER : CP_MONITOR, callExposeAndNotify, (HCALL)pParams->Param2, callExposeAndNotify, &pCall ); } if ( NULL != pCallInfo ) { ClientFree( pCallInfo ); } // // don't keep a ref if(pCall != NULL) { pCall->Release(); } // //FindAddressObject addrefs the address objct pAddress->Release(); } else { LOG((TL_ERROR, "Ignoring call with wrong address id")); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, lDeallocateCall), { pParams->Param2 }, { Dword } }; LOG((TL_INFO, "lineDeallocateCall - hCall = 0x%08lx", pParams->Param2)); DOFUNC (&funcArgs, "lineDeallocateCall"); } break; } case LINE_CREATE: { QueueCallbackEvent( pParams ); break; } case LINE_REMOVE: { QueueCallbackEvent( pParams ); break; } case LINE_REQUEST: { CTAPI *pTapi = NULL; if (!IsBadReadPtr(pInitData, sizeof(pInitData))) { pTapi = pInitData->pTAPI; } HandleLineRequest( pTapi, pParams ); break; } case LINE_CALLHUBCLOSE: { gpRetryQueue->RemoveNewCallHub(pParams->Param1); HandleCallHubClose( pParams ); break; } case PRIVATE_MSPEVENT: { HandlePrivateMSPEvent( pParams ); break; } case PHONE_BUTTON: { HandlePhoneButtonMessage( pParams ); break; } case PHONE_CLOSE: { HandlePhoneCloseMessage( pParams ); break; } case PHONE_DEVSPECIFIC: { HandlePhoneDevSpecificMessage( pParams ); break; } case PHONE_STATE: { QueueCallbackEvent( pParams ); break; } case PHONE_CREATE: { QueueCallbackEvent( pParams ); break; } case PHONE_REMOVE: { QueueCallbackEvent( pParams ); break; } case LINE_AGENTSPECIFIC: case LINE_PROXYREQUEST: default: break; } return hResult; } void __RPC_FAR * __RPC_API midl_user_allocate(size_t len) { LOG((TL_TRACE, "midl_user_allocate: enter, size=x%x", len)); return (ClientAlloc (len)); } void __RPC_API midl_user_free(void __RPC_FAR * ptr) { LOG((TL_TRACE, "midl_user_free: enter, p=x%p", ptr)); ClientFree (ptr); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // AllocClientResources // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // // Starts tapisrv if it is not started and calls ClientAttach // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LONG WINAPI AllocClientResources( DWORD dwErrorClass ) { LOG((TL_INFO, "AllocClientResources - enter")); DWORD dwExceptionCount = 0; DWORD dwError = 0; LONG lResult = gaOpFailedErrors[dwErrorClass]; // // service handles // SC_HANDLE hSCMgr = NULL; SC_HANDLE hTapiSrv = NULL; EnterCriticalSection ( &gcsClientResources ); // // If we're in safeboot mode, tapisrv won't start; // fail initialization. // if (0 != GetSystemMetrics (SM_CLEANBOOT)) { lResult = gaOpFailedErrors[dwErrorClass]; goto AllocClientResources_return; } // // Start the TAPISRV.EXE service // if (!(GetVersion() & 0x80000000)) // Win NT { if ((hSCMgr = OpenSCManager( NULL, // local machine NULL, // ServicesActive database SC_MANAGER_CONNECT // desired access )) == NULL) { dwError = GetLastError(); LOG((TL_ERROR, "OpenSCManager failed, err=%d", dwError)); if ( ERROR_ACCESS_DENIED == dwError || ERROR_NOACCESS == dwError ) { // if OpenSCManager fails with ACCESS_DENIED, // we still need to try to attach to TAPISRV goto AllocClientResources_attachToServer; } else { goto AllocClientResources_return; } } if ((hTapiSrv = OpenService( hSCMgr, // SC mgr handle (LPCTSTR) "TAPISRV", // name of service to open //SERVICE_START | // desired access SERVICE_QUERY_STATUS )) == NULL) { dwError = GetLastError(); LOG((TL_ERROR, "OpenService failed, err=%d", dwError)); if ( ERROR_ACCESS_DENIED == dwError || ERROR_NOACCESS == dwError ) { // if OpenService fails with ACCESS_DENIED, // we still need to try to attach to TAPISRV goto AllocClientResources_attachToServer; } else { goto AllocClientResources_cleanup1; } } AllocClientResources_queryServiceStatus: { #define MAX_NUM_SECONDS_TO_WAIT_FOR_TAPISRV 180 DWORD dwNumSecondsSleptStartPending = 0, dwNumSecondsSleptStopPending = 0; while (1) { SERVICE_STATUS status; QueryServiceStatus (hTapiSrv, &status); switch (status.dwCurrentState) { case SERVICE_RUNNING: LOG((TL_INFO, "Tapisrv running")); goto AllocClientResources_attachToServer; case SERVICE_START_PENDING: Sleep (1000); if (++dwNumSecondsSleptStartPending > MAX_NUM_SECONDS_TO_WAIT_FOR_TAPISRV) { LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_START_PENDING" )); goto AllocClientResources_cleanup2; } break; case SERVICE_STOP_PENDING: Sleep (1000); if (++dwNumSecondsSleptStopPending > MAX_NUM_SECONDS_TO_WAIT_FOR_TAPISRV) { LOG((TL_ERROR, "ERROR: Tapisrv stuck SERVICE_STOP_PENDING" )); goto AllocClientResources_cleanup2; } break; case SERVICE_STOPPED: LOG((TL_ERROR, "Starting tapisrv (NT)...")); // // close service handle that we already have // if (NULL != hTapiSrv) { CloseServiceHandle(hTapiSrv); hTapiSrv = NULL; } /*Change: This is done in order to avoid opening service with SERVICE_START previleges unless it needs to be started*/ if ((hTapiSrv = OpenService( hSCMgr, // SC mgr handle (LPCTSTR) "TAPISRV", // name of service to open SERVICE_START | // desired access SERVICE_QUERY_STATUS )) == NULL) { LOG((TL_ERROR, "OpenService failed, err=%d", GetLastError())); goto AllocClientResources_cleanup2; } if (!StartService( hTapiSrv, // service handle 0, // num args NULL // args )) { DWORD dwLastError = GetLastError(); if (dwLastError != ERROR_SERVICE_ALREADY_RUNNING) { LOG((TL_ERROR, "StartService(TapiSrv) failed, err=%d", dwLastError )); goto AllocClientResources_cleanup2; } } break; default: LOG((TL_ERROR, "error, service status=%d", status.dwCurrentState )); goto AllocClientResources_cleanup2; } } } } else // Win95 { HANDLE hMutex, hEvent; // // First grab the global mutex that serializes the following // across all instances of tapi32.dll // if (!(hMutex = CreateMutex (NULL, FALSE, "StartTapiSrv"))) { LOG((TL_ERROR, "CreateMutex ('StartTapiSrv') failed, err=%d", GetLastError() )); } WaitForSingleObject (hMutex, INFINITE); // // Try to open the event that tells us tapisrv has inited // if (!(hEvent = OpenEvent (EVENT_ALL_ACCESS, TRUE, "TapiSrvInited"))) { // // OpenEvent failed, so tapisrv hasn't been started yet. Start // tapisrv, and then get the event handle. // STARTUPINFO startupInfo; PROCESS_INFORMATION processInfo; LOG((TL_ERROR, "OpenEvent ('TapiSrvInited') failed, err=%d", GetLastError() )); ZeroMemory(&startupInfo, sizeof (STARTUPINFO)); startupInfo.cb = sizeof (STARTUPINFO); LOG((TL_INFO, "Starting tapisrv (Win95)...")); if (!CreateProcess( NULL, // image name "tapisrv.exe", // cmd line NULL, // process security attrs NULL, // thread security attrs FALSE, // inherit handles NORMAL_PRIORITY_CLASS, // create opts NULL, // environment NULL, // curr dir &startupInfo, &processInfo )) { LOG((TL_ERROR, "CreateProcess('tapisrv.exe') failed, err=%d", GetLastError() )); } else { CloseHandle (processInfo.hProcess); CloseHandle (processInfo.hThread); } if (!(hEvent = CreateEvent (NULL, TRUE, FALSE, "TapiSrvInited"))) { LOG((TL_ERROR, "CreateEvent ('TapiSrvInited') failed, err=%d", GetLastError() )); } } // // Now wait on the event (it's will be signaled when tapisrv has // completed it's initialization). Then clean up. // WaitForSingleObject (hEvent, INFINITE); CloseHandle (hEvent); ReleaseMutex (hMutex); CloseHandle (hMutex); } // // Init the RPC connection // AllocClientResources_attachToServer: { #define CNLEN 25 // computer name length #define UNCLEN CNLEN+2 // \\computername #define PATHLEN 260 // Path #define MAXPROTSEQ 20 // protocol sequence "ncacn_np" BOOL bException = FALSE; RPC_STATUS status; unsigned char pszNetworkAddress[UNCLEN+1]; unsigned char *pszUuid = NULL; unsigned char *pszOptions = NULL; unsigned char *pszStringBinding = NULL; DWORD dwProcessID = GetCurrentProcessId(); // // UNLEN (as documented for GetUserName()) is defined in LMCONS.H // to be 256 characters. LMCONS.H cannot be easily included, so we are // redefining the value here. // const DWORD MAXIMUM_USER_NAME_LENGTH = 256; // // allocate memory for user name // DWORD dwUserNameSize = MAXIMUM_USER_NAME_LENGTH + 1; WCHAR *pszUserName = (WCHAR *) ClientAlloc (dwUserNameSize * sizeof(WCHAR) ); if (NULL == pszUserName) { LOG((TL_ERROR, "AllocClientResources: failed to allocate 0x%lx characters for pszUserName", dwUserNameSize)); goto AllocClientResources_cleanup2; } // // try to get user name. we are passing in a buffer for the // longest possible user name so if the call fails, do not // retry with a bigger buffer // BOOL bResult = GetUserNameW(pszUserName, &dwUserNameSize); if ( ! bResult ) { LOG((TL_ERROR, "AllocClientResources: GetUserName failed. LastError = 0x%lx", GetLastError())); ClientFree(pszUserName); pszUserName = NULL; goto AllocClientResources_cleanup2; } LOG((TL_INFO, "AllocClientResources: UserName [%S]", pszUserName)); // // allocate memory for computer name // DWORD dwComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1 ; WCHAR *pszComputerName = (WCHAR *) ClientAlloc (dwComputerNameSize * sizeof(WCHAR) ); if (NULL == pszComputerName) { LOG((TL_ERROR, "AllocClientResources: failed to allocate 0x%lx characters for pszUserName", dwComputerNameSize )); ClientFree(pszUserName); pszUserName = NULL; goto AllocClientResources_cleanup2; } // // try to get computer name. we are passing in a buffer for the // longest possible computer name so if the call fails, do not // retry with a bigger buffer // bResult = GetComputerNameW(pszComputerName, &dwComputerNameSize); if ( ! bResult ) { LOG((TL_ERROR, "AllocClientResources: GetComputerName failed. LastError = 0x%lx", GetLastError())); ClientFree(pszUserName); pszUserName = NULL; ClientFree(pszComputerName); pszComputerName = NULL; goto AllocClientResources_cleanup2; } LOG((TL_INFO, "AllocClientResources: ComputerName [%S]", pszComputerName)); pszNetworkAddress[0] = '\0'; status = RpcStringBindingCompose( pszUuid, (unsigned char *)"ncalrpc", pszNetworkAddress, (unsigned char *)"tapsrvlpc", pszOptions, &pszStringBinding ); if (status) { LOG((TL_ERROR, "RpcStringBindingCompose failed: err=%d, szNetAddr='%s'", status, pszNetworkAddress )); } status = RpcBindingFromStringBinding( pszStringBinding, &hTapSrv ); if (status) { LOG((TL_ERROR, "RpcBindingFromStringBinding failed, err=%d, szBinding='%s'", status, pszStringBinding )); } RpcTryExcept { LOG((TL_INFO, "AllocCliRes: calling ClientAttach...")); lResult = ClientAttach( (PCONTEXT_HANDLE_TYPE *) &gphCx, dwProcessID, (long *) &ghAsyncEventsEvent, pszUserName, pszComputerName ); LOG((TL_INFO, "AllocCliRes: ClientAttach returned x%x. ghAsyncEventsEvent[%p]", lResult, ghAsyncEventsEvent)); } RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) { LOG((TL_ERROR, "AllocCliRes: ClientAttach caused except=%d", RpcExceptionCode() )); bException = TRUE; } RpcEndExcept ClientFree (pszUserName); ClientFree (pszComputerName); RpcBindingFree (&hTapSrv); // LOG((TL_ // 3, // "AllocCliRes: gphCx=x%x, PID=x%x, hAEEvent=x%x", // gphCx, // dwProcessID, // ghAsyncEventsEvent // )); RpcStringFree(&pszStringBinding); if (bException) { // // If here chances are that we started the service and it's // not ready to receive rpc requests. So we'll give it a // little time to get rolling and then try again. // if (dwExceptionCount < gdwMaxNumRequestRetries) { Sleep ((++dwExceptionCount > 1 ? gdwRequestRetryTimeout : 0)); if (hTapiSrv) // Win NT && successful OpenService() { goto AllocClientResources_queryServiceStatus; } else { goto AllocClientResources_attachToServer; } } else { LOG((TL_ERROR, "AllocCliRes: ClientAttach failed, result=x%x", gaServiceNotRunningErrors[dwErrorClass] )); lResult = gaServiceNotRunningErrors[dwErrorClass]; } } } AllocClientResources_cleanup2: if (NULL != hTapiSrv) { CloseServiceHandle (hTapiSrv); hTapiSrv = NULL; } AllocClientResources_cleanup1: if (NULL != hSCMgr) { CloseServiceHandle (hSCMgr); hSCMgr = NULL; } AllocClientResources_return: //release the mutex LeaveCriticalSection ( &gcsClientResources ); LOG((TL_TRACE, "AllocClientResources: exit, returning x%x", lResult)); return lResult; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // NewShutdown // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ HRESULT CTAPI::NewShutdown() { LOG((TL_TRACE, "NewShutdown - enter")); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, lShutdown), { (ULONG_PTR)m_dwLineInitDataHandle }, { hXxxApp } }; // // deallocate line resources // if (0 != m_dwLineInitDataHandle) { DOFUNC( &funcArgs, "lineShutdown" ); FreeInitData (m_pLineInitData); m_pLineInitData = NULL; DeleteHandleTableEntry(m_dwLineInitDataHandle); m_dwLineInitDataHandle = 0; } // // deallocate phone resources // if (0 != m_dwPhoneInitDataHandle) { funcArgs.Args[0] = (ULONG_PTR)m_dwPhoneInitDataHandle; funcArgs.Flags = MAKELONG (PHONE_FUNC | SYNC | 1, pShutdown), DOFUNC( &funcArgs, "phoneShutdown" ); FreeInitData (m_pPhoneInitData); m_pPhoneInitData = NULL; DeleteHandleTableEntry(m_dwPhoneInitDataHandle); m_dwPhoneInitDataHandle = 0; } LOG((TL_TRACE, "NewShutdown - finish")); return S_OK; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // CreateThreadsAndStuff // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // // This is called when the last TAPI object has been freed //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void CTAPI::FinalTapiCleanup() { DWORD dwSignalled; STATICLOG((TL_TRACE, "FinalTapiCleanup - enter")); // // tell our threads that we are shutting down // if (gpAsyncEventsThreadParams) { gpAsyncEventsThreadParams->bExitThread = TRUE; } SetEvent( ghAsyncEventsEvent ); gbExitThread = TRUE; SetEvent( ghCallbackThreadEvent ); // // and wait for them to exit // STATICLOG((TL_INFO, "FinalTapiCleanup - ghAsyncEventsThread")); //WaitForSingleObject( ghAsyncEventsThread, INFINITE ); CoWaitForMultipleHandles (COWAIT_ALERTABLE, INFINITE, 1, &ghAsyncEventsThread, &dwSignalled); STATICLOG((TL_INFO, "FinalTapiCleanup - ghCallbackThread")); //WaitForSingleObject( ghCallbackThread, INFINITE ); CoWaitForMultipleHandles (COWAIT_ALERTABLE, INFINITE, 1, &ghCallbackThread, &dwSignalled); // // close their handles // CloseHandle( ghAsyncEventsThread ); CloseHandle( ghCallbackThread ); gpAsyncEventsThreadParams = NULL; // // Safely close any existing generic dialog instances // EnterCriticalSection (&gcsTapisrvCommunication); if (gpUIThreadInstances) { PUITHREADDATA pUIThreadData, pNextUIThreadData; pUIThreadData = gpUIThreadInstances; while (pUIThreadData) { // // Grab a ptr to the next UIThreadData while it's still // safe, wait until the ui dll has indicated that it // is will to receive generic dlg data, then pass it // NULL/0 to tell it to shutdown the dlg inst // pNextUIThreadData = pUIThreadData->pNext; // WaitForSingleObject (pUIThreadData->hEvent, INFINITE); CoWaitForMultipleHandles (COWAIT_ALERTABLE, INFINITE, 1, &pUIThreadData->hEvent, &dwSignalled ); STATICLOG((TL_INFO, "NewShutdown: calling TUISPI_providerGenericDialogData..." )); ((TUIGDDPROC)(*pUIThreadData->pfnTUISPI_providerGenericDialogData))( pUIThreadData->htDlgInst, NULL, 0 ); STATICLOG((TL_INFO, "NewShutdown: TUISPI_providerGenericDialogData returned" )); pUIThreadData = pNextUIThreadData; } } LeaveCriticalSection (&gcsTapisrvCommunication); FreeClientResources(); STATICLOG((TL_TRACE, "FinalTapiCleanup - exit")); } #if DBG LPVOID WINAPI ClientAllocReal( DWORD dwSize, DWORD dwLine, PSTR pszFile ) #else LPVOID WINAPI ClientAllocReal( DWORD dwSize ) #endif { // // Alloc 16 extra bytes so we can make sure the pointer we pass back // is 64-bit aligned & have space to store the original pointer // #if DBG PMYMEMINFO pHold; PDWORD_PTR pAligned; PBYTE p; p = (PBYTE)LocalAlloc(LPTR, dwSize + sizeof(MYMEMINFO) + 16); if (p == NULL) { return NULL; } // note note note - this only works because mymeminfo is // a 16 bit multiple in size. if it wasn't, this // align stuff would cause problems. pAligned = (PDWORD_PTR) (p + 8 - (((DWORD_PTR) p) & (DWORD_PTR)0x7)); *pAligned = (DWORD_PTR) p; pHold = (PMYMEMINFO)((DWORD_PTR)pAligned + 8); pHold->dwSize = dwSize; pHold->dwLine = dwLine; pHold->pszFile = pszFile; pHold->pPrev = NULL; pHold->pNext = NULL; EnterCriticalSection(&csMemoryList); if (gpMemLast != NULL) { gpMemLast->pNext = pHold; pHold->pPrev = gpMemLast; gpMemLast = pHold; } else { gpMemFirst = gpMemLast = pHold; } LeaveCriticalSection(&csMemoryList); return (LPVOID)(pHold + 1); #else LPBYTE p; PDWORD_PTR pAligned; if ((p = (LPBYTE) LocalAlloc (LPTR, dwSize + 16))) { pAligned = (PDWORD_PTR) (p + 8 - (((DWORD_PTR) p) & (DWORD_PTR)0x7)); *pAligned = (DWORD_PTR) p; pAligned = (PDWORD_PTR)((DWORD_PTR)pAligned + 8); } else { LOG((TL_ERROR, "ClientAlloc: LocalAlloc (x%lx) failed, err=x%lx", dwSize, GetLastError()) ); pAligned = NULL; } return ((LPVOID) pAligned); #endif } void WINAPI ClientFree( LPVOID p ) { #if DBG PMYMEMINFO pHold; if (p == NULL) { return; } pHold = (PMYMEMINFO)(((LPBYTE)p) - sizeof(MYMEMINFO)); EnterCriticalSection(&csMemoryList); if (pHold->pPrev) { pHold->pPrev->pNext = pHold->pNext; } else { gpMemFirst = pHold->pNext; } if (pHold->pNext) { pHold->pNext->pPrev = pHold->pPrev; } else { gpMemLast = pHold->pPrev; } LeaveCriticalSection(&csMemoryList); { LPVOID pOrig = (LPVOID) *((PDWORD_PTR)((DWORD_PTR)pHold - 8)); LocalFree (pOrig); } //LocalFree(pHold); return; #else if (p != NULL) { LPVOID pOrig = (LPVOID) *((PDWORD_PTR)((DWORD_PTR)p - 8)); LocalFree (pOrig); } else { LOG((TL_INFO,"----- ClientFree: ptr = NULL!")); } #endif } SIZE_T WINAPI ClientSize( LPVOID p ) { if (p != NULL) { #if DBG p = (LPVOID)(((LPBYTE)p) - sizeof(MYMEMINFO)); #endif p = (LPVOID)*((PDWORD_PTR)((DWORD_PTR)p - 8)); return (LocalSize (p) - 16); } LOG((TL_INFO,"----- ClientSize: ptr = NULL!")); return 0; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // FreeClientResources // // This function is called from inside CTAPI::Initialize and CTAPI::Shutdown // only and hence access to it is serialized. Calling this function from some // other functionality would need making an alternate arrangement to serialize // access to this function // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ LONG WINAPI FreeClientResources( void ) { LOG((TL_INFO, "FreeClientResources - enter")); //grab the critical section EnterCriticalSection ( &gcsClientResources ); // // If ghTapi32 is non-NULL it means the AsyncEventsThread is // still running (an ill-behaved app is trying to unload us // without calling shutdown) so go thru the motions of getting // the thread to terminate (like we do in xxxShutdown) // // Otherwise close our handle to the shared event // if (gpAsyncEventsThreadParams) { gpAsyncEventsThreadParams->bExitThread = TRUE; SetEvent (ghAsyncEventsEvent); gpAsyncEventsThreadParams = NULL; gbExitThread = TRUE; SetEvent (ghCallbackThreadEvent); } else if (gphCx) { if (NULL != ghAsyncEventsEvent) { CloseHandle (ghAsyncEventsEvent); ghAsyncEventsEvent = NULL; } if (NULL != ghCallbackThreadEvent) { CloseHandle (ghCallbackThreadEvent); ghCallbackThreadEvent = NULL; } if (NULL != ghAsyncRetryQueueEvent) { CloseHandle (ghAsyncRetryQueueEvent); ghAsyncRetryQueueEvent = NULL; } } gpLineAsyncReplyList->FreeList(); gpPhoneAsyncReplyList->FreeList(); // // If we've made an rpc connection with tapisrv then cleanly detach // if (gphCx) { RpcTryExcept { ClientDetach (&gphCx); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { // do something? } RpcEndExcept gphCx = NULL; } // // Free up any other resources we were using // if (ghWow32Dll) { FreeLibrary (ghWow32Dll); ghWow32Dll = NULL; } //release the mutex LeaveCriticalSection ( &gcsClientResources ); LOG((TL_INFO, "FreeClientResources - exit")); return 0; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // eventName // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char *eventName(TAPI_EVENT event) { switch(event) { case TE_TAPIOBJECT: return "TE_TAPIOBJECT"; case TE_ADDRESS: return "TE_ADDRESS"; case TE_CALLNOTIFICATION: return "TE_CALLNOTIFICATION"; case TE_CALLSTATE: return "TE_CALLSTATE"; case TE_CALLMEDIA: return "TE_CALLMEDIA"; case TE_CALLHUB: return "TE_CALLHUB"; case TE_CALLINFOCHANGE: return "TE_CALLINFOCHANGE"; case TE_PRIVATE: return "TE_PRIVATE"; case TE_REQUEST: return "TE_REQUEST"; case TE_AGENT: return "TE_AGENT"; case TE_AGENTSESSION: return "TE_AGENTSESSION"; case TE_QOSEVENT: return "TE_QOSEVENT"; case TE_AGENTHANDLER: return "TE_AGENTHANDLER"; case TE_ACDGROUP: return "TE_ACDGROUP"; case TE_QUEUE: return "TE_QUEUE"; case TE_DIGITEVENT: return "TE_DIGITEVENT"; case TE_GENERATEEVENT: return "TE_GENERATEEVENT"; case TE_PHONEEVENT: return "TE_PHONEEVENT"; case TE_PHONEDEVSPECIFIC: return "TE_PHONEDEVSPECIFIC"; case TE_ADDRESSDEVSPECIFIC: return "TE_ADDRESSDEVSPECIFIC"; default: return "???"; } } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // callStateName // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ char *callStateName(CALL_STATE callState) { switch(callState) { case CS_IDLE: return "CS_IDLE"; case CS_INPROGRESS: return "CS_INPROGRESS"; case CS_CONNECTED: return "CS_CONNECTED"; case CS_DISCONNECTED: return "CS_DISCONNECTED"; case CS_OFFERING: return "CS_OFFERING"; case CS_HOLD: return "CS_HOLD"; case CS_QUEUED: return "CS_QUEUED"; default: return "???"; } } #ifdef TRACELOG void TAPIFormatMessage(HRESULT hr, LPVOID lpMsgBuf) { // Get the error message relating to our HRESULT FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, (LPCVOID)GetModuleHandle("TAPI3.DLL"), hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) lpMsgBuf, 0, NULL ); } #endif LONG CALLBACK TUISPIDLLCallback( DWORD_PTR dwObjectID, DWORD dwObjectType, LPVOID lpParams, DWORD dwSize ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 6, xUIDLLCallback), { (ULONG_PTR) dwObjectID, (ULONG_PTR) dwObjectType, (ULONG_PTR) lpParams, (ULONG_PTR) dwSize, (ULONG_PTR) lpParams, (ULONG_PTR) dwSize }, { Dword, Dword, lpSet_SizeToFollow, Size, lpGet_SizeToFollow, Size } }; return (DOFUNC (&funcArgs, "UIDLLCallback")); } void UIThread( LPVOID pParams ) { DWORD dwThreadID = GetCurrentThreadId(); HANDLE hTapi32; PUITHREADDATA pUIThreadData = (PUITHREADDATA) pParams; LOG((TL_TRACE, "UIThread: enter (tid=%d)", dwThreadID)); // // Call LoadLibrary to increment the reference count in case this // thread is still running when this dll gets unloaded // hTapi32 = LoadLibrary ("tapi32.dll"); LOG((TL_INFO, "UIThread: calling TUISPI_providerGenericDialog...")); ((TUIGDPROC)(*pUIThreadData->pfnTUISPI_providerGenericDialog))( TUISPIDLLCallback, pUIThreadData->htDlgInst, pUIThreadData->pParams, pUIThreadData->dwSize, pUIThreadData->hEvent ); LOG((TL_INFO, "UIThread: TUISPI_providerGenericDialog returned (tid=%d)", dwThreadID )); // // Remove the ui thread data struct from the global list // EnterCriticalSection (&gcsTapisrvCommunication); if (pUIThreadData->pNext) { pUIThreadData->pNext->pPrev = pUIThreadData->pPrev; } if (pUIThreadData->pPrev) { pUIThreadData->pPrev->pNext = pUIThreadData->pNext; } else { gpUIThreadInstances = pUIThreadData->pNext; } LeaveCriticalSection (&gcsTapisrvCommunication); // // Free the library & buffers, then alert tapisrv // FreeLibrary (pUIThreadData->hUIDll); CloseHandle (pUIThreadData->hThread); CloseHandle (pUIThreadData->hEvent); if (pUIThreadData->pParams) { ClientFree (pUIThreadData->pParams); } { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, xFreeDialogInstance), { (ULONG_PTR) pUIThreadData->htDlgInst }, { Dword } }; DOFUNC (&funcArgs, "FreeDialogInstance"); } ClientFree (pUIThreadData); LOG((TL_TRACE, "UIThread: exit (tid=%d)", dwThreadID)); if (hTapi32 != NULL) { FreeLibraryAndExitThread ((HINSTANCE)hTapi32, 0); } else { ExitThread (0); } } LONG //WINAPI CALLBACK LAddrParamsInited( LPDWORD lpdwInited ) { HKEY hKey; HKEY hKey2; DWORD dwDataSize; DWORD dwDataType; // // This is called by the modem setup wizard to determine // whether they should put up TAPI's Wizard page. // if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszTelephonyKey, 0, KEY_READ, &hKey2 )) { LOG((TL_ERROR, "LAddrParamsInited - failed to open registry key" )); return 0; } if (ERROR_SUCCESS != RegOpenKeyEx( hKey2, gszLocations, 0, KEY_READ, &hKey )) { RegCloseKey (hKey2); LOG((TL_ERROR, "LAddrParamsInited - failed to open registry key" )); return 0; } dwDataSize = sizeof(DWORD); *lpdwInited=0; RegQueryValueEx( hKey, gszNumEntries, 0, &dwDataType, (LPBYTE)lpdwInited, &dwDataSize ); RegCloseKey( hKey ); RegCloseKey( hKey2); // // Return a "proper" code // if ( *lpdwInited > 1 ) { *lpdwInited = 1; } return 0; } LONG WINAPI lineTranslateDialogA( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, HWND hwndOwner, LPCSTR lpszAddressIn ); ///////////////////////////////////////////////////////////////////// // internalPerformance // tapiperf.dll calls this function to get performance data // this just calls into tapisrv ///////////////////////////////////////////////////////////////////// LONG WINAPI internalPerformance(PPERFBLOCK pPerfBlock) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, tPerformance), { (ULONG_PTR)pPerfBlock, sizeof(PERFBLOCK) }, { lpGet_SizeToFollow, Size } }; return (DOFUNC (&funcArgs, "PerfDataCall")); } //*************************************************************************** //*************************************************************************** //*************************************************************************** #if DBG char *aszLineErrors[] = { NULL, "ALLOCATED", "BADDEVICEID", "BEARERMODEUNAVAIL", "inval err value (0x80000004)", // 0x80000004 isn't valid err code "CALLUNAVAIL", "COMPLETIONOVERRUN", "CONFERENCEFULL", "DIALBILLING", "DIALDIALTONE", "DIALPROMPT", "DIALQUIET", "INCOMPATIBLEAPIVERSION", "INCOMPATIBLEEXTVERSION", "INIFILECORRUPT", "INUSE", "INVALADDRESS", // 0x80000010 "INVALADDRESSID", "INVALADDRESSMODE", "INVALADDRESSSTATE", "INVALAPPHANDLE", "INVALAPPNAME", "INVALBEARERMODE", "INVALCALLCOMPLMODE", "INVALCALLHANDLE", "INVALCALLPARAMS", "INVALCALLPRIVILEGE", "INVALCALLSELECT", "INVALCALLSTATE", "INVALCALLSTATELIST", "INVALCARD", "INVALCOMPLETIONID", "INVALCONFCALLHANDLE", // 0x80000020 "INVALCONSULTCALLHANDLE", "INVALCOUNTRYCODE", "INVALDEVICECLASS", "INVALDEVICEHANDLE", "INVALDIALPARAMS", "INVALDIGITLIST", "INVALDIGITMODE", "INVALDIGITS", "INVALEXTVERSION", "INVALGROUPID", "INVALLINEHANDLE", "INVALLINESTATE", "INVALLOCATION", "INVALMEDIALIST", "INVALMEDIAMODE", "INVALMESSAGEID", // 0x80000030 "inval err value (0x80000031)", // 0x80000031 isn't valid err code "INVALPARAM", "INVALPARKID", "INVALPARKMODE", "INVALPOINTER", "INVALPRIVSELECT", "INVALRATE", "INVALREQUESTMODE", "INVALTERMINALID", "INVALTERMINALMODE", "INVALTIMEOUT", "INVALTONE", "INVALTONELIST", "INVALTONEMODE", "INVALTRANSFERMODE", "LINEMAPPERFAILED", // 0x80000040 "NOCONFERENCE", "NODEVICE", "NODRIVER", "NOMEM", "NOREQUEST", "NOTOWNER", "NOTREGISTERED", "OPERATIONFAILED", "OPERATIONUNAVAIL", "RATEUNAVAIL", "RESOURCEUNAVAIL", "REQUESTOVERRUN", "STRUCTURETOOSMALL", "TARGETNOTFOUND", "TARGETSELF", "UNINITIALIZED", // 0x80000050 "USERUSERINFOTOOBIG", "REINIT", "ADDRESSBLOCKED", "BILLINGREJECTED", "INVALFEATURE", "NOMULTIPLEINSTANCE", "INVALAGENTID", "INVALAGENTGROUP", "INVALPASSWORD", "INVALAGENTSTATE", "INVALAGENTACTIVITY", "DIALVOICEDETECT" }; char *aszPhoneErrors[] = { "SUCCESS", "ALLOCATED", "BADDEVICEID", "INCOMPATIBLEAPIVERSION", "INCOMPATIBLEEXTVERSION", "INIFILECORRUPT", "INUSE", "INVALAPPHANDLE", "INVALAPPNAME", "INVALBUTTONLAMPID", "INVALBUTTONMODE", "INVALBUTTONSTATE", "INVALDATAID", "INVALDEVICECLASS", "INVALEXTVERSION", "INVALHOOKSWITCHDEV", "INVALHOOKSWITCHMODE", // 0x90000010 "INVALLAMPMODE", "INVALPARAM", "INVALPHONEHANDLE", "INVALPHONESTATE", "INVALPOINTER", "INVALPRIVILEGE", "INVALRINGMODE", "NODEVICE", "NODRIVER", "NOMEM", "NOTOWNER", "OPERATIONFAILED", "OPERATIONUNAVAIL", "inval err value (0x9000001e)", // 0x9000001e isn't valid err code "RESOURCEUNAVAIL", "REQUESTOVERRUN", // 0x90000020 "STRUCTURETOOSMALL", "UNINITIALIZED", "REINIT" }; char *aszTapiErrors[] = { "SUCCESS", "DROPPED", "NOREQUESTRECIPIENT", "REQUESTQUEUEFULL", "INVALDESTADDRESS", "INVALWINDOWHANDLE", "INVALDEVICECLASS", "INVALDEVICEID", "DEVICECLASSUNAVAIL", "DEVICEIDUNAVAIL", "DEVICEINUSE", "DESTBUSY", "DESTNOANSWER", "DESTUNAVAIL", "UNKNOWNWINHANDLE", "UNKNOWNREQUESTID", "REQUESTFAILED", "REQUESTCANCELLED", "INVALPOINTER" }; char * PASCAL MapResultCodeToText( LONG lResult, char *pszResult ) { if (lResult == 0) { wsprintf (pszResult, "SUCCESS"); } else if (lResult > 0) { wsprintf (pszResult, "x%x (completing async)", lResult); } else if (((DWORD) lResult) <= LINEERR_DIALVOICEDETECT) { lResult &= 0x0fffffff; wsprintf (pszResult, "LINEERR_%s", aszLineErrors[lResult]); } else if (((DWORD) lResult) <= PHONEERR_REINIT) { if (((DWORD) lResult) >= PHONEERR_ALLOCATED) { lResult &= 0x0fffffff; wsprintf (pszResult, "PHONEERR_%s", aszPhoneErrors[lResult]); } else { goto MapResultCodeToText_badErrorCode; } } else if (((DWORD) lResult) <= ((DWORD) TAPIERR_DROPPED) && ((DWORD) lResult) >= ((DWORD) TAPIERR_INVALPOINTER)) { lResult = ~lResult + 1; wsprintf (pszResult, "TAPIERR_%s", aszTapiErrors[lResult]); } else { MapResultCodeToText_badErrorCode: wsprintf (pszResult, "inval error value (x%x)"); } return pszResult; } #endif #if DBG void DumpMemoryList() { PMYMEMINFO pHold; if (gpMemFirst == NULL) { LOG((TL_ERROR, "All memory deallocated")); return; } pHold = gpMemFirst; while (pHold) { LOG((TL_ERROR, "DumpMemoryList: %p not freed - LINE %d FILE %s!", pHold+1, pHold->dwLine, pHold->pszFile)); pHold = pHold->pNext; } LOG((TL_ERROR, "MEMORY LEAKS ALMOST ALWAYS INDICATE A REFERENCE COUNT PROBLEM")); LOG((TL_ERROR, "...except for the leaks in client.cpp")); if (gbBreakOnLeak) { DebugBreak(); } } #endif HRESULT LineCreateAgent( HLINE hLine, PWSTR pszAgentID, PWSTR pszAgentPIN, LPHAGENT lphAgent // Return value ) { DWORD hpAgentHandle = CreateHandleTableEntry((ULONG_PTR)lphAgent); // // the agent handle is filled when callback is called. until then, clear its value // *lphAgent = 0; FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lCreateAgent), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) pszAgentID, (ULONG_PTR) pszAgentPIN, hpAgentHandle, }, { Dword, Dword, lpszW, lpszW, Dword } }; if ( NULL == pszAgentID ) { funcArgs.Args[2] = TAPI_NO_DATA; funcArgs.ArgTypes[2] = Dword; } if ( NULL == pszAgentPIN ) { funcArgs.Args[3] = TAPI_NO_DATA; funcArgs.ArgTypes[3] = Dword; } HRESULT hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineCreateAgent")); // // if failed, delete the handle table entry now. otherwise it will be deleted by the callback // if (FAILED(hr)) { DeleteHandleTableEntry(hpAgentHandle); } return hr; } LONG WINAPI lineSetAgentMeasurementPeriod( HLINE hLine, HAGENT hAgent, DWORD dwMeasurementPeriod ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetAgentMeasurementPeriod), { (ULONG_PTR) hLine, (ULONG_PTR) hAgent, (ULONG_PTR) dwMeasurementPeriod }, { Dword, Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetAgentMeasurementPeriod")); } LONG WINAPI lineGetAgentInfo( HLINE hLine, HAGENT hAgent, LPLINEAGENTINFO lpAgentInfo // Returned structure ) { DWORD hpAgentInfo = CreateHandleTableEntry((ULONG_PTR)lpAgentInfo); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentInfo), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) hAgent, hpAgentInfo, // pass the actual ptr (for ppproc) (ULONG_PTR) lpAgentInfo // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct } }; HRESULT hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetAgentInfo")); if (FAILED(hr)) { DeleteHandleTableEntry(hpAgentInfo); } return hr; } HRESULT LineCreateAgentSession( HLINE hLine, HAGENT hAgent, PWSTR pszAgentPIN, DWORD dwWorkingAddressID, LPGUID lpGroupID, HAGENTSESSION *phAgentSession // Return value ) { DWORD hpAgentSession = CreateHandleTableEntry((ULONG_PTR)phAgentSession); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 8, lCreateAgentSession), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) hAgent, (ULONG_PTR) pszAgentPIN, (ULONG_PTR) dwWorkingAddressID, (ULONG_PTR) lpGroupID, // GroupID GUID (ULONG_PTR) sizeof(GUID), // GroupID GUID (size) hpAgentSession }, { Dword, Dword, Dword, lpszW, Dword, lpSet_SizeToFollow, // GroupID GUID Size, // GroupID GUID Dword } }; if ( NULL == pszAgentPIN ) { funcArgs.Args[3] = TAPI_NO_DATA; funcArgs.ArgTypes[3] = Dword; } HRESULT hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineCreateAgentSession")); // // if we failed, remove handle table entry now. otherwise it will be // removed by the callback // if (FAILED(hr)) { DeleteHandleTableEntry(hpAgentSession); } return hr; } LONG WINAPI lineGetAgentSessionInfo( HLINE hLine, HAGENTSESSION hAgentSession, LPLINEAGENTSESSIONINFO lpAgentSessionInfo // Returned structure ) { DWORD hpAgentSessionInfo = CreateHandleTableEntry((ULONG_PTR)lpAgentSessionInfo); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentSessionInfo), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) hAgentSession, hpAgentSessionInfo, // pass the actual ptr (for ppproc) (ULONG_PTR) lpAgentSessionInfo // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct } }; HRESULT hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetAgentSessionInfo")); // // if failed, clear handle table now. otherwise the callback will do this. // if (FAILED(hr)) { DeleteHandleTableEntry(hpAgentSessionInfo); } return hr; } LONG WINAPI lineSetAgentSessionState( HLINE hLine, HAGENTSESSION hAgentSession, DWORD dwAgentState, DWORD dwNextAgentState ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 4, lSetAgentSessionState), { (ULONG_PTR) hLine, (ULONG_PTR) hAgentSession, dwAgentState, dwNextAgentState }, { Dword, Dword, Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetAgentSessionState")); } LONG WINAPI lineSetQueueMeasurementPeriod( HLINE hLine, DWORD dwQueueID, DWORD dwMeasurementPeriod ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 3, lSetQueueMeasurementPeriod), { (ULONG_PTR) hLine, dwQueueID, dwMeasurementPeriod }, { Dword, Dword, Dword } }; return mapTAPIErrorCode(DOFUNC (&funcArgs, "lineSetQueueMeasurementPeriod")); } LONG WINAPI lineGetQueueInfo( HLINE hLine, DWORD dwQueueID, LPLINEQUEUEINFO lpQueueInfo // Returned structure ) { DWORD hpQueueInfo = CreateHandleTableEntry((ULONG_PTR)lpQueueInfo); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetQueueInfo), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, dwQueueID, hpQueueInfo, // pass the actual ptr (for ppproc) (ULONG_PTR) lpQueueInfo // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct } }; HRESULT hr = mapTAPIErrorCode(DOFUNC (&funcArgs, "lineGetQueueInfo")); // // if we failed, cleanup now. otherwise the callback will. // if (FAILED(hr)) { DeleteHandleTableEntry(hpQueueInfo); } return hr; } // Proxy message - LINEPROXYREQUEST_GETGROUPLIST : struct - GetGroupList HRESULT LineGetGroupList( HLINE hLine, LPLINEAGENTGROUPLIST * ppGroupList // Returned structure ) { HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof(LINEAGENTGROUPLIST) + 500; *ppGroupList = (LPLINEAGENTGROUPLIST) ClientAlloc( dwSize ); if (NULL == *ppGroupList) { return E_OUTOFMEMORY; } (*ppGroupList)->dwTotalSize = dwSize; DWORD hpGroupList = CreateHandleTableEntry( (ULONG_PTR)*ppGroupList ); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 4, lGetGroupList), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, hpGroupList, // pass the actual ptr (for ppproc) (ULONG_PTR) *ppGroupList // pass data }, { Dword, Dword, Dword, lpGet_Struct, } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetGroupList"); if (lResult > 0) // async reply { hr = WaitForReply( lResult ); if ((hr == S_OK)) { if (((*ppGroupList)->dwNeededSize > (*ppGroupList)->dwTotalSize)) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "lineGetGroupList failed - buffer too small")); dwSize = (*ppGroupList)->dwNeededSize; DeleteHandleTableEntry(hpGroupList); hpGroupList = 0; ClientFree( *ppGroupList ); *ppGroupList = NULL; *ppGroupList = (LPLINEAGENTGROUPLIST) ClientAlloc( dwSize ); if (*ppGroupList == NULL) { LOG((TL_ERROR, "lineGetGroupList - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { (*ppGroupList)->dwTotalSize = dwSize; _ASSERTE(0 == hpGroupList); hpGroupList = CreateHandleTableEntry((ULONG_PTR)*ppGroupList); if (0 == hpGroupList) { LOG((TL_ERROR, "lineGetGroupList - failed to create a handle")); ClientFree( *ppGroupList ); hr = E_OUTOFMEMORY; break; } funcArgs.Args[2] = hpGroupList; funcArgs.Args[3] = (ULONG_PTR)*ppGroupList; } } else { // // WaitForReply succeeded and the buffer was big enough // break; } } // WaitforReply succeeded else { // // WaitForReply failed // LOG((TL_ERROR, "lineGetGroupList - WaitForReply failed")); break; } } else // failed sync { LOG((TL_ERROR, "lineGetGroupList - failed sync")); hr = mapTAPIErrorCode(lResult); break; } } // end while(TRUE) DeleteHandleTableEntry(hpGroupList); hpGroupList = 0; LOG((TL_ERROR, "lineGetGroupList - completed hr %lx", hr)); return hr; } HRESULT lineGetQueueList( HLINE hLine, LPGUID lpGroupID, LPLINEQUEUELIST * ppQueueList // Returned structure ) { LOG((TL_TRACE, "lineGetQueueList - enter")); HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof(LINEQUEUELIST) + 500; *ppQueueList = (LPLINEQUEUELIST) ClientAlloc( dwSize ); if (NULL == *ppQueueList) { return E_OUTOFMEMORY; } (*ppQueueList)->dwTotalSize = dwSize; DWORD hpQueueRequest = CreateHandleTableEntry((ULONG_PTR)*ppQueueList); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 6, lGetQueueList), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) lpGroupID, // GroupID GUID (ULONG_PTR) sizeof(GUID), // GroupID GUID (size) hpQueueRequest, // pass the actual ptr (for ppproc) (ULONG_PTR) *ppQueueList // pass data }, { Dword, Dword, lpSet_SizeToFollow, // GroupID GUID Size, // GroupID GUID (size) Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetQueueList"); if (lResult > 0) { hr = WaitForReply( lResult ); if ((hr == S_OK) ) { if ((*ppQueueList)->dwNeededSize > (*ppQueueList)->dwTotalSize) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "lineGetQueueList failed - buffer to small")); dwSize = (*ppQueueList)->dwNeededSize; DeleteHandleTableEntry(hpQueueRequest); hpQueueRequest = 0; ClientFree( *ppQueueList ); *ppQueueList = NULL; *ppQueueList = (LPLINEQUEUELIST) ClientAlloc( dwSize ); if (*ppQueueList == NULL) { LOG((TL_ERROR, "lineGetQueueList - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { hpQueueRequest = CreateHandleTableEntry((ULONG_PTR)*ppQueueList); (*ppQueueList)->dwTotalSize = dwSize; funcArgs.Args[4] = hpQueueRequest; funcArgs.Args[5] = (ULONG_PTR)*ppQueueList; } } // buffer too small else { // // everything is fine and dandy. nothing else left to do. // break; } } else { // // error case. we have hr, break out. we should really not be // here, since we checked lResult > 0 above // break; } } else // failed sync { LOG((TL_ERROR, "lineGetQueueList - failed sync")); hr = mapTAPIErrorCode(lResult); break; } } // end while(TRUE) DeleteHandleTableEntry(hpQueueRequest); hpQueueRequest = 0; LOG((TL_TRACE, "lineGetQueueList - finished hr = %lx", hr)); return hr; } LONG WINAPI lineGetAgentSessionList( HLINE hLine, HAGENT hAgent, LPLINEAGENTSESSIONLIST * ppSessionList // Returned structure ) { HRESULT hr = S_OK; long lResult; DWORD dwSize = sizeof(LINEAGENTSESSIONLIST) + 500; *ppSessionList = (LPLINEAGENTSESSIONLIST) ClientAlloc( dwSize ); if (NULL == *ppSessionList) { return E_OUTOFMEMORY; } (*ppSessionList)->dwTotalSize = dwSize; DWORD hpSessionList = CreateHandleTableEntry((ULONG_PTR)*ppSessionList); FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | ASYNC | 5, lGetAgentSessionList), { GetFunctionIndex(lineDevSpecificPostProcess), (ULONG_PTR) hLine, (ULONG_PTR) hAgent, hpSessionList, // pass the actual ptr (for ppproc) (ULONG_PTR) *ppSessionList // pass data }, { Dword, Dword, Dword, Dword, lpGet_Struct } }; while (TRUE) { lResult = DOFUNC (&funcArgs, "lineGetAgentSessionList"); if (lResult > 0) { hr = WaitForReply( lResult ); if ((hr == S_OK) && ((*ppSessionList)->dwNeededSize > (*ppSessionList)->dwTotalSize)) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "lineGetAgentSessionList failed - buffer to small")); dwSize = (*ppSessionList)->dwNeededSize; DeleteHandleTableEntry(hpSessionList); hpSessionList = 0; ClientFree( *ppSessionList ); *ppSessionList = NULL; *ppSessionList = (LPLINEAGENTSESSIONLIST) ClientAlloc( dwSize ); if (*ppSessionList == NULL) { LOG((TL_ERROR, "lineGetAgentSessionList - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { hpSessionList = CreateHandleTableEntry((ULONG_PTR)*ppSessionList); (*ppSessionList)->dwTotalSize = dwSize; funcArgs.Args[3] = hpSessionList; funcArgs.Args[4] = (ULONG_PTR)*ppSessionList; } } else { // // either hr is not ok or hr is ok and the buffer was sufficient. // in both cases, nothing much we need to do here, so break out // break; } } else // failed sync { LOG((TL_ERROR, "lineGetAgentSessionListt - failed sync")); hr = mapTAPIErrorCode(lResult); break; } } // end while(TRUE) DeleteHandleTableEntry(hpSessionList); hpSessionList = 0; LOG((TL_TRACE, "lineGetAgentSessionListt - finish. hr = %lx", hr)); return hr; } HRESULT LineCreateMSPInstance( HLINE hLine, DWORD dwAddressID ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 2, lCreateMSPInstance), { (ULONG_PTR) hLine, dwAddressID }, { Dword, Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineCreateMSPInstance") ); } HRESULT LineCloseMSPInstance( HLINE hLine ) { FUNC_ARGS funcArgs = { MAKELONG (LINE_FUNC | SYNC | 1, lCloseMSPInstance), { (ULONG_PTR) hLine }, { Dword } }; return mapTAPIErrorCode( DOFUNC (&funcArgs, "lineCloseMSPInstance") ); } /**/ HRESULT mapTAPIErrorCode(long lErrorCode) { HRESULT hr; // Check if it's async if (lErrorCode > 0) { hr = lErrorCode; } else { switch(lErrorCode) { // // Sucess codes - ie 0 // case TAPI_SUCCESS: // case LINEERR_SUCCESS: // The operation completed successfully. // case PHONEERR_SUCCESS: // The operation completed successfully // case TAPIERR_CONNECTED: // The request was accepted hr = S_OK; break; // // Serious errors - Somethings very wrong in TAPI3 ! // // Bad handles !! case LINEERR_INVALAPPHANDLE: // Invalid TAPI line application handle case LINEERR_INVALCALLHANDLE: // Invalid call handle case LINEERR_INVALCONFCALLHANDLE: // Invalid conference call handle case LINEERR_INVALCONSULTCALLHANDLE: // Invalid consultation call handle case LINEERR_INVALDEVICEHANDLE: // Invalid device handle case LINEERR_INVALLINEHANDLE: // Invalid line handle case LINEERR_BADDEVICEID: // Invalid line device ID case LINEERR_INCOMPATIBLEAPIVERSION: // Incompatible API version case LINEERR_INVALADDRESSID: // Invalid address ID case LINEERR_INVALADDRESSMODE: // Invalid address mode case LINEERR_INVALAPPNAME: // Invalid application name case LINEERR_INVALCALLSELECT: // Invalid call select parameter case LINEERR_INVALEXTVERSION: // Invalid extension version case LINEERR_INVALTERMINALID: // Invalid terminal ID case LINEERR_INVALTERMINALMODE: // Invalid terminal mode case LINEERR_LINEMAPPERFAILED: // No device matches the specified requirements case LINEERR_UNINITIALIZED: // The telephony service has not been initialized case LINEERR_NOMULTIPLEINSTANCE: // You cannot have two instances of the same service provider case PHONEERR_INVALAPPHANDLE: // Invalid TAPI phone application handle case PHONEERR_INVALPHONEHANDLE: // Invalid phone handle case PHONEERR_BADDEVICEID: // Invalid phone device ID case PHONEERR_INCOMPATIBLEAPIVERSION:// Incompatible API version case PHONEERR_INVALEXTVERSION: // Invalid extension version case PHONEERR_INVALAPPNAME: // Invalid application name case PHONEERR_UNINITIALIZED: // The telephony service has not been initialized case TAPIERR_INVALDEVICEID: // Invalid device ID case TAPIERR_UNKNOWNWINHANDLE: // Unknown window handle case TAPIERR_UNKNOWNREQUESTID: // Unknown request ID case TAPIERR_INVALWINDOWHANDLE: // Invalid window handle // Memory/ Allocation errors case LINEERR_STRUCTURETOOSMALL: // The application failed to allocate sufficient memory for the // minimum structure size case PHONEERR_STRUCTURETOOSMALL: // The application failed to allocate sufficient memory for the // minimum structure size //_ASSERTE( 0 ); hr = E_UNEXPECTED; break; case PHONEERR_INIFILECORRUPT: // The TAPI configuration information is unusable case LINEERR_INIFILECORRUPT: // The TAPI configuration information is unusable hr = TAPI_E_REGISTRY_SETTING_CORRUPT; break; // Bad Pointers case LINEERR_INVALPOINTER: // Invalid pointer case PHONEERR_INVALPOINTER: // Invalid pointer case TAPIERR_INVALPOINTER: // Invalid pointer hr = E_POINTER; break; // // Unexpected Errors // case LINEERR_OPERATIONFAILED: // The operation failed for unspecified reasons case PHONEERR_OPERATIONFAILED: // The operation failed for unspecified reasons case LINEERR_INCOMPATIBLEEXTVERSION: // Incompatible extension version case PHONEERR_INCOMPATIBLEEXTVERSION:// Incompatible extension version hr = TAPI_E_OPERATIONFAILED; break; case LINEERR_ALLOCATED: // The line device is already in use case PHONEERR_ALLOCATED: // The phone device is already in use hr = TAPI_E_ALLOCATED; break; case LINEERR_BEARERMODEUNAVAIL: // The requested bearer mode is unavailable case LINEERR_INVALBEARERMODE: // Invalid bearer mode hr = TAPI_E_INVALMODE; break; case LINEERR_CALLUNAVAIL: // No call appearance available hr = TAPI_E_CALLUNAVAIL; break; case LINEERR_COMPLETIONOVERRUN: // Too many call completions outstanding hr = TAPI_E_COMPLETIONOVERRUN; break; case LINEERR_CONFERENCEFULL: // The conference is full hr = TAPI_E_CONFERENCEFULL; break; case LINEERR_DIALBILLING: // The '$' dial modifier is not supported case LINEERR_DIALDIALTONE: // The 'W' dial modifier is not supported case LINEERR_DIALPROMPT: // The '?' dial modifier is not supported case LINEERR_DIALQUIET: // The '@' dial modifier is not supported case LINEERR_DIALVOICEDETECT: // The ':' dial modifier is not supported hr = TAPI_E_DIALMODIFIERNOTSUPPORTED; break; case LINEERR_RESOURCEUNAVAIL: // A resource needed to fulfill the request is not available case PHONEERR_RESOURCEUNAVAIL: // A resource needed to fulfill the request is not available hr = TAPI_E_RESOURCEUNAVAIL; break; case LINEERR_INUSE: // The line device is already in use case PHONEERR_INUSE: // The phone device is already in use case TAPIERR_DEVICEINUSE: // The device is already in use hr = TAPI_E_INUSE; break; case LINEERR_INVALADDRESS: // The phone number is invalid or not properly formatted case TAPIERR_INVALDESTADDRESS: // The phone number is invalid or improperly formatted hr = TAPI_E_INVALADDRESS; break; case LINEERR_INVALADDRESSSTATE: // Operation not permitted in current address state case LINEERR_INVALLINESTATE: // Operation not permitted in current line state case PHONEERR_INVALPHONESTATE: // Operation not permitted in current phone state hr = TAPI_E_INVALADDRESSSTATE; break; case LINEERR_INVALADDRESSTYPE: // The specified address type is not supported by this address. hr = TAPI_E_INVALADDRESSTYPE; break; case LINEERR_INVALCALLCOMPLMODE: // Invalid call completion mode hr = TAPI_E_INVALMODE; break; case LINEERR_INVALCALLPARAMS: // Invalid LINECALLPARAMS structure hr = TAPI_E_INVALCALLPARAMS; break; case LINEERR_INVALCALLPRIVILEGE: // Invalid call privilege case LINEERR_INVALPRIVSELECT: // Invalid call privilege selection hr = TAPI_E_INVALCALLPRIVILEGE; break; case LINEERR_INVALCALLSTATE: // Operation not permitted in current call state hr = TAPI_E_INVALCALLSTATE; break; case LINEERR_INVALCALLSTATELIST: // Invalid call state list hr = TAPI_E_INVALLIST; break; case LINEERR_INVALCARD: // Invalid calling card ID hr = TAPI_E_INVALCARD; break; case LINEERR_INVALCOMPLETIONID: // Invalid call completion ID hr = TAPI_E_INVALCOMPLETIONID; break; case LINEERR_INVALCOUNTRYCODE: // Invalid country code hr = TAPI_E_INVALCOUNTRYCODE; break; case LINEERR_INVALDEVICECLASS: // Invalid device class identifier case PHONEERR_INVALDEVICECLASS: // Invalid device class identifier case TAPIERR_INVALDEVICECLASS: case TAPIERR_DEVICECLASSUNAVAIL: // The device class is unavailable case TAPIERR_DEVICEIDUNAVAIL: // The specified device is unavailable hr = TAPI_E_INVALDEVICECLASS; break; case LINEERR_INVALDIALPARAMS: // Invalid dialing parameters hr = TAPI_E_INVALDIALPARAMS; break; case LINEERR_INVALDIGITLIST: // Invalid digit list hr = TAPI_E_INVALLIST; break; case LINEERR_INVALDIGITMODE: // Invalid digit mode hr = TAPI_E_INVALMODE; break; case LINEERR_INVALDIGITS: // Invalid digits hr = TAPI_E_INVALDIGITS; break; case LINEERR_INVALGROUPID: // Invalid group pickup ID hr = TAPI_E_INVALGROUPID; break; case LINEERR_INVALLOCATION: // Invalid location ID hr = TAPI_E_INVALLOCATION; break; case LINEERR_INVALMEDIALIST: // Invalid media list hr = TAPI_E_INVALLIST; break; case LINEERR_INVALMEDIAMODE: // Invalid media mode hr = TAPI_E_INVALIDMEDIATYPE; break; case LINEERR_INVALMESSAGEID: // Invalid message ID hr = TAPI_E_INVALMESSAGEID; break; case LINEERR_INVALPARAM: // Invalid parameter hr = E_INVALIDARG; break; case LINEERR_INVALPARKID: // Invalid park ID hr = TAPI_E_INVALPARKID; break; case LINEERR_INVALPARKMODE: // Invalid park mode case PHONEERR_INVALPARAM: // Invalid parameter hr = TAPI_E_INVALMODE; break; case LINEERR_INVALRATE: // Invalid rate case LINEERR_RATEUNAVAIL: // The requested data rate is not available hr = TAPI_E_INVALRATE; break; case LINEERR_INVALREQUESTMODE: // Invalid request mode hr = TAPI_E_INVALMODE; break; case LINEERR_INVALTIMEOUT: // Invalid timeout value hr = TAPI_E_INVALTIMEOUT; break; case LINEERR_INVALTONE: // Invalid tone hr = TAPI_E_INVALTONE; break; case LINEERR_INVALTONELIST: // Invalid tone list hr = TAPI_E_INVALLIST; break; case LINEERR_INVALTONEMODE: // Invalid tone mode case LINEERR_INVALTRANSFERMODE: // Invalid transfer mode case PHONEERR_INVALBUTTONMODE: // Invalid button mode case PHONEERR_INVALHOOKSWITCHMODE: // Invalid hookswitch mode case PHONEERR_INVALLAMPMODE: // Invalid lamp mode case PHONEERR_INVALRINGMODE: // Invalid ring mode hr = TAPI_E_INVALMODE; break; case LINEERR_NOCONFERENCE: // The call is not part of a conference hr = TAPI_E_NOCONFERENCE; break; case LINEERR_NODEVICE: // The device was removed, or the device class is not recognized case PHONEERR_NODEVICE: // The device was removed, or the device class is not recognized hr = TAPI_E_NODEVICE; break; case LINEERR_NODRIVER: // The service provider was removed case PHONEERR_NODRIVER: // The service provider was removed hr = TAPI_E_NODRIVER; break; case LINEERR_NOMEM: // Insufficient memory available to complete the operation case PHONEERR_NOMEM: // Insufficient memory available to complete the operation hr = E_OUTOFMEMORY; break; case LINEERR_NOREQUEST: // No Assisted Telephony requests are pending hr = TAPI_E_NOREQUEST; break; case LINEERR_NOTOWNER: // The application is does not have OWNER privilege on the call case PHONEERR_NOTOWNER: // The application is does not have OWNER privilege on the phone hr = TAPI_E_NOTOWNER; break; case LINEERR_NOTREGISTERED: // The application is not registered to handle requests hr = TAPI_E_NOTREGISTERED; break; case LINEERR_OPERATIONUNAVAIL: // The operation is not supported by the underlying service provider case PHONEERR_OPERATIONUNAVAIL: // The operation is not supported by the underlying service provider hr = TAPI_E_NOTSUPPORTED; break; case LINEERR_REQUESTOVERRUN: // The request queue is already full case PHONEERR_REQUESTOVERRUN: // The request queue is already full hr= TAPI_E_REQUESTOVERRUN; break; case LINEERR_SERVICE_NOT_RUNNING: // The Telephony service could not be contacted case PHONEERR_SERVICE_NOT_RUNNING: // The Telephony service could not be contacted hr = TAPI_E_SERVICE_NOT_RUNNING; break; case LINEERR_TARGETNOTFOUND: // The call handoff failed because the specified target was not found hr = TAPI_E_TARGETNOTFOUND; break; case LINEERR_TARGETSELF: // No higher priority target exists for the call handoff hr = TAPI_E_TARGETSELF; break; case LINEERR_USERUSERINFOTOOBIG: // The amount of user-user info exceeds the maximum permitted hr = TAPI_E_USERUSERINFOTOOBIG; break; case LINEERR_REINIT: // The operation cannot be completed until all TAPI applications // call lineShutdown case PHONEERR_REINIT: // The operation cannot be completed until all TAPI applications hr = TAPI_E_REINIT; break; case LINEERR_ADDRESSBLOCKED: // You are not permitted to call this number hr = TAPI_E_ADDRESSBLOCKED; break; case LINEERR_BILLINGREJECTED: // The calling card number or other billing information was rejected hr = TAPI_E_BILLINGREJECTED; break; case LINEERR_INVALFEATURE: // Invalid device-specific feature hr = TAPI_E_INVALFEATURE; break; case LINEERR_INVALAGENTID: // Invalid agent ID hr = TAPI_E_CALLCENTER_INVALAGENTID; break; case LINEERR_INVALAGENTGROUP: // Invalid agent group hr = TAPI_E_CALLCENTER_INVALAGENTGROUP; break; case LINEERR_INVALPASSWORD: // Invalid agent password hr = TAPI_E_CALLCENTER_INVALPASSWORD; break; case LINEERR_INVALAGENTSTATE: // Invalid agent state hr = TAPI_E_CALLCENTER_INVALAGENTSTATE; break; case LINEERR_INVALAGENTACTIVITY: // Invalid agent activity hr = TAPI_E_CALLCENTER_INVALAGENTACTIVITY; break; case PHONEERR_INVALPRIVILEGE: // Invalid privilege hr = TAPI_E_INVALPRIVILEGE; break; case PHONEERR_INVALBUTTONLAMPID: // Invalid button or lamp ID hr = TAPI_E_INVALBUTTONLAMPID; break; case PHONEERR_INVALBUTTONSTATE: // Invalid button state hr = TAPI_E_INVALBUTTONSTATE; break; case PHONEERR_INVALDATAID: // Invalid data segment ID hr = TAPI_E_INVALDATAID; break; case PHONEERR_INVALHOOKSWITCHDEV: // Invalid hookswitch device ID hr = TAPI_E_INVALHOOKSWITCHDEV; break; case TAPIERR_DROPPED: // The call was disconnected hr = TAPI_E_DROPPED; break; case TAPIERR_NOREQUESTRECIPIENT: // No program is available to handle the request hr = TAPI_E_NOREQUESTRECIPIENT; break; case TAPIERR_REQUESTQUEUEFULL: // The queue of call requests is full hr = TAPI_E_REQUESTQUEUEFULL; break; case TAPIERR_DESTBUSY: // The called number is busy hr = TAPI_E_DESTBUSY; break; case TAPIERR_DESTNOANSWER: // The called party does not answer hr = TAPI_E_DESTNOANSWER; break; case TAPIERR_DESTUNAVAIL: // The called number could not be reached hr = TAPI_E_DESTUNAVAIL; break; case TAPIERR_REQUESTFAILED: // The request failed for unspecified reasons hr = TAPI_E_REQUESTFAILED; break; case TAPIERR_REQUESTCANCELLED: // The request was cancelled hr = TAPI_E_REQUESTCANCELLED; break; default: hr = E_FAIL; break; } // End switch(lErrorCode) } return hr; } HRESULT UnloadTapi32( BOOL bShutdown ) { EnterCriticalSection( &gcsTapi32 ); if ( bShutdown ) { if ( NULL == gpShutdown ) { gpShutdown = (LINESHUTDOWNPROC)GetProcAddress( ghTapi32, "lineShutdown" ); if ( NULL == gpShutdown ) { LeaveCriticalSection( &gcsTapi32 ); return E_FAIL; } (gpShutdown)(ghLineApp); } } ghLineApp = NULL; gpShutdown = NULL; gpInitialize = NULL; if ( NULL != ghTapi32 ) { FreeLibrary( ghTapi32 ); } LeaveCriticalSection( &gcsTapi32 ); return S_OK; } HRESULT LoadTapi32( BOOL bInitialize ) { HRESULT hr; DWORD dwNumDevs; DWORD dwAPIVersion = TAPI_CURRENT_VERSION; EnterCriticalSection( &gcsTapi32 ); ghTapi32 = LoadLibrary("tapi32.dll"); // // ll failed // if ( NULL == ghTapi32 ) { LeaveCriticalSection( &gcsTapi32 ); return E_FAIL; } if ( bInitialize ) { if ( NULL == gpInitialize ) { gpInitialize = (LINEINITIALIZEPROC)GetProcAddress( ghTapi32, "lineInitializeExW" ); if ( NULL == gpInitialize ) { LOG((TL_ERROR, "LoadTapi32 - getprocaddres failed 1")); LeaveCriticalSection( &gcsTapi32 ); UnloadTapi32( FALSE ); return E_FAIL; } } LINEINITIALIZEEXPARAMS lei; ZeroMemory( &lei, sizeof(lei) ); lei.dwTotalSize = sizeof(lei); lei.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT; hr = (gpInitialize)( &ghLineApp, NULL, NULL, L"tapi3helper", &dwNumDevs, &dwAPIVersion, &lei ); if ( !SUCCEEDED(hr) ) { ghLineApp = NULL; LOG((TL_ERROR, "LoadTapi32 - lineinit failed")); LeaveCriticalSection( &gcsTapi32 ); UnloadTapi32( FALSE ); return mapTAPIErrorCode( hr ); } } LeaveCriticalSection( &gcsTapi32 ); return S_OK; } HRESULT TapiMakeCall( BSTR pDestAddress, BSTR pAppName, BSTR pCalledParty, BSTR pComment ) { HRESULT hr; TAPIREQUESTMAKECALLPROC pTapiMakeCall; hr = LoadTapi32( FALSE ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "Could not load TAPI32.DLL")); return hr; } pTapiMakeCall = (TAPIREQUESTMAKECALLPROC)GetProcAddress( ghTapi32, "tapiRequestMakeCallW" ); if ( NULL == pTapiMakeCall ) { LOG((TL_ERROR, "Could not get the address of tapimakecall")); UnloadTapi32( FALSE ); return E_FAIL; } hr = pTapiMakeCall( pDestAddress, pAppName, pCalledParty, pComment ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "tapimakecall failed - %lx", hr)); } UnloadTapi32( FALSE ); return hr; } HRESULT LineTranslateDialog( DWORD dwDeviceID, DWORD dwAPIVersion, HWND hwndOwner, BSTR pAddressIn ) { HRESULT hr; LINEINITIALIZEPROC pInitialize; LINETRANSLATEDIALOGPROC pTranslateDialog; hr = LoadTapi32( TRUE ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "LineTranslateDialog - load tapi32 failed")); return hr; } pTranslateDialog = (LINETRANSLATEDIALOGPROC)GetProcAddress( ghTapi32, "lineTranslateDialogW" ); if ( NULL == pTranslateDialog ) { LOG((TL_ERROR, "LineTranslateDialog - getprocaddress failed 2")); UnloadTapi32( TRUE ); return E_FAIL; } hr = (pTranslateDialog)( ghLineApp, dwDeviceID, dwAPIVersion, hwndOwner, pAddressIn ); hr = mapTAPIErrorCode( hr ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "LineTranslateDialog failed - %lx", hr)); } UnloadTapi32( TRUE ); return hr; } typedef LONG (PASCAL *LINETRANSLATEADDRESSPROC)(HLINEAPP, DWORD, DWORD, LPCWSTR, DWORD, DWORD, LPLINETRANSLATEOUTPUT); typedef LONG (PASCAL *LINEGETTRANSLATECAPSPROC)(HLINEAPP, DWORD, LPLINETRANSLATECAPS); HRESULT LineTranslateAddress( HLINEAPP hLineApp, DWORD dwDeviceID, DWORD dwAPIVersion, LPCWSTR lpszAddressIn, DWORD dwCard, DWORD dwTranslateOptions, LPLINETRANSLATEOUTPUT *ppTranslateOutput ) { LONG lResult = 0; HRESULT hr = S_OK; DWORD dwSize = sizeof(LINETRANSLATECAPS ) + 2000; LINETRANSLATEADDRESSPROC pTranslateProc; LOG((TL_TRACE, "lineTranslateAddress - enter")); hr = LoadTapi32( FALSE ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "lineTranslateAddress - load tapi32 failed")); return hr; } pTranslateProc = (LINETRANSLATEADDRESSPROC)GetProcAddress( ghTapi32, "lineTranslateAddressW" ); if ( NULL == pTranslateProc ) { LOG((TL_ERROR, "lineTranslateAddress - getprocaddress failed 2")); UnloadTapi32( FALSE ); return E_FAIL; } *ppTranslateOutput = (LPLINETRANSLATEOUTPUT) ClientAlloc( dwSize ); if (*ppTranslateOutput == NULL) { LOG((TL_ERROR, "lineTranslateAddress - ClientAlloc failed")); hr = E_OUTOFMEMORY; } else { (*ppTranslateOutput)->dwTotalSize = dwSize; while (TRUE) { lResult = (pTranslateProc)(0, dwDeviceID, dwAPIVersion, lpszAddressIn, dwCard, dwTranslateOptions, *ppTranslateOutput ); if ((lResult == 0) && ((*ppTranslateOutput)->dwNeededSize > (*ppTranslateOutput)->dwTotalSize)) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "LineGetTranslateCaps failed - buffer to small")); dwSize = (*ppTranslateOutput)->dwNeededSize; ClientFree( *ppTranslateOutput ); *ppTranslateOutput = (LPLINETRANSLATEOUTPUT) ClientAlloc( dwSize ); if (*ppTranslateOutput == NULL) { LOG((TL_ERROR, "lineTranslateAddress - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { (*ppTranslateOutput)->dwTotalSize = dwSize; } } else { hr = mapTAPIErrorCode( lResult ); break; } } // end while(TRUE) } UnloadTapi32( FALSE ); LOG((TL_TRACE, hr, "lineTranslateAddress - exit")); return hr; } HRESULT LineGetTranslateCaps( HLINEAPP hLineApp, DWORD dwAPIVersion, LPLINETRANSLATECAPS *ppTranslateCaps ) { LONG lResult = 0; HRESULT hr = S_OK; DWORD dwSize = sizeof(LINETRANSLATECAPS ) + 2000; LINEGETTRANSLATECAPSPROC pTranslateProc; LOG((TL_TRACE, "LineGetTranslateCaps - enter")); hr = LoadTapi32( FALSE ); if ( !SUCCEEDED(hr) ) { LOG((TL_ERROR, "LineGetTranslateCapsg - load tapi32 failed")); return hr; } pTranslateProc = (LINEGETTRANSLATECAPSPROC)GetProcAddress( ghTapi32, "lineGetTranslateCapsW" ); if ( NULL == pTranslateProc ) { LOG((TL_ERROR, "LineGetTranslateCaps - getprocaddress failed 2")); UnloadTapi32( FALSE ); return E_FAIL; } *ppTranslateCaps = (LPLINETRANSLATECAPS) ClientAlloc( dwSize ); if (*ppTranslateCaps == NULL) { LOG((TL_ERROR, "LineGetTranslateCaps - ClientAlloc failed")); hr = E_OUTOFMEMORY; } else { (*ppTranslateCaps)->dwTotalSize = dwSize; while (TRUE) { lResult = (pTranslateProc)(0, dwAPIVersion, *ppTranslateCaps ); if ((lResult == 0) && ((*ppTranslateCaps)->dwNeededSize > (*ppTranslateCaps)->dwTotalSize)) { // didnt Work , adjust buffer size & try again LOG((TL_INFO, "LineGetTranslateCaps failed - buffer to small")); dwSize = (*ppTranslateCaps)->dwNeededSize; ClientFree( *ppTranslateCaps ); *ppTranslateCaps = (LPLINETRANSLATECAPS) ClientAlloc( dwSize ); if (*ppTranslateCaps == NULL) { LOG((TL_ERROR, "LineGetTranslateCaps - repeat ClientAlloc failed")); hr = E_OUTOFMEMORY; break; } else { (*ppTranslateCaps)->dwTotalSize = dwSize; } } else { hr = mapTAPIErrorCode( lResult ); break; } } // end while(TRUE) } UnloadTapi32( FALSE ); LOG((TL_TRACE, hr, "LineGetTranslateCaps - exit")); return hr; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Function : GenerateHandleAndAddToHashTable // Creates a unique ULONG_PTR handle & maps this to the passed in // object via a hash table // Returns handle // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ULONG_PTR GenerateHandleAndAddToHashTable( ULONG_PTR Element) { static ULONG_PTR gNextHandle = 0; ULONG_PTR uptrHandle = 0; gpHandleHashTable->Lock(); gNextHandle = ++gNextHandle % 0x10; uptrHandle = (Element << 4) + gNextHandle; gpHandleHashTable->Insert( uptrHandle, Element ); gpHandleHashTable->Unlock(); return uptrHandle; } //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Function : RemoveHandleFromHashTable // Removes hash table entry, based on passed in handle // //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void RemoveHandleFromHashTable(ULONG_PTR dwHandle) { gpHandleHashTable->Lock(); gpHandleHashTable->Remove( (ULONG_PTR)(dwHandle) ); gpHandleHashTable->Unlock(); } ///////////////////////////////////////////////////////////////////// // // Internal event filtering functions // ///////////////////////////////////////////////////////////////////// #define LOWDWORD(ul64) ((DWORD)(ul64 & 0xffffffff)) #define HIDWORD(ul64) ((DWORD)((ul64 & 0xffffffff00000000) >> 32)) LONG WINAPI tapiSetEventFilterMasks ( DWORD dwObjType, LONG_PTR lObjectID, ULONG64 ulEventMasks ) { FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 6, tSetEventMasksOrSubMasks), { (ULONG_PTR) dwObjType, // type of object handle (ULONG_PTR) lObjectID, // object handle (ULONG_PTR) FALSE, // fSubMask (ULONG_PTR) 0, // dwSubMasks (ULONG_PTR) LOWDWORD(ulEventMasks), // ulEventMasks low (ULONG_PTR) HIDWORD(ulEventMasks), // ulEventMasks hi }, { Dword, (dwObjType == TAPIOBJ_HLINEAPP || dwObjType == TAPIOBJ_HPHONEAPP)?\ hXxxApp : Dword, Dword, Dword, Dword, Dword, } }; return (DOFUNC (&funcArgs, "tapiSetEventFilter")); } LONG WINAPI tapiSetEventFilterSubMasks ( DWORD dwObjType, LONG_PTR lObjectID, ULONG64 ulEventMasks, DWORD dwEventSubMasks ) { FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 6, tSetEventMasksOrSubMasks), { (ULONG_PTR) dwObjType, // type of object handle (ULONG_PTR) lObjectID, // object handle (ULONG_PTR) TRUE, // fSubMask (ULONG_PTR) dwEventSubMasks, // dwSubMasks (ULONG_PTR) LOWDWORD(ulEventMasks), // ulEventMasks low (ULONG_PTR) HIDWORD(ulEventMasks), // ulEventMasks hi }, { Dword, (dwObjType == TAPIOBJ_HLINEAPP || dwObjType == TAPIOBJ_HPHONEAPP)?\ hXxxApp : Dword, Dword, Dword, Dword, Dword, } }; return (DOFUNC (&funcArgs, "tapiSetEventFilter")); } LONG WINAPI tapiGetEventFilterMasks ( DWORD dwObjType, LONG_PTR lObjectID, ULONG64 * pulEventMasks ) { DWORD dwEventSubMasks; DWORD dwHiMasks; DWORD dwLowMasks; LONG lResult; FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 8, tGetEventMasksOrSubMasks), { (ULONG_PTR) dwObjType, // object type (ULONG_PTR) lObjectID, // object handles (ULONG_PTR) FALSE, // fSubMask (ULONG_PTR) &dwEventSubMasks, // &dwEventSubMasks (ULONG_PTR) 0, // ulEventMasksIn low (ULONG_PTR) 0, // ulEventMasksIn hi (ULONG_PTR) &dwLowMasks, // ulEventMasksOut low (ULONG_PTR) &dwHiMasks, // ulEventMasksOut hi }, { Dword, (dwObjType == TAPIOBJ_HLINEAPP || dwObjType == TAPIOBJ_HPHONEAPP)?\ hXxxApp : Dword, Dword, lpDword, Dword, Dword, lpDword, lpDword, } }; lResult = DOFUNC (&funcArgs, "tapiGetEventFilter"); if (lResult == 0) { *pulEventMasks = dwHiMasks; (*pulEventMasks) <<= 32; *pulEventMasks += dwLowMasks; } return lResult; } LONG WINAPI tapiGetEventFilterSubMasks ( DWORD dwObjType, LONG_PTR lObjectID, ULONG64 ulEventMasks, DWORD * pdwEventSubMasks ) { DWORD dwHiMasks; DWORD dwLowMasks; FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 8, tGetEventMasksOrSubMasks), { (ULONG_PTR) dwObjType, // object type (ULONG_PTR) lObjectID, // object handle (ULONG_PTR) TRUE, // fSubMask (ULONG_PTR) pdwEventSubMasks, // &dwEventSubMasks (ULONG_PTR) LOWDWORD(ulEventMasks), // ulEventMasksIn low (ULONG_PTR) HIDWORD(ulEventMasks), // ulEventMasksIn hi (ULONG_PTR) &dwLowMasks, // ulEventMasksOut low (ULONG_PTR) &dwHiMasks, // ulEventMasksOut hi }, { Dword, (dwObjType == TAPIOBJ_HLINEAPP || dwObjType == TAPIOBJ_HPHONEAPP)?\ hXxxApp : Dword, Dword, lpDword, Dword, Dword, lpDword, lpDword, } }; return (DOFUNC (&funcArgs, "tapiGetEventFilter")); } LONG WINAPI tapiGetPermissibleMasks ( ULONG64 * pulPermMasks ) { LONG lResult; DWORD dwLowMasks; DWORD dwHiMasks; FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 2, tGetPermissibleMasks), { (ULONG_PTR) &dwLowMasks, // ulPermMasks low (ULONG_PTR) &dwHiMasks, // ulPermMasks hi }, { lpDword, lpDword, } }; lResult = DOFUNC (&funcArgs, "tapiGetPermissibleMasks"); if (lResult == 0) { *pulPermMasks = dwHiMasks; (*pulPermMasks) <<= 32; *pulPermMasks += dwLowMasks; } return lResult; } LONG WINAPI tapiSetPermissibleMasks ( ULONG64 ulPermMasks ) { FUNC_ARGS funcArgs = { MAKELONG (TAPI_FUNC | SYNC | 2, tSetPermissibleMasks), { (ULONG_PTR)LOWDWORD(ulPermMasks), // ulPermMasks low (ULONG_PTR)HIDWORD(ulPermMasks), // ulPermMasks hi }, { Dword, Dword, } }; return (DOFUNC (&funcArgs, "tapiGetPermissibleMasks")); } BOOL WaveStringIdToDeviceId( LPWSTR pwszStringID, LPCWSTR pwszDeviceType, LPDWORD pdwDeviceId ) { // // This function converts a wave device string ID to a numeric device ID // The numeric device ID can be used in wave functions (waveOutOpen, etc) // if (!pwszDeviceType || !pwszStringID) return FALSE; LOG((TL_TRACE, "WaveStringIdToDeviceId (%S, %S) - enter", pwszStringID, pwszDeviceType)); // get the device id, based on string id and device class if ( !_wcsicmp(pwszDeviceType, L"wave/in") || !_wcsicmp(pwszDeviceType, L"wave/in/out") ) { return (MMSYSERR_NOERROR == waveInMessage( NULL, DRV_QUERYIDFROMSTRINGID, (DWORD_PTR)pwszStringID, (DWORD_PTR)pdwDeviceId)); } else if (!_wcsicmp(pwszDeviceType, L"wave/out")) { return (MMSYSERR_NOERROR == waveOutMessage( NULL, DRV_QUERYIDFROMSTRINGID, (DWORD_PTR)pwszStringID, (DWORD_PTR)pdwDeviceId)); } else if (!_wcsicmp(pwszDeviceType, L"midi/in")) { return (MMSYSERR_NOERROR == midiInMessage( NULL, DRV_QUERYIDFROMSTRINGID, (DWORD_PTR)pwszStringID, (DWORD_PTR)pdwDeviceId)); } else if (!_wcsicmp(pwszDeviceType, L"midi/out")) { return (MMSYSERR_NOERROR == midiOutMessage( NULL, DRV_QUERYIDFROMSTRINGID, (DWORD_PTR)pwszStringID, (DWORD_PTR)pdwDeviceId)); } LOG((TL_TRACE, "WaveStringIdToDeviceId (%S, %S) - failed", pwszStringID, pwszDeviceType)); return FALSE; }