Click to See Complete Forum and Search --> : Tapi


kunir
September 17th, 2003, 08:29 AM
:cool:
hi therei think you can help me!

i am trying to start a minor project on TAPI.
if you can help me to some good web resiource or post some basic project so that i can get started with it.
Thanks.
kunir

Michello
September 30th, 2003, 07:54 PM
Hello kunir,
enclosed some basic functions to make a call via TAPI.

First you have to initialize TAPI before any other TAPI function is called. If the following function succeeds, it returns a HLINEAPP handle that is the application's usage handle for TAPI, which should be defined as global. Further it return the number of available line devices to your application.

DWORD InitializeTAPI()
{
DWORD dwReturn, dwNumLineDevices;

dwReturn = lineInitialize( &g_hLineApp,
g_hInstance, // Your application's instance handle.
( LINECALLBACK )TAPICallbackFunc,
"MyApplication",
&dwNumLineDevices );

switch( dwReturn )
{
case LINEERR_REINIT:
// Try again later.
break;

// Handle other return values here.
}

return dwNumLineDevices;
}
An application should provide a callback function, in order to get some information about a line's state.

void TAPICallbackFunc( DWORD hDevice,
DWORD dwMsg,
DWORD dwCallbackInstance,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3 )
{
switch( dwMsg )
{
case LINE_CALLSTATE:
switch( dwParam1 )
{
case LINECALLSTATE_IDLE:
break;
case LINECALLSTATE_DIALTONE:
break;
case LINECALLSTATE_DIALING:
break;
case LINECALLSTATE_PROCEEDING:
break;
case LINECALLSTATE_RINGBACK:
break;
case LINECALLSTATE_CONNECTED:
break;
case LINECALLSTATE_BUSY:
break;
case LINECALLSTATE_DISCONNECTED:
switch( dwParam2 ):
{
case LINEDISCONNECTMODE_NORMAL:
break;
case LINEDISCONNECTMODE_UNKOWN:
break;
case LINEDISCONNECTMODE_REJECT:
break;
case LINEDISCONNECTMODE_BUSY:
break;
}
break;

default:
// Some other reason for disconnection.
}
break;

default:
// Some other notification.
}
}
When an application has finsihed using TAPI, a call to the following function should be made.

void ShutdownTAPI()
{
if( g_hLineApp )
{
lineShutdown( g_hLineApp );
g_hLineApp = NULL;
}
}
You need to negotiate the right version to ensure that all parties - the application, TAPI and the service provider DLL - agree on the version to use.

#define TAPI_VERSION_1_3 0x00010003
#define TAPI_VERSION_3_0 0x00030000
#define TAPI_CURRENT_VERSION TAPI_VERSION_3_0

DWORD NegotiateTAPIVersion( DWORD dwLineId )
{
DWORD dwTAPIVersion;

if( 0 != lineNegotiateAPIVersion( g_hLineApp,
dwLineId,
TAPI_VERSION_1_0, // Least recent API version.
TAPI_CURRENT_VERSION, // Most recent API version.
&dwTAPIVersion,
NULL ))
{
// The version could not be negotiated.
return 0;
}

return dwTAPIVersion;
}
In order to get detailled information about a certain line device, you need to pass a LINEDEVCAPS structure to the TAPI function lineGetDevCaps() - it further needs the negotiated TAPI version. The complexity in calling this function results from the LINEDEVCAPS structure - the size of the structure differs from line device to line device.

bool GetLineDeviceCaps( DWORD dwLineId,
DWORD dwTAPIVersion,
LINEDEVCAPS* pLineDeviceCaps )
{
DWORD dwSize = sizeof( LINEDEVCAPS );

while( 1 )
{
if( !( pLineDeviceCaps = ( LINEDEVCAPS* )LocalAlloc( LPTR, dwSize )))
{
// Not enough memory.
return false;
}

if( 0 != lineGetDevCaps( g_hLineApp,
dwLineId,
dwTAPIVersion,
0,
pLineDeviceCaps ))
{
// The line device capabilities could not be detected.
LocalFree( pLineDeviceCaps );
pLineDeviceCaps = NULL;

return false;
}

// Did we allocate enough memory?
if( pLineDeviceCaps->deNeededSize <= pLineDeviceCaps->dwTotalSize )
break;

dwSize = pLineDeviceCaps->dwNeededSize;
LocalFree( pLineDeviceCaps );
}

// Don't forget to free memory outside this function!
return true;
}
Now you're able to determine wether a certain line device is able to send or receive data or a fax, by checking the element dwLineMediaMode of the LINEDEVCAPS structure for the flag LINEMEDIAMODE_DATAMODEM or LINEMEDIAMODE_G3FAX.
Before you can do a call now, you first have to open a specified line. Do it like that.

HLINE OpenLine( DWORD dwLineId,
DWORD dwTAPIVersion )
{
HLINE hLine;

if( 0 != lineOpen( g_hLineApp,
dwLineId,
&hLine,
dwTAPIVersion,
0,
0,
LINECALLPRIVILEGE_NONE, // Can only make an outgoing call.
0,
NULL ))
{
// Could not open line.
return NULL;
}

return hLine;
}
Well, before doing the call, a last step hast to be made: translating the phone number. This translation takes into account the configured current location of the user and determines if a local, long distance or international call needs to be made. It is even important, if you have a correctly formatted telephone number for the current location. Some line devices place a 'P' or 'T' before the telephone number to indicate pulse or tone dialing when translating the number, and without this call will fail. The needed structure LINETRANSLATEOUTPUT has again a variable size. So we have to proceed like above.

bool TranslateAddress( DWORD dwLineId,
DWORD dwTAPIVersion,
LPTSTR szPhoneNumber,
LPTSTR szDialablePhoneNumber)
{
LINETRANSLATEOUTPUT* pLineTranslateOutput;
DWORD dwSize = sizeof( LINETRANSLATEOUTPUT );

while( 1 )
{
if( !( pLineTranslateOutput = ( LINETRANSLATEOUTPUT* )LocalAlloc( LPTR, dwSize )))
{
// Not enogh memory.
return false;
}

if( 0 != lineTranslateAddress( g_hLineApp,
dwLineId,
dwTAPIVersion,
szPhoneNumber,
0,
0,
pLineTranslateOutput ))
{
// The phone number could not be translated.
LocalFree( pLineTranslateOutput );
pLineTranslateOutput = NULL;

return false;
}

// Did we allocate enough memory?
if( pLineTranslateOutput->dwNeededSize <= pLineTranslateOutput->dwTotalSize )
break;

dwSize = pLineTranslateOutput->dwNeededSize;
LocalFree( pLineTranslateOutput );
}

// Get the dialable phone number.
_tcscpy( szDialablePhoneNumber,
( LPTSTR )(( LPBYTE )pLineTranslateOutput + pLineTranslateOutput->dwDialableStringOffset ));

LocalFree( pLineTranslateOutput );
return true;
}
Now the time has come to do the call! :-)

HCALL MakeCall( HLINE hLine,
LPTSTR szDialablePhoneNumber )
{
HCALL hCall;

if( 0 > lineMakeCall( hLine,
&hCall,
szDialablePhoneNumber,
0, // This should be your country code.
NULL ))
{
// The call could not be made.
return NULL;
}

// Dialing asynchronously.
return hCall;
}
To be continued...

Michello
September 30th, 2003, 08:21 PM
Hello again...

Your main() could do something like this now (excuse the 'goto' ;-).

#include <tapi.h>

DWORD InitializeTAPI ();
void ShutdownTAPI ();
DWORD NegotiateTAPIVersion ( DWORD );
bool GetLineDeviceCaps ( DWORD, DWORD, LINEDEVCAPS* );
HLINE OpenLine ( DWORD, DWORD );
bool TranslateAddress ( DWORD, DWORD, LPTSTR, LPTSTR );
HCALL MakeCall ( HLINE, LPTSTR );
void TAPICallbackFunc ( DWORD, DWORD, DWORD, DWORD, DWORD, DWORD );

HINSTANCE g_hInstance = NULL;
HLINEAPP g_hLineApp = NULL;

int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
DWORD dwNumLineDevices, dwTAPIVersion, dwLineId;
LINEDEVCAPS* pLineDevCaps = NULL;
HLINE hLine = NULL;
HCALL hCall = NULL;
TCHAR szDialablePhoneNumber[ 128 ];
bool bDataModem;

// Save the instance handle for global use.
g_hInstance = hInstance;

// Initialize TAPI and get number of available line devices.
if( !( dwNumLineDevices = InitializeTAPI() )
goto Exit;

for( dwLineId = 0; dwLineId < dwNumLineDevices; ++dwLineId )
{
// Negotiate TAPI version of the current line device.
if( !( dwTAPIVersion = NegotiateTAPIVersion( dwLineId )))
{
// Try the next line device.
continue;
}

// Search for the first datamodem.
if( GetLineDeviceCaps( dwLineId,
dwTAPIVersion,
pLineDeviceCaps ))
{
bDataModem = pLineDeviceCaps->dwLineMediaMode & LINEMEDIAMODE_DATAMODEM;

LocalFree( pLineDeviceCaps );
pLineDeviceCaps = NULL;

if( bDataModem )
break;
}
}

// Replace 'xxx' with your phone number.
if( !TranslateAddress( dwLineId,
dwTAPIVersion,
_T("xxx"),
szDialablePhoneNumber ))
{
goto Exit;
}

// Open the line.
if( !( hLine = OpenLine( dwLineId,
dwTAPIVersion )))
{
goto Exit;
}

// And make the call.
if( !( hCall = MakeCall( hLine,
szDialablePhoneNumber )))
{
goto Exit;
}

// Now wait for LINCALLSTATE_CONNECTED in the callback function and do something.

Exit:
if( hCall )
{
lineDrop( hCall, 0, NULL );
DeallocateCall( hCall );
hCall = NULL;
}

if( hLine )
{
lineClose( hLine );
hLine = NULL;
}

ShutdownTAPI();

return 0;
}
I'm quite sure a lot of people are interested in using TAPI. That's why I did this small tutorial. Good luck!

kunir
October 1st, 2003, 04:11 PM
Hi Michello
thanx man for help, i have to submit a project next month and i was thinking of TAPI and i was searching through MSDN but didn't got much idea, thanx for the code.
let me try it, i will be posting a reply after trying it out.

Kunir