📄 communication.cpp
字号:
{
TRACE("CreateEvent failed\n");
return 0; // TODO: Notify parent that thread is dead
}
HANDLE hArray[NUMBER_OF_READER_EVENTS];
hArray[reKILL] = pThis->m_hKillEvent;
hArray[reREADER] = osReader.hEvent;
hArray[reSTATUS] = osStatus.hEvent;
// perform initial status checks
pThis->CheckModemStatus();
pThis->CheckComStatus();
DWORD dwStoredFlags = -1;
char *pBuffer[AMOUNT_TO_READ];
DWORD dwCommEvent = 0;
BOOL bWaitingOnRead = FALSE;
BOOL bWaitingOnStatus = FALSE;
BOOL bKeepAlive = TRUE;
while (bKeepAlive)
{
//--------------------------------------------------------------------
// If not connected, suspend thread (if not being killed).
//--------------------------------------------------------------------
if (FALSE == pThis->m_bConnected)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(pThis->m_hKillEvent, 0))
{
break;
}
SuspendThread(pThis->m_hReaderThread);
dwStoredFlags = -1; // reset stored flags
}
//--------------------------------------------------------------------
// if no read is outstanding, then issue another one
if (FALSE == bWaitingOnRead)
{
bWaitingOnRead = pThis->AttemptToRead((char*)pBuffer, AMOUNT_TO_READ,
&osReader);
}
// If status flags have changed, then reset comm mask.
// This will cause a pending WaitCommEvent to complete
// and the resultant event flag will be NULL.
if (dwStoredFlags != pThis->m_dwEventFlags)
{
dwStoredFlags = pThis->m_dwEventFlags;
if (INVALID_HANDLE_VALUE != pThis->m_hPortHandle)
{
if (FALSE == SetCommMask(pThis->m_hPortHandle, dwStoredFlags))
{
TRACE("SetCommMask failed\n");
}
}
}
// if no status check is outstanding, then issue another one
if (FALSE == bWaitingOnStatus)
{
bWaitingOnStatus = pThis->AttemptToGetCommEvent(&osStatus, dwCommEvent);
}
// wait for pending operations to complete
if (bWaitingOnStatus || bWaitingOnRead)
{
DWORD dwRes = WaitForMultipleObjects(NUMBER_OF_READER_EVENTS,
hArray,
FALSE,
STATUS_CHECK_TIMEOUT);
switch(dwRes)
{
// read completed
case WAIT_OBJECT_0 + reREADER:
{
if (INVALID_HANDLE_VALUE != pThis->m_hPortHandle)
{
DWORD dwRead = 0;
if (FALSE == GetOverlappedResult(pThis->m_hPortHandle,
&osReader,
&dwRead,
FALSE))
{
TRACE("GetOverlappedResult failed Err=%d\n", GetLastError());
}
else
{
// read completed successfully
if (MAX_READ_BUFFER == dwRead)
{
TRACE("Read timed-out overlapped\n");
}
if (dwRead)
{
pThis->PutDataReadInQue((char*)pBuffer, dwRead);
}
}
}
bWaitingOnRead = FALSE;
}
break;
// status completed
case WAIT_OBJECT_0 + reSTATUS:
{
if (INVALID_HANDLE_VALUE != pThis->m_hPortHandle)
{
DWORD dwSize;
if (FALSE == GetOverlappedResult(pThis->m_hPortHandle,
&osStatus,
&dwSize,
FALSE))
{
TRACE("GetOverlappedResult failed Err=%d\n", GetLastError());
}
else
{
// status check completed successfully
pThis->ReportStatusEvent(dwCommEvent);
}
}
bWaitingOnStatus = FALSE;
}
break;
// thread exit event
case WAIT_OBJECT_0 + reKILL:
bKeepAlive = FALSE;
break;
case WAIT_TIMEOUT:
// timeouts are not reported because they happen too often.
// Take this opportunity to do a modem status check and a
// comm status check.
pThis->CheckModemStatus();
pThis->CheckComStatus();
break;
case WAIT_FAILED:
{
DWORD dwError = GetLastError();
ASSERT(1);
}
break;
default:
TRACE("Unkown value from WaitForMultipleObjects\n");
break;
}
}
else
{
if (WAIT_OBJECT_0 == WaitForSingleObject(pThis->m_hKillEvent, 0))
{
bKeepAlive = FALSE;
}
}
}
CloseHandle(osReader.hEvent);
CloseHandle(osStatus.hEvent);
return 0;
}
typedef enum
{
whKILL,
whOVERLAPPED
} HWREVENTS;
#define NUMBER_OF_HWR_EVENTS (2)
extern BOOL afxTraceEnabled;
//----------------------------------------------------------------------------
// Private method (called by writer thread).
//----------------------------------------------------------------------------
void CCommunication::HandleWriteRequest(OVERLAPPED *posWrite)
{
HANDLE hArray[NUMBER_OF_HWR_EVENTS];
hArray[whOVERLAPPED] = posWrite->hEvent;
hArray[whKILL] = m_hKillEvent;
// Get any data to write from byte array and copy into local byte array
// for sending it.
int nChunkSize = 0;
CByteArray byteArray;
{
CMakeSafe ms(&m_MakeSafeWriterArray); // make access to que thread-safe
nChunkSize = m_WriterByteArray.GetSize();
if (0 == nChunkSize)
{
return; // no data to write
}
if (nChunkSize > MAX_WRITE_SIZE)
{
nChunkSize = MAX_WRITE_SIZE;
byteArray.SetSize(nChunkSize);
CopyMemory((void*)byteArray.GetData(), m_WriterByteArray.GetData(),
nChunkSize);
int nUnusedSize = m_WriterByteArray.GetSize() - nChunkSize;
CopyMemory((void*)m_WriterByteArray.GetData(),
(void*)((char*)m_WriterByteArray.GetData() + nChunkSize),
nUnusedSize);
m_WriterByteArray.SetSize(nUnusedSize);
::SetEvent(m_hWriteDataEvent);
}
else
{
byteArray.Copy(m_WriterByteArray); // copy data to local array
m_WriterByteArray.RemoveAll(); // empty original array
}
}
char *pData = (char*)byteArray.GetData();
DWORD dwSize = byteArray.GetSize();
DWORD dwSizeRemaining = dwSize;
BOOL bOk = TRUE;
while (dwSizeRemaining && bOk)
{
// issue write
DWORD dwWritten = 0;
#ifdef _MAX_DEBUG
if (dwSize > 1536)
{
ASSERT(0);
}
TRACE("Writing %d bytes\n", dwSize);
#endif
if (!WriteFile(m_hPortHandle, pData, dwSize, &dwWritten, posWrite))
{
DWORD dwError = GetLastError();
if (ERROR_IO_PENDING == dwError)
{
// write is delayed
DWORD dwRes = WaitForMultipleObjects(NUMBER_OF_HWR_EVENTS,
hArray,
FALSE,
INFINITE);
switch(dwRes)
{
// write event set
case WAIT_OBJECT_0 + whOVERLAPPED:
SetLastError(ERROR_SUCCESS);
if (INVALID_HANDLE_VALUE == m_hPortHandle)
{
bOk = FALSE;
break;
}
if (FALSE == GetOverlappedResult(m_hPortHandle,
posWrite,
&dwWritten,
FALSE))
{
TRACE("GetOverlappedResult failed Err=%d\n", GetLastError());
}
if (dwWritten != dwSize)
{
TRACE("Buffer full. Wrote %d of %d bytes\n", dwWritten, dwSize);
}
break;
// thread exit event set
case WAIT_OBJECT_0 + whKILL:
bOk = FALSE;
break;
case WAIT_TIMEOUT:
TRACE("WaitForMultipleObjects timed-out\n");
bOk = FALSE;
break;
default:
TRACE("Unknown value from WaitForMultipleObjects\n");
bOk = FALSE;
break;
}
}
else
{
TRACE("(not pending) WriteFile failed\n");
// We must clear the device's error flag to enable additional I/O operations.
CheckComStatus();
bOk = FALSE;
}
}
else
{
if (dwWritten != dwSize)
{
TRACE("(not pending) Buffer full. Wrote %d of %d bytes\n", dwWritten, dwSize);
}
}
dwSizeRemaining -= dwWritten;
pData += dwWritten;
}
CMakeSafe ms(&m_MakeSafeWriterArray); // make access to que thread-safe
if (0 == m_WriterByteArray.GetSize())
{
::SetEvent(m_hWriteBufferEmptyEvent); // writer buffer is empty
}
return;
}
typedef enum
{
weNEWDATA,
weKILL
} WRITEREVENTS;
#define NUMBER_OF_WRITER_EVENTS (2)
//----------------------------------------------------------------------------
// Static private thread procedure.
//----------------------------------------------------------------------------
DWORD WINAPI CCommunication::WriterThreadProc(LPVOID pParam)
{
CCommunication *pThis = (CCommunication*)pParam;
OVERLAPPED osWrite = {0};
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (0 == osWrite.hEvent)
{
TRACE("CreateEvent failed\n");
return 0; // TODO: Notify parent that thread is dead
}
HANDLE hArray[NUMBER_OF_WRITER_EVENTS];
hArray[weNEWDATA] = pThis->m_hWriteDataEvent;
hArray[weKILL] = pThis->m_hKillEvent;
BOOL bKeepAlive = TRUE;
while (bKeepAlive)
{
//--------------------------------------------------------------------
// If not connected, suspend thread (if not being killed).
//--------------------------------------------------------------------
if (FALSE == pThis->m_bConnected)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(pThis->m_hKillEvent, 0))
{
break;
}
SuspendThread(pThis->m_hWriterThread);
}
DWORD dwRes = WaitForMultipleObjects(NUMBER_OF_WRITER_EVENTS,
hArray,
FALSE,
WRITE_CHECK_TIMEOUT);
switch(dwRes)
{
case WAIT_TIMEOUT:
break;
case WAIT_FAILED:
TRACE("WaitForMultipleObjects failed\n");
break;
// write request event
case WAIT_OBJECT_0 + weNEWDATA:
pThis->HandleWriteRequest(&osWrite);
break;
// thread exit event
case WAIT_OBJECT_0 + weKILL:
bKeepAlive = FALSE;
break;
}
}
CloseHandle(osWrite.hEvent);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -