用TAPI,我曾用C++在BCB下写个一个控件,楼主可以参考。
用纯API写的,很容易改写成Pascal的。
//---------------------------------------------------------------------------
/*
1.0.1 2000.7.25
修改:无MODEM时软件运行TAPI初始化死机。
禁止自动初始化
增加函数InitializeTAPI()以初始化TAPI.
1.0 2000.6.6
编写基本模块
*/
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TAPIComm.h"
#include "Assign.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//-- var, const, procedure ---------------------------------------------------
const int TL_TIMEOUT = 0x14;
const int HiVer = 0x20000;
const int LoVer = 0x10004;
const int LINENOTUSEABLE_ERROR = 0x1;
const int LINENOTUSEABLE_NOVOICE = 0x2;
const int LINENOTUSEABLE_NODATAMODEM = 0x3;
const int LINENOTUSEABLE_NOMAKECALL = 0x4;
const int LINENOTUSEABLE_ALLOCATED = 0x5;
const int LINENOTUSEABLE_INUSE = 0x6;
const int LINENOTUSEABLE_NOCOMMDATAMODEM = 0x7;
//const int HEAP_ZERO_MEMORY = 0x8;
const Word EVENT_TIMEOUT = 0x12c;
const Word CM_NEWDATATHREAD = 0x709;
const Word CM_NEWDATAARRIVES = 0x70a;
#define NEW_LINE "/r/n"
#define LINEUNAVAIL "Line Unavailable"
#define LINEUNNAMED "Line Unnamed"
#define LINENAMEEMPTY "Line Name is Empty"
extern PACKAGE bool bWaitingInProcess;
extern PACKAGE void __fastcall Register(void);
extern PACKAGE void __stdcall LineCallbackProc(DWORD hDevice, DWORD dwMessage,
DWORD dwInstance, DWORD dwParam1,
DWORD dwParam2, DWORD dwParam3 );
extern PACKAGE void __fastcall ZeroMem(char * p);
//---------------------------------------------------------------------------
TTAPIComm* thisTAPIComm = NULL;
//TformDialing* formDialing NULL;
TNewData* thread;
bool bWaitingInProcess;
void __fastcall TapiCheck(int );
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TTAPIComm *)
{
new TTAPIComm(NULL);
}
//---------------------------------------------------------------------------
namespace Tapicomm
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TTAPIComm)};
RegisterComponents("APW Tools", classes, 0);
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// TAPIComm
__fastcall TTAPIComm::TTAPIComm(TComponent* AOwner)
: TComponent(AOwner)
{
if( thisTAPIComm != NULL )
throw Exception("TAPIComm component already exists in this process.");
Parent = AOwner;
thisTAPIComm = this;
LineApp = NULL;
TAPIInitialized = false;
FDirectAccess = false;
FDirectAccessScript = new TStringList;
FDevIDToInitialize = MAXDWORD;
FWaitForCall = true;
FInfoLabel = NULL;
FLogStrings = NULL;
Timeout = TL_TIMEOUT;
eventCallInProcess = CreateEvent (NULL, true, true, NULL);
eventOverlappedWrite = CreateEvent (NULL, true, true, NULL);
eventOverlappedRead = CreateEvent (NULL, true, true, NULL);
bStopWaitingNewData = false;
hCommFile = INVALID_HANDLE_VALUE;
}
//---------------------------------------------------------------------------
__fastcall TTAPIComm::~TTAPIComm()
{
try
{
Drop();
Close();
}
catch(...)
{
}
if( LineApp != NULL )
TapiCheck(lineShutdown(LineApp));
CloseHandle (eventCallInProcess);
CloseHandle (eventOverlappedWrite);
CloseHandle (eventOverlappedRead);
thisTAPIComm = NULL;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TTAPIComm::LineCallStateToStr(DWORD CallState)
{
AnsiString Result;
switch( CallState )
{
case LINECALLSTATE_IDLE :
{
Result = "IDLE";
break;
}
case LINECALLSTATE_OFFERING :
{
Result = "OFFERING";
break;
}
case LINECALLSTATE_ACCEPTED :
{
Result = "ACCEPTED";
break;
}
case LINECALLSTATE_DIALTONE :
{
Result = "DIALTONE";
break;
}
case LINECALLSTATE_DIALING :
{
Result = "DIALING";
break;
}
case LINECALLSTATE_RINGBACK :
{
Result = "RINGBACK";
break;
}
case LINECALLSTATE_BUSY :
{
Result = "BUSY";
break;
}
case LINECALLSTATE_SPECIALINFO :
{
Result = "SPECIALINFO";
break;
}
case LINECALLSTATE_CONNECTED :
{
Result = "CONNECTED";
break;
}
case LINECALLSTATE_PROCEEDING :
{
Result = "PROCEEDING";
break;
}
case LINECALLSTATE_ONHOLD :
{
Result = "ONHOLD";
break;
}
case LINECALLSTATE_CONFERENCED :
{
Result = "CONFERENCED";
break;
}
case LINECALLSTATE_ONHOLDPENDCONF :
{
Result = "ONHOLDPENDCONF";
break;
}
case LINECALLSTATE_ONHOLDPENDTRANSFER :
{
Result = "ONHOLDPENDTRANSFER";
break;
}
case LINECALLSTATE_DISCONNECTED :
{
Result = "DISCONNECTED";
break;
}
case LINECALLSTATE_UNKNOWN :
{
Result = "UNKNOWN";
break;
}
default:
{
Result = "Unknown (" + IntToStr(CallState) + ")";
break;
}
}
return Result;
}
//---------------------------------------------------------------------------
AnsiString __fastcall TTAPIComm::LineCallStateInfoToStr (DWORD CallState, DWORD Info)
{
AnsiString Result = "";
if( Info == 0 )
Result = "Command complete";
else
{
switch( CallState )
{
case LINECALLSTATE_DIALTONE :
{
switch( Info )
{
case LINEDIALTONEMODE_NORMAL :
{
Result = "Dialtone normal";
break;
}
case LINEDIALTONEMODE_SPECIAL:
{
Result = "SPECIAL";
break;
}
case LINEDIALTONEMODE_INTERNAL:
{
Result = "INTERNAL";
break;
}
case LINEDIALTONEMODE_EXTERNAL:
{
Result = "EXTERNAL";
break;
}
case LINEDIALTONEMODE_UNKNOWN:
{
Result = "UNKNOWN";
break;
}
case LINEDIALTONEMODE_UNAVAIL:
{
Result = "UNAVAIL";
break;
}
}
break;
}
case LINECALLSTATE_BUSY :
{
switch( Info )
{
case LINEBUSYMODE_STATION :
{
Result = "STATION";
break;
}
case LINEBUSYMODE_TRUNK :
{
Result = "TRUNK";
break;
}
case LINEBUSYMODE_UNKNOWN :
{
Result = "UNKNOWN";
break;
}
case LINEBUSYMODE_UNAVAIL :
{
Result = "UNAVAIL";
break;
}
}
break;
}
case LINECALLSTATE_DISCONNECTED :
{
switch( Info )
{
case LINEDISCONNECTMODE_NORMAL :
{
Result = "NORMAL";
break;
}
case LINEDISCONNECTMODE_UNKNOWN :
{
Result = "UNKNOWN";
break;
}
case LINEDISCONNECTMODE_REJECT :
{
Result = "REJECT";
break;
}
case LINEDISCONNECTMODE_PICKUP :
{
Result = "PICKUP";
break;
}
case LINEDISCONNECTMODE_FORWARDED :
{
Result = "FORWARDED";
break;
}
case LINEDISCONNECTMODE_BUSY :
{
Result = "BUSY";
break;
}
case LINEDISCONNECTMODE_NOANSWER :
{
Result = "NOANSWER";
break;
}
case LINEDISCONNECTMODE_BADADDRESS :
{
Result = "BADADDRESS";
break;
}
case LINEDISCONNECTMODE_UNREACHABLE :
{
Result = "UNREACHABLE";
break;
}
case LINEDISCONNECTMODE_CONGESTION :
{
Result = "CONGESTION";
break;
}
case LINEDISCONNECTMODE_INCOMPATIBLE :
{
Result = "INCOMPATIBLE";
break;
}
case LINEDISCONNECTMODE_UNAVAIL :
{
Result = "UNAVAIL";
break;
}
case LINEDISCONNECTMODE_NODIALTONE: // TAPI v1.4
{
Result = "NODIALTONE";
break;
}
}
break;
}
}
}
if( Result == "" )
Result = String("Undefined (") + IntToStr(Info) + ")";
return Result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 初始化TAPI
bool __fastcall TTAPIComm::InitializeTAPI()
{
if( TAPIInitialized == true )
return true;
TapiCheck(lineInitialize(&LineApp,
GetModuleHandle (NULL),
LineCallbackProc,
PChar(Application->Title.c_str()),
&NumDevs));
Version = 0;
if( NumDevs == 0 )
ShowMessage(String("There is no modem installed in your PC.") + "/x0d/x0a" +
"You should install it via Control panel | Modems | Add.");
else
TAPIInitialized = true;
return TAPIInitialized;
}
//---------------------------------------------------------------------------
// TAPI回调函数
void __stdcall LineCallbackProc (DWORD hDevice, DWORD dwMessage,
DWORD dwInstance, DWORD dwParam1,
DWORD dwParam2, DWORD dwParam3 )
{
AnsiString S;
switch( dwMessage )
{
case LINE_CLOSE:
{
S = "Line has been unexpectedly closed";
if( Assigned(thisTAPIComm->OnUnexpectedClose) )
thisTAPIComm->OnUnexpectedClose (thisTAPIComm);
break;
}
case LINE_CALLSTATE:
{
S = thisTAPIComm->LineCallStateInfoToStr(dwParam1, dwParam2);
switch( dwParam1 )
{
case LINECALLSTATE_CONNECTED: // CONNECTED!!!
{
if( !thisTAPIComm->bDropped &&
thisTAPIComm->DevIDToInitialize != MAXDWORD &&
!thisTAPIComm->bConnected )
{
try
{
thisTAPIComm->OnConnectionInt();
}
catch(...)
{
ShowMessage("An error occured on connection internal.");
//formDialing.Hide;
return ;
}
// Perform a direct access to device end
if( thisTAPIComm->DirectAccess &&
thisTAPIComm->DirectAccessScript->Count != 0 )
{
try
{
thisTAPIComm->MakeDirectAccessScript();
}
catch(...)
{
ShowMessage(thisTAPIComm->sDirectAccessResult);
//formDialing.Hide;
return;
}
}
//formDialing.Hide;
if( Assigned (thisTAPIComm->OnConnection) )
thisTAPIComm->OnConnection (thisTAPIComm);
}
break;
}
case LINECALLSTATE_OFFERING:
{
if( !thisTAPIComm->bConnected )
{
thisTAPIComm->Call = HCALL (hDevice);
if( Assigned (thisTAPIComm->OnCallOffering) )
thisTAPIComm->OnCallOffering (thisTAPIComm);
if( thisTAPIComm->WaitForCall )
{
//formDialing.Show;
try
{
TapiCheck(lineAnswer(thisTAPIComm->Call, NULL, 0));
}
catch(...)
{
ShowMessage ("Unable to answer to call.");
//formDialing.Hide;
return;
}
}
}
break;
}
case LINECALLSTATE_IDLE:
{
try
{
if( thisTAPIComm->Call != 0 )
TapiCheck(lineDeallocateCall (thisTAPIComm->Call));
}
catch(...)
{
ShowMessage ("Unable to dealocate a call.");
//formDialing.Hide;
return;
}
thisTAPIComm->Call = 0;
CloseHandle (thisTAPIComm->hCommFile);
thisTAPIComm->hCommFile = INVALID_HANDLE_VALUE;
break;
}
case LINECALLSTATE_DISCONNECTED:
{
CloseHandle (thisTAPIComm->hCommFile);
thisTAPIComm->hCommFile = INVALID_HANDLE_VALUE;
if( Assigned (thisTAPIComm->OnDisconnect) )
thisTAPIComm->OnDisconnect (thisTAPIComm);
//formDialing.Hide;
break;
}
case LINECALLSTATE_BUSY:
{
if( Assigned (thisTAPIComm->OnBusy) )
thisTAPIComm->OnBusy (thisTAPIComm);
//formDialing.Hide;
break;
}
default:
{
S = thisTAPIComm->LineCallStateToStr(dwParam1);
break;
}
}
break;
}
case LINE_REPLY :
{
try
{
thisTAPIComm->OnReply(dwParam1, dwParam2);
}
catch(...)
{
ShowMessage ("An error occured on reply.");
//formDialing.Hide;
return;
}
break;
}
}
if( S != "" )
thisTAPIComm->IssueInfo( S );
}
//---------------------------------------------------------------------------
// TAPI回应消息处理
void __fastcall TTAPIComm::OnReply(DWORD dwParam1, DWORD dwErrorCode)
{
if( dwParam1 == dwRequestAnswer )
{
dwRequestAnswer = 0;
TapiCheck (dwErrorCode);
if( Assigned(OnCallAnswering) )
OnCallAnswering (this);
}
if( dwParam1 == dwRequestMakeCall )
{
//if( Assigned (dwRequestMakeCall) ) dwRequestMakeCall (this);
dwRequestMakeCall = 0;
TapiCheck(dwErrorCode);
}
if( dwParam1 == dwRequestDrop )
{
dwRequestAnswer = 0;
dwRequestMakeCall = 0;
dwRequestDrop = 0;
//formDialing.Hide;
TapiCheck (dwErrorCode);
//if( Assigned (dwRequestMakeCall) )
// dwRequestMakeCall (this);
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 建立数据链结通道
void __fastcall TTAPIComm::OnConnectionInt()
{
// 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( (bConnected) )
// return;
bConnected = true;
hCommFile = 0;
// Get the handle to the comm port from the driver so we can start
// communicating. This is returned in a LPVARSTRING structure.
// Allocate the VARSTRING structure
DWORD dwSizeofVarString = sizeof(VARSTRING) + 1024;
char* buf = new char[dwSizeofVarString];
LPVARSTRING lpVarString_ = (LPVARSTRING)buf;
memset( (char*)lpVarString_, 0, dwSizeofVarString );
lpVarString_->dwTotalSize = dwSizeofVarString;
// Fill the VARSTRING structure
TapiCheck (lineGetID(Line, 0, Call, LINECALLSELECT_CALL,
lpVarString_, "comm/datamodem"));
// Again, the handle to the comm port is contained in a
// LPVARSTRING structure. Thus, the handle is the very first
// thing after the } of the structure. Note that the name of
// the comm port is right after the handle, but I don"t want it.
memcpy(&hCommFile, (char*)(LONG(lpVarString_) + lpVarString_->dwStringOffset), sizeof(int));
// We don"t need to set the baud rate && other parameters
// because most of them are set up with TAPIserv
if( hCommFile != INVALID_HANDLE_VALUE )
{
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts(hCommFile, &CommTimeOuts);
// The CommTimeout numbers will very likely change if( you are
// coding to meet some kind of specif(ication where
// you need to reply within a certain amount of time after
// recieving the last byte. However, if 1/4th of a second
// goes by between recieving two characters, its a good
// indication that the transmitting } has finished, even
// assuming a 1200 baud modem.
CommTimeOuts.ReadIntervalTimeout = 250;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hCommFile, &CommTimeOuts);
// set OnNewData event
SetCommMask (hCommFile, EV_RXCHAR);
if( Assigned (OnNewData) )
ResumeWaitingNewData();
}
else
bConnected = false;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 打开线路
void __fastcall TTAPIComm::Open()
{
if( TAPIInitialized == false )
{ShowMessage( "TAPI should be initalized." );
return;
}
if( DevIDToInitialize == MAXDWORD )
throw Exception("TAPIComm: You must select TAPI compatible line");
IssueInfo( "Try to open line... (takes several seconds)" );
Version = 0;
LINEEXTENSIONID Ext;
TapiCheck(lineNegotiateAPIVersion(LineApp, DevIDToInitialize,
LoVer, HiVer, &Version, &Ext));
TapiCheck (lineOpen(LineApp, DevIDToInitialize, &Line, Version, 0, 0,
LINECALLPRIVILEGE_MONITOR | LINECALLPRIVILEGE_OWNER,
LINEMEDIAMODE_DATAMODEM, NULL));
IssueInfo( "Line opened" );
bDropped = false;
bStopWaitingNewData = false;
bWaitingInProcess = false;
// if( Thread != NULL )
// Thread.Free;
// Thread = NULL;
if( Assigned (FOnOpen) )
FOnOpen (this);
}
//---------------------------------------------------------------------------
// 关闭线路
void __fastcall TTAPIComm::Close()
{
IssueInfo( "Try to close line... (takes several seconds)" );
Application->ProcessMessages();
SetEvent (eventCallInProcess);
bConnected = false;
if( hCommFile != INVALID_HANDLE_VALUE )
{
PurgeComm (hCommFile, PURGE_TXABORT+PURGE_RXABORT);
CloseHandle (hCommFile);
hCommFile = INVALID_HANDLE_VALUE;
}
if( NumDevs != 0 )
{
lineClose (Line);
Line = 0;
}
IssueInfo( "Line Closed." );
if( Assigned(FOnClose) )
FOnClose (this);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 拨号
bool __fastcall TTAPIComm::MakeCall()
{
if( DevIDToInitialize == MAXDWORD )
throw Exception("TAPIComm: You must select TAPI compatible line");
if( Line == 0 )
throw Exception("TAPIComm: You must open line at first");
if( dwRequestMakeCall > 0 )
return false;
// formDialing.Show;
LINECALLPARAMS LineCallParams;
memset( &LineCallParams, 0, sizeof(LineCallParams) );
LineCallParams.dwTotalSize = sizeof(LineCallParams);
if( FDirectAccess )
LineCallParams.dwBearerMode = LINEBEARERMODE_PASSTHROUGH;
else
LineCallParams.dwBearerMode = LINEBEARERMODE_VOICE;
LineCallParams.dwMediaMode = LINEMEDIAMODE_DATAMODEM;
bDropped = false;
if( FDirectAccess )
dwRequestMakeCall = lineMakeCall(Line, &Call, NULL, 0, &LineCallParams);
else
dwRequestMakeCall = lineMakeCall(Line, &Call, FPhoneNumber.c_str(), 0, &LineCallParams);
TapiCheck (dwRequestMakeCall);
return true;
}
//---------------------------------------------------------------------------
// 关闭呼叫
bool __fastcall TTAPIComm:
rop()
{
IssueInfo( "Try to drop call... (takes several seconds)" );
bool Result = false;
SetEvent (eventCallInProcess);
bConnected = false;
bDropped = true;
if( Call != 0 )
{
dwRequestDrop = lineDrop (Call, NULL, 0);
// TapiCheck (dwRequestDrop);
Call = 0;
}
while( WaitForSingleObject (eventCallInProcess, EVENT_TIMEOUT) == WAIT_TIMEOUT )
Application->ProcessMessages();
if( Assigned (FOnDropCall) )
FOnDropCall (this);
IssueInfo( "Call droped." );
return Result;
}
//---------------------------------------------------------------------------
// 以直接控制方式拨号
void __fastcall TTAPIComm::MakeDirectAccessScript()
{
if( DevIDToInitialize == MAXDWORD )
throw Exception("TAPIComm: You must select TAPI compatible line");
TLogFile* slLog = NULL;
if( FDirectAccessLogFile != "" )
slLog = new TLogFile(this);
if( Assigned (slLog) )
slLog->WriteLog ("TAPIComm logfile: ", DateTimeToStr(Now()));
//SetThreadPriority (GetCurrentThread, THREAD_PRIORITY_HIGHEST);
int limit = FDirectAccessScript->Count;
AnsiString sResponse = "";
for( int i = 0; i< limit; i++ )
{
AnsiString s = FDirectAccessScript->Strings
;
if( Assigned (slLog) )
slLog->WriteLog ("Write (send command to modem)", s + NEW_LINE);
Write(s + NEW_LINE);
while( !bDropped )
{
// our modem have to have time to answer...
DWORD waitTime = GetTickCount () + 1000;
while( waitTime > GetTickCount() )
Application->ProcessMessages();
sResponse = sResponse + Read (0);
if( Assigned (slLog) )
slLog->WriteLog ("Read (command in process)", sResponse);
if( UpperCase(sResponse).Pos("OK") != 0 )
{
if( Assigned (slLog) )
slLog->WriteLog ("Command complete (OK received)", sResponse);
sResponse = "";
if( limit != i )
break; //Go to do the next command from script
}
else if( UpperCase(sResponse).Pos("CONNECT") != 0 )
{
// we made a connection!
if( Assigned(slLog) )
slLog->WriteLog ("Connected! (conection esteblished)", sResponse);
if( Assigned (slLog) )
slLog->SaveToFile (FDirectAccessLogFile);
delete slLog;
//SetThreadPriority (GetCurrentThread, THREAD_PRIORITY_NORMAL);
PurgeComm (hCommFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
return;
}
else if( UpperCase(sResponse).Pos("ERROR") != 0 ||
UpperCase(sResponse).Pos("NO") != 0 )
{
if( Assigned (slLog) )
slLog->WriteLog ("Error (modem return bad response)", sResponse);
PurgeComm (hCommFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
if( Assigned (slLog) )
slLog->SaveToFile (FDirectAccessLogFile);
delete slLog;
//SetThreadPriority (GetCurrentThread, THREAD_PRIORITY_NORMAL);
sDirectAccessResult = String("TAPIComm: Device direct access script error: ") +
s + "." + NEW_LINE + sResponse;
throw Exception(sDirectAccessResult);
}
Application->ProcessMessages();
}
}
if( bDropped )
if( Assigned (slLog) )
slLog->WriteLog ("Dropped (user hangup)", sResponse);
if( slLog != NULL )
{
slLog->SaveToFile (FDirectAccessLogFile);
delete slLog;
}
//SetThreadPriority (GetCurrentThread, THREAD_PRIORITY_NORMAL);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 通讯方式对话框
void __fastcall TTAPIComm::ConfigDialog()
{
if( DevIDToInitialize == MAXDWORD )
throw Exception("TAPIComm: You must select TAPI compatible line");
TapiCheck(lineConfigDialog(DevIDToInitialize, ((TForm*)Parent)->Handle, "comm/datamodem"));
}
//---------------------------------------------------------------------------
// 拨号方式对话框
void __fastcall TTAPIComm::TranslateDialog()
{
DWORD lVer;
if( DevIDToInitialize == MAXDWORD )
throw Exception("TAPIComm: You must select TAPI compatible line");
if( Version == 0 )
lVer = LoVer;
else
lVer = Version;
TapiCheck(lineTranslateDialog(LineApp, DevIDToInitialize, lVer,
((TForm*)Parent)->Handle, LPCSTR(PhoneNumber.c_str())));
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::SetPhoneNumber(AnsiString value)
{
if( FPhoneNumber != value )
FPhoneNumber = value;
}
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::SetDevIDToInitialize(DWORD value)
{
if( FDevIDToInitialize == value )
return;
if( VerifyUsableLine(value) == 0 )
FDevIDToInitialize = value;
// This routine is necessary,
// because we want to take modem name
// Let"s go!
DWORD dwAPIVersion;
LPLINEDEVCAPS lpLineDevCaps_;
DWORD dwSizeofLineDev = sizeof(LINEDEVCAPS) + 1024;
unsigned char* buf = new unsigned char[dwSizeofLineDev];
lpLineDevCaps_ = (LPLINEDEVCAPS)buf;
memset((char*)lpLineDevCaps_, 0, dwSizeofLineDev);
lpLineDevCaps_->dwTotalSize = dwSizeofLineDev;
dwAPIVersion = I_lineNegotiateAPIVersion(DevIDToInitialize);
TapiCheck (lineGetDevCaps (LineApp, DevIDToInitialize, dwAPIVersion, 0, lpLineDevCaps_));
//formDialing.ModemName.Caption = GetLineName (lpLineDevCaps_);
delete[] buf;
}
//---------------------------------------------------------------------------
void __fastcall ZeroMem(AnsiString str)
{
for( int i = 0; i< str.Length(); i++ )
str= '/x0';
}
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::SetWaitForCall (bool value)
{
if( FWaitForCall != value )
FWaitForCall = value;
}
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::SetLines(TStrings* value)
{
if( value != NULL )
FDirectAccessScript->Assign(value);
}
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::SetInfoLabel(TStatusPanel* value)
{
// if( value != NULL )
// FInfoLabel->Assign(value);
}
//---------------------------------------------------------------------------
bool __fastcall TTAPIComm::GetOpened()
{
return (Line != NULL);
}
//---------------------------------------------------------------------------
bool __fastcall TTAPIComm::GetCalled()
{
return (Call != NULL);
}
//---------------------------------------------------------------------------
// 取出错信息的字符串
AnsiString __fastcall TTAPIComm::ClearCommErrorToStr(DWORD dwErrorFlags)
{
AnsiString Result = "";
if( dwErrorFlags == CE_BREAK )
Result += "The hardware detected a break condition.";
if( dwErrorFlags == CE_DNS )
Result += "Windows 95 only: A parallel device is ! selected.";
if( dwErrorFlags == CE_FRAME )
Result += "The hardware detected a framing error.";
if( dwErrorFlags == CE_IOE )
Result += "An I/O error occurred during communications with the device.";
if( dwErrorFlags == CE_MODE )
Result += "The requested mode is! supported, or the hFile parameter is invalid. if( this value is specif(ied, it is the only valid error.";
if( dwErrorFlags == CE_OOP )
Result += "Windows 95 only: A parallel device signaled that it is out of paper.";
if( dwErrorFlags == CE_OVERRUN )
Result += "A character-buffer overrun has occurred. The next character is lost.";
if( dwErrorFlags == CE_PTO )
Result += Result + "Windows 95 only: A time-out occurred on a parallel device.";
if( dwErrorFlags == CE_RXOVER )
Result += "An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the }-of-file (EOF) character.";
if( dwErrorFlags == CE_RXPARITY )
Result += "The hardware detected a parity error.";
if( dwErrorFlags == CE_TXFULL )
Result += "The application tried to transmit a character, but the output buffer was full.";
return Result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 硬件信息
//---------------------------------------------------------------------------
// 取设备图标
HICON __fastcall TTAPIComm::GetIcon(DWORD DevId)
{
HICON Result = 0;
if( DevId == MAXDWORD )
DevId = DevIDToInitialize;
if( DevId == MAXDWORD )
// throw Exception.Create ("TAPIComm: You must select TAPI compatible line");
return Result;
TapiCheck (lineGetIcon(DevId, "comm/datamodem", &Result));
return Result;
}
//------------------------------------------------------------------------------
//
// __fastcall: void FillTAPIComm(HWND)
//
// PURPOSE: Fills the "TAPI Line" control with the available line devices.
//
// PARAMETERS:
// hwndDlg - handle to the current "Dial" dialog
//
// RETURN VALUE:
// none
//
// COMMENTS:
//
// This __fastcall enumerates through all the TAPI line devices &&
// queries each for the device name. The device name is ) put into
// the "TAPI Line" control. These device names are kept in order rather
// than sorted. This allows "Dial" to know which device ID the user
// selected just by the knowing the index of the selected AnsiString.
//
// There are default values if( there isn"t a device name, if( there is
// an error on the device, or if( the device name is an empty AnsiString.
// The device name is also checked to make sure it is null terminated.
//
// Note that a Legacy API Version is negotiated. Since the fields in
// the LINEDEVCAPS structure that we are interested in haven"t moved, we
// can negotiate a lower API Version than this sample is designed for
// && still be able to access the necessary structure members.
//
// The first line that is usable by TapiComm is selected as the "default"
// line. Also note that if( there was a previously selected line, this
// remains the default line. This would likely only occur if( this
// __fastcall is called after the dialog has initialized once; for example,
// if( a new line is added.
//
// 取系统中全部可用线路
DWORD __fastcall TTAPIComm::FillLine(Classes::TStrings* sl)
{
DWORD Result = 0;
sl->Clear();
DWORD dwSizeofLineDev = sizeof(LINEDEVCAPS) + 1024;
char* buf = new char[dwSizeofLineDev];
memset( buf, 0, dwSizeofLineDev);
LPLINEDEVCAPS lpLineDevCaps_ = (LPLINEDEVCAPS)buf;;
lpLineDevCaps_->dwTotalSize = dwSizeofLineDev;
AnsiString sLineName;
for( DWORD dwDeviceID = 0; dwDeviceID < NumDevs; dwDeviceID++ )
{
DWORD dwAPIVersion = I_lineNegotiateLegacyAPIVersion (dwDeviceID);
if( dwAPIVersion != 0 )
{
TapiCheck(lineGetDevCaps (LineApp, dwDeviceID, dwAPIVersion, 0, lpLineDevCaps_));
sLineName = GetLineName (lpLineDevCaps_);
}
else // Couldn"t NegotiateAPIVersion. Line is unavail.
sLineName = LINEUNAVAIL;
// Put the device name into the control
sl->Add (sLineName);
sLineName = "";
Result++;
}
if( (lpLineDevCaps_ != NULL) )
delete[] buf;
return Result;
}
//---------------------------------------------------------------------------
// 取指定线路的名称
AnsiString __fastcall TTAPIComm::GetLineName(LPLINEDEVCAPS lpLineDevCaps_)
{
AnsiString Result = "";
if( lpLineDevCaps_ != NULL )
{
char* lpszLineName = new char[lpLineDevCaps_->dwLineNameSize + 1];
if( lpLineDevCaps_->dwLineNameSize != 0 &&
lpLineDevCaps_->dwLineNameOffset != 0 &&
lpLineDevCaps_->dwStringFormat == STRINGFORMAT_ASCII )
{
// This is the name of the device.
StrMove(lpszLineName,
(char*)(int(lpLineDevCaps_) + lpLineDevCaps_->dwLineNameOffset),
lpLineDevCaps_->dwLineNameSize);
if( lpszLineName[0] != '/x0' )
{
// Reverse indented to make this fit
// Make sure the device name is null terminated.
if( lpszLineName [lpLineDevCaps_->dwLineNameSize -1] != '/x0' )
{
// if( the device name is ! null terminated, null
// terminate it. Yes, this looses the end character.
// Its a bug in the service provider.
lpszLineName[lpLineDevCaps_->dwLineNameSize - 1] = '/x0';
}
}
else // Line name started with a NULL.
StrPCopy(lpszLineName, LINENAMEEMPTY);
}
else // DevCaps doesn"t have a valid line name. Unnamed.
StrPCopy (lpszLineName, LINEUNNAMED);
Result = StrPas (lpszLineName);
delete[] lpszLineName;
}
else // Couldn"t GetDevCaps. Line is unavail.
Result = LINEUNAVAIL;
return Result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// __fastcall: long Verif(yUsableLine(DWORD)
//
// PURPOSE: Verif(ies that a specif(ic line device is useable by TapiComm.
//
// PARAMETERS:
// dwDeviceID - The ID of the line device to be verif(ied
//
// RETURN VALUE:
// Returns SUCCESS if dwDeviceID is a usable line device.
// Returns a LINENOTUSEABLE_ constant otherwise.
//
// COMMENTS:
//
// VerifyUsableLine takes the give device ID && verifies step by step
// that the device supports all the features that TapiComm requires.
//
// 确定线路是否可用
int __fastcall TTAPIComm::VerifyUsableLine(DWORD dwDeviceID)
{
if( TAPIInitialized == false )
{
ShowMessage( "TAPI should be initalized." );
return -1;
}
LPLINEADDRESSSTATUS lpLineAddressStatus_;
LPLINEDEVCAPS lpLineDevCaps_;
LPVARSTRING lpVarString_;
char* abuf = NULL;
char* dbuf = NULL;
char* vbuf = NULL;
HCALL hCall_ = 0;
HLINE hLine_ = 0;
DWORD dwSizeofLineAddr = sizeof(LINEADDRESSSTATUS) + 1024;
DWORD dwSizeofLineDev = sizeof(LINEDEVCAPS) + 1024;
DWORD dwSizeofVarStr = sizeof(VARSTRING) + 1024;
DWORD Result = 0;
int lReturn;
// The line device must support an API Version that TapiComm does.
DWORD dwAPIVersion = I_lineNegotiateAPIVersion(dwDeviceID);
if( dwAPIVersion == 0 )
{
Result = LINENOTUSEABLE_ERROR;
// h-mm, operator GOTO!!!
goto glbDeleteBuffers;
}
dbuf = new char[dwSizeofLineDev];
memset( dbuf, 0, dwSizeofLineDev);
lpLineDevCaps_ = (LPLINEDEVCAPS)dbuf;;
lpLineDevCaps_->dwTotalSize = dwSizeofLineDev;
TapiCheck (lineGetDevCaps (LineApp, dwDeviceID, dwAPIVersion, 0, lpLineDevCaps_));
// Must support LINEBEARERMODE_VOICE
if( (lpLineDevCaps_->dwBearerModes & LINEBEARERMODE_VOICE) == 0 )
{
Result = LINENOTUSEABLE_NOVOICE;
ShowMessage ("VerifyUsableLine: doesn't support LINEBEARERMODE_VOICE");
goto glbDeleteBuffers;
}
// Must support LINEMEDIAMODE_DATAMODEM
if( (lpLineDevCaps_->dwMediaModes && LINEMEDIAMODE_DATAMODEM) == 0 )
{
Result = LINENOTUSEABLE_NODATAMODEM;
ShowMessage ("VerifyUsableLine: doesn't support LINEMEDIAMODE_DATAMODEM");
goto glbDeleteBuffers;
}
// Must be able to make calls
if( (lpLineDevCaps_->dwLineFeatures & LINEFEATURE_MAKECALL) == 0 )
{
Result = LINENOTUSEABLE_NOMAKECALL;
ShowMessage ("VerifyUsableLine: doesn""t support LINEFEATURE_MAKECALL");
goto glbDeleteBuffers;
}
// It is necessary to open the line so we can check if
// there are any call appearances available. Other TAPI
// applications could be using all call appearances.
// Opening the line also checks for other possible problems.
lReturn = lineOpen(LineApp, dwDeviceID, &hLine_, dwAPIVersion, 0, 0,
LINECALLPRIVILEGE_NONE, LINEMEDIAMODE_DATAMODEM,
LPLINECALLPARAMS(0));
if( lReturn == LINEERR_ALLOCATED )
{
ShowMessage (String("VerifyUsableLine: ") + NEW_LINE +
"Line is already in use by a non-TAPI app or" + NEW_LINE +
"another Service Provider.");
Result = LINENOTUSEABLE_ALLOCATED;
goto glbDeleteBuffers;
}
else
TapiCheck (lReturn);
abuf = new char[dwSizeofLineAddr];
memset( abuf, 0, dwSizeofLineAddr );
lpLineAddressStatus_ = (LPLINEADDRESSSTATUS)abuf;
lpLineAddressStatus_->dwTotalSize = dwSizeofLineAddr;
// Get LineAddressStatus to make sure the line isn"t already in use.
TapiCheck (lineGetAddressStatus(hLine_, 0, lpLineAddressStatus_));
// Are there any available call appearances (ie: is it in use)?
if( (lpLineAddressStatus_->dwAddressFeatures & LINEADDRFEATURE_MAKECALL) == 0 )
{
ShowMessage (String("VerifyUsableLine: ") + NEW_LINE +
"Line make call feature is not available." );
Result = LINENOTUSEABLE_INUSE;
goto glbDeleteBuffers;
}
// Make sure the "comm/datamodem" device class is supported
// Note that we don"t want any of the "extra" information
// normally returned in the VARSTRING structure. All we care
// about is if( lineGetID succeeds.
vbuf = new char[dwSizeofVarStr];
memset( vbuf, 0, dwSizeofVarStr );
lpVarString_ = (LPVARSTRING)vbuf;
lpVarString_->dwTotalSize = dwSizeofVarStr;
// Fill the VARSTRING structure
TapiCheck (lineGetID(hLine_, 0, hCall_, LINECALLSELECT_LINE, lpVarString_, "comm/datamodem"));
glbDeleteBuffers:
if( hCall_ != 0 )
lineDrop(hCall_, NULL, 0);
if( hLine_ != 0 )
lineClose (hLine_);
if( abuf != NULL )
delete[] abuf;
if( dbuf != NULL )
delete[] dbuf;
if( vbuf != NULL )
delete[] vbuf;
return Result;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// __fastcall: DWORD I_lineNegotiateLegacyAPIVersion(DWORD)
//
// PURPOSE: Negotiate an API Version to use for a specif(ic device.
//
// PARAMETERS:
// dwDeviceID - device to negotiate an API Version for.
//
// RETURN VALUE:
// Returns the API Version to use for this line if( successful.
// Returns 0 if( negotiations fall through.
//
// COMMENTS:
//
// This wrapper is slightly different from the I_lineNegotiateAPIVersion.
// This wrapper allows TapiComm to negotiate an API version between
// 1.3 && SAMPLE_TAPI_VERSION. Normally, this sample is specif(ic to
// API Version SAMPLE_TAPI_VERSION. However, there are a few times when
// TapiComm needs to get information from a service provider, but also knows
// that a lower API Version would be ok. This allows TapiComm to recognize
// legacy service providers even though it can"t use them. 1.3 is the
// lowest API Version a legacy service provider should support.
//
// 协商TAPI的版本
DWORD __fastcall TTAPIComm::I_lineNegotiateLegacyAPIVersion(DWORD dwDeviceID)
{
DWORD dwLocalAPIVersion;
LINEEXTENSIONID LineExtensionID;
DWORD dwReturn = lineNegotiateAPIVersion(LineApp, dwDeviceID,
LoVer, HiVer,
&dwLocalAPIVersion, &LineExtensionID);
if( dwReturn == LINEERR_INCOMPATIBLEAPIVERSION )
return 0;
TapiCheck (dwReturn);
return dwLocalAPIVersion;
}
//---------------------------------------------------------------------------
DWORD __fastcall TTAPIComm::I_lineNegotiateAPIVersion(DWORD dwDeviceID)
{
LINEEXTENSIONID LineExtensionID;
DWORD dwLocalAPIVersion;
DWORD dwReturn = lineNegotiateAPIVersion(LineApp, dwDeviceID,
LoVer, LoVer,
&dwLocalAPIVersion, &LineExtensionID);
if( (dwReturn == LINEERR_INCOMPATIBLEAPIVERSION) )
return 0;
TapiCheck (dwReturn);
return dwLocalAPIVersion;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 数据通讯相关
//---------------------------------------------------------------------------
// 接收数据
AnsiString __fastcall TTAPIComm::Read(DWORD wantedToRead)
{
AnsiString Result;
if( wantedToRead == 0 )
wantedToRead = cbInQue();
if( wantedToRead == 0 )
return Result;
char* buffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, wantedToRead+10);
ReadLargeData (buffer, wantedToRead);
Result.SetLength(wantedToRead + 10);
Result = StrPas(buffer);
HeapFree(GetProcessHeap, 0, buffer);
return Result;
}
//---------------------------------------------------------------------------
// 发送数据
bool __fastcall TTAPIComm::Write (const AnsiString sData)
{
if( sData == "" )
return false;
char* buffer = new char[sData.Length() + 10];
StrPCopy(buffer, sData);
bool Result = WriteLargeData(buffer, sData.Length());
delete[] buffer;
return Result;
}
//---------------------------------------------------------------------------
// 接收大量数据
int __fastcall TTAPIComm::ReadLargeData(char* buffer, DWORD wantedToRead)
{
int Result = 0;
if( bConnected == false || hCommFile == INVALID_HANDLE_VALUE )
return Result;
if( wantedToRead == 0 )
wantedToRead = cbInQue();
if( wantedToRead <= 0 )
return Result;
memset( buffer, 0, wantedToRead);
OVERLAPPED overlappedRead;
overlappedRead.Internal = 0;
overlappedRead.InternalHigh =0;
overlappedRead.Offset =0;
overlappedRead.OffsetHigh =0;
overlappedRead.hEvent = eventOverlappedRead;
DWORD dwNumberOfBytesRead = 0;
DWORD dwWhereToStartReading = 0;
do
{
// Start the overlapped I/O.
if( !ReadFile(hCommFile, (buffer+dwWhereToStartReading),
wantedToRead, &dwNumberOfBytesRead, &overlappedRead))
{
// WriteFile failed. Expected; lets handle it.
DWORD dwLastError = GetLastError();
// Its possible for this error to occur if( the
// service provider has closed the port. Time to }.
if( dwLastError == ERROR_INVALID_HANDLE )
{
// Likely that the Service Provider has closed the port.
COMSTAT comstat;
DWORD dwErrors;
ClearCommError(hCommFile, &dwErrors, &comstat);
throw Exception("COM Error: " + ClearCommErrorToStr(dwErrors));
}
// Unexpected error. No idea what.
if( dwLastError != ERROR_IO_PENDING )
throw Exception("Error reading from com port.");
// This is the expected ERROR_IO_PENDING case.
// Wait for overlapped I/O completion,
DWORD dwHandleSignaled = WaitForSingleObject(eventOverlappedRead, Timeout*1000);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0: // Wait finished.
{ // Time to get the results of the WriteFile
break;
}
case WAIT_TIMEOUT: // Wait failed.
{
// CancelIO (hCommFile);
// Really useful __fastcall, but works only under Windows NT
// Why?!
PurgeComm(hCommFile, PURGE_TXABORT+PURGE_RXABORT);
throw Exception("Timeout during read operation.");
}
default: // This case should never occur.
{
throw Exception("Unexpected Wait return value ");
}
}
if( !GetOverlappedResult(hCommFile, &overlappedRead, &dwNumberOfBytesRead, true) )
{
dwLastError = GetLastError();
// Its possible for this error to occur if( the
// service provider has closed the port.
if( dwLastError == ERROR_INVALID_HANDLE )
// Likely that the Service Provider has closed the port.
throw Exception("Connection has been broken during read.");
// No idea what could cause another error.
throw Exception("Error reading from com port while waiting");
}
}
// Some data was written. Make sure it all got written.
wantedToRead = wantedToRead - dwNumberOfBytesRead;
dwWhereToStartReading = dwWhereToStartReading + dwNumberOfBytesRead;
}
while(wantedToRead > 0); // Read the whole thing!
return dwWhereToStartReading;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 发送大量数据
bool __fastcall TTAPIComm::WriteLargeData (const char* buffer, DWORD wantedToWrite)
{
if( bConnected == false || hCommFile == INVALID_HANDLE_VALUE )
return false;
OVERLAPPED OverlappedWrite;
OverlappedWrite.Internal =0;
OverlappedWrite.InternalHigh =0;
OverlappedWrite.Offset =0;
OverlappedWrite.OffsetHigh =0;
OverlappedWrite.hEvent = eventOverlappedWrite;
DWORD dwNumberOfBytesWritten = 0;
DWORD dwWhereToStartWriting = 0; // Start at the beginning.
// Keep looping until all characters have been written.
do
{
// Start the overlapped I/O.
if( !WriteFile(hCommFile, (buffer+dwWhereToStartWriting),
wantedToWrite, &dwNumberOfBytesWritten, &OverlappedWrite) )
{
// WriteFile failed. Expected; lets handle it.
DWORD dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if( dwLastError == ERROR_INVALID_HANDLE )
{
// Likely that the Service Provider has closed the port.
COMSTAT ComStat;
DWORD dwErrors = 0;
ClearCommError (hCommFile, &dwErrors, &ComStat);
throw Exception(String("COM Error: ") + ClearCommErrorToStr(dwErrors));
}
// Unexpected error. No idea what.
if( dwLastError != ERROR_IO_PENDING )
throw Exception("Error to writing to com port.");
// This is the expected ERROR_IO_PENDING case.
// Wait for overlapped I/O completion,
DWORD dwHandleSignaled = WaitForSingleObject(eventOverlappedWrite, Timeout*1000);
switch( dwHandleSignaled )
{
case WAIT_OBJECT_0: // Wait finished.
{ // Time to get the results of the WriteFile
break;
}
case WAIT_TIMEOUT: // Wait failed.
{
// CancelIO (hCommFile);
PurgeComm (hCommFile, PURGE_TXABORT+PURGE_RXABORT);
throw Exception("Timeout during write operation.");
}
default:// This case should never occur.
throw Exception("Unexpected Wait return value ");
}
if( !GetOverlappedResult(hCommFile, &OverlappedWrite,
&dwNumberOfBytesWritten, true) )
{
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port.
if( dwLastError == ERROR_INVALID_HANDLE )
// Likely that the Service Provider has closed the port.
throw Exception("Connection has been broken during write.");
// No idea what could cause another error.
throw Exception("Error writing to com port while waiting");
}
}
// Some data was written. Make sure it all got written.
wantedToWrite = wantedToWrite - dwNumberOfBytesWritten;
dwWhereToStartWriting = dwWhereToStartWriting + dwNumberOfBytesWritten;
}
while( wantedToWrite >= 0); // Write the whole thing!
// Wrote the whole AnsiString.
return true;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 取端口接收缓冲区尺寸
int __fastcall TTAPIComm::cbInQue()
{
int Result = 0;
if( bConnected )
{
COMSTAT ComStat;
ComStat.cbInQue = 0;
DWORD dwErrorFlags = 0;
ClearCommError (hCommFile, &dwErrorFlags, &ComStat);
Result = ComStat.cbInQue;
if( Result > 1000 )
throw Exception(String("It seems that ClearCommError __fastcall failed.") +
"/x0d" + "Or you try to get more than 1000 kB.");
}
return Result;
}
//---------------------------------------------------------------------------
// 设置通讯接收等待时间间隔
void __fastcall TTAPIComm::SetTimeout(DWORD Value)
{
COMMTIMEOUTS commtimeouts;
if( Value != FTimeout )
{
GetCommTimeouts(hCommFile, &commtimeouts);
// The CommTimeout numbers will very likely change if( you are
// coding to meet some kind of specif(ication where
// you need to reply within a certain amount of time after
// recieving the last byte. However, if( 1/4th of a second
// goes by between recieving two characters, its a good
// indication that the transmitting end has finished, even
// assuming a 1200 baud modem.
commtimeouts.ReadIntervalTimeout = 0xFFFFFFFF;
commtimeouts.ReadTotalTimeoutMultiplier = 0xFFFFFFFF;
commtimeouts.ReadTotalTimeoutConstant = Value;
commtimeouts.WriteTotalTimeoutMultiplier = 0;
commtimeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(hCommFile, &commtimeouts);
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TTAPIComm::ResumeWaitingNewData()
{
if( bConnected )//&& (Thread = NULL) )
{
bStopWaitingNewData = false;
// PostMessage (formDialing.handle, CM_NEWDATATHREAD, 0, 0);
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 发布工作状态
void __fastcall TTAPIComm::IssueInfo( AnsiString info )
{
// 关闭状态下不可发布
if( ComponentState.Contains( csDestroying ) == true )
return;
try
{
if( Assigned(thisTAPIComm->InfoLabel) )
thisTAPIComm->InfoLabel->Text = info;
if( Assigned(thisTAPIComm->LogStrings) )
thisTAPIComm->LogStrings->Add( info );
}
catch(...)
{
}
}
//---------------------------------------------------------------------------
/*
void __fastcall TformDialing::bHangUpClick(TObject* Sender);
{
try
{
thisTAPIComm->Drop();
}
catch(...)
{
}
// formDialing.Hide();
}
//---------------------------------------------------------------------------
void __fastcall TformDialing.CMNewData (var Message: TMessage);
{
Thread = TNewData.Create (false);
Thread.FreeOnTerminate = true;
}
//---------------------------------------------------------------------------
void __fastcall TformDialing.CMNewDataArrives (var Message: TMessage);
{
if( ! thisTAPIComm->bStopWaitingNewData )
if( Assigned (thisTAPIComm->OnNewData) ) thisTAPIComm->OnNewData (this);
}
*/
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// TNewData
void __fastcall TNewData::Execute()
{
if( bWaitingInProcess )
return;
DWORD dwEvent = 0;
HANDLE eventOverlappedWait = CreateEvent (NULL, true, true, NULL);
OVERLAPPED OverlappedWait;
OverlappedWait.Internal =0;
OverlappedWait.InternalHigh =0;
OverlappedWait.Offset =0;
OverlappedWait.OffsetHigh =0;
OverlappedWait.hEvent = eventOverlappedWait;
ResetEvent (eventOverlappedWait);
while(thisTAPIComm->bConnected &&
thisTAPIComm->hCommFile != INVALID_HANDLE_VALUE &&
!thisTAPIComm->bStopWaitingNewData )
{
// Keep looping until EV_RXCHAR arrives...
Application->ProcessMessages();
// Start the overlapped I/O.
if( !WaitCommEvent(thisTAPIComm->hCommFile, &dwEvent, &OverlappedWait) )
{
// Wait for overlapped I/O completion,
DWORD dwHandleSignaled = WaitForSingleObject (eventOverlappedWait, 1000);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0: // Wait finished.
{
// Time to get the results of the WaitCommEvent
// lfLog.WriteLog ("WaitForSingleObject == true", "New data");
//-- PostMessage(formDialing.handle, CM_NEWDATAARRIVES, 0, 0);
dwEvent = 0;
break;
}
case WAIT_TIMEOUT: // Wait failed.
{
break;
}
}
DWORD dwNumberOfBytesWritten;
if( GetOverlappedResult(thisTAPIComm->hCommFile, &OverlappedWait,
&dwNumberOfBytesWritten, false) )
{
DWORD dwLastError = GetLastError();
if( dwLastError != ERROR_IO_INCOMPLETE )
{
// Its possible for this error to occur if( the
// service provider has closed the port.
if( dwLastError == ERROR_INVALID_HANDLE )
return;
// Likely that the Service Provider has closed the port.
//throw Exception.Create ("Connection has been broken waiting for COM port event.");
// No idea what could cause another error.
return;
// throw Exception.Create ("Error waiting for COM port event");
}
}
else
{
// lfLog.WriteLog ("GetOverlappedResult == true", "New data");
//--PostMessage (formDialing.handle, CM_NEWDATAARRIVES, 0, 0);
}
// for some strange reason EV_RXCHAR arrives two times.
// That is why I have to dispatch it one time at least.
}
else
{
//--PostMessage(formDialing.handle, CM_NEWDATAARRIVES, 0, 0);
// lfLog.WriteLog ("WaitCommEvent == true", "New data");
}
}
CloseHandle(eventOverlappedWait);
// Thread = NULL;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// TLogFile }
__fastcall TLogFile::TLogFile(Classes::TComponent* AOwner)
: inherited(AOwner)
{
slLogFile = new TStringList;
slLogFile->Clear();
}
//---------------------------------------------------------------------------
__fastcall TLogFile::~TLogFile()
{
delete slLogFile;
}
//---------------------------------------------------------------------------
void __fastcall TLogFile::WriteLog(AnsiString tag, AnsiString responce)
{
if( responce != "" )
slLogFile->Add(DateTimeToStr(Now()) + " - "+ tag + ": " + responce);
else
slLogFile->Add(DateTimeToStr(Now()) + " - "+ tag);
}
//---------------------------------------------------------------------------
void __fastcall TLogFile::SaveToFile(AnsiString sfile)
{
slLogFile->SaveToFile(sfile);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// 检查TAPI出错信息
void __fastcall TapiCheck(int ResultCode)
{
if( ResultCode >= 0 )
return;
AnsiString strError;
// OSVERSIONINFO osver;
switch( ResultCode)
{
case LINEERR_ALLOCATED:
strError = "TAPI Line: LINEERR_ALLOCATED";
break;
case LINEERR_BADDEVICEID:
strError = "TAPI Line: LINEERR_BADDEVICEID";
break;
case LINEERR_BEARERMODEUNAVAIL:
strError = "TAPI Line: LINEERR_BEARERMODEUNAVAIL";
break;
case LINEERR_CALLUNAVAIL:
strError = "TAPI Line: LINEERR_CALLUNAVAIL";
break;
case LINEERR_COMPLETIONOVERRUN:
strError = "TAPI Line: LINEERR_COMPLETIONOVERRUN";
break;
case LINEERR_CONFERENCEFULL:
strError = "TAPI Line: LINEERR_CONFERENCEFULL";
break;
case LINEERR_DIALBILLING:
strError = "TAPI Line: LINEERR_DIALBILLING";
break;
case LINEERR_DIALDIALTONE:
strError = "TAPI Line: LINEERR_DIALDIALTONE";
break;
case LINEERR_DIALPROMPT:
strError = "TAPI Line: LINEERR_DIALPROMPT";
break;
case LINEERR_DIALQUIET:
strError = "TAPI Line: LINEERR_DIALQUIET";
break;
case LINEERR_INCOMPATIBLEAPIVERSION:
strError = "TAPI Line: LINEERR_INCOMPATIBLEAPIVERSION";
break;
case LINEERR_INCOMPATIBLEEXTVERSION:
strError = "TAPI Line: LINEERR_INCOMPATIBLEEXTVERSION";
break;
case LINEERR_INIFILECORRUPT:
strError = "TAPI Line: LINEERR_INCOMPATIBLEEXTVERSION";
break;
case LINEERR_INUSE:
strError = "TAPI Line: LINEERR_INUSE";
break;
case LINEERR_INVALADDRESS:
strError = "TAPI Line: LINEERR_INVALADDRESS";
break;
case LINEERR_INVALADDRESSID:
strError = "TAPI Line: LINEERR_INVALADDRESSID";
break;
case LINEERR_INVALADDRESSMODE:
strError = "TAPI Line: LINEERR_INVALADDRESSMODE";
break;
case LINEERR_INVALADDRESSSTATE:
strError = "TAPI Line: LINEERR_INVALADDRESSSTATE";
break;
case LINEERR_INVALAPPHANDLE:
strError = "TAPI Line: LINEERR_INVALAPPHANDLE";
break;
case LINEERR_INVALAPPNAME:
strError = "TAPI Line: LINEERR_INVALAPPNAME";
break;
case LINEERR_INVALBEARERMODE:
strError = "TAPI Line: LINEERR_INVALBEARERMODE";
break;
case LINEERR_INVALCALLCOMPLMODE:
strError = "TAPI Line: LINEERR_INVALCALLCOMPLMODE";
break;
case LINEERR_INVALCALLHANDLE:
strError = "TAPI Line: LINEERR_INVALCALLHANDLE";
break;
case LINEERR_INVALCALLPARAMS:
strError = "TAPI Line: LINEERR_INVALCALLPARAMS";
break;
case LINEERR_INVALCALLPRIVILEGE:
strError = "TAPI Line: LINEERR_INVALCALLPRIVILEGE";
break;
case LINEERR_INVALCALLSELECT:
strError = "TAPI Line: LINEERR_INVALCALLSELECT";
break;
case LINEERR_INVALCALLSTATE:
strError = "TAPI Line: LINEERR_INVALCALLSTATE";
break;
case LINEERR_INVALCALLSTATELIST:
strError = "TAPI Line: LINEERR_INVALCALLSTATELIST";
break;
case LINEERR_INVALCARD:
strError = "TAPI Line: LINEERR_INVALCARD";
break;
case LINEERR_INVALCOMPLETIONID:
strError = "TAPI Line: LINEERR_INVALCOMPLETIONID";
break;
case LINEERR_INVALCONFCALLHANDLE:
strError = "TAPI Line: LINEERR_INVALCOMPLETIONID";
break;
case LINEERR_INVALCONSULTCALLHANDLE:
strError = "TAPI Line: LINEERR_INVALCONSULTCALLHANDLE";
break;
case LINEERR_INVALCOUNTRYCODE:
strError = "TAPI Line: LINEERR_INVALCOUNTRYCODE";
break;
case LINEERR_INVALDEVICECLASS:
strError = "TAPI Line: LINEERR_INVALDEVICECLASS";
break;
case LINEERR_INVALDEVICEHANDLE:
strError = "TAPI Line: LINEERR_INVALDEVICEHANDLE";
break;
case LINEERR_INVALDIALPARAMS:
strError = "TAPI Line: LINEERR_INVALDIALPARAMS";
break;
case LINEERR_INVALDIGITLIST:
strError = "TAPI Line: LINEERR_INVALDIGITLIST";
break;
case LINEERR_INVALDIGITMODE:
strError = "TAPI Line: LINEERR_INVALDIGITMODE";
break;
case LINEERR_INVALDIGITS:
strError = "TAPI Line: LINEERR_INVALDIGITS";
break;
case LINEERR_INVALEXTVERSION:
strError = "TAPI Line: LINEERR_INVALEXTVERSION";
break;
case LINEERR_INVALGROUPID:
strError = "TAPI Line: LINEERR_INVALGROUPID";
break;
case LINEERR_INVALLINEHANDLE:
strError = "TAPI Line: LINEERR_INVALLINEHANDLE";
break;
case LINEERR_INVALLINESTATE:
strError = "TAPI Line: LINEERR_INVALLINESTATE";
break;
case LINEERR_INVALLOCATION:
strError = "TAPI Line: LINEERR_INVALLOCATION";
break;
case LINEERR_INVALMEDIALIST:
strError = "TAPI Line: LINEERR_INVALMEDIALIST";
break;
case LINEERR_INVALMEDIAMODE:
strError = "TAPI Line: LINEERR_INVALMEDIAMODE";
break;
case LINEERR_INVALMESSAGEID:
strError = "TAPI Line: LINEERR_INVALMESSAGEID";
break;
case LINEERR_INVALPARAM:
strError = "TAPI Line: LINEERR_INVALPARAM";
break;
case LINEERR_INVALPARKID:
strError = "TAPI Line: LINEERR_INVALPARKID";
break;
case LINEERR_INVALPARKMODE:
strError = "TAPI Line: LINEERR_INVALPARKMODE";
break;
case LINEERR_INVALPOINTER:
strError = "TAPI Line: LINEERR_INVALPOINTER";
break;
case LINEERR_INVALPRIVSELECT:
strError = "TAPI Line: LINEERR_INVALPRIVSELECT";
break;
case LINEERR_INVALRATE:
strError = "TAPI Line: LINEERR_INVALRATE";
break;
case LINEERR_INVALREQUESTMODE:
strError = "TAPI Line: LINEERR_INVALREQUESTMODE";
break;
case LINEERR_INVALTERMINALID:
strError = "TAPI Line: LINEERR_INVALREQUESTMODE";
break;
case LINEERR_INVALTERMINALMODE:
strError = "TAPI Line: LINEERR_INVALTERMINALMODE";
break;
case LINEERR_INVALTIMEOUT:
strError = "TAPI Line: LINEERR_INVALTIMEOUT";
break;
case LINEERR_INVALTONE:
strError = "TAPI Line: LINEERR_INVALTONE";
break;
case LINEERR_INVALTONELIST:
strError = "TAPI Line: LINEERR_INVALTONELIST";
break;
case LINEERR_INVALTONEMODE:
strError = "TAPI Line: LINEERR_INVALTONEMODE";
break;
case LINEERR_INVALTRANSFERMODE:
strError = "TAPI Line: LINEERR_INVALTRANSFERMODE";
break;
case LINEERR_LINEMAPPERFAILED:
strError = "TAPI Line: LINEERR_LINEMAPPERFAILED";
break;
case LINEERR_NOCONFERENCE:
strError = "TAPI Line: LINEERR_NOCONFERENCE";
break;
case LINEERR_NODEVICE:
strError = "TAPI Line: LINEERR_NODEVICE";
break;
case LINEERR_NODRIVER:
strError = "TAPI Line: LINEERR_NODRIVER";
break;
case LINEERR_NOMEM:
strError = "TAPI Line: LINEERR_NOMEM";
break;
case LINEERR_NOREQUEST:
strError = "TAPI Line: LINEERR_NOREQUEST";
break;
case LINEERR_NOTOWNER:
strError = "TAPI Line: LINEERR_NOTOWNER";
break;
case LINEERR_NOTREGISTERED:
strError = "TAPI Line: LINEERR_NOTREGISTERED";
break;
case LINEERR_OPERATIONFAILED:
strError = "TAPI Line: LINEERR_OPERATIONFAILED";
break;
case LINEERR_OPERATIONUNAVAIL:
strError = "TAPI Line: LINEERR_OPERATIONUNAVAIL";
break;
case LINEERR_RATEUNAVAIL:
strError = "TAPI Line: LINEERR_RATEUNAVAIL";
break;
case LINEERR_RESOURCEUNAVAIL:
strError = "TAPI Line: LINEERR_RESOURCEUNAVAIL";
break;
case LINEERR_REQUESTOVERRUN:
strError = "TAPI Line: LINEERR_REQUESTOVERRUN";
break;
case LINEERR_STRUCTURETOOSMALL:
strError = "TAPI Line: LINEERR_STRUCTURETOOSMALL";
break;
case LINEERR_TARGETNOTFOUND:
strError = "TAPI Line: LINEERR_TARGETNOTFOUND";
break;
case LINEERR_TARGETSELF:
strError = "TAPI Line: LINEERR_TARGETSELF";
break;
case LINEERR_UNINITIALIZED:
strError = "TAPI Line: LINEERR_UNINITIALIZED";
break;
case LINEERR_USERUSERINFOTOOBIG:
strError = "TAPI Line: LINEERR_USERUSERINFOTOOBIG";
break;
case LINEERR_REINIT:
strError = "TAPI Line: LINEERR_REINIT";
break;
case LINEERR_ADDRESSBLOCKED:
strError = "TAPI Line: LINEERR_ADDRESSBLOCKED";
break;
case LINEERR_BILLINGREJECTED:
strError = "TAPI Line: LINEERR_BILLINGREJECTED";
break;
case LINEERR_INVALFEATURE:
strError = "TAPI Line: LINEERR_INVALFEATURE";
break;
case LINEERR_NOMULTIPLEINSTANCE:
strError = "TAPI Line: LINEERR_NOMULTIPLEINSTANCE";
break;
#ifdef Tapi_Ver20
case LINEERR_INVALAGENTID:
strError = "TAPI Line: LINEERR_INVALAGENTID";
break;
case LINEERR_INVALAGENTGROUP:
strError = "TAPI Line: LINEERR_INVALAGENTGROUP";
break;
case LINEERR_INVALPASSWORD:
strError = "TAPI Line: LINEERR_INVALPASSWORD";
break;
case LINEERR_INVALAGENTSTATE:
strError = "TAPI Line: LINEERR_INVALAGENTSTATE";
break;
case LINEERR_INVALAGENTACTIVITY:
strError = "TAPI Line: LINEERR_INVALAGENTACTIVITY";
break;
case LINEERR_DIALVOICEDETECT:
strError = "TAPI Line: LINEERR_DIALVOICEDETECT";
break;
#endif
default:
strError = "Unknown Error - " + IntToStr(ResultCode);
break;
}
throw Exception(strError);
}
//---------------------------------------------------------------------------
使用:
1.枚举可用线路:
lbLines->Items->Clear();
if( FTAPIComm->InitializeTAPI() == true )
FTAPIComm->FillLine( lbLines->Items );
2.线路信息
FTAPIComm->DevIDToInitialize = lbLines->ItemIndex;
FTAPIComm->ConfigDialog();
TAPI用"Line"标识MODEM等通讯设备。