⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 directorynumber.cpp

📁 使用CT-C开发的一个CTI软电话系统,ActiveX形式的,仅供参考
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// DirectoryNumber.cpp : Implementation of CDirectoryNumber
#include "stdafx.h"
#include "resource.h"
#include "ctcv4.h"
#include "KVPair.h"
#include "KVList.h"
#include "CTIEvent.h"
#include "MichelleCTI.h"
#include "DirectoryNumber.h"
#include <ctc_rpc.h>
#include <math.h>

#include <list>
using namespace std;

#define TIME_WAIT_API	60*1000   // max time of waiting api reply to dn default handler
#define TIME_WAIT_MESSAGE  60*1000 // max time of waiting incoming event
#define MAX_STEP_COUNT		1  // the max search step in the state map
								// This number should >=1, and not be too big

DECLARE_CASTER(CKVList, IKVList)
extern void WriteLog(char* pData);
extern BOOL B2C(BSTR bStr,char* pStr,int nBufLen);
extern HWND h_gPumpWnd;  // The main window message process
extern HINSTANCE h_gInstance; // the dll instance handle

/////////////////////////////////////////////////////
// The telephone state convert table

//Convert to	Active		Deliver		Hold		Null/Initiate	Receive		Unknown		error
//Active		-1			-1			TpSuspended	TpDisconnected	-1			-1			-1
//Deliver		OpAnswered	-1			-1			TpDisconnected	-1			ctcK_Other	-1
//Hold			TpRetrieved	-1			-1			-1				-1			-1			-1
//Null/Initiate	-1			Destseized	-1			ctcK_Offhook	InboundCall	-1			-1
//Receive		TpAnswered	-1			-1			-1				-1			-1			-1
//Unknown		Any			Any			Any			Any				Any			Any			Any
//error			Any			Any			Any			Any				Any			Any			-1

/////////////MARK by rick --begin
//enum PHONE_STATE
//{
//	CTC_NULL=3,    // means this state's index in this table 
//	CTC_INITIAL=3,
//	CTC_ACTIVE=0,
//	CTC_DELIVER=1,
//	CTC_RECEIVE=4,
//	CTC_HOLD=2,
//	CTC_ERROR=5
//};

/////////////MARK --end

// The telephone sate convert table, -1 means no routine, other means a event which 
//		causing this transfor
static int phone_table[7][7]={{-1,-1,ctcK_TpSuspended,ctcK_TpDisconnected,-1,-1,-1},
							{ctcK_OpAnswered,-1,-1,ctcK_TpDisconnected,-1,ctcK_Other,-1},
							{ctcK_TpRetrieved,-1,-1,-1,-1,-1,-1},
							{-1,ctcK_DestSeized,-1,-1,ctcK_InboundCall,-1,-1},
							{ctcK_TpAnswered,-1,-1,-1,-1,-1,-1},
							{0,0,0,0,0,0,0},
							{0,0,0,0,0,-1}
							};

static BOOL CALLBACK DialingDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if(uMsg==WM_COMMAND) 
	{
		if(LOWORD(wParam)==IDCANCEL) 
		{
			while(!::PostMessage(NULL, UM_CANCELDIAL, (WPARAM)0, (LPARAM)0))
				Sleep(100);
		}
		return(TRUE);
	}
	return(FALSE);
}

UINT _stdcall CDirectoryNumber::MointorThread(void* p)
{
	CoInitialize(NULL);
	CDirectoryNumber* pDN=(CDirectoryNumber* )p;
	DWORD dwStatus=0;
	if (p)
	{
		while (pDN->m_bMonitorOn)
		{
			try
			{
				ctcEventData* pevent=new ctcEventData;
				if (pevent)
				{
					dwStatus=ctcGetEvent(pDN->m_channelId, pevent, 0);
					if (dwStatus!=ctcSuccess)
					{
						char temp[200];
						wsprintf(temp,"ctc getevent failed. error code: %d",dwStatus);
						WriteLog(temp);
					}else
					{//Get a dn event, process it.
						list<WPARAM> eventList;
						if (!pDN->DefaultHandler(pevent,&eventList))
						{//post event to pumpWindow
							for (int i=1;i<eventList.size();i++)
							{// post fake message, if it exsit
								list<WPARAM>::iterator item=eventList.begin();
								eventList.remove(*item);
								ctcEventData* fakeEvent=new ctcEventData;
								if (fakeEvent)
								{
									fakeEvent->event=*item;
									while (!PostMessage(h_gPumpWnd,UM_DNEVENT,(WPARAM)pDN,(LPARAM)fakeEvent))
										Sleep(100);
								}else
								{
									break;
								}
							}
							//Post this event
							while (!PostMessage(h_gPumpWnd,UM_DNEVENT,(WPARAM)pDN,(LPARAM)pevent))
								Sleep(100);
						}
					}
				}else
				{
					WriteLog("Allocate buffer for ctcEventData failed.");
				}
			}catch(...)
			{
				WriteLog("ctc getevent exception failed");
			}
		}
	}

	CoUninitialize();
	return 0;
}


PHONE_STATE CDirectoryNumber::GetPhoneState(UINT ctcState)
{
	//enum PHONE_STATE
//{
//	CTC_NULL=3,    // means this state's index in this table 
//	CTC_INITIAL=3,
//	CTC_ACTIVE=0,
//	CTC_DELIVER=1,
//	CTC_RECEIVE=4,
//	CTC_HOLD=2,
//	CTC_UNKNOWN=5,
//	CTC_ERROR=6
//}

	PHONE_STATE ctc;
	switch (ctcState)
	{
	case ctcK_ActiveState:
		ctc=CTC_ACTIVE;
		break;
	case ctcK_DeliverState:
		ctc=CTC_DELIVER;
		break;
	case ctcK_UnavailableState:
	case ctcK_FailState:
		ctc=CTC_ERROR;
		break;
	case ctcK_HoldState:
		ctc=CTC_HOLD;
		break;
	case ctcK_InitiateState:
	case ctcK_NullState:
		ctc=CTC_NULL;
		break;
	case ctcK_ReceiveState:
		ctc=CTC_RECEIVE;
		break;
	case ctcK_UnknownState:
		ctc=CTC_UNKNOWN;
	default:
		ctc=CTC_UNKNOWN;
		break;
	}
	return ctc;
}

BOOL CDirectoryNumber::SearchRoutine(PHONE_STATE start,PHONE_STATE end,list<UINT>* eventList,int* level)
{
	BOOL bRet=FALSE;
	if (++(*level)<=MAX_STEP_COUNT)
	{
		if (phone_table[start][end]>=0)
		{
			//find the path
			bRet=TRUE;
			eventList->push_front(phone_table[start][end]);
		}else
		{
			for (int i=0;i<=sqrt(sizeof(phone_table)/sizeof(int))-1;i++)
			{
				PHONE_STATE tempEnd=(PHONE_STATE)i;
				if (phone_table[start][tempEnd]>=0)
				{
					
					if (SearchRoutine(tempEnd,end,eventList,level))
					{
						eventList->push_front(phone_table[start][tempEnd]);
						bRet=TRUE;
						break;
					}
				}
			}
		}
	}
	(*level)--;
	return bRet;
}


BOOL CDirectoryNumber::ValidateStateRoutine(UINT startState,UINT endState,list<UINT>*routine)
{
	PHONE_STATE phone_start=GetPhoneState(startState);
	PHONE_STATE phone_end=GetPhoneState(endState);

	routine->clear();
	int step=0;
	
	return SearchRoutine(phone_start,phone_end,routine,&step);
}

BOOL CDirectoryNumber::Initialize(char* dn,ctcChanId chanelID, ADDRTYPES type, CMichelleCTI *pCTI)
{
	BOOL bRet=FALSE;

	memset(&m_curState,0,sizeof(m_curState));
	m_curState.state=ctcK_NullState;

	m_hNotifyApi=CreateEvent(NULL,FALSE,TRUE,NULL); //ini as signal
	m_hConfirm=CreateEvent(NULL,FALSE,FALSE,NULL); //ini as nonsingal

	if (m_hNotifyApi && m_hConfirm)
	{
		m_ActiveCallRef=0;
		m_HoldCallRef=0;
		m_bInvokingApi=FALSE;
		m_pCTI = pCTI;
		m_channelId=chanelID;
		m_type = type;
		m_bMonitorOn=TRUE; // The monitor thread can execute now
		int nLen=strlen(dn)>sizeof(m_ThisDN)?sizeof(m_ThisDN):strlen(dn);
		memcpy(m_ThisDN,dn,nLen);
		
		m_hMonitor=(HANDLE)_beginthreadex(NULL,0,CDirectoryNumber::MointorThread,
											this, 0, &m_idMonitor);
		bRet=(m_hMonitor!=NULL);
	}
	return bRet;
}

void CDirectoryNumber::Uninitialize()
{
	if (m_hMonitor)
	{
		m_bMonitorOn=FALSE;
		WaitForSingleObject(m_hMonitor, INFINITE);
		CloseHandle(m_hMonitor);
		m_hMonitor=NULL;
		m_idMonitor=0;
	}

	if (m_hNotifyApi)
	{
		CloseHandle(m_hNotifyApi);
		m_hNotifyApi=NULL;
	}
	if (m_hConfirm)
	{
		CloseHandle(m_hConfirm);
		m_hConfirm=NULL;
	}
	m_HoldCallRef=0;
	m_ActiveCallRef=0;
	m_bInvokingApi=FALSE;
	return;
}

void CDirectoryNumber::ClearApiInfo()
{
	m_lErrCode=0;
	m_ErrMsg="";
	return;
}

BOOL CDirectoryNumber::OnDialing()
{
	BOOL bRet=FALSE;
	m_bInvokingApi=TRUE;

	HWND hDlg = CreateDialog(h_gInstance, MAKEINTRESOURCE(IDD_DIALINGDLG), NULL, DialingDlgProc);
	ATLASSERT(hDlg);
	RECT rcDlg, rcDesk;
	GetWindowRect(GetDesktopWindow(), &rcDesk);
	GetWindowRect(hDlg, &rcDlg);
	int x = ((rcDesk.right - rcDesk.left) - (rcDlg.right - rcDlg.left)) / 2 + rcDesk.left;
	int y = ((rcDesk.bottom - rcDesk.top) - (rcDlg.bottom - rcDlg.top)) / 2 + rcDesk.top;
	if(m_bDisableDialing)
	{
		SetWindowPos(hDlg, HWND_TOPMOST, -400, -400, 0, 0, SWP_NOSIZE);
	}
	else
	{
		SetWindowPos(hDlg, HWND_TOPMOST, x, y, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
	}

	UINT lastState=m_curState.state; // record the last phone state
	list<PHONE_STATE> tempState; // the full state routine except the final state
	tempState.clear();
	tempState.push_back(CTC_NULL);
	tempState.push_back(CTC_INITIAL);
	tempState.push_back(CTC_DELIVER);
	DWORD result=0;
	while (TRUE)
	{
		// Process the message in this message queue
		MSG msg;
		while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if (!IsDialogMessage(hDlg,&msg))
			{
				if(msg.message==WM_PAINT || msg.message==WM_NCPAINT || msg.message==WM_ERASEBKGND) 
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			}else if (!msg.hwnd && msg.message == UM_CANCELDIAL)
			{
				if (m_HoldCallRef!=0)
					ReconnectCall();
				else
					ReleaseCall(NULL);
			}
		}
		
		//wait for message or fired event
		result=MsgWaitForMultipleObjects(1,&m_hNotifyApi,FALSE,TIME_WAIT_MESSAGE,QS_ALLEVENTS);
		if (result=WAIT_TIMEOUT)
		{//time out
			break;
		}else
		{// the telephon may update to a new state 
			if (!InSet(m_curState.state,tempState))
			{// The current state has not belonged to this api's state routine
				break;
			}else
			{// update the current state as the last state
				lastState=m_curState.state;
				//notify the defaulthandler that this api has check the current state
				SetEvent(m_hConfirm);
			}
		}
	}//end while (true)

	if (result==WAIT_TIMEOUT)
	{
		m_lErrCode=CTC_TIMEOUT_ERR;
		m_ErrMsg="This api invoke is time out";
	}else
	{
		list<UINT> routine;
		if (ValidateStateRoutine(lastState,m_curState.state,&routine))
		{//ok,quit
			bRet=TRUE;
		}else
		{//This state transmission is invailed
			m_lErrCode=CTC_RELEASECALL_ERR;
			m_ErrMsg="Release call reached an invaild state";
		}
	}
	SetEvent(m_hConfirm);
	m_bInvokingApi=TRUE;
	return bRet;
}

BOOL CDirectoryNumber::GetAnsiFromBSTR(char** dest, BSTR source)
{
	BOOL ret=TRUE;
	int nLength=WideCharToMultiByte(CP_ACP,0,source,-1,NULL,0,NULL,NULL);
	if (nLength>0)
	{
		char* pTemp=new char[nLength];
		if (pTemp)
		{
			if (WideCharToMultiByte(CP_ACP,0,source,-1,pTemp,nLength,NULL,NULL))
			{
				*dest=new char[nLength*2];
				int nDestLen=0;
				if (*dest)
				{
					for (UINT i=0;i<strlen(pTemp);i++)
					{
						if (pTemp[i]=='/')
						{
							(*dest)[nDestLen]='/';
							nDestLen++;
						}
						(*dest)[nDestLen]=pTemp[i];
						nDestLen++;

					}
					(*dest)[nDestLen]='\0';
				}else
				{
					ret=FALSE;
				}
			}else
				ret=FALSE;
			delete pTemp;
			pTemp=NULL;
		}else
			ret=FALSE;
	}
	return ret;
}

BOOL CDirectoryNumber::GetAnsiFromInt(char** dest, int source)
{
	BOOL ret=TRUE;
	*dest=new char[sizeof(int)];
	if (*dest)	_itoa(source,*dest,16);
	else ret=FALSE;
	return ret;
}

BOOL CDirectoryNumber::KVListToAppString(IKVList* pkvlist, char* pAppString,UINT bufLen)
{
	//Transform character: "/"
	//	/k:  type : key
	//	/s:	type: string
	//	/i:	type: int
	//	/b:	type: binary
	//	/l:	type: binary length (/l23/l)
	//sample:  /kRick/sMyname/kName/i100
	BOOL bReturn=TRUE;

	if (pkvlist)
	{
		KVRESULTS res=pkvlist->InitScanLoop();
		if (KVR_Successful==res)
		{
			IKVPair* pkvpair=NULL;
			while (pkvpair=pkvlist->NextPair())
			{
				pkvpair->AddRef();

				BSTR key=NULL;
				char* pKey=NULL;
				if (SUCCEEDED(pkvpair->get_Key(&key)))
				{
					if (GetAnsiFromBSTR(&pKey,key))
					{
//						ValidateString(pKey,bufLen);
						if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
						{
							strcat(pAppString,"/k");
							strcat(pAppString,pKey);
							key=NULL;
							if (pKey) 
							{
								delete pKey;
								pKey=NULL;
							}
							KVTYPES type;
							if (SUCCEEDED(pkvpair->get_Type(&type)))
							{
								int nVal=0;
								switch (type)
								{
								case KVT_String:
									pkvpair->get_StringValue(&key);
									if (GetAnsiFromBSTR(&pKey,key))
									{
//										ValidateString(pKey,bufLen);
										if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
										{
											strcat(pAppString,"/s");
											strcat(pAppString,pKey);
										}else
											bReturn = FALSE;
									}else
									{
										bReturn = FALSE;
									}
									if (pKey)
									{
										delete pKey;
										pKey=NULL;
									}
									key=NULL;
									break;
								case KVT_Int:
									pkvpair->get_IntValue(&nVal);
									if (GetAnsiFromInt(&pKey,nVal))
									{
										if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
										{
											strcat(pAppString,"/i");
											strcat(pAppString,pKey);
										}else
											bReturn= FALSE;
									}else
										bReturn= FALSE;
									if (pKey)
									{
										delete pKey;
										pKey=NULL;
									}
									break;
								default:
									bReturn=FALSE;
								}
							}else//pkvpair->Type
							{
								bReturn =FALSE;
							}
						}else//LENGTH CHECK
						{
							bReturn =FALSE;
						}
					}else//GetAnsiFromBSTR
					{
						bReturn =FALSE;
					}
					if (pKey)
					{
						delete pKey;
						pKey=NULL;
					}
					key=NULL;
				}else//pkvpair->Key
				{
					bReturn = FALSE;
				}

				pkvpair->Release();
				pkvpair=NULL;
			}//while
		}else//KVR_Successful==res
		{
			bReturn= FALSE;
		}
	}//if (pkvlist)
	else
	{
		bReturn =TRUE;
	}
	if (!bReturn ) 
		ZeroMemory(pAppString, strlen(pAppString));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -