📄 tapix.cpp
字号:
// dwCallbackInstance - Unused by this sample.
// dwParam1 - Unused.
// dwParam2 - Unused.
// dwParam3 - Unused.
// This message is sent when something outside our app
// shuts down a line in use.
//
// The hLine (and any hCall on this line) are no longer valid.
void CTAPIConnection::DoLineClose(DWORD dwDevice,
DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
TRACE0("Call was shut down.");
// Line has been shut down. Clean up our internal variables.
int nIndex = GetLineDeviceIDIndex((HLINE)dwDevice);
ASSERT(nIndex != -1);
m_lineArray[nIndex]->HangupCall();
// ::MessageBox(NULL, "Call was shut down.", "Warning", MB_OK);
}
// Handle LINE_LINEDEVSTATE asynchronous messages.
// dwDevice - Line Handle that was closed.
// dwMsg - Should always be LINE_LINEDEVSTATE.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - LINEDEVSTATE constant.
// dwParam2 - Depends on dwParam1.
// dwParam3 - Depends on dwParam1.
// The LINE_LINEDEVSTATE message is received if the state of the line
// changes. Examples are RINGING, MAINTENANCE, MSGWAITON. Very few of
// these are relevant to this sample.
//
// Assuming that any LINEDEVSTATE that removes the line from use by TAPI
// will also send a LINE_CLOSE message.
void CTAPIConnection::DoLineDevState(DWORD dwDevice,
DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
switch (dwParam1)
{
case LINEDEVSTATE_RINGING:
TRACE0("Line Ringing.\n");
break;
case LINEDEVSTATE_REINIT:
// This is an important case! Usually means that a service provider
// has changed in such a way that requires TAPI to REINIT.
// Note that there are both 'soft' REINITs and 'hard' REINITs.
// Soft REINITs don't actually require a full shutdown but is instead
// just an informational change that historically required a REINIT
// to force the application to deal with. TAPI API Version 1.3 apps
// will still need to do a full REINIT for both hard and soft REINITs.
switch (dwParam2)
{
// This is the hard REINIT. No reason given, just REINIT.
// TAPI is waiting for everyone to shutdown.
// Our response is to immediately shutdown any calls,
// shutdown our use of TAPI and notify the user.
case 0:
ShutdownTAPI();
CTAPIError::WarningBox(_T("Tapi line configuration has changed."));
break;
case LINE_CREATE:
TRACE0("Soft REINIT: LINE_CREATE.\n");
DoLineCreate(dwDevice, dwParam2, dwCallbackInstance,
dwParam3, 0, 0);
break;
case LINE_LINEDEVSTATE:
TRACE0("Soft REINIT: LINE_LINEDEVSTATE.\n");
DoLineDevState(dwDevice, dwParam2, dwCallbackInstance,
dwParam3, 0, 0);
break;
// There might be other reasons to send a soft reinit.
// No need to to shutdown for these.
default:
TRACE0("Ignoring soft REINIT\n");
break;
}
break;
case LINEDEVSTATE_OUTOFSERVICE:
CTAPIError::WarningBox(_T("Line selected is now Out of Service."));
{
int nIndex = GetLineDeviceIDIndex((HLINE)dwDevice);
ASSERT(nIndex != -1);
m_lineArray[nIndex]->HangupCall();
}
break;
case LINEDEVSTATE_DISCONNECTED:
CTAPIError::WarningBox(_T("Line selected is now disconnected."));
{
int nIndex = GetLineDeviceIDIndex((HLINE)dwDevice);
ASSERT(nIndex != -1);
m_lineArray[nIndex]->HangupCall();
}
break;
case LINEDEVSTATE_MAINTENANCE:
CTAPIError::WarningBox(_T("Line selected is now out for maintenance."));
{
int nIndex = GetLineDeviceIDIndex((HLINE)dwDevice);
ASSERT(nIndex != -1);
m_lineArray[nIndex]->HangupCall();
}
break;
case LINEDEVSTATE_TRANSLATECHANGE:
// if (g_hDialog)
// PostMessage(g_hDialog, WM_COMMAND, IDC_CONFIGURATIONCHANGED, 0);
break;
case LINEDEVSTATE_REMOVED:
TRACE0("A Line device has been removed; no action taken.\n");
break;
default:
TRACE0("Unhandled LINEDEVSTATE message\n");
}
}
// Handle LINE_CREATE asynchronous messages.
// dwDevice - Unused.
// dwMsg - Should always be LINE_CREATE.
// dwCallbackInstance - Unused.
// dwParam1 - dwDeviceID of new Line created.
// dwParam2 - Unused.
// dwParam3 - Unused.
// This message is new for Windows 95. It is sent when a new line is
// added to the system. This allows us to handle new lines without having
// to REINIT. This allows for much more graceful Plug and Play.
//
// This sample just changes the number of devices available and can use
// it next time a call is made. It also tells the "Dial" dialog.
void CTAPIConnection::DoLineCreate(DWORD dwDevice,
DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
// dwParam1 is the Device ID of the new line.
// Add one to get the number of total devices.
SetNewLine(dwParam1);
// if (g_hDialog)
// PostMessage(g_hDialog, WM_COMMAND, IDC_LINECREATE, 0);
}
// Handle LINE_CALLSTATE asynchronous messages.
// dwDevice - Handle to Call who's state is changing.
// dwMsg - Should always be LINE_CALLSTATE.
// dwCallbackInstance - Unused by this sample.
// dwParam1 - LINECALLSTATE constant specifying state change.
// dwParam2 - Specific to dwParam1.
// dwParam3 - LINECALLPRIVILEGE change, if any.
// This message is received whenever a call changes state. Lots of
// things we do, ranging from notifying the user to closing the line
// to actually connecting to the target of our phone call.
//
// What we do is usually obvious based on the call state change.
void CTAPIConnection::DoLineCallState(DWORD dwDevice,
DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{
// When receive the LINECALLSTATE_IDLE,
// the line is already hanguped, so ASSERT will fail !
int nIndex = -1;
if (dwParam1 != LINECALLSTATE_IDLE)
{
if (m_dwAnswerCallWait == (DWORD)-1)// && m_dwMakeCallWait == (DWORD)-1)
{
nIndex = GetCallDeviceIDIndex((HCALL)dwDevice);
ASSERT(nIndex != -1);
}
else
{
// if (m_dwMakeCallWait != (DWORD)-1)
// nIndex = (int)m_dwMakeCallWait;
// else
nIndex = (int)m_dwAnswerCallWait;
ASSERT(m_lineArray[nIndex]->m_hCall == (HCALL)-1);
m_lineArray[nIndex]->m_hCall = (HCALL)dwDevice;
// m_dwMakeCallWait = (DWORD)-1;
}
}
// This sets the global m_dwCallState variable so if we are waiting
// for a specific call state change, we will know when it happens.
m_dwCallState = dwParam1;
m_bCallStateReceived = TRUE;
// dwParam1 is the specific CALLSTATE change that is occurring.
switch (dwParam1)
{
case LINECALLSTATE_DIALTONE:
TRACE0("Dial Tone\n");
break;
case LINECALLSTATE_DIALING:
TRACE0("Dialing Call\n");
break;
case LINECALLSTATE_PROCEEDING:
TRACE0("Call is Proceeding\n");
break;
case LINECALLSTATE_RINGBACK:
TRACE0("RingBack\n");
break;
case LINECALLSTATE_BUSY:
TRACE0("Line busy, shutting down\n");
m_lineArray[nIndex]->HangupCall();
break;
case LINECALLSTATE_IDLE:
TRACE0("Line is idle\n");
// m_lineArray[nIndex]->HangupCall();
break;
case LINECALLSTATE_OFFERING:
// The call is being offered, signaling the arrival of a new call.
// check if we are the owner of the call, and if we are, then answer it.
// dwParam3 contains changes to LINECALLPRIVILEGE, if there are any.
switch (dwParam3)
{
case 0:
break; // no change to call state
// if we are made monitor.
case LINECALLPRIVILEGE_MONITOR:
TRACE0("line given monitor privilege\n");
return;
// if we are made owner.
case LINECALLPRIVILEGE_OWNER:
{
TRACE0("line given owner privilege\n");
long lReturn = ::lineAnswer(m_lineArray[nIndex]->m_hCall, NULL, 0);
if (lReturn < 0)
{
m_lineArray[nIndex]->m_hCall = (HCALL)-1;
m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
return;
} // end if (we own this call)
else
{
m_lineArray[nIndex]->m_dwAsyncID = lReturn;
m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_ANSWERCALL;
}
break;
}
default: // Shouldn't happen! All cases handled.
TRACE0("Unknown LINECALLPRIVILEGE message: closing\n");
m_lineArray[nIndex]->HangupCall();
return;
}
break;
case LINECALLSTATE_SPECIALINFO:
TRACE0("Special Info, probably couldn't dial number\n");
m_lineArray[nIndex]->HangupCall();
break;
case LINECALLSTATE_DISCONNECTED:
switch (dwParam2)
{
case LINEDISCONNECTMODE_NORMAL:
TRACE0("Remote Party Disconnected\n");
break;
case LINEDISCONNECTMODE_UNKNOWN:
TRACE0("Disconnected: Unknown reason\n");
break;
case LINEDISCONNECTMODE_REJECT:
TRACE0("Remote Party rejected call\n");
break;
case LINEDISCONNECTMODE_PICKUP:
TRACE0("Disconnected: Local phone picked up\n");
break;
case LINEDISCONNECTMODE_FORWARDED:
TRACE0("Disconnected: Forwarded\n");
break;
case LINEDISCONNECTMODE_BUSY:
TRACE0("Disconnected: Busy\n");
break;
case LINEDISCONNECTMODE_NOANSWER:
TRACE0("Disconnected: No Answer\n");
break;
case LINEDISCONNECTMODE_BADADDRESS:
TRACE0("Disconnected: Bad Address\n");
break;
case LINEDISCONNECTMODE_UNREACHABLE:
TRACE0("Disconnected: Unreachable\n");
break;
case LINEDISCONNECTMODE_CONGESTION:
TRACE0("Disconnected: Congestion\n");
break;
case LINEDISCONNECTMODE_INCOMPATIBLE:
TRACE0("Disconnected: Incompatible\n");
break;
case LINEDISCONNECTMODE_UNAVAIL:
TRACE0("Disconnected: Unavail\n");
break;
case LINEDISCONNECTMODE_NODIALTONE:
TRACE0("Disconnected: No Dial Tone\n");
break;
default:
TRACE0("Disconnected: LINECALLSTATE; Bad Reason\n");
break;
}
m_lineArray[nIndex]->HangupCall();
break;
case LINECALLSTATE_CONNECTED: // CONNECTED!!!
{
HANDLE hCommFile = 0;
// pNotifyWnd->SendMessage();
// Very first, make sure this isn't a duplicated message.
// A CALLSTATE message can be sent whenever there is a
// change to the capabilities of a line, meaning that it is
// possible to receive multiple CONNECTED messages per call.
// The CONNECTED CALLSTATE message is the only one in TapiComm
// where it would cause problems if it where sent more
// than once.
if (m_lineArray[nIndex]->m_bConnected)
break;
m_lineArray[nIndex]->m_bConnected = TRUE;
hCommFile = m_lineArray[nIndex]->GetCommHandle();
if (hCommFile == INVALID_HANDLE_VALUE)
goto LABEL_ERRORCONNECTING;
// Started communications!
m_lineArray[nIndex]->m_pComm = new CCommInfo();
m_lineArray[nIndex]->m_pComm->Create(m_pNotifyWnd,
m_dwCommBaseCommandID + nIndex * CCommInfo::ID_COMM_EVENT_NUMBER,
m_pReadBuf, m_nReadBufLen, hCommFile);
if (m_lineArray[nIndex]->m_pComm->OpenConnection())
{
TRACE0("Connected, Starting communications!\n");
m_lineArray[nIndex]->m_pComm->WriteCommBlock("A",1);
break;
}
TRACE0("Connected Fail!\n");
// Couldn't start communications. Clean up instead.
LABEL_ERRORCONNECTING:
// Its very important that we close all Win32 handles.
// The CommCode module is responsible for closing the hCommFile
// handle if it succeeds in starting communications.
if (hCommFile)
::CloseHandle(hCommFile);
m_lineArray[nIndex]->HangupCall();
TRACE0("Failed to Connect\n");
break;
}
default:
TRACE0("Unhandled LINECALLSTATE message\n");
break;
}
}
int CTAPIConnection::GetNumDevs(void)
{
return m_lineArray.GetSize();
}
int CTAPIConnection::GetCallDeviceIDIndex(HCALL hCall)
{
if (hCall != (HCALL)-1)
{
for (int i = 0; i < GetNumDevs(); ++ i)
{
CTAPILine* pLineObject = m_lineArray[i];
if (pLineObject->m_hCall == hCall)
return i;
}
}
return -1;
}
int CTAPIConnection::GetLineDeviceIDIndex(HLINE hLine)
{
if (hLine != (HLINE)-1)
{
for (int i = 0; i < GetNumDevs(); ++ i)
{
CTAPILine* pLineObject = m_lineArray[i];
if (pLineObject->m_hLine == hLine)
return i;
}
}
return -1;
}
int CTAPIConnection::GetAsyncIDIndex(DWORD dwAsyncID)
{
if (dwAsyncID > 0)
{
for (int i = 0; i < GetNumDevs(); ++ i)
{
CTAPILine* pLineObject = m_lineArray[i];
if (pLineObject->m_dwAsyncID == dwAsyncID)
return i;
}
}
return -1;
}
void CTAPIConnection::SetNewLine(DWORD dwDeviceID)
{
CTAPILine* pLineObject = new CTAPILine;
if (pLineObject->Create(dwDeviceID, m_dwAPILowVersion, m_dwAPIHighVersion) == TRUE)
m_lineArray.Add(pLineObject);
else
delete pLineObject;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -