原博客网址:http://blog.csdn.NET/itas109
QQ技术交流群:129518033
这是一份优秀的串口类文件,好多的地方值得我们学习,具体在多线程,事件,自定义消息,类的封装方面等等。
Remon提供的串口类网址为: http://codeguru.earthweb.com/network/serialport.shtml,
由于已经运行十几年了,原文的问答部分列出来这么多年来的问题,经过网友们的总结,补充和修改原来代码后,整理出一份相对比较完美的代码。
CSerialPort类地址:https://github.com/itas109/CSerialPort
2016-08-02补充说明
CSDN下载:http://download.csdn.net/detail/itas109/9598347
更新内容:
1、 改进IsOpen方法,m_hComm增加INVALID_HANDLE_VALUE的情况,因为CreateFile方法失败返回的是INVALID_HANDLE_VALUE,不是NULL
2、改进ClosePort方法:增加串口句柄无效的判断(防止关闭死锁);m_hWriteEvent不使用CloseHandle关闭
3、 改进CommThread、ReceiveChar、ReceiveStr和WriteChar方法中异常处理的判断,增加三种判断:串口打开失败(error code:ERROR_INVALID_HANDLE)、连接过程中非法断开(error code:ERROR_BAD_COMMAND)和拒绝访问(error code:ERROR_ACCESS_DENIED)
4、 采用安全函数sprintf_s和strcpy_s函数替换掉sprintf和strcpy
5、 改进QueryKey方法,用于查询注册表的可用串口值,可以搜索到任意的可用串口
6、改进InitPort方法,串口打开失败,增加提示信息:串口不存在(error code:ERROR_FILE_NOT_FOUND)和串口拒绝访问(error code:ERROR_ACCESS_DENIED)
7、加入viruscamp 取消对 MFC 的依赖
8、改进InitPort方法,如果上次串口是打开,再次调用InitPort方法,关闭串口需要做一定的延时,否则有几率导致ERROR_ACCESS_DENIED拒绝访问,也就是串口占用问题
9、初始化默认波特率修改为9600
10、修复一些释放的BUG
11、规范了一些错误信息,参考winerror.h -- error code definitions for the Win32 API functions
12、删除SendData和RecvData方法
2016-06-29补充说明:
CSDN下载:http://download.csdn.Net/detail/itas109/9563059
更新内容:
1、解决RestartMonitoring方法和StopMonitoring方法命令不准确引起的歧义,根据实际作用。 将RestartMonitoring更改为ResumeMonitoring,将StopMonitoring更改为SuspendMonitoring。
2、增加IsThreadSuspend方法,用于判断线程是否挂起。
3、改进ClosePort方法,增加线程挂起判断,解决由于线程挂起导致串口关闭死锁的问题。
4、增加IsReceiveString宏定义,用于接收时采用单字节接收还是多字节接收。
2016-06-22补充说明:
更新内容:
1、增加ReceiveStr方法,用于接收字符串(接收缓冲区有多少字符就接收多少字符)。 解决ReceiveChar只能接收单个字符的问题。
2016-05-07补充说明:
CSDN下载:http://download.csdn.net/detail/itas109/9512828
更新内容:
1、修复每次打开串口发送一次,当串口无应答时,需要关闭再打开或者接收完数据才能发送的问题。 解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置也调换。 参考:http://zhidao.baidu.com/link?url=RSrbPcfTZRULFFd2ziHZPBwnoXv1iCSu_Nmycb_yEw1mklT8gkoNZAkWpl3UDhk8L35DtRPo5VV5kEGpOx-Gea
2、修复停止位在头文件中定义成1导致SetCommState报错的问题,应为1对应的停止位是1.5。UINT stopsbits = ONESTOPBIT
3、switch(stopbits)和switch(parity)增加默认情况,增强程序健壮性
历史更新:
First Version by Remon Spekreijse on 2000-02-08
http://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2483/A-communication-class-for-serial-port.htm
Second Version by mrlong on 2007-12-25
https://code.google.com/p/mycom/
* 增加 ClosePort
* 增加 WriteToPort 两个方法
* 增加 SendData 与 RecvData 方法
by liquanhai on 2011-11-04
http://blog.csdn.net/liquanhai/article/details/4955253
* 增加 ClosePort 中交出控制权,防止死锁问题
by liquanhai on 2011-11-06
http://blog.csdn.net/liquanhai/article/details/6941574
* 增加 ReceiveChar 中防止线程死锁
by viruscamp on 2013-12-04
https://github.com/viruscamp/CSerialPort
* 增加 IsOpen 判断是否打开
* 修正 InitPort 中 parity Odd Even 参数取值错误
* 修改 InitPort 中 portnr 取值范围,portnr>9 时特殊处理
* 取消对 MFC 的依赖,使用 HWND 替代 CWnd,使用 win32 thread 函数而不是 MFC 的
* 增加用户消息编号自定义,方法来自 CnComm
by itas109 on 2014-01-10
http://blog.csdn.net/itas109/article/details/18358297
* 解决COM10以上端口无法显示的问题
* 扩展可选择端口,最大值MaxSerialPortNum可以自定义
* 添加QueryKey()和Hkey2ComboBox两个方法,用于自动查询当前有效的串口号。
by liquanhai on 2014-12-18
* 增加一些处理措施,主要是对减少CPU占用率
by itas109 on 2016-05-06
* 修复每次打开串口发送一次,当串口无应答时,需要关闭再打开或者接收完数据才能发送的问题。
解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置也调换。
参考:http://zhidao.baidu.com/link?url=RSrbPcfTZRULFFd2ziHZPBwnoXv1iCSu_Nmycb_yEw1mklT8gkoNZAkWpl3UDhk8L35DtRPo5VV5kEGpOx-Gea
* 修复停止位在头文件中定义成1导致SetCommState报错的问题,应为1对应的停止位是1.5。UINT stopsbits = ONESTOPBIT
* switch(stopbits)和switch(parity)增加默认情况,增强程序健壮性
by itas109 on 2016-06-22
* 增加ReceiveStr方法,用于接收字符串(接收缓冲区有多少字符就接收多少字符)。
* 解决ReceiveChar只能接收单个字符的问题。
by itas109 on 2016-06-29
* 解决RestartMonitoring方法和StopMonitoring方法命令不准确引起的歧义,根据实际作用。
* 将RestartMonitoring更改为ResumeMonitoring,将StopMonitoring更改为SuspendMonitoring。
* 增加IsThreadSuspend方法,用于判断线程是否挂起。
* 改进ClosePort方法,增加线程挂起判断,解决由于线程挂起导致串口关闭死锁的问题。
* 增加IsReceiveString宏定义,用于接收时采用单字节接收还是多字节接收
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #ifndef __SERIALPORT_H__
- #define __SERIALPORT_H__
-
- #ifndef WM_COMM_MSG_BASE
- #define WM_COMM_MSG_BASE WM_USER + 617 //!< 消息编号的基点
- #endif
-
- #define WM_COMM_BREAK_DETECTED WM_COMM_MSG_BASE + 1 // A break was detected on input.
- #define WM_COMM_CTS_DETECTED WM_COMM_MSG_BASE + 2 // The CTS (clear-to-send) signal changed state.
- #define WM_COMM_DSR_DETECTED WM_COMM_MSG_BASE + 3 // The DSR (data-set-ready) signal changed state.
- #define WM_COMM_ERR_DETECTED WM_COMM_MSG_BASE + 4 // A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY.
- #define WM_COMM_RING_DETECTED WM_COMM_MSG_BASE + 5 // A ring indicator was detected.
- #define WM_COMM_RLSD_DETECTED WM_COMM_MSG_BASE + 6 // The RLSD (receive-line-signal-detect) signal changed state.
- #define WM_COMM_RXCHAR WM_COMM_MSG_BASE + 7 // A character was received and placed in the input buffer.
- #define WM_COMM_RXFLAG_DETECTED WM_COMM_MSG_BASE + 8 // The event character was received and placed in the input buffer.
- #define WM_COMM_TXEMPTY_DETECTED WM_COMM_MSG_BASE + 9 // The last character in the output buffer was sent.
- #define WM_COMM_RXSTR WM_COMM_MSG_BASE + 10 // Receive string
-
- #define MaxSerialPortNum 200 ///有效的串口总个数,不是串口的号 //add by itas109 2014-01-09
- #define IsReceiveString 1 //采用何种方式接收:ReceiveString 1多字符串接收(对应响应函数为WM_COMM_RXSTR),ReceiveString 0一个字符一个字符接收(对应响应函数为WM_COMM_RXCHAR)
- class CSerialPort
- {
- public:
-
- CSerialPort();
- virtual ~CSerialPort( );
-
-
-
-
-
- BOOL InitPort(HWND pPortOwner, UINT portnr = 1, UINT baud = 9600,
- char parity = 'N', UINT databits = 8, UINT stopsbits = ONESTOPBIT,
- DWORD dwCommEvents = EV_RXCHAR | EV_CTS, UINT nBufferSize = 512,
-
- DWORD ReadIntervalTimeout = 1000,
- DWORD ReadTotalTimeoutMultiplier = 1000,
- DWORD ReadTotalTimeoutConstant = 1000,
- DWORD WriteTotalTimeoutMultiplier = 1000,
- DWORD WriteTotalTimeoutConstant = 1000);
-
-
-
- BOOL StartMonitoring();
- BOOL ResumeMonitoring();
- BOOL SuspendMonitoring();
- BOOL IsThreadSuspend(HANDLE hThread);
-
- DWORD GetWriteBufferSize();
- DWORD GetCommEvents();
- DCB GetDCB();
-
-
- void WriteToPort(char* string);
- void WriteToPort(char* string,int n);
- void WriteToPort(LPCTSTR string);
- void WriteToPort(LPCTSTR string,int n);
- void WriteToPort(BYTE* Buffer, int n);
- void ClosePort();
- BOOL IsOpen();
-
-
-
- void QueryKey(HKEY hKey);
- void Hkey2ComboBox(CComboBox& m_PortNO);
-
- protected:
-
- void ProcessErrorMessage(char* ErrorText);
- static DWORD WINAPI CommThread(LPVOID pParam);
- static void ReceiveChar(CSerialPort* port);
- static void ReceiveStr(CSerialPort* port);
- static void WriteChar(CSerialPort* port);
-
-
-
- HANDLE m_Thread;
- BOOL m_bIsSuspened;
-
-
- CRITICAL_SECTION m_csCommunicationSync;
- BOOL m_bThreadAlive;
-
-
- HANDLE m_hShutdownEvent;
- HANDLE m_hComm;
- HANDLE m_hWriteEvent;
-
-
-
-
-
-
-
-
-
- HANDLE m_hEventArray[3];
-
-
- OVERLAPPED m_ov;
- COMMTIMEOUTS m_CommTimeouts;
- DCB m_dcb;
-
-
-
- HWND m_pOwner;
-
-
-
- UINT m_nPortNr;
- char* m_szWriteBuffer;
- DWORD m_dwCommEvents;
- DWORD m_nWriteBufferSize;
-
- int m_nWriteSize;
- };
-
- #endif __SERIALPORT_H__
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #include "stdafx.h"
- #include "SerialPort.h"
-
- #include
-
- int m_nComArray[20];
-
-
-
- CSerialPort::CSerialPort()
- {
- m_hComm = NULL;
-
-
-
- m_ov.Offset = 0;
- m_ov.OffsetHigh = 0;
-
-
- m_ov.hEvent = NULL;
- m_hWriteEvent = NULL;
- m_hShutdownEvent = NULL;
-
- m_szWriteBuffer = NULL;
-
- m_bThreadAlive = FALSE;
- m_nWriteSize = 1;
- m_bIsSuspened = FALSE;
- }
-
-
-
-
- CSerialPort::~CSerialPort()
- {
- MSG message;
-
-
- if(IsThreadSuspend(m_Thread))
- {
- ResumeThread(m_Thread);
- }
-
-
- if(m_hComm == INVALID_HANDLE_VALUE)
- {
- CloseHandle(m_hComm);
- m_hComm = NULL;
- return;
- }
-
- do
- {
- SetEvent(m_hShutdownEvent);
-
- if(::PeekMessage(&message,m_pOwner,0,0,PM_REMOVE))
- {
- ::TranslateMessage(&message);
- ::DispatchMessage(&message);
- }
- } while (m_bThreadAlive);
-
-
- if (m_hComm != NULL)
- {
- CloseHandle(m_hComm);
- m_hComm = NULL;
- }
-
- if(m_hShutdownEvent!=NULL)
- CloseHandle( m_hShutdownEvent);
- if(m_ov.hEvent!=NULL)
- CloseHandle( m_ov.hEvent );
- if(m_hWriteEvent!=NULL)
- CloseHandle( m_hWriteEvent );
-
-
-
- if(m_szWriteBuffer != NULL)
- {
- delete [] m_szWriteBuffer;
- m_szWriteBuffer = NULL;
- }
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BOOL CSerialPort::InitPort(HWND pPortOwner,
- UINT portnr,
- UINT baud,
- char parity,
- UINT databits,
- UINT stopbits,
- DWORD dwCommEvents,
- UINT writebuffersize,
-
- DWORD ReadIntervalTimeout,
- DWORD ReadTotalTimeoutMultiplier,
- DWORD ReadTotalTimeoutConstant,
- DWORD WriteTotalTimeoutMultiplier,
- DWORD WriteTotalTimeoutConstant )
-
- {
- assert(portnr > 0 && portnr < MaxSerialPortNum);
- assert(pPortOwner != NULL);
-
- MSG message;
-
-
- if(IsThreadSuspend(m_Thread))
- {
- ResumeThread(m_Thread);
- }
-
-
- if (m_bThreadAlive)
- {
- do
- {
- SetEvent(m_hShutdownEvent);
-
- if(::PeekMessage(&message,m_pOwner,0,0,PM_REMOVE))
- {
- ::TranslateMessage(&message);
- ::DispatchMessage(&message);
- }
- } while (m_bThreadAlive);
-
-
- Sleep(50);
- }
-
-
- if (m_ov.hEvent != NULL)
- ResetEvent(m_ov.hEvent);
- else
- m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- if (m_hWriteEvent != NULL)
- ResetEvent(m_hWriteEvent);
- else
- m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
- if (m_hShutdownEvent != NULL)
- ResetEvent(m_hShutdownEvent);
- else
- m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-
-
-
- m_hEventArray[0] = m_hShutdownEvent;
-
-
-
-
-
-
-
- m_hEventArray[1] = m_hWriteEvent;
- m_hEventArray[2] = m_ov.hEvent;
-
-
-
-
- InitializeCriticalSection(&m_csCommunicationSync);
-
-
- m_pOwner = pPortOwner;
-
- if(m_szWriteBuffer != NULL)
- {
- delete [] m_szWriteBuffer;
- m_szWriteBuffer = NULL;
- }
- m_szWriteBuffer = new char[writebuffersize];
-
- m_nPortNr = portnr;
-
- m_nWriteBufferSize = writebuffersize;
- m_dwCommEvents = dwCommEvents;
-
- BOOL bResult = FALSE;
- char *szPort = new char[50];
- char *szBaud = new char[50];
-
-
-
-
-
-
-
-
- EnterCriticalSection(&m_csCommunicationSync);
-
-
-
- if (m_hComm != NULL)
- {
- CloseHandle(m_hComm);
- m_hComm = NULL;
- }
-
-
- sprintf_s(szPort,50, "\\\\.\\COM%d", portnr);
-
-
- int mystop;
- int myparity;
- switch(stopbits)
- {
- case 0:
- mystop = ONESTOPBIT;
- break;
- case 1:
- mystop = ONE5STOPBITS;
- break;
- case 2:
- mystop = TWOSTOPBITS;
- break;
-
-
-
- default:
- mystop = ONESTOPBIT;
- break;
- }
- myparity = 0;
- parity = toupper(parity);
- switch(parity)
- {
- case 'N':
- myparity = 0;
- break;
- case 'O':
- myparity = 1;
- break;
- case 'E':
- myparity = 2;
- break;
- case 'M':
- myparity = 3;
- break;
- case 'S':
- myparity = 4;
- break;
-
-
- default:
- myparity = 0;
- break;
- }
- sprintf_s(szBaud,50, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, mystop);
-
-
-
-
-
-
-
-
-
-
-
-
-
- m_hComm = CreateFile(szPort,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- 0);
-
-
- if (m_hComm == INVALID_HANDLE_VALUE)
- {
-
-
- switch(GetLastError())
- {
-
- case ERROR_FILE_NOT_FOUND:
- {
- CString str;
- str.Format("COM%d ERROR_FILE_NOT_FOUND,Error Code:%d",portnr,GetLastError());
- AfxMessageBox(str);
- break;
- }
-
- case ERROR_ACCESS_DENIED:
- {
- CString str;
- str.Format("COM%d ERROR_ACCESS_DENIED,Error Code:%d",portnr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- default:
- break;
- }
-
- delete [] szPort;
- delete [] szBaud;
-
- return FALSE;
- }
-
-
-
- m_CommTimeouts.ReadIntervalTimeout = ReadIntervalTimeout * 1000;
- m_CommTimeouts.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier * 1000;
- m_CommTimeouts.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant * 1000;
- m_CommTimeouts.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier * 1000;
- m_CommTimeouts.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant * 1000;
-
-
-
-
- if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
- {
-
-
-
-
-
-
-
-
-
-
-
- if (SetCommMask(m_hComm, dwCommEvents))
- {
-
- if (GetCommState(m_hComm, &m_dcb))
- {
- m_dcb.EvtChar = 'q';
- m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
- m_dcb.BaudRate = baud;
- m_dcb.Parity = myparity;
- m_dcb.ByteSize = databits;
- m_dcb.StopBits = mystop;
-
-
-
- if (SetCommState(m_hComm, &m_dcb))
- ;
- else
- ProcessErrorMessage("SetCommState()");
-
-
-
- }
- else
- ProcessErrorMessage("GetCommState()");
- }
- else
- ProcessErrorMessage("SetCommMask()");
- }
- else
- ProcessErrorMessage("SetCommTimeouts()");
-
- delete [] szPort;
- delete [] szBaud;
-
-
-
- PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
-
-
-
- LeaveCriticalSection(&m_csCommunicationSync);
-
-
-
- return TRUE;
- }
-
-
-
-
-
-
-
- DWORD WINAPI CSerialPort::CommThread(LPVOID pParam)
- {
-
-
- CSerialPort *port = (CSerialPort*)pParam;
-
-
-
-
- port->m_bThreadAlive = TRUE;
-
-
- DWORD BytesTransfered = 0;
- DWORD Event = 0;
- DWORD CommEvent = 0;
- DWORD dwError = 0;
- COMSTAT comstat;
-
- BOOL bResult = TRUE;
-
-
-
- if (port->m_hComm)
- PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
-
-
-
- for (;;)
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);
-
- if (!bResult)
- {
-
-
-
- switch (dwError = GetLastError())
- {
- case ERROR_IO_PENDING:
- {
-
-
-
- break;
- }
- case ERROR_INVALID_PARAMETER:
- {
-
-
-
- break;
- }
- case ERROR_ACCESS_DENIED:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_ACCESS_DENIED,WaitCommEvent() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- case ERROR_INVALID_HANDLE:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- break;
- }
- case ERROR_BAD_COMMAND:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_BAD_COMMAND,WaitCommEvent() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- default:
- {
-
-
- port->m_hComm = INVALID_HANDLE_VALUE;
-
- port->ProcessErrorMessage("WaitCommEvent()");
- break;
- }
- }
- }
- else
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
-
- if (comstat.cbInQue == 0)
- continue;
- }
-
-
-
-
-
- Event = WaitForMultipleObjects(3,
- port->m_hEventArray,
- FALSE,
- INFINITE);
-
- switch (Event)
- {
- case 0:
- {
-
-
-
- CloseHandle(port->m_hComm);
- port->m_hComm=NULL;
- port->m_bThreadAlive = FALSE;
-
-
-
- ::ExitThread(100);
-
- break;
- }
- case 1:
- {
-
- WriteChar(port);
- break;
- }
- case 2:
- {
- GetCommMask(port->m_hComm, &CommEvent);
- if (CommEvent & EV_RXCHAR)
- {
- if (IsReceiveString == 1)
- {
- ReceiveStr(port);
- }
- else if (IsReceiveString == 0)
- {
- ReceiveChar(port);
- }
- else
- {
-
- ReceiveStr(port);
- }
- }
-
- if (CommEvent & EV_CTS)
- ::SendMessage(port->m_pOwner, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
- if (CommEvent & EV_RXFLAG)
- ::SendMessage(port->m_pOwner, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
- if (CommEvent & EV_BREAK)
- ::SendMessage(port->m_pOwner, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
- if (CommEvent & EV_ERR)
- ::SendMessage(port->m_pOwner, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
- if (CommEvent & EV_RING)
- ::SendMessage(port->m_pOwner, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);
-
- break;
- }
- default:
- {
- AfxMessageBox("接收有问题!");
- break;
- }
-
- }
-
- }
-
- return 0;
- }
-
-
-
-
-
- BOOL CSerialPort::StartMonitoring()
- {
-
- if (!(m_Thread = ::CreateThread (NULL, 0, CommThread, this, 0, NULL )))
- return FALSE;
-
- return TRUE;
- }
-
-
-
-
-
- BOOL CSerialPort::ResumeMonitoring()
- {
-
-
- ::ResumeThread(m_Thread);
- return TRUE;
- }
-
-
-
-
-
- BOOL CSerialPort::SuspendMonitoring()
- {
-
-
- ::SuspendThread(m_Thread);
- return TRUE;
- }
-
- BOOL CSerialPort::IsThreadSuspend(HANDLE hThread)
- {
- DWORD count = SuspendThread(hThread);
- if (count == -1)
- {
- return FALSE;
- }
- ResumeThread(hThread);
- return (count != 0);
- }
-
-
-
-
-
- void CSerialPort::ProcessErrorMessage(char* ErrorText)
- {
- char *Temp = new char[200];
-
- LPVOID lpMsgBuf;
-
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
-
- sprintf_s(Temp,200,"WARNING: %s Failed with the following error: \n%s\nPort: %d\n", (char*)ErrorText, lpMsgBuf, m_nPortNr);
- MessageBox(NULL, Temp, "Application Error", MB_ICONSTOP);
-
- LocalFree(lpMsgBuf);
- delete[] Temp;
- }
-
-
-
-
- void CSerialPort::WriteChar(CSerialPort* port)
- {
- BOOL bWrite = TRUE;
- BOOL bResult = TRUE;
-
- DWORD BytesSent = 0;
- DWORD SendLen = port->m_nWriteSize;
- ResetEvent(port->m_hWriteEvent);
-
-
-
- EnterCriticalSection(&port->m_csCommunicationSync);
-
- if (bWrite)
- {
-
- port->m_ov.Offset = 0;
- port->m_ov.OffsetHigh = 0;
-
-
- PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
-
- bResult = WriteFile(port->m_hComm,
- port->m_szWriteBuffer,
- SendLen,
-
- &BytesSent,
- &port->m_ov);
-
-
- if (!bResult)
- {
- DWORD dwError = GetLastError();
- switch (dwError)
- {
- case ERROR_IO_PENDING:
- {
-
- BytesSent = 0;
- bWrite = FALSE;
- break;
- }
- case ERROR_ACCESS_DENIED:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_ACCESS_DENIED,WriteFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- case ERROR_INVALID_HANDLE:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- break;
- }
- case ERROR_BAD_COMMAND:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_BAD_COMMAND,WriteFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- default:
- {
-
- port->ProcessErrorMessage("WriteFile()");
- }
- }
- }
- else
- {
- LeaveCriticalSection(&port->m_csCommunicationSync);
- }
- }
-
- if (!bWrite)
- {
- bWrite = TRUE;
-
- bResult = GetOverlappedResult(port->m_hComm,
- &port->m_ov,
- &BytesSent,
- TRUE);
-
- LeaveCriticalSection(&port->m_csCommunicationSync);
-
-
- if (!bResult)
- {
- port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");
- }
- }
-
-
- if (BytesSent != SendLen )
- {
-
- }
- }
-
-
-
-
- void CSerialPort::ReceiveChar(CSerialPort* port)
- {
- BOOL bRead = TRUE;
- BOOL bResult = TRUE;
- DWORD dwError = 0;
- DWORD BytesRead = 0;
- COMSTAT comstat;
- unsigned char RXBuff;
-
- for (;;)
- {
-
- if(WaitForSingleObject(port->m_hShutdownEvent,0)==WAIT_OBJECT_0)
- return;
-
-
-
-
-
- EnterCriticalSection(&port->m_csCommunicationSync);
-
-
-
-
-
- bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
-
- LeaveCriticalSection(&port->m_csCommunicationSync);
-
-
-
-
-
-
-
-
-
-
-
-
- if (comstat.cbInQue == 0)
- {
-
- break;
- }
-
- EnterCriticalSection(&port->m_csCommunicationSync);
-
- if (bRead)
- {
-
- bResult = ReadFile(port->m_hComm,
- &RXBuff,
- 1,
- &BytesRead,
- &port->m_ov);
-
-
- if (!bResult)
- {
- switch (dwError = GetLastError())
- {
- case ERROR_IO_PENDING:
- {
-
-
-
- bRead = FALSE;
- break;
- }
- case ERROR_ACCESS_DENIED:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_ACCESS_DENIED,ReadFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- case ERROR_INVALID_HANDLE:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- break;
- }
- case ERROR_BAD_COMMAND:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_BAD_COMMAND,ReadFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- default:
- {
-
- port->ProcessErrorMessage("ReadFile()");
- break;
-
- }
- }
- }
- else
- {
-
- bRead = TRUE;
- }
- }
-
-
- if (!bRead)
- {
- bRead = TRUE;
- bResult = GetOverlappedResult(port->m_hComm,
- &port->m_ov,
- &BytesRead,
- TRUE);
-
-
- if (!bResult)
- {
- port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
- }
- }
-
- LeaveCriticalSection(&port->m_csCommunicationSync);
-
-
-
- PostMessage(port->m_pOwner, WM_COMM_RXCHAR, (WPARAM)RXBuff, (LPARAM) port->m_nPortNr);
-
- }
-
- }
-
-
-
-
- void CSerialPort::ReceiveStr(CSerialPort* port)
- {
- BOOL bRead = TRUE;
- BOOL bResult = TRUE;
- DWORD dwError = 0;
- DWORD BytesRead = 0;
- COMSTAT comstat;
-
- for (;;)
- {
-
- if(WaitForSingleObject(port->m_hShutdownEvent,0)==WAIT_OBJECT_0)
- return;
-
-
-
-
-
- EnterCriticalSection(&port->m_csCommunicationSync);
-
-
-
-
-
- bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
-
- LeaveCriticalSection(&port->m_csCommunicationSync);
-
-
-
-
-
-
-
-
-
-
-
-
- if (comstat.cbInQue == 0)
- {
-
- break;
- }
-
-
- unsigned char* RXBuff = new unsigned char[comstat.cbInQue+1];
- if(RXBuff == NULL)
- {
- return;
- }
- RXBuff[comstat.cbInQue] = '\0';
-
- EnterCriticalSection(&port->m_csCommunicationSync);
-
- if (bRead)
- {
-
- bResult = ReadFile(port->m_hComm,
- RXBuff,
- comstat.cbInQue,
- &BytesRead,
- &port->m_ov);
-
-
- if (!bResult)
- {
- switch (dwError = GetLastError())
- {
- case ERROR_IO_PENDING:
- {
-
-
-
- bRead = FALSE;
- break;
- }
- case ERROR_ACCESS_DENIED:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_ACCESS_DENIED,ReadFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- case ERROR_INVALID_HANDLE:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- break;
- }
- case ERROR_BAD_COMMAND:
- {
- port->m_hComm = INVALID_HANDLE_VALUE;
- CString str;
- str.Format("COM%d ERROR_BAD_COMMAND,ReadFile() Error Code:%d",port->m_nPortNr,GetLastError());
- AfxMessageBox(str);
- break;
- }
- default:
- {
-
- port->ProcessErrorMessage("ReadFile()");
- break;
-
- }
- }
- }
- else
- {
-
- bRead = TRUE;
- }
- }
-
-
- if (!bRead)
- {
- bRead = TRUE;
- bResult = GetOverlappedResult(port->m_hComm,
- &port->m_ov,
- &BytesRead,
- TRUE);
-
-
- if (!bResult)
- {
- port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
- }
- }
-
- LeaveCriticalSection(&port->m_csCommunicationSync);
-
-
- ::SendMessage((port->m_pOwner), WM_COMM_RXSTR, (WPARAM) RXBuff, (LPARAM) port->m_nPortNr);
-
-
-
-
- delete[] RXBuff;
- RXBuff = NULL;
-
- }
-
- }
-
-
-
-
- void CSerialPort::WriteToPort(char* string)
- {
- assert(m_hComm != 0);
-
- memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
- strcpy_s(m_szWriteBuffer,m_nWriteBufferSize,string);
- m_nWriteSize=strlen(string);
-
- SetEvent(m_hWriteEvent);
- }
-
-
-
-
- DCB CSerialPort::GetDCB()
- {
- return m_dcb;
- }
-
-
-
-
- DWORD CSerialPort::GetCommEvents()
- {
- return m_dwCommEvents;
- }
-
-
-
-
- DWORD CSerialPort::GetWriteBufferSize()
- {
- return m_nWriteBufferSize;
- }
-
- BOOL CSerialPort::IsOpen()
- {
- return m_hComm != NULL && m_hComm!= INVALID_HANDLE_VALUE;
- }
-
- void CSerialPort::ClosePort()
- {
- MSG message;
-
-
- if(IsThreadSuspend(m_Thread))
- {
- ResumeThread(m_Thread);
- }
-
-
- if(m_hComm == INVALID_HANDLE_VALUE)
- {
- CloseHandle(m_hComm);
- m_hComm = NULL;
- return;
- }
-
- do
- {
- SetEvent(m_hShutdownEvent);
-
- if(::PeekMessage(&message,m_pOwner,0,0,PM_REMOVE))
- {
- ::TranslateMessage(&message);
- ::DispatchMessage(&message);
- }
- } while (m_bThreadAlive);
-
-
- if (m_hComm != NULL)
- {
- CloseHandle(m_hComm);
- m_hComm = NULL;
- }
-
-
- if(m_hShutdownEvent!=NULL)
- {
- ResetEvent(m_hShutdownEvent);
- }
- if(m_ov.hEvent!=NULL)
- {
- ResetEvent(m_ov.hEvent);
- }
- if(m_hWriteEvent!=NULL)
- {
- ResetEvent(m_hWriteEvent);
-
- }
-
- if(m_szWriteBuffer != NULL)
- {
- delete [] m_szWriteBuffer;
- m_szWriteBuffer = NULL;
- }
- }
-
- void CSerialPort::WriteToPort(char* string,int n)
- {
- assert(m_hComm != 0);
- memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
- memcpy(m_szWriteBuffer, string, n);
- m_nWriteSize = n;
-
-
- SetEvent(m_hWriteEvent);
- }
-
- void CSerialPort::WriteToPort(LPCTSTR string)
- {
- assert(m_hComm != 0);
- memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
- strcpy_s(m_szWriteBuffer,m_nWriteBufferSize,string);
- m_nWriteSize=strlen(string);
-
- SetEvent(m_hWriteEvent);
- }
-
- void CSerialPort::WriteToPort(BYTE* Buffer, int n)
- {
- assert(m_hComm != 0);
- memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
- int i;
- for(i=0; i
- {
- m_szWriteBuffer[i] = Buffer[i];
- }
- m_nWriteSize=n;
-
-
- SetEvent(m_hWriteEvent);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- void CSerialPort::QueryKey(HKEY hKey)
- {
- #define MAX_KEY_LENGTH 255
- #define MAX_VALUE_NAME 16383
-
-
- TCHAR achClass[MAX_PATH] = TEXT("");
- DWORD cchClassName = MAX_PATH;
- DWORD cSubKeys=0;
- DWORD cbMaxSubKey;
- DWORD cchMaxClass;
- DWORD cValues;
- DWORD cchMaxValue;
- DWORD cbMaxValueData;
- DWORD cbSecurityDescriptor;
- FILETIME ftLastWriteTime;
-
- DWORD i, retCode;
-
- TCHAR achValue[MAX_VALUE_NAME];
- DWORD cchValue = MAX_VALUE_NAME;
-
-
- retCode = RegQueryInfoKey(
- hKey,
- achClass,
- &cchClassName,
- NULL,
- &cSubKeys,
- &cbMaxSubKey,
- &cchMaxClass,
- &cValues,
- &cchMaxValue,
- &cbMaxValueData,
- &cbSecurityDescriptor,
- &ftLastWriteTime);
-
- for (i=0;i<20;i++)
- {
- m_nComArray[i] = -1;
- }
-
-
- if (cValues > 0) {
- for (i=0, retCode=ERROR_SUCCESS; i