⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vcthread.cpp

📁 提供串口通讯参数设置接口
💻 CPP
📖 第 1 页 / 共 2 页
字号:
///////////////////////////////////////////////////////////////
// 文件: vcthread.cpp
// 功能: 读写线程功能实现文件
// 作者: 王念峰
// 日期: 1999.05.15 - 修改,整理
// E_mai:wnf@wisepeak.com
// Http://www.wisepeak.com
///////////////////////////////////////////////////////////////
// 版本: 1.0
///////////////////////////////////////////////////////////////
// 注:由于涉及串口通讯,要求系统必须同时响应串口事件和用户输入,
//    所以该处使用多线程来实现
///////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "vcThread.h"
#include "define.h"

IMPLEMENT_DYNAMIC(TReadThread, CWinThread)

////////////////////////////////////////////////////////
//  过程: TReadThread.Thread
//
//  目的: 读线程运行并执行相应的功能.
//
//  参数:
//    None.
//
//  返回值:
//    None.
//
//  注释:
//
//    The Read Thread uses overlapped ReadFile and sends any data
//    read from the comm port to the Comm32Window.  This is
//    eventually done through a PostMessage so that the Read Thread
//    is never away from the comm port very long.  This also provides
//    natural desynchronization between the Read thread and the UI.
//
//    If the CloseEvent object is signaled, the Read Thread returns.
//
//        Separating the Read and Write threads is natural for a application
//    where there is no need for synchronization between
//    reading and writing.  However, if there is such a need (for example,
//    most file transfer algorithms synchronize the reading and writing),
//     it would make a lot more sense to have a single thread to handle
//    both reading and writing.
//

TReadThread::TReadThread()
{

}

BOOL TReadThread::InitInstance()
{
   char szInputBuffer[TINPUTBUFFERSIZE];
   DWORD nNumberOfBytesRead;
   HANDLE HandlesToWaitFor[3];
   DWORD dwHandleSignaled;
   DWORD fdwEvtMask;
   // Needed for overlapped I/O (ReadFile)
   OVERLAPPED overlappedRead;
   // Needed for overlapped Comm Event handling.
   OVERLAPPED overlappedCommEvent;
   memset( &overlappedRead,0, sizeof(overlappedRead));
   memset( &overlappedCommEvent,0, sizeof(overlappedCommEvent));
   // Lets put an event in the Read overlapped structure.
   overlappedRead.hEvent = CreateEvent( NULL, true, false, NULL);
   if (overlappedRead.hEvent == 0 )
   {
      PostHangupCall();
      goto EndReadThread;
   }
   ResetEvent(overlappedRead.hEvent);
   // And an event for the CommEvent overlapped structure.
   overlappedCommEvent.hEvent = CreateEvent( NULL, true, false, NULL);
   if (overlappedCommEvent.hEvent == 0 )
   {
      PostHangupCall();
      goto EndReadThread;
   }
   ResetEvent(overlappedCommEvent.hEvent);
   // We will be waiting on these objects.
   HandlesToWaitFor[0] = m_hCloseEvent;
   HandlesToWaitFor[1] = overlappedCommEvent.hEvent;
   HandlesToWaitFor[2] = overlappedRead.hEvent;
   // Setup CommEvent handling.
   // Set the comm mask so we receive error signals.
   if (! SetCommMask(m_hCommFile, EV_ERR | EV_RLSD))// | EV_RING )) 
   {
      PostHangupCall();
      goto EndReadThread;
   }

   // Start waiting for CommEvents (Errors)
   if (! SetupCommEvent( &overlappedCommEvent,  fdwEvtMask ) )
      goto EndReadThread;

   // Start waiting for Read events.
   if (! SetupReadEvent( &overlappedRead,
      szInputBuffer, TINPUTBUFFERSIZE,
      nNumberOfBytesRead ) )
      goto EndReadThread;
   // Keep looping until we break out.
   while (true)
   {
      // Wait until some event occurs (data to read; error; stopping).
      dwHandleSignaled = WaitForMultipleObjects(3, HandlesToWaitFor,false, INFINITE);
      // Which event occured?
      switch (dwHandleSignaled) 
      {
      case  WAIT_OBJECT_0:     // Signal to end the thread.
         // Time to return.
         goto EndReadThread;         
      case WAIT_OBJECT_0 + 1: // CommEvent signaled.
         // Handle the CommEvent.
         if (! HandleCommEvent( &overlappedCommEvent, fdwEvtMask, true ) )
            goto EndReadThread;
         // Start waiting for the next CommEvent.
         if (! SetupCommEvent( &overlappedCommEvent, fdwEvtMask ) )
            goto EndReadThread;
         break;
      case WAIT_OBJECT_0 + 2: // Read Event signaled.
         // Get the new data!
         if (! HandleReadEvent( &overlappedRead,szInputBuffer,
            TINPUTBUFFERSIZE,nNumberOfBytesRead )) 
            goto EndReadThread;
         // Wait for more new data.
         if (! SetupReadEvent( &overlappedRead,szInputBuffer, TINPUTBUFFERSIZE,
            nNumberOfBytesRead ) )
            goto EndReadThread;
         break;
      case WAIT_FAILED:       // Wait failed.  Shouldn't happen.
         PostHangupCall();
         goto EndReadThread;         
      default:    // This case should never occur.
         PostHangupCall();
         goto EndReadThread;
      } //{case dwHandleSignaled}
   } //{while True}
   // Time to clean up Read Thread.
EndReadThread:
   PurgeComm( m_hCommFile, PURGE_RXABORT + PURGE_RXCLEAR );
   CloseHandle( overlappedRead.hEvent );
   CloseHandle( overlappedCommEvent.hEvent );
   return false;
}


///////////////////////////////////////////////////////
//读线程类提供的方法
//
//  函数: SetupCommEvent(LPOVERLAPPED, LPDWORD)
//
//  目的: Sets up the overlapped WaitCommEvent call.
//
//  参数:
//    lpOverlappedCommEvent - Pointer to the overlapped structure to use.
//    lpfdwEvtMask          - Pointer to DWORD to received Event data.
//
//  返回值:
//    TRUE if able to successfully setup the WaitCommEvent.
//    FALSE if unable to setup WaitCommEvent, unable to handle
//    an existing outstanding event or if the CloseEvent has been signaled.
//
//  注释:
//
//    This function is a helper function for the Read Thread that sets up
//    the WaitCommEvent so we can deal with comm events (like Comm errors)
//    if they occur.
//

bool TReadThread::SetupCommEvent( OVERLAPPED* lpOverlappedCommEvent,DWORD & lpfdwEvtMask)
{
   DWORD dwLastError;
   //Result = false;

StartSetupCommEvent:   
   //确定关闭事件还没有被启动,查看它的目的是为了防止关闭事件递归调用.
   //当返回值不为WAIT_TIMEOUT时表明关闭事件已被启动
   if (WAIT_TIMEOUT != WaitForSingleObject( m_hCloseEvent,0 ) )
      return false;
   // Start waiting for Comm Errors.
   if (WaitCommEvent( m_hCommFile, &lpfdwEvtMask, lpOverlappedCommEvent ) )
   {
      // This could happen if there was an error waiting on the
      // comm port.  Lets try and handle it.
      if (! HandleCommEvent( NULL, lpfdwEvtMask, false ) )
      {
         //{??? GetOverlappedResult does not handle "NULL" as defined by Borland}
         return false;
      }
      // What could cause infinite recursion at this point?
      goto StartSetupCommEvent;
   }

   // We expect ERROR_IO_PENDING returned from WaitCommEvent
   // because we are waiting with an overlapped structure.
   dwLastError = GetLastError();
   // LastError was ERROR_IO_PENDING, as expected.
   if (dwLastError == ERROR_IO_PENDING)    
      return true;
   
   // 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 could cause this to happen.
   PostHangupCall();
   return false;
}//{TReadThread.SetupCommEvent}


//////////////////////////////////////////////////////////
//  函数: SetupReadEvent(LPOVERLAPPED, LPSTR, DWORD, LPDWORD)
//
//  目的: Sets up an overlapped ReadFile
//
//  参数:
//    lpOverlappedRead      - address of overlapped structure to use.
//    lpszInputBuffer       - Buffer to place incoming bytes.
//    dwSizeofBuffer        - size of lpszInputBuffer.
//    lpnNumberOfBytesRead  - address of DWORD to place the number of read bytes.
//
//  返回值:
//    TRUE if able to successfully setup the ReadFile.  FALSE if there
//    was a failure setting up or if the CloseEvent object was signaled.
//
//  注释:
//
//    This function is a helper function for the Read Thread.  This
//    function sets up the overlapped ReadFile so that it can later
//    be waited on (or more appropriatly, so the event in the overlapped
//    structure can be waited upon).  If there is data waiting, it is
//    handled and the next ReadFile is initiated.
//    Another possible reason for returning FALSE is if the comm port
//    is closed by the service provider.
//
//

bool TReadThread::SetupReadEvent( OVERLAPPED* lpOverlappedRead,LPSTR lpszInputBuffer,DWORD dwSizeofBuffer,DWORD & lpnNumberOfBytesRead)
{
   DWORD dwLastError;
   //Result = False;
StartSetupReadEvent:
   // Make sure the CloseEvent hasn't been signaled yet.
   // Check is needed because this function is potentially recursive.
   if (WAIT_TIMEOUT != WaitForSingleObject(m_hCloseEvent,0) )
      return false;
   // Start the overlapped ReadFile.
   if (ReadFile( m_hCommFile,
      lpszInputBuffer, dwSizeofBuffer,
      &lpnNumberOfBytesRead, lpOverlappedRead ) )
   {
      // This would only happen if there was data waiting to be read.
      // Handle the data.
      if (! HandleReadData( lpszInputBuffer, lpnNumberOfBytesRead ) )
         return false;
      // Start waiting for more data.
      goto StartSetupReadEvent;
   }
   // ReadFile failed.  Expected because of overlapped I/O.
   dwLastError = GetLastError();
   // LastError was ERROR_IO_PENDING, as expected.
   
   if (dwLastError == ERROR_IO_PENDING )   
      return true;
   
   // 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 come here. No idea what could cause this to happen.
   PostHangupCall();
   return false;
}//{TReadThread.SetupReadEvent}


///////////////////////////////////////////////////////
//  函数: HandleCommEvent(LPOVERLAPPED, LPDWORD, BOOL)
//
//  目的: 处理标准的通讯事件.
//
//  参数:
//    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.
//
//  返回值:
//    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.
//
//  注释:
//
//    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 TReadThread::HandleCommEvent(OVERLAPPED* lpOverlappedCommEvent,DWORD & lpfdwEvtMask,bool fRetrieveEvent)
{
   DWORD dwDummy;
   DWORD dwErrors;
   DWORD dwLastError;
   // 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( m_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();//ERROR_IO_INCOMPLETE
         return false;
      }
   }
   // Was the event an error? EV_ERR 0x80
   if ((lpfdwEvtMask && EV_ERR) != 0 )
   {
      // Which error was it?
      if (! ClearCommError( m_hCommFile, &dwErrors, NULL ) )
      {
         dwLastError = GetLastError();
         // Its possible for this error to occur if the

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -