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

📄 tapiconn._cp

📁 串口调试助手的源代码
💻 _CP
📖 第 1 页 / 共 5 页
字号:
	return  0;
}

//
//  FUNCTION: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
//  PURPOSE: Writes a given string to the comm file handle.
//
//  PARAMETERS:
//    lpOverlappedWrite      - Overlapped structure to use in WriteFile
//    lpszStringToWrite      - String to write.
//    dwNumberOfBytesToWrite - Length of String to write.
//
//  RETURN VALUE:
//    TRUE if all bytes were written.  False if there was a failure to
//    write the whole string.
//
//  COMMENTS:
//
//    This function is a helper function for the Write Thread.  It
//    is this call that actually writes a string to the comm file.
//    Note that this call blocks and waits for the Write to complete
//    or for the CloseEvent object to signal that the thread should end.
//    Another possible reason for returning FALSE is if the comm port
//    is closed by the service provider.
//
//
BOOL	CTapiConnection::HandleWriteData(LPOVERLAPPED  lpOverlappedWrite,
	LPCSTR  lpszStringToWrite, DWORD  dwNumberOfBytesToWrite)
{
	DWORD	dwLastError;

	DWORD	dwNumberOfBytesWritten = 0;
	DWORD	dwWhereToStartWriting = 0; // Start at the beginning.

	HANDLE	HandlesToWaitFor[2];

	HandlesToWaitFor[0] = m_hCloseEvent;
	HandlesToWaitFor[1] = lpOverlappedWrite -> hEvent;

	// Keep looping until all characters have been written.
	do
	{
		// Start the overlapped I/O.
		if (!WriteFile(m_hCommFile, 
			&lpszStringToWrite[ dwWhereToStartWriting ], 
			dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
			lpOverlappedWrite))
		{
			// WriteFile failed.  Expected; lets handle it.
			dwLastError = GetLastError();

			// Its possible for this error to occur if the 
			// service provider has closed the port.  Time to end.
			if (dwLastError == ERROR_INVALID_HANDLE)
			{
				TRACE0("ERROR_INVALID_HANDLE, "
					"Likely that the Service Provider has closed the port.\n");
				return  FALSE;
			}

			// Unexpected error.  No idea what.
			if (dwLastError != ERROR_IO_PENDING)
			{
				OutputDebugLastError(dwLastError,
					"Error to writing to CommFile");
                
				TRACE0("Closing TAPI\n");
				PostHangupCall();
				return  FALSE;
			}

			// This is the expected ERROR_IO_PENDING case.

			// Wait for either overlapped I/O completion,
			// or for the CloseEvent to get signaled.
			DWORD	dwHandleSignaled = ::WaitForMultipleObjects(2, HandlesToWaitFor,
					FALSE, INFINITE);

			switch (dwHandleSignaled)
			{
			case WAIT_OBJECT_0:     // CloseEvent signaled!
			{
				// Time to exit.
				return  FALSE;
			}

			case  WAIT_OBJECT_0 + 1: // Wait finished.
			{
				// Time to get the results of the WriteFile
				break;
			}

			case  WAIT_FAILED: // Wait failed.  Shouldn't happen.
			{
				OutputDebugLastError(GetLastError(), 
					"Write WAIT_FAILED: ");
				PostHangupCall();
				return  FALSE;
			}

			default:	// This case should never occur.
			{
				TRACE1("Unexpected Wait return value '%lx'",
					dwHandleSignaled);
				PostHangupCall();
				return  FALSE;
			}
			}

			if (!GetOverlappedResult(m_hCommFile,
				lpOverlappedWrite,
				&dwNumberOfBytesWritten, TRUE))
			{
				dwLastError = GetLastError();

				// Its possible for this error to occur if the 
				// service provider has closed the port.
				if (dwLastError == ERROR_INVALID_HANDLE)
				{
					TRACE0("ERROR_INVALID_HANDLE, "
						"Likely that the Service Provider has closed the port.\n");
					return  FALSE;
				}

				// No idea what could cause another error.
				OutputDebugLastError(dwLastError,
					"Error writing to CommFile while waiting");
				TRACE0("Closing TAPI\n");
				PostHangupCall();
				return  FALSE;
			}
		}

		// Some data was written.  Make sure it all got written.
		dwNumberOfBytesToWrite -= dwNumberOfBytesWritten;
		dwWhereToStartWriting += dwNumberOfBytesWritten;
	}
	while (dwNumberOfBytesToWrite > 0);	// Write the whole thing!

	// Wrote the whole string.
	return  TRUE;
}

//
//  FUNCTION: StartReadThreadProc(LPVOID)
//
//  PURPOSE: This is the starting point for the Read Thread.
//
//  RETURN VALUE:
//    DWORD - unused.
//
//  COMMENTS:
//
//    The Read Thread uses overlapped ReadFile and sends any strings
//    read from the comm port to the UI to be printed.  This is
//    eventually done through a PostMessage so that the Read Thread
//    is never away from the comm port very long.  This also provides
//    natural desynchronization between the Read thread and the UI.
//
//    If the CloseEvent object is signaled, the Read Thread exits.
//
//    Note that there is absolutely *no* interpretation of the data,
//    which means no terminal emulation.  It basically means that this
//    sample is pretty useless as a TTY program.
//
//	  Separating the Read and Write threads is natural for a application
//    like this sample where there is no need for synchronization between
//    reading and writing.  However, if there is such a need (for example,
//    most file transfer algorithms synchronize the reading and writing),
//    then it would make a lot more sense to have a single thread to handle
//    both reading and writing.
//
DWORD	CTapiConnection::StartReadThreadProc(LPVOID  lpvParam)
{
	CTapiConnection*	pConn = (CTapiConnection*)lpvParam;

	char	szInputBuffer[INPUTBUFFERSIZE];
	DWORD	nNumberOfBytesRead;

	HANDLE	HandlesToWaitFor[3];
	DWORD	dwHandleSignaled;

	DWORD	fdwEvtMask;

	// Needed for overlapped I/O (ReadFile)
	OVERLAPPED	overlappedRead = {0, 0, 0, 0, NULL};

	// Needed for overlapped Comm Event handling.
	OVERLAPPED	overlappedCommEvent = {0, 0, 0, 0, NULL};

	// Lets put an event in the Read overlapped structure.
	overlappedRead.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	if (overlappedRead.hEvent == NULL)
	{
		OutputDebugLastError(GetLastError(), "Unable to CreateEvent: ");
		pConn->PostHangupCall();
		goto  LABEL_ENDREADTHREAD;
	}

	// And an event for the CommEvent overlapped structure.
	overlappedCommEvent.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
	if (overlappedCommEvent.hEvent == NULL)
	{
		OutputDebugLastError(GetLastError(), "Unable to CreateEvent: ");
		pConn->PostHangupCall();
		goto  LABEL_ENDREADTHREAD;
	}

	// We will be waiting on these objects.
	HandlesToWaitFor[0] = pConn->m_hCloseEvent;
	HandlesToWaitFor[1] = overlappedCommEvent.hEvent;
	HandlesToWaitFor[2] = overlappedRead.hEvent;


	// Setup CommEvent handling.

	// Set the comm mask so we receive error signals.
	if (!::SetCommMask(pConn->m_hCommFile, EV_ERR))
	{
		OutputDebugLastError(GetLastError(),"Unable to SetCommMask: ");
		pConn->PostHangupCall();
		goto  LABEL_ENDREADTHREAD;
	}

	// Start waiting for CommEvents (Errors)
	if (!pConn->SetupCommEvent(&overlappedCommEvent, &fdwEvtMask))
	{
		pConn->PostHangupCall();
		goto  LABEL_ENDREADTHREAD;
	}

	// Start waiting for Read events.
	if (!pConn->SetupReadEvent(&overlappedRead,
		szInputBuffer, INPUTBUFFERSIZE,
		&nNumberOfBytesRead))
	{
		pConn->PostHangupCall();
		goto  LABEL_ENDREADTHREAD;
	}

	// Keep looping until we break out.
	while (TRUE)
	{
		// Wait until some event occurs (data to read; error; stopping).
		dwHandleSignaled = 
			WaitForMultipleObjects(3, HandlesToWaitFor,
				FALSE, INFINITE);

		// Which event occured?
		switch (dwHandleSignaled)
		{
		case WAIT_OBJECT_0:	// Signal to end the thread.
		{
			// Time to exit.
			goto  LABEL_ENDREADTHREAD;
		}

		case WAIT_OBJECT_0 + 1:	// CommEvent signaled.
		{
			// Handle the CommEvent.
			if (!pConn->HandleCommEvent(&overlappedCommEvent, &fdwEvtMask, TRUE))
			{
				pConn->PostHangupCall();
				goto  LABEL_ENDREADTHREAD;
			}

			// Start waiting for the next CommEvent.
			if (!pConn->SetupCommEvent(&overlappedCommEvent, &fdwEvtMask))
			{
				pConn->PostHangupCall();
				goto  LABEL_ENDREADTHREAD;
			}
			break;
		}

		case WAIT_OBJECT_0 + 2: // Read Event signaled.
		{
			// Get the new data!
			if (!pConn->HandleReadEvent(&overlappedRead,
				szInputBuffer, INPUTBUFFERSIZE,
				&nNumberOfBytesRead))
			{
				pConn->PostHangupCall();
				goto  LABEL_ENDREADTHREAD;
			}

			// Wait for more new data.
			if (!pConn->SetupReadEvent(&overlappedRead,
				szInputBuffer, INPUTBUFFERSIZE,
				&nNumberOfBytesRead))
			{
				pConn->PostHangupCall();
				goto  LABEL_ENDREADTHREAD;
			}
			break;
		}

		case WAIT_FAILED:	// Wait failed. Shouldn't happen.
		{
			OutputDebugLastError(GetLastError(),"Read WAIT_FAILED: ");
			pConn->PostHangupCall();
			goto  LABEL_ENDREADTHREAD;
		}

		default:	// This case should never occur.
		{
			TRACE1("Unexpected Wait return value '%lx'",
				dwHandleSignaled);
			pConn->PostHangupCall();
			goto  LABEL_ENDREADTHREAD;
		}
		}	// End of switch(dwHandleSignaled).

	}	// End of while(TRUE) loop.


	// Time to clean up Read Thread.
LABEL_ENDREADTHREAD:

	TRACE0("Read thread shutting down\n");
	::PurgeComm(pConn->m_hCommFile, PURGE_RXABORT | PURGE_RXCLEAR);
	::CloseHandle(overlappedRead.hEvent);
	::CloseHandle(overlappedCommEvent.hEvent);
	pConn->m_dwReadThreadID = 0;
	::CloseHandle(pConn->m_hReadThread);
	pConn->m_hReadThread = 0;
	return  0;
}

//
//  FUNCTION: SetupReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
//  PURPOSE: Sets up an overlapped ReadFile
//
//  PARAMETERS:
//    lpOverlappedRead      - address of overlapped structure to use.
//    lpszInputBuffer       - Buffer to place incoming bytes.
//    dwSizeofBuffer        - size of lpszInputBuffer.
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes.
//
//  RETURN VALUE:
//    TRUE if able to successfully setup the ReadFile.  FALSE if there
//    was a failure setting up or if the CloseEvent object was signaled.
//
//  COMMENTS:
//
//    This function is a helper function for the Read Thread.  This
//    function sets up the overlapped ReadFile so that it can later
//    be waited on (or more appropriatly, so the event in the overlapped
//    structure can be waited upon).  If there is data waiting, it is
//    handled and the next ReadFile is initiated.
//    Another possible reason for returning FALSE is if the comm port
//    is closed by the service provider.
//    
//
//
BOOL	CTapiConnection::SetupReadEvent(LPOVERLAPPED  lpOverlappedRead,
	LPSTR  lpszInputBuffer, DWORD  dwSizeofBuffer,
	LPDWORD  lpnNumberOfBytesRead)
{
	DWORD	dwLastError;

LABEL_STARTSETUPREADEVENT:

	// Make sure the CloseEvent hasn't been signaled yet.
	// Check is needed because this function is potentially recursive.
	if (WAIT_TIMEOUT != WaitForSingleObject(m_hCloseEvent,0))
		return  FALSE;
    
	// Start the overlapped ReadFile.
	if (ReadFile(m_hCommFile, 
		lpszInputBuffer, dwSizeofBuffer,
		lpnNumberOfBytesRead, lpOverlappedRead))
	{
		// This would only happen if there was data waiting to be read.
		TRACE0("Data waiting for ReadFile.\n");
        
		// Handle the data.
		if (!HandleReadData(lpszInputBuffer, *lpnNumberOfBytesRead))
		{
			return  FALSE;
		}

		// Start waiting for more data.
		goto  LABEL_STARTSETUPREADEVENT;
	}

	// ReadFile failed.  Expected because of overlapped I/O.
	dwLastError = GetLastError();

	// LastError was ERROR_IO_PENDING, as expected.
	if (dwLastError == ERROR_IO_PENDING)
	{
		TRACE0("Waiting for data from comm connection.\n");
		return  TRUE;
	}

	// Its possible for this error to occur if the 
	// service provider has closed the port.  Time to end.
	if (dwLastError == ERROR_INVALID_HANDLE)
	{
		TRACE0("ERROR_INVALID_HANDLE, "
			"Likely that the Service Provider has closed the port.\n");
		return  FALSE;
	}

	// Unexpected error. No idea what could cause this to happen.
	OutputDebugLastError(dwLastError,"Unexpected ReadFile error: ");
    
	PostHangupCall();
	return  FALSE;
}
 
//
//  FUNCTION: HandleReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
//  PURPOSE: Retrieves and handles data when there is data ready.
//
//  PARAMETERS:
//    lpOverlappedRead      - address of overlapped structure to use.
//    lpszInputBuffer       - Buffer to place incoming bytes.
//    dwSizeofBuffer        - size of lpszInputBuffer.
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes.
//
//  RETURN VALUE:
//    TRUE if able to successfully retrieve and handle the available data.
//    FALSE if unable to retrieve or handle the data.
//
//  COMMENTS:
//
//    This function is another helper function for the Read Thread.  This
//    is the function that is called when there is data available after
//    an overlapped ReadFile has been setup.  It retrieves the data and
//    handles it.
//
//
BOOL	CTapiConnection::HandleReadEvent(LPOVERLAPPED  lpOverlappedRead,
	LPSTR  lpszInputBuffer, DWORD  dwSizeofBuffer,
	LPDWORD  lpnNumberOfBytesRead)
{
	DWORD	dwLastError;

	if (GetOverlappedResult(m_hCommFile,
		lpOverlappedRead, lpnNumberOfBytesRead, FALSE))
	{
		return  HandleReadData(lpszInputBuffer, *lpnNumberOfBytesRead);
	}

	// Error in GetOverlappedResult; handle it.
	dwLastError = GetLastError();

	// Its possible for this error to occur if the 
	// service provider has closed the port.  Time to end.
	if (dwLastError == ERROR_INVALID_HANDLE)
	{
		TRACE0("ERROR_INVALID_HANDLE, "
			"Likely that the Service Provider has closed the port.\n");
		return  FALSE;
	}

	OutputDebugLastError(dwLastError, 
		"Unexpected GetOverlappedResult Read Error: ");

	PostHangupCall();
	return  FALSE;
}

//
//  FUNCTION: HandleReadData(LPCSTR, DWORD)
//
//  PURPOSE: Deals with data after its been read from the comm file.
//
//  PARAMETERS:
//    lpszInputBuffer  - Buffer to place incoming bytes.
//    dwSizeofBuffer   - size of lpszInputBuffer.
//
//  RETURN VALUE:
//    TRUE if able to successfully handle the data.
//    FALSE if unable to allocate memory or handle the data.
//
// 

⌨️ 快捷键说明

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