如何使两个MODEM点对点连接并且相互发送数据?(答的好再加300分)

xiao_zhu 2001-04-12 08:28:00
请详细解说一下用TAPI实现的过程(只要能建立连接并且互相发送数据就可以)如果打开串口直接用ATDT命令拨号会怎么样?
...全文
270 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
use_id 2001-09-11
  • 打赏
  • 举报
回复
关注
xiao_zhu 2001-04-20
  • 打赏
  • 举报
回复
a
Frank0233 2001-04-14
  • 打赏
  • 举报
回复
有什么问题问我
或者给我写信mailwp@21cn.com
Frank0233 2001-04-14
  • 打赏
  • 举报
回复

---------------------------TAPIUTILS.CPP

// This module implements the CTapiConnection class.
//
#include "stdafx.h"
#include <string.h>
#include "TapiUtils.h"

// All TAPI line functions return 0 for SUCCESS, so define it.
#define SUCCESS 0

// TAPI version that this sample is designed to use.
#define SAMPLE_TAPI_VERSION 0x00010004

// Early TAPI version
#define EARLY_TAPI_VERSION 0x00010003

// Possible return error for resynchronization functions.
#define WAITERR_WAITABORTED 1

// A pointer to my class because TAPI needs a callback
CTapiConnection *MyThis;

#if FALSE
// Structures needed to handle special non-dialable characters.
#define g_sizeofNonDialable (sizeof(g_sNonDialable)/sizeof(g_sNonDialable[0]))

typedef struct {
LONG lError;
DWORD dwDevCapFlag;
LPSTR szToken;
LPSTR szMsg;
} NONDIALTOKENS;

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"},
};
#endif

//
// Constructor
//
CTapiConnection::CTapiConnection()
{
m_bShuttingDown = FALSE;
m_bStoppingCall = FALSE;
m_bInitializing = FALSE;
m_bTapiInUse = FALSE;
m_dwNumDevs = 0;
m_hCall = NULL;
m_hLine = NULL;
m_dwDeviceID = 0;
m_hLineApp = NULL;

MyThis = this;

};

//
// Destructor
//
CTapiConnection::~CTapiConnection()
{
m_bInitialized = FALSE;
};

//
// FUNCTION: BOOL Create()
//
// PURPOSE: Initializes TAPI
//
BOOL CTapiConnection::Create(char *szPhoneNumber)
{
long lReturn;

// 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,
"DialIt",
&m_dwNumDevs);

if (m_dwNumDevs == 0)
{
AfxMessageBox("There are no telephony devices installed.");
m_bInitializing = FALSE;
return FALSE;
}

if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("lineInitialize unhandled error\n");
m_bInitializing = FALSE;
return FALSE;
}
}
while(lReturn != SUCCESS);

OutputDebugString("Tapi initialized.\n");
AfxMessageBox("intialized!");

// 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(char *szPhoneNumber)
{
long lReturn;
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, quit.
if (m_dwNumDevs < 1)
return FALSE;

// We now have a call active. Prevent future calls.
m_bTapiInUse = TRUE;

// Get a phone number from the user.
if (szPhoneNumber == (char *)NULL)
{
if (m_szPhoneNumber == (char *)NULL)
{
HangupCall();
goto DeleteBuffers;
}
}
else
strcpy(m_szPhoneNumber, szPhoneNumber);

// 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)
{
OutputDebugString("Error on Requested line\n");
goto DeleteBuffers;
}

if (!(lpLineDevCaps->dwBearerModes & LINEBEARERMODE_VOICE ))
{
AfxMessageBox("The selected line doesn't support VOICE capabilities");
goto DeleteBuffers;
}

// Does this line have the capability to make calls?
if (!(lpLineDevCaps->dwLineFeatures & LINEFEATURE_MAKECALL))
{
AfxMessageBox("The selected line doesn't support MAKECALL capabilities");
goto DeleteBuffers;
}

// Does this line have the capability for interactive voice?
if (!(lpLineDevCaps->dwMediaModes & LINEMEDIAMODE_INTERACTIVEVOICE))
{
AfxMessageBox("The selected line doesn't support INTERACTIVE VOICE capabilities");
goto 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);

if((lReturn == LINEERR_ALLOCATED)||(lReturn == LINEERR_RESOURCEUNAVAIL))
{
HangupCall();
OutputDebugString("Line is already in use by a non-TAPI application "
"or by another TAPI Service Provider.\n");
goto DeleteBuffers;
}

if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("Unable to Use Line\n");
HangupCall();
goto DeleteBuffers;
}
}
while(lReturn != SUCCESS);

// Start dialing the number
if( MakeTheCall(lpLineDevCaps, m_szPhoneNumber))
OutputDebugString("lineMakeCall succeeded.\n");
else
{
OutputDebugString("lineMakeCall failed.\n");
HangupCall();
}

DeleteBuffers:

if (lpLineDevCaps)
LocalFree(lpLineDevCaps);

return m_bTapiInUse;
}

//
// FUNCTION: void GetDeviceLine()
//
// PURPOSE: Gets the first available line device.
//
//
LPLINEDEVCAPS CTapiConnection::GetDeviceLine(DWORD *pdwAPIVersion, LPLINEDEVCAPS lpLineDevCaps)
{
DWORD dwDeviceID;
char szLineUnavail[] = "Line Unavailable";
char szLineUnnamed[] = "Line Unnamed";
char szLineNameEmpty[] = "Line Name is Empty";
LPSTR lpszLineName;
long lReturn;
char buf[MAX_PATH];
LINEEXTENSIONID lineExtID;
BOOL bDone = FALSE;

for (dwDeviceID = 0; (dwDeviceID < m_dwNumDevs) && !bDone; dwDeviceID ++)
{
//get the tapi version********************
lReturn = ::lineNegotiateAPIVersion(m_hLineApp, dwDeviceID,
EARLY_TAPI_VERSION, SAMPLE_TAPI_VERSION,
pdwAPIVersion, &lineExtID);

if ((HandleLineErr(lReturn))&&(*pdwAPIVersion))
{
lpLineDevCaps = MylineGetDevCaps(lpLineDevCaps, dwDeviceID, *pdwAPIVersion);

if ((lpLineDevCaps -> dwLineNameSize) &&
(lpLineDevCaps -> dwLineNameOffset) &&
(lpLineDevCaps -> dwStringFormat == STRINGFORMAT_ASCII))
{
// This is the name of the device.
lpszLineName = ((char *) lpLineDevCaps) +
lpLineDevCaps -> dwLineNameOffset;
sprintf(buf, "Name of device is: %s\n", lpszLineName);
OutputDebugString(buf);

}
else // DevCaps doesn't have a valid line name. Unnamed.
lpszLineName = szLineUnnamed;
}
else // Couldn't NegotiateAPIVersion. Line is unavail.
lpszLineName = szLineUnavail;

// If this line is usable and we don't have a default initial
// line yet, make this the initial line.
if ((lpszLineName != szLineUnavail) &&
(lReturn == SUCCESS ))
{
m_dwDeviceID = dwDeviceID;
bDone = TRUE;
}
else
m_dwDeviceID = MAXDWORD;
}
return (lpLineDevCaps);
}

//
// FUNCTION: MylineGetDevCaps(LPLINEDEVCAPS, DWORD , DWORD)
//
// PURPOSE: Gets a LINEDEVCAPS structure for the specified line.
//
// COMMENTS:
//
// This function is a wrapper around lineGetDevCaps to make it easy
// to handle the variable sized structure and any errors received.
//
// The returned structure has been allocated with LocalAlloc,
// so LocalFree has to be called on it when you're finished with it,
// or there will be a memory leak.
//
// Similarly, if a lpLineDevCaps structure is passed in, it *must*
// have been allocated with LocalAlloc and it could potentially be
// LocalFree()d.
//
// If lpLineDevCaps == NULL, then a new structure is allocated. It is
// normal to pass in NULL for this parameter unless you want to use a
// lpLineDevCaps that has been returned by a previous I_lineGetDevCaps
// call.
//
//

LPLINEDEVCAPS CTapiConnection::MylineGetDevCaps(
LPLINEDEVCAPS lpLineDevCaps,
DWORD dwDeviceID, DWORD dwAPIVersion)
{
// Allocate enough space for the structure plus 1024.
size_t sizeofLineDevCaps = sizeof(LINEDEVCAPS) + 1024;
long lReturn;

// Continue this loop until the structure is big enough.
while(TRUE)
{
// Make sure the buffer exists, is valid and big enough.
lpLineDevCaps =
(LPLINEDEVCAPS) CheckAndReAllocBuffer(
(LPVOID) lpLineDevCaps, // Pointer to existing buffer, if any
sizeofLineDevCaps); // Minimum size the buffer should be

if (lpLineDevCaps == NULL)
return NULL;

// Make the call to fill the structure.
do
{
lReturn =
::lineGetDevCaps(m_hLineApp,
dwDeviceID, dwAPIVersion, 0, lpLineDevCaps);

if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("lineGetDevCaps unhandled error/n");
LocalFree(lpLineDevCaps);
return NULL;
}
}
while (lReturn != SUCCESS);

// If the buffer was big enough, then succeed.
if ((lpLineDevCaps -> dwNeededSize) <= (lpLineDevCaps -> dwTotalSize))
return lpLineDevCaps;

// Buffer wasn't big enough. Make it bigger and try again.
sizeofLineDevCaps = lpLineDevCaps -> dwNeededSize;
}
}

//
// FUNCTION: LPVOID CheckAndReAllocBuffer(LPVOID, size_t, LPCSTR)
//
// PURPOSE: Checks and ReAllocates a buffer if necessary.
//
LPVOID CTapiConnection::CheckAndReAllocBuffer(LPVOID lpBuffer, size_t sizeBufferMinimum)
{
size_t sizeBuffer;

if (lpBuffer == NULL) // Allocate the buffer if necessary.
{
sizeBuffer = sizeBufferMinimum;
lpBuffer = (LPVOID) LocalAlloc (LPTR, sizeBuffer);

if (lpBuffer == NULL)
{
OutputDebugString("LocalAlloc failed in CheckAndReAllocBuffer./n");
return NULL;
}
}
else // If the structure already exists, make sure its good.
{
sizeBuffer = LocalSize((HLOCAL) lpBuffer);

if (sizeBuffer == 0) // Bad pointer?
{
OutputDebugString("LocalSize returned 0 in CheckAndReAllocBuffer/n");
return NULL;
}

// Was the buffer big enough for the structure?
if (sizeBuffer < sizeBufferMinimum)
{
OutputDebugString("Reallocating structure\n");
LocalFree(lpBuffer);
return CheckAndReAllocBuffer(NULL, sizeBufferMinimum);
}
}

memset(lpBuffer, 0, sizeBuffer);
((LPVARSTRING) lpBuffer ) -> dwTotalSize = (DWORD) sizeBuffer;
return lpBuffer;
}


//
// FUNCTION: MylineGetAddressCaps(LPLINEADDRESSCAPS, ..)
//
// PURPOSE: Return a LINEADDRESSCAPS structure for the specified line.
//
LPLINEADDRESSCAPS CTapiConnection::MylineGetAddressCaps (
LPLINEADDRESSCAPS lpLineAddressCaps,
DWORD dwDeviceID, DWORD dwAddressID,
DWORD dwAPIVersion, DWORD dwExtVersion)
{
size_t sizeofLineAddressCaps = sizeof(LINEADDRESSCAPS) + 1024;
long lReturn;

// Continue this loop until the structure is big enough.
while(TRUE)
{
// Make sure the buffer exists, is valid and big enough.
lpLineAddressCaps =
(LPLINEADDRESSCAPS) CheckAndReAllocBuffer(
(LPVOID) lpLineAddressCaps,
sizeofLineAddressCaps);

if (lpLineAddressCaps == NULL)
return NULL;

// Make the call to fill the structure.
do
{
lReturn =
::lineGetAddressCaps(m_hLineApp,
dwDeviceID, dwAddressID, dwAPIVersion, dwExtVersion,
lpLineAddressCaps);

if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("lineGetAddressCaps unhandled error\n");
LocalFree(lpLineAddressCaps);
return NULL;
}
}
while (lReturn != SUCCESS);

// If the buffer was big enough, then succeed.
if ((lpLineAddressCaps -> dwNeededSize) <=
(lpLineAddressCaps -> dwTotalSize))
{
return lpLineAddressCaps;
}

// Buffer wasn't big enough. Make it bigger and try again.
sizeofLineAddressCaps = lpLineAddressCaps -> dwNeededSize;
}
}

//
// FUNCTION: MakeTheCall(LPLINEDEVCAPS, LPCSTR)
//
// PURPOSE: Dials the call
//

BOOL CTapiConnection::MakeTheCall(LPLINEDEVCAPS lpLineDevCaps, LPCTSTR lpszAddress)
{
LPLINECALLPARAMS lpCallParams = NULL;
LPLINEADDRESSCAPS lpAddressCaps = NULL;
long lReturn;
BOOL bFirstDial = TRUE;

// Get the capabilities for the line device we're going to use.
lpAddressCaps = MylineGetAddressCaps(lpAddressCaps,
m_dwDeviceID, 0, m_dwAPIVersion, 0);
if (lpAddressCaps == NULL)
return FALSE;

// Setup our CallParams.******************
lpCallParams = CreateCallParams (lpCallParams, lpszAddress);
if (lpCallParams == NULL)
return FALSE;

do
{
if (bFirstDial)
//lReturn = ::lineMakeCall(m_hLine, &m_hCall, lpszAddress, 0, lpCallParams);
lReturn = WaitForReply( ::lineMakeCall(m_hLine, &m_hCall, lpszAddress,
0, lpCallParams) );
else
lReturn = WaitForReply(::lineDial(m_hCall, lpszAddress, 0));

if (lReturn == WAITERR_WAITABORTED)
{
OutputDebugString("While Dialing, WaitForReply aborted.\n");
goto errExit;
}

if (HandleLineErr(lReturn))
continue;
else
{
if (bFirstDial)
OutputDebugString("lineMakeCall unhandled error\n");
else
OutputDebugString("lineDial unhandled error\n");

goto errExit;
}
}
while (lReturn != SUCCESS);

bFirstDial = FALSE;

if (lpCallParams)
LocalFree(lpCallParams);
if (lpAddressCaps)
LocalFree(lpAddressCaps);

return TRUE;

errExit:
if (lpCallParams)
LocalFree(lpCallParams);
if (lpAddressCaps)
LocalFree(lpAddressCaps);

AfxMessageBox("Dial failed.");

return FALSE;
}


//
// FUNCTION: CreateCallParams(LPLINECALLPARAMS, LPCSTR)
//
// PURPOSE: Allocates and fills a LINECALLPARAMS structure
//
//
LPLINECALLPARAMS CTapiConnection::CreateCallParams (
LPLINECALLPARAMS lpCallParams, LPCSTR lpszDisplayableAddress)
{
size_t sizeDisplayableAddress;

if (lpszDisplayableAddress == NULL)
lpszDisplayableAddress = "";

sizeDisplayableAddress = strlen(lpszDisplayableAddress) + 1;

lpCallParams = (LPLINECALLPARAMS) CheckAndReAllocBuffer(
(LPVOID) lpCallParams,
sizeof(LINECALLPARAMS) + sizeDisplayableAddress);

if (lpCallParams == NULL)
return NULL;

// This is where we configure the line.
lpCallParams -> dwBearerMode = LINEBEARERMODE_VOICE;
lpCallParams -> dwMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE;

// This specifies that we want to use only IDLE calls and
// don't want to cut into a call that might not be IDLE (ie, in use).
lpCallParams -> dwCallParamFlags = LINECALLPARAMFLAGS_IDLE;

// if there are multiple addresses on line, use first anyway.
// It will take a more complex application than a simple tty app
// to use multiple addresses on a line anyway.
lpCallParams -> dwAddressMode = LINEADDRESSMODE_ADDRESSID;

// Address we are dialing.
lpCallParams -> dwDisplayableAddressOffset = sizeof(LINECALLPARAMS);
lpCallParams -> dwDisplayableAddressSize = sizeDisplayableAddress;
strcpy((LPSTR)lpCallParams + sizeof(LINECALLPARAMS),
lpszDisplayableAddress);

return lpCallParams;
}

//
// FUNCTION: long WaitForReply(long)
//
// PURPOSE: Resynchronize by waiting for a LINE_REPLY
//
// PARAMETERS:
// lRequestID - The asynchronous request ID that we're
// on a LINE_REPLY for.
//
// RETURN VALUE:
// - 0 if LINE_REPLY responded with a success.
// - LINEERR constant if LINE_REPLY responded with a LINEERR
// - 1 if the line was shut down before LINE_REPLY is received.
//
// COMMENTS:
//
// This function allows us to resynchronize an asynchronous
// TAPI line call by waiting for the LINE_REPLY message. It
// waits until a LINE_REPLY is received or 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).
//
// 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.
//
// 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 times out and returns WAITERR_WAITTIMEDOUT
// after WAITTIMEOUT milliseconds have elapsed.
//
//


long CTapiConnection::WaitForReply (long lRequestID)
{
static BOOL bReentered;
bReentered = FALSE;

if (lRequestID > SUCCESS)
{
MSG msg;
DWORD dwTimeStarted;

m_bReplyReceived = FALSE;
m_dwRequestedID = (DWORD) lRequestID;

// Initializing this just in case there is a bug
// that sets m_bReplyRecieved without setting the reply value.
m_lAsyncReply = LINEERR_OPERATIONFAILED;

dwTimeStarted = GetTickCount();

while(!m_bReplyReceived)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

// This should only occur if the line is shut down while waiting.
if ((m_hCall != NULL) &&(!m_bTapiInUse || bReentered))
{
bReentered = TRUE;
return WAITERR_WAITABORTED;
}

// Its a really bad idea to timeout a wait for a LINE_REPLY.
// If we are execting a LINE_REPLY, we should wait till we get
// it; it might take a long time to dial (for example).

// If 5 seconds go by without a reply, it might be a good idea
// to display a dialog box to tell the user that a
// wait is in progress and to give the user the capability to
// abort the wait.
}

bReentered = TRUE;
return m_lAsyncReply;
}

bReentered = TRUE;
return lRequestID;
}

//
// FUNCTION: lineCallbackFunc(..)
//
// PURPOSE: Receive asynchronous TAPI events
//
void CALLBACK CTapiConnection::lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{

// Handle the line messages.
switch(dwMsg)
{
case LINE_CALLSTATE:
MyThis->HandleLineCallState(dwDevice, dwMsg, dwCallbackInstance, dwParam1, dwParam2,
dwParam3);
break;

case LINE_CLOSE:
// Line has been shut down.
ASSERT(MyThis);
MyThis->m_hLine = NULL;
MyThis->m_hCall = NULL;
MyThis->HangupCall(); // all handles invalidated by this time
break;

case LINE_REPLY:
if ((long) dwParam2 != SUCCESS)
OutputDebugString("LINE_REPLY error\n");
else
OutputDebugString("LINE_REPLY: successfully replied.\n");
break;

case LINE_CREATE:
ASSERT(MyThis);
if (MyThis->m_dwNumDevs <= dwParam1)
MyThis->m_dwNumDevs = dwParam1+1;
break;

default:
OutputDebugString("lineCallbackFunc message ignored\n");
break;
}
return;
}

//
// FUNCTION: HandleLineCallState(..)
//
// PURPOSE: Handle LINE_CALLSTATE asynchronous messages.
//

void CTapiConnection::HandleLineCallState(
DWORD dwDevice, DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3)
{

// Error if this CALLSTATE doesn't apply to our call in progress.
if ((HCALL) dwDevice != m_hCall)
{
OutputDebugString("LINE_CALLSTATE: Unknown device ID ");
return;
}


// dwParam1 is the specific CALLSTATE change that is occurring.
switch (dwParam1)
{
case LINECALLSTATE_DIALTONE:
OutputDebugString("Dial Tone\n");
break;

case LINECALLSTATE_DIALING:
OutputDebugString("Dialing\n");
break;

case LINECALLSTATE_PROCEEDING:
OutputDebugString("Proceeding\n");
break;

case LINECALLSTATE_RINGBACK:
OutputDebugString("RingBack\n");
break;

case LINECALLSTATE_BUSY:
OutputDebugString("Line busy, shutting down\n");
HangupCall();
break;

case LINECALLSTATE_IDLE:
OutputDebugString("Line idle\n");
HangupCall();
break;

case LINECALLSTATE_SPECIALINFO:
OutputDebugString("Special Info, probably couldn't dial number\n");
HangupCall();
break;

case LINECALLSTATE_DISCONNECTED:
{
LPSTR pszReasonDisconnected;

switch (dwParam2)
{
case LINEDISCONNECTMODE_NORMAL:
pszReasonDisconnected = "Remote Party Disconnected";
break;

case LINEDISCONNECTMODE_UNKNOWN:
pszReasonDisconnected = "Disconnected: Unknown reason";
break;

case LINEDISCONNECTMODE_REJECT:
pszReasonDisconnected = "Remote Party rejected call";
break;

case LINEDISCONNECTMODE_PICKUP:
pszReasonDisconnected =
"Disconnected: Local phone picked up";
break;

case LINEDISCONNECTMODE_FORWARDED:
pszReasonDisconnected = "Disconnected: Forwarded";
break;

case LINEDISCONNECTMODE_BUSY:
pszReasonDisconnected = "Disconnected: Busy";
break;

case LINEDISCONNECTMODE_NOANSWER:
pszReasonDisconnected = "Disconnected: No Answer";
break;

case LINEDISCONNECTMODE_BADADDRESS:
pszReasonDisconnected = "Disconnected: Bad Address";
break;

case LINEDISCONNECTMODE_UNREACHABLE:
pszReasonDisconnected = "Disconnected: Unreachable";
break;

case LINEDISCONNECTMODE_CONGESTION:
pszReasonDisconnected = "Disconnected: Congestion";
break;

case LINEDISCONNECTMODE_INCOMPATIBLE:
pszReasonDisconnected = "Disconnected: Incompatible";
break;

case LINEDISCONNECTMODE_UNAVAIL:
pszReasonDisconnected = "Disconnected: Unavail";
break;

case LINEDISCONNECTMODE_NODIALTONE:
pszReasonDisconnected = "Disconnected: No Dial Tone";
break;

default:
pszReasonDisconnected =
"Disconnected: LINECALLSTATE; Bad Reason";
break;

}

OutputDebugString(pszReasonDisconnected);
OutputDebugString("\n");
HangupCall();
break;
}

case LINECALLSTATE_CONNECTED: // CONNECTED!!!
OutputDebugString("Connected!\n");
break;

default:
OutputDebugString("Unhandled LINECALLSTATE message\n");
break;
}
}

//
// FUNCTION: HandleLineErr(long)
//
// PURPOSE: Handle several of the standard LINEERR errors
//
BOOL CTapiConnection::HandleLineErr(long lLineErr)
{
BOOL bRet = FALSE;

// lLineErr is really an async request ID, not an error.
if (lLineErr > SUCCESS)
return bRet;

// All we do is dispatch the correct error handler.
switch(lLineErr)
{
case SUCCESS:
bRet = TRUE;
break;

case LINEERR_INVALCARD:
case LINEERR_INVALLOCATION:
case LINEERR_INIFILECORRUPT:
OutputDebugString("The values in the INI file are invalid.\n");
break;

case LINEERR_NODRIVER:
OutputDebugString("There is a problem with your Telephony device driver.\n");
break;

case LINEERR_REINIT:
ShutdownTAPI();
break;

case LINEERR_NOMULTIPLEINSTANCE:
OutputDebugString("Remove one of your copies of your Telephony driver.\n");
break;

case LINEERR_NOMEM:
OutputDebugString("Out of memory. Cancelling action.\n");
break;

case LINEERR_OPERATIONFAILED:
OutputDebugString("The TAPI operation failed.\n");
break;

case LINEERR_RESOURCEUNAVAIL:
OutputDebugString("A TAPI resource is unavailable at this time.\n");
break;

// Unhandled errors fail.
default:
break;
}
return bRet;
}


//
// FUNCTION: BOOL HangupCall()
//
// PURPOSE: Hangup the call in progress if it exists.
//
BOOL CTapiConnection::HangupCall()
{
LPLINECALLSTATUS pLineCallStatus = NULL;
long lReturn;

// Prevent HangupCall re-entrancy problems.
if (m_bStoppingCall)
return TRUE;

// If Tapi is not being used right now, then the call is hung up.
if (!m_bTapiInUse)
return TRUE;

m_bStoppingCall = TRUE;

OutputDebugString("Stopping Call in progress\n");

// If there is a call in progress, drop and deallocate it.
if (m_hCall)
{
pLineCallStatus = (LPLINECALLSTATUS)malloc(sizeof(LINECALLSTATUS));

if (!pLineCallStatus)
{
ShutdownTAPI();
m_bStoppingCall = FALSE;
return FALSE;
}

lReturn = ::lineGetCallStatus(m_hCall, pLineCallStatus);

// Only drop the call when the line is not IDLE.
if (!((pLineCallStatus -> dwCallState) & LINECALLSTATE_IDLE))
{
WaitForReply(lineDrop(m_hCall, NULL, 0));
OutputDebugString("Call Dropped.\n");
}

// The call is now idle. Deallocate it!
do
{
lReturn = ::lineDeallocateCall(m_hCall);
if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("lineDeallocateCall unhandled error\n");
break;
}
}
while(lReturn != SUCCESS);

OutputDebugString("Call Deallocated.\n");

}

// if we have a line open, close it.
if (m_hLine)
{
lReturn = ::lineClose(m_hLine);
if (!HandleLineErr(lReturn))
OutputDebugString("lineClose unhandled error\n");

OutputDebugString("Line Closed.\n");
}

// Clean up.
m_hCall = NULL;
m_hLine = NULL;
m_bTapiInUse = FALSE;
m_bStoppingCall = FALSE; // allow HangupCall to be called again.

// Need to free buffer returned from lineGetCallStatus
if (pLineCallStatus)
free(pLineCallStatus);

OutputDebugString("Call stopped\n");
return TRUE;
}

//
// FUNCTION: BOOL ShutdownTAPI()
//
// PURPOSE: Shuts down all use of TAPI
//
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.
if (m_bShuttingDown)
return TRUE;

m_bShuttingDown = TRUE;

HangupCall();

do
{
lReturn = ::lineShutdown(m_hLineApp);
if (HandleLineErr(lReturn))
continue;
else
{
OutputDebugString("lineShutdown unhandled error\n");
break;
}
}
while(lReturn != SUCCESS);

m_bTapiInUse = FALSE;
m_hLineApp = NULL;
m_hCall = NULL;
m_hLine = NULL;
m_bShuttingDown = FALSE;

OutputDebugString("TAPI uninitialized.\n");

return TRUE;
}
///
//打开线路
BOOL CTapiConnection::Open_Line()
{

LONG lResult;
do
{
lResult =
::lineOpen(m_hLineApp,
m_dwDeviceID,
&m_hLine,
m_dwAPIVersion,
0,
(DWORD)this,
LINECALLPRIVILEGE_NONE,
LINEMEDIAMODE_DATAMODEM,
//LINEMEDIAMODE_INTERACTIVEVOICE,
NULL);

if((lResult == LINEERR_ALLOCATED) ||(lResult == LINEERR_RESOURCEUNAVAIL))
{
//线路已经被占用
return FALSE;
}
}while( lResult!=SUCCESS );

if( !GetModemID() )
return FALSE;
return( TRUE );


}
/////
HANDLE CTapiConnection::GetPortHandle()
{
char temp[ 4096 ];
char str_vs_offset[1024];
VARSTRING *vs = (VARSTRING *) temp;
vs->dwTotalSize = 4096;

LONG result = lineGetID( m_hLine, //hLine
0, //dwAddressID
0, //hCall
LINECALLSELECT_LINE, //dwSelect
vs,
"comm/datamodem" );
if ( result < 0 ) {
//Error( "Error returned from lineGetID : ", result );
return 0;
}
for (int i=0;i<=vs->dwTotalSize ;i++)
str_vs_offset[i]=(char)vs++;

HANDLE p = (HANDLE *) ((LPSTR) vs + vs->dwStringOffset);

return p;
}
void CTapiConnection::Write_Port()
{
DWORD ModemState;
if (GetModemID())
{
HANDLE hComm=m_hModem;
if (hComm!=0)
{
BOOL B=GetCommModemStatus(
hComm, // handle to communications device
&ModemState); // control-register values
if (B!=0)
{
DWORD A;
A=ModemState;
if (A&MS_CTS_ON==(DWORD)0x0010)
MessageBox(0,"ss","CTS_ON",MB_OK);
A=ModemState;

if (A&MS_DSR_ON==(DWORD)0x0020)
MessageBox(0,"ss","DSR_ON",MB_OK);
A=ModemState;
if (A&MS_RING_ON==(DWORD)0x0040)
MessageBox(0,"ss","RING_ON",MB_OK);
A=ModemState;
if (A&MS_RLSD_ON==(DWORD)0x0080)
MessageBox(0,"ss","RLSD_ON",MB_OK);
}
}
}


}
BOOL CTapiConnection::Get_Link_Status()
{
DWORD s,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10;
char temp[ 4096 ];
LINEDEVSTATUS *lpLineDevStatus = (LINEDEVSTATUS *) temp;
lpLineDevStatus->dwTotalSize = 4096;


LONG result=lineGetLineDevStatus(
m_hLine,
lpLineDevStatus);

if (result==LINEERR_INVALLINEHANDLE) AfxMessageBox("line1 ok");
if (result==LINEERR_RESOURCEUNAVAIL) AfxMessageBox("line2 ok");
if (result==LINEERR_INVALPOINTER) AfxMessageBox("line3 ok");
if (result==LINEERR_STRUCTURETOOSMALL) AfxMessageBox("line4 ok");
if (result==LINEERR_NOMEM) AfxMessageBox("line5 ok");
if (result==LINEERR_UNINITIALIZED) AfxMessageBox("line6 ok");
if (result==LINEERR_OPERATIONFAILED) AfxMessageBox("line7 ok");
if (result==LINEERR_OPERATIONUNAVAIL) AfxMessageBox("line8 ok");
if (result==0)
{
s=lpLineDevStatus->dwNumOpens;
s1=lpLineDevStatus->dwOpenMediaModes;
s2=lpLineDevStatus->dwNumActiveCalls;
s3=lpLineDevStatus->dwNumOnHoldCalls;
s4=lpLineDevStatus->dwNumOnHoldPendCalls;
s5=lpLineDevStatus->dwDevStatusFlags;
if (s5==LINEDEVSTATUSFLAGS_CONNECTED ) AfxMessageBox("CONNECTED");
if (s5==LINEDEVSTATUSFLAGS_INSERVICE ) AfxMessageBox("INSERVICE");
if (s5==LINEDEVSTATUSFLAGS_LOCKED ) AfxMessageBox("LOCKED");
if (s5==LINEDEVSTATUSFLAGS_MSGWAIT ) AfxMessageBox("MSGWAIT");


if (s2>0) return TRUE;
}
return FALSE;

}
BOOL CTapiConnection::GetModemID( )
{


ModemID *mid;
VARSTRING * str;
char mark=1;

str=(VARSTRING *)malloc(sizeof(VARSTRING));
if(!str)
return NULL;
str->dwTotalSize=sizeof(VARSTRING);
do
{
if((lineGetID(m_hLine,
0,
NULL,
LINECALLSELECT_LINE,//LINECALLSELECT_ADDRESS, //LINECALLSELECT_LINE,
str,
"comm/datamodem")==0)
&&(str->dwTotalSize < str->dwNeededSize))

{
DWORD dwSize=str->dwNeededSize;
free(str);
str=(VARSTRING *)malloc(dwSize);
if(!str)
{
m_hModem=NULL;
mark=2;
}
str->dwTotalSize=dwSize;
}
else
{
mark=0;

}
}while(mark==1);
if(mark==0)
{
mid=(ModemID *)((LPSTR)str+str->dwStringOffset);
m_hModem=mid->hModem;
}
free(str);
// CString strmsg;
//strmsg.Format("ModemID:%ld",m_hModem);
//ShowMessage(strmsg);
return m_hModem!=NULL?TRUE:FALSE;
}


Frank0233 2001-04-14
  • 打赏
  • 举报
回复
这里是一个封装Tapi的class:
-------------------------TAPIUTILS.H
#include <tapi.h>

typedef struct tagModemID{
HANDLE hModem;
char ModemName[1];
}ModemID;

class CTapiConnection
{

protected:
// this area contains the protected members of the CTapiConnection class
DWORD m_dwNumDevs; // the number of line devices available
DWORD m_dwDeviceID; // the device ID
DWORD m_dwRequestedID;
LONG m_lAsyncReply;


// BOOLEANS to handle reentrancy
BOOL m_bShuttingDown;
BOOL m_bStoppingCall;
BOOL m_bInitializing;
BOOL m_bReplyReceived;


BOOL m_bTapiInUse; // whether TAPI is in use or not
BOOL m_bInitialized; // whether TAPI has been initialized

public:
// this area contains the public members of the CTapiConnection class
HLINEAPP m_hLineApp; // the usage handle of this application for TAPI
HCALL m_hCall; // handle to the call
HLINE m_hLine; // handle to the open line
HANDLE m_hModem; //调制解调器句柄
DWORD m_dwAPIVersion; // the API version
char m_szPhoneNumber[64]; // the phone number to call

protected:
// Here is where I put the protected (internal) functions
BOOL ShutdownTAPI();
BOOL HandleLineErr(long lLineErr);
LPLINEDEVCAPS GetDeviceLine(DWORD *dwAPIVersion, LPLINEDEVCAPS lpLineDevCaps);
LPLINEDEVCAPS MylineGetDevCaps(LPLINEDEVCAPS lpLineDevCaps,
DWORD dwDeviceID, DWORD dwAPIVersion);
LPVOID CheckAndReAllocBuffer(LPVOID lpBuffer, size_t sizeBufferMinimum);
LPLINEADDRESSCAPS MylineGetAddressCaps (LPLINEADDRESSCAPS lpLineAddressCaps,
DWORD dwDeviceID, DWORD dwAddressID,DWORD dwAPIVersion, DWORD dwExtVersion);
BOOL MakeTheCall(LPLINEDEVCAPS lpLineDevCaps,LPCSTR lpszAddress);
LPLINECALLPARAMS CreateCallParams (LPLINECALLPARAMS lpCallParams, LPCSTR lpszDisplayableAddress);
long WaitForReply (long lRequestID);
void HandleLineCallState(DWORD dwDevice, DWORD dwMessage, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3);


private:
// This section is for private functions

public:
// Public functions
CTapiConnection();
~CTapiConnection();
BOOL Create(char *szPhoneNumber = NULL);
BOOL DialCall(char *szPhoneNumber = NULL);
BOOL HangupCall();
// Access the com port
HANDLE GetPortHandle();
//open the line
BOOL Open_Line();
//WRITE PORT
void Write_Port();
///
BOOL Get_Link_Status();
//
BOOL CTapiConnection::GetModemID( );

static void CALLBACK lineCallbackFunc(
DWORD dwDevice, DWORD dwMsg, DWORD dwCallbackInstance,
DWORD dwParam1, DWORD dwParam2, DWORD dwParam3);

};

Frank0233 2001-04-14
  • 打赏
  • 举报
回复
这里是对modem的指令AT 命令集说明

命令 说明
AT 注意代码。AT 为命令前缀,告诉调制解调器正在输入一条命令或命令序列,
它可以作为除 A/(重复)和 +++ (退出)命令外所有命令的前缀。单独输入,
如果调制解调器已准备好接收命令,只输入 AT 会使它发出确定的响应。
A/ 重复上一条命令。A/ 使调制解调器重复上一条命令,例如重拨一个电话号
码。刚执行完毕的命令会保存在命令缓冲区中,直到输入 AT 或关闭电源。
上述方法均可清除缓冲区并使 A/ 命令无效,因为已没有命令让调制解调器
重复。没有必要输入<cr>或AT,因为它们和上一条命令一起保存在命令缓冲
区中。参数:无
A 应答命令。A 使调制解调器应答呼叫而无需等待响铃。适合在手动应答呼叫
或在发送方式 下直接与另一台调制解调器建立联络时使用。参数:无
注:在同一命令行上随 A 后的任何命令均会被忽略。
注:某些国家可能不允许使用手动应答呼叫(用 A 命令)。
Bn 通信标准选项。决定选用 ITU 或 Bell 标准。参数:n = 0、1、2、3、15、
16(视调制解调器的型号而定)
n = 0 ITU V.22 速率为 1200 bps;V.21 速率为 300 bps
n = 1 贝尔(Bell)212 A 速率为 1200 bps (默认值)
n=2 或 3 调制解调器发送时采用 CCITT V.23 R1200/T75 ASB ;
调制解调器接收时采用 CCITT V.23 T1200/R75
n = 15 V.21 速率为 300 bps
n = 16 贝尔(Bell)103 速率为 300 bps (Compaq Presario 192-VS型和
Compaq Presario 288-VS 型调制解调器的默认值)
Dn 拨号命令。D 使调制解调器拨命令行中随 D 后的号码。有效的拨号数字和拨
号修改程序详列于本章后面的表格 3-4:拨号命令修改程序拨号命令修改程序
中。参数:无。注:脉冲拨号的情况下,非数字字符是无效的。
En 命令回显选项。调制解调器处于命令方式时,En 用于禁用或启用输入字符的
本地回显 。参数: n = 0、1
n = 0 禁用本地回显
n = 1 启动本地回显(默认值)
Hn 挂机控制选项。Hn 控制挂机 延迟。参数: n = 0、1
n = 0 调制解调器挂机(挂断)(默认值)
n = 1 调制解调器摘机
注: H1 在某些国家可能不允许使用。在那种情况下,ATH1 将返回一个错误
代码。
In 要求识别选项。In 向调制解调器询问其产品识别代码,ROM 校验和 /或 ROM
校验和状态。参数: n = 0、 1、2、4、9
n = 0 返回固件 版本。
n = 1 计算并显示 ROM 校验和(如 12AB)
n = 2 执行 ROM 校验,计算并核对校验和,显示确定或错误。
n = 4 返回数据激励的软件版本。
n = 9 返回国家代码
Ln 扬声器音量选项。使用 Ln 控制在传真和数据通信期间扬声器的音量。
参数: n = 0、1、2、3
n = 0 扬声器低音量
n = 1 扬声器低音量
n = 2 扬声器中音量(默认值)
n = 3 扬声器高音量
注:要彻底关闭扬声器,请使用 MO 命令。
Mn 扬声器控制选项。使用 Mn 控制在传真和数据通信期间扬声器的开/关。
参数: n = 0、1、2、3 (视调制解调器的型号而定)
n = 0 扬声器关闭
n = 1 扬声器打开,直到检测到载波(默认值)
n = 2 调制解调器在摘机状态时扬声器一直打开
n = 3 拨号后扬声器打开,直到检测到载波。
Nn 调制信息交换。在本地调制解调器和远程调制解调器连接时,如果两者通信
速度不同,可使用 Nn 控制本地调制解调器是否执行协商信号交换 。
参数: n = 0、1
n = 0 发送或应答时,交换仅采用由 S37 和 ATB 命令指定的通信标准。
n = 1 发送或应答时,采用由 S37 和ATB命令指定的通信标准开始交换,
交换期间速度则可能会降低(默认值)。
On 联机命令。On 将调制解调器强制为联机方式 。
参数: n = 0、1、3 (视调制解器的型号而定)
n = 0 进入联机方式
n = 1 进入联机方式,并初始化均衡器重整 。
n = 3 进入联机方式,并在返回联机数据方式前发出通信速率重协商。
注:「退出」到命令方式后可用此命令返回联机方式。
P 脉冲拨号。P 将拨号方式设置为脉冲,所有呼叫都将保持脉冲方式,直到选
择音频拨号方式(T命令)。此命令也可作为拨号修改程序使用。(请参阅本章
后面的表格 3-4: 拨号命令修改程序。)参数:无
注:某些国家可能不设脉冲拨号,在那种情况下,P 命令将被忽略。
Qn 结果代码抑制。Qn 使调制解调器可以发送结果代码。参数:n = 0、1
n = 0 启用结果代码(默认值)
n = 1 禁用返回结果代码(静噪)
Sn 选择 S 寄存器。Sn 将指针指向某个 S 寄存器,其中「n」为寄存器号。在
选择另一个寄存器之前,n 值可用 AT? 读出,并可用 AT= 修改。
参数:无范围: n = 0-29、31-33、35、37、89
Sr=n 写 S 寄存器。Sr=n 将寄存器r设为值n。这些寄存器的内容可用此命令修
改。参数:无
范围: r = 0-29、31-33、35、37 和 89(寄存器号)n = 0-255(值)
注:写保留的寄存器或只读寄存器可能会引起不可预测的结果。有关寄存
器的完整列表,请参阅第四章,S 寄存器。
Sn? 读 S 寄存器。Sn? 报告由 n 指定的寄存器值,n 可为任何有效的 S 寄存
器号。参数:无
范围: n = 0-29、31-33、35、37 和 89
注:数值以十进制格式报告。要说明位映象寄存器值,将十进制值转换为
二进制。
T 音频拨号。T 将拨号方式设置为音频,所有呼叫将保持音频方式,直到选用
脉冲方式(P 命令)。此命令也可作为拨号修改程序使用。
(请参阅本章后面的表格 3-4: 拨号命令修改程序。)参数:无
Vn 结果代码格式选项。Vn 决定结果代码的类型。参数: n = 0、1
n = 0 结果代码以数字形式发送(短格式或数字)
n = 1 结果代码以单词形式发送(长格式[文本]或冗余格式)(默认值)
Xn 结果代码设置/呼叫进度选项。Xn 选择结果代码集和拨号功能。Vn 命令决定
结果代码是以单词还是以数字形式发送。请参阅附录中的结果代码定义。
参数: n = 0-7 (视调制解调器的型号而定)
n = 0 启用连接(CONNECT)结果代码,禁用 CONNECT XXXX 结果代码。
不检测占用信号和拨号音频。
n = 1 调制解调器进入盲拨号状态,启用 CONNECT XXXX 结果代码。
不检测占用信号和拨号音频。
n = 2 调制解调器在拨号前等待拨号音频,启用 CONNECT XXXX 结果代
码。不检测占用信号。
n = 3 调制解调器进入盲拨号状态,启用 CONNECT XXXX 结果代码。
如果检测到占用信号,调制解调器发出占用(BUSY)结果代码。
n = 4 调制解调器在拨号前等待拨号音频,启用 CONNECT XXXX 结果代
码。如果检测到占用信号,调制解调器发出占用(BUSY)结果代码(默认值)。
Z 重置命令选项。Z 将命令和 S 寄存器的参数和命令序列重新设置为默认值,
即恢复工厂设置。
+++退出代码序列。寄存器 S2 中的字符集 以极快的速度连续三次发送给调制解
调器(参阅 S12),调制解调器暂时退回到命令方式。退出字符的默认值为+,
说明文件中如果指明要输入 +++,迅速连续三次输入寄存器 S2 中的字符。
退出代码序列不要以 AT 开头,输完后也不要按 Enter 键。
注:要返回联机方式 ,请使用 ATO 命令。
? S 寄存器内容。AT? 返回上次寻址的 S 寄存器的内容。

表 3-2: 高级功能命令

命令 说明
&Cn 数据载波检测选项。AT&Cn 控制 DCD 选项。参数: n = 0、1
n=0 DCD总处于打开(ON)状态;来自远程调制解调器的数据载波状态被忽略。
n=1 检测到数据载波时 DCD 打开(ON);未检测到数据载波时
DCD关闭(OFF)(默认值)。
&Dn 数据终端就绪选项。AT&Dn 控制 DTR 选项。参数: n = 0、1、2、3
n=0 调制解调器忽略 DTR (默认值)。
n=1 调制解调器检测到 DTR 由打开向关闭转换时,进入命令方式。
n=2 调制解调器挂断,进入命令方式,并在检测到 DTR 由打开关闭转
换时禁用自动应答。
n=3 调制解调器在检测到 DTR 由打开向关闭转换时,进入初始化状态。
&Mn 异步通信方式。参数: n = 0
n=0 异步方式
&Qn 异步通信方式。参数: n= 0、5、6
n=0 异步方式
n=5 错误控制方式(默认值)
n=6 异步方式
&Tn 测试命令选择。AT&Tn 选择 8 条测试命令中的一条。参数: n = 0、1
n=0 终止任何进行中的测试。
n=1 初始化本地模拟环回(ALB) 。如果正在进行呼叫,将返回一条
错误信息。
-Cn 数据呼叫音频。数据呼叫音是一种频率 为 1300Hz 的音频。其步调为 0.5
秒打开,2 秒关闭。该音频在 ITUV.25 中指定为允许判定远程数据/传真/
音频。参数: n = 0、1
n=0 禁用数据呼叫音频(默认值)
n=1 启用数据呼叫音频
注:默认值随国家的不同而改变。

表 3-3: 传真(AT+F)命令(略)

表 3-4:拨号命令修改程序

修改程序 说明
L 重拨上次的号码。L 命令调制解调器重拨自开机后所拨的最后一个号码。
这应是 ATD 后的第一条命令;否则调制解调器将忽略该字符。
P 脉冲拨号。P 命令调制解调器使用脉冲拨号,直到选用音频拨号(T)为止。
脉冲的拨号/间隔比率由 &P 命令选择。注:某些国家可能不设脉冲拨号。
在那种情况下,P 命令将被忽略。
T 音频拨号。T 命令调制解调器使用音频拨号,直到选用脉冲拨号(P)为止,
音频的持续和间隔时间由寄存器 S11 设置。
W 等待拨号音频。W 使调制解调器暂停,直到检测到第二次拨号音频,检测到
拨号音频后,即立即开始拨电话号码。在通过PBX 拨号或使用某些长途电话
服务的情况下,这可能会相当有用。最长等待时间在寄存器 S7 中设置。
; (分号) 返回命令方式。分号(;)强制调制解调器在拨号后联络不断开的情况
下保持在命令方式。分号必须放在拨号命令的结尾。
@ (在字符) 等待静噪应答命令。@字符使调制解调器在处理拨号串的下一个符号
前在静噪数秒后寻找响铃。S7 寄存器决定最长等待时间。如果检测
到静噪应答, 将执行此命令后的拨号修改程序。如果检测到占用信
号,调制解调器返回占用(BUSY)结果代码并进入挂断过程,同时中止
命令的进一步执行。
! (感叹号) 快速挂机摘机命令。感叹号(!)使调制解调器处于挂机状态0.5 秒,
然后返回摘机状态,某些 PBX 系统用此命令来访问诸如呼叫转传和
呼叫转送等特殊功能。
,(逗号) 拨号期间暂停。逗号(,)使调制解调器在拨号期间暂停一段指定时间,
持续时间由寄存器 S8 设置。
^ (脱字号) 禁用数据呼叫音频传输。此命令仅对当前呼叫有效。
0 到 9 拨号数字。脉冲或音频拨号的有效数字。
A、B、C、D、#、* 拨号字符。仅为音频拨号的有效字符。A、B、C 和 D 是双
音频多频率(DTMF) 系统中加在 369# 键右边的四个键。
注:在禁用这些字符的国家,它们将被忽略。
注:电话号码(拨号串)输入时可带或不带空格或其它标点符号。T和 P 修改命令
可出现在拨号串的任何地方;因此,如果您所在的国家允许使用此功能,信号发
送方法可能会在传送了几个数字后发生改变。

panda_w 2001-04-13
  • 打赏
  • 举报
回复
vchelp.net应该有的阿
Un1 2001-04-13
  • 打赏
  • 举报
回复
最好使用 RAS
zqzxf 2001-04-12
  • 打赏
  • 举报
回复
http://www.sellsbrothers.com/telprog/
xiao_zhu 2001-04-12
  • 打赏
  • 举报
回复
vcbear,谢谢,能不能给点示例性的代码啊?看MSDN里的TAPI说明,看的直吐血啊!
vcbear 2001-04-12
  • 打赏
  • 举报
回复
串口通过AT指令实现简单,到网上查一下“串口”,包你满意。
TAPI同样,比串口的还要简单。
xiao_zhu 2001-04-12
  • 打赏
  • 举报
回复
怎么连看的人都没有啊,大家帮帮忙啊!

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧