不能得到有效的串口句柄
我是用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,不知道有没有关系。

解决方案 »

  1.   

    //初始化COM端口
    // this->Open(m_bOverlap);这里如果不去掉好象会初始化两次。
    什么意思?
    应该说你所说的问题不会出现,除非在运行CCOMSerialDlg::Open(BOOL bOverlap)
    前串口已被打开,并且没有关闭。你把共享模式改一下,试一试。
      

  2.   

    不应该会这样吧,你跟踪一下看看,也许你说的“this->Open(m_bOverlap);这里如果不去掉好象会初始化两次,”如果这是真的,那一定有问题,第二次肯定会返回打开失败,传口没有共享模式一说,它是独占设备,打开串口没有关闭之前别的程序都不能打开设备,
      

  3.   

    有这句“this->Open(m_bOverlap);这里如果不去掉好象会初始化两次,”时 ,确实会出现两次“完了”,不知道怎么回事。
      

  4.   

    代码拿来我给你调
    [email protected]
      

  5.   

    xp和2k是不能采用同步的吧,
    串口多是异步重叠读的方式的,我做过几个串口的程序,也是用api的。
      

  6.   

    是你打开不成功,所以返回INVALID_HANDLE_VALUE
    见大家对串行口编程都这么烦恼
    我贴一个类出来给大家参考参考
      

  7.   

    // Serial.h#ifndef __SERIAL_H__
    #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
      

  8.   

    // Serial.cpp#include "stdafx.h"
    #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 );}
      

  9.   

    不路:你给的程序好象不能编译!还差一个stdafx.h文件。我先仔细看看再说 。现在我把我的主要代码贴出来给大家分析以下:HCURSOR CCOMSerialDlg::OnQueryDragIcon()
    {
    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);
    }
      

  10.   

    你的代码其实没有什么问题,但是因为你用的时候打开的是COM0口,而计算机上是没有COM0口的,不信你可以把串口号设成1,肯定成功,所以你的程序中最好把m_nCom初始化设成0,另外程序本身还有许多其它问题,
    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分,打字好累,而且打了两遍(第一遍没发上来)
      

  11.   

    加分没有问题。结帐的时候一定加。
    但是好象还是不行,你用我的源程序可以发送数据吗?我现在执行文件后,点“发送”还是弹出现原来的“完了”,也就是无效句柄。
    还有UpdateData(TURE)应该加在哪里。第二点也不明白什么意思?第5点的nCom指 的是hCom吗??
    这样太慢了,我后天就要用了。能用QQ聊吗。我的号是30030707。我现在整天在线上。:)
      

  12.   

    用别人的机子还是出现一样的问题,还有现在用同步方式发送的话会程序会死掉的。
    后来我把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);
    还是不行呀。会得到无效句柄,对于串口来说到底有那几种情况呢??
      

  13.   

    在亚,你联系我的QQ好了。 30030707,我晚上10:30分以前都是在的,你把你调通的给我看看吧([email protected]),我一直得不到有效句柄,今天会一直在线上等你的。
      

  14.   

    (2)  问题:在开始编写程序时我在OnTransfer()函数中是这样写的:
    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);
    }