⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 异步的com基类 serialport.cpp

📁 使用短信猫可以实现短信的群发
💻 CPP
字号:
// SerialPort.cpp: implementation of the CSerialPort class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "sms.h"
#include "SerialPort.h"

#include <Winreg.h> //RegEnumValue所在头文件
#include <atlbase.h> //CRegKey所在头文件


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSerialPort::CSerialPort()
{

}

CSerialPort::~CSerialPort()
{

}

//////////////////////////////////////////////////////////////////////////
//取得系统上的所有COM口
void CSerialPort::GetCOMList(vector<CString> & PortList)
{
	CRegKey RegKey;   
    int nCount = 0;   
	//CString * pNameList=new CString[5];
	//CString * pPortList=new CString[5];
    if(RegKey.Open(HKEY_LOCAL_MACHINE, "Hardware\\DeviceMap\\SerialComm") == ERROR_SUCCESS)   
    {   
        while(true)   
        {   
            char ValueName[_MAX_PATH];   
            unsigned char ValueData[_MAX_PATH];   
            DWORD nValueSize = _MAX_PATH;   
            DWORD nDataSize = _MAX_PATH;   
            DWORD nType;   
			
			//RegEnumValue函数的作用是,从被指定打开的注册表项中列举所有的值
			//这函数每调用一次就会拷贝一个索引值的名称和数据块
            if(::RegEnumValue(HKEY(RegKey), nCount, ValueName, &nValueSize, NULL, &nType, ValueData, &nDataSize) == ERROR_NO_MORE_ITEMS)   
            {   
                break;   
            }   
			
//              if(pNameList)   
//                  pNameList[nCount] = ValueName;   
// 			
//             if(pPortList)  
//                 pPortList[nCount] = ValueData;   
			CString temp=ValueData;
			PortList.push_back(temp);
			TRACE(PortList[nCount]+"\n");
            nCount++;   
        }
	}
}

BOOL CSerialPort::OpenCOMPort(CString sPort,int nBaudRate,int nByteSize,int nParity,int nStopBit)
{
	BOOL result=FALSE;
	//打开文件
	hCom=CreateFile((LPCSTR)(LPCTSTR(sPort)), //指定要找开或创建的文件 这里指定串口名或设置的路径
			GENERIC_READ|GENERIC_WRITE,		//提供读写方式
			0,								//这里设置共享方式,这里采用独占方式
			NULL,							//设置安全属性,我们采用默认的设置
			OPEN_EXISTING,					//指定打开一个已存在的文件,由于COM口在系统中被认为是一个以存在的文件 打开而不是创建
			FILE_ATTRIBUTE_NORMAL |FILE_FLAG_OVERLAPPED ,//FILE_ATTRIBUTE_NORMAL 属性 指明该文件不使用文件属性 FILE_FLAG_OVERLAPPED 标记指定使用重叠方式
			NULL );							//不需要参照模板文件

	if(INVALID_HANDLE_VALUE==hCom)			//如果打开COM口文件失改,将会返回INVALID_HANDLE_VALUE这个错误
	{
		TRACE("打开COM失败!");
		return FALSE;
	}

	//////////////////////////////////////////////////////////////////////////
	//清空异步读写参数
	memset(&m_OverlappedRead,0,sizeof(OVERLAPPED));
	memset(&m_OverlappedWrite,0,sizeof(OVERLAPPED));


	//////////////////////////////////////////////////////////////////////////
	//读取通信状态,并对特定属性进行修改
	DCB dcb;

	//通过GetCommState函数可获取指定通信端口的状态
	GetCommState(hCom,&dcb);   //取得打开COM口的状态
	dcb.BaudRate=nBaudRate;   //波特率
	dcb.ByteSize=nByteSize;  //字节大小
	dcb.Parity=nParity;     //奇偶校验
	dcb.StopBits=nStopBit; //停止位
	
	//通过dcb结构体来重置一下通信状态
	//SetCommState(hCom,&dcb);

	//////////////////////////////////////////////////////////////////////////
	//设置通信超时

	//设置通信超时信息结构体
	COMMTIMEOUTS commTimeouts;
	commTimeouts.ReadIntervalTimeout=100; // 读字符间隔超时时间: 100 ms
	commTimeouts.ReadTotalTimeoutConstant=500 ; // 基本的(额外的)读超时时间: 500 ms
	commTimeouts.ReadTotalTimeoutMultiplier=1; // 读操作时每字符的时间: 1 ms (n个字符总共为n ms)
	commTimeouts.WriteTotalTimeoutConstant=100; // 基本的(额外的)写超时时间: 100 ms
	commTimeouts.WriteTotalTimeoutMultiplier=1;// 写操作时每字符的时间: 1 ms (n个字符总共为n ms)

	//将超时信信息结构体的内容设置到指定的通信设备上去
	SetCommTimeouts(hCom,&commTimeouts);


	//获取信号句柄
	m_OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //创建事件,并将事件处理非激发状态,并且通过第二个参数使该事件使用手动重置
	m_OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);


	//////////////////////////////////////////////////////////////////////////
	//初始化通信设备的缓冲区

	//SetupComm函数来初始化一个指定通信设备的通信参数 通过句柄来指明要修改参数的设备
	//SetupComm(hCom/*设备的句柄*/ ,4096 /*输入缓冲区大小*/,1024 /*输出缓冲区大小*/);	

	if( !SetCommState(hCom,&dcb) || //通过dcb结构体来重置一下通信状态

		!SetupComm(hCom/*设备的句柄*/ ,4096 /*输入缓冲区大小*/,1024 /*输出缓冲区大小*/) ||

		!SetCommMask(hCom, EV_RXCHAR) || //为一个通信设备指定一组被监听的事件

		NULL == m_OverlappedRead.hEvent || //判断读事件是否创建成功

		NULL == m_OverlappedWrite.hEvent ) //判断写事件是否创建成功
	{
		DWORD dwError = GetLastError();                     //获取最后的错误信息
        if( m_OverlappedRead.hEvent != NULL )  CloseHandle( m_OverlappedRead.hEvent );
		if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
		CloseHandle(hCom);
		hCom=NULL;
		return FALSE;
	}
	//删除指定通信资源的输入和输出缓冲区中的所有字符
	PurgeComm(hCom,PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);


	TRACE("连接串口成功");
	return TRUE;
}
BOOL CSerialPort::CloseSerialPort()
{

	BOOL result=FALSE;
	if(NULL==hCom)
	{
		return TRUE;
	}
	//为一个通信设备指定一组被监听的事件
	SetCommMask(hCom,NULL);
	//SetEvent(m_OverlappedRead.hEvent);//将事件置为激发状态
	//SetEvent(m_OverlappedWrite.hEvent);//将事件置为激发状态
	if( NULL != m_OverlappedRead.hEvent) CloseHandle( m_OverlappedRead.hEvent);
	if( NULL != m_OverlappedWrite.hEvent) CloseHandle( m_OverlappedWrite.hEvent);
	result=CloseHandle(hCom);
	if(TRUE == result)
	{
		hCom=NULL;
	}
	return result;
}
BOOL CSerialPort::IsOpen()
{
	return hCom != INVALID_HANDLE_VALUE;
}
BOOL CSerialPort::Read(LPVOID buffer, DWORD bufferLength)
{
	if(!IsOpen())
	{
		return FALSE;
	}
	DWORD dwError;
	COMSTAT comStat;
	DWORD readLength=0;

	//这里的的作用是指,还没有执行ReadFile操作时,串口能接收的字节数
	ClearCommError( hCom, &dwError, &comStat ) ;//取得串设备的当前状和错误,并清除错误
	readLength = min( (DWORD) bufferLength, comStat.cbInQue ) ;

	if(ClearCommError(hCom,&dwError,&comStat) && dwError>0)
	{
		//清除通信源的输入输出缓冲区中的所有字符
		PurgeComm(hCom,PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR);
		return FALSE;
	}

	if(readLength>0)
	{
		//对于异步方式要指定重叠结构,可不指定已读取节数  将读取操作跟m_OverlappedRead结构体中的hEvent事件关连起来
		if(!::ReadFile(hCom,buffer,bufferLength,&readLength,&m_OverlappedRead))
		{
			//如果返回的错误是IO挂起错误
			if(GetLastError()==ERROR_IO_PENDING)
			{
				//等侍读取事件变成激发状态后才返回 只有当文件读取完成后,与之关连的事件会从非激发状态变成激发状态
				if(!WaitForSingleObject(m_OverlappedRead.hEvent,INFINITE))
				{
					//将事件置成非激发状态
					ResetEvent(m_OverlappedRead.hEvent);
					if(GetLastError()!=WAIT_OBJECT_0)
					{
						return FALSE;
					}

				}

// 				//检索指定文件的重叠操作的结果 成功返回非0值
// 				while(!GetOverlappedResult(hCom,&m_OverlappedRead,&readLength,TRUE))
// 				{
// 					//判断IO操作是否完成 即文件是否读取完成
// 					if(GetLastError()!=ERROR_IO_INCOMPLETE)
// 					{
// 						//用来接收一个通信错误信息和一个通信设备的当前状态报表
// 						ClearCommError(hCom,&dwError,&comStat);
// 						break;
// 					}
// 				}

			}
			else
			{		
				//当该函数被调用后,将清除设备的错误标记,以允许附加输入输出操作
				//同时返回一个通信错误信息和一个通信设备的当前状态报表
				ClearCommError(hCom,&dwError,&comStat);
				return FALSE;
			}
		}
	}
	return TRUE;
}

BOOL CSerialPort::Write(LPVOID buffer, DWORD bufferLength)
{
	//判断是否连接
	if(!IsOpen())
            return FALSE;

	DWORD readLength;
	DWORD dwError;
	COMSTAT comStat;

	//对于异步方式要指定重叠结构,可不指定已写入字节数  将写入操作跟m_OverlappedWrite结构体中的hEvent事件关连起来
	if(!WriteFile(hCom,buffer,bufferLength,&readLength,&m_OverlappedWrite))
	{
		//判断最近一次错误信息是不是I/O挂起错误
		if(GetLastError()==ERROR_IO_PENDING)
		{

			//等侍读取事件变成激发状态后才返回 只有当文件读取完成后,与之关连的事件会从非激发状态变成激发状态
			if(!WaitForSingleObject(m_OverlappedWrite.hEvent,INFINITE))
			{

				if(GetLastError()!=WAIT_OBJECT_0)
				{
					return FALSE;
				}
				//将事件置成非激发状态			
				ResetEvent(m_OverlappedWrite.hEvent);
			}
// 			while(!GetOverlappedResult(hCom,&m_OverlappedWrite,&readLength,TRUE))
// 			{
// 				//判断IO操作是否完成 即文件是否读取完成
// 				if(GetLastError()!=ERROR_IO_INCOMPLETE) //ERROR_IO_INCOMPLETE 为未完成IO错误
// 				{
// 					ClearCommError(hCom,&dwError,&comStat);
// 					break;
// 				}
// 			}
		}
		else
		{
			ClearCommError(hCom,&dwError,&comStat);
			return FALSE;
		}
	}
	return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -