📄 tapix.cpp
字号:
// Written by JHCC, 1997
#include "stdafx.h"
#include "tapix.h"
#include "TAPIErr.h"
#include "comm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// ---- CTAPIConnection ----
IMPLEMENT_SERIAL(CTAPIConnection, CObject, 0 /* schema number*/ )
BOOL CTAPIConnection::m_bInitializing = FALSE;
BOOL CTAPIConnection::m_bShuttingDown = FALSE;
CTypedPtrArray<class CObArray,class CTAPILine*> CTAPIConnection::m_lineArray;
HLINEAPP CTAPIConnection::m_hLineApp = 0;
CWnd* CTAPIConnection::m_pNotifyWnd = NULL;
DWORD CTAPIConnection::m_dwCallState = 0;
DWORD CTAPIConnection::m_dwAPILowVersion = 0x00010003;
DWORD CTAPIConnection::m_dwAPIHighVersion = 0x00010004;
DWORD CTAPIConnection::m_dwAnswerCallWait = (DWORD)-1;
//DWORD CTAPIConnection::m_dwMakeCallWait = (DWORD)-1;
BOOL CTAPIConnection::m_bCallStateReceived = FALSE;
DWORD CTAPIConnection::m_dwCommBaseCommandID = 0;
BYTE* CTAPIConnection::m_pReadBuf = NULL;
int CTAPIConnection::m_nReadBufLen = 0;
CTAPIConnection::CTAPIConnection()
{
}
CTAPIConnection::~CTAPIConnection()
{
ShutdownTAPI();
}
// Initializes TAPI
BOOL CTAPIConnection::Create(CWnd* pNotifyWnd,
DWORD dwAPILowVersion, DWORD dwAPIHighVersion,
DWORD dwCommBaseCommandID,
BYTE* pReadBuf, int nReadBufLen)
{
// If we're already initialized, then initialization succeeds.
if (m_hLineApp != 0)
{
TRACE0("Already initialized !\n");
return TRUE;
}
// If we're in the middle of initializing, then fail, we're not done.
// because a message loop in function, may be repeat call this function
if (m_bInitializing)
{
TRACE0("In the middle of initializing !\n");
return FALSE;
}
m_bInitializing = TRUE;
// Initialize TAPI
BOOL bFirstTryReInit = TRUE;
DWORD dwNumDevs;
long lReturn;
do
{
// Initialize TAPI
lReturn = ::lineInitialize(&m_hLineApp,
::AfxGetInstanceHandle(),
CTAPIConnection::LineCallbackFunc,
::AfxGetAppName(),
&dwNumDevs);
switch (lReturn)
{
// If we get this error, its because some other app has yet
// to respond to the REINIT message. Wait 5 seconds and try
// again. If it still doesn't respond, tell the user.
case LINEERR_REINIT:
if (bFirstTryReInit)
{
CTime startTime = CTime::GetCurrentTime();
CTimeSpan elapsedTime;
do
{
MSG msg;
if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
CTime endTime = CTime::GetCurrentTime();
elapsedTime = endTime - startTime;
}
while (elapsedTime.GetTotalSeconds() < 5);
bFirstTryReInit = FALSE;
}
else
{
::MessageBox(NULL,
"A change to the system configuration requires that "
"all Telephony applications relinquish their use of "
"Telephony before any can progress. "
"Some have not yet done so.", "Warning", MB_OK);
m_bInitializing = FALSE;
return FALSE;
}
break;
case LINEERR_NODEVICE:
if (!CTAPIError::HandleNoDevicesInstalled())
{
TRACE0("No devices installed.\n");
m_bInitializing = FALSE;
return FALSE;
}
break;
default:
if (!CTAPIError::HandleLineErr(lReturn))
{
TRACE0("lineInitialize unhandled error\n");
m_bInitializing = FALSE;
return FALSE;
}
}
// If there are no line devices installed on the machine, lets give
// the user the opportunity to install one.
if (lReturn == TAPISUCCESS && dwNumDevs < 1)
{
TRACE0("There are no telephony devices installed.");
if (!CTAPIError::HandleNoDevicesInstalled())
{
m_bInitializing = FALSE;
return FALSE;
}
}
}
while (lReturn != TAPISUCCESS);
// pNotifyWnd->AssertValid();
m_pNotifyWnd = pNotifyWnd;
m_dwAPILowVersion = dwAPILowVersion;
m_dwAPIHighVersion = dwAPIHighVersion;
// m_lineArray.SetSize(dwNumDevs);
// because some line maybe fail, such as INCOMPATIBLEAPIVERSION,
// the GetNumDevs() may not equals to dwNumDevs
for (DWORD i = 0; i < dwNumDevs; ++ i)
{
SetNewLine(i);
}
m_dwCommBaseCommandID = dwCommBaseCommandID;
m_pReadBuf = pReadBuf;
m_nReadBufLen = nReadBufLen;
TRACE0("Tapi initialized.\n");
m_bInitializing = FALSE;
return TRUE;
}
// Shuts down all use of TAPI
// If ShutdownTAPI fails, then its likely either a problem
// with the service provider (and might require a system
// reboot to correct) or the application ran out of memory.
BOOL CTAPIConnection::ShutdownTAPI()
{
long lReturn;
// If we aren't initialized, then Shutdown is unnecessary.
if (m_hLineApp == NULL)
return TRUE;
// Prevent ShutdownTAPI re-entrancy problems.
// because HangupCall have a message loop
if (m_bShuttingDown)
return TRUE;
m_bShuttingDown = TRUE;
for (int i = 0; i < GetNumDevs(); ++ i)
m_lineArray[i]->HangupCall();
do
{
lReturn = ::lineShutdown(m_hLineApp);
if (CTAPIError::HandleLineErr(lReturn))
continue;
else
{
TRACE0("lineShutdown unhandled error\n");
break;
}
}
while (lReturn != TAPISUCCESS);
for (int n = 0; n < m_lineArray.GetSize(); ++ n)
{
delete m_lineArray[n];
}
m_lineArray.RemoveAll();
m_hLineApp = NULL;
TRACE0("TAPI uninitialized.\n");
m_bShuttingDown = FALSE;
return TRUE;
}
// Wait for the line to reach a specific CallState.
// This function allows us to synchronously wait for a line
// to reach a specific LINESTATE or until the line is shut down.
//
// Note that this could cause re-entrancy problems as
// well as mess with any message preprocessing that might
// occur on this thread (such as TranslateAccelerator).
//
// One more note. This function can potentially be re-entered
// if the call is dropped for any reason while waiting. If this
// happens, just drop out and assume the wait has been canceled.
// This is signaled by setting bReentered to FALSE when the function
// is entered and TRUE when it is left. If bReentered is ever TRUE
// during the function, then the function was re-entered.
//
// This function should to be called from the thread that did
// lineInitialize, or the PeekMessage is on the wrong thread
// and the synchronization is not guaranteed to work. Also note
// that if another PeekMessage loop is entered while waiting,
// this could also cause synchronization problems.
//
// If the constant value I_LINECALLSTATE_ANY is used for the
// dwDesiredCallState, then WaitForCallState will return SUCCESS
// upon receiving any CALLSTATE messages.
long CTAPIConnection::WaitForCallState(DWORD dwDesiredCallState)
{
static BOOL bReentered = FALSE;
DWORD dwTimeStarted = GetTickCount();
m_bCallStateReceived = FALSE;
while ((dwDesiredCallState == I_LINECALLSTATE_ANY) ||
(m_dwCallState != dwDesiredCallState))
{
MSG msg;
if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
// If we are waiting for any call state and get one, succeed.
if ((dwDesiredCallState == I_LINECALLSTATE_ANY) &&
m_bCallStateReceived)
{
break;
}
// This should only occur if the line is shut down while waiting.
if (/*!m_bTapiInUse || */bReentered)
{
bReentered = TRUE;
TRACE0("WAITABORTED\n");
return WAITERR_WAITABORTED;
}
// If we don't get the reply in a reasonable time, we time out.
if (GetTickCount() - dwTimeStarted > WAITTIMEOUT)
{
bReentered = TRUE;
TRACE0("WAITTIMEDOUT\n");
return WAITERR_WAITTIMEDOUT;
}
}
bReentered = TRUE;
return TAPISUCCESS;
}
//**************************************************
// LineCallback Function and Handlers.
//**************************************************
// Receive asynchronous TAPI events
// dwDevice - Device associated with the event, if any
// dwMsg - TAPI event that occurred.
// dwCallbackInstance - User defined data supplied when opening the line.
// dwParam1 - dwMsg specific information
// dwParam2 - dwMsg specific information
// dwParam3 - dwMsg specific information
// This is the function where all asynchronous events will come.
// Almost all events will be specific to an open line, but a few
// will be general TAPI events (such as LINE_REINIT).
//
// Its important to note that this callback will *ALWAYS* be
// called in the context of the thread that does the lineInitialize.
// Even if another thread (such as the COMM threads) calls the API
// that would result in the callback being called, it will be called
// in the context of the main thread (since in this sample, the main
// thread does the lineInitialize).
void CALLBACK CTAPIConnection::LineCallbackFunc(DWORD dwDevice,
DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
CTAPIError::OutputDebugLineCallback(dwDevice, dwMsg,
dwCallbackInstance, dwParam1, dwParam2, dwParam3);
// All we do is dispatch the dwMsg to the correct handler.
switch (dwMsg)
{
case LINE_CALLSTATE:
DoLineCallState(dwDevice, dwMsg, dwCallbackInstance, dwParam1, dwParam2,
dwParam3);
break;
case LINE_CLOSE:
DoLineClose(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_LINEDEVSTATE:
DoLineDevState(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_REPLY:
DoLineReply(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
case LINE_CREATE:
DoLineCreate(dwDevice, dwMsg, dwCallbackInstance,
dwParam1, dwParam2, dwParam3);
break;
// other messages that can be processed
case LINE_ADDRESSSTATE:
break;
case LINE_CALLINFO:
break;
case LINE_DEVSPECIFIC:
break;
case LINE_DEVSPECIFICFEATURE:
break;
case LINE_GATHERDIGITS:
break;
case LINE_GENERATE:
break;
case LINE_MONITORDIGITS:
break;
case LINE_MONITORMEDIA:
break;
case LINE_MONITORTONE:
break;
default:
TRACE0("LineCallbackFunc message ignored\n");
break;
}
}
// Handle LINE_REPLY asynchronous messages.
// dwDevice - Line Handle associated with this LINE_REPLY.
// dwMsg - Should always be LINE_REPLY.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - Asynchronous request ID.
// dwParam2 - success or LINEERR error value.
// dwParam3 - Unused.
// All line API calls that return an asynchronous request ID
// will eventually cause a LINE_REPLY message. Handle it.
//
// This sample assumes only one call at time, and that we wait
// for a LINE_REPLY before making any other line API calls.
//
// The only exception to the above is that we might shut down
// the line before receiving a LINE_REPLY.
void CTAPIConnection::DoLineReply(DWORD dwDevice,
DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
if (dwParam2 != TAPISUCCESS)
{
TRACE1("LINE_REPLY error: 0x%lx\n", (long)dwParam2);
return;
}
TRACE0("LINE_REPLY: successfully replied.\n");
int nIndex = -1;
/* if (m_dwMakeCallWait == (DWORD)-1)
{*/
nIndex = GetAsyncIDIndex(dwParam1);
ASSERT(nIndex != -1);
/* }
else
{
nIndex = (int)m_dwMakeCallWait;
ASSERT(m_lineArray[nIndex]->m_dwAsyncID == (DWORD)-1);
m_lineArray[nIndex]->m_dwAsyncID == dwParam1;
TRACE0("m_dwAsyncID = dwParam1\n");
}*/
switch (m_lineArray[nIndex]->m_WaitReplyType)
{
case CTAPILine::REPLY_NONE:
break;
// reply message for lineAnswer
case CTAPILine::REPLY_ANSWERCALL:
m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
m_dwAnswerCallWait = (DWORD)-1;
break;
// reply message for lineMakeCall
case CTAPILine::REPLY_MAKECALL:
m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
// m_dwMakeCallWait = (DWORD)-1;
break;
// reply message for lineDrop
case CTAPILine::REPLY_DROPCALL:
m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
break;
}
}
// Handle LINE_CLOSE asynchronous messages.
// dwDevice - Line Handle that was closed.
// dwMsg - Should always be LINE_CLOSE.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -