【问题标题】:WaitCommEvent Fails Invalid Parameter on Second PassWaitCommEvent 在第二次通过时失败无效参数
【发布时间】:2011-05-16 16:54:37
【问题描述】:

我的应用程序使用带有重叠事件的串行 I/O。出于某种原因,::WaitCommEvent 在与ERROR_INVALID_PARAMETER 的第二次循环中始终失败。如果有人可以解释我需要做的不同的事情,将不胜感激。我的串口初始化/打开代码和线程函数如下。需要注意的是,init/open 代码是在线程函数启动之后执行的,这就是调用::WaitForSingleObject 的目的。

此外,我想知道像 ::WaitForSingleObject( pobjSerialPort->m_hSerialPort, INFINITE ); 这样的东西是否可以作为确定串行端口何时打开的非阻塞方式有效。

串口初始化:

DWORD CSerialPort::Open( const wchar_t * portName )
{
    DCB dcb = {0};
    DWORD dwError = ERROR_SUCCESS;

    do
    {
        if ( this->IsOpen() != FALSE )
        {
            TRACE(_T("CSerialPort::Open : Warning: Attempted to re-open serial port that is already open.\r\n"));
            continue;
        }

        // Overwrite port name if specified.
        if ( portName != NULL )
        {
            this->m_pwcPortName.clear();
            this->m_pwcPortName.append( SP_NAME_PREFIX );
            this->m_pwcPortName.append( portName );
        }

        ASSERT(this->m_pwcPortName.length() > 0);

        // Open the serial port.
        if ( (this->m_hSerialPort = ::CreateFile(
            m_pwcPortName.c_str(),          // Formatted serial port name
            GENERIC_READ | GENERIC_WRITE,   // Access: Read and write
            0,                              // Share: No sharing
            NULL,                           // Security: None
            OPEN_EXISTING,                  // COM port already exists
            FILE_FLAG_OVERLAPPED,           // Asynchronous I/O
            NULL                            // No template file for COM port
            )) == INVALID_HANDLE_VALUE )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to get the handle to the serial port.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Initialize the DCB structure with COM port parameters.
        if ( !::BuildCommDCB( _T("baud=38400 parity=N data=8 stop=1"), &dcb ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to build the DCB structure.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Set the serial port communications events mask.
        if ( !::SetCommMask( this->m_hSerialPort, SP_COMM_MASK ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to set comm. events to be monitored.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Set serial port parameters.
        if ( !::SetCommState( this->m_hSerialPort, &dcb ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to set the comm state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Set the serial port communications timeouts.
        this->m_ct.ReadIntervalTimeout = MAXDWORD;
        this->m_ct.ReadTotalTimeoutMultiplier = 0;
        this->m_ct.ReadTotalTimeoutConstant = 0;
        this->m_ct.WriteTotalTimeoutMultiplier = 0;
        this->m_ct.WriteTotalTimeoutConstant = 0;

        if ( !::SetCommTimeouts( this->m_hSerialPort, &(this->m_ct) ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to set the comm timeout values.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Create thread to receive data.
        if ( (this->m_hSpRxThread = CreateThread(
            NULL,                           // No security attributes.
            0,                              // Use default initial stack size.
            reinterpret_cast<LPTHREAD_START_ROUTINE>(SerialPortRxThreadFn), // Function to execute in new thread.
            this,                           // Thread parameters.
            0,                              // Use default creation settings.
            NULL                            // Thread ID is not needed.
            )) == NULL )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to create serial port receive thread.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Create thread to transmit data.
        if ( (this->m_hSpTxThread = CreateThread(
            NULL,                           // No security attributes.
            0,                              // Use default initial stack size.
            reinterpret_cast<LPTHREAD_START_ROUTINE>(SerialPortTxThreadFn), // Function to execute in new thread.
            this,                           // Thread parameters.
            0,                              // Use default creation settings.
            NULL                            // Thread ID is not needed.
            )) == NULL )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to create serial port transmit thread.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        if ( !::SetEvent( this->m_hSpPortOpenEvent ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("CSerialPort::Open : Failed to set event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }
    }
    while ( 0 );

    return dwError;
}

串口通信事件线程:

static DWORD SerialPortCommEvtsThreadFn( void * pParam )
{
    CSerialPort * pobjSerialPort = NULL;
    BOOL blContinue = TRUE;
    DWORD dwError = ERROR_SUCCESS;
    DWORD dwEventMask = 0;
    DWORD dwObjectWaitState;
    OVERLAPPED ovComm = { 0 };
    int i = 0;
    static HANDLE pHandles[SPCM_MAX_EVENTS + SP_ONE_ITEM]; // +1 for overlapped event

    // Validate parameters.
    if ( pParam == NULL )
    {
        dwError = ERROR_INVALID_PARAMETER;
        TRACE(_T("SerialPortTxThreadFn : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
        return dwError;
    }

    pobjSerialPort = (CSerialPort *)pParam;

    // Load event handles.
    pHandles[i++] = pobjSerialPort->GetCommHandle( SPCM_THREAD_EXIT_EVT_ID );
    pHandles[i++] = pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID );
    pHandles[i++] = pobjSerialPort->GetCommHandle( SPCM_PORT_CLOSED_EVT_ID );

    while ( (blContinue != FALSE) && (dwError == ERROR_SUCCESS) )
    {
        // Wait for serial port to open.
        if ( (dwObjectWaitState = ::WaitForSingleObject( pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID ), INFINITE )) != WAIT_OBJECT_0 )
        {
            dwError = ( dwObjectWaitState == WAIT_FAILED ) ? ::GetLastError() : dwObjectWaitState;
            TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        if ( ovComm.hEvent == NULL )
        {
            // Create event object for serial port communications events OVERLAPPED structure.
            if ( (ovComm.hEvent = ::CreateEvent(
                NULL,                           // No security
                TRUE,                           // Create a manual-reset event object
                FALSE,                          // Initial state is non-signaled
                NULL                            // No name specified
                )) == NULL )
            {
                dwError = ::GetLastError();
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed to create event object.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }

            pHandles[i++] = ovComm.hEvent;
        }
        else
        {
            i++;
        }

        // Wait for a communications event.
        if ( !::WaitCommEvent( pobjSerialPort->m_hSerialPort, &dwEventMask, &ovComm ) )
        {
            if ( (dwError = ::GetLastError()) != ERROR_IO_PENDING )
            {
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for communications event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }
            else
            {
                dwError = ERROR_SUCCESS;
            }
        }
        else
        {
            if ( (dwError = HandleCommOvEvent( pobjSerialPort, dwEventMask )) != ERROR_SUCCESS )
            {
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed handling communications event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }

            continue;
        }

        dwObjectWaitState = ::WaitForMultipleObjects( i--, pHandles, FALSE, INFINITE );

        switch ( dwObjectWaitState )
        {
        case WAIT_OBJECT_0 + SPCM_THREAD_EXIT_EVT_ID:
            blContinue = FALSE;
            break;

        case WAIT_OBJECT_0 + SPCM_PORT_OPEN_EVT_ID:
            if ( !::ResetEvent( pobjSerialPort->GetCommHandle( SPCM_PORT_CLOSED_EVT_ID ) ) )
            {
                dwError = ::GetLastError();
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed to reset event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }
            break;

        case WAIT_OBJECT_0 + SPCM_PORT_CLOSED_EVT_ID:
            if ( !::ResetEvent( pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID ) ) )
            {
                dwError = ::GetLastError();
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed to reset event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }
            break;

        case WAIT_OBJECT_0 + SPCM_MAX_EVENTS:
            if ( (dwError = HandleCommOvEvent( pobjSerialPort, dwEventMask )) != ERROR_SUCCESS )
            {
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed handling communications event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }

            ::CloseHandle( ovComm.hEvent );
            ::memset( &ovComm, 0, sizeof(OVERLAPPED) );
            break;

        default:
            dwError = ( dwObjectWaitState == WAIT_FAILED ) ? ::GetLastError() : dwObjectWaitState;
            TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            break;
        }
    }

    return dwError;
}

处理通讯事件函数

static DWORD HandleCommOvEvent( CSerialPort * pobjSerialPort, DWORD dwEvtMask )
{
    DWORD dwError = ERROR_SUCCESS;

    do
    {
        // Validate parameters.
        if ( pobjSerialPort == NULL )
        {
            dwError = ERROR_INVALID_PARAMETER;
            TRACE(_T("HandleCommEvent : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        // Handle the transmit complete event.
        if ( dwEvtMask & EV_TXEMPTY )
        {
            if ( (dwError = HandleTxDoneCommEvent( pobjSerialPort )) != ERROR_SUCCESS )
            {
                TRACE(_T("HandleCommEvent : Failed handling transmit complete event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }
        }

        // Handle the received data event.
        if ( dwEvtMask & EV_RXCHAR )
        {
            if ( (dwError = HandleRxDataCommEvent( pobjSerialPort )) != ERROR_SUCCESS )
            {
                TRACE(_T("HandleCommEvent : Failed handling received data event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }
        }
    }
    while ( 0 );

    return dwError;
}

处理接收到的数据通信事件函数

static DWORD HandleRxDataCommEvent( CSerialPort * pobjSerialPort )
{
    DWORD dwError = ERROR_SUCCESS;

    do
    {
        // Validate parameters.
        if ( pobjSerialPort == NULL )
        {
            dwError = ERROR_INVALID_PARAMETER;
            TRACE(_T("HandleRxDataCommEvent : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }

        if ( !::SetEvent( pobjSerialPort->GetRxHandle( SPRX_RECEIVED_DATA_EVT_ID ) ) )
        {
            dwError = ::GetLastError();
            TRACE(_T("HandleRxDataCommEvent : Failed setting event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            continue;
        }
    }
    while ( 0 );

    return dwError;
}

接收线程函数

static DWORD SerialPortRxThreadFn( void * pParam )
{
    CSerialPort * pobjSerialPort = NULL;
    BOOL blContinue = TRUE;
    DWORD dwError = ERROR_SUCCESS;
    DWORD dwEventMask = 0;
    DWORD dwObjectWaitState;
    OVERLAPPED ovComm = { 0 };
    int i = 0;
    static BYTE pBuf[SP_RX_BUF_SIZE];
    static HANDLE pHandles[SPRX_MAX_EVENTS + SP_ONE_ITEM]; // +1 for overlapped event

    ASSERT(s_pobjRxBuffer != NULL);

    // Validate parameters.
    if ( pParam == NULL )
    {
        dwError = ERROR_INVALID_PARAMETER;
        TRACE(_T("SerialPortRxThreadFn : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
        return dwError;
    }

    pobjSerialPort = (CSerialPort *)pParam;

    // Load event handles.
    pHandles[i++] = pobjSerialPort->GetRxHandle( SPRX_THREAD_EXIT_EVT_ID );
    pHandles[i++] = pobjSerialPort->GetRxHandle( SPRX_RECEIVED_DATA_EVT_ID );

    while ( (blContinue != FALSE) && (dwError == ERROR_SUCCESS) )
    {
        if ( ovComm.hEvent == NULL )
        {
            // Create event object for serial port communications events OVERLAPPED structure.
            if ( (ovComm.hEvent = ::CreateEvent(
                NULL,                           // No security
                TRUE,                           // Create a manual-reset event object
                FALSE,                          // Initial state is non-signaled
                NULL                            // No name specified
                )) == NULL )
            {
                dwError = ::GetLastError();
                TRACE(_T("SerialPortRxThreadFn : Failed to create event object.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }

            pHandles[i++] = ovComm.hEvent;
        }
        else
        {
            i++;
        }

        dwObjectWaitState = ::WaitForMultipleObjects( i--, pHandles, FALSE, INFINITE );

        switch ( dwObjectWaitState )
        {
        case WAIT_OBJECT_0 + SPRX_THREAD_EXIT_EVT_ID:
            blContinue = FALSE;
            break;

        case WAIT_OBJECT_0 + SPRX_RECEIVED_DATA_EVT_ID:
            if ( !::ReadFile( pobjSerialPort->m_hSerialPort, pBuf, SP_RX_BUF_SIZE, NULL, &ovComm ) )
            {
                if ( (dwError = ::GetLastError()) != ERROR_IO_PENDING )
                {
                    TRACE(_T("SerialPortRxThreadFn : Failed reading data from serial port.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                    continue;
                }
            }
            else
            {
                if ( (dwError = HandleReceivedDataOvEvent( pobjSerialPort, &ovComm, pBuf )) != ERROR_SUCCESS )
                {
                    TRACE(_T("SerialPortRxThreadFn : Failed handling serial port received data event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                    continue;
                }
            }
            break;

        case WAIT_OBJECT_0 + SPRX_MAX_EVENTS:
            if ( (dwError = HandleReceivedDataOvEvent( pobjSerialPort, &ovComm, pBuf )) != ERROR_SUCCESS )
            {
                TRACE(_T("SerialPortRxThreadFn : Failed handling serial port received data event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                continue;
            }

            ::CloseHandle( ovComm.hEvent );
            ::memset( &ovComm, 0, sizeof(OVERLAPPED) );
            break;

        default:
            dwError = ( dwObjectWaitState == WAIT_FAILED ) ? ::GetLastError() : dwObjectWaitState;
            TRACE(_T("SerialPortRxThreadFn : There is a problem with the OVERLAPPED structure's event handle.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            break;
        }
    }

    return dwError;
}

【问题讨论】:

    标签: c++ asynchronous io serial-port overlapped-io


    【解决方案1】:

    看起来您正在尝试对 WaitCommEventReadFile 使用相同的 OVERLAPPED 结构。这应该会给你带来无穷无尽的问题。


    文档引用:When performing multiple simultaneous overlapped operations on a single thread, the calling thread must specify an OVERLAPPED structure for each operation


    尝试修复它(未经测试,甚至未经编译)。您需要针对您的项目填写的内容标有// TODO

    static DWORD SerialPortCommEvtsThreadFn( void * pParam )
    {
        CSerialPort * pobjSerialPort = NULL;
        BOOL blContinue = TRUE;
        DWORD dwError = ERROR_SUCCESS;
        DWORD dwEventMask = 0;
        DWORD dwObjectWaitState;
        OVERLAPPED ovWaitComm = { 0 };
        OVERLAPPED ovRead = { 0 };
        const DWORD numHandles = SPCM_MAX_EVENTS + 2;
        HANDLE pHandles[numHandles];
    
        // Validate parameters.
        if ( pParam == NULL )
        {
            dwError = ERROR_INVALID_PARAMETER;
            TRACE(_T("SerialPortTxThreadFn : Invalid parameter.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            return dwError;
        }
        pobjSerialPort = static_cast<CSerialPort *>(pParam);
    
        ovWaitComm.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
        ovRead.hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
        if (!ovWaitComm.hEvent || !ovRead.hEvent) {
            dwError = ::GetLastError();
            TRACE(_T("SerialPortCommEvtsThreadFn : Failed to create event objects.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            return dwError;
        }
    
        // Load event handles.
        pHandles[SPCM_THREAD_EXIT_EVT_ID ] = pobjSerialPort->GetCommHandle( SPCM_THREAD_EXIT_EVT_ID );
        pHandles[SPCM_PORT_OPEN_EVT_ID ] = pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID );
        pHandles[SPCM_PORT_CLOSED_EVT_ID ] = pobjSerialPort->GetCommHandle( SPCM_PORT_CLOSED_EVT_ID );
        pHandles[numHandles - 2] = ovWaitComm.hEvent;
        pHandles[numHandles - 1] = ovRead.hEvent;
    
        // Wait for serial port to open.
        if ( (dwObjectWaitState = ::WaitForSingleObject( pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID ), INFINITE )) != WAIT_OBJECT_0 ) {
            dwError = ( dwObjectWaitState == WAIT_FAILED ) ? ::GetLastError() : dwObjectWaitState;
            TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
            return dwError;
        }
    
        // TODO: SetCommTimeouts
    
        // Wait for a communications event.
        if ( !::WaitCommEvent( pobjSerialPort->m_hSerialPort, &dwEventMask, &ovWaitComm ) {
            if ( (dwError = ::GetLastError()) != ERROR_IO_PENDING ) {
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for communications event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                return dwError;
            }
        }
    
        // TODO: Here, call ReadFile, passing &ovRead
    
        dwError = ERROR_SUCCESS;
        while ( blContinue && (dwError == ERROR_SUCCESS) )
        {
            dwObjectWaitState = ::WaitForMultipleObjects( numHandles, pHandles, FALSE, INFINITE );
            switch ( dwObjectWaitState )
            {
            case WAIT_OBJECT_0 + SPCM_THREAD_EXIT_EVT_ID:
                blContinue = FALSE;
                break;
    
            case WAIT_OBJECT_0 + SPCM_PORT_OPEN_EVT_ID:
                if ( !::ResetEvent( pobjSerialPort->GetCommHandle( SPCM_PORT_CLOSED_EVT_ID ) ) )
                {
                    dwError = ::GetLastError();
                    TRACE(_T("SerialPortCommEvtsThreadFn : Failed to reset event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                    continue;
                }
                break;
    
            case WAIT_OBJECT_0 + SPCM_PORT_CLOSED_EVT_ID:
                if ( !::ResetEvent( pobjSerialPort->GetCommHandle( SPCM_PORT_OPEN_EVT_ID ) ) )
                {
                    dwError = ::GetLastError();
                    TRACE(_T("SerialPortCommEvtsThreadFn : Failed to reset event object signal state.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                    continue;
                }
                break;
    
            case WAIT_OBJECT_0 + numHandles - 2:
                if ( (dwError = HandleCommOvEvent( pobjSerialPort, dwEventMask )) != ERROR_SUCCESS )
                {
                    TRACE(_T("SerialPortCommEvtsThreadFn : Failed handling communications event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                    continue;
                }
    
                // TODO: call WaitCommEvent again, if HandleCommOvEvent didn't already
                break;
    
            case WAIT_OBJECT_0 + numHandles - 1:
                // TODO: do something with the received data, it's now in the buffer supplied to ReadFile
                // TODO: call ReadFile again
                break;
    
            default:
                dwError = ( dwObjectWaitState == WAIT_FAILED ) ? ::GetLastError() : dwObjectWaitState;
                TRACE(_T("SerialPortCommEvtsThreadFn : Failed waiting for event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwError, _T(__FILE__), __LINE__);
                break;
            }
        }
    
        return dwError;
    }
    

    【讨论】:

    • 您能详细说明一下吗?我以为他们应该使用相同的OVERLAPPED 结构。
    • @Jim:哦,绝对不是。内核使用OVERLAPPED 结构来存储操作的进度。从您开始操作到操作完成(使用GetOverlappedResultWaitForSingleObject 测试),OVERLAPPED 缓冲区归内核所有,您不应该对它做任何事情,尤其是您不能释放它,也不能将其传递给任何 API 函数(例外:您可以并且应该将其地址传递给 GetOverlappedResultCancelIoEx)。 OVERLAPPED 与 linux 中的 aiocb(异步 io 控制块)数据类型完全类似。
    • 这应该是不言而喻的,因为如果你将同一个OVERLAPPED缓冲区传递给多个操作,GetOverlappedResult如何知道检查哪个操作的结果?
    • WaitCommEventReadFile 的调用 属于同一操作。 ReadFile 用于从 COM 端口读取数据,WaitCommEvent 用于确定该 COM 端口的 I/O 状态。
    • @Jim:根据您的想法,属于同一任务,但不是同一操作的一部分,因为操作是由 Win32 API 定义的。 WaitCommEvent 启动重叠操作。 ReadFile 也是如此。这两个操作需要两个不同的 OVERLAPPED 缓冲区。
    【解决方案2】:

    您似乎在调用 GetLastError() 时尚未检查是否存在错误。

    【讨论】:

    • 什么意思?据我了解,在进行重叠 I/O 时,如果 WaitCommEvent 返回 false,则 GetLastError 应该返回 ERROR_IO_PENDING,但我得到的是 ERROR_INVALID_PARAMETERWaitCommEvent 是一个具有误导性的名称,根据 MSDN 文档,它或多或少会立即返回。我知道这是一个严重的问题,因为代码只是在试图处理 ERROR_INVALID_PARAMETER 错误,这会阻止我的应用程序中的其他线程运行。
    【解决方案3】:

    你在打电话

    WaitCommEvent(pobjSerialPort->m_hSerialPort, &dwEventMask, &(pobjSerialPort->m_ovEvents))
    

    WaitCommEvent 的第 1 和第 3 个参数是输入参数,但是您没有提供它们的初始化代码。

    如何初始化 m_hSerialPort?您是否使用有效参数调用 CreateFile 并验证没有错误? 你如何初始化 m_ovEvents?您是否使用有效参数调用 CreateEvent 并验证没有错误?

    由于您收到 ERROR_INVALID_PARAMETER,我认为您的问题在于这些参数之一的初始化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-04
      • 2015-09-01
      • 2016-06-09
      • 2011-11-24
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 2010-12-21
      相关资源
      最近更新 更多