www.pudn.com > TAPISample.rar > TapiLine.cpp


// TapiLine.cpp: implementation of the CTapiLine class. 
// Author: T.Yogaramanan 
// Include this header if you use any part of the code from this file  
///////////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "TAPISample.h" 
#include "TapiLine.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CTapiLine::CTapiLine() 
{ 
	m_hEventFromThread = NULL; 
	m_hLineMsgThread = NULL;   // TAPI Event monitoring thread. 
	m_bStopLineEventThread = true;  
	m_lEventThreadResult = 0;  
	m_dwLineMsg= 0; 
	m_nDevID = 0; 
	m_hLineApp = NULL; 
	m_hLine = NULL; 
	m_hCall = NULL; 
	m_bConnected = false; 
 
} 
 
CTapiLine::~CTapiLine() 
{ 
	Close(); 
} 
 
// if nMode = 0 then it is data/fax calls 
//    nMode = 1 then it is data/fax/voice calls 
int CTapiLine::Open(int nMode) 
{ 
	LINEINITIALIZEEXPARAMS stInitParams; 
	LINEDEVCAPS *lpDevCaps =NULL; 
	LONG lRet; 
	 
	DWORD dwMediaMode; 
	DWORD dwNumDevs =0; 
	DWORD dwTAPIVer =TAPI_CURRENT_VERSION;; 
	DWORD dwTmpVer =0; 
	LINEEXTENSIONID stExtID; 
 
	if(!nMode) 
		dwMediaMode = LINEMEDIAMODE_DATAMODEM; // data/fax this should be 
	else 
		dwMediaMode = LINEMEDIAMODE_AUTOMATEDVOICE;// for voice this should be 
 
	memset(&stInitParams, 0, sizeof(LINEINITIALIZEEXPARAMS)); 
	// set the options... 
	stInitParams.dwTotalSize = sizeof(LINEINITIALIZEEXPARAMS); 
	stInitParams.dwOptions = LINEINITIALIZEEXOPTION_USEEVENT; 
	 
	// Initialize TAPI. 
	lRet = lineInitializeEx(&m_hLineApp, NULL, NULL, "CallAnswer", &dwNumDevs, &dwTAPIVer, &stInitParams); 
	if(lRet)  //error 
		return lRet; 
 
	// Got the event handle... 
	m_hLineEvent = stInitParams.Handles.hEvent; 
 
	m_nDevID = -1; 
	// go through the device list and select the appropriate device to transfer voice 
	for(int i=0; idwTotalSize = sizeof(LINEDEVCAPS)+1024; 
 
		lRet = lineGetDevCaps(m_hLineApp, i, dwTmpVer, 0, lpDevCaps); 
		 
		if(lRet)  //error 
		{ 
			free(lpDevCaps); 
			lpDevCaps=NULL; 
			continue; 
		} 
		 
		char *szText = ((char*)lpDevCaps) + lpDevCaps->dwLineNameOffset;// FOR DEBUGGING 
		// for more refer LINEMEDIAMODE_ Constants in MSDN 
 
		if(lpDevCaps->dwMediaModes & dwMediaMode)  
		{ 
			free(lpDevCaps); 
			m_nDevID = i; 
			break; 
		} 
		free(lpDevCaps); 
	} 
	if(m_nDevID < 0) 
		return LINEERR_BADDEVICEID; // no device available 
 
	// Open the line... 
	lRet = lineOpen(m_hLineApp, m_nDevID, &m_hLine, dwTAPIVer, 0x00000000, 1,LINECALLPRIVILEGE_OWNER,dwMediaMode,NULL); 
	if(lRet) 
	{ 
		lineShutdown(m_hLineApp); 
		return lRet; 
	} 
	 
	// We want to be notified for everything 
	lRet = lineSetStatusMessages(m_hLine, 0x1ffffff, 0); 
	if(lRet) 
	{	 
		lineShutdown(m_hLineApp); 
		return lRet;	 
	} 
	m_bStopLineEventThread = false; 
	m_hLineMsgThread = CreateThread(NULL,NULL,LineEventThread,this,NULL,0); 
	/// 在这个事件上建立信号 
	m_hEventFromThread = CreateEvent(NULL,0,0,NULL); 
	return 0; 
} 
 
int CTapiLine::Close() 
{ 
	LINECALLSTATUS stLineStatus; 
	LONG lRet; 
 
	if(m_hCall)  // Call might be in progress... 
	{ 
		memset(&stLineStatus, 0, sizeof(LINECALLSTATUS)); 
 
		lRet = lineGetCallStatus(m_hCall, &stLineStatus);  
			// Technically, lineGetCallStatus returns more info than  
			// there is in the structure.  Since we don't care about it, 
			// We just go on our merry way... 
		if(!lRet) // If it didn't fail, there's at least a call that needs to be droped. 
			lineDrop(m_hCall, NULL, 0); 
	} 
	m_hCall = NULL; 
 
	if(m_hLine) 
		lineClose(m_hLine); 
	m_hLine = NULL; 
 
	if(m_hLineMsgThread) 
	{ 
		m_bStopLineEventThread = true;  // stop the event waiting thread 
		WaitForSingleObject(m_hLineMsgThread, INFINITE); // Wait for it to comit suicide.. 
		CloseHandle(m_hLineMsgThread); 
		CloseHandle(m_hEventFromThread); 
	} 
	if(m_hLineApp)	 
		lineShutdown(m_hLineApp); 
	m_hLineApp = NULL; 
 
	m_hLineMsgThread = NULL; 
	m_hEventFromThread = NULL; 
	m_hLineMsgThread = NULL; 
 
	m_lEventThreadResult = 0;  
	m_dwLineMsg= 0; 
	m_nDevID = -1; 
	m_bConnected= false; 
	return 0; 
} 
 
 
int CTapiLine::GetIncomingCall() 
{ 
	long lRet; 
	 
	// set the ring b4 receiving the call 
	lRet = lineSetNumRings(m_hLine,0,5); 
	if(lRet) 
		return lRet; 
	 
	// Now we wait for notification. 
	switch(WaitForSingleObject(m_hEventFromThread, INFINITE)) 
	{ 
	case WAIT_OBJECT_0: 
		if(m_dwLineMsg == LINECALLSTATE_OFFERING) 
		{ 
			lRet = lineAnswer(m_hCall, NULL, 0); 
			lRet = (lRet>0)?0:lRet; 
 
			if(lRet) 
				Close(); 
			return lRet; 
		} 
		break; 
	case WAIT_TIMEOUT: 
		return ERROR_TIMEOUT; 
	}; 
	return 0xffffffff; // unknown error 
} 
 
int CTapiLine::PickupIncomingCall() 
{ 
	long lRet; 
 
	lRet = linePickup(m_hLine,0,&m_hCall,NULL,NULL); 
 
	return (lRet>=0)?0:lRet; 
} 
 
 
int CTapiLine::MakeOutgoingCall(const char *szAddress) 
{ 
	long lRet; 
 
	LPLINECALLPARAMS lpCallParams; 
 
	lpCallParams = (LPLINECALLPARAMS)malloc(sizeof(LINECALLPARAMS)+1024); 
	 
	memset(lpCallParams,0,sizeof(LINECALLPARAMS)+1024); 
 
	lpCallParams->dwTotalSize = sizeof(LINECALLPARAMS)+1024; 
 
	    // This is where we configure the line for DATAMODEM usage. 
    lpCallParams->dwBearerMode = LINEBEARERMODE_VOICE; 
    lpCallParams->dwMediaMode  = LINEMEDIAMODE_DATAMODEM; 
 
    // 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; 
    lpCallParams->dwAddressID = 0; 
 
    // Address we are dialing. 
    lpCallParams->dwDisplayableAddressOffset = sizeof(LINECALLPARAMS); 
    lpCallParams->dwDisplayableAddressSize = strlen(szAddress); 
    strcpy((LPSTR)lpCallParams+sizeof(LINECALLPARAMS), szAddress); 
	 
	lRet = lineMakeCall(m_hLine, &m_hCall, szAddress, 0, lpCallParams); 
 
	return (lRet>=0)?0:lRet; 
} 
 
//Author: Ramanan.T 
HANDLE CTapiLine::GetHandle(const char *szClassType, long *lError) 
{ 
	if(!m_bConnected) 
	{ 
		*lError = ERROR_DEVICE_NOT_CONNECTED; 
		return NULL; 
	} 
 
	VARSTRING *pvarStrDevID = (VARSTRING *)malloc(sizeof(VARSTRING)+255); 
 
	memset(pvarStrDevID,0,sizeof(VARSTRING)+255); 
	pvarStrDevID->dwTotalSize = sizeof(VARSTRING)+255; 
	 
	long lRet = lineGetID(m_hLine,0,m_hCall,LINECALLSELECT_LINE,pvarStrDevID,szClassType); 
	if(lRet) 
	{ 
		*lError = lRet; 
		return NULL; 
	} 
 
	*lError = 0; 
 
	return *((LPHANDLE)((char *)pvarStrDevID + pvarStrDevID->dwStringOffset)); 
} 
 
//Author: Ramanan.T 
/// 这里有事件处理函数 
DWORD WINAPI CTapiLine::LineEventThread(LPVOID lpVoid) 
{ 
	CTapiLine *pcTapiLine = (CTapiLine *)lpVoid; 
	long lRet; 
	LINEMESSAGE stLineMsg; 
	LINECALLINFO *lpCallInfo; 
 
	while(!pcTapiLine->m_bStopLineEventThread) 
	{ 
		// Get a TAPI event if available, wait for 10ms just enough to give up quontum 
		switch(WaitForSingleObject(pcTapiLine->m_hLineEvent, 10)) 
		{ 
		case WAIT_OBJECT_0: 
			//TAPI's got something 
			if ((lRet = lineGetMessage(pcTapiLine->m_hLineApp, &stLineMsg, 0)) != 0) 
			{ 
				pcTapiLine->m_lEventThreadResult = lRet; 
				return lRet; 
			} 
			// Process the retruned msg 
			switch (stLineMsg.dwMessageID) 
			{ 
			case LINE_REPLY: // Sent after lineMakeCall or lineDrop				 
				pcTapiLine->m_lEventThreadResult = (LONG)stLineMsg.dwParam2; 
				break; 
 
			case LINE_CALLSTATE:  // Sent after change of call state 
				switch (stLineMsg.dwParam1) 
				{ 
					case LINECALLSTATE_OFFERING:	//Incoming call is offering. 
						//  Get the call handle 
						pcTapiLine->m_hCall = (HCALL)stLineMsg.hDevice; 
						///  设置消息 
						pcTapiLine->m_dwLineMsg = LINECALLSTATE_OFFERING; 
						/// 设置事件 
						SetEvent(pcTapiLine->m_hEventFromThread); 
						break; 
 
					case LINECALLSTATE_IDLE: 
						lineDrop(pcTapiLine->m_hCall, NULL, 0); 
						pcTapiLine->m_hCall = NULL; 
						break; 
 
					case LINECALLSTATE_CONNECTED: 
						 
						if(stLineMsg.dwCallbackInstance == 1) 
						{ 
							pcTapiLine->m_dwLineMsg = LINECALLSTATE_CONNECTED; 
							SetEvent(pcTapiLine->m_hEventFromThread); 
							pcTapiLine->m_bConnected = true; 
						} 
 
						break; 
 
					case LINECALLSTATE_DISCONNECTED: 
						switch (stLineMsg.dwParam2)  
						{// currently these r not handled separately 
							case LINEDISCONNECTMODE_NORMAL: 
							case LINEDISCONNECTMODE_UNKNOWN: 
							case LINEDISCONNECTMODE_REJECT: 
							case LINEDISCONNECTMODE_PICKUP: 
							case LINEDISCONNECTMODE_FORWARDED: 
							case LINEDISCONNECTMODE_BUSY: 
							case LINEDISCONNECTMODE_NOANSWER: 
							case LINEDISCONNECTMODE_BADADDRESS: 
							case LINEDISCONNECTMODE_UNREACHABLE: 
							case LINEDISCONNECTMODE_CONGESTION: 
							case LINEDISCONNECTMODE_INCOMPATIBLE: 
							case LINEDISCONNECTMODE_UNAVAIL: 
							case LINEDISCONNECTMODE_NODIALTONE: 
							default: 
								// Got disconnected, so drop the call 
								lineDrop((HCALL)stLineMsg.hDevice, NULL, 0); 
								pcTapiLine->m_bConnected = false; 
								break; 
						}					 
						break; 
 
					default: 
						break; 
				} 
				break; 
 
			case LINE_CALLINFO: //  Call Info is available 
				if(stLineMsg.dwParam1 == LINECALLINFOSTATE_CALLID) 
				{  //Caller ID became available. 
					lpCallInfo = (LINECALLINFO *)malloc(sizeof(LINECALLINFO)+1000); 
					memset(lpCallInfo, 0, sizeof(LINECALLINFO)+1024); 
					lpCallInfo->dwTotalSize = sizeof(LINECALLINFO)+1024; 
					lineGetCallInfo(pcTapiLine->m_hCall, lpCallInfo); 
					if (lpCallInfo->dwTotalSize < lpCallInfo->dwNeededSize) 
					{ 
						lpCallInfo = (LINECALLINFO *)realloc(lpCallInfo, lpCallInfo->dwNeededSize); 
						lineGetCallInfo(pcTapiLine->m_hCall, lpCallInfo); 
					} 
				}  
				break; 
 
			default: 
				break; 
			}; 
			break; 
 
		case WAIT_TIMEOUT: 
			break;; 
			 
		default: 
			continue; 
		}; 
	} 
	return 0; 
} 
 
//Author: Ramanan.T 
void CTapiLine::GetErrorString(int nError, char *&szErrText) 
{ 
	szErrText = (char*)malloc(255); 
	switch(nError) 
	{ 
	case LINEERR_ALLOCATED: 
		strcpy(szErrText,"LINEERR_ALLOCATED"); 
		break; 
	case LINEERR_BADDEVICEID: 
		strcpy(szErrText,"LINEERR_BADDEVICEID"); 
		break; 
	case LINEERR_BEARERMODEUNAVAIL: 
		strcpy(szErrText,"LINEERR_BEARERMODEUNAVAIL"); 
		break; 
	case LINEERR_CALLUNAVAIL: 
		strcpy(szErrText,"LINEERR_CALLUNAVAIL"); 
		break; 
	case LINEERR_COMPLETIONOVERRUN: 
		strcpy(szErrText,"LINEERR_COMPLETIONOVERRUN"); 
		break; 
	case LINEERR_CONFERENCEFULL: 
		strcpy(szErrText,"LINEERR_CONFERENCEFULL"); 
		break; 
	case LINEERR_DIALBILLING: 
		strcpy(szErrText,"LINEERR_DIALBILLING"); 
		break; 
	case LINEERR_DIALDIALTONE: 
		strcpy(szErrText,"LINEERR_DIALDIALTONE"); 
		break; 
	case LINEERR_DIALPROMPT: 
		strcpy(szErrText,"LINEERR_DIALPROMPT"); 
		break; 
	case LINEERR_DIALQUIET: 
		strcpy(szErrText,"LINEERR_DIALQUIET"); 
		break; 
	case LINEERR_INCOMPATIBLEAPIVERSION: 
		strcpy(szErrText,"LINEERR_INCOMPATIBLEAPIVERSION"); 
		break; 
	case LINEERR_INCOMPATIBLEEXTVERSION: 
		strcpy(szErrText,"LINEERR_INCOMPATIBLEEXTVERSION"); 
		break;           
	case LINEERR_INIFILECORRUPT: 
		strcpy(szErrText,"LINEERR_INIFILECORRUPT"); 
		break;                   
	case LINEERR_INUSE: 
		strcpy(szErrText,"LINEERR_INUSE"); 
		break;                            
	case LINEERR_INVALADDRESS: 
		strcpy(szErrText,"LINEERR_INVALADDRESS"); 
		break;                     
	case LINEERR_INVALADDRESSID: 
		strcpy(szErrText,"LINEERR_INVALADDRESSID"); 
		break;                   
	case LINEERR_INVALADDRESSMODE: 
		strcpy(szErrText,"LINEERR_INVALADDRESSMODE"); 
		break;                 
	case LINEERR_INVALADDRESSSTATE: 
		strcpy(szErrText,"LINEERR_INVALADDRESSSTATE"); 
		break;                
	case LINEERR_INVALAPPHANDLE: 
		strcpy(szErrText,"LINEERR_INVALAPPHANDLE"); 
		break;                   
	case LINEERR_INVALAPPNAME: 
		strcpy(szErrText,"LINEERR_INVALAPPNAME"); 
		break;                     
	case LINEERR_INVALBEARERMODE: 
		strcpy(szErrText,"LINEERR_INVALBEARERMODE"); 
		break;                  
	case LINEERR_INVALCALLCOMPLMODE: 
		strcpy(szErrText,"LINEERR_INVALCALLCOMPLMODE"); 
		break;               
	case LINEERR_INVALCALLHANDLE: 
		strcpy(szErrText,"LINEERR_INVALCALLHANDLE"); 
		break;                  
	case LINEERR_INVALCALLPARAMS: 
		strcpy(szErrText,"LINEERR_INVALCALLPARAMS"); 
		break;                  
	case LINEERR_INVALCALLPRIVILEGE: 
		strcpy(szErrText,"LINEERR_INVALCALLPRIVILEGE"); 
		break;               
	case LINEERR_INVALCALLSELECT: 
		strcpy(szErrText,"LINEERR_INVALCALLSELECT"); 
		break;                  
	case LINEERR_INVALCALLSTATE: 
		strcpy(szErrText,"LINEERR_INVALCALLSTATE"); 
		break;                   
	case LINEERR_INVALCALLSTATELIST: 
		strcpy(szErrText,"LINEERR_INVALCALLSTATELIST"); 
		break;               
	case LINEERR_INVALCARD: 
		strcpy(szErrText,"LINEERR_INVALCARD"); 
		break;                        
	case LINEERR_INVALCOMPLETIONID: 
		strcpy(szErrText,"LINEERR_INVALCOMPLETIONID"); 
		break;                
	case LINEERR_INVALCONFCALLHANDLE: 
		strcpy(szErrText,"LINEERR_INVALCONFCALLHANDLE"); 
		break;              
	case LINEERR_INVALCONSULTCALLHANDLE: 
		strcpy(szErrText,"LINEERR_INVALCONSULTCALLHANDLE"); 
		break;           
	case LINEERR_INVALCOUNTRYCODE: 
		strcpy(szErrText,"LINEERR_INVALCOUNTRYCODE"); 
		break;                 
	case LINEERR_INVALDEVICECLASS: 
		strcpy(szErrText,"LINEERR_INVALDEVICECLASS"); 
		break;                 
	case LINEERR_INVALDEVICEHANDLE: 
		strcpy(szErrText,"LINEERR_INVALDEVICEHANDLE"); 
		break;                
	case LINEERR_INVALDIALPARAMS: 
		strcpy(szErrText,"LINEERR_INVALDIALPARAMS"); 
		break;                  
	case LINEERR_INVALDIGITLIST: 
		strcpy(szErrText,"LINEERR_INVALDIGITLIST"); 
		break;                   
	case LINEERR_INVALDIGITMODE: 
		strcpy(szErrText,"LINEERR_INVALDIGITMODE"); 
		break;                   
	case LINEERR_INVALDIGITS: 
		strcpy(szErrText,"LINEERR_INVALDIGITS"); 
		break;                     
	case LINEERR_INVALEXTVERSION: 
		strcpy(szErrText,"LINEERR_INVALEXTVERSION"); 
		break;                  
	case LINEERR_INVALGROUPID: 
		strcpy(szErrText,"LINEERR_INVALGROUPID"); 
		break;                     
	case LINEERR_INVALLINEHANDLE: 
		strcpy(szErrText,"LINEERR_INVALLINEHANDLE"); 
		break;                 
	case LINEERR_INVALLINESTATE: 
		strcpy(szErrText,"LINEERR_INVALLINESTATE"); 
		break;                   
	case LINEERR_INVALLOCATION: 
		strcpy(szErrText,"LINEERR_INVALLOCATION"); 
		break;                    
	case LINEERR_INVALMEDIALIST: 
		strcpy(szErrText,"LINEERR_INVALMEDIALIST"); 
		break;                   
	case LINEERR_INVALMEDIAMODE: 
		strcpy(szErrText,"LINEERR_INVALMEDIAMODE"); 
		break;                   
	case LINEERR_INVALMESSAGEID: 
		strcpy(szErrText,"LINEERR_INVALMESSAGEID"); 
		break;                   
	case LINEERR_INVALPARAM: 
		strcpy(szErrText,"LINEERR_INVALPARAM"); 
		break;                       
	case LINEERR_INVALPARKID: 
		strcpy(szErrText,"LINEERR_INVALPARKID"); 
		break;                      
	case LINEERR_INVALPARKMODE: 
		strcpy(szErrText,"LINEERR_INVALPARKMODE"); 
		break;                    
	case LINEERR_INVALPOINTER: 
		strcpy(szErrText,"LINEERR_INVALPOINTER"); 
		break;                     
	case LINEERR_INVALPRIVSELECT: 
		strcpy(szErrText,"LINEERR_INVALPRIVSELECT"); 
		break;                  
	case LINEERR_INVALRATE: 
		strcpy(szErrText,"LINEERR_INVALRATE"); 
		break;                        
	case LINEERR_INVALREQUESTMODE: 
		strcpy(szErrText,"LINEERR_INVALREQUESTMODE"); 
		break;                 
	case LINEERR_INVALTERMINALID: 
		strcpy(szErrText,"LINEERR_INVALTERMINALID"); 
		break;                  
	case LINEERR_INVALTERMINALMODE: 
		strcpy(szErrText,"LINEERR_INVALTERMINALMODE"); 
		break;                
	case LINEERR_INVALTIMEOUT: 
		strcpy(szErrText,"LINEERR_INVALTIMEOUT"); 
		break;                     
	case LINEERR_INVALTONE: 
		strcpy(szErrText,"LINEERR_INVALTONE"); 
		break;                        
	case LINEERR_INVALTONELIST: 
		strcpy(szErrText,"LINEERR_INVALTONELIST"); 
		break;                    
	case LINEERR_INVALTONEMODE: 
		strcpy(szErrText,"LINEERR_INVALTONEMODE"); 
		break;                    
	case LINEERR_INVALTRANSFERMODE: 
		strcpy(szErrText,"LINEERR_INVALTRANSFERMODE"); 
		break;                
	case LINEERR_LINEMAPPERFAILED: 
		strcpy(szErrText,"LINEERR_LINEMAPPERFAILED"); 
		break;                 
	case LINEERR_NOCONFERENCE: 
		strcpy(szErrText,"LINEERR_NOCONFERENCE"); 
		break;                     
	case LINEERR_NODEVICE: 
		strcpy(szErrText,"LINEERR_NODEVICE"); 
		break;                         
	case LINEERR_NODRIVER: 
		strcpy(szErrText,"LINEERR_NODRIVER"); 
		break;                         
	case LINEERR_NOMEM: 
		strcpy(szErrText,"LINEERR_NOMEM"); 
		break;                            
	case LINEERR_NOREQUEST: 
		strcpy(szErrText,"LINEERR_NOREQUEST"); 
		break;                        
	case LINEERR_NOTOWNER: 
		strcpy(szErrText,"LINEERR_NOTOWNER"); 
		break;                         
	case LINEERR_NOTREGISTERED: 
		strcpy(szErrText,"LINEERR_NOTREGISTERED"); 
		break;                    
	case LINEERR_OPERATIONFAILED: 
		strcpy(szErrText,"LINEERR_OPERATIONFAILED"); 
		break;                  
	case LINEERR_OPERATIONUNAVAIL: 
		strcpy(szErrText,"LINEERR_OPERATIONUNAVAIL"); 
		break;                 
	case LINEERR_RATEUNAVAIL: 
		strcpy(szErrText,"LINEERR_RATEUNAVAIL"); 
		break;                      
	case LINEERR_RESOURCEUNAVAIL: 
		strcpy(szErrText,"LINEERR_RESOURCEUNAVAIL"); 
		break;                  
	case LINEERR_REQUESTOVERRUN: 
		strcpy(szErrText,"LINEERR_REQUESTOVERRUN"); 
		break;                   
	case LINEERR_STRUCTURETOOSMALL: 
		strcpy(szErrText,"LINEERR_STRUCTURETOOSMALL"); 
		break;                
	case LINEERR_TARGETNOTFOUND: 
		strcpy(szErrText,"LINEERR_TARGETNOTFOUND"); 
		break;                   
	case LINEERR_TARGETSELF: 
		strcpy(szErrText,"LINEERR_TARGETSELF"); 
		break;                       
	case LINEERR_UNINITIALIZED: 
		strcpy(szErrText,"LINEERR_UNINITIALIZED"); 
		break;                    
	case LINEERR_USERUSERINFOTOOBIG: 
		strcpy(szErrText,"LINEERR_USERUSERINFOTOOBIG"); 
		break;            
	case LINEERR_REINIT: 
		strcpy(szErrText,"LINEERR_REINIT"); 
		break; 
	case LINEERR_ADDRESSBLOCKED: 
		strcpy(szErrText,"LINEERR_ADDRESSBLOCKED"); 
		break; 
	case LINEERR_BILLINGREJECTED: 
		strcpy(szErrText,"LINEERR_BILLINGREJECTED"); 
		break; 
	case LINEERR_INVALFEATURE: 
		strcpy(szErrText,"LINEERR_INVALFEATURE"); 
		break; 
	case LINEERR_NOMULTIPLEINSTANCE: 
		strcpy(szErrText,"LINEERR_NOMULTIPLEINSTANCE"); 
		break; 
	case LINEERR_INVALAGENTID: 
		strcpy(szErrText,"LINEERR_INVALAGENTID"); 
		break; 
	case LINEERR_INVALAGENTGROUP: 
		strcpy(szErrText,"LINEERR_INVALAGENTGROUP"); 
		break; 
	case LINEERR_INVALPASSWORD: 
		strcpy(szErrText,"LINEERR_INVALPASSWORD"); 
		break; 
	case LINEERR_INVALAGENTSTATE: 
		strcpy(szErrText,"LINEERR_INVALAGENTSTATE"); 
		break; 
	case LINEERR_INVALAGENTACTIVITY: 
		strcpy(szErrText,"LINEERR_INVALAGENTACTIVITY"); 
		break; 
	case LINEERR_DIALVOICEDETECT: 
		strcpy(szErrText,"LINEERR_DIALVOICEDETECT"); 
		break; 
	default: 
		free(szErrText); 
		FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,NULL,nError,0,(LPTSTR)&szErrText,0,NULL); 
	}; 
}