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

📄 vcthread.cpp

📁 c++实现的一个个串口通讯类
💻 CPP
📖 第 1 页 / 共 2 页
字号:
      }
      // 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;
   }
   else
   {
      PostHangupCall();
      return false;
   }
}// {TReadThread.HandleCommEvent}

bool TReadThread::HandleReadEvent( OVERLAPPED* lpOverlappedRead,LPSTR lpszInputBuffer,DWORD dwSizeofBuffer,DWORD & lpnNumberOfBytesRead)
{
   DWORD dwLastError;
   //Result = false;
   if (GetOverlappedResult( m_hCommFile,lpOverlappedRead, &lpnNumberOfBytesRead, false ) )
   {
       return( HandleReadData( lpszInputBuffer, lpnNumberOfBytesRead ));
   }
   // Error in GetOverlappedResult; 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 come here. No idea what could cause this to happen.
   PostHangupCall();
   return false;
}// {TReadThread.HandleReadEvent}


//////////////////////////////////////////////////////////
//  函数: HandleReadData(LPCSTR, DWORD)
//
//  目的: Deals with data after its been read from the comm file.
//
//  参数:
//    lpszInputBuffer  - Buffer to place incoming bytes.
//    dwSizeofBuffer   - size of lpszInputBuffer.
//
//  返回值:
//    TRUE if able to successfully handle the data.
//    FALSE if unable to allocate memory or handle the data.
//
//  注释:
//
//    This function is yet another helper function for the Read Thread.
//    It LocalAlloc()s a buffer, copies the new data to this buffer and
//    calls PostWriteToDisplayCtl to let the EditCtls module deal with
//    the data.  Its assumed that PostWriteToDisplayCtl posts the message
//    rather than dealing with it right away so that the Read Thread
//    is free to get right back to waiting for data.  Its also assumed
//    that the EditCtls module is responsible for LocalFree()ing the
//    pointer that is passed on.
//

bool TReadThread::HandleReadData(LPCSTR lpszInputBuffer, DWORD dwSizeofBuffer)
{
   LPSTR lpszPostedBytes;
//Result = false;
// If we got data and didn't just time out empty...
   if (dwSizeofBuffer != 0 )
   {
      // Do something with the bytes read.
      lpszPostedBytes = (LPSTR)( LocalAlloc( LPTR, dwSizeofBuffer+1 ) );
      if (lpszPostedBytes == NULL )
      {
         // Out of memory        
         PostHangupCall();
         return false;
       }
       strncpy( lpszPostedBytes,lpszInputBuffer,dwSizeofBuffer);
       lpszPostedBytes[dwSizeofBuffer] = '\0';
       return (ReceiveData( lpszPostedBytes, dwSizeofBuffer ));
   }
   return false;
}//{TReadThread.HandleReadData}

bool TReadThread::ReceiveData(LPSTR lpNewString,DWORD dwSizeofNewString)
{
   if (! PostMessage(m_handlemsg,USER_RECEIVEDATA,WPARAM(dwSizeofNewString), LPARAM(lpNewString)))
   {
      PostHangupCall();
      return false;
   }
   return true;
}
   


bool TReadThread::ReceiveError(DWORD EvtMask)
{
   if (! PostMessage(m_handlemsg,USER_RECEIVEDATAERROR, 0, LPARAM(EvtMask) ) )
   {   
      PostHangupCall ();
      return false;
   }
   return true; 
}

void TReadThread::PostHangupCall()
//当读线程挂起时,触发挂起线程事件,让用户处理它
{            //接收窗体        读数据时事件挂起标识
   int i=1;
   PostMessage(m_handlemsg,USER_ONCOMMHANGUP, 0, LPARAM(i));
}


IMPLEMENT_DYNAMIC(TWriteThread, CWinThread)
////////////////////////////////////////////////////////
//  过程:  TWriteThread::TWriteThread
//
//  目的: 写线程的起始点
//
//  参数: 无
//
//  返回值: 无
//
//  注释:
//
//    写线程使用消息循环等待要写入的字符串,当得到后便写入到串口中。
//    如果收到关闭消息,则关闭退出
//    使用消息的方法使得向串口中写数据与用户的操作是不同步的。
/////////////////////////////////////////////////////////////////////////////
TWriteThread::TWriteThread()
{

}

//////////////////////////////////////////////////////////////////
//线程处理实体,当返回FALSE时,表示线程结束
//////////////////////////////////////////////////////////////////
BOOL TWriteThread::InitInstance()
{
   MSG msg;
   DWORD dwHandleSignaled;
   OVERLAPPED overlappedWrite;
   BOOL CompleteOneWriteRequire;
   BOOL contiflag;
   // overlapped 方式的输入输出需要下面处理过的结构体.
   memset( &overlappedWrite,0, sizeof(overlappedWrite));
   overlappedWrite.hEvent = CreateEvent( NULL, true, false, NULL );
   //没有创建适合的事件
   if (overlappedWrite.hEvent == 0 )
   {
      PostHangupCall();
      goto EndWriteThread;
   }
   CompleteOneWriteRequire = false;
   //主循环,直到结束它.
   while (true)
   {      
      contiflag=false;
      if (! PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
      {
         // 如果没有消息则等待消息产生或者操作被停止
         m_pbSendDataEmpty = true;//此时当然没有要传输的数据
         if (CompleteOneWriteRequire) //一次传输完毕告诉用户
         {
            if (!PostMessage(m_handlemsg,USER_DATASENDFINISHED, 0, 0 ) )
            {
               PostHangupCall();
               goto EndWriteThread;
            }
         }
         CompleteOneWriteRequire = false;
         dwHandleSignaled = MsgWaitForMultipleObjects(1, &m_hCloseEvent, false,
                                                       INFINITE, QS_ALLINPUT);
         switch (dwHandleSignaled)
         {
         case WAIT_OBJECT_0:     // 关闭消息!
               // 退出.
               goto EndWriteThread;
               break; 
         case WAIT_OBJECT_0 + 1: // 得到新的消息.
               // 重新循环来处理它.
               contiflag =true;
               break;
         case WAIT_FAILED:       // 超时,不可能出现.
               PostHangupCall();
               goto EndWriteThread;
               break;
         default:                // 不可能出现.
               PostHangupCall();
               goto EndWriteThread;
         }
         if (contiflag) continue;
      }
	   else
	   {
         // 确认在接收数据时是否有关闭消息产生
         if (WAIT_TIMEOUT != WaitForSingleObject(m_hCloseEvent,0) )
            goto EndWriteThread;
         // 处理该条消息,如果此时有对话框出现则下面语句可做范例.
         //本控件用不到
         if (msg.hwnd != NULL )
         {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            continue;
         }

         // 处理得到的消息.
         switch ( msg.message )
         {
         case USER_WRITEPORT:  // 向串口中写入字符串.
            // 向串口中写入字符串.  HandleWriteData
            // 直到写完数据后才返回,
            // 除非出现错误或者端口被关闭.
            if (! HandleWriteData( &overlappedWrite,
                                    (char*)(msg.lParam), DWORD(msg.wParam) ) )
            {
               // 将得到的消息结构体释放
               LocalFree( HLOCAL(msg.lParam) );
               goto EndWriteThread;
            }
			
            CompleteOneWriteRequire = true;//成功完成一次写操作
            // 将写入到消息结构体中的数据空间清空.
            LocalFree( HLOCAL(msg.lParam) );
         }
      }
   } //{main loop}
   //结束写线程.
EndWriteThread:
   PurgeComm(m_hCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
   m_pbSendDataEmpty = true;
   CloseHandle(overlappedWrite.hEvent);
   return false;
}//{TWriteThread.Execute}


////////////////////////////////////////////////////////
//  函数: HandleWriteData(LPOVERLAPPED, LPCSTR, DWORD)
//
//  目的: 向串口文件写入字符串.
//
//  参数:
//    lpOverlappedWrite      - WriteFile函数中使用的LPOVERLAPPED结构体
//    pDataToWrite           - 需要写入的字符串.
//    dwNumberOfBytesToWrite - 字符串的长度.
//
//  返回值:
//    当所有字节都写完时返回真值(非零). 否则返回假值(零)
//
//  注释:
//
//    该函数是写线程的辅助函数,它实际向串口写数据.
//    注意该调用将阻塞直到写线程结束写操作,或者收到结束线程的消息.
//    返回假值时可能的原因是串口被服务提供者关闭
//
bool TWriteThread::HandleWriteData(OVERLAPPED* lpOverlappedWrite,LPSTR pDataToWrite, DWORD dwNumberOfBytesToWrite)
{
   DWORD dwLastError;
   DWORD dwNumberOfBytesWritten,dwWhereToStartWriting,dwHandleSignaled;
   HANDLE HandlesToWaitFor[2];
   //Result = false;//缺省返回值
   dwNumberOfBytesWritten = 0;//已经写的字符为零
   dwWhereToStartWriting = 0; // 从字符串的开始位置写字符串.
   //记录两个事件
   HandlesToWaitFor[0] = m_hCloseEvent;//关闭事件句柄
   HandlesToWaitFor[1] = lpOverlappedWrite->hEvent;
   // 循环,直到将字符写完.
   do
   {
   // 开始进行输入/输出.
      if (! WriteFile( m_hCommFile,//串口文件句柄
                       &(pDataToWrite[ dwWhereToStartWriting ]),//每次接着传输剩下的字符串
                       dwNumberOfBytesToWrite, &dwNumberOfBytesWritten,
                       lpOverlappedWrite ) )
      {
         //如果写操作失败,则下面要得到错误句柄.
         dwLastError = GetLastError();
         // 如果服务提供者关闭了串口或者超时,则将出现下面的错误
         if (dwLastError == ERROR_INVALID_HANDLE)   return false;
         //不可知的错误.
         if (dwLastError != ERROR_IO_PENDING )
         {
            PostHangupCall();//调用用户的相应事件处理程序
            return false;
         };
         // 下面是可以处理的情况.有时没有等待写完数据便返回FALSE
         // 等待写过程结束或者收到了停止信号。
         dwHandleSignaled = WaitForMultipleObjects(2, HandlesToWaitFor,
                             false, INFINITE);

         switch ( dwHandleSignaled )
         {
         case  WAIT_OBJECT_0:     // 收到了关闭消息!
               // 退出.
               return false;

         case WAIT_OBJECT_0 + 1: // 写操作完毕.            
            // 得到写操作的结果
            if (! GetOverlappedResult(m_hCommFile,
                                     lpOverlappedWrite,
                                     &dwNumberOfBytesWritten, true) )
            {
               dwLastError = GetLastError();
               // 当服务提供者关闭端口时将出现下面的错误
               if (dwLastError == ERROR_INVALID_HANDLE)  return false;
               // 其它情况不再做特殊处理,直接退出.
               PostHangupCall();
               return false;
            }            
            break;
         case WAIT_FAILED: // 等待超时,由于参数为真值,所以不可能出现.
            PostHangupCall();
            return false;
         default: // 所以不可能出现.
            PostHangupCall();
            return false;
         }
      }
      //{处理了写操作失败的情况}
      // 记录写过的数据数和剩下的字节数.
      dwNumberOfBytesToWrite -= dwNumberOfBytesWritten; //减
      dwWhereToStartWriting+=dwNumberOfBytesWritten ;//加
   } while (dwNumberOfBytesToWrite > 0);  // 直到写完为止!
   // 写完毕后返回真.
   return true;
}//{TWriteThread.HandleWriteData}

void TWriteThread::PostHangupCall()
//当写线程挂起时,触发挂起线程事件,让用户处理它
{            //接收窗体        写数据时事件挂起标识
   int i=0;
   PostMessage(m_handlemsg,USER_ONCOMMHANGUP, 0, LPARAM(i));
}

⌨️ 快捷键说明

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