📄 tapiconn._cp
字号:
// Modify by FangHong, 1997
#include "stdafx.h"
#include "tapiconn.h"
//BOOL bAnswerCallInProgress;
//DWORD m_dwAsyncID; // id of pending async operation
DWORD m_dwCallState = 0;
char m_szDisplayableAddress[1024] = "";
//char m_szDialableAddress[1024] = "";
BOOL m_bCallStateReceived;
LPVOID g_lpDeviceConfig = NULL;
// Possible return error for resynchronization functions.
#define WAITERR_WAITABORTED 1
// Constant used in WaitForCallState when any new
// callstate message is acceptable.
#define I_LINECALLSTATE_ANY 0
// Wait up to 30 seconds for an async completion.
#define WAITTIMEOUT 30000
// Possible return error for resynchronization functions.
#define WAITERR_WAITABORTED 1
#define WAITERR_WAITTIMEDOUT 2
// Structures needed to handle special non-dialable characters.
#define g_sizeofNonDialable (sizeof(g_sNonDialable)/sizeof(g_sNonDialable[0]))
struct NONDIALTOKENS
{
LONG lError;
DWORD dwDevCapFlag;
LPSTR szToken;
LPSTR szMsg;
};
NONDIALTOKENS g_sNonDialable[] =
{
{
LINEERR_DIALBILLING,
LINEDEVCAPFLAGS_DIALBILLING,
"$",
"Wait for the credit card bong tone"
},
{
LINEERR_DIALDIALTONE,
LINEDEVCAPFLAGS_DIALDIALTONE,
"W",
"Wait for the second dial tone"
},
{
LINEERR_DIALDIALTONE,
LINEDEVCAPFLAGS_DIALDIALTONE,
"w",
"Wait for the second dial tone"
},
{
LINEERR_DIALQUIET,
LINEDEVCAPFLAGS_DIALQUIET,
"@",
"Wait for the remote end to answer"
},
{
LINEERR_DIALPROMPT,
0,
"?",
"Press OK when you are ready to continue dialing"
},
};
// A pointer to my class because TAPI needs a callback
BOOL CTapiConnection::m_bTapiInUse = FALSE;
DWORD CTapiConnection::m_dwRequestedID;
LONG CTapiConnection::m_lAsyncReply;
BOOL CTapiConnection::m_bReplyRecieved;
CTapiConnection* CTapiConnection::m_this = NULL;
//
// Constructor
//
CTapiConnection::CTapiConnection()
{
m_bShuttingDown = FALSE;
m_bStoppingCall = FALSE;
m_bInitializing = FALSE;
m_dwNumDevs = 0;
m_hCall = NULL;
m_hLine = NULL;
m_dwDeviceID = 0;
m_hLineApp = NULL;
// Comm Ctrls
m_bConnected = FALSE;
m_pNotifyWnd = NULL;
m_hCommFile = NULL;
m_dwReadThreadID = 0;
m_dwWriteThreadID = 0;
m_hReadThread = NULL;
m_hWriteThread = NULL;
m_hCloseEvent = NULL;
m_this = this;
};
//
// Destructor
//
CTapiConnection::~CTapiConnection()
{
m_bInitialized = FALSE;
ShutdownTAPI();
};
//
// FUNCTION: BOOL Create()
//
// PURPOSE: Initializes TAPI
//
BOOL CTapiConnection::Create(LPCTSTR szPhoneNumber)
{
long lReturn;
BOOL bTryReInit = TRUE;
// If we're already initialized, then initialization succeeds.
if (m_hLineApp)
return TRUE;
// If we're in the middle of initializing, then fail, we're not done.
if (m_bInitializing)
return FALSE;
m_bInitializing = TRUE;
// Initialize TAPI
do
{
lReturn = ::lineInitialize(&m_hLineApp,
::AfxGetInstanceHandle(),
lineCallbackFunc,
::AfxGetAppName(),
&m_dwNumDevs);
// 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.
if (lReturn == LINEERR_REINIT)
{
if (bTryReInit)
{
MSG msg;
DWORD dwTimeStarted;
dwTimeStarted = GetTickCount();
while (GetTickCount() - dwTimeStarted < 5000)
{
if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
bTryReInit = FALSE;
continue;
}
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;
}
}
if (lReturn == LINEERR_NODEVICE)
{
if (HandleNoDevicesInstalled())
continue;
else
{
TRACE0("No devices installed.\n");
m_bInitializing = FALSE;
return FALSE;
}
}
if (m_dwNumDevs == 0)
{
::AfxMessageBox("There are no telephony devices installed.");
m_bInitializing = FALSE;
return FALSE;
}
if (HandleLineErr(lReturn))
continue;
else
{
TRACE0("lineInitialize unhandled error\n");
m_bInitializing = FALSE;
return FALSE;
}
}
while(lReturn != TAPISUCCESS);
TRACE0("Tapi initialized.\n");
// If the user furnished a phone number copy it over.
if (szPhoneNumber)
::strcpy(m_szPhoneNumber, szPhoneNumber);
m_bInitializing = FALSE;
return TRUE;
}
//
// FUNCTION: DialCall()
//
// PURPOSE: Get a number from the user and dial it.
//
BOOL CTapiConnection::DialCall(LPCTSTR szPhoneNumber)
{
// if already connected or in a pending state, do nothing
// if (m_bConnected || m_dwAsyncID)
// return FALSE;
long lReturn;
LPLINEADDRESSSTATUS lpLineAddressStatus = NULL;
LPLINEDEVCAPS lpLineDevCaps = NULL;
if (m_bTapiInUse)
{
::AfxMessageBox("A call is already being handled.");
return FALSE;
}
// Make sure TAPI is initialized properly
if (!m_hLineApp)
{
if (!Create(NULL))
return FALSE;
}
// If there are no line devices installed on the machine, lets give
// the user the opportunity to install one.
if (m_dwNumDevs < 1)
{
if (!HandleNoDevicesInstalled())
return FALSE;
}
// We now have a call active. Prevent future calls.
m_bTapiInUse = TRUE;
// Get a phone number from the user.
if (szPhoneNumber == NULL)
{
if (m_szPhoneNumber == NULL)
{
HangupCall();
goto LABEL_DELETEBUFFERS;
}
}
else
strcpy(m_szPhoneNumber, szPhoneNumber);
// Negotiate the API version to use for this device.
m_dwAPIVersion = I_lineNegotiateAPIVersion(m_dwDeviceID);
if (m_dwAPIVersion == 0)
{
MessageBox(NULL,
"Line Version unsupported by this Sample",
"Unable to Use Line",MB_OK);
HangupCall();
goto LABEL_DELETEBUFFERS;
}
// Need to check the DevCaps to make sure this line is usable.
// The 'Dial' dialog checks also, but better safe than sorry.
lpLineDevCaps = I_lineGetDevCaps(lpLineDevCaps,
m_dwDeviceID, m_dwAPIVersion);
// Get the line to use
// lpLineDevCaps = GetDeviceLine(&m_dwAPIVersion, lpLineDevCaps);
// Need to check the DevCaps to make sure this line is usable.
if (lpLineDevCaps == NULL)
{
HangupCall();
MessageBox(NULL,
"Error on Requested line",
"Unable to Use Line",MB_OK);
goto LABEL_DELETEBUFFERS;
}
if (!(lpLineDevCaps->dwBearerModes & LINEBEARERMODE_VOICE))
{
HangupCall();
::AfxMessageBox("The selected line doesn't support VOICE capabilities");
goto LABEL_DELETEBUFFERS;
}
if (!(lpLineDevCaps->dwMediaModes & LINEMEDIAMODE_DATAMODEM))
{
HangupCall();
MessageBox(NULL,
"Error on Requested line",
"The selected line doesn't support DATAMODEM capabilities",
MB_OK);
goto LABEL_DELETEBUFFERS;
}
// Does this line have the capability to make calls?
if (!(lpLineDevCaps->dwLineFeatures & LINEFEATURE_MAKECALL))
{
HangupCall();
::AfxMessageBox("The selected line doesn't support MAKECALL capabilities");
goto LABEL_DELETEBUFFERS;
}
// Open the Line for an outgoing call.
do
{
lReturn = ::lineOpen(m_hLineApp, m_dwDeviceID, &m_hLine,
m_dwAPIVersion, 0, 0,
// LINECALLPRIVILEGE_NONE, 0, 0);
LINECALLPRIVILEGE_OWNER, LINEMEDIAMODE_DATAMODEM, NULL);
if ((lReturn == LINEERR_ALLOCATED) || (lReturn == LINEERR_RESOURCEUNAVAIL))
{
HangupCall();
TRACE0("Line is already in use by a non-TAPI application "
"or by another TAPI Service Provider.\n");
goto LABEL_DELETEBUFFERS;
}
if (HandleLineErr(lReturn))
continue;
else
{
TRACE0("Unable to Use Line\n");
HangupCall();
goto LABEL_DELETEBUFFERS;
}
}
while (lReturn != TAPISUCCESS);
// Tell the service provider that we want all notifications that
// have anything to do with this line.
do
{
// Set the messages we are interested in.
// Note that while most applications aren't really interested
// in dealing with all of the possible messages, its interesting
// to see which come through the callback for testing purposes.
lReturn = ::lineSetStatusMessages(m_hLine,
LINEDEVSTATE_OTHER |
LINEDEVSTATE_RINGING |
LINEDEVSTATE_CONNECTED | // Important state!
LINEDEVSTATE_DISCONNECTED | // Important state!
LINEDEVSTATE_MSGWAITON |
LINEDEVSTATE_MSGWAITOFF |
LINEDEVSTATE_INSERVICE |
LINEDEVSTATE_OUTOFSERVICE | // Important state!
LINEDEVSTATE_MAINTENANCE | // Important state!
LINEDEVSTATE_OPEN |
LINEDEVSTATE_CLOSE |
LINEDEVSTATE_NUMCALLS |
LINEDEVSTATE_NUMCOMPLETIONS |
LINEDEVSTATE_TERMINALS |
LINEDEVSTATE_ROAMMODE |
LINEDEVSTATE_BATTERY |
LINEDEVSTATE_SIGNAL |
LINEDEVSTATE_DEVSPECIFIC |
LINEDEVSTATE_REINIT | // Not allowed to disable this.
LINEDEVSTATE_LOCK |
LINEDEVSTATE_CAPSCHANGE |
LINEDEVSTATE_CONFIGCHANGE |
LINEDEVSTATE_COMPLCANCEL,
LINEADDRESSSTATE_OTHER |
LINEADDRESSSTATE_DEVSPECIFIC |
LINEADDRESSSTATE_INUSEZERO |
LINEADDRESSSTATE_INUSEONE |
LINEADDRESSSTATE_INUSEMANY |
LINEADDRESSSTATE_NUMCALLS |
LINEADDRESSSTATE_FORWARD |
LINEADDRESSSTATE_TERMINALS |
LINEADDRESSSTATE_CAPSCHANGE);
if (HandleLineErr(lReturn))
continue;
else
{
// If we do get an unhandled problem, we don't care.
// We just won't get notifications.
OutputDebugLineError(lReturn,
"lineSetStatusMessages unhandled error: ");
break;
}
}
while (lReturn != TAPISUCCESS);
// Get LineAddressStatus so we can make sure the line
// isn't already in use by a TAPI application.
lpLineAddressStatus =
I_lineGetAddressStatus(lpLineAddressStatus, m_hLine, 0);
if (lpLineAddressStatus == NULL)
{
HangupCall();
MessageBox(NULL,
"Error on Requested line",
"Unable to Use Line",MB_OK);
goto LABEL_DELETEBUFFERS;
}
// MAKECALL will be set if there are any available call appearances
if (!((lpLineAddressStatus->dwAddressFeatures) & LINEADDRFEATURE_MAKECALL))
{
TRACE0("This line is not available to place a call.\n");
HangupCall();
MessageBox(NULL,
"Requested line is already in use",
"Unable to Use Line",MB_OK);
goto LABEL_DELETEBUFFERS;
}
// If the line was configured in the 'Dial' dialog, then
// we need to actually complete the configuration.
if (g_lpDeviceConfig)
::lineSetDevConfig(m_dwDeviceID, g_lpDeviceConfig,
m_dwSizeDeviceConfig, "comm/datamodem");
/*
// Start dialing the number
if (MakeTheCall(lpLineDevCaps, m_szPhoneNumber))
TRACE0("lineMakeCall succeeded.\n");
else
{
TRACE0("lineMakeCall failed.\n");
HangupCall();
}
*/
// Start dialing the number
if (DialCallInParts(lpLineDevCaps, m_szPhoneNumber,//m_szDialableAddress,
/*m_szDisplayableAddress*/m_szPhoneNumber + 1))
{
TRACE0("DialCallInParts succeeded.\n");
}
else
{
TRACE0("DialCallInParts failed.\n");
HangupCall();
goto LABEL_DELETEBUFFERS;
}
LABEL_DELETEBUFFERS:
if (lpLineAddressStatus)
LocalFree(lpLineAddressStatus);
if (lpLineDevCaps)
::LocalFree(lpLineDevCaps);
return m_bTapiInUse;
}
//
// FUNCTION: void GetDeviceLine()
//
// PURPOSE: Gets the first available line device.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -