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

📄 tapix.cpp

📁 串口调试助手的源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Written by JHCC, 1997

#include "stdafx.h"

#include "tapix.h"
#include "TAPIErr.h"

#include "comm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// ---- CTAPIConnection ----
IMPLEMENT_SERIAL(CTAPIConnection, CObject, 0 /* schema number*/ )
BOOL	CTAPIConnection::m_bInitializing = FALSE;
BOOL	CTAPIConnection::m_bShuttingDown = FALSE;

CTypedPtrArray<class CObArray,class CTAPILine*>	CTAPIConnection::m_lineArray;
HLINEAPP	CTAPIConnection::m_hLineApp = 0;
CWnd*	CTAPIConnection::m_pNotifyWnd = NULL;
DWORD	CTAPIConnection::m_dwCallState = 0;

DWORD	CTAPIConnection::m_dwAPILowVersion = 0x00010003;
DWORD	CTAPIConnection::m_dwAPIHighVersion = 0x00010004;

DWORD	CTAPIConnection::m_dwAnswerCallWait = (DWORD)-1;
//DWORD	CTAPIConnection::m_dwMakeCallWait = (DWORD)-1;
BOOL	CTAPIConnection::m_bCallStateReceived = FALSE;

DWORD	CTAPIConnection::m_dwCommBaseCommandID = 0;
BYTE*	CTAPIConnection::m_pReadBuf = NULL;
int	CTAPIConnection::m_nReadBufLen = 0;

CTAPIConnection::CTAPIConnection()
{
}

CTAPIConnection::~CTAPIConnection()
{
	ShutdownTAPI();
}

// Initializes TAPI
BOOL	CTAPIConnection::Create(CWnd*  pNotifyWnd,
	DWORD  dwAPILowVersion, DWORD  dwAPIHighVersion,
	DWORD  dwCommBaseCommandID,
	BYTE*  pReadBuf, int  nReadBufLen)
{
	// If we're already initialized, then initialization succeeds.
	if (m_hLineApp != 0)
	{
		TRACE0("Already initialized !\n");
		return  TRUE;
	}

	// If we're in the middle of initializing, then fail, we're not done.
	// because a message loop in function, may be repeat call this function
	if (m_bInitializing)
	{
		TRACE0("In the middle of initializing !\n");
		return  FALSE;
	}
	m_bInitializing = TRUE;

	// Initialize TAPI
	BOOL	bFirstTryReInit = TRUE;
	DWORD	dwNumDevs;
	long	lReturn;
	do
	{
		// Initialize TAPI
		lReturn = ::lineInitialize(&m_hLineApp,
			::AfxGetInstanceHandle(),
			CTAPIConnection::LineCallbackFunc,
			::AfxGetAppName(),
			&dwNumDevs);

		switch (lReturn)
		{
		// If we get this error, its because some other app has yet
		// to respond to the REINIT message. Wait 5 seconds and try
		// again.  If it still doesn't respond, tell the user.
		case  LINEERR_REINIT:
			if (bFirstTryReInit)
			{
				CTime	startTime = CTime::GetCurrentTime();
				CTimeSpan	elapsedTime;
				do
				{
					MSG	msg;
					if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
					{
						::TranslateMessage(&msg);
						::DispatchMessage(&msg);
					}

					CTime	endTime = CTime::GetCurrentTime();
					elapsedTime = endTime - startTime;
				}
				while (elapsedTime.GetTotalSeconds() < 5);
				bFirstTryReInit = FALSE;
			}
			else
			{
				::MessageBox(NULL,
					"A change to the system configuration requires that "
					"all Telephony applications relinquish their use of "
					"Telephony before any can progress.  "
					"Some have not yet done so.", "Warning", MB_OK);
				m_bInitializing = FALSE;
				return  FALSE;
			}
			break;

		case  LINEERR_NODEVICE:
			if (!CTAPIError::HandleNoDevicesInstalled())
			{
				TRACE0("No devices installed.\n");
				m_bInitializing = FALSE;
				return  FALSE;
			}
			break;

		default:
			if (!CTAPIError::HandleLineErr(lReturn))
			{
				TRACE0("lineInitialize unhandled error\n");
				m_bInitializing = FALSE;
				return  FALSE;
			}
		}

		// If there are no line devices installed on the machine, lets give
		// the user the opportunity to install one.
		if (lReturn == TAPISUCCESS && dwNumDevs < 1)
		{
			TRACE0("There are no telephony devices installed.");
			if (!CTAPIError::HandleNoDevicesInstalled())
			{
				m_bInitializing = FALSE;
				return  FALSE;
			}
		}
	}
	while (lReturn != TAPISUCCESS);

//	pNotifyWnd->AssertValid();
	m_pNotifyWnd = pNotifyWnd;

	m_dwAPILowVersion = dwAPILowVersion;
	m_dwAPIHighVersion = dwAPIHighVersion;

//	m_lineArray.SetSize(dwNumDevs);
	// because some line maybe fail, such as INCOMPATIBLEAPIVERSION,
	// the GetNumDevs() may not equals to dwNumDevs
	for (DWORD  i = 0; i < dwNumDevs; ++ i)
	{
		SetNewLine(i);
	}

	m_dwCommBaseCommandID = dwCommBaseCommandID;
	m_pReadBuf = pReadBuf;
	m_nReadBufLen = nReadBufLen;

	TRACE0("Tapi initialized.\n");
	m_bInitializing = FALSE;

	return  TRUE;
}

// Shuts down all use of TAPI
// If ShutdownTAPI fails, then its likely either a problem
// with the service provider (and might require a system
// reboot to correct) or the application ran out of memory.
BOOL CTAPIConnection::ShutdownTAPI()
{
	long	lReturn;

	// If we aren't initialized, then Shutdown is unnecessary.
	if (m_hLineApp == NULL)
		return  TRUE;

	// Prevent ShutdownTAPI re-entrancy problems.
	// because HangupCall have a message loop
	if (m_bShuttingDown)
		return  TRUE;

	m_bShuttingDown = TRUE;
	for (int  i = 0; i < GetNumDevs(); ++ i)
		m_lineArray[i]->HangupCall();
    
	do
	{
		lReturn = ::lineShutdown(m_hLineApp);
		if (CTAPIError::HandleLineErr(lReturn))
			continue;
		else
		{
			TRACE0("lineShutdown unhandled error\n");
			break;
		}
	}
	while (lReturn != TAPISUCCESS);

	for (int  n = 0; n < m_lineArray.GetSize(); ++ n)
	{
		delete  m_lineArray[n];
	}
	m_lineArray.RemoveAll();

	m_hLineApp = NULL;
	TRACE0("TAPI uninitialized.\n");
	m_bShuttingDown = FALSE;

	return  TRUE;
}

// Wait for the line to reach a specific CallState.
// This function allows us to synchronously wait for a line
// to reach a specific LINESTATE or until the line is shut down.
//
// Note that this could cause re-entrancy problems as
// well as mess with any message preprocessing that might
// occur on this thread (such as TranslateAccelerator).
//
// One more note.  This function can potentially be re-entered
// if the call is dropped for any reason while waiting.  If this
// happens, just drop out and assume the wait has been canceled.
// This is signaled by setting bReentered to FALSE when the function 
// is entered and TRUE when it is left.  If bReentered is ever TRUE 
// during the function, then the function was re-entered.
//
// This function should to be called from the thread that did
// lineInitialize, or the PeekMessage is on the wrong thread
// and the synchronization is not guaranteed to work.  Also note
// that if another PeekMessage loop is entered while waiting,
// this could also cause synchronization problems.
//
// If the constant value I_LINECALLSTATE_ANY is used for the 
// dwDesiredCallState, then WaitForCallState will return SUCCESS
// upon receiving any CALLSTATE messages.
long	CTAPIConnection::WaitForCallState(DWORD  dwDesiredCallState)
{
	static BOOL	bReentered = FALSE;
	DWORD	dwTimeStarted = GetTickCount();

	m_bCallStateReceived = FALSE;

	while ((dwDesiredCallState == I_LINECALLSTATE_ANY) || 
		(m_dwCallState != dwDesiredCallState))
	{
		MSG	msg;
		if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}

		// If we are waiting for any call state and get one, succeed.
		if ((dwDesiredCallState == I_LINECALLSTATE_ANY) && 
			m_bCallStateReceived)
		{
			break;
		}

		// This should only occur if the line is shut down while waiting.
		if (/*!m_bTapiInUse || */bReentered)
		{
			bReentered = TRUE;
			TRACE0("WAITABORTED\n");
			return  WAITERR_WAITABORTED;
		}

		// If we don't get the reply in a reasonable time, we time out.
		if (GetTickCount() - dwTimeStarted > WAITTIMEOUT)
		{
			bReentered = TRUE;
			TRACE0("WAITTIMEDOUT\n");
			return  WAITERR_WAITTIMEDOUT;
		}
	}
	bReentered = TRUE;
	return  TAPISUCCESS;
}

//**************************************************
// LineCallback Function and Handlers.
//**************************************************

// Receive asynchronous TAPI events
//	dwDevice - Device associated with the event, if any
//	dwMsg - TAPI event that occurred.
//	dwCallbackInstance - User defined data supplied when opening the line.
//	dwParam1 - dwMsg specific information
//	dwParam2 - dwMsg specific information
//	dwParam3 - dwMsg specific information

// This is the function where all asynchronous events will come.
// Almost all events will be specific to an open line, but a few
// will be general TAPI events (such as LINE_REINIT).
//
// Its important to note that this callback will *ALWAYS* be
// called in the context of the thread that does the lineInitialize.
// Even if another thread (such as the COMM threads) calls the API
// that would result in the callback being called, it will be called
// in the context of the main thread (since in this sample, the main
// thread does the lineInitialize).
void CALLBACK	CTAPIConnection::LineCallbackFunc(DWORD  dwDevice,
	DWORD  dwMsg, DWORD  dwCallbackInstance,
	DWORD  dwParam1, DWORD  dwParam2, DWORD  dwParam3)
{
	CTAPIError::OutputDebugLineCallback(dwDevice, dwMsg,
		dwCallbackInstance, dwParam1, dwParam2, dwParam3);

    // All we do is dispatch the dwMsg to the correct handler.
	switch (dwMsg)
	{
	case LINE_CALLSTATE:
		DoLineCallState(dwDevice, dwMsg, dwCallbackInstance, dwParam1, dwParam2,
			dwParam3);
		break;

	case LINE_CLOSE:
		DoLineClose(dwDevice, dwMsg, dwCallbackInstance,
			dwParam1, dwParam2, dwParam3);
		break;

	case LINE_LINEDEVSTATE:
		DoLineDevState(dwDevice, dwMsg, dwCallbackInstance,
			dwParam1, dwParam2, dwParam3);
		break;

	case LINE_REPLY:
		DoLineReply(dwDevice, dwMsg, dwCallbackInstance,
			dwParam1, dwParam2, dwParam3);
		break;

	case LINE_CREATE:
		DoLineCreate(dwDevice, dwMsg, dwCallbackInstance,
			dwParam1, dwParam2, dwParam3);
		break;

	// other messages that can be processed
	case  LINE_ADDRESSSTATE:
		break;

	case  LINE_CALLINFO:
		break;

	case  LINE_DEVSPECIFIC:
		break;

	case  LINE_DEVSPECIFICFEATURE:
		break;

	case  LINE_GATHERDIGITS:
		break;

	case  LINE_GENERATE:
		break;

	case  LINE_MONITORDIGITS:
		break;

	case  LINE_MONITORMEDIA:
		break;

	case  LINE_MONITORTONE:
		break;

	default:
		TRACE0("LineCallbackFunc message ignored\n");
		break;
	}
}

// Handle LINE_REPLY asynchronous messages.
//	dwDevice - Line Handle associated with this LINE_REPLY.
//	dwMsg - Should always be LINE_REPLY.
//	dwCallbackInstance - Unused by this sample.
//	dwParam1 - Asynchronous request ID.
//	dwParam2 - success or LINEERR error value.
//	dwParam3 - Unused.

// All line API calls that return an asynchronous request ID
// will eventually cause a LINE_REPLY message. Handle it.
//
// This sample assumes only one call at time, and that we wait
// for a LINE_REPLY before making any other line API calls.
//
// The only exception to the above is that we might shut down
// the line before receiving a LINE_REPLY.
void	CTAPIConnection::DoLineReply(DWORD  dwDevice,
	DWORD  dwMessage, DWORD  dwCallbackInstance,
	DWORD  dwParam1, DWORD  dwParam2, DWORD  dwParam3)
{
	if (dwParam2 != TAPISUCCESS)
	{
		TRACE1("LINE_REPLY error: 0x%lx\n", (long)dwParam2);
		return;
	}
	TRACE0("LINE_REPLY: successfully replied.\n");

	int	nIndex = -1;
/*	if (m_dwMakeCallWait == (DWORD)-1)
	{*/
		nIndex = GetAsyncIDIndex(dwParam1);
		ASSERT(nIndex != -1);
/*	}
	else
	{
		nIndex = (int)m_dwMakeCallWait;
		ASSERT(m_lineArray[nIndex]->m_dwAsyncID == (DWORD)-1);
		m_lineArray[nIndex]->m_dwAsyncID == dwParam1;
		TRACE0("m_dwAsyncID = dwParam1\n");
	}*/

	switch (m_lineArray[nIndex]->m_WaitReplyType)
	{
	case CTAPILine::REPLY_NONE:
		break;

	// reply message for lineAnswer
	case CTAPILine::REPLY_ANSWERCALL:
		m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
		m_dwAnswerCallWait = (DWORD)-1;
		break;

	// reply message for lineMakeCall
	case CTAPILine::REPLY_MAKECALL:
		m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
//		m_dwMakeCallWait = (DWORD)-1;
		break;

	// reply message for lineDrop
	case CTAPILine::REPLY_DROPCALL:
		m_lineArray[nIndex]->m_WaitReplyType = CTAPILine::REPLY_NONE;
		break;
	}
}

// Handle LINE_CLOSE asynchronous messages.
//	dwDevice - Line Handle that was closed.
//	dwMsg - Should always be LINE_CLOSE.

⌨️ 快捷键说明

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