/*************************************************************
EasySoft easycomm v2.0
(c) 2001-2004 EasySoft Corporation. All Rights Reserved.
@doc easycomm.rtf
@module easycomm.h | easycomm interface file
@devnote jdzwq 2003.01 - 2004.10
*************************************************************/
#ifndef _EASYCOMM_H
#define _EASYCOMM_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum{
NC_COMMBREAK = 110,
NC_COMMERROR = 111,
NC_COMMMONITOR = 112,
NC_COMMACK = 113,
NC_COMMRECIVE = 114,
NC_COMMSENT = 115
}NotifyCode;
typedef struct tagNMHDR_COMM{
HWND hwndFrom;
UINT idFrom;
UINT code;
LPARAM lParam;
WPARAM wParam;
}NMHDR_COMM;
#define WM_COMMMSG WM_USER + 10
#define COMMCTRLCLASS _T("CommCtrl")
ATOM RegisterCommCtrlClass(HINSTANCE hInstance);
#define COM_SETPORT WM_COMMMSG + 150
#define COM_GETPORT WM_COMMMSG + 151
#define COM_SETBAUDRATE WM_COMMMSG + 152
#define COM_GETBAUDRATE WM_COMMMSG + 153
#define COM_SETBYTESIZE WM_COMMMSG + 154
#define COM_GETBYTESIZE WM_COMMMSG + 155
#define COM_SETSTOPBITS WM_COMMMSG + 156
#define COM_GETSTOPBITS WM_COMMMSG + 157
#define COM_SETPARITY WM_COMMMSG + 158
#define COM_GETPARITY WM_COMMMSG + 159
#define COM_SETFCTRL WM_COMMMSG + 160
#define COM_GETFCTRL WM_COMMMSG + 161
#define COM_SETTIMEOUTS WM_COMMMSG + 162
#define COM_GETTIMEOUTS WM_COMMMSG + 163
#define COM_SETACKCHAR WM_COMMMSG + 164
#define COM_GETACKCHAR WM_COMMMSG + 165
#define COM_SETLISTIMER WM_COMMMSG + 166
#define COM_GETLISTIMER WM_COMMMSG + 167
#define COM_SETACTIVE WM_COMMMSG + 168
#define COM_GETACTIVE WM_COMMMSG + 169
#define COM_SETDATA WM_COMMMSG + 170
#define COM_GETDATA WM_COMMMSG + 171
#define COM_SETQUEUE WM_COMMMSG + 172
#define COM_POSTERROR WM_COMMMSG + 175
#define COM_POSTRECIVE WM_COMMMSG + 176
#define COM_POSTSENT WM_COMMMSG + 177
#define COM_POSTBREAK WM_COMMMSG + 178
#define COM_POSTACK WM_COMMMSG + 179
#define COM_POSTMONITOR WM_COMMMSG + 180
#define COM_QUERYSEND WM_COMMMSG + 181
#define PY_NONE 0 /*无奇偶校验*/
#define PY_EVEN 1 /*偶校验*/
#define PY_ODD 2 /*奇校验*/
#define PY_MARK 3
#define PY_SPACE 4
#define STOPBITS_ONE 1 /*1位停止位*/
#define STOPBITS_TWO 2 /*2位停止位*/
#define STOPBITS_ONEHALF 3 /*1.5停止位*/
#define FLOWCTRL_NONE 0 /*无流控制*/
#define FLOWCTRL_HARD 1 /*硬件控制*/
#define FLOWCTRL_SOFT 2 /*软件控制*/
#define CE_PARAM -1
#define READ_SUCCESS 0
#define READ_TIMEOUTS 1
#define WRITE_SUCCESS 0
#define WRITE_TIMEOUTS 1
/*端口状态*/
typedef struct _CommMonitor{
BOOL bRLSDHold;
BOOL bCTSHold;
BOOL bDSRHold;
BOOL bXOFFHold;
BOOL bXOFFSent;
int nInQueue;
int nOutQueue;
}CommMonitor;
#ifdef _CHS
#define ERROR_PARAM _T("参数错误")
#define ERROR_BREAK _T("硬件中断")
#define ERROR_FRAME _T("硬件幀错误")
#define ERROR_IOE _T("通讯I/O错误")
#define ERROR_OVERRUM _T("数据丢失")
#define ERROR_RXOVER _T("输入缓冲区溢出")
#define ERROR_RXPARITY _T("硬件校验错误")
#define ERROR_TXFULL _T("输出缓冲区溢出")
#define ERROR_UNKNOWN _T("其他错误")
#else
#define ERROR_PARAM _T("The parameter setup error")
#define ERROR_BREAK _T("The hardware detected a break condition.")
#define ERROR_FRAME _T("The hardware detected a framing error.")
#define ERROR_IOE _T("An I/O error occurred during communications with the device.")
#define ERROR_OVERRUN _T("A character-buffer overrun has occurred. The next character is lost.")
#define ERROR_RXOVER _T("An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character.")
#define ERROR_RXPARITY _T("The hardware detected a parity error.")
#define ERROR_TXFULL _T("The application tried to transmit a character, but the output buffer was full.")
#define ERROR_UNKNOWN _T("Other error occurred")
#endif
extern void InitCommControl(HINSTANCE hInstance);
extern void UnInitCommControl(HINSTANCE hInstance);
#ifdef __cplusplus
}
#endif
#endif
/*************************************************************
EasySoft easycomm v2.0
(c) 2001-2004 EasySoft Corporation. All Rights Reserved.
@doc easycomm.rtf
@module easycomm.c | easycomm impliment file
@devnote jdzwq 2003.01 - 2004.10
*************************************************************/
#include "easycomm.h"
typedef struct tagCommDelta{
HWND hWnd;
BOOL bActive; /*侦听标志*/
BOOL bReady; /*串口可写标志*/
HANDLE hListen; /*侦听线程句柄*/
DWORD dwListen; /*侦听线程ID*/
OVERLAPPED ovListen; /*用于侦听的重叠操作结构*/
HANDLE hCom; /*端口句柄*/
CRITICAL_SECTION cs; /* 同步临界区*/
short nFlowCtrl; /*流控制模式*/
short nAckChar; /*回应字符*/
short nParity; /*校验方式*/
short nStopBits; /*停止位*/
short nByteSize; /*位长*/
short nReadTimeoutPerByte; /*读每字节超时参数*/
short nWriteTimeoutPerByte; /*写每字节超时参数*/
long nListenTimeout; /*侦听超时*/
long nBaudRate; /*波特率*/
long nInQueue; /*输入缓冲区大小*/
long nOutQueue; /*输出缓冲区大小*/
TCHAR szPort[10]; /*端口*/
}CommDelta;
/*定义线程操作结构*/
typedef struct _OperaParam
{
HANDLE hCom; /*串口句柄*/
LPCRITICAL_SECTION pcs; /*临界区引用*/
DWORD dwDataBytes; /*请求操作字节数*/
DWORD dwOperaBytes; /*实际操作字节数*/
BYTE* data; /*读写数据指针*/
short nRetCode;
}OperaParam;
#define GETCOMMDELTA(hWnd) ((CommDelta*)GetWindowLong(hWnd,GWL_USERDATA))
#define SETCOMMDELTA(hWnd,ptd) SetWindowLong(hWnd,GWL_USERDATA,(LONG)ptd)
LRESULT CALLBACK CommCtrlProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void COM_Paint(HWND hWnd,HDC hDC);
int COM_SendSign(HWND hWnd,UINT sign, WPARAM wParam,LPARAM lParam);
BOOL COM_Active(HWND hWnd,BOOL bActive);
long COM_SendData(HWND hWnd,long size,BYTE* data);
long COM_ReciveData(HWND hWnd,long size,BYTE* data);
DWORD WINAPI ListenProc(LPVOID lpParam);
DWORD WINAPI WriteProc(LPVOID lpParam);
void* _CommAlloc(long size);
void _CommFree(void* data);
ATOM RegisterCommCtrlClass(HINSTANCE hInstance)
{
WNDCLASS wcex;
#ifdef _WINDOWS
wcex.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
#else
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
#endif
wcex.lpfnWndProc = (WNDPROC)CommCtrlProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = COMMCTRLCLASS;
return RegisterClass(&wcex);
}
LRESULT CALLBACK CommCtrlProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
PAINTSTRUCT ps;
int n;
switch(message)
{
case WM_CREATE:
ptd = (CommDelta*)calloc(1,sizeof(CommDelta));
ptd->hWnd = hWnd;
/*默认参数配置*/
lstrcpy(ptd->szPort,_T("COM1"));
ptd->nReadTimeoutPerByte = ptd->nWriteTimeoutPerByte = 10;
ptd->nListenTimeout = 5000;
ptd->nFlowCtrl = 0;
ptd->nAckChar = 0;
ptd->nParity = 0;
ptd->nStopBits = 1;
ptd->nByteSize = 8;
ptd->nBaudRate = 1200;
ptd->bReady = FALSE;
ptd->bActive = FALSE;
ptd->hCom = INVALID_HANDLE_VALUE;
ptd->hListen = NULL;
InitializeCriticalSection(&ptd->cs);
SETCOMMDELTA(hWnd,ptd);
break;
case WM_DESTROY:
if(ptd->bActive)
SendMessage(hWnd,COM_SETACTIVE,(WPARAM)FALSE,0);
DeleteCriticalSection(&ptd->cs);
free(ptd);
break;
case WM_PAINT:
if(GetUpdateRect(hWnd,NULL,TRUE))
{
BeginPaint(hWnd,&ps);
COM_Paint(hWnd,ps.hdc);
EndPaint(hWnd,&ps);
}
case COM_SETPORT:
if(lParam)
{
n = _tcslen((TCHAR*)lParam);
n = (n < 9)? n : 9;
_tcsncpy(ptd->szPort,(TCHAR*)lParam,n);
(ptd->szPort)[n] = _T('\0');
}
return 0;
case COM_GETPORT:
if(lParam)
{
n = _tcslen(ptd->szPort);
n = (n < (int)wParam)? n : (int)wParam;
_tcsncpy((TCHAR*)lParam,ptd->szPort,n);
((TCHAR*)lParam)[n] = _T('\0');
}
return 0;
case COM_GETBAUDRATE:
return (LRESULT)ptd->nBaudRate;
case COM_SETBAUDRATE:
ptd->nBaudRate = (long)wParam;
return 0;
case COM_GETBYTESIZE:
return (LRESULT)ptd->nByteSize;
case COM_SETBYTESIZE:
ptd->nByteSize = (short)wParam;
return 0;
case COM_GETSTOPBITS:
return (LRESULT)ptd->nStopBits;
case COM_SETSTOPBITS:
ptd->nStopBits = (short)wParam;
return 0;
case COM_GETPARITY:
return (LRESULT)ptd->nParity;
case COM_SETPARITY:
ptd->nParity = (short)wParam;
return 0;
case COM_GETFCTRL:
return ptd->nFlowCtrl;
case COM_SETFCTRL:
ptd->nFlowCtrl = (short)wParam;
return 0;
case COM_GETTIMEOUTS:
return (LRESULT)MAKEWPARAM((WORD)ptd->nReadTimeoutPerByte,(WORD)ptd->nWriteTimeoutPerByte);
case COM_SETTIMEOUTS:
ptd->nReadTimeoutPerByte = (short)LOWORD(wParam);
ptd->nWriteTimeoutPerByte = (short)HIWORD(wParam);
return 0;
case COM_GETACKCHAR:
return (LRESULT)ptd->nAckChar;
case COM_SETACKCHAR:
ptd->nAckChar = (short)wParam;
return 0;
case COM_GETLISTIMER:
return (LRESULT)ptd->nListenTimeout;
case COM_SETLISTIMER:
ptd->nListenTimeout = (long)wParam;
return 0;
case COM_SETQUEUE:
ptd->nInQueue = (long)wParam;
ptd->nOutQueue = (long)lParam;
return 0;
case COM_GETACTIVE:
return (LRESULT)ptd->bActive;
case COM_SETACTIVE:
return (LRESULT)COM_Active(hWnd,(BOOL)wParam);
case COM_SETDATA:
return (LRESULT)COM_SendData(hWnd,(long)wParam,(BYTE*)lParam);
case COM_GETDATA:
return (LRESULT)COM_ReciveData(hWnd,(long)wParam,(BYTE*)lParam);
case COM_POSTBREAK:
COM_SendSign(hWnd,NC_COMMBREAK,0,0);
return 0;
case COM_POSTERROR:
COM_SendSign(hWnd,NC_COMMERROR,wParam,lParam);
if(lParam)
_CommFree((void*)lParam);
return 0;
case COM_POSTMONITOR:
COM_SendSign(hWnd,NC_COMMMONITOR,wParam,lParam);
if(lParam)
_CommFree((void*)lParam);
return 0;
case COM_POSTACK:
COM_SendSign(hWnd,NC_COMMACK,(long)wParam,0);
return 0;
case COM_POSTRECIVE:
COM_SendSign(hWnd,NC_COMMRECIVE,(long)wParam,0);
return 0;
case COM_POSTSENT:
COM_SendSign(hWnd,NC_COMMSENT,(long)wParam,0);
return 0;
case COM_QUERYSEND:
return (LRESULT)ptd->bReady;
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
void* _CommAlloc(long size)
{
return (TCHAR*)GlobalLock(GlobalAlloc(GHND,size));
}
void _CommFree(void* data)
{
GlobalUnlock((HGLOBAL)data);
GlobalFree((HGLOBAL)data);
}
void _FormatCommError(DWORD errcode,TCHAR* buf)
{
switch(errcode)
{
case CE_PARAM:
_tcscpy(buf,ERROR_PARAM);
break;
case CE_BREAK:
_tcscpy(buf,ERROR_BREAK);
break;
case CE_FRAME:
_tcscpy(buf,ERROR_FRAME);
break;
case CE_IOE:
_tcscpy(buf,ERROR_IOE);
break;
case CE_OVERRUN:
_tcscpy(buf,ERROR_OVERRUN);
break;
case CE_RXOVER:
_tcscpy(buf,ERROR_RXOVER);
break;
case CE_RXPARITY:
_tcscpy(buf,ERROR_RXPARITY);
break;
case CE_TXFULL:
_tcscpy(buf,ERROR_TXFULL);
break;
default:
_tcscpy(buf,ERROR_UNKNOWN);
break;
}
}
DWORD _InternalRead(HWND hWnd,DWORD size, void *buf)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
DWORD dwOperaBytes = 0;
if(ptd->hCom == INVALID_HANDLE_VALUE)
return 0;
ReadFile(ptd->hCom,buf,size,&dwOperaBytes,NULL);
return dwOperaBytes;
}
BOOL _InternalOpen(HWND hWnd)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
TCHAR szFile[20];
DCB dcb;
COMMTIMEOUTS to;
TCHAR* mem;
_stprintf(szFile,_T("\\\\.\\%s"),ptd->szPort);
/*打开端口文件*/
ptd->hCom = CreateFile(szFile,GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,NULL);
if(ptd->hCom == INVALID_HANDLE_VALUE)
return FALSE;
/*配置端口参数*/
memset((void*)&dcb,0,sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
GetCommState(ptd->hCom,&dcb);
switch(ptd->nBaudRate)
{
case 110:
dcb.BaudRate = CBR_110;
break;
case 300:
dcb.BaudRate = CBR_300;
break;
case 600:
dcb.BaudRate = CBR_600;
break;
case 1200:
dcb.BaudRate = CBR_1200;
break;
case 2400:
dcb.BaudRate = CBR_2400;
break;
case 4800:
dcb.BaudRate = CBR_4800;
break;
case 9600:
dcb.BaudRate = CBR_9600;
break;
case 14400:
dcb.BaudRate = CBR_14400;
break;
case 19200:
dcb.BaudRate = CBR_19200;
break;
case 38400:
dcb.BaudRate = CBR_38400;
break;
case 56000:
dcb.BaudRate = CBR_56000;
break;
case 57600 :
dcb.BaudRate = CBR_57600;
break;
case 115200 :
dcb.BaudRate = CBR_115200;
break;
case 128000 :
dcb.BaudRate = CBR_128000;
break;
case 256000 :
dcb.BaudRate = CBR_256000;
break;
default:
ptd->nBaudRate = 1200;
dcb.BaudRate = CBR_1200;
}
switch(ptd->nByteSize)
{
case 5:
case 6:
case 7:
case 8:
dcb.ByteSize = (BYTE)ptd->nByteSize;
break;
default:
ptd->nByteSize = 8;
dcb.ByteSize = 8;
}
switch(ptd->nStopBits)
{
case STOPBITS_ONE:
dcb.StopBits = ONESTOPBIT;
break;
case STOPBITS_TWO:
dcb.StopBits = TWOSTOPBITS;
break;
case STOPBITS_ONEHALF:
dcb.StopBits = ONE5STOPBITS;
break;
default:
ptd->nStopBits = STOPBITS_ONE;
dcb.StopBits = ONESTOPBIT;
break;
}
switch(ptd->nParity)
{
case PY_NONE:
dcb.Parity = NOPARITY;
break;
case PY_EVEN:
dcb.Parity = EVENPARITY;
break;
case PY_ODD:
dcb.Parity = ODDPARITY;
break;
case PY_MARK:
dcb.Parity = MARKPARITY;
break;
case PY_SPACE:
dcb.Parity = SPACEPARITY;
break;
default:
ptd->nParity = PY_NONE;
dcb.Parity = NOPARITY;
break;
}
switch(ptd->nFlowCtrl)
{
case FLOWCTRL_NONE:
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
break;
case FLOWCTRL_HARD:
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fOutxDsrFlow = TRUE;
dcb.fOutxCtsFlow = TRUE;
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
case FLOWCTRL_SOFT:
dcb.fInX = TRUE;
dcb.fOutX = TRUE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
break;
default:
ptd->nFlowCtrl = FLOWCTRL_NONE;
dcb.fInX = FALSE;
dcb.fOutX = FALSE;
dcb.fOutxDsrFlow = FALSE;
dcb.fOutxCtsFlow = FALSE;
dcb.fDtrControl = DTR_CONTROL_ENABLE;
dcb.fRtsControl = RTS_CONTROL_ENABLE;
break;
}
if(ptd->nAckChar)
dcb.EvtChar = (char)ptd->nAckChar;
if(!SetCommState(ptd->hCom,&dcb))
{
mem = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
_FormatCommError(CE_PARAM,mem);
PostMessage(hWnd,COM_POSTERROR,(WPARAM)_tcslen(mem),(LPARAM)mem);
}
GetCommTimeouts(ptd->hCom,&to);
to.ReadTotalTimeoutConstant = 500;
to.WriteTotalTimeoutConstant = 500;
to.ReadTotalTimeoutMultiplier = ptd->nReadTimeoutPerByte;
to.WriteTotalTimeoutMultiplier = ptd->nWriteTimeoutPerByte;
if(!SetCommTimeouts(ptd->hCom,&to))
{
mem = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
_FormatCommError(CE_PARAM,mem);
PostMessage(hWnd,COM_POSTERROR,(WPARAM)_tcslen(mem),(LPARAM)mem);
}
return TRUE;
}
BOOL _InternalClose(HWND hWnd)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
if(ptd->hCom != INVALID_HANDLE_VALUE)
{
CloseHandle(ptd->hCom);
}
ptd->hCom = INVALID_HANDLE_VALUE;
return TRUE;
}
BOOL COM_Active(HWND hWnd,BOOL newVal)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
if(newVal)
{
if(ptd->bActive)
return TRUE;
/*打开端口*/
if(!_InternalOpen(hWnd))
return FALSE;
ptd->ovListen.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
ptd->bActive = TRUE;
/*创建侦听线程*/
ptd->hListen = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ListenProc,(LPVOID)ptd,0,&ptd->dwListen);
if(ptd->hListen == NULL)
{
_InternalClose(hWnd);
CloseHandle(ptd->ovListen.hEvent);
memset((void*)&ptd->ovListen,0,sizeof(OVERLAPPED));
ptd->bActive = FALSE;
return FALSE;
}
ptd->bReady = TRUE;
Sleep(100); /*让线程运行*/
return TRUE;
}else
{
if(!ptd->bActive)
return TRUE;
EnterCriticalSection(&ptd->cs);
ptd->bActive = FALSE;
ptd->bReady = FALSE;
LeaveCriticalSection(&ptd->cs);
Sleep(100); /*让线程终止*/
/*等待侦听线程中止*/
WaitForSingleObject(ptd->ovListen.hEvent,ptd->nListenTimeout);
/*关闭线程句柄*/
TerminateThread(ptd->hListen,0);
CloseHandle(ptd->hListen);
CloseHandle(ptd->ovListen.hEvent);
memset((void*)&ptd->ovListen,0,sizeof(OVERLAPPED));
/*关闭端口*/
_InternalClose(hWnd);
return TRUE;
}
}
DWORD WINAPI ListenProc(LPVOID lpParam)
{
CommDelta* pCom = (CommDelta*)lpParam;
DWORD dwMask,dwError;
COMSTAT cst;
TCHAR* err;
CommMonitor* pm;
BOOL bActive;
EnterCriticalSection(&pCom->cs);
/*清空输入流和输出流*/
PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
switch(pCom->nFlowCtrl)
{
case FLOWCTRL_NONE: /*无流控制*/
dwMask = EV_BREAK | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
SetCommMask(pCom->hCom,dwMask);
break;
case FLOWCTRL_HARD: /*硬件控制*/
dwMask = EV_BREAK | EV_CTS | EV_DSR | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
SetCommMask(pCom->hCom,dwMask);
/*通知DCE可以输出数据*/
EscapeCommFunction(pCom->hCom,SETRTS);
EscapeCommFunction(pCom->hCom,SETDTR);
break;
case FLOWCTRL_SOFT: /*Xon/Xoff控制*/
dwMask = EV_BREAK | EV_RXCHAR | EV_RXFLAG | EV_ERR | EV_TXEMPTY;
SetCommMask(pCom->hCom,dwMask);
break;
default:
dwMask = EV_BREAK | EV_RXCHAR |EV_RXFLAG | EV_ERR | EV_TXEMPTY;
SetCommMask(pCom->hCom,dwMask);
break;
}
LeaveCriticalSection(&pCom->cs);
bActive = pCom->bActive;
while(bActive)
{
/*异步等待端口事件*/
dwMask = 0;
/*重制信号*/
ResetEvent(pCom->ovListen.hEvent);
EnterCriticalSection(&pCom->cs);
WaitCommEvent(pCom->hCom,&dwMask,&pCom->ovListen);
LeaveCriticalSection(&pCom->cs);
WaitForSingleObject(pCom->ovListen.hEvent,INFINITE);
switch(dwMask)
{
case EV_BREAK:
PostMessage(pCom->hWnd,COM_POSTBREAK,0,0);
break;
case EV_CTS:
case EV_DSR:
ClearCommError(pCom->hCom,&dwError,&cst);
pm = (CommMonitor*)_CommAlloc(sizeof(CommMonitor));
pm->bCTSHold = cst.fCtsHold;
pm->bDSRHold = cst.fDsrHold;
pm->bRLSDHold = cst.fRlsdHold;
pm->bXOFFHold = cst.fXoffHold;
pm->bXOFFSent = cst.fXoffSent;
pm->nInQueue = cst.cbInQue;
pm->nOutQueue = cst.cbOutQue;
PostMessage(pCom->hCom,COM_POSTMONITOR,(WPARAM)sizeof(CommMonitor),(LPARAM)pm);
break;
case EV_ERR:
ClearCommError(pCom->hCom,&dwError,&cst);
if(dwError == CE_RXOVER)
{
PurgeComm(pCom->hCom,PURGE_RXCLEAR);
}else if(dwError == CE_TXFULL)
{
PurgeComm(pCom->hCom,PURGE_TXCLEAR);
}else
{
PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
}
err = (TCHAR*)_CommAlloc(256 * sizeof(TCHAR));
_FormatCommError(dwError,err);
PostMessage(pCom->hWnd,COM_POSTERROR,(WPARAM)dwError,(LPARAM)err);
break;
case EV_RXFLAG:
case EV_RXCHAR:
ClearCommError(pCom->hCom,&dwError,&cst);
if(dwMask == EV_RXCHAR)
PostMessage(pCom->hWnd,COM_POSTRECIVE,(WPARAM)cst.cbInQue,0);
else
PostMessage(pCom->hWnd,COM_POSTACK,(WPARAM)cst.cbInQue,0);
break;
case EV_TXEMPTY:
EnterCriticalSection(&pCom->cs);
/*允许后继写入*/
pCom->bReady = TRUE;
LeaveCriticalSection(&pCom->cs);
PostMessage(pCom->hWnd,COM_POSTSENT,0,0); /*通知端口可写*/
break;
}
/*查询主线程终止信号*/
EnterCriticalSection(&pCom->cs);
bActive = pCom->bActive;
LeaveCriticalSection(&pCom->cs);
}
EnterCriticalSection(&pCom->cs);
/*通知DCE停止数据传输*/
if(pCom->nFlowCtrl == FLOWCTRL_HARD)
{
EscapeCommFunction(pCom->hCom,CLRRTS);
EscapeCommFunction(pCom->hCom,CLRDTR);
}
/*撤销输入流和输出流*/
PurgeComm(pCom->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
PurgeComm(pCom->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
LeaveCriticalSection(&pCom->cs);
/*通知主线程,本线程结束*/
SetEvent(pCom->ovListen.hEvent);
return 0;
}
DWORD WINAPI ReadProc(LPVOID lpParam)
{
OperaParam* pop = (OperaParam*)lpParam;
OVERLAPPED ov;
COMMTIMEOUTS to;
/*取读超时参数*/
GetCommTimeouts(pop->hCom,&to);
/*创建异步写事件*/
memset((void*)&ov,0,sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
/*端口异步读*/
EnterCriticalSection(pop->pcs);
ReadFile(pop->hCom,(void*)pop->data,pop->dwDataBytes,&(pop->dwOperaBytes),&ov);
LeaveCriticalSection(pop->pcs);
/*等待异步读结果*/
if(WAIT_OBJECT_0 != WaitForSingleObject(ov.hEvent,to.ReadTotalTimeoutConstant + to.ReadTotalTimeoutMultiplier * pop->dwDataBytes))
{
/*中止未完成的异步读*/
PurgeComm(pop->hCom,PURGE_RXABORT | PURGE_RXCLEAR);
pop->nRetCode = READ_TIMEOUTS;
}else
{
pop->nRetCode = READ_SUCCESS;
}
/*取读结果*/
GetOverlappedResult(pop->hCom,&ov,&(pop->dwOperaBytes),FALSE);
CloseHandle(ov.hEvent);
return 0;
}
DWORD WINAPI WriteProc(LPVOID lpParam)
{
OperaParam* pop = (OperaParam*)lpParam;
OVERLAPPED ov;
COMMTIMEOUTS to;
/*取写超时参数*/
GetCommTimeouts(pop->hCom,&to);
/*创建异步写事件*/
memset((void*)&ov,0,sizeof(OVERLAPPED));
ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
/*端口异步写*/
EnterCriticalSection(pop->pcs);
WriteFile(pop->hCom,(void*)pop->data,pop->dwDataBytes,&(pop->dwOperaBytes),&ov);
LeaveCriticalSection(pop->pcs);
/*等待异步写结果*/
if(WAIT_OBJECT_0 != WaitForSingleObject(ov.hEvent,to.WriteTotalTimeoutConstant + to.WriteTotalTimeoutMultiplier * pop->dwDataBytes))
{
/*中止未完成的异步写*/
PurgeComm(pop->hCom,PURGE_TXABORT | PURGE_TXCLEAR);
pop->nRetCode = WRITE_TIMEOUTS;
}else
{
pop->nRetCode = WRITE_SUCCESS;
}
/*取写结果*/
GetOverlappedResult(pop->hCom,&ov,&(pop->dwOperaBytes),FALSE);
CloseHandle(ov.hEvent);
return 0;
}
long COM_SendData(HWND hWnd,long size, BYTE* data)
{
CommDelta* pCom = GETCOMMDELTA(hWnd);
HANDLE hWrite;
DWORD dw;
OperaParam op;
if(!pCom->bActive)
return -1;
if(!pCom->bReady)
return -1;
//禁止后继写入
pCom->bReady = FALSE;
memset((void*)&op,0,sizeof(OperaParam));
op.hCom = pCom->hCom;
op.pcs = &pCom->cs;
op.data = data;
op.dwDataBytes = size;
/*异步写线程*/
hWrite = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteProc,(void*)&op,0,&dw);
if(hWrite)
{
/*等待线程结束*/
WaitForSingleObject(hWrite,INFINITE);
CloseHandle(hWrite);
}else
op.dwOperaBytes = -1;
return op.dwOperaBytes;
}
long COM_ReciveData(HWND hWnd,long size, BYTE* data)
{
CommDelta* pCom = GETCOMMDELTA(hWnd);
HANDLE hRead;
DWORD dw;
OperaParam op;
if(!pCom->bActive)
return -1;
memset((void*)&op,0,sizeof(OperaParam));
op.hCom = pCom->hCom;
op.pcs = &pCom->cs;
op.data = data;
op.dwDataBytes = size;
/*异步读线程*/
hRead = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadProc,(void*)&op,0,&dw);
if(hRead)
{
/*等待线程结束*/
WaitForSingleObject(hRead,INFINITE);
CloseHandle(hRead);
}else
op.dwOperaBytes = -1;
return op.dwOperaBytes;
}
int COM_SendSign(HWND hWnd,UINT sign, WPARAM wParam,LPARAM lParam)
{
CommDelta* ptd = GETCOMMDELTA(hWnd);
NMHDR_COMM hdr;
hdr.hwndFrom = hWnd;
hdr.idFrom = GetWindowLong(hWnd,GWL_ID);
hdr.code = sign;
hdr.wParam = wParam;
hdr.lParam = lParam;
return (int)SendMessage(GetParent(hWnd),WM_NOTIFY,hdr.idFrom,(LPARAM)&hdr);
}
void COM_Paint(HWND hWnd,HDC hDC)
{
RECT rt;
GetClientRect(hWnd,&rt);
DrawText(hDC,_T("EasyComm"),-1,&rt,DT_CENTER | DT_SINGLELINE | DT_VCENTER);
}
void InitCommControl(HINSTANCE hInstance)
{
HINSTANCE hInst = (hInstance)? hInstance : GetModuleHandle(NULL);
RegisterCommCtrlClass(hInst);
}
void UnInitCommControl(HINSTANCE hInstance)
{
HINSTANCE hInst = (hInstance)? hInstance : GetModuleHandle(NULL);
UnregisterClass(COMMCTRLCLASS,hInst);
}