📄 simpletapi.cpp
字号:
if ( result != 0 )
::MessageBox( GetWindow(),
"Something bad happened",
"SimpleTapi Message",
MB_OK );
}
//
// Configuring phone calls is another fairly difficult task
// that TAPI takes on for us. All we have to do is pass in
// the ID of the device and the phone number to be called.
// TAPI then creates a dialog that takes care of thinking
// about all sorts of dialing issues.
//
void SimpleTapi::ConfigureCall( int index, const string &number )
{
int dev_id = m_Devices[ index ].m_iDeviceNumber;
LONG result = lineTranslateDialog( m_hLineApp,
dev_id,
TAPI_CURRENT_VERSION,
GetWindow(),
number.c_str() );
if ( result != 0 )
Error( "Error returned from lineTranslateDialog : ",
result );
}
//
// If a line is open and doesn't have a call in progress, we
// can use this routine to initiate a call. Looking down into
// the call, you can see that you need to have a valid m_hLine
// handle to make the call, along with a number and a device
// id. The first part of the function calls
// lineTranslateAddress() to mangle the digit string into
// something that can be used to make the call. It needs the
// device ID and the phone number to do that.
//
// Once the phone number has been properly mangled, we set up
// a LINECALLPARMS structure and make a call to lineMakeCall.
// That function can do one of three things. It might fail
// with an error, It might return immediately with a valid
// result. But most likely, it will tell me that it doesn't
// have a result yet, and I'll just have to wait. When that
// happens, I set up the m_ReplyAction so that I know I'm
// expecting something, and I return.
//
// Note that when you call this function, or the other
// asynchronous functions in SimpleTapi, you never get
// anything useful back, which is why these guys are all of
// type void. You wait for response to come back from the
// callback notification routines.
//
void SimpleTapi::MakeCall( const string &number )
{
//
// This first call is another one of those with an
// indeterminate requirement for the size of the
// data structure. The Redmond way is to call it twice,
// the first time you will fail but find out how much
// space you need. The second time you call it with the
// correct amount of space. I thwart this strategy by
// allocating a hugely excessive amount of space so
// that I'll never fail. probably.
//
char buf[ 4096 ];
LINETRANSLATEOUTPUT *lto = (LINETRANSLATEOUTPUT *) buf;
lto->dwTotalSize = 4096;
LONG result = lineTranslateAddress( m_hLineApp,
m_iDeviceId,
TAPI_CURRENT_VERSION,
number.c_str(),
0,
0,
lto );
if ( result != 0 ) {
Error( "Error returned from lineTranslateAddress : ", result );
return;
}
m_sNumber = string( buf + lto->dwDialableStringOffset,
lto->dwDialableStringSize );
m_Trace << "Dial number = "
<< m_sNumber
<< "\n";
LINECALLPARAMS lcp;
memset( &lcp, 0, sizeof( LINECALLPARAMS ) );
lcp.dwTotalSize = sizeof( LINECALLPARAMS );
lcp.dwBearerMode = LINEBEARERMODE_VOICE;
lcp.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
lcp.dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;
lcp.dwAddressMode = LINEADDRESSMODE_ADDRESSID;
result = lineMakeCall( m_hLine,
&m_hCall,
m_sNumber.c_str(),
0,
&lcp );
if ( result < 0 ) {
Error( "Error returned from lineMakeCall : ", result );
return;
} else if ( result == 0 ) {
m_Trace << "lineMakeCall returned : "
<< TranslateTapiError( result )
<< "\n";
HandleMakeCallResult( 0 );
} else {
m_ReplyAction = HANDLE_MAKE_CALL_RESULT;
m_dwPendingReplyCode = result;
}
}
//
// Dropping a call is easier than making one, but it still
// has to be dealt with asynchronously. All we need to
// get the whole thing going is a call handle, which we
// pass to lineDrop(). It might generate an eerror, or an
// immediate response, but most likely it will let us
// know that it will get back to us later via notification
// We make a note of that by setting the m_ReplyAction
// enumerated value to signify that we are waiting for a
// drop result.
//
void SimpleTapi::DropCall()
{
LONG result = lineDrop( m_hCall,
NULL,
0 );
if ( result < 0 ) {
Error( "Error returned from lineDrop : ", result );
return;
} else if ( result == 0 ) {
m_Trace << "lineDrop returned : "
<< dec << result
<< "\n";
HandleDropResult( 0 );
} else {
m_ReplyAction = HANDLE_DROP_RESULT;
m_dwPendingReplyCode = result;
}
}
//
// These three functions are all fundamentally the same.
// Each of them is called when a delayed response comes
// in to a previous action, which is either a request to
// make a call, answer a call, or drop a call.
//
// Each of the functions does a small amount of internal
// class maintenance. Two of the functions then call a
// user notification function. The two notification functions
// are pure virtual, so they must be defined in a derived
// class.
//
// Why doesn't the Answer handler have a notification
// routine? SimpleTapi doesn't have an Answer call that the
// user of the class can call. Instead, it automatically
// answers any incoming call. So the user doesn't ever have
// to worry about a response to an Answer call. A more
// completel TAPI class wouldn't automatically answer calls;
// it would notify users of incoming offering states and
// let the user make some sort of answer response.
//
void SimpleTapi::HandleMakeCallResult( DWORD result )
{
m_Trace << "lineMakeCall returned (delayed) : "
<< TranslateTapiError( result )
<< "\n";
if ( result == 0 )
m_bCallHandleValid = true;
else {
Error( "Delayed error returned from lineMakeCall : ", result );
m_bCallHandleValid = false;
}
MakeCallResult( m_bCallHandleValid );
}
void SimpleTapi::HandleAnswerResult( DWORD result )
{
m_Trace << "lineAnswer returned (delayed) : "
<< result
<< "\n";
if ( result == 0 )
m_bCallHandleValid = true;
else {
Error( "Delayed error returned from lineAnswer : ", result );
m_bCallHandleValid = false;
}
}
void SimpleTapi::HandleDropResult( DWORD result )
{
m_Trace << "lineDrop returned (delayed) : "
<< result
<< "\n";
if ( result != 0 )
Error( "Delayed error returned from lineDrop : ", result );
DropCallResult( result == 0 );
}
//
// After creating the TAPI object, the user has to open a
// line to do antyhing useful at all. This is done with a
// call to lineOpen(). That call expects a valid device
// id, which we get from the caller, and an app handle,
// which was created when the object was first built.
//
// The device ID is retrieved from the m_Devices[] vector,
// which got copies of all device names and IDs when we
// iterated through the list at creation time.
//
// If we opne the line succesfully, the m_hLine member will
// then have a valid handle, and we are ready to make and
// accept calls.
//
int SimpleTapi::OpenLine( int index )
{
m_iDeviceId = m_Devices[ index ].m_iDeviceNumber;
LONG result = lineOpen( m_hLineApp,
m_iDeviceId,
&m_hLine,
TAPI_CURRENT_VERSION,
0,
(DWORD) this,
LINECALLPRIVILEGE_OWNER,
LINEMEDIAMODE_DATAMODEM,
NULL );
if ( result != 0 )
Error( "Error returned in WaitFoprCall from lineOpen : ", result );
else
NotifyCallStateChange( LINECALLSTATE_IDLE );
return result;
}
//
// Before shutting down we really need to close the line.
// This is also a good way to make sure we don't accidentally
// answer any incoming calls. TAPI function lineClose()
// takes care of this immediately.
int SimpleTapi::CloseLine()
{
LONG result = lineClose( m_hLine );
m_hLine = 0;
if ( result < 0 )
Error( "Error returned from lineClose : ", result );
else {
m_Trace << "lineClose returned : "
<< result
<< "\n";
NotifyCallStateChange( -1 );
}
return result;
}
//
// This function is a little deceptive. After a call is put
// through to the connected state, we can take the resulting
// handle and treat it as a port handle, using it for normal
// serial port functions. In the Chapter 15 example we take
// the resulting port handle and turn it into a Win32Port,
// and proceed to use it as a terminal emulator.
//
// Once we get this port handle, we bear a certain measure
// of responsibility for it. When we are done using it, we
// have to specifically close it with a call to
// CloseHandle(), or the books in the O/S won't balance.
//
HANDLE SimpleTapi::GetPortHandle()
{
//
// This is another one of those calls that take an
// unknown number of byte. I drastically overestimate
// the amount in hopes that I won't have to deal with
// possibility of failure.
//
char temp[ 4096 ];
VARSTRING *vs = (VARSTRING *) temp;
vs->dwTotalSize = 4096;
LONG result = lineGetID( 0, //hLine
0, //dwAddressID
m_hCall, //hCall
LINECALLSELECT_CALL, //dwSelect
vs,
"comm/datamodem" );
if ( result < 0 ) {
Error( "Error returned from lineGetID : ", result );
return 0;
}
HANDLE *p = (HANDLE *) ((LPSTR) vs + vs->dwStringOffset);
return *p;
}
//EOF SimpleTapi.cpp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -