封装线程类CThread、串口线程类CThreadComm、串口通讯类CSerialPort

Thread.h

#pragma once

class CThread
{
public:
	CThread();
	~CThread();

public:
	HANDLE m_hThread;//线程句柄
	bool m_bExit;//线程退出标志位
	DWORD m_dwParam;//通知线程什么参数可以传到线程当中

public:
	void start();//启动线程
	void stop();//停止线程

public:
	virtual void SetThreadData(DWORD dwParam);//额外参数,将外面额外的参数传入
	virtual DWORD GetThreadData();//额外参数,获取该线程的参数

public:
	virtual void run();

public:
	static DWORD ThreadProc(LPVOID pParam);//回调函数
};

Thread.cpp

#include "pch.h"
#include "Thread.h"


CThread::CThread()
{
	m_bExit = false;
	m_dwParam = 0;
	m_hThread = NULL;
}


CThread::~CThread()
{
	if (!m_bExit)
	{
		stop();
	}
}


void CThread::start()
{
	m_bExit = false;
	DWORD dwThreadID;
	//创建线程
	HANDLE hThread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc, this, 0, &dwThreadID);
	ASSERT(hThread);
	m_hThread = hThread;
}


void CThread::stop()
{
	if (m_hThread)
	{
		m_bExit = true;
		::WaitForSingleObject(m_hThread, INFINITE);//等待线程完全退出
		::CloseHandle(m_hThread);
		m_hThread = NULL;
	}
}

DWORD CThread::ThreadProc(LPVOID pParam)
{
	CThread* pThis = (CThread*)pParam;//强制转换
	ASSERT(pThis);

	while (!pThis->m_bExit)//判断线程是否退出,未退出则一直循环
	{
		pThis->run();
	}
	return TRUE;
}

void CThread::run()
{
	Sleep(100);//空循环需要sleep
}

void CThread::SetThreadData(DWORD dwParam)
{
	if (m_dwParam != dwParam)
	{
		m_dwParam = dwParam;
	}
}


DWORD CThread::GetThreadData()
{
	return m_dwParam;
}

ThreadComm.h

#pragma once
#include "Thread.h"

class CThreadComm :
	public CThread
{
public:
	CThreadComm();
	~CThreadComm();

public:
	virtual void run();
};


ThreadComm.cpp

#include "pch.h"
#include "SerialPort.h"
#include "resource.h"
#include "MesFirstTest1.h"
#include "MesFirstTest1Dlg.h"
CThreadComm::CThreadComm()
{
}


CThreadComm::~CThreadComm()
{
}

void CThreadComm::run()
{
	Sleep(100);
	CWnd* pWinApp = (CWnd*)AfxGetApp()->m_pMainWnd;
	if (NULL == pWinApp)
	{
		return;
	}

	CSerialPort* pSerialPort = (CSerialPort*)GetThreadData();
	if (NULL == pSerialPort) return;

	DWORD dwError = 0;
	COMSTAT comStat;
	BOOL bRet = TRUE;
	CHAR recvTemp[512];//临时缓冲区
	ZeroMemory(recvTemp, sizeof(recvTemp));

	CHAR recvBuf[4096];//真正的缓冲区
	ZeroMemory(recvBuf, sizeof(recvBuf));

	DWORD dwRead = 0;
	int nLength = 0;

	pSerialPort->ClearCommError(&dwError, &comStat);
	if (comStat.cbInQue > 0)//判断输入缓存区是否有数据
	{
		OVERLAPPED overlappedRead;
		ZeroMemory(&overlappedRead, sizeof(OVERLAPPED));
		overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

		if (comStat.cbInQue < 512)
		{
			bRet = pSerialPort->ReadFile(recvTemp, comStat.cbInQue, &dwRead, &overlappedRead);
		}
		else
		{
			bRet = pSerialPort->ReadFile(recvTemp, 500, &dwRead, &overlappedRead);
		}

		if (comStat.cbInQue >= dwRead)
		{
			nLength = 0;
			memcpy(recvBuf + nLength, recvTemp, dwRead);
			nLength += dwRead;
		}

		CloseHandle(overlappedRead.hEvent);


		if (comStat.cbInQue == dwRead)
		{
			nLength = 0;
			CEdit* pEditRecv = (CEdit*)pWinApp->GetDlgItem(IDC_EDIT_CK_RECV);
			if (pEditRecv)
			{
				CString strRecv;
				pEditRecv->GetWindowText(strRecv);
				strRecv += recvBuf;
				pEditRecv->SetWindowText(strRecv);
			}
		}

		if (!bRet)//判断是否重叠
		{
			if (ERROR_IO_PENDING == GetLastError())
			{
				while (!bRet)
				{
					bRet = pSerialPort->GetOverlappedResult(NULL, &dwRead, TRUE);
					if (GetLastError() != ERROR_IO_INCOMPLETE)
					{
						pSerialPort->ClearCommError(&dwError, &comStat);
						break;
					}
				}
			}
		}
	}
}

SerialPort.h

#pragma once
#include "ThreadComm.h"

class CSerialPort
{
public:
	CSerialPort();
	~CSerialPort();
public:
	/*OpenComm打开串口
	**/
	BOOL OpenComm(CString strComm);
	/*SetCommState设置串口状态
	**/
	BOOL SetCommState(DWORD dwBaudrate, BYTE byParity, BYTE byByteSize, BYTE byStopBits);
	BOOL SetupComm(DWORD dwInQueue, DWORD dwOutQueue);
	BOOL PurgeComm(DWORD dwFlags);
	/*SetCommMask串口事件
	**/
	BOOL SetCommMask(DWORD dwEvtNask);
	/*WriteFile写数据
	**/
	BOOL WriteFile(
		IN LPCVOID lpBuffer, // 写入的数据存储的地址:即以该指针的值为首地址的nNumberOfBytesToWrite个字节的数据将要写入
		//串口的发送数据缓冲区。 
		IN DWORD nNumberOfBytesToWrite, //要写入的数据的字节数  
		OUT LPDWORD lpNumberOfBytesWritten,// 指向指向一个DWORD数值,该数值返回实际写入的字节数 
		IN LPOVERLAPPED lpOverlapped// 重叠操作时,该参数指向一个OVERLAPPED结构;同步操作时,该参数为NULL。 
	);
	/*ReadFile读数据
	**/
	BOOL ReadFile(
		OUT LPVOID lpBuffer,// 读入的数据存储的地址:即读入的数据将存储在以该指针的值为首地址的一片内存区  
		IN DWORD nNumberOfBytesToRead, // 要读入的数据的字节数  
		OUT LPDWORD lpNumberOfBytesRead,// 指向一个DWORD数值,该数值返回读操作实际读入的字节数  
		IN LPOVERLAPPED lpOverlapped// 重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL 
	);
	/*ClearCommError清除数据
	**/
	BOOL ClearCommError(OUT LPDWORD lpError, OUT LPCOMSTAT lpStat);

	BOOL GetOverlappedResult(
		IN LPOVERLAPPED lpOverlapped,//指向重叠操作开始时指定的OVERLAPPED结构  
		OUT LPDWORD lpNumberOfBytesTransferred,//指向一个32位变量,该变量的值返回实际读写操作传输的字节数。  
		IN BOOL bWait// 该参数用于指定函数是否一直等到重叠操作结束:如果该参数为TRUE,函数直到操作结束才返回;
		//如果该参数为FALSE,函数直接返回,这时如果操作没有完成,通过调用GetLastError()函数会
		//返回ERROR_IO_INCOMPLETE。 
	);
	void CloseComm();

public:
	void StartComm();

public:
	CThreadComm m_hThreadComm;

public:
	HANDLE m_hComm;
};


SerialPort.cpp

#include "pch.h"
#include "SerialPort.h"


CSerialPort::CSerialPort()
{
	m_hComm = NULL;
}


CSerialPort::~CSerialPort()
{
	CloseComm();
}

void CSerialPort::StartComm()
{
	m_hThreadComm.SetThreadData((DWORD)this);
	m_hThreadComm.start();
}

BOOL CSerialPort::OpenComm(CString strComm)
{
	if (NULL == m_hComm)
	{
		m_hComm = CreateFile((TCHAR*)(LPCTSTR)strComm,//COM口  
			GENERIC_READ | GENERIC_WRITE, //允许读和写  
			0, //独占方式  
			NULL,
			OPEN_EXISTING, //打开而不是创建  
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, //同步方式  
			NULL);
		if (INVALID_HANDLE_VALUE /*无效句柄值*/ == m_hComm)
		{
			int nError = GetLastError();
			m_hComm = NULL;
			AfxMessageBox(_T("串口" + strComm + "打开失败"));
			return FALSE;
		}
		return TRUE;
	}
	return FALSE;
}

BOOL CSerialPort::SetCommState(DWORD dwBaudrate, BYTE byParity, BYTE byByteSize, BYTE byStopBits)
{
	if (NULL == m_hComm) return FALSE;
	DCB dcb;
	BOOL bRet = ::GetCommState(m_hComm, &dcb);
	if (!bRet)
	{
		if (m_hComm)
		{
			CloseHandle(m_hComm);
			m_hComm = NULL;
		}
		return FALSE;
	}
	dcb.BaudRate = dwBaudrate;
	dcb.Parity = byParity;
	dcb.ByteSize = byByteSize;
	dcb.StopBits = byStopBits;

	bRet = ::SetCommState(m_hComm, &dcb);//前面的两个冒号表示调用win32下的标准API函数
	if (!bRet)
	{
		if (m_hComm)
		{
			CloseHandle(m_hComm);
			m_hComm = NULL;
		}
		return FALSE;
	}
	return TRUE;
}

BOOL CSerialPort::SetupComm(DWORD dwInQueue, DWORD dwOutQueue)
{
	if (NULL == m_hComm) return FALSE;
	return ::SetupComm(m_hComm, dwInQueue, dwOutQueue);
}

BOOL CSerialPort::PurgeComm(DWORD dwFlags)
{
	if (NULL == m_hComm) return FALSE;
	return ::PurgeComm(m_hComm, dwFlags);
}

BOOL CSerialPort::SetCommMask(DWORD dwEvtNask)
{
	if (NULL == m_hComm) return FALSE;
	return ::SetCommMask(m_hComm, dwEvtNask);
}


BOOL CSerialPort::WriteFile(
	IN LPCVOID lpBuffer, // 写入的数据存储的地址:即以该指针的值为首地址的nNumberOfBytesToWrite个字节的数据将要写入
	//串口的发送数据缓冲区。 
	IN DWORD nNumberOfBytesToWrite, //要写入的数据的字节数  
	OUT LPDWORD lpNumberOfBytesWritten,// 指向指向一个DWORD数值,该数值返回实际写入的字节数 
	IN LPOVERLAPPED lpOverlapped// 重叠操作时,该参数指向一个OVERLAPPED结构;同步操作时,该参数为NULL。 
)
{
	if (NULL == m_hComm) return FALSE;
	return ::WriteFile(m_hComm, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);

}


BOOL CSerialPort::ReadFile(
	OUT LPVOID lpBuffer,// 读入的数据存储的地址:即读入的数据将存储在以该指针的值为首地址的一片内存区  
	IN DWORD nNumberOfBytesToRead, // 要读入的数据的字节数  
	OUT LPDWORD lpNumberOfBytesRead,// 指向一个DWORD数值,该数值返回读操作实际读入的字节数  
	IN LPOVERLAPPED lpOverlapped// 重叠操作时,该参数指向一个OVERLAPPED结构,同步操作时,该参数为NULL 
)
{
	if (NULL == m_hComm) return FALSE;
	return ::ReadFile(m_hComm, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}

BOOL CSerialPort::ClearCommError(OUT LPDWORD lpError, OUT LPCOMSTAT lpStat)
{
	if (NULL == m_hComm) return FALSE;
	return ::ClearCommError(m_hComm, lpError, lpStat);
}

BOOL CSerialPort::GetOverlappedResult(
	IN LPOVERLAPPED lpOverlapped,//指向重叠操作开始时指定的OVERLAPPED结构  
	OUT LPDWORD lpNumberOfBytesTransferred,//指向一个32位变量,该变量的值返回实际读写操作传输的字节数。  
	IN BOOL bWait// 该参数用于指定函数是否一直等到重叠操作结束:如果该参数为TRUE,函数直到操作结束才返回;
	//如果该参数为FALSE,函数直接返回,这时如果操作没有完成,通过调用GetLastError()函数会
	//返回ERROR_IO_INCOMPLETE。 
)
{
	if (NULL == m_hComm) return FALSE;
	return ::GetOverlappedResult(m_hComm, lpOverlapped, lpNumberOfBytesTransferred, bWait);
}


void CSerialPort::CloseComm()
{
	m_hThreadComm.stop();
	if (m_hComm)
	{
		CloseHandle(m_hComm);
		m_hComm = NULL;
	}
}

你可能感兴趣的:(c++)