|
|
/*++
Copyright (c) 1995-1996 Microsoft Corporation
Module Name:
atsp.c
Notes:
--*/
#include "atsp.h"
BOOL WINAPI DllMain( HANDLE hDLL, DWORD dwReason, LPVOID lpReserved ) { if (dwReason == DLL_PROCESS_ATTACH) { ghInst = hDLL;
#if DBG
{ HKEY hKey; DWORD dwDataSize, dwDataType; char szAtsp32DebugLevel[] = "Atsp32DebugLevel";
RegOpenKeyExA( HKEY_LOCAL_MACHINE, gszAtspKey, 0, KEY_ALL_ACCESS, &hKey );
dwDataSize = sizeof (DWORD); gdwDebugLevel=0;
RegQueryValueEx( hKey, szAtsp32DebugLevel, 0, &dwDataType, (LPBYTE) &gdwDebugLevel, &dwDataSize );
RegCloseKey (hKey); } #endif
}
return TRUE; }
void CommThread( PDRVLINE pLine ) { char buf[4]; DWORD dwThreadID = GetCurrentThreadId(), dwNumBytes; HANDLE hComm = pLine->hComm, hEvent; LPOVERLAPPED pOverlapped = &pLine->Overlapped;
DBGOUT(( 3, "CommThread (id=%d): enter, port=%s", dwThreadID, pLine->szComm ));
hEvent = pOverlapped->hEvent; buf[0] = buf[1] = '.';
//
// Loop waiting for i/o to complete (either the Write done in
// TSPI_lineMakeCall or the Reads done to retrieve status info).
// Note that TSPI_lineDrop or TSPI_lineCloseCall may set the
// event to alert us that they're tearing down the call, in
// which case we just exit.
//
for (;;) { if (WaitForSingleObject (hEvent, ATSP_TIMEOUT) == WAIT_OBJECT_0) { if (pLine->bDropInProgress == TRUE) { DBGOUT((2, "CommThread (id=%d): drop in progress")); goto CommThread_exit; }
GetOverlappedResult (hComm, pOverlapped, &dwNumBytes, FALSE); ResetEvent (hEvent); } else { DBGOUT((2, "CommThread (id=%d): wait timeout")); SetCallState (pLine, LINECALLSTATE_IDLE, 0); goto CommThread_exit; }
buf[1] &= 0x7f; // nuke the parity bit
DBGOUT(( 3, "CommThread (id=%d): read '%c'", dwThreadID, (buf[1] == '\r' ? '.' : buf[1]) ));
switch ((buf[0] << 8) + buf[1]) { case 'CT': // "CONNECT"
case 'OK': // "OK"
SetCallState (pLine, LINECALLSTATE_CONNECTED, 0); goto CommThread_exit;
case 'SY': // "BUSY"
case 'OR': // "ERROR"
case 'NO': // "NO ANSWER", "NO DIALTONE", "NO CARRIER"
SetCallState (pLine, LINECALLSTATE_IDLE, 0); goto CommThread_exit;
default:
break; }
buf[0] = buf[1];
ZeroMemory (pOverlapped, sizeof (OVERLAPPED) - sizeof (HANDLE)); if ( 0 == ReadFile (hComm, &buf[1], 1, &dwNumBytes, pOverlapped)) { DBGOUT((2, "CommThread (id=%d): fail to read from line")); goto CommThread_exit; } }
CommThread_exit:
CloseHandle (hEvent); DBGOUT((3, "CommThread (id=%d): exit", dwThreadID)); ExitThread (0); }
//
// We get a slough of C4047 (different levels of indrection) warnings down
// below in the initialization of FUNC_PARAM structs as a result of the
// real func prototypes having params that are types other than DWORDs,
// so since these are known non-interesting warnings just turn them off
//
#pragma warning (disable:4047)
//
// --------------------------- TAPI_lineXxx funcs -----------------------------
//
LONG TSPIAPI TSPI_lineClose( HDRVLINE hdLine ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine } }; FUNC_INFO info = { "TSPI_lineClose", 1, params, }; #endif
Prolog (&info); DrvFree ((PDRVLINE) hdLine); return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineCloseCall( HDRVCALL hdCall ) { PDRVLINE pLine = (PDRVLINE) hdCall; #if DBG
FUNC_PARAM params[] = { { gszhdCall, hdCall } }; FUNC_INFO info = { "TSPI_lineCloseCall", 1, params }; #endif
//
// Note that in TAPI 2.0 TSPI_lineCloseCall can get called
// without TSPI_lineDrop ever being called, so we need to
// be prepared for either case.
//
Prolog (&info); DropActiveCall (pLine); pLine->htCall = NULL; return (Epilog (&info, 0)); }
LONG TSPIAPI TSPI_lineConditionalMediaDetection( HDRVLINE hdLine, DWORD dwMediaModes, LPLINECALLPARAMS const lpCallParams ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "dwMediaModes", dwMediaModes }, { gszlpCallParams, lpCallParams } }; FUNC_INFO info = { "TSPI_lineConditionalMediaDetection", 3, params }; #endif
//
// This func is really a no-op for us, since we don't look
// for incoming calls (though we do say we support them to
// make apps happy)
//
Prolog (&info); return (Epilog (&info, 0)); }
LONG TSPIAPI TSPI_lineDrop( DRV_REQUESTID dwRequestID, HDRVCALL hdCall, LPCSTR lpsUserUserInfo, DWORD dwSize ) { PDRVLINE pLine = (PDRVLINE) hdCall; #if DBG
FUNC_PARAM params[] = { { gszdwRequestID, dwRequestID }, { gszhdCall, hdCall }, { "lpsUserUserInfo", lpsUserUserInfo }, { gszdwSize, dwSize } }; FUNC_INFO info = { "TSPI_lineDrop", 4, params }; #endif
Prolog (&info); DropActiveCall (pLine); SetCallState (pLine, LINECALLSTATE_IDLE, 0); (*gpfnCompletionProc)(dwRequestID, 0); return (Epilog (&info, dwRequestID)); }
LONG TSPIAPI TSPI_lineGetAddressCaps( DWORD dwDeviceID, DWORD dwAddressID, DWORD dwTSPIVersion, DWORD dwExtVersion, LPLINEADDRESSCAPS lpAddressCaps ) {
#if DBG
FUNC_PARAM params[] = { { gszdwDeviceID, dwDeviceID }, { "dwAddressID", dwAddressID }, { "dwTSPIVersion", dwTSPIVersion }, { "dwExtVersion", dwExtVersion }, { "lpAddressCaps", lpAddressCaps } }; FUNC_INFO info = { "TSPI_lineGetAddressCaps", 5, params }; #endif
LONG lResult = 0;
Prolog (&info);
if (dwAddressID != 0) { lResult = LINEERR_INVALADDRESSID; }
lpAddressCaps->dwNeededSize = lpAddressCaps->dwUsedSize = sizeof(LINEADDRESSCAPS);
lpAddressCaps->dwLineDeviceID = dwDeviceID; lpAddressCaps->dwAddressSharing = LINEADDRESSSHARING_PRIVATE; lpAddressCaps->dwCallInfoStates = LINECALLINFOSTATE_MEDIAMODE | LINECALLINFOSTATE_APPSPECIFIC; lpAddressCaps->dwCallerIDFlags = lpAddressCaps->dwCalledIDFlags = lpAddressCaps->dwRedirectionIDFlags = lpAddressCaps->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL; lpAddressCaps->dwCallStates = LINECALLSTATE_IDLE | LINECALLSTATE_OFFERING | LINECALLSTATE_ACCEPTED | LINECALLSTATE_DIALTONE | LINECALLSTATE_DIALING | LINECALLSTATE_CONNECTED | LINECALLSTATE_PROCEEDING | LINECALLSTATE_DISCONNECTED | LINECALLSTATE_UNKNOWN; lpAddressCaps->dwDialToneModes = LINEDIALTONEMODE_UNAVAIL; lpAddressCaps->dwBusyModes = LINEBUSYMODE_UNAVAIL; lpAddressCaps->dwSpecialInfo = LINESPECIALINFO_UNAVAIL; lpAddressCaps->dwDisconnectModes = LINEDISCONNECTMODE_NORMAL | LINEDISCONNECTMODE_BUSY | LINEDISCONNECTMODE_NOANSWER | LINEDISCONNECTMODE_UNAVAIL | LINEDISCONNECTMODE_NODIALTONE; lpAddressCaps->dwMaxNumActiveCalls = 1; lpAddressCaps->dwAddrCapFlags = LINEADDRCAPFLAGS_DIALED; lpAddressCaps->dwCallFeatures = LINECALLFEATURE_ACCEPT | LINECALLFEATURE_ANSWER | LINECALLFEATURE_DROP | LINECALLFEATURE_SETCALLPARAMS; lpAddressCaps->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetAddressStatus( HDRVLINE hdLine, DWORD dwAddressID, LPLINEADDRESSSTATUS lpAddressStatus ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "dwAddressID", dwAddressID }, { "lpAddressStatus", lpAddressStatus } }; FUNC_INFO info = { "TSPI_lineGetAddressStatus", 3, params }; #endif
LONG lResult = 0; PDRVLINE pLine = (PDRVLINE) hdLine;
Prolog (&info);
lpAddressStatus->dwNeededSize = lpAddressStatus->dwUsedSize = sizeof(LINEADDRESSSTATUS);
lpAddressStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0); lpAddressStatus->dwAddressFeatures = LINEADDRFEATURE_MAKECALL;
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetCallAddressID( HDRVCALL hdCall, LPDWORD lpdwAddressID ) { #if DBG
FUNC_PARAM params[] = { { gszhdCall, hdCall }, { "lpdwAddressID", lpdwAddressID } }; FUNC_INFO info = { "TSPI_lineGetCallAddressID", 2, params }; #endif
//
// We only support 1 address (id=0)
//
Prolog (&info); *lpdwAddressID = 0; return (Epilog (&info, 0)); }
LONG TSPIAPI TSPI_lineGetCallInfo( HDRVCALL hdCall, LPLINECALLINFO lpLineInfo ) { #if DBG
FUNC_PARAM params[] = { { gszhdCall, hdCall }, { "lpLineInfo", lpLineInfo } }; FUNC_INFO info = { "TSPI_lineGetCallInfo", 2, params }; #endif
LONG lResult = 0; PDRVLINE pLine = (PDRVLINE) hdCall;
Prolog (&info);
lpLineInfo->dwNeededSize = lpLineInfo->dwUsedSize = sizeof(LINECALLINFO);
lpLineInfo->dwBearerMode = LINEBEARERMODE_VOICE; lpLineInfo->dwMediaMode = pLine->dwMediaMode; lpLineInfo->dwCallStates = LINECALLSTATE_IDLE | LINECALLSTATE_DIALTONE | LINECALLSTATE_DIALING | LINECALLSTATE_CONNECTED | LINECALLSTATE_PROCEEDING | LINECALLSTATE_DISCONNECTED | LINECALLSTATE_UNKNOWN; lpLineInfo->dwOrigin = LINECALLORIGIN_OUTBOUND; lpLineInfo->dwReason = LINECALLREASON_DIRECT; lpLineInfo->dwCallerIDFlags = lpLineInfo->dwCalledIDFlags = lpLineInfo->dwConnectedIDFlags = lpLineInfo->dwRedirectionIDFlags = lpLineInfo->dwRedirectingIDFlags = LINECALLPARTYID_UNAVAIL;
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetCallStatus( HDRVCALL hdCall, LPLINECALLSTATUS lpLineStatus ) { #if DBG
FUNC_PARAM params[] = { { gszhdCall, hdCall }, { "lpLineStatus", lpLineStatus } }; FUNC_INFO info = { "TSPI_lineGetCallStatus", 2, params }; #endif
LONG lResult = 0; PDRVLINE pLine = (PDRVLINE) hdCall;
Prolog (&info);
lpLineStatus->dwNeededSize = lpLineStatus->dwUsedSize = sizeof(LINECALLSTATUS);
lpLineStatus->dwCallState = pLine->dwCallState;
if (pLine->dwCallState != LINECALLSTATE_IDLE) { lpLineStatus->dwCallFeatures = LINECALLFEATURE_DROP; }
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetDevCaps( DWORD dwDeviceID, DWORD dwTSPIVersion, DWORD dwExtVersion, LPLINEDEVCAPS lpLineDevCaps ) { #if DBG
FUNC_PARAM params[] = { { gszdwDeviceID, dwDeviceID }, { "dwTSPIVersion", dwTSPIVersion }, { "dwExtVersion", dwExtVersion }, { "lpLineDevCaps", lpLineDevCaps } }; FUNC_INFO info = { "TSPI_lineGetDevCaps", 4, params }; #endif
LONG lResult = 0; static WCHAR szProviderInfo[] = L"AT-compatible modem service provider";
#define PROVIDER_INFO_SIZE (37 * sizeof (WCHAR))
Prolog (&info);
lpLineDevCaps->dwNeededSize = sizeof (LINEDEVCAPS) + PROVIDER_INFO_SIZE + (MAX_DEV_NAME_LENGTH + 1) * sizeof (WCHAR);
if (lpLineDevCaps->dwTotalSize >= lpLineDevCaps->dwNeededSize) { #define LINECONFIG_SIZE (2 * (MAX_DEV_NAME_LENGTH + 1) + 40)
char szLineConfig[LINECONFIG_SIZE], szLineN[16], *p; HKEY hKey; DWORD dwDataSize, dwDataType;
lpLineDevCaps->dwUsedSize = lpLineDevCaps->dwNeededSize;
lpLineDevCaps->dwProviderInfoSize = PROVIDER_INFO_SIZE; lpLineDevCaps->dwProviderInfoOffset = sizeof(LINEDEVCAPS);
My_lstrcpyW ((WCHAR *)(lpLineDevCaps + 1), szProviderInfo);
RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszAtspKey, 0, KEY_ALL_ACCESS, &hKey );
dwDataSize = LINECONFIG_SIZE; wsprintf (szLineN, "Line%d", dwDeviceID - gdwLineDeviceIDBase); lstrcpy (szLineConfig, gszDefLineConfigParams);
RegQueryValueEx( hKey, szLineN, 0, &dwDataType, (LPBYTE) szLineConfig, &dwDataSize );
RegCloseKey (hKey);
for (p = szLineConfig; *p != ','; p++); *p = 0;
lpLineDevCaps->dwLineNameSize = (lstrlen (szLineConfig) + 1) * sizeof (WCHAR); lpLineDevCaps->dwLineNameOffset = sizeof(LINEDEVCAPS) + PROVIDER_INFO_SIZE;
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, szLineConfig, -1, (WCHAR *) ((LPBYTE) (lpLineDevCaps + 1) + PROVIDER_INFO_SIZE), lpLineDevCaps->dwLineNameSize ); } else { lpLineDevCaps->dwUsedSize = sizeof(LINEDEVCAPS); }
lpLineDevCaps->dwStringFormat = STRINGFORMAT_ASCII; lpLineDevCaps->dwAddressModes = LINEADDRESSMODE_ADDRESSID; lpLineDevCaps->dwNumAddresses = 1; lpLineDevCaps->dwBearerModes = LINEBEARERMODE_VOICE; lpLineDevCaps->dwMaxRate = 9600; lpLineDevCaps->dwMediaModes = LINEMEDIAMODE_INTERACTIVEVOICE | LINEMEDIAMODE_DATAMODEM; lpLineDevCaps->dwDevCapFlags = LINEDEVCAPFLAGS_CLOSEDROP | LINEDEVCAPFLAGS_DIALBILLING | LINEDEVCAPFLAGS_DIALQUIET | LINEDEVCAPFLAGS_DIALDIALTONE; lpLineDevCaps->dwMaxNumActiveCalls = 1; lpLineDevCaps->dwRingModes = 1; lpLineDevCaps->dwLineFeatures = LINEFEATURE_MAKECALL;
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetID( HDRVLINE hdLine, DWORD dwAddressID, HDRVCALL hdCall, DWORD dwSelect, LPVARSTRING lpDeviceID, LPCWSTR lpszDeviceClass, HANDLE hTargetProcess ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "dwAddressID", dwAddressID }, { gszhdCall, hdCall }, { "dwSelect", dwSelect }, { "lpDeviceID", lpDeviceID }, { "lpszDeviceClass", lpszDeviceClass }, { "hTargetProcess", hTargetProcess } }; FUNC_INFO info = { "TSPI_lineGetID", 7, params }; #endif
DWORD dwNeededSize = sizeof(VARSTRING) + sizeof (DWORD); LONG lResult = 0; PDRVLINE pLine = (dwSelect == LINECALLSELECT_CALL ? (PDRVLINE) hdCall : (PDRVLINE) hdLine);
Prolog (&info);
if (lstrcmpiW (lpszDeviceClass, L"tapi/line") == 0) { if (lpDeviceID->dwTotalSize < dwNeededSize) { lpDeviceID->dwUsedSize = 3*sizeof(DWORD); } else { lpDeviceID->dwUsedSize = dwNeededSize;
lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY; lpDeviceID->dwStringSize = sizeof(DWORD); lpDeviceID->dwStringOffset = sizeof(VARSTRING);
*((LPDWORD)(lpDeviceID + 1)) = pLine->dwDeviceID; }
lpDeviceID->dwNeededSize = dwNeededSize; } else if (lstrcmpiW (lpszDeviceClass, L"comm/datamodem") == 0) { dwNeededSize += (strlen (pLine->szComm) + 1) * sizeof (WCHAR);
if (lpDeviceID->dwTotalSize < dwNeededSize) { lpDeviceID->dwUsedSize = 3 * sizeof(DWORD); } else { HANDLE hCommDup = NULL;
if (!pLine->htCall) { DBGOUT((1, "TSPI_lineGetID32: error, no active call"));
lResult = LINEERR_OPERATIONFAILED;
goto TSPI_lineGetID_epilog; }
if (!DuplicateHandle( GetCurrentProcess(), pLine->hComm, hTargetProcess, &hCommDup, 0, TRUE, DUPLICATE_SAME_ACCESS )) { DBGOUT(( 1, "TSPI_lineGetID: DupHandle failed, err=%ld", GetLastError() ));
lResult = LINEERR_OPERATIONFAILED;
goto TSPI_lineGetID_epilog; }
lpDeviceID->dwUsedSize = dwNeededSize;
lpDeviceID->dwStringFormat = STRINGFORMAT_BINARY; lpDeviceID->dwStringSize = dwNeededSize - sizeof(VARSTRING); lpDeviceID->dwStringOffset = sizeof(VARSTRING);
*((HANDLE *)(lpDeviceID + 1)) = hCommDup;
lstrcpy( ((char *)(lpDeviceID + 1)) + sizeof (HANDLE), pLine->szComm );
MultiByteToWideChar( CP_ACP, 0, pLine->szComm, -1, ((WCHAR *)(lpDeviceID + 1)) + sizeof (HANDLE), 256 ); }
lpDeviceID->dwNeededSize = dwNeededSize; } else { lResult = LINEERR_NODEVICE; }
TSPI_lineGetID_epilog:
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetLineDevStatus( HDRVLINE hdLine, LPLINEDEVSTATUS lpLineDevStatus ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "lpLineDevStatus", lpLineDevStatus } }; FUNC_INFO info = { "TSPI_lineGetLineDevStatus", 2, params }; #endif
LONG lResult = 0; PDRVLINE pLine = (PDRVLINE) hdLine;
Prolog (&info);
lpLineDevStatus->dwUsedSize = lpLineDevStatus->dwNeededSize = sizeof (LINEDEVSTATUS);
lpLineDevStatus->dwNumActiveCalls = (pLine->htCall ? 1 : 0); //lpLineDevStatus->dwLineFeatures =
lpLineDevStatus->dwDevStatusFlags = LINEDEVSTATUSFLAGS_CONNECTED | LINEDEVSTATUSFLAGS_INSERVICE; return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineGetNumAddressIDs( HDRVLINE hdLine, LPDWORD lpdwNumAddressIDs ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "lpdwNumAddressIDs", lpdwNumAddressIDs } }; FUNC_INFO info = { "TSPI_lineGetNumAddressIDs", 2, params }; #endif
LONG lResult = 0; PDRVLINE pLine = (PDRVLINE) hdLine;
//
// We only support 1 address (id=0)
//
Prolog (&info); *lpdwNumAddressIDs = 1; return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineMakeCall( DRV_REQUESTID dwRequestID, HDRVLINE hdLine, HTAPICALL htCall, LPHDRVCALL lphdCall, LPCWSTR lpszDestAddress, DWORD dwCountryCode, LPLINECALLPARAMS const lpCallParams ) { char szCommands[64], szCommand[64], szDestAddress[128]; DWORD dwThreadID, dwNumBytes, dwError; PDRVLINE pLine = (PDRVLINE) hdLine; #if DBG
FUNC_PARAM params[] = { { gszdwRequestID, dwRequestID }, { gszhdLine, hdLine }, { "htCall", htCall }, { "lphdCall", lphdCall }, { "lpszDestAddress", szDestAddress }, { "dwCountryCode", dwCountryCode }, { gszlpCallParams, lpCallParams } }; FUNC_INFO info = { "TSPI_lineMakeCall", 7, params }; #endif
if (lpszDestAddress) { WideCharToMultiByte( CP_ACP, 0, lpszDestAddress, -1, (LPSTR) szDestAddress, 128, NULL, NULL ); }
Prolog (&info);
//
// Check to see if there's already another call
//
if (pLine->htCall) { (*gpfnCompletionProc)(dwRequestID, LINEERR_CALLUNAVAIL); goto TSPI_lineMakeCall_return; }
//
// Since we don't support TSPI_lineDial, fail if app tries
// to pass a NULL lpszDestAddress (implying that app just
// wants to go offhook)
//
if (lpszDestAddress == NULL) { (*gpfnCompletionProc)(dwRequestID, LINEERR_INVALADDRESS); goto TSPI_lineMakeCall_return; }
//
// Get the line's config info
//
{ HKEY hKey; DWORD dwDataSize, dwDataType; char szLineN[8], *pszConfig, *p, *p2;
wsprintf( szLineN, "Line%d", ((PDRVLINE) hdLine)->dwDeviceID - gdwLineDeviceIDBase );
dwDataSize = 256;
pszConfig = DrvAlloc (dwDataSize);
RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszAtspKey, 0, KEY_ALL_ACCESS, &hKey );
RegQueryValueEx( hKey, szLineN, 0, &dwDataType, (LPBYTE) pszConfig, &dwDataSize );
pszConfig[dwDataSize] = '\0'; // *pszConfig = "MyLine,COM1,L0"
RegCloseKey (hKey);
//
// szComm
//
for (p = pszConfig; *p != ','; p++); p++; // *p = "COM1,L0"
for (p2 = p; *p2 != ','; p2++); *p2 = 0; // *p = "COM1"
lstrcpy (pLine->szComm, p);
//
// szCommands
//
p2++; // *p2 = "L0"
lstrcpy (szCommands, p2);
DrvFree (pszConfig); }
//
// Open the port
//
if ((pLine->hComm = CreateFile( pLine->szComm, GENERIC_READ | GENERIC_WRITE, 0, //FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // no security attrs
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL // no template file
)) == INVALID_HANDLE_VALUE) { DBGOUT(( 3, "TSPI_lineMakeCall: CreateFile(%s) failed, err=%ld", pLine->szComm, GetLastError() ));
(*gpfnCompletionProc)(dwRequestID, LINEERR_RESOURCEUNAVAIL); goto TSPI_lineMakeCall_return; }
//
// Setup up the modem command string. If there's an initial 'T'
// or 'P' (for Tone or Pulse) in the dest address then disregard
// it. Also if it's a voice call add the semi colon so we return
// to cmd mode.
//
{ char *p = (char *) szDestAddress;
if (*p == 'T' || *p == 'P') { p++; }
if (lpCallParams && lpCallParams->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE) { wsprintf (szCommand, "AT%sDT%s\r", szCommands, p); } else { wsprintf (szCommand, "AT%sDT%s;\r", szCommands, p); } }
//
// Init the data structure & tell tapi our handle to the call
//
pLine->htCall = htCall; pLine->bDropInProgress = FALSE; pLine->dwMediaMode = (lpCallParams ? lpCallParams->dwMediaMode : LINEMEDIAMODE_INTERACTIVEVOICE);
*lphdCall = (HDRVCALL) pLine;
//
// Do an overlapped write, the comm thread will deal with the results
//
pLine->Overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!WriteFile( pLine->hComm, szCommand, lstrlen (szCommand), &dwNumBytes, &pLine->Overlapped )
&& (dwError = GetLastError()) != ERROR_IO_PENDING) { DBGOUT(( 1, "TSPI_lineMakeCall: WriteFile(%s) failed, error=%d", pLine->szComm, dwError ));
pLine->htCall = NULL; CloseHandle (pLine->hComm); CloseHandle (pLine->Overlapped.hEvent); (*gpfnCompletionProc)(dwRequestID, LINEERR_OPERATIONFAILED); goto TSPI_lineMakeCall_return; }
//
// Complete the requests & set the initial call state
//
(*gpfnCompletionProc)(dwRequestID, 0); SetCallState (pLine, LINECALLSTATE_DIALING, 0);
//
// Spin the comm thread to handle the results of the Write above
//
{ HANDLE hCommThread;
if (!(hCommThread = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) CommThread, pLine, 0, &dwThreadID ))) { DBGOUT(( 1, "TSPI_lineMakeCall: CreateThread failed, err=%ld", GetLastError() ));
GetOverlappedResult( pLine->hComm, &pLine->Overlapped, &dwNumBytes, TRUE );
SetCallState (pLine, LINECALLSTATE_IDLE, 0); CloseHandle (pLine->hComm); CloseHandle (pLine->Overlapped.hEvent); goto TSPI_lineMakeCall_return; }
CloseHandle (hCommThread); }
TSPI_lineMakeCall_return:
return (Epilog (&info, dwRequestID)); }
LONG TSPIAPI TSPI_lineNegotiateTSPIVersion( DWORD dwDeviceID, DWORD dwLowVersion, DWORD dwHighVersion, LPDWORD lpdwTSPIVersion ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { gszdwDeviceID, dwDeviceID }, { "dwLowVersion", dwLowVersion }, { "dwHighVersion", dwHighVersion }, { "lpdwTSPIVersion", lpdwTSPIVersion } }; FUNC_INFO info = { "TSPI_lineNegotiateTSPIVersion", 4, params }; #endif
Prolog (&info); *lpdwTSPIVersion = 0x00020000; return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineOpen( DWORD dwDeviceID, HTAPILINE htLine, LPHDRVLINE lphdLine, DWORD dwTSPIVersion, LINEEVENT lpfnEventProc ) { LONG lResult; PDRVLINE pLine; #if DBG
FUNC_PARAM params[] = { { gszdwDeviceID, dwDeviceID }, { "htLine", htLine }, { "lphdLine", lphdLine }, { "dwTSPIVersion", dwTSPIVersion }, { "lpfnEventProc", lpfnEventProc } }; FUNC_INFO info = { "TSPI_lineOpen", 5, params }; #endif
Prolog (&info);
if ((pLine = DrvAlloc (sizeof (DRVLINE)))) { pLine->htLine = htLine; pLine->pfnEventProc = lpfnEventProc; pLine->dwDeviceID = dwDeviceID;
*lphdLine = (HDRVLINE) pLine;
lResult = 0; } else { lResult = LINEERR_NOMEM; }
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_lineSetDefaultMediaDetection( HDRVLINE hdLine, DWORD dwMediaModes ) { #if DBG
FUNC_PARAM params[] = { { gszhdLine, hdLine }, { "dwMediaModes", dwMediaModes } }; FUNC_INFO info = { "TSPI_lineSetDefaultMediaDetection", 2, params }; #endif
//
// This func is really a no-op for us, since we don't look
// for incoming calls (though we do say we support them to
// make apps happy)
//
Prolog (&info); return (Epilog (&info, 0)); }
//
// ------------------------- TSPI_providerXxx funcs ---------------------------
//
LONG TSPIAPI TSPI_providerConfig( HWND hwndOwner, DWORD dwPermanentProviderID ) { //
// Although this func is never called by TAPI v2.0, we export
// it so that the Telephony Control Panel Applet knows that it
// can configure this provider via lineConfigProvider(),
// otherwise Telephon.cpl will not consider it configurable
//
return 0; }
LONG TSPIAPI TSPI_providerGenericDialogData( ULONG_PTR dwObjectID, DWORD dwObjectType, LPVOID lpParams, DWORD dwSize ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "dwObjectID", dwObjectID }, { "dwObjectType", dwObjectType }, { "lpParams", lpParams }, { "dwSize", dwSize } }; FUNC_INFO info = { "TSPI_providerGenericDialogData", 4, params }; #endif
Prolog (&info); return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_providerInit( DWORD dwTSPIVersion, DWORD dwPermanentProviderID, DWORD dwLineDeviceIDBase, DWORD dwPhoneDeviceIDBase, DWORD_PTR dwNumLines, DWORD_PTR dwNumPhones, ASYNC_COMPLETION lpfnCompletionProc, LPDWORD lpdwTSPIOptions ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "dwTSPIVersion", dwTSPIVersion }, { gszdwPermanentProviderID, dwPermanentProviderID }, { "dwLineDeviceIDBase", dwLineDeviceIDBase }, { "dwPhoneDeviceIDBase", dwPhoneDeviceIDBase }, { "dwNumLines", dwNumLines }, { "dwNumPhones", dwNumPhones }, { "lpfnCompletionProc", lpfnCompletionProc } }; FUNC_INFO info = { "TSPI_providerInit", 7, params }; #endif
Prolog (&info); gdwLineDeviceIDBase = dwLineDeviceIDBase; gpfnCompletionProc = lpfnCompletionProc; *lpdwTSPIOptions = LINETSPIOPTION_NONREENTRANT; return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_providerInstall( HWND hwndOwner, DWORD dwPermanentProviderID ) { //
// Although this func is never called by TAPI v2.0, we export
// it so that the Telephony Control Panel Applet knows that it
// can add this provider via lineAddProvider(), otherwise
// Telephon.cpl will not consider it installable
//
//
return 0; }
LONG TSPIAPI TSPI_providerRemove( HWND hwndOwner, DWORD dwPermanentProviderID ) { //
// Although this func is never called by TAPI v2.0, we export
// it so that the Telephony Control Panel Applet knows that it
// can remove this provider via lineRemoveProvider(), otherwise
// Telephon.cpl will not consider it removable
//
return 0; }
LONG TSPIAPI TSPI_providerShutdown( DWORD dwTSPIVersion, DWORD dwPermanentProviderID ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "dwTSPIVersion", dwTSPIVersion }, { gszdwPermanentProviderID, dwPermanentProviderID } }; FUNC_INFO info = { "TSPI_providerShutdown", 2, params }; #endif
Prolog (&info);
return (Epilog (&info, lResult)); }
LONG TSPIAPI TSPI_providerEnumDevices( DWORD dwPermanentProviderID, LPDWORD lpdwNumLines, LPDWORD lpdwNumPhones, HPROVIDER hProvider, LINEEVENT lpfnLineCreateProc, PHONEEVENT lpfnPhoneCreateProc ) { HKEY hKey; DWORD dwNumLines, dwDataType, dwDataSize;
//
// Retrieve the number of devices we're
// configured for from our registry section
//
if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszAtspKey, 0, KEY_ALL_ACCESS, &hKey )) { return LINEERR_OPERATIONFAILED; }
dwDataSize = sizeof(dwNumLines); dwNumLines = 0;
RegQueryValueEx( hKey, gszNumLines, 0, &dwDataType, (LPBYTE) &dwNumLines, &dwDataSize );
RegCloseKey (hKey);
*lpdwNumLines = dwNumLines; *lpdwNumPhones = 0; return 0; }
LONG TSPIAPI TSPI_providerUIIdentify( LPWSTR lpszUIDLLName ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "lpsUIDLLName", lpszUIDLLName } }; FUNC_INFO info = { "TSPI_providerUIIdentify", 1, params }; #endif
Prolog (&info); My_lstrcpyW(lpszUIDLLName, L"atsp32.tsp"); return (Epilog (&info, lResult)); }
//
// ---------------------------- TUISPI_xxx funcs ------------------------------
//
LONG TSPIAPI TUISPI_lineConfigDialog( TUISPIDLLCALLBACK lpfnUIDLLCallback, DWORD dwDeviceID, HWND hwndOwner, LPCWSTR lpszDeviceClass ) { char szDeviceClass[128]; LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "lpfnUIDLLCallback", lpfnUIDLLCallback }, { gszdwDeviceID, dwDeviceID }, { gszhwndOwner, hwndOwner }, { "lpszDeviceClass", szDeviceClass } }; FUNC_INFO info = { "TUISPI_lineConfigDialog", 4, params }; #endif
if (lpszDeviceClass) { WideCharToMultiByte( CP_ACP, 0, lpszDeviceClass, -1, (LPSTR) szDeviceClass, 128, NULL, NULL ); }
Prolog (&info);
DialogBoxParam( ghInst, MAKEINTRESOURCE(IDD_DIALOG1), hwndOwner, (DLGPROC) ConfigDlgProc, 0 );
return (Epilog (&info, lResult)); }
LONG TSPIAPI TUISPI_providerConfig( TUISPIDLLCALLBACK lpfnUIDLLCallback, HWND hwndOwner, DWORD dwPermanentProviderID ) { LONG lResult = 0; #if DBG
FUNC_PARAM params[] = { { "lpfnUIDLLCallback", lpfnUIDLLCallback }, { gszhwndOwner, hwndOwner }, { gszdwPermanentProviderID, dwPermanentProviderID } }; FUNC_INFO info = { "TUISPI_providerConfig", 3, params }; #endif
Prolog (&info);
DialogBoxParam( ghInst, MAKEINTRESOURCE(IDD_DIALOG1), hwndOwner, (DLGPROC) ConfigDlgProc, 0 );
return (Epilog (&info, lResult)); }
LONG TSPIAPI TUISPI_providerInstall( TUISPIDLLCALLBACK lpfnUIDLLCallback, HWND hwndOwner, DWORD dwPermanentProviderID ) { LONG lResult;
if ((lResult = ProviderInstall ("atsp32.tsp", TRUE)) == 0) { DialogBoxParam( ghInst, MAKEINTRESOURCE(IDD_DIALOG1), hwndOwner, (DLGPROC) ConfigDlgProc, 0 ); }
return lResult; }
LONG TSPIAPI TUISPI_providerRemove( TUISPIDLLCALLBACK lpfnUIDLLCallback, HWND hwndOwner, DWORD dwPermanentProviderID ) { HKEY hKey; char szSoftwareMsft[] = "Software\\Microsoft", szATSP[] = "ATSP"; LONG lResult;
//
// Clean up our registry section
//
lResult = RegOpenKeyExA( HKEY_LOCAL_MACHINE, szSoftwareMsft, 0, KEY_ALL_ACCESS, &hKey );
if (ERROR_SUCCESS != lResult) return 0;
RegDeleteKeyA (hKey, szATSP); RegCloseKey (hKey); return 0; }
#pragma warning (default:4047)
//
// ---------------------- Misc private support routines -----------------------
//
LPWSTR PASCAL My_lstrcpyW( WCHAR *pString1, WCHAR *pString2 ) { WCHAR *p = pString1;
for (; (*p = *pString2); p++, pString2++); return pString1; }
void PASCAL EnableChildren( HWND hwnd, BOOL bEnable ) { int i; static int aiControlIDs[] = { IDC_DEVICES, IDC_NAME, IDC_PORT, IDC_COMMANDS, IDC_REMOVE, 0 };
for (i = 0; aiControlIDs[i]; i++) { EnableWindow (GetDlgItem (hwnd, aiControlIDs[i]), bEnable); } }
void PASCAL SelectDevice( HWND hwnd, LRESULT lDevice ) { SendDlgItemMessage (hwnd, IDC_DEVICES, LB_SETCURSEL, lDevice, 0); PostMessage(hwnd, WM_COMMAND, IDC_DEVICES | (LBN_SELCHANGE << 16), 0); }
BOOL CALLBACK ConfigDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) { static HKEY hAtspKey;
DWORD dwDataSize; DWORD dwDataType;
switch (msg) { case WM_INITDIALOG: { char *pBuf; DWORD i, iNumLines;
//
// Create or open our configuration key in the registry. If the
// create fails it may well be that the current user does not
// have write access to this portion of the registry, so we'll
// just show a "read only" dialog and not allow user to make any
// changes
//
{ LONG lResult; DWORD dwDisposition;
if ((lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE, gszAtspKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, (LPSECURITY_ATTRIBUTES) NULL, &hAtspKey, &dwDisposition
)) != ERROR_SUCCESS) { DBGOUT(( 3, "RegCreateKeyEx(%s,ALL_ACCESS) failed, err=%d", gszAtspKey, lResult ));
if ((lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, gszAtspKey, 0, KEY_QUERY_VALUE, &hAtspKey
)) != ERROR_SUCCESS) { DBGOUT(( 3, "RegOpenKeyEx(%s,ALL_ACCESS) failed, err=%d", gszAtspKey, lResult ));
EndDialog (hwnd, 0); return FALSE; }
{ int i; static int aiControlIDs[] = { IDC_NAME, IDC_PORT, IDC_COMMANDS, IDC_ADD, IDC_REMOVE, IDOK, 0 };
for (i = 0; aiControlIDs[i]; i++) { EnableWindow( GetDlgItem (hwnd, aiControlIDs[i]), FALSE ); } } } }
//
// Retrieve our configuration info from the registry
//
dwDataSize = sizeof(iNumLines); iNumLines = 0;
RegQueryValueEx( hAtspKey, gszNumLines, 0, &dwDataType, (LPBYTE) &iNumLines, &dwDataSize );
SendDlgItemMessage( hwnd, IDC_NAME, EM_LIMITTEXT, MAX_DEV_NAME_LENGTH, 0 );
SendDlgItemMessage( hwnd, IDC_COMMANDS, EM_LIMITTEXT, MAX_DEV_NAME_LENGTH, 0 );
pBuf = DrvAlloc (256);
for (i = 0; i < iNumLines; i++) { char *p, *p2, szLineN[8]; PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG)); LONG lResult;
wsprintf (szLineN, "Line%d", i);
dwDataSize = 256;
lResult = RegQueryValueEx( hAtspKey, szLineN, 0, &dwDataType, (LPBYTE) pBuf, &dwDataSize );
//
// If there was a problem, use the default config
//
if (0 != lResult) { lstrcpy (pBuf, gszDefLineConfigParams); }
for (p = pBuf; *p != ','; p++); *p = 0;
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_ADDSTRING, 0, (LPARAM) pBuf );
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_SETITEMDATA, i, (LPARAM) pLineConfig );
p++; for (p2 = p; *p2 != ','; p2++); *p2 = 0;
lstrcpy (pLineConfig->szPort, p);
p = p2 + 1;
lstrcpy (pLineConfig->szCommands, p); }
DrvFree (pBuf);
//
// Fill up the various controls with configuration options
//
{ static char *aszPorts[] = { "COM1","COM2","COM3",NULL };
for (i = 0; aszPorts[i]; i++) { SendDlgItemMessage( hwnd, IDC_PORT, LB_ADDSTRING, 0, (LPARAM) aszPorts[i] ); } }
if (iNumLines == 0) { EnableChildren (hwnd, FALSE); } else { SelectDevice (hwnd, 0); }
break; } case WM_COMMAND: { LRESULT lSelection; PDRVLINECONFIG pLineConfig;
lSelection = SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETCURSEL, 0, 0 );
pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETITEMDATA, (WPARAM) lSelection, 0 );
switch (LOWORD((DWORD)wParam)) { case IDC_DEVICES:
if (HIWORD(wParam) == LBN_SELCHANGE) { char buf[MAX_DEV_NAME_LENGTH + 1];
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETTEXT, lSelection, (LPARAM) buf );
SetDlgItemText (hwnd, IDC_NAME, buf);
SendDlgItemMessage( hwnd, IDC_PORT, LB_SELECTSTRING, (WPARAM) -1, (LPARAM) pLineConfig->szPort );
SetDlgItemText (hwnd, IDC_COMMANDS, pLineConfig->szCommands); }
break;
case IDC_NAME:
if ((HIWORD(wParam) == EN_CHANGE) && (lSelection != LB_ERR)) { char buf[MAX_DEV_NAME_LENGTH + 1];
GetDlgItemText (hwnd, IDC_NAME, buf, MAX_DEV_NAME_LENGTH);
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_DELETESTRING, lSelection, 0 );
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_INSERTSTRING, lSelection, (LPARAM) buf );
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_SETCURSEL, lSelection, 0 );
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_SETITEMDATA, lSelection, (LPARAM) pLineConfig ); }
break;
case IDC_PORT:
if (HIWORD(wParam) == LBN_SELCHANGE) { lSelection = SendDlgItemMessage( hwnd, IDC_PORT, LB_GETCURSEL, 0, 0 );
SendDlgItemMessage( hwnd, IDC_PORT, LB_GETTEXT, lSelection, (LPARAM) pLineConfig->szPort ); }
break;
case IDC_COMMANDS:
if ((HIWORD(wParam) == EN_CHANGE) && (lSelection != LB_ERR)) { GetDlgItemText( hwnd, IDC_COMMANDS, pLineConfig->szCommands, 63 ); }
break;
case IDC_ADD: { LRESULT lNumLines, l = 2; char szLineName[32]; PDRVLINECONFIG pLineConfig = DrvAlloc (sizeof(DRVLINECONFIG));
lNumLines = SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETCOUNT, 0, 0 );
lstrcpy (pLineConfig->szPort, "COM1");
lstrcpy (szLineName, "my new line");
find_unique_line_name:
if (SendDlgItemMessage( hwnd, IDC_DEVICES, LB_FINDSTRING, (WPARAM) -1, (LPARAM) szLineName
) != LB_ERR) { wsprintf (szLineName, "my new line%d", l++); goto find_unique_line_name; }
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_ADDSTRING, 0, (LPARAM) szLineName );
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_SETITEMDATA, lNumLines, (LPARAM) pLineConfig );
EnableChildren (hwnd, TRUE);
SelectDevice (hwnd, lNumLines);
SetFocus (GetDlgItem (hwnd, IDC_NAME));
SendDlgItemMessage( hwnd, IDC_NAME, EM_SETSEL, 0, (LPARAM) -1 );
break; } case IDC_REMOVE: { LRESULT lNumLines;
DrvFree (pLineConfig);
lNumLines = SendDlgItemMessage( hwnd, IDC_DEVICES, LB_DELETESTRING, lSelection, 0 );
if (lNumLines == 0) { SetDlgItemText (hwnd, IDC_NAME, ""); SetDlgItemText (hwnd, IDC_COMMANDS, "");
EnableChildren (hwnd, FALSE); } else { SelectDevice (hwnd, 0); }
break; } case IDOK: { char *pBuf; LRESULT l, lNumLines;
//
// Update the num lines & num phones values
//
pBuf = DrvAlloc (256);
lNumLines = SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETCOUNT, 0, 0 );
RegSetValueEx( hAtspKey, gszNumLines, 0, REG_DWORD, (LPBYTE) &lNumLines, sizeof(DWORD) );
//
// For each installed device save it's config info
//
for (l = 0; l < lNumLines; l++) { char szLineN[8]; PDRVLINECONFIG pLineConfig;
SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETTEXT, l, (LPARAM) pBuf );
pLineConfig = (PDRVLINECONFIG) SendDlgItemMessage( hwnd, IDC_DEVICES, LB_GETITEMDATA, l, 0 );
wsprintf( pBuf + strlen (pBuf), ",%s,%s", pLineConfig->szPort, pLineConfig->szCommands );
wsprintf (szLineN, "Line%d", l);
RegSetValueEx( hAtspKey, szLineN, 0, REG_SZ, (LPBYTE) pBuf, lstrlen (pBuf) + 1 );
DrvFree (pLineConfig); }
DrvFree (pBuf);
// fall thru to EndDialog...
} case IDCANCEL:
RegCloseKey (hAtspKey); EndDialog (hwnd, 0); break;
} // switch (LOWORD((DWORD)wParam))
break; } } // switch (msg)
return FALSE; }
LPVOID PASCAL DrvAlloc( DWORD dwSize ) { return (LocalAlloc (LPTR, dwSize)); }
VOID PASCAL DrvFree( LPVOID lp ) { LocalFree (lp); }
void PASCAL SetCallState( PDRVLINE pLine, DWORD dwCallState, DWORD dwCallStateMode ) { if (dwCallState != pLine->dwCallState) { pLine->dwCallState = dwCallState; pLine->dwCallStateMode = dwCallStateMode;
(*pLine->pfnEventProc)( pLine->htLine, pLine->htCall, LINE_CALLSTATE, dwCallState, dwCallStateMode, pLine->dwMediaMode ); } }
#if DBG
void PASCAL Prolog( PFUNC_INFO pInfo ) { DWORD i;
DBGOUT((3, "%s: enter", pInfo->lpszFuncName));
for (i = 0; i < pInfo->dwNumParams; i++) { if (pInfo->aParams[i].dwVal && pInfo->aParams[i].lpszVal[3] == 'z') // lpszVal = "lpsz..."
{ DBGOUT(( 3, "%s%s=x%lx, '%s'", gszTab, pInfo->aParams[i].lpszVal, pInfo->aParams[i].dwVal, pInfo->aParams[i].dwVal )); } else { DBGOUT(( 3, "%s%s=x%lx", gszTab, pInfo->aParams[i].lpszVal, pInfo->aParams[i].dwVal )); } } }
LONG PASCAL Epilog( PFUNC_INFO pInfo, LONG lResult ) { DBGOUT((3, "%s: returning x%x", pInfo->lpszFuncName, lResult));
return lResult; }
void CDECL DebugOutput( DWORD dwDbgLevel, LPCSTR lpszFormat, ... ) { if (dwDbgLevel <= gdwDebugLevel) { char buf[128] = "ATSP32: "; va_list ap;
va_start(ap, lpszFormat);
wvsprintf (&buf[8], lpszFormat, ap);
lstrcat (buf, "\n");
OutputDebugString (buf);
va_end(ap); } }
#endif
LONG PASCAL ProviderInstall( char *pszProviderName, BOOL bNoMultipleInstance ) { LONG lResult;
//
// If only one installation instance of this provider is
// allowed then we want to check the provider list to see
// if the provider is already installed
//
if (bNoMultipleInstance) { LONG (WINAPI *pfnGetProviderList)(); DWORD dwTotalSize, i; HINSTANCE hTapi32; LPLINEPROVIDERLIST pProviderList; LPLINEPROVIDERENTRY pProviderEntry;
//
// Load Tapi32.dll & get a pointer to the lineGetProviderList
// func. We don't want to statically link because this module
// plays the part of both core SP & UI DLL, and we don't want
// to incur the performance hit of automatically loading
// Tapi32.dll when running as a core SP within Tapisrv.exe's
// context.
//
if (!(hTapi32 = LoadLibrary ("tapi32.dll"))) { DBGOUT(( 1, "LoadLibrary(tapi32.dll) failed, err=%d", GetLastError() ));
lResult = LINEERR_OPERATIONFAILED; goto ProviderInstall_return; }
if (!((FARPROC) pfnGetProviderList = GetProcAddress( hTapi32, (LPCSTR) "lineGetProviderList" ))) { DBGOUT(( 1, "GetProcAddr(lineGetProviderList) failed, err=%d", GetLastError() ));
lResult = LINEERR_OPERATIONFAILED; goto ProviderInstall_unloadTapi32; }
//
// Loop until we get the full provider list
//
dwTotalSize = sizeof (LINEPROVIDERLIST);
goto ProviderInstall_allocProviderList;
ProviderInstall_getProviderList:
if ((lResult = (*pfnGetProviderList)(0x00020000, pProviderList)) != 0) { goto ProviderInstall_freeProviderList; }
if (pProviderList->dwNeededSize > pProviderList->dwTotalSize) { dwTotalSize = pProviderList->dwNeededSize;
LocalFree (pProviderList);
ProviderInstall_allocProviderList:
if (!(pProviderList = LocalAlloc (LPTR, dwTotalSize))) { lResult = LINEERR_NOMEM; goto ProviderInstall_unloadTapi32; }
pProviderList->dwTotalSize = dwTotalSize;
goto ProviderInstall_getProviderList; }
//
// Inspect the provider list entries to see if this provider
// is already installed
//
pProviderEntry = (LPLINEPROVIDERENTRY) (((LPBYTE) pProviderList) + pProviderList->dwProviderListOffset);
for (i = 0; i < pProviderList->dwNumProviders; i++) { char *pszInstalledProviderName = ((char *) pProviderList) + pProviderEntry->dwProviderFilenameOffset, *p;
//
// Make sure pszInstalledProviderName points at <filename>
// and not <path>\filename by walking backeards thru the
// string searching for last '\\'
//
p = pszInstalledProviderName + lstrlen (pszInstalledProviderName) - 1;
for (; *p != '\\' && p != pszInstalledProviderName; p--);
pszInstalledProviderName = (p == pszInstalledProviderName ? p : p + 1);
if (lstrcmpiA (pszInstalledProviderName, pszProviderName) == 0) { lResult = LINEERR_NOMULTIPLEINSTANCE; goto ProviderInstall_freeProviderList; }
pProviderEntry++; }
//
// If here then the provider isn't currently installed,
// so do whatever configuration stuff is necessary and
// indicate SUCCESS
//
lResult = 0;
ProviderInstall_freeProviderList:
LocalFree (pProviderList);
ProviderInstall_unloadTapi32:
FreeLibrary (hTapi32); } else { //
// Do whatever configuration stuff is necessary and return SUCCESS
//
lResult = 0; }
ProviderInstall_return:
return lResult; }
void PASCAL DropActiveCall( PDRVLINE pLine ) { if (pLine->hComm) { DWORD dwNumBytes, dwError; OVERLAPPED overlapped;
pLine->bDropInProgress = TRUE;
SetEvent (pLine->Overlapped.hEvent);
ZeroMemory (&overlapped, sizeof (OVERLAPPED));
overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
if (pLine->dwMediaMode != LINEMEDIAMODE_INTERACTIVEVOICE) { if (!WriteFile( pLine->hComm, "+++\r", 4, &dwNumBytes, &overlapped )) { if ((dwError = GetLastError()) == ERROR_IO_PENDING) { GetOverlappedResult( pLine->hComm, &overlapped, &dwNumBytes, TRUE );
ResetEvent (overlapped.hEvent); } else { } } }
if (!WriteFile (pLine->hComm, "ATH\r", 4, &dwNumBytes, &overlapped)) { if ((dwError = GetLastError()) == ERROR_IO_PENDING) { GetOverlappedResult( pLine->hComm, &overlapped, &dwNumBytes, TRUE ); } else { } }
CloseHandle (overlapped.hEvent); CloseHandle (pLine->hComm); pLine->hComm = NULL; } }
|