📄 comm.cpp
字号:
//---------------------------------------------------------------------------
//
// FUNCTION: HandleCommEvent(LPOVERLAPPED, LPDWORD, BOOL)
//
// PURPOSE: Handle an outstanding Comm Event.
//
// PARAMETERS:
// lpOverlappedCommEvent - Pointer to the overlapped structure to use.
// lpfdwEvtMask - Pointer to DWORD to received Event data.
// fRetrieveEvent - Flag to signal if the event needs to be
// retrieved, or has already been retrieved.
//
// RETURN VALUE:
// TRUE if able to handle a Comm Event.
// FALSE if unable to setup WaitCommEvent, unable to handle
// an existing outstanding event or if the CloseEvent has been signaled.
//
// COMMENTS:
//
// This function is a helper function for the Read Thread that (if
// fRetrieveEvent == TRUE) retrieves an outstanding CommEvent and
// deals with it. The only event that should occur is an EV_ERR event,
// signalling that there has been an error on the comm port.
//
// Normally, comm errors would not be put into the normal data stream
// as this sample is demonstrating. Putting it in a status bar would
// be more appropriate for a real application.
//
//
bool __fastcall TReadThread::HandleCommEvent(
Windows::POverlapped lpOverlappedCommEvent,
DWORD &lpfdwEvtMask,
bool fRetrieveEvent)
{
DWORD dwDummy;
DWORD dwErrors;
DWORD dwLastError;
DWORD dwModemEvent;
// If this fails, it could be because the file was closed (and I/O is
// finished) or because the overlapped I/O is still in progress. In
// either case (or any others) its a bug and return FALSE.
if (fRetrieveEvent)
{
if (! GetOverlappedResult( hCommFile, lpOverlappedCommEvent, &dwDummy, false ))
{
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if (dwLastError == ERROR_INVALID_HANDLE)
return false;
PostHangupCall();
return false;
}
}
// Was the event an error?
if ((lpfdwEvtMask && EV_ERR) != 0)
{
// Which error was it?
if (! ClearCommError( hCommFile, &dwErrors, NULL ) )
{
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if (dwLastError == ERROR_INVALID_HANDLE )
return false;
PostHangupCall();
return false;
}
// Its possible that multiple errors occured and were handled
// in the last ClearCommError. Because all errors were signaled
// individually, but cleared all at once, pending comm events
// can yield EV_ERR while dwErrors equals 0. Ignore this event.
if (! ReceiveError( dwErrors ) ) return false;
return true;// Result := True
}
dwModemEvent = 0;
if ((lpfdwEvtMask && EV_RLSD) != 0) dwModemEvent = ME_RLSD;
if ((lpfdwEvtMask && EV_RING) != 0) dwModemEvent = dwModemEvent | ME_RING;
if (dwModemEvent != 0)
{
if (! ModemStateChange( dwModemEvent ) )
return false;
return true;
}
if (((lpfdwEvtMask && EV_ERR)==0) && (dwModemEvent==0))
PostHangupCall(); // Should not have gotten here.
return false;
}
//---------------------------------------------------------------------------
//
//
//
bool __fastcall TReadThread::ReceiveData(
char * lpNewString,
DWORD dwSizeofNewString)
{
if (!PostMessage(hComm32Window,PWM_GOTCOMMDATA,WPARAM(dwSizeofNewString),LPARAM(lpNewString)))
PostHangupCall();
else return true;
return false;
}
//---------------------------------------------------------------------------
//
//
//
bool __fastcall TReadThread::ReceiveError(DWORD EvtMask)
{
if (!PostMessage(hComm32Window,PWM_RECEIVEERROR,0,LPARAM(EvtMask)))
PostHangupCall();
else return true;
return false;
}
//---------------------------------------------------------------------------
//
//
bool __fastcall TReadThread::ModemStateChange(DWORD ModemEvent)
{
if(!PostMessage(hComm32Window,PWM_MODEMSTATECHANGE,0,LPARAM(ModemEvent)))
PostHangupCall();
else return true;
return false;
}
//---------------------------------------------------------------------------
//
//
//
void __fastcall TReadThread::PostHangupCall(void)
{
PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}
//---------------------------------------------------------------------------
/***************************************************************************/
// WRITE THREAD - 写线程
/***************************************************************************/
//---------------------------------------------------------------------------
//
// PROCEDURE: TWriteThread.Execute
//
// PURPOSE: The starting point for the Write thread.
//
// PARAMETERS:
// lpvParam - unused.
//
// RETURN VALUE:
// DWORD - unused.
//
// COMMENTS:
//
// The Write thread uses a PeekMessage loop to wait for a string to write,
// and when it gets one, it writes it to the Comm port. If the CloseEvent
// object is signaled, then it exits. The use of messages to tell the
// Write thread what to write provides a natural desynchronization between
// the UI and the Write thread.
//
//
void __fastcall TWriteThread::Execute(void)
{
TMsg msg;
DWORD dwHandleSignaled;
OVERLAPPED overlappedWrite;
bool CompleteOneWriteRequire;
// Needed for overlapped I/O.
memset( &overlappedWrite, 0, sizeof(overlappedWrite));
overlappedWrite.hEvent = CreateEvent( NULL, true, true, NULL );
if (overlappedWrite.hEvent == 0)
{
PostHangupCall();
goto EndWriteThread;
}
CompleteOneWriteRequire = true;
// This is the main loop. Loop until we break out.
while (true)
{
if (! PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ))
{
// If there are no messages pending, wait for a message or
// the CloseEvent.
*pFSendDataEmpty = true;
if (CompleteOneWriteRequire)
{
if (! PostMessage( hComm32Window, PWM_SENDDATAEMPTY, 0, 0 ) )
{
PostHangupCall();
goto EndWriteThread;
}
}
CompleteOneWriteRequire = false;
dwHandleSignaled = MsgWaitForMultipleObjects(1, &hCloseEvent, false,
INFINITE, QS_ALLINPUT);
switch( dwHandleSignaled )
{
case WAIT_OBJECT_0: // CloseEvent signaled!
{
// Time to exit.
goto EndWriteThread;
}
case WAIT_OBJECT_0 + 1: // New message was received.
{
// Get the message that woke us up by looping again.
continue;
}
case WAIT_FAILED: // Wait failed. Shouldn't happen.
{
PostHangupCall();
goto EndWriteThread;
}
default : // This case should never occur.
{
PostHangupCall();
goto EndWriteThread;
}
}
}
// Make sure the CloseEvent isn't signaled while retrieving messages.
if (WAIT_TIMEOUT != WaitForSingleObject(hCloseEvent, 0))
goto EndWriteThread;
// Process the message.
// This could happen if a dialog is created on this thread.
// This doesn't occur in this sample, but might if modified.
if (msg.hwnd != NULL)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
// Handle the message.
switch (msg.message)
{
case PWM_COMMWRITE: // New string to write to Comm port.
{
// Write the string to the comm port. HandleWriteData
// does not return until the whole string has been written,
// an error occurs or until the CloseEvent is signaled.
if (! HandleWriteData( overlappedWrite, PChar(msg.lParam), DWORD(msg.wParam) ))
{
// If it failed, either we got a signal to end or there
// really was a failure.
LocalFree( HLOCAL(msg.lParam) );
goto EndWriteThread;
}
CompleteOneWriteRequire = true;
// Data was sent in a LocalAlloc()d buffer. Must free it.
LocalFree( HLOCAL(msg.lParam) );
break;
}
}
}
// Thats the end. Now clean up.
EndWriteThread:
PurgeComm(hCommFile, PURGE_TXABORT | PURGE_TXCLEAR);
*pFSendDataEmpty = true;
CloseHandle(overlappedWrite.hEvent);
}
//---------------------------------------------------------------------------
//
// FUNCTION: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
// PURPOSE: Writes a given string to the comm file handle.
//
// PARAMETERS:
// lpOverlappedWrite - Overlapped structure to use in WriteFile
// pDataToWrite - String to write.
// dwNumberOfBytesToWrite - Length of String to write.
//
// RETURN VALUE:
// TRUE if all bytes were written. False if there was a failure to
// write the whole string.
//
// COMMENTS:
//
// This function is a helper function for the Write Thread. It
// is this call that actually writes a string to the comm file.
// Note that this call blocks and waits for the Write to complete
// or for the CloseEvent object to signal that the thread should end.
// Another possible reason for returning FALSE is if the comm port
// is closed by the service provider.
//
//
bool __fastcall TWriteThread::HandleWriteData(
OVERLAPPED OverlappedWrite,
char * pDataToWrite,
DWORD dwNumberOfBytesToWrite)
{
DWORD dwLastError;
DWORD dwNumberOfBytesWritten;
DWORD dwWhereToStartWriting;
DWORD dwHandleSignaled;
HANDLE HandlesToWaitFor[2];
dwNumberOfBytesWritten = 0;
dwWhereToStartWriting = 0; // Start at the beginning.
HandlesToWaitFor[0] = hCloseEvent;
HandlesToWaitFor[1] = OverlappedWrite.hEvent;
// Keep looping until all characters have been written.
do
{
// Start the overlapped I/O.
if (! WriteFile( hCommFile,
&pDataToWrite[ dwWhereToStartWriting ],
dwNumberOfBytesToWrite,
&dwNumberOfBytesWritten,
&OverlappedWrite ))
{
// WriteFile failed. Expected; lets handle it.
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port. Time to end.
if (dwLastError == ERROR_INVALID_HANDLE )
{
return false;
}
// Unexpected error. No idea what.
if (dwLastError != ERROR_IO_PENDING)
{
PostHangupCall();
return false;
}
// This is the expected ERROR_IO_PENDING case.
// Wait for either overlapped I/O completion,
// or for the CloseEvent to get signaled.
dwHandleSignaled = WaitForMultipleObjects(2,HandlesToWaitFor,false,INFINITE);
switch (dwHandleSignaled)
{
case WAIT_OBJECT_0: // CloseEvent signaled!
{
return false;
}
case WAIT_OBJECT_0 + 1: // Wait finished.
{
// Time to get the results of the WriteFile
if (!GetOverlappedResult(hCommFile,&OverlappedWrite,&dwNumberOfBytesWritten,true))
{
dwLastError = GetLastError();
// Its possible for this error to occur if the
// service provider has closed the port.
if (dwLastError == ERROR_INVALID_HANDLE)
{
return false;
}
// No idea what could cause another error.
PostHangupCall();
return false;
}
break;
}
case WAIT_FAILED: // Wait failed. Shouldn't happen.
{
PostHangupCall();
return false;
}
default : // This case should never occur.
{
PostHangupCall();
return false;
}
} // switch
} // writedata error
// Some data was written. Make sure it all got written.
dwNumberOfBytesToWrite -= dwNumberOfBytesWritten;
dwWhereToStartWriting += dwNumberOfBytesWritten;
}while (dwNumberOfBytesToWrite > 0); // Write the whole thing!
// Wrote the whole string.
return true;
}
//---------------------------------------------------------------------------
void __fastcall TWriteThread::PostHangupCall(void)
{
PostMessage( hComm32Window, PWM_REQUESTHANGUP, 0, 0 );
}
//---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -