不能得到有效的串口句柄
我是用API编的,前面的程序是这样的:
void CCOMSerialDlg::OnTransfer()
{ // 获得用户指定的参数
this->UpdateData(); //初始化COM端口
// this->Open(m_bOverlap);这里如果不去掉好象会初始化两次。 //分别采用同步异步模式
if(m_bOverlap)
{ this->Sync();}
else
{this->Async();}}
HANDLE CCOMSerialDlg::Open(BOOL bOverlap)
{
DWORD dwFlags=bOverlap?FILE_FLAG_OVERLAPPED:0;
CString strCom;
strCom.Format("COM%d",m_nCom+1);
MessageBox(strCom);
//打开指定的串口
HANDLE hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,dwFlags,NULL); if (hCom == INVALID_HANDLE_VALUE)
{AfxMessageBox(_T("完了"));
return NULL;}
在这里我加上// ASSERT(hCom!=INVALID_HANDLE_VALUE);也提示错误 //获得串口的配置信息
char buffer[sizeof(COMMCONFIG)+1000];
LPCOMMCONFIG pCfg=(LPCOMMCONFIG)buffer;
DWORD dwSize=sizeof(buffer);
if(!::GetCommConfig(hCom,pCfg,&dwSize))
{
AfxMessageBox(_T("读取串口配置失败!"));
::CloseHandle(hCom);
return NULL;
}
结果运行程序后弹出“完了”呵呵。
我的系统是xp,不知道有没有关系。
我是用API编的,前面的程序是这样的:
void CCOMSerialDlg::OnTransfer()
{ // 获得用户指定的参数
this->UpdateData(); //初始化COM端口
// this->Open(m_bOverlap);这里如果不去掉好象会初始化两次。 //分别采用同步异步模式
if(m_bOverlap)
{ this->Sync();}
else
{this->Async();}}
HANDLE CCOMSerialDlg::Open(BOOL bOverlap)
{
DWORD dwFlags=bOverlap?FILE_FLAG_OVERLAPPED:0;
CString strCom;
strCom.Format("COM%d",m_nCom+1);
MessageBox(strCom);
//打开指定的串口
HANDLE hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,dwFlags,NULL); if (hCom == INVALID_HANDLE_VALUE)
{AfxMessageBox(_T("完了"));
return NULL;}
在这里我加上// ASSERT(hCom!=INVALID_HANDLE_VALUE);也提示错误 //获得串口的配置信息
char buffer[sizeof(COMMCONFIG)+1000];
LPCOMMCONFIG pCfg=(LPCOMMCONFIG)buffer;
DWORD dwSize=sizeof(buffer);
if(!::GetCommConfig(hCom,pCfg,&dwSize))
{
AfxMessageBox(_T("读取串口配置失败!"));
::CloseHandle(hCom);
return NULL;
}
结果运行程序后弹出“完了”呵呵。
我的系统是xp,不知道有没有关系。
// this->Open(m_bOverlap);这里如果不去掉好象会初始化两次。
什么意思?
应该说你所说的问题不会出现,除非在运行CCOMSerialDlg::Open(BOOL bOverlap)
前串口已被打开,并且没有关闭。你把共享模式改一下,试一试。
[email protected]
串口多是异步重叠读的方式的,我做过几个串口的程序,也是用api的。
见大家对串行口编程都这么烦恼
我贴一个类出来给大家参考参考
#define __SERIAL_H__#define FC_DTRDSR 0x01
#define FC_RTSCTS 0x02
#define FC_XONXOFF 0x04
#define ASCII_BEL 0x07
#define ASCII_BS 0x08
#define ASCII_LF 0x0A
#define ASCII_CR 0x0D
#define ASCII_XON 0x11
#define ASCII_XOFF 0x13class CSerial
{public:
CSerial();
~CSerial(); BOOL Open( int nPort = 2, int nBaud = 9600 );
BOOL Close( void ); int ReadData( void *, int );
int SendData( const char *, int );
int ReadDataWaiting( void ); BOOL IsOpened( void ){ return( m_bOpened ); }protected:
BOOL WriteCommByte( unsigned char ); HANDLE m_hIDComDev;
OVERLAPPED m_OverlappedRead;
OVERLAPPED m_OverlappedWrite;
BOOL m_bOpened;};#endif
#include "Serial.h"
CSerial::CSerial()
{ memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );
m_hIDComDev = NULL;
m_bOpened = FALSE;}CSerial::~CSerial()
{ Close();}
BOOL CSerial::Open( int nPort, int nBaud )
{ if( m_bOpened ) return( TRUE ); char szPort[15];
char szComParams[50];
DCB dcb; wsprintf( szPort, "COM%d", nPort );
m_hIDComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hIDComDev == NULL ) return( FALSE ); memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) ); COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts( m_hIDComDev, &CommTimeOuts ); wsprintf( szComParams, "COM%d:%d,n,8,1", nPort, nBaud ); m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); dcb.DCBlength = sizeof( DCB );
GetCommState( m_hIDComDev, &dcb );
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
unsigned char ucSet;
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_DTRDSR ) != 0 );
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_RTSCTS ) != 0 );
ucSet = (unsigned char) ( ( FC_RTSCTS & FC_XONXOFF ) != 0 );
if( !SetCommState( m_hIDComDev, &dcb ) ||
!SetupComm( m_hIDComDev, 10000, 10000 ) ||
m_OverlappedRead.hEvent == NULL ||
m_OverlappedWrite.hEvent == NULL ){
DWORD dwError = GetLastError();
if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
CloseHandle( m_hIDComDev );
return( FALSE );
} m_bOpened = TRUE; return( m_bOpened );}BOOL CSerial::Close( void )
{ if( !m_bOpened || m_hIDComDev == NULL ) return( TRUE ); if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
CloseHandle( m_hIDComDev );
m_bOpened = FALSE;
m_hIDComDev = NULL; return( TRUE );}BOOL CSerial::WriteCommByte( unsigned char ucByte )
{
BOOL bWriteStat;
DWORD dwBytesWritten; bWriteStat = WriteFile( m_hIDComDev, (LPSTR) &ucByte, 1, &dwBytesWritten, &m_OverlappedWrite );
if( !bWriteStat && ( GetLastError() == ERROR_IO_PENDING ) ){
if( WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 ) ) dwBytesWritten = 0;
else{
GetOverlappedResult( m_hIDComDev, &m_OverlappedWrite, &dwBytesWritten, FALSE );
m_OverlappedWrite.Offset += dwBytesWritten;
}
} return( TRUE );}int CSerial::SendData( const char *buffer, int size )
{ if( !m_bOpened || m_hIDComDev == NULL ) return( 0 ); DWORD dwBytesWritten = 0;
int i;
for( i=0; i<size; i++ ){
WriteCommByte( buffer[i] );
dwBytesWritten++;
} return( (int) dwBytesWritten );}int CSerial::ReadDataWaiting( void )
{ if( !m_bOpened || m_hIDComDev == NULL ) return( 0 ); DWORD dwErrorFlags;
COMSTAT ComStat; ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat ); return( (int) ComStat.cbInQue );}int CSerial::ReadData( void *buffer, int limit )
{ if( !m_bOpened || m_hIDComDev == NULL ) return( 0 ); BOOL bReadStatus;
DWORD dwBytesRead, dwErrorFlags;
COMSTAT ComStat; ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );
if( !ComStat.cbInQue ) return( 0 ); dwBytesRead = (DWORD) ComStat.cbInQue;
if( limit < (int) dwBytesRead ) dwBytesRead = (DWORD) limit; bReadStatus = ReadFile( m_hIDComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );
if( !bReadStatus ){
if( GetLastError() == ERROR_IO_PENDING ){
WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );
return( (int) dwBytesRead );
}
return( 0 );
} return( (int) dwBytesRead );}
{
return (HCURSOR) m_hIcon;
}void CCOMSerialDlg::OnButton3()
{
// TODO: Add your control notification handler code here
OnOK();
}void CCOMSerialDlg::OnTransfer()
{
// TODO: Add your control notification handler code here
// 获得用户指定的参数
this->UpdateData(); //初始化COM端口
this->Open(m_bOverlap); //分别采用同步异步模式
if(m_bOverlap)
{ this->Sync();}
else
{this->Async();}}
HANDLE CCOMSerialDlg::Open(BOOL bOverlap)
{
DWORD dwFlags=bOverlap?FILE_FLAG_OVERLAPPED:0;
CString strCom;
strCom.Format("COM%d",m_nCom+1);
MessageBox(strCom);
//打开指定的串口
HANDLE hCom;
hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,0,
OPEN_EXISTING,dwFlags,NULL);// GetLastError();
// ASSERT(hCom!=INVALID_HANDLE_VALUE);
if (hCom == INVALID_HANDLE_VALUE)
{AfxMessageBox(_T("完了"));
return NULL;}
//获得串口的配置信息
char buffer[sizeof(COMMCONFIG)+1000];
LPCOMMCONFIG pCfg=(LPCOMMCONFIG)buffer;
DWORD dwSize=sizeof(buffer);
if(!::GetCommConfig(hCom,pCfg,&dwSize))
{
AfxMessageBox(_T("读取串口配置失败!"));
::CloseHandle(hCom);
return NULL;
} /* COMMCONFIG ComCfg;
DWORD dwSize=sizeof (ComCfg);
if(!::GetCommConfig(hCom,&ComCfg,&dwSize))
{
AfxMessageBox(_T("读取串口配置失败!"));
::CloseHandle(hCom);
return NULL;
}
*/
//获得当前的串口配置状态
DCB dcb;
if(!GetCommState(hCom,&dcb))
{
AfxMessageBox(_T("读取串口状态失败!"));
::CloseHandle(hCom);
return NULL;
} //设置奇偶校验方式
switch(m_nParity)
{
case 0:
//不校验
dcb.Parity=NOPARITY;
break;
case 1:
//奇校验
dcb.Parity=ODDPARITY;
break;
case 2:
//偶校验
dcb.Parity=EVENPARITY;
break;
case 3:
//MARK方式
dcb.Parity=MARKPARITY;
break;
case 4:
//SPACE方式
dcb.Parity=SPACEPARITY;
break;
}
//设置数据位格式
dcb.ByteSize=m_nData; //设置波特率
dcb.BaudRate=m_dwBaud; //设置停止位方式
switch(m_nStop)
{
case 0:
//停止位为1位
dcb.StopBits=ONESTOPBIT;
break;
case 1:
//停止位为1.5位
dcb.StopBits=ONE5STOPBITS;
break;
case 2:
//停止位为2位
dcb.StopBits=TWOSTOPBITS;
break;
} //设置灵敏度
dcb.fDsrSensitivity=FALSE;
//设置流控制方式
switch(m_nShake)
{
case 0:
//无流量控制
dcb.fOutxCtsFlow=FALSE;
dcb.fOutxDsrFlow=FALSE;
dcb.fOutX=FALSE;
dcb.fInX=FALSE;
break;
case 1:
//RTS控制,监视CTS信号
dcb.fOutxCtsFlow=TRUE;
dcb.fOutxDsrFlow=FALSE;
dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
dcb.fOutX=FALSE;
dcb.fInX=FALSE;
break;
case 2:
//DTR控制,监视CTS信号
dcb.fOutxCtsFlow=TRUE;
dcb.fOutxDsrFlow=FALSE;
dcb.fDtrControl=DTR_CONTROL_HANDSHAKE;
dcb.fOutX=FALSE;
dcb.fInX=FALSE;
break;
case 3:
//RTS控制,监视DSR信号
dcb.fOutxCtsFlow=FALSE;
dcb.fOutxDsrFlow=TRUE;
dcb.fRtsControl=RTS_CONTROL_HANDSHAKE;
dcb.fOutX=FALSE;
dcb.fInX=FALSE;
break;
case 4:
//DTR控制,监视DSR信号
dcb.fOutxCtsFlow=FALSE;
dcb.fOutxDsrFlow=TRUE;
dcb.fDtrControl=DTR_CONTROL_HANDSHAKE;
dcb.fOutX=FALSE;
dcb.fInX=FALSE;
break;
case 5:
//XON/XOFF控制方式
dcb.fOutxCtsFlow=FALSE;
dcb.fOutxDsrFlow=FALSE;
dcb.fOutX=TRUE;
dcb.fInX=TRUE;
dcb.XonChar=0x11;
dcb.XoffChar=0x13;
dcb.XoffLim=100;
dcb.XonLim=100;
break;
} //将设定的参数值用于该串口
if(!SetCommState(hCom,&dcb))
{
AfxMessageBox(_T("设置COM端口状态失败!"));
::CloseHandle(hCom);
return NULL;
} return hCom;
}
void CCOMSerialDlg::Async()
{
HANDLE hCom=Open(TRUE);
if(hCom!=NULL)
return; CEvent event(FALSE,TRUE);
OVERLAPPED overlapped;
//初始化OVERLAPPED结构
memset(&overlapped,sizeof(OVERLAPPED),'\0');
overlapped.hEvent=event; DWORD dwWritten=0;
CString strSend="The Data has been Sent!";
//异步发送
if(!WriteFile(hCom,(LPCTSTR)strSend,strSend.GetLength(),
&dwWritten,&overlapped))
{
if(GetLastError()!=ERROR_IO_PENDING)
{
AfxMessageBox(_T("写端口失败!"));
::CloseHandle(hCom);
return;
} WaitForSingleObject(event,INFINITE);
if(!::GetOverlappedResult(hCom,&overlapped,&dwWritten,TRUE))
{
AfxMessageBox(_T("等待异步操作结果时发生错误!"));
::CloseHandle(hCom);
return;
}
} char chRead[18];
DWORD dwRead=0;
//异步读取
if(!ReadFile(hCom,chRead,18,&dwRead,&overlapped))
{
if(GetLastError()!=ERROR_IO_PENDING)
{
AfxMessageBox(_T("读取端口失败!"));
::CloseHandle(hCom);
return;
} if(WaitForSingleObject(event,1888)!=WAIT_OBJECT_0)
{
AfxMessageBox(_T("读端口失败!"));
::CloseHandle(hCom);
return;
} if(!::GetOverlappedResult(hCom,&overlapped,&dwRead,TRUE))
{
AfxMessageBox(_T("等待异步操作结果时发生错误!"));
::CloseHandle(hCom);
return;
}
} DWORD dwMask=EV_TXEMPTY;
if(!SetCommMask(hCom,dwMask))
{
AfxMessageBox(_T("选择监听信号失败!"));
::CloseHandle(hCom);
return;
} //等待预定事件发生
if(!WaitCommEvent(hCom,&dwMask,&overlapped))
{
if(GetLastError()!=ERROR_IO_PENDING)
{
AfxMessageBox(_T("等待串口事件时出错!"));
::CloseHandle(hCom);
return;
}
} ::CloseHandle(hCom);}void CCOMSerialDlg::Sync()
{
HANDLE hCom=Open(FALSE);
if(hCom==NULL)
return; //获得调制解调器状态
DWORD dwModemStatus;
if(!GetCommModemStatus(hCom,&dwModemStatus))
{
AfxMessageBox(_T("读取MODEM状态失败!"));
::CloseHandle(hCom);
return;
} if(!SetupComm(hCom,9888,9888))
{
AfxMessageBox(_T("创建输入/输出缓冲区失败!"));
::CloseHandle(hCom);
return;
} //设定访问的超时值
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout=MAXDWORD;
timeouts.ReadTotalTimeoutConstant=0;
timeouts.ReadTotalTimeoutMultiplier=0;
timeouts.WriteTotalTimeoutConstant=0;
timeouts.WriteTotalTimeoutMultiplier=0; //发送一批数据
// CString strSend="The Data has been Sent!";
DWORD dwWritten=0;
if(!WriteFile(hCom,(LPCTSTR)strSend,strSend.GetLength(),&dwWritten,NULL))
{
AfxMessageBox(_T("向端口写数据失败!"));
::CloseHandle(hCom);
return;
} //选定"感兴趣"的事件、信号
if(!SetCommMask(hCom,EV_TXEMPTY))
{
AfxMessageBox(_T("选择监听信号失败!"));
::CloseHandle(hCom);
return;
} //停止对串口的写操作
if(!PurgeComm(hCom,PURGE_TXABORT))
{
AfxMessageBox(_T("停止写端口操作时发生错误!"));
::CloseHandle(hCom);
return;
} char chRead[18];
DWORD dwRead=0;
if(!ReadFile(hCom,chRead,18,&dwRead,NULL))
{
AfxMessageBox(_T("从串口读取数据失败!"));
::CloseHandle(hCom);
return;
} //停止对串口的写操作
if(!PurgeComm(hCom,PURGE_RXABORT))
{
AfxMessageBox(_T("停止读端口操作时发生错误!"));
::CloseHandle(hCom);
return;
} //将缓冲区中的数据发送到串口
if(!FlushFileBuffers(hCom))
{
AfxMessageBox(_T("处理缓冲数据时发生错误!"));
::CloseHandle(hCom);
return;
} ::CloseHandle(hCom);
}
1 在传递界面值给程序时(DCB)应该先刷新界面数据到程序变量UpdateData(TRUE),
2 还有要注意默认的DCB设置,因为假如界面没有设置DCB数据时,调用SetCommState(hCom,&dcb)就会失败"设置COM端口状态失败!"
3 你的同步和异步的调用正好弄反了应该把
if(m_bOverlap)
{ this->Sync();}
else
{this->Async();}
改成
if(m_bOverlap)
{ this->ASync();}
else
{this->sync();}4 因为你的异步和同步函数里面已经有Open函数了,所以在OnTransfer中不应该在有this->Open(m_bOverlap);
5 nCom应该设置成全局的,这样就不容易出错了6 看上去还有许多BUG因为我没有串口设备做实验,所以也不知道另外多加点分吧,我现在才看到,原来这个问题只有20分,打字好累,而且打了两遍(第一遍没发上来)
但是好象还是不行,你用我的源程序可以发送数据吗?我现在执行文件后,点“发送”还是弹出现原来的“完了”,也就是无效句柄。
还有UpdateData(TURE)应该加在哪里。第二点也不明白什么意思?第5点的nCom指 的是hCom吗??
这样太慢了,我后天就要用了。能用QQ聊吗。我的号是30030707。我现在整天在线上。:)
后来我把hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,dwFlags,NULL);
改成hCom=::CreateFile(“COM1”,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,dwFlags,NULL);
还是不行呀。会得到无效句柄,对于串口来说到底有那几种情况呢??
void CCOMSerialDlg::OnTransfer()
{
// 获得用户指定的参数
this->UpdateData(TURE); //初始化COM端口
this->Open(m_bOverlap); //分别采用同步异步模式
if(m_bOverlap)
{ this->Async();}//异步模式
else
{this->Sync();}
//计算发送的字节数
LONG lByte=m_strSend.GetLength()*2;
CString str;
str.Format(_T("%ld"),lByte);
m_SendByte.SetWindowText("发送字节数:"+str);
}
但是我在Async()和Sync()函数还有这样两句代码:
Open(TRUE)和Open(FALSE)
这样在程序运行的时候,Open()函数被调用两次,串口也被打开两次,由于串口是不可共享设备,同一时间只有一个进程能够使用它,所以出现错误。这是一个做串行通信程序常常出现的问题,必须注意,在打开串口前确定串口没有被使用。
解决方法:最后我把OnTransfer()函数中的代码改成如下:
void CCOMSerialDlg::OnTransfer()
{
// 获得用户指定的参数
if(!this->UpdateData(TRUE))
return; //如果数据不符合规范则不打开端口操作
//分别采用同步异步模式
if(m_bOverlap)
{ this->Async();}//异步模式
else
{this->Sync();}
//计算发送的字节数
LONG lByte=m_strSend.GetLength()*2;
CString str;
str.Format(_T("%ld"),lByte);
m_SendByte.SetWindowText("发送字节数:"+str);
}