Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从串行端口mfc读取信息_C++_Visual C++_Mfc - Fatal编程技术网

C++ 从串行端口mfc读取信息

C++ 从串行端口mfc读取信息,c++,visual-c++,mfc,C++,Visual C++,Mfc,我正在尝试编写一个基于MFC对话框的应用程序,它从PC的串行通信端口读取信息,然后将一些信息写回串行通信端口。你知道我从哪里开始吗 提前谢谢。这有帮助吗?:-) SerialPort.h /////////Macros/Structs等*/ #ifndef\uuu串行端口\uh__ #定义串行端口__ #定义WIN32_精益_和_平均值 #包括 #包括 /*////////////////Classes////////////////////////////////////////////*/

我正在尝试编写一个基于MFC对话框的应用程序,它从PC的串行通信端口读取信息,然后将一些信息写回串行通信端口。你知道我从哪里开始吗

提前谢谢。

这有帮助吗?:-)

SerialPort.h

/////////Macros/Structs等*/
#ifndef\uuu串行端口\uh__
#定义串行端口__
#定义WIN32_精益_和_平均值
#包括
#包括
/*////////////////Classes////////////////////////////////////////////*/
/*////串行端口异常类////////////////////*/
void AfxThrowSerialException(DWORD dwError=0);
类CSerialException:公共CEException
{
公众:
/*构造函数/析构函数*/
CSerialException(DWORD dwError);
~CSerialException();
/*方法*/
#ifdef_调试
虚拟无效转储(CDumpContext&dc)常量;
#恩迪夫
虚拟BOOL GetErrorMessage(LPTSTR lpstrError,UINT nMaxError,PUINT pnHelpContext=NULL);
CString GetErrorMessage();
/*数据成员*/
德沃德·穆德韦罗;
受保护的:
声明动态(CSerialException)
};
/*//实际的串行端口类////////////////////*/
CSerialPort类:公共对象
{
公众:
/*列举*/
枚举流控制{
无流量控制,
CtsRtsFlowControl,
CtsDtrFlowControl,
DsrRtsFlowControl,
DsrDtrFlowControl,
XonXoffFlowControl
};
枚举奇偶校验{
平等,
市场平价,
不平等,
奇偶,
空间奇偶性
};
枚举停止位{
一站式,
一点五位,
两个停止位
};
/*构造函数/析构函数*/
CSerialPort();
~CSerialPort();
/*一般方法*/
静态std::向量枚举串行端口(void);
无效打开(int nPort,DWORD dwBaud=9600,奇偶校验=NoParity,字节数据位=8,
停止位停止位=一个停止位,流量控制fc=无流量控制,BOOL bOverlapped=假);
无效打开(LPCTSTR szPort,DWORD dwBaud=9600,奇偶校验=NoParity,字节数据位=8,
停止位停止位=一个停止位,流量控制fc=无流量控制,BOOL bOverlapped=假);
无效关闭();
无效连接(手柄hComm);
手柄分离();
运算符句柄()常量{return m_hComm;}
BOOL IsOpen()常量{return m_hComm!=无效的句柄值;}
#ifdef_调试
void CSerialPort::Dump(CDumpContext&dc)const;
#恩迪夫
/*阅读/写作方法*/
DWORD Read(无效*lpBuf,DWORD dwCount);
BOOL读取(无效*lpBuf、DWORD dwCount、重叠和重叠);
void ReadEx(void*lpBuf,DWORD dwCount);
DWORD写入(常量无效*lpBuf,DWORD dwCount);
BOOL写入(const void*lpBuf、DWORD dwCount、重叠和重叠);
无效写入(常量无效*lpBuf,DWORD dwCount);
无效传输卡(char cChar);
void GetOverlappedResult(重叠和重叠,
DWORD和DWBYTEST转让,
布尔布韦特);
void CancelIo();
/*配置方法*/
void GetConfig(COMMCONFIG&config);
静态void GetDefaultConfig(int-nPort、COMMCONFIG和config);
void SetConfig(COMMCONFIG&Config);
静态无效SetDefaultConfig(int nPort、COMMCONFIG和config);
/*其他RS232方法*/
void ClearBreak();
无效挫折();
无效清除错误(DWORD和dwErrors);
无效状态(COMSTAT和stat);
无效状态(DCB和DCB);
无效设置状态(DCB和DCB,布尔B关闭端口=假);
无效逃逸(DWORD dwFunc);
void ClearDTR();
void clearts();
void SetDTR();
void SetRTS();
void SetXOFF();
void SetXON();
void GetProperties(COMMPROP&properties);
无效GetModemStatus(DWORD和dwModemStatus);
/*超时*/
无效设置超时(常数通信超时和超时);
无效获取超时(通信超时和超时);
void Set0Timeout();
void Set0WriteTimeout();
void Set0ReadTimeout();
/*事件方法*/
无效设置掩码(DWORD dwMask);
无效获取掩码(DWORD和dwMask);
无效等待事件(DWORD和dwMask);
无效等待事件(DWORD和dwMask,重叠和重叠);
/*队列方法*/
无效冲洗();
无效清除(DWORD dwFlags);
void TerminateOutstandingWrites();
void TerminateOutstandingReads();
void ClearWriteBuffer();
void ClearReadBuffer();
无效设置(DWORD dwOutQueue、DWORD dwOutQueue);
/*可重写*/
完成时的虚拟无效(DWORD dwErrorCode、DWORD dwCount、LPOVERLAPPED LPOVERLAPPED);
受保护的:
句柄m_hComm;/*到通信端口的句柄*/
BOOL m_bOverlapped;/*端口是否在重叠IO中打开*/
静态无效WINAPI_OnCompletion(DWORD dwErrorCode、DWORD dwCount、LPOVERLAPPED LPOVERLAPPED);
声明动态(CSerialPort)
私人:
void OpenComm(LPCTSTR szPort,DWORD dwBaud=9600,奇偶校验=noprity,字节数据位=8,
停止位停止位=一个停止位,流量控制fc=无流量控制,BOOL bOverlapped=假);
};
#endif/*\uuu串行端口\u H\uu*/
SerialPort.cpp

///////////////////////Includes///////Includes////*/
#包括“stdafx.h”
#包括
#包括“serialport.h”
#包括“winerror.h”
/*////////////////////////defines//////////////////////////////*/
#ifdef_调试
#定义新调试\u新
#取消定义此文件
静态字符此\u文件[]=\u文件\u;
#恩迪夫
/*/////////////////////Implementation//////////////////*/
/*类,该类处理必须在运行时构造的CancelIo函数
*因为它没有在NT 3.51或Windows 95上实现。避开
/* /////////////////// Macros / Structs etc ////////////////////////// */

#ifndef __SERIALPORT_H__
#define __SERIALPORT_H__

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <vector>


/* ///////////////////////// Classes /////////////////////////////////////////// */


/* //// Serial port exception class //////////////////////////////////////////// */

void AfxThrowSerialException(DWORD dwError = 0);

class CSerialException : public CException
{
 public:
  /* Constructors / Destructors */
  CSerialException (DWORD dwError);
  ~CSerialException ();

  /* Methods */
#ifdef _DEBUG
  virtual void  Dump(CDumpContext & dc) const;
#endif

  virtual BOOL    GetErrorMessage(LPTSTR lpstrError, UINT nMaxError, PUINT pnHelpContext = NULL);
  CString         GetErrorMessage();

  /* Data members */
  DWORD m_dwError;

 protected:
  DECLARE_DYNAMIC(CSerialException)
};


/* // The actual serial port class ///////////////////////////////////////////// */

class CSerialPort : public CObject
{
 public:
  /* Enums */
  enum FlowControl {
    NoFlowControl,
    CtsRtsFlowControl,
    CtsDtrFlowControl,
    DsrRtsFlowControl,
    DsrDtrFlowControl,
    XonXoffFlowControl
  };

  enum Parity {
    EvenParity,
    MarkParity,
    NoParity,
    OddParity,
    SpaceParity
  };

  enum StopBits {
    OneStopBit,
    OnePointFiveStopBits,
    TwoStopBits
  };

  /* Constructors / Destructors */
  CSerialPort ();
  ~CSerialPort ();

  /* General Methods */
  static std::vector<CString> EnumSerialPorts( void );

  void Open(int nPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8, 
            StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
  void Open(LPCTSTR szPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8, 
            StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
  void    Close();
  void    Attach(HANDLE hComm);
  HANDLE  Detach();

  operator HANDLE() const { return m_hComm; }
  BOOL IsOpen() const { return m_hComm != INVALID_HANDLE_VALUE; }
#ifdef _DEBUG
  void CSerialPort::Dump(CDumpContext & dc) const;
#endif


  /* Reading / Writing Methods */
  DWORD         Read(void *lpBuf, DWORD dwCount);
  BOOL          Read(void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped);
  void          ReadEx(void *lpBuf, DWORD dwCount);
  DWORD         Write(const void *lpBuf, DWORD dwCount);
  BOOL          Write(const void *lpBuf, DWORD dwCount, OVERLAPPED &overlapped);
  void          WriteEx(const void *lpBuf, DWORD dwCount);
  void          TransmitChar(char cChar);
  void          GetOverlappedResult(OVERLAPPED & overlapped,
                                    DWORD & dwBytesTransferred,
                                    BOOL bWait);
  void          CancelIo();

  /* Configuration Methods */
  void          GetConfig(COMMCONFIG & config);
  static void   GetDefaultConfig(int nPort, COMMCONFIG & config);
  void          SetConfig(COMMCONFIG & Config);
  static void   SetDefaultConfig(int nPort, COMMCONFIG & config);

  /* Misc RS232 Methods */
  void          ClearBreak();
  void          SetBreak();
  void          ClearError(DWORD & dwErrors);
  void          GetStatus(COMSTAT & stat);
  void          GetState(DCB & dcb);
  void          SetState(DCB & dcb, BOOL bClosePortOnErr = FALSE);
  void          Escape(DWORD dwFunc);
  void          ClearDTR();
  void          ClearRTS();
  void          SetDTR();
  void          SetRTS();
  void          SetXOFF();
  void          SetXON();
  void          GetProperties(COMMPROP & properties);
  void          GetModemStatus(DWORD & dwModemStatus);

  /* Timeouts */
  void          SetTimeouts(const COMMTIMEOUTS& timeouts);
  void          GetTimeouts(COMMTIMEOUTS& timeouts);
  void          Set0Timeout();
  void          Set0WriteTimeout();
  void          Set0ReadTimeout();

  /* Event Methods */
  void          SetMask(DWORD dwMask);
  void          GetMask(DWORD & dwMask);
  void          WaitEvent(DWORD & dwMask);
  void          WaitEvent(DWORD & dwMask, OVERLAPPED & overlapped);

  /* Queue Methods */
  void          Flush();
  void          Purge(DWORD dwFlags);
  void          TerminateOutstandingWrites();
  void          TerminateOutstandingReads();
  void          ClearWriteBuffer();
  void          ClearReadBuffer();
  void          Setup(DWORD dwInQueue, DWORD dwOutQueue);

  /* Overridables */
  virtual void  OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped);

 protected:
  HANDLE      m_hComm;        /* Handle to the comms port */
  BOOL        m_bOverlapped;  /* Is the port open in overlapped IO */

  static void WINAPI  _OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped);

  DECLARE_DYNAMIC(CSerialPort)

 private:
  void OpenComm(LPCTSTR szPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE dataBits = 8, 
            StopBits stopBits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE);
};


#endif /* __SERIALPORT_H__ */
/* ///////////////////////////////  Includes  ////////////////////////////////// */
#include "stdafx.h"
#include <winspool.h>
#include "serialport.h"
#include "winerror.h"


/* /////////////////////////////// defines ///////////////////////////////////// */

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
  static char THIS_FILE[] = __FILE__;
#endif


/* ////////////////////////////// Implementation /////////////////////////////// */


/* Class which handles CancelIo function which must be constructed at run time
 * since it is not imeplemented on NT 3.51 or Windows 95. To avoid the loader
 * bringing up a message such as "Failed to load due to missing export...", the
 * function is constructed using GetProcAddress. The CSerialPort::CancelIo
 * function then checks to see if the function pointer is NULL and if it is it
 * throws an exception using the error code ERROR_CALL_NOT_IMPLEMENTED which
 * is what 95 would have done if it had implemented a stub for it in the first
 * place !!
 */

class _SERIAL_PORT_DATA
{
 public:
/* Constructors /Destructors */
  _SERIAL_PORT_DATA ();
  ~_SERIAL_PORT_DATA ();

  HINSTANCE  m_hKernel32;
  typedef BOOL ( CANCELIO )( HANDLE );
  typedef CANCELIO    *LPCANCELIO;
  LPCANCELIO m_lpfnCancelIo;
};

_SERIAL_PORT_DATA::_SERIAL_PORT_DATA ()
{
  m_hKernel32    = LoadLibrary( _T("KERNEL32.DLL") );
  VERIFY(m_hKernel32 != NULL);
  m_lpfnCancelIo = (LPCANCELIO)GetProcAddress(m_hKernel32, "CancelIo");
}


_SERIAL_PORT_DATA::~_SERIAL_PORT_DATA ()
{
  FreeLibrary(m_hKernel32);
  m_hKernel32 = NULL;
}


/* The local variable which handle the function pointers */

_SERIAL_PORT_DATA _SerialPortData;


/* //////// Exception handling code */

void AfxThrowSerialException(DWORD dwError /* = 0 */)
{
  if(dwError == 0) {
    dwError = ::GetLastError();
  }
  CSerialException *pException = new CSerialException(dwError);

  TRACE( _T("Warning: throwing CSerialException for error %d\n"), dwError );
  THROW( pException );
}


BOOL CSerialException::GetErrorMessage(LPTSTR pstrError, UINT nMaxError, PUINT pnHelpContext)
{
  ASSERT( pstrError != NULL && AfxIsValidString(pstrError, nMaxError) );

  if(pnHelpContext != NULL) {
    *pnHelpContext = 0;
  }
  LPTSTR lpBuffer;
  BOOL   bRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                              NULL,  m_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT),
                              (LPTSTR)&lpBuffer, 0, NULL);

  if(bRet == FALSE) {
    *pstrError = '\0';
  } else {
    lstrcpyn(pstrError, lpBuffer, nMaxError);
    bRet = TRUE;

    LocalFree(lpBuffer);
  }
  return bRet;
} /* GetErrorMessage */


CString CSerialException::GetErrorMessage()
{
  CString rVal;
  LPTSTR  pstrError = rVal.GetBuffer(4096);

  GetErrorMessage(pstrError, 4096, NULL);
  rVal.ReleaseBuffer();
  return rVal;
}


CSerialException::CSerialException (DWORD dwError)
{
  m_dwError = dwError;
}


CSerialException::~CSerialException ()
{}


IMPLEMENT_DYNAMIC(CSerialException, CException)

#ifdef _DEBUG
  void CSerialException::Dump(CDumpContext & dc) const
  {
    CObject::Dump(dc);

    dc << "m_dwError = " << m_dwError;
  }


#endif


/* //////// The actual serial port code */

CSerialPort::CSerialPort ()
{
  m_hComm       = INVALID_HANDLE_VALUE;
  m_bOverlapped = FALSE;
}


CSerialPort::~CSerialPort ()
{
  Close();
}


IMPLEMENT_DYNAMIC(CSerialPort, CObject)

#ifdef _DEBUG
  void CSerialPort::Dump(CDumpContext & dc) const
  {
    CObject::Dump(dc);

    dc << _T("m_hComm = ") << m_hComm << _T("\n");
    dc << _T("m_bOverlapped = ") << m_bOverlapped;
  }


#endif


std::vector<CString> CSerialPort::EnumSerialPorts(void)
{
  /* Clear existing list of COMM ports */
  std::vector<CString> commPortList;

  /* COM ports can be numbered from 1 to 255, loop through all possibilities and add the ones we 
   * find.
   */
  for( UINT i = 1; i < 256; i++ ) {
    //Form the Raw device name
    CString sPort;
    sPort.Format( _T("COM%d"), i );

    COMMCONFIG cc;
    DWORD dwSize = sizeof(cc);
    if( GetDefaultCommConfig(sPort, &cc, &dwSize) != 0 ) {
      commPortList.push_back( (LPCTSTR)sPort );
    }
  }

  return commPortList;
}


void CSerialPort::Open(int nPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopBits,
                       FlowControl fc, BOOL bOverlapped)
{
  /* Validate our parameters */
  ASSERT(nPort > 0 && nPort <= 255);

  /* Call CreateFile to open up the comms port */
  CString sPort;
  sPort.Format(_T("\\\\.\\COM%d"), nPort);

  OpenComm(sPort, dwBaud, parity, dataBits, stopBits, fc, bOverlapped);
}

void CSerialPort::Open(LPCTSTR szPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopBits,
                       FlowControl fc, BOOL bOverlapped)
{
  OpenComm(szPort, dwBaud, parity, dataBits, stopBits, fc, bOverlapped);
}

void CSerialPort::OpenComm(LPCTSTR szPort, DWORD dwBaud, Parity parity, BYTE dataBits, StopBits stopbits, 
              FlowControl fc, BOOL bOverlapped)
{
  m_hComm       = CreateFile(szPort, (GENERIC_READ | GENERIC_WRITE), 0, NULL, OPEN_EXISTING,
                             bOverlapped ? FILE_FLAG_OVERLAPPED : 0, NULL);
  if(m_hComm == INVALID_HANDLE_VALUE) {
    TRACE( _T("Failed to open up the comms port\n") );
    AfxThrowSerialException();
  }
  m_bOverlapped = bOverlapped;

  /* Get the current state prior to changing it */
  DCB dcb;
  GetState(dcb);

  /* Setup the baud rate */
  dcb.BaudRate  = dwBaud;

  /* Setup the Parity */
  switch(parity) {
    case EvenParity:
      dcb.Parity = EVENPARITY;  break;

    case MarkParity:
      dcb.Parity = MARKPARITY;  break;

    case NoParity:
      dcb.Parity = NOPARITY;    break;

    case OddParity:
      dcb.Parity = ODDPARITY;   break;

    case SpaceParity:
      dcb.Parity = SPACEPARITY; break;

    default:
      ASSERT(FALSE);            break;
  }

  /* Setup the data bits */
  dcb.ByteSize = dataBits;

  /* Setup the stop bits */
  switch(stopbits) {
    case OneStopBit:
      dcb.StopBits = ONESTOPBIT;   break;

    case OnePointFiveStopBits:
      dcb.StopBits = ONE5STOPBITS; break;

    case TwoStopBits:
      dcb.StopBits = TWOSTOPBITS;  break;

    default:
      ASSERT(FALSE);               break;
  }

  /* Setup the flow control */
  dcb.fDsrSensitivity = FALSE;
  switch(fc) {
    case NoFlowControl:
    {
      dcb.fOutxCtsFlow = FALSE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fOutX        = FALSE;
      dcb.fInX = FALSE;
      break;
    }

    case CtsRtsFlowControl:
    {
      dcb.fOutxCtsFlow = TRUE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fRtsControl  = RTS_CONTROL_HANDSHAKE;
      dcb.fOutX        = FALSE;
      dcb.fInX = FALSE;
      break;
    }

    case CtsDtrFlowControl:
    {
      dcb.fOutxCtsFlow = TRUE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fDtrControl  = DTR_CONTROL_HANDSHAKE;
      dcb.fOutX        = FALSE;
      dcb.fInX = FALSE;
      break;
    }

    case DsrRtsFlowControl:
    {
      dcb.fOutxCtsFlow = FALSE;
      dcb.fOutxDsrFlow = TRUE;
      dcb.fRtsControl  = RTS_CONTROL_HANDSHAKE;
      dcb.fOutX        = FALSE;
      dcb.fInX = FALSE;
      break;
    }

    case DsrDtrFlowControl:
    {
      dcb.fOutxCtsFlow = FALSE;
      dcb.fOutxDsrFlow = TRUE;
      dcb.fDtrControl  = DTR_CONTROL_HANDSHAKE;
      dcb.fOutX        = FALSE;
      dcb.fInX = FALSE;
      break;
    }

    case XonXoffFlowControl:
    {
      dcb.fOutxCtsFlow = FALSE;
      dcb.fOutxDsrFlow = FALSE;
      dcb.fOutX        = TRUE;
      dcb.fInX = TRUE;
      dcb.XonChar      = 0x11;
      dcb.XoffChar     = 0x13;
      dcb.XoffLim      = 100;
      dcb.XonLim       = 100;
      break;
    }

    default:
    {
      ASSERT(FALSE);
      break;
    }
  }

  /* Now that we have all the settings in place, make the changes */
  SetState(dcb);
} /* Open */


void CSerialPort::Close()
{
  if( IsOpen() ) {
    BOOL bSuccess = CloseHandle(m_hComm);
    m_hComm       = INVALID_HANDLE_VALUE;
    if(!bSuccess) {
      TRACE( _T("Failed to close up the comms port, GetLastError:%d\n"), GetLastError() );
    }
    m_bOverlapped = FALSE;
  }
}


void CSerialPort::Attach(HANDLE hComm)
{
  Close();
  m_hComm = hComm;
}


HANDLE CSerialPort::Detach()
{
  HANDLE hrVal = m_hComm;

  m_hComm = INVALID_HANDLE_VALUE;
  return hrVal;
}


DWORD CSerialPort::Read(void *lpBuf, DWORD dwCount)
{
  ASSERT( IsOpen() );
  ASSERT(!m_bOverlapped);

  DWORD dwBytesRead = 0;
  if( !ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, NULL) ) {
    TRACE( _T("Failed in call to ReadFile\n") );
    AfxThrowSerialException();
  }
  return dwBytesRead;
}


BOOL CSerialPort::Read(void *lpBuf, DWORD dwCount, OVERLAPPED & overlapped)
{
  ASSERT( IsOpen() );
  ASSERT(m_bOverlapped);
  ASSERT(overlapped.hEvent);

  DWORD dwBytesRead = 0;
  BOOL  bSuccess    = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
  if(!bSuccess) {
    if(GetLastError() != ERROR_IO_PENDING) {
      TRACE( _T("Failed in call to ReadFile\n") );
      AfxThrowSerialException();
    }
  }
  return bSuccess;
}


DWORD CSerialPort::Write(const void *lpBuf, DWORD dwCount)
{
  ASSERT( IsOpen() );
  ASSERT(!m_bOverlapped);

  DWORD dwBytesWritten = 0;
  if( !WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, NULL) ) {
    TRACE( _T("Failed in call to WriteFile\n") );
    AfxThrowSerialException();
  }
  return dwBytesWritten;
}


BOOL CSerialPort::Write(const void *lpBuf, DWORD dwCount, OVERLAPPED & overlapped)
{
  ASSERT( IsOpen() );
  ASSERT(m_bOverlapped);
  ASSERT(overlapped.hEvent);

  DWORD dwBytesWritten = 0;
  BOOL  bSuccess       = WriteFile(m_hComm, lpBuf, dwCount, &dwBytesWritten, &overlapped);
  if(!bSuccess) {
    if(GetLastError() != ERROR_IO_PENDING) {
      TRACE( _T("Failed in call to WriteFile\n") );
      AfxThrowSerialException();
    }
  }
  return bSuccess;
}


void CSerialPort::GetOverlappedResult(OVERLAPPED & overlapped,
                                      DWORD & dwBytesTransferred,
                                      BOOL bWait)
{
  ASSERT( IsOpen() );
  ASSERT(m_bOverlapped);
  ASSERT(overlapped.hEvent);

  //DWORD dwBytesWritten = 0;
  if( !::GetOverlappedResult(m_hComm, &overlapped, &dwBytesTransferred, bWait) ) {
    if(GetLastError() != ERROR_IO_PENDING) {
      TRACE( _T("Failed in call to GetOverlappedResult\n") );
      AfxThrowSerialException();
    }
  }
}


void CSerialPort::_OnCompletion(DWORD dwErrorCode, DWORD dwCount, LPOVERLAPPED lpOverlapped)
{
  /* Validate our parameters */
  ASSERT(lpOverlapped);

  /* Convert back to the C++ world */
  CSerialPort *pSerialPort = (CSerialPort *)lpOverlapped->hEvent;
  ASSERT( pSerialPort->IsKindOf( RUNTIME_CLASS(CSerialPort) ) );

  /* Call the C++ function */
  pSerialPort->OnCompletion(dwErrorCode, dwCount, lpOverlapped);
}


void CSerialPort::OnCompletion(DWORD /*dwErrorCode*/, DWORD /*dwCount*/, LPOVERLAPPED lpOverlapped)
{
  /* Just free up the memory which was previously allocated for the OVERLAPPED structure */
  delete lpOverlapped;

  /* Your derived classes can do something useful in OnCompletion, but don't forget to
   * call CSerialPort::OnCompletion to ensure the memory is freed up
   */
}


void CSerialPort::CancelIo()
{
  ASSERT( IsOpen() );

  if(_SerialPortData.m_lpfnCancelIo == NULL) {
    TRACE( _T(
            "CancelIo function is not supported on this OS. You need to be running at least NT 4 or Win 98 to use this function\n") );
    AfxThrowSerialException(ERROR_CALL_NOT_IMPLEMENTED);
  }
  if( !::_SerialPortData.m_lpfnCancelIo(m_hComm) ) {
    TRACE( _T("Failed in call to CancelIO\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::WriteEx(const void *lpBuf, DWORD dwCount)
{
  ASSERT( IsOpen() );

  OVERLAPPED *pOverlapped = new OVERLAPPED;
  ZeroMemory( pOverlapped, sizeof(OVERLAPPED) );
  pOverlapped->hEvent = (HANDLE) this;
  if( !WriteFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion) ) {
    delete pOverlapped;
    TRACE( _T("Failed in call to WriteFileEx\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::ReadEx(void *lpBuf, DWORD dwCount)
{
  ASSERT( IsOpen() );

  OVERLAPPED *pOverlapped = new OVERLAPPED;
  ZeroMemory( pOverlapped, sizeof(OVERLAPPED) );
  pOverlapped->hEvent = (HANDLE) this;
  if( !ReadFileEx(m_hComm, lpBuf, dwCount, pOverlapped, _OnCompletion) ) {
    delete pOverlapped;
    TRACE( _T("Failed in call to ReadFileEx\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::TransmitChar(char cChar)
{
  ASSERT( IsOpen() );

  if( !TransmitCommChar(m_hComm, cChar) ) {
    TRACE( _T("Failed in call to TransmitCommChar\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetConfig(COMMCONFIG & config)
{
  ASSERT( IsOpen() );

  DWORD dwSize = sizeof(COMMCONFIG);
  if( !GetCommConfig(m_hComm, &config, &dwSize) ) {
    TRACE( _T("Failed in call to GetCommConfig\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetConfig(COMMCONFIG & config)
{
  ASSERT( IsOpen() );

  DWORD dwSize = sizeof(COMMCONFIG);
  if( !SetCommConfig(m_hComm, &config, dwSize) ) {
    TRACE( _T("Failed in call to SetCommConfig\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetBreak()
{
  ASSERT( IsOpen() );

  if( !SetCommBreak(m_hComm) ) {
    TRACE( _T("Failed in call to SetCommBreak\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::ClearBreak()
{
  ASSERT( IsOpen() );

  if( !ClearCommBreak(m_hComm) ) {
    TRACE( _T("Failed in call to SetCommBreak\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::ClearError(DWORD & dwErrors)
{
  ASSERT( IsOpen() );

  if( !ClearCommError(m_hComm, &dwErrors, NULL) ) {
    TRACE( _T("Failed in call to ClearCommError\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetDefaultConfig(int nPort, COMMCONFIG & config)
{
  /* Validate our parameters */
  ASSERT(nPort > 0 && nPort <= 255);

  /* Create the device name as a string */
  CString sPort;
  sPort.Format(_T("COM%d"), nPort);

  DWORD   dwSize = sizeof(COMMCONFIG);
  if( !GetDefaultCommConfig(sPort, &config, &dwSize) ) {
    TRACE( _T("Failed in call to GetDefaultCommConfig\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetDefaultConfig(int nPort, COMMCONFIG & config)
{
  /* Validate our parameters */
  ASSERT(nPort > 0 && nPort <= 255);

  /* Create the device name as a string */
  CString sPort;
  sPort.Format(_T("COM%d"), nPort);

  DWORD   dwSize = sizeof(COMMCONFIG);
  if( !SetDefaultCommConfig(sPort, &config, dwSize) ) {
    TRACE( _T("Failed in call to GetDefaultCommConfig\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetStatus(COMSTAT & stat)
{
  ASSERT( IsOpen() );

  DWORD dwErrors;
  if( !ClearCommError(m_hComm, &dwErrors, &stat) ) {
    TRACE( _T("Failed in call to ClearCommError\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetState(DCB& dcb)
{
  ASSERT( IsOpen() );

  if( !GetCommState(m_hComm, &dcb) ) {
    TRACE( _T("Failed in call to GetCommState\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetState(DCB& dcb, BOOL bClosePortOnErr)
{
  ASSERT( IsOpen() );

  if( !SetCommState(m_hComm, &dcb) ) {
    if( bClosePortOnErr == TRUE ) {
      Close();
    }
    TRACE( _T("Failed in call to SetCommState\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::Escape(DWORD dwFunc)
{
  ASSERT( IsOpen() );

  if( !EscapeCommFunction(m_hComm, dwFunc) ) {
    TRACE( _T("Failed in call to EscapeCommFunction\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::ClearDTR()
{
  Escape(CLRDTR);
}


void CSerialPort::ClearRTS()
{
  Escape(CLRRTS);
}


void CSerialPort::SetDTR()
{
  Escape(SETDTR);
}


void CSerialPort::SetRTS()
{
  Escape(SETRTS);
}


void CSerialPort::SetXOFF()
{
  Escape(SETXOFF);
}


void CSerialPort::SetXON()
{
  Escape(SETXON);
}


void CSerialPort::GetProperties(COMMPROP & properties)
{
  ASSERT( IsOpen() );

  if( !GetCommProperties(m_hComm, &properties) ) {
    TRACE( _T("Failed in call to GetCommProperties\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetModemStatus(DWORD & dwModemStatus)
{
  ASSERT( IsOpen() );

  if( !GetCommModemStatus(m_hComm, &dwModemStatus) ) {
    TRACE( _T("Failed in call to GetCommModemStatus\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetMask(DWORD dwMask)
{
  ASSERT( IsOpen() );

  if( !SetCommMask(m_hComm, dwMask) ) {
    TRACE( _T("Failed in call to SetCommMask\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetMask(DWORD & dwMask)
{
  ASSERT( IsOpen() );

  if( !GetCommMask(m_hComm, &dwMask) ) {
    TRACE( _T("Failed in call to GetCommMask\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::Flush()
{
  ASSERT( IsOpen() );

  if( !FlushFileBuffers(m_hComm) ) {
    TRACE( _T("Failed in call to FlushFileBuffers\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::Purge(DWORD dwFlags)
{
  ASSERT( IsOpen() );

  if( !PurgeComm(m_hComm, dwFlags) ) {
    TRACE( _T("Failed in call to PurgeComm\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::TerminateOutstandingWrites()
{
  Purge(PURGE_TXABORT);
}


void CSerialPort::TerminateOutstandingReads()
{
  Purge(PURGE_RXABORT);
}


void CSerialPort::ClearWriteBuffer()
{
  Purge(PURGE_TXCLEAR);
}


void CSerialPort::ClearReadBuffer()
{
  Purge(PURGE_RXCLEAR);
}


void CSerialPort::Setup(DWORD dwInQueue, DWORD dwOutQueue)
{
  ASSERT( IsOpen() );

  if( !SetupComm(m_hComm, dwInQueue, dwOutQueue) ) {
    TRACE( _T("Failed in call to SetupComm\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::SetTimeouts(const COMMTIMEOUTS& timeouts)
{
  ASSERT( IsOpen() );

  if( !SetCommTimeouts(m_hComm, (LPCOMMTIMEOUTS)&timeouts) ) {
    TRACE( _T("Failed in call to SetCommTimeouts\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::GetTimeouts(COMMTIMEOUTS & timeouts)
{
  ASSERT( IsOpen() );

  if( !GetCommTimeouts(m_hComm, &timeouts) ) {
    TRACE( _T("Failed in call to GetCommTimeouts\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::Set0Timeout()
{
  COMMTIMEOUTS Timeouts;

  ZeroMemory( &Timeouts, sizeof(COMMTIMEOUTS) );
  Timeouts.ReadIntervalTimeout         = MAXDWORD;
  Timeouts.ReadTotalTimeoutMultiplier  = 0;
  Timeouts.ReadTotalTimeoutConstant    = 0;
  Timeouts.WriteTotalTimeoutMultiplier = 0;
  Timeouts.WriteTotalTimeoutConstant   = 0;
  SetTimeouts(Timeouts);
}


void CSerialPort::Set0WriteTimeout()
{
  COMMTIMEOUTS Timeouts;

  GetTimeouts(Timeouts);
  Timeouts.WriteTotalTimeoutMultiplier = 0;
  Timeouts.WriteTotalTimeoutConstant   = 0;
  SetTimeouts(Timeouts);
}


void CSerialPort::Set0ReadTimeout()
{
  COMMTIMEOUTS Timeouts;

  GetTimeouts(Timeouts);
  Timeouts.ReadIntervalTimeout        = MAXDWORD;
  Timeouts.ReadTotalTimeoutMultiplier = 0;
  Timeouts.ReadTotalTimeoutConstant   = 0;
  SetTimeouts(Timeouts);
}


void CSerialPort::WaitEvent(DWORD & dwMask)
{
  ASSERT( IsOpen() );
  ASSERT(!m_bOverlapped);

  if( !WaitCommEvent(m_hComm, &dwMask, NULL) ) {
    TRACE( _T("Failed in call to WaitCommEvent\n") );
    AfxThrowSerialException();
  }
}


void CSerialPort::WaitEvent(DWORD & dwMask, OVERLAPPED & overlapped)
{
  ASSERT( IsOpen() );
  ASSERT(m_bOverlapped);
  ASSERT(overlapped.hEvent);

  if( !WaitCommEvent(m_hComm, &dwMask, &overlapped) ) {
    if(GetLastError() != ERROR_IO_PENDING) {
      TRACE( _T("Failed in call to WaitCommEvent\n") );
      AfxThrowSerialException();
    }
  }
}