打开的串口无法关闭?

sasdaa 2007-06-13 12:40:44
我参考cnComm类写了一个串口类(采用多线程),
调试时发现当打开多个串口,经常出现串口无法关闭的现象,麻烦各位大哥帮忙看看!

//当接受到数据送到窗口的消息
#define ON_COM_RECEIVE WM_USER + 170 // WPARAM 端口号

class CSerial
{
public:
CSerial();
virtual ~CSerial();

int Open( int nPort, //端口
int nBaud = 9600 , //波特率
BYTE ByteSize = 8, //
BYTE Parity = NOPARITY, //奇偶校验
BYTE StopBits=ONESTOPBIT//停止位
);
bool IsOpen();
bool Close();
int SetState();
void SetNotifyNum(int NotifyNum);
void SetWnd(HWND hWnd);
DWORD Write(char *szBuffer, DWORD dwBufferLength);
DWORD Read(char *szBuffer, DWORD dwBufferLength);

HANDLE m_hComDev; //打开串口的句柄
HANDLE m_hWatchThread; //监视线程的句柄

volatile HWND m_hUIWnd; //通知串口
volatile int m_nPort; //
int m_nBaud; //
bool m_bOpened;
int m_nErrId;
volatile int m_nNotifyNum;
OVERLAPPED m_ReadOverlapped;
OVERLAPPED m_WriteOverlapped;
OVERLAPPED m_WaitOverlapped;
COMMPROP m_Commprop;
COMMCONFIG m_CommConfig;

BYTE m_OutData[30];

};
...全文
343 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
ReverseEngineering 2007-09-06
  • 打赏
  • 举报
回复
函数不返回导致无法关闭吗?
sasdaa 2007-06-13
  • 打赏
  • 举报
回复
//继续

DWORD WINAPI CommWatchProc(LPVOID lpPara)
{
CSerial* pComm = (CSerial*)lpPara;

if(!::SetCommMask(pComm->m_hComDev, EV_RXCHAR | EV_ERR))
return 1;

int d;
COMSTAT Stat;
DWORD dwError;
DWORD dwEvtMask=0 ;

for(DWORD dwLength, dwMask = 0; pComm->m_bOpened && pComm->IsOpen(); dwMask = 0)
{
if(!::WaitCommEvent(pComm->m_hComDev, &dwMask, &pComm->m_WaitOverlapped))
{
if(::GetLastError() == ERROR_IO_PENDING)
{
::GetOverlappedResult(pComm->m_hComDev, &pComm->m_WaitOverlapped, &dwLength, TRUE);
}
}

if(dwMask & EV_ERR) // == EV_ERR
::ClearCommError(pComm->m_hComDev, &dwError, &Stat);

if(dwMask & EV_RXCHAR) // == EV_RXCHAR
{
::ClearCommError(pComm->m_hComDev, &dwError, &Stat);

if(Stat.cbInQue > (pComm->m_nNotifyNum))
{
d = pComm->Read((char*)(pComm->m_OutData), Stat.cbInQue);

if(d >0)
{
::PostMessage(pComm->m_hUIWnd, ON_COM_RECEIVE, WPARAM(pComm->m_nPort), LPARAM(Stat.cbInQue));
}

}


}
}
return 0;
}



CSerial::CSerial()
{
// memset(_szCommStr, 0, 20);



memset(&m_ReadOverlapped, 0, sizeof(m_ReadOverlapped));
memset(&m_WriteOverlapped, 0, sizeof(m_WriteOverlapped));
memset(&m_WaitOverlapped, 0, sizeof(m_WaitOverlapped));

m_hComDev = INVALID_HANDLE_VALUE;
m_hWatchThread = INVALID_HANDLE_VALUE;
m_hUIWnd = NULL;
m_bOpened = false;
m_nNotifyNum = 0;

}

CSerial::~CSerial()
{
Close();

}

//打开串口,异步通讯
int CSerial::Open( int nPort, int nBaud ,BYTE ByteSize, BYTE Parity , BYTE StopBits)
{
if( m_bOpened ) return( TRUE );
bool ret;
char szPort[15];
DCB dcb;
memset(szPort, 0, sizeof(szPort));
wsprintf( szPort, "COM%d", nPort );

m_nPort = nPort;

m_hComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hComDev == INVALID_HANDLE_VALUE ) return( 1 );


//设定超时结构
COMMTIMEOUTS CommTimeOuts;


CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;

SetCommTimeouts( m_hComDev, &CommTimeOuts );

dcb.DCBlength = sizeof( DCB );
GetCommState( m_hComDev, &dcb );

//设定波特率
dcb.BaudRate = nBaud;
//设定无奇偶校验
dcb.Parity = Parity;
//设定数据位为8
dcb.ByteSize = ByteSize;
//设定一个停止位
dcb.StopBits=ONESTOPBIT;

ret = SetCommState( m_hComDev, &dcb );
if(!ret){

m_nErrId = GetLastError();
return 2;
}

//设置推荐缓冲区
ret = SetupComm( m_hComDev, 2048,2048 );
if(!ret){

m_nErrId = GetLastError();
return 3;
}

//清空串口缓冲区
PurgeComm( m_hComDev, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR| PURGE_RXCLEAR ); //清干净输入、输出缓冲区



m_ReadOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(m_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE);

m_WriteOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(m_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE);

m_WaitOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
assert(m_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE);


if( m_ReadOverlapped.hEvent == NULL ||
m_WriteOverlapped.hEvent == NULL )
{
DWORD dwError = GetLastError();
if(m_ReadOverlapped.hEvent!= NULL)
CloseHandle( m_ReadOverlapped.hEvent );

if(m_WriteOverlapped.hEvent!= NULL)
CloseHandle( m_WriteOverlapped.hEvent );
CloseHandle( m_hComDev );

m_nErrId = GetLastError();
return 4;
}


// unsigned long i;
// GetCommConfig(m_hComDev, &m_CommConfig, &i);
//
// m_CommConfig.dwProviderSubType = PST_RS422;
// SetCommConfig(m_hComDev, &m_CommConfig, sizeof(COMMCONFIG));
// GetCommConfig(m_hComDev, &m_CommConfig, &i);

DWORD dw;
m_hWatchThread = CreateThread(NULL, 0, CommWatchProc, this, 0, &dw);
if(!m_hWatchThread) return 5;

m_bOpened = TRUE;
return 0;
}

bool CSerial::IsOpen()
{

return m_hComDev != INVALID_HANDLE_VALUE;;
}

//写串口 szBuffer
DWORD CSerial::Write(char *szBuffer, DWORD dwBufferLength)
{
if(!IsOpen())
return 0;

DWORD dwError;

if(::ClearCommError(m_hComDev, &dwError, NULL) && dwError > 0) //清除错误
::PurgeComm(m_hComDev, PURGE_TXABORT | PURGE_TXCLEAR);

unsigned long uWriteLength = 0;

if(!::WriteFile(m_hComDev, szBuffer, dwBufferLength, &uWriteLength, &m_WriteOverlapped))
if(::GetLastError() != ERROR_IO_PENDING)
uWriteLength = 0;

return uWriteLength;
}

//读取串口 dwBufferLength 个字符到 szBuffer 返回实际读到的字符数
DWORD CSerial::Read(char *szBuffer, DWORD dwBufferLength)
{
if(!IsOpen())
return 0;

// szBuffer[0] = '\0';

COMSTAT Stat;
DWORD dwError;

if(::ClearCommError(m_hComDev, &dwError, &Stat) && dwError > 0) //清除错误
{
::PurgeComm(m_hComDev, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
return 0;
}

if(!Stat.cbInQue)// 缓冲区无数据
return 0;

unsigned long uReadLength = 0;

/// dwBufferLength = dwBufferLength - 1 > Stat.cbInQue ? Stat.cbInQue : dwBufferLength - 1;
dwBufferLength > Stat.cbInQue ? Stat.cbInQue : dwBufferLength ;
if(!::ReadFile(m_hComDev, szBuffer, dwBufferLength, &uReadLength, &m_ReadOverlapped)) //2000 下 ReadFile 始终返回 True
{
if(::GetLastError() == ERROR_IO_PENDING) // 结束异步I/O
{

if(!::GetOverlappedResult(m_hComDev, &m_ReadOverlapped, &uReadLength, false))
{
if(::GetLastError() != ERROR_IO_INCOMPLETE)//其他错误
uReadLength = 0;
WaitForSingleObject(m_ReadOverlapped.hEvent, 20); //等待20ms
}
}
else
uReadLength = 0;
}


// szBuffer[uReadLength] = '\0';
return uReadLength;
}


//关闭串口
bool CSerial::Close()
{
if(IsOpen())
{
if(m_hWatchThread != NULL)
{
m_bOpened = false;

::SetCommMask(m_hComDev, 0);
::SetEvent(m_WaitOverlapped.hEvent);
if(::WaitForSingleObject(m_hWatchThread, 100) != WAIT_OBJECT_0)
if(!::TerminateThread(m_hWatchThread, 0))
{
return false;
}


::CloseHandle(m_hWatchThread);
::ResetEvent(m_WaitOverlapped.hEvent);

m_hWatchThread = NULL;

}
::CloseHandle(m_hComDev);

m_hComDev = INVALID_HANDLE_VALUE;

if(m_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE)
CloseHandle(m_ReadOverlapped.hEvent);

if(m_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE)
CloseHandle(m_WriteOverlapped.hEvent);

if(m_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE)
CloseHandle(m_WaitOverlapped.hEvent);

m_hComDev = INVALID_HANDLE_VALUE;

return true;
}
}


//送消息的窗口句柄
void CSerial::SetWnd(HWND hWnd)
{
m_hUIWnd = hWnd;
}

void CSerial::SetNotifyNum(int NotifyNum)
{
m_nNotifyNum = NotifyNum;

}
sasdaa 2007-06-13
  • 打赏
  • 举报
回复
设置信号量啊
CathySun118 2007-06-13
  • 打赏
  • 举报
回复
太长了,SetEvent(m_WaitOverlapped.hEvent);这句话做什么?
sasdaa 2007-06-13
  • 打赏
  • 举报
回复
麻烦各位给各意见啊!
sasdaa 2007-06-13
  • 打赏
  • 举报
回复

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧