3.2 各功能模块的设计 3.2.1 TAPI的配置阶段 paper51.com TAPI 的置阶段配置阶段包括对线路的配置和对 MODEM 的配置,只有正确地配置并打开线路设备之后,才能对 MODEM 进行配置。以下函数完成对 TAPI 的配置: copyright paper51.com TAPI 类成员函数 telephonylnitialize 分配支持逻辑线路设备的使用所必须的某些内部资源,并返回应用程序一个TAPI句柄,同时传递了一个回调函数的地址作为参数,此函数处理对整个线路状态进行处理。然后使用TAPI的类成员函数lineNegotiateAPIVersion与Windows协商TAPI版本。TAPI类成员函数 mylineGetDevCaps 获得有关逻辑线路的性能的信息Windows把这些信息填充到一个名为 LINEDEVCAPS 的只读结构中,应用程序检查这个结构就可以了解哪些设置是驱动程序所允许的TAPI 类成员函数lineOpen打开线路。 内容来自www.paper51.com
3.2.2 TAPI的连接阶段 http://www.paper51.com TPAI在连接阶段MODEN会产生很多消息,消息的处理 TAPI由回调函数进行消息处理,回调函数在初始化TAPI时创建,消息的处理在TAPI的使用过程中是至关重要的。以下是一些主要的消息 内容来自www.paper51.com (1)LINECALLSTATE_IDLE 没有呼叫,为空,此时应断接,释放掉占用的资源; paper51.com
(2)LINECALLSTATE_DIALING 拨号中,正在拨号。 内容来自www.paper51.com (3)LINECALLSTATE_BUSY 线路忙或设备忙,此时应断接,释放掉占用的资源。 copyright paper51.com
(4)LINECALLSTATE_SPECIALINFO 特别的消息,此时应断接,释放掉占用的资源; http://www.paper51.com (5)LINECALLSTATE_OFFERING 应答方已收到呼叫方信号,此时应进行应答,调用lineAnswer函数; copyright paper51.com (6)LINECALLSTATE_CONNECTED 已连接成功,此时可进行数据的传输,但必须先得到MODEM的句柄 http://www.paper51.com (7)LINECALLSTATE_DISCONNECTED 已断接,此时应释放掉占用的资源。 内容来自www.paper51.com TAPI类成员函数MakeCall被用于发起呼叫,产生呼叫后依次进入图4状态: 内容来自www.paper51.com
内容来自论文无忧网 www.paper51.com
图4 状态流程图 paper51.com 新生成的呼叫处于IDLE状态,随后依次进入PROCEDING,OFFERING, CONNECTED和DISCONNECTED最后回到IDLE状态。这些状态都通过在调telephonylnitialize函数初始化TAPIDLL的时候传递的回调函数来处理。 paper51.com 3.2.3 数据传送阶段 内容来自论文无忧网 www.paper51.com TAPI并不提供数据传输的函数。因为 MODEM 通过控制计算机串口来进行通信,所以MODEM的数据通信与串口数据通信的方法一样,采用 ReadFile 和 writeFile函数来接收数据和发送数据。传送数据的时候要用到MODEM的句柄,此时调用TAPI的类成员函数lineGetID得到MODEN的句柄后就可以通过ReadFile和WriteFile函数来进行数据传输。ReadFile与WriteFile有两种模式,一种是等待模式,一种是非等待模式。等待模式下必须完成了所有读写操作函数才会返回,最后一个参数必须为NULL。非等待模式下要先定义一个OVERLAPPED变量,并且作为函数的最后一个参数传递进去。非等待模式下函数会马上返回,OVERLAPPED变量在初始化的时候会调CreateEvent函数产生一个事件,当函数返回后我们调用WaiForSingObject(Event)函数让线程阻塞,当数据传送完以后操作系统会给应用程序发出一消息,当应用程序得到此消息以后程序继续往下运行。 内容来自论文无忧网 www.paper51.com 一旦呼叫进入CONNECTED数据链路连通状态,则表明连接已经建立。此时我们就可以进行数据传输了,不过在传送数据之前我们要得到MODEN的句柄,此时调用TAPI的类成员函数lineGetID,此函数会把MODEN的名称和句柄保存到一个VARSTRING类型的变量里面。通过次句柄我们就可以利用WriteFile和ReadFile来读写数据了。 copyright paper51.com 3.2.4 关闭连接阶段 paper51.com 当我们数据传送完成后需要退出程序的时候。我们会对线路进行挂断操作,TAPI的类成员函数LineDrop来断开连接,然后调用LineClose来关闭一条打开的线路,同时释放前面阶段操作所用到的一些缓存以及复位一些信号型变量。 copyright paper51.com 4 编码实现4.1 程序主类的的定义 http://www.paper51.com 为了使程序的结构更为清晰和易于维护和升级,我把程序所要使用的数据结构封装成一个类。类的定义如下: paper51.com class CTapiLine http://www.paper51.com { copyright paper51.com
protected: http://www.paper51.com HLINEAPP m_hLineApp; //TPAIDLL的句柄 内容来自www.paper51.com HLINE m_hLine;//线路的句柄 内容来自论文无忧网 www.paper51.com HCALL m_hCall;//呼叫的句柄 copyright paper51.com int m_nDevID;//设备号 http://www.paper51.com HANDLE m_hLineEvent;// 线路改变事件 http://www.paper51.com DWORD m_dwLineMsg;//线路消息 paper51.com
bool m_bConnected;//是否连接 内容来自论文无忧网 www.paper51.com
HANDLE m_hEventFromThread;// http://www.paper51.com
HANDLE m_hLineMsgThread; // TAPI 事件监听线程 内容来自论文无忧网 www.paper51.com
bool m_bStopLineEventThread; paper51.com staticDWORD WINAPI LineEventThread(LPVOID lpVoid); 内容来自www.paper51.com long m_lEventThreadResult; http://www.paper51.com
public: copyright paper51.com
HANDLEGetHandle(const char *szClassType, long *lError); copyright paper51.com
intPickupIncomingCall(); paper51.com voidGetErrorString(int nError, char *&szErrText); 内容来自论文无忧网 www.paper51.com intMakeOutgoingCall(const char *szAddress); 内容来自www.paper51.com intGetIncomingCall(); http://www.paper51.com intClose(); 内容来自www.paper51.com intOpen(int nMode = 0); copyright paper51.com
CTapiLine(); http://www.paper51.com virtual~CTapiLine(); copyright paper51.com
}; 内容来自论文无忧网 www.paper51.com 类里面定义了整个程序运行所需要用到的变量。在进行线路操作时调用TAPI的类成员函数需要同时取得设备和线路的状态,所以我对TAPI的类成员函数进行了封装,使这些操作都模块化。 内容来自论文无忧网 www.paper51.com |