我的应用程序使用带有重叠事件的串行I / O。由于某些原因,::WaitCommEvent
在第二次通过ERROR_INVALID_PARAMETER
循环时始终失败。如果有人可以解释我需要做的不同的事情,将不胜感激。我的串口初始化/打开代码和线程功能如下。应该注意的是,初始化/打开代码是在线程函数启动之后执行的,这就是对::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;
}
最佳答案
看起来您正在尝试对WaitCommEvent
和ReadFile
使用相同的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;
}
关于c++ - WaitCommEvent在第二遍失败的无效参数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6020699/