www.pudn.com > tapi3.zip > CALLINFO.CPP


// callinfo.cpp : implementation file for callinfo class 
// (c) Dialogic corp 1995, 1996 
 
#include "stdafx.h" 
#include  
#include "tapiapp.h" 
#include "tapiline.h" 
#include "tapicall.h" 
#include "talker32.h" 
#include "talkdlg.h" 
#include "callinfo.h" 
#include "lineinfo.h" 
#include "helpid.h" 
#include "tonedlg.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char BASED_CODE THIS_FILE[] = __FILE__; 
#endif 
 
#define CALLINFO_TIMER_ID	1 
#define WAVE_TIMER_ID		2 
 
UINT uiMsg; 
///////////////////////////////////////////////////////////////////////////// 
// CCallInfo property page 
 
IMPLEMENT_DYNCREATE(CCallInfo, CPropertyPage) 
 
CCallInfo::CCallInfo() : CPropertyPage(CCallInfo::IDD) 
{ 
	//{{AFX_DATA_INIT(CCallInfo) 
	m_csCallInfo = _T(""); 
	m_csCallState = _T(""); 
	m_csCallAction = _T(""); 
	m_csGathered = _T(""); 
	m_csLastDigit = _T(""); 
	m_csGatherRes = _T(""); 
	//}}AFX_DATA_INIT 
	m_pWaveName = NULL; 
	m_nRecTime = 0; 
	m_uiMsg = RegisterWindowMessage("TALKER32 callinfo alert"); 
	uiMsg = m_uiMsg; 
	SetHelpID(HIDD_TALKER32_DialogCallInfo); 
} 
 
CCallInfo::~CCallInfo() 
{ 
} 
 
void CCallInfo::DoDataExchange(CDataExchange* pDX) 
{ 
	CPropertyPage::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CCallInfo) 
	DDX_Control(pDX, IDC_CALLALERT, m_btnCallAlert); 
	DDX_Control(pDX, IDC_VOLUME, m_ctlVolume); 
	DDX_Control(pDX, IDC_STOP, m_btnStop); 
	DDX_Control(pDX, IDC_PAUSE, m_btnPause); 
	DDX_Control(pDX, IDC_GATHER, m_btnGather); 
	DDX_Control(pDX, IDC_MONITOR, m_btnMonitor); 
	DDX_Control(pDX, IDC_RECORD, m_btnRecord); 
	DDX_Control(pDX, IDC_PLAY, m_btnPlay); 
	DDX_Text(pDX, IDC_CALLINFO, m_csCallInfo); 
	DDX_Text(pDX, IDC_STATE, m_csCallState); 
	DDX_Text(pDX, IDC_ACTIVITY, m_csCallAction); 
	DDX_Text(pDX, IDC_GATHERED, m_csGathered); 
	DDX_Text(pDX, IDC_LASTDIGIT, m_csLastDigit); 
	DDX_Text(pDX, IDC_GATHERRES, m_csGatherRes); 
	//}}AFX_DATA_MAP 
} 
 
 
BEGIN_MESSAGE_MAP(CCallInfo, CPropertyPage) 
	//{{AFX_MSG_MAP(CCallInfo) 
	ON_BN_CLICKED(IDC_PLAY, OnPlay) 
	ON_BN_CLICKED(IDC_RECORD, OnRecord) 
	ON_BN_CLICKED(IDC_REFRESH, OnRefresh) 
	ON_WM_CLOSE() 
	ON_WM_TIMER() 
	ON_BN_CLICKED(IDC_INFOBTN, OnInfobtn) 
	ON_BN_CLICKED(IDC_MONITOR, OnMonitor) 
	ON_WM_DESTROY() 
	ON_BN_CLICKED(IDC_CALLALERT, OnCallalert) 
	ON_BN_CLICKED(IDC_GATHER, OnGather) 
	ON_BN_CLICKED(IDC_PAUSE, OnPause) 
	ON_BN_CLICKED(IDC_STOP, OnStop) 
	ON_WM_HSCROLL() 
	ON_REGISTERED_MESSAGE(uiMsg, OnDynamicAlert) 
	ON_BN_CLICKED(IDC_GENTONE, OnGentone) 
	ON_WM_SETFOCUS() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
void CCallInfo::DisplayCallInfo(BOOL bUpdateCallInfo) 
{ 
	if(m_pCall == NULL) return; 
	if(NULL == m_pLine->ctlGetActiveCall()) 	// call no longer active 
	{ 
		if(m_pCall) { 
			m_pCall->m_hStatusWnd = NULL;	 
			m_pCall->m_hCallAlertWnd = NULL;	 
			m_pCall->m_uiAlertMsg = NULL;	 
		   } 
		m_pCall = NULL; 
		::PostMessage(::GetParent(m_hWnd), WM_CLOSE, 0, NULL); 
		KillTimer(CALLINFO_TIMER_ID); 
		return; 
	} 
		// display status 
	WORD wState = m_pCall->GetCallState(); 
	WORD wDir = m_pCall->GetCallDirection(); 
	CString csTemp; 
 
	m_csCallState = "State ="; 
	switch(wState) 
	{ 
	case IDLE: 
		csTemp = "idle"; 
		break; 
	case MAKING: 
		csTemp = "making";			 
		break; 
	case STOP_MAKING: 
		csTemp = "stop making"; 
		break;	 
	case PROGRESS:		 
		csTemp = "progress"; 
		break;	 
	case DIALING:			 
		csTemp = "dialing"; 
		break;	 
 	case OFFERING:		 
		csTemp = "offering"; 
		break;	 
 	case ANSWERING:		 
		csTemp = "answering"; 
		break;	 
 	case CONNECTED:		 
		csTemp = "connected"; 
		break;	 
	case HOLD:			 
		csTemp = "hold"; 
		break;	 
 	case DROPPING:		 
		csTemp = "dropping"; 
		break;	 
 	case DISCONNECTED: 	 
		csTemp = "disconnected"; 
		break;	 
	default: 
		csTemp = "undefined"; 
		break;	 
	} 
	m_csCallState += csTemp; 
	DWORD dwWaveStatus = m_pCall->GetWaveStatus(); 
	DWORD dwPRStatus; 
	switch(dwWaveStatus) 
	{ 
		case WAVE_IDLE: 
			csTemp = "Idle"; 
			m_btnPause.SetWindowText("Pause"); 
			m_btnStop.EnableWindow(FALSE); 
			KillTimer(WAVE_TIMER_ID); 
			m_nRecTime = 0; 
			break; 
		case PREPARING_TO_PLAY: 
		case PLAYING: 
		case FINISHING_PLAY: 
			csTemp = "Playing"; 
			m_btnPause.SetWindowText("Pause"); 
			m_btnStop.EnableWindow(); 
			break; 
		case PAUSED: 
			csTemp = "Paused"; 
			m_btnPause.SetWindowText("Resume"); 
			break; 
		case PREPARING_TO_RECORD:	 
		case RECORDING:		 	 
		case FINISHING_RECORD: 
			csTemp.Format("Recording, %d seconds left", m_nRecTime); 
			m_btnStop.EnableWindow(); 
			break; 
		case WAVE_DISFUNCTIONAL: 
			csTemp = "Wave disabled"; 
			m_btnStop.EnableWindow(FALSE); 
		//	m_nRecTime = 0; 
		// check the dev specific play/record status 
			dwPRStatus = m_pCall->GetRecPlayStatus(); 
			switch(dwPRStatus)	// all possible cases for dev specific play/record 
			{ 
				case WAVE_IDLE: 
					KillTimer(WAVE_TIMER_ID); 
					m_nRecTime = 0; 
				break; 
				case PREPARING_TO_RECORD: 
				case RECORDING: 
					csTemp.Format("Recording, %d seconds left", m_nRecTime); 
					m_btnStop.EnableWindow(); 
				break; 
				case PREPARING_TO_PLAY: 
				case PLAYING: 
				case FINISHING_PLAY: 
					csTemp = "Playing"; 
					m_btnStop.EnableWindow(); 
				break; 
				case FAILED_START: 
					csTemp = "Wave disabled"; 
					m_pLine->ctlUpdateDevSpecStatus(DEVSPEC_IDLE); 
					MessageBox("WAVE function failed to start", NULL, MB_ICONSTOP); 
					m_btnStop.EnableWindow(FALSE); 
				break; 
				case WAVE_FAILED: 
					csTemp = "Wave disabled"; 
					m_pLine->ctlUpdateDevSpecStatus(DEVSPEC_IDLE); 
					MessageBox("WAVE function failed to complete", NULL, MB_ICONSTOP); 
					m_btnStop.EnableWindow(FALSE); 
				break;	 
			} 
			break; 
		default: 
			csTemp = "Not available"; 
			m_btnStop.EnableWindow(FALSE); 
			m_nRecTime = 0; 
			break; 
	} 	//end-switch 
 
	m_csCallAction = "Action:"; 
	m_csCallAction += csTemp; 
	if(wState != CONNECTED) 
		m_btnStop.EnableWindow(FALSE); 
	// Determine if WAVE play/record are available thru TAPI extensions 
	// Make it available if: local system, wave driver not installed OR remote system 
	if(dwWaveStatus == WAVE_DISFUNCTIONAL && m_bRunningOnNT) 
	{ 
		m_btnPlay.SetWindowText("PlayX"); 
		m_btnRecord.SetWindowText("RecordX"); 
		m_btnPlay.EnableWindow(wState == CONNECTED); 
		m_btnRecord.EnableWindow(wState == CONNECTED); 
	} 
	else 
	{ 
		m_btnPlay.EnableWindow(wState == CONNECTED && dwWaveStatus == WAVE_IDLE); 
		m_btnRecord.EnableWindow(wState == CONNECTED && dwWaveStatus == WAVE_IDLE); 
	} 
	m_btnPause.EnableWindow(dwWaveStatus==PREPARING_TO_PLAY || dwWaveStatus==PLAYING ||	// dwWaveStatus==WAVE_IDLE || 
						dwWaveStatus== PAUSED); //PREPARING_TO_RECORD || dwWaveStatus==RECORDING); 
 
	UpdateData(FALSE); 
	if(!bUpdateCallInfo) return; 
 
	//UpdateDigitsMonitorStatus();	// do not read gathered 
	m_csCallInfo.Empty(); 
	LPLINECALLSTATUS lpLCI = ((CTalkApp *)AfxGetApp())->GetCallStatus(m_pCall->m_hCall); 
	if(lpLCI == NULL) return;	// failed for some reason 
 
	char szState[48]; 
	if(!((CTalkApp *)AfxGetApp())->Code2CallState(lpLCI->dwCallState, szState, 46)) 
	csTemp.Format("state = %lx\r\nstatemode = %lx\r\nprivilege = %lx\r\nfeatures = %lx\r\n", 
			lpLCI->dwCallState, lpLCI->dwCallStateMode, lpLCI->dwCallPrivilege,lpLCI->dwCallFeatures); 
	else 
	csTemp.Format("state = %s\r\nstatemode = %lx\r\nprivilege = %lx\r\nfeatures = %lx\r\n", 
			szState, lpLCI->dwCallStateMode, lpLCI->dwCallPrivilege,lpLCI->dwCallFeatures); 
	m_csCallInfo += csTemp; 
	m_btnMonitor.EnableWindow(lpLCI->dwCallState == LINECALLSTATE_CONNECTED || lpLCI->dwCallState == LINECALLSTATE_DIALTONE); 
	m_btnGather.EnableWindow(lpLCI->dwCallState == LINECALLSTATE_CONNECTED); 
	UpdateData(FALSE); 
	delete (PBYTE) lpLCI; 	 
} 
 
void CCallInfo::UpdateDigitsMonitorStatus(BOOL bReadGathered, UINT wParam, LONG lParam) 
{ 
	MONITORSTATE msMonState ={0, 0, 0L, 0L, 0}; 
	BOOL bUpdateMon = FALSE; 
 
	// Check/update monitor & gather state here 
	if(lParam)		// this is always != 0 for the parametrized alert 
	{ 
		if(wParam)	// Monitor result 
		{ 
			msMonState.wState |= MONITOR_DIGITS; 
			msMonState.wLastDigit = (WORD) wParam; 
			bUpdateMon = TRUE; 
		}	 	 	 
		else 		// gather result 
		{ 
			msMonState.dwGatherResult = lParam; 
			msMonState.wState &= ~START_GATHER; 
		} 
	} 
	else if(!wParam) 	// non-parametrized alert 
	{ 
		m_pCall->GetMonitorState(&msMonState); 
		bUpdateMon = TRUE; 
	} 
	if(bUpdateMon) 
	{ 
		if(msMonState.wState & MONITOR_DIGITS)		 
		{ 
			m_btnMonitor.SetWindowText("Stop Monitor");	 
			m_csLastDigit.Format("%c", LOBYTE(msMonState.wLastDigit)); 
		} 
		else  
			m_btnMonitor.SetWindowText("Monitor Digits");	 
	} 
	if(msMonState.wState & START_GATHER)  	// gathering in progress 
		m_btnGather.SetWindowText("Stop Gather");	 
	else if(bReadGathered && msMonState.dwGatherResult)	// read result if available 
	{ 
		if(msMonState.dwGatherResult != LINEGATHERTERM_CANCEL) 
		{ 
			m_pCall->m_szDigits[20] = 0;	 
			m_csGathered = m_pCall->m_szDigits; 
			int i; 
			for(i=0; im_szDigits); i++) 
			{ 
				if(m_pCall->m_szDigits[i] != '*' && m_pCall->m_szDigits[i] != '#' 
				 && !isdigit(m_pCall->m_szDigits[i])) 
				 { 
				 	m_csGathered.Empty(); 
					break; 
				 } 
			} 
		} 
		m_csGatherRes.Format("%d",msMonState.dwGatherResult); 
		m_pCall->UpdateMonitorState(RESET_GATHER_RESULT, 0L, 0L);  
		m_btnGather.SetWindowText("Gather Digits"); 
	} 
	UpdateData(FALSE);		//from data to controls 
}			 
 
///////////////////////////////////////////////////////////////////////////// 
// CCallInfo message handlers 
 
BOOL CCallInfo::OnInitDialog()  
{ 
	CPropertyPage::OnInitDialog(); 
	 
	SetHelpID(HIDD_TALKER32_DialogCallInfo); 
	if(!m_csCaption.IsEmpty()) SetWindowText(m_csCaption); 
	m_ctlVolume.SetRange(0, MAX_REL_VOLUME); 
	if(m_pCall) 
		m_ctlVolume.SetPos((int) ((MAX_REL_VOLUME * (int) (m_pCall->GetWaveVolume()))/MAX_ABS_VOLUME)); 
	else 
		m_ctlVolume.SetPos(MAX_REL_VOLUME); 
	SetTimer(CALLINFO_TIMER_ID, 2000, NULL); 
	DisplayCallInfo(TRUE);	 
	UpdateDigitsMonitorStatus(TRUE, 0, 0);	// get monitoring & gathering result from the status structure	 
	if(m_pCall)  
	{ 
		m_pCall->m_hStatusWnd = m_hWnd;	// register self to the pCall 
		m_pCall->m_hCallAlertWnd = m_btnCallAlert.GetSafeHwnd();	// register self to the pCall 
		m_pCall->m_dwCallAlert = IDC_CALLALERT; 
		m_pCall->m_uiAlertMsg = m_uiMsg; 
	} 
 	return TRUE;  // return TRUE unless you set the focus to a control 
	              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
void CCallInfo::OnPlay()  
{ 
	long lrc; 
	if(m_pWaveName == NULL || m_pWaveName->IsEmpty())  
	{ 
		AfxMessageBox("No file to play"); 
		return; 
	}	 
	if(m_pCall)  
	{ 
		SetTimer(WAVE_TIMER_ID, 500, NULL); 
		if(WAVE_DISFUNCTIONAL ==  m_pCall->GetWaveStatus()) 	// use devspecific 
		{ 
			lrc = m_pCall->PlayEx(m_pWaveName->GetBuffer(128)); 
			if(lrc < 0)  
				AfxMessageBox("Failed to start playing"); 
		} 
		else 
			m_pCall->Play(m_pWaveName->GetBuffer(128));	 
	} 
	DisplayCallInfo(); 
} 
 
void CCallInfo::OnRecord()  
{ 
	if(m_pCall) 
	{ 
		if(*m_pnWaveFormatID == 0 )	 
			m_nRecTime = *m_pdwRecFileSize/3000; 
		else if(*m_pnWaveFormatID == 1 )	 
			m_nRecTime = *m_pdwRecFileSize/4000; 
		else if(*m_pnWaveFormatID == 2	 || *m_pnWaveFormatID == 5 || *m_pnWaveFormatID == 8)	 
			m_nRecTime = *m_pdwRecFileSize/6000; 
		else if(*m_pnWaveFormatID == 3 || *m_pnWaveFormatID == 6 || *m_pnWaveFormatID == 9)	 
			m_nRecTime = *m_pdwRecFileSize/8000; 
		else 
			m_nRecTime = *m_pdwRecFileSize/11000; 
		SetTimer(WAVE_TIMER_ID, 1000, NULL); 
		if(WAVE_DISFUNCTIONAL ==  m_pCall->GetWaveStatus()) 	// use devspecific 
		{			 
			if(m_pWaveRecName->IsEmpty())  
				m_pWaveRecName->Format("%s","C:\\WINNT35\\SYSTEM32\\TESTREC.WAV"); 
			TRACE("Recording into %s\n", m_pWaveRecName->GetBuffer(120)); 
			m_pCall->RecordEx(m_pWaveRecName->GetBuffer(120), m_nRecTime, *m_pnWaveFormatID); 
		} 
		else 
			m_pCall->Record(*m_pnWaveFormatID, *m_pdwRecFileSize);	 
	} 
	DisplayCallInfo(); 
} 
 
void CCallInfo::OnRefresh()  
{ 
	DisplayCallInfo(TRUE);	// update=FALSE by default 
} 
 
void CCallInfo::OnClose()  
{ 
	KillTimer(CALLINFO_TIMER_ID);	 
	CPropertyPage::OnClose(); 
} 
 
void CCallInfo::OnTimer(UINT nIDEvent)  
{ 
	//if(nIDEvent == CALLINFO_TIMER_ID && !m_nRecTime) DisplayCallInfo(TRUE); 
	if(nIDEvent == WAVE_TIMER_ID)  
	{	 
		if(m_nRecTime >1) m_nRecTime -=1;  
		else m_nRecTime = 0; 
		DisplayCallInfo(); 
	} 
	CPropertyPage::OnTimer(nIDEvent); 
} 
 
// Get call info 
void CCallInfo::OnInfobtn()  
{ 
	CString csTemp; 
 
	m_csCallInfo.Empty(); 
	LPLINECALLINFO lpLCI = ((CTalkApp *)AfxGetApp())->GetCallInfo(m_pCall->m_hCall); 
	if(lpLCI == NULL) return;	// failed for some reason 
 
	csTemp.Format("hLine = %lx\r\ndwLineDeviceID = %d\r\ndwBearerMode = %lx\r\n", 
			lpLCI->hLine, lpLCI->dwLineDeviceID, lpLCI->dwBearerMode); 
	m_csCallInfo += csTemp; 
	csTemp.Format("dwMediaMode = %lx\r\ndwCallStates = %lx\r\ndwMonitorDigitModes = %lx\r\nCallerID flags = %lx\r\nCalledID flags = %lx\r\n", 
			lpLCI->dwMediaMode, lpLCI->dwCallStates, lpLCI->dwMonitorDigitModes,lpLCI->dwCallerIDFlags,lpLCI->dwCalledIDFlags); 
	m_csCallInfo += csTemp; 
 
    if (lpLCI->dwCallerIDFlags & LINECALLPARTYID_NAME && lpLCI->dwCallerIDNameSize) 
    { 
        	csTemp.Format("Caller name=%s\r\n",(LPSTR)(((LPSTR)(lpLCI))+lpLCI->dwCallerIDNameOffset)); 
			m_csCallInfo += csTemp; 
    }  
 
   	if (lpLCI->dwCallerIDFlags & LINECALLPARTYID_ADDRESS && lpLCI->dwCallerIDSize) 
    { 
        	csTemp.Format("Caller number=%s\r\n", (LPSTR)(((LPSTR)(lpLCI))+lpLCI->dwCallerIDOffset));       
			m_csCallInfo += csTemp; 
    }  
	UpdateData(FALSE); 
	delete (PBYTE) lpLCI; 	 
	 
} 
 
void CCallInfo::OnMonitor()  
{ 
	LONG lrc; 
	CString csTemp; 
	HCALL hCall; 
 
	if(m_pCall) hCall = m_pCall->m_hCall;	// protect this  
	m_btnMonitor.GetWindowText(csTemp); 
	if(!csTemp.CompareNoCase("Monitor Digits"))	// currently not monitoring 
	{ 
		lrc = m_pCall->MonitorDigits(LINEDIGITMODE_DTMF);	 
		if(!lrc) m_btnMonitor.SetWindowText("Stop Monitor");	 
	} 
	else 
	{ 
		lrc = m_pCall->MonitorDigits(0);	 
		m_btnMonitor.SetWindowText("Monitor Digits");	 
	} 
} 
 
void CCallInfo::OnDestroy()  
{ 
	CPropertyPage::OnDestroy(); 
	 
	if(m_pCall)  
	{ 
		m_pCall->m_hStatusWnd = NULL;	 
		m_pCall->m_hCallAlertWnd = NULL;	 
		m_pCall->m_dwCallAlert = NULL; 
		m_pCall->m_uiAlertMsg = m_uiMsg; 
	} 
} 
 
// Alert message w/o parameters  
void CCallInfo::OnCallalert()  
{ 
	UpdateDigitsMonitorStatus(TRUE);	// get monitoring & gathering result	 
} 
 
// Alert message w/parameters  
LONG CCallInfo::OnDynamicAlert(UINT wParam, LONG lParam) 
{ 
	if(!wParam) 	// gather result 
		UpdateDigitsMonitorStatus(TRUE, 0, lParam);	// get gathering result	 
	else  
		UpdateDigitsMonitorStatus(FALSE, wParam, lParam);	// get monitoring result	 
	return 0; 
} 
 
void CCallInfo::OnGather()  
{ 
	CString csTemp; 
	LONG lrc; 
	char szErr[48]; 
 
	if(m_pCall == NULL) return; 
	m_btnGather.GetWindowText(csTemp); 
 
	if(!csTemp.CompareNoCase("Gather Digits"))	// currently not gathering 
	{ 
		m_csGathered.Empty(); 
		m_csGatherRes.Empty(); 
		UpdateData(FALSE); 
		lrc = m_pCall->GatherDigits(20, "*#", 10000, 5000, NULL); 
		if(lrc) 
		{ 
			if(!((CTalkApp *)AfxGetApp())->Code2Error(lrc, szErr, 46)) 
				csTemp.Format("lineGatherDigits failed reason=%lx", lrc); 
			else 
				csTemp.Format("lineGatherDigits failed reason=%s", szErr); 
			AfxMessageBox(csTemp); 
		} 
		else m_btnGather.SetWindowText("Stop Gather");	 
	} 
	else   				// user said stop  
	{ 
		lrc = m_pCall->GatherDigits(0, "", 0, 0, NULL);	 
		if(lrc) 
		{ 
			if(!((CTalkApp *)AfxGetApp())->Code2Error(lrc, szErr, 46)) 
				csTemp.Format("attempt to cancel lineGatherDigits failed reason=%lx", lrc); 
			else 
				csTemp.Format("attempt to cancel lineGatherDigits failed reason=%s", szErr); 
			AfxMessageBox(csTemp); 
		} 
//		else m_btnGather.SetWindowText("Gather Digits"); // consider it done...	 
	} 
} 
 
void CCallInfo::OnPause()  
{ 
	if(!m_pCall) return; 
	DWORD dwWaveStatus = m_pCall->GetWaveStatus(); 
	if(dwWaveStatus == PLAYING)  
		m_pCall->Pause(); 
	else if(dwWaveStatus == PAUSED) 
		m_pCall->Resume(); 
	DisplayCallInfo(); 
} 
 
void CCallInfo::OnStop()  
{ 
	m_pCall->StopWave(); 
	DisplayCallInfo(); 
} 
 
void CCallInfo::OnSetFocus(CWnd* pOldWnd)  
{ 
	CPropertyPage::OnSetFocus(pOldWnd); 
	((CTalkApp *)AfxGetApp())->SetHelpId(HIDD_TALKER32_DialogCallInfo); 
} 
 
void CCallInfo::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)  
{ 
	int nP; 
	if(nSBCode == SB_THUMBPOSITION || nSBCode == SB_THUMBTRACK) nP = nPos; 
	else nP = m_ctlVolume.GetPos(); 
	if(m_pCall) m_pCall->SetWaveVolume((DWORD) ((MAX_ABS_VOLUME/MAX_REL_VOLUME) * nP));  
	CPropertyPage::OnHScroll(nSBCode, nPos, pScrollBar); 
} 
 
void CCallInfo::OnGentone()  
{ 
	// display tone selection dialog 
	CToneDlg dlg(this); 
	//LPLINEGENERATETONE lplgT = NULL; 
	dlg.m_bRunningOnNT = m_bRunningOnNT; 
	if(IDCANCEL == dlg.DoModal()) return; 
	if(dlg.m_bBeep)  
		lineGenerateTone(m_pCall->m_hCall, LINETONEMODE_BEEP, dlg.m_dwDur, 0, 0); 
	else 
	{	 
		LINEGENERATETONE lgt[2]; 
		DWORD dwNum = 1; 
		LONG lrc; 
 
//		lplgT = (LPLINEGENERATETONE)new char[200*sizeof(LINEGENERATETONE)]; 
//		if(!lplgT) return; 
		lgt[0].dwFrequency = dlg.m_dwF1; 
		lgt[0].dwVolume = dlg.m_dwA1; 
		lgt[0].dwCadenceOn = dlg.m_dwDur/2; 
		lgt[0].dwCadenceOff = dlg.m_dwDur/2; 
		if(dlg.m_dwF2) 
		{ 
			lgt[1].dwFrequency = dlg.m_dwF2; 
			lgt[1].dwVolume = dlg.m_dwA2; 
			lgt[1].dwCadenceOn = dlg.m_dwDur/2; 
			lgt[1].dwCadenceOff = dlg.m_dwDur/2; 
			dwNum++; 
		} 
		if(lrc = lineGenerateTone(m_pCall->m_hCall, LINETONEMODE_CUSTOM,  
				dlg.m_dwDur, dwNum, lgt)) 
		{ 
			CString csTemp; 
			csTemp.Format("lineGenerateTone failed rc=%lx", lrc); 
			AfxMessageBox(csTemp); 
		} 
//		if(lplgT) delete lplgT; 
	} 
} 
 
/*  
 #define SB_LINEUP           0 
#define SB_LINELEFT         0 
#define SB_LINEDOWN         1 
#define SB_LINERIGHT        1 
#define SB_PAGEUP           2 
#define SB_PAGELEFT         2 
#define SB_PAGEDOWN         3 
#define SB_PAGERIGHT        3 
#define SB_THUMBPOSITION    4 
#define SB_THUMBTRACK       5 
#define SB_TOP              6 
#define SB_LEFT             6 
#define SB_BOTTOM           7 
#define SB_RIGHT            7 
#define SB_ENDSCROLL        8 
*/