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;
}
}