title: Serial port reading in c, using WinApi functions; WaitCommEvent fails
body: <p>I tried to write a small event-based application in C for serial port reading (sources below). My program is to use the WinApi functions. The comport.c has the functions written to handle COM-port (open, read, write), the utils.c has some helper functions.</p>
  <p>My program produces always the following output:</p>
  <blockquote>
  <p>COM1 is selected to be listened.</p>
  <p>GetCommMask result: 0x00000029 (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)</p>
  <p>Press any key to proceed...</p>
  <p>I/O is pending (WaitCommEvent)...</p>
  <p>I/O is pending (WaitCommEvent)...</p>
  <p>I/O is pending (WaitCommEvent)...</p>
  <p>I/O is pending (WaitCommEvent)...</p>
  <p>I/O is pending (WaitCommEvent)...</p>
  </blockquote>
  <p>It seems, that the function WaitCommEvent fails, the GetLastError() gives back error 87 (I/O pending).</p>
  <p>Please help me to find out what the problem is, which parameter is invalid? See below the code.</p>
  <p>The main.c:</p>
  <pre><code>#include &quot;stdafx.h&quot;
  #include &quot;comport.h&quot;
  #include &quot;utils.h&quot;
  #include &lt;conio.h&gt;
  
  #define READ_BUFF_MAX_LENGTH    1024
  
  int _tmain(int argc, _TCHAR* argv[])
  {
      DWORD dwEvtMask;
      HANDLE hComPort;
      OVERLAPPED oEventHandler;
      int portNum;
      DWORD readTotal;
      BOOL bOverlappedPending = FALSE;
      char readBuff[READ_BUFF_MAX_LENGTH];
  
      if(2 &gt; argc)
      {
          printf(&quot;Use the program: ZliFuerZlvbusInterface.exe XXX (where XXX is the number of com port), \r\ne.G. for COM1 -&gt; ZliFuerZlvbusInterface.exe 1\r\n&quot;);
          return 1;
      }
      else
      {
          portNum = atoi(argv[1]);
          if(0 == IsValidComNumber(portNum))
          {
              printf(&quot;ERROR: COM port number %d is invalid (parsed from '%s').\r\n&quot;, portNum, argv[1]);
              return 2;
          }
          else
          {
              printf(&quot;COM%d is selected to be listened.\r\n&quot;, portNum);
          }
      }
  
      if(0 == CreateSerialConnection(&amp;hComPort, &amp;oEventHandler, portNum, 1200, 8, EVEN, STOP1))
      {
          return 3;
      }
  
      if(FALSE == GetCommMask(hComPort, &amp;dwEvtMask))
      {
          printf(&quot;GetCommMask failed with error:\r\n&quot;);
          PrintLastErrorText();
          return 4;
      }
      else
      {
          printf(&quot;GetCommMask result: 0x%08X (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)\r\n&quot;, dwEvtMask);
      }
  
      printf(&quot;Press any key to proceed...\r\n&quot;);
      getch();
  
      while(1)
      {
          if(0 != kbhit())
          {
              if(27 == getch()) // ESC pressed
              {
                  printf(&quot;Key ESC pressed, exiting...\r\n&quot;);
                  break;
              }
          }
  
          bOverlappedPending = FALSE;
          readTotal = 0;
  
          if(TRUE == WaitCommEvent(hComPort, &amp;dwEvtMask, &amp;oEventHandler))
          {
              if(dwEvtMask &amp; EV_CTS) // Clear-to-send signal present
              {
                  PrintCurrentDateTime();
                  printf(&quot;COM%d: Clear-to-send signal set\r\n&quot;, portNum);
              }
  
              if(dwEvtMask &amp; EV_RLSD) // Data-carrier-detect signal present
              {
                  PrintCurrentDateTime();
                  printf(&quot;COM%d: Data-carrier-detect signal set\r\n&quot;, portNum);
              }
  
              if(dwEvtMask &amp; EV_RXCHAR) // Data received
              {
                  ReadSerial(&amp;hComPort, &amp;oEventHandler, portNum, readBuff, READ_BUFF_MAX_LENGTH);
              }
          }
          else
          {
              if(ERROR_IO_PENDING == GetLastError())
              {
                  printf(&quot;I/O is pending (WaitCommEvent)...\r\n&quot;);
                  bOverlappedPending = TRUE;
              }
              else
              {
                  printf(&quot;WaitCommEvent failed with error:\r\n&quot;);
                  PrintLastErrorText();
              }
          }
  
          if(TRUE == bOverlappedPending)
          {
              if(FALSE == GetOverlappedResult(hComPort, &amp;oEventHandler, &amp;readTotal, TRUE))
              {
                  printf(&quot;GetOverlappedResult failed with error:\r\n&quot;);
                  PrintLastErrorText();
              }
          }
      }
  
      CloseSerialConnection(&amp;hComPort);
  
      return 0;
  }
  </code></pre>
  <p>The comport.c:</p>
  <pre><code>#include &lt;stdio.h&gt;
  #include &quot;comport.h&quot;
  #include &quot;utils.h&quot;
  
  int IsValidComNumber(int com)
  {
      if ((com &lt; 1) ||
          (com &gt; 256))
      {
          return 0;
      }
  
      return 1;
  }
  
  int IsValidBaud(int baud)
  {
      switch(baud)
      {
      case CBR_110:
      case CBR_300:
      case CBR_600:
      case CBR_1200:
      case CBR_2400:
      case CBR_4800:
      case CBR_9600:
      case CBR_14400:
      case CBR_19200:
      case CBR_38400:
      case CBR_56000:
      case CBR_57600:
      case CBR_115200:
      case CBR_128000:
      case CBR_256000:
          {
              return 1;
              break;
          }
      default:
          {
              break;
          }
      }
  
      return 0;
  }
  
  int IsValidBits(int bits)
  {
      if ((bits &lt; 5) ||
          (bits &gt; 8))
      {
          return 0;
      }
      else
      {
          return 1;
      }
  }
  
  int CreateSerialConnection(HANDLE* handle, OVERLAPPED* overlapped, int portNumber, int baud, int bits, enum ParType parity, enum StopType stopbits)
  {
      DCB dcb;
      COMMTIMEOUTS timeouts;
      TCHAR portVirtualFile[32];
      
      // For serial port name this format must be used (as virtual file): &quot;\\\\.\\COMx&quot;
      memset(portVirtualFile, 0, 32);
  #ifdef _UNICODE
      swprintf(portVirtualFile, 32, L&quot;\\\\.\\COM%d&quot;, portNumber);
  #else
      sprintf_s(portVirtualFile, 32, &quot;\\\\.\\COM%d&quot;, portNumber);
  #endif
  
      if(0 == IsValidBaud(baud))
      {
          printf(&quot;ERROR: Specified baud rate %d is invalid for serial connection to COM%d.\r\n&quot;, baud, portNumber);
          return 0;
      }
  
      if(0 == IsValidBits(bits))
      {
          printf(&quot;ERROR: Specified number of data bits %d is invalid for serial connection to COM%d.\r\n&quot;, bits, portNumber);
          return 0;
      }
  
      *handle = CreateFile(portVirtualFile,    // Specify port device
          GENERIC_READ | GENERIC_WRITE,        // Specify mode that open device.
          0,                                    // the devide isn't shared.
          NULL,                                // the object gets a default security.
          OPEN_EXISTING,                        // Specify which action to take on file. 
          FILE_FLAG_OVERLAPPED,                // Use overlapped I/O.
          NULL);                                // default.
  
      if(*handle == INVALID_HANDLE_VALUE)
      {
          printf(&quot;ERROR: Opening serial port COM%d failed\r\n&quot;, portNumber);
          return 0;
      }
  
      if(FALSE == GetCommState(*handle, &amp;dcb))
      {
          printf(&quot;ERROR: Getting current state of COM%d\r\n&quot;, portNumber);
          PrintLastErrorText();
          return 0;
      }
  
      memset(&amp;dcb, 0, sizeof(dcb));    //zero initialize the structure
      dcb.DCBlength = sizeof(dcb);    //fill in length
      dcb.BaudRate = baud;        // baud rate
      dcb.ByteSize = bits;        // data size, xmit and rcv
      dcb.Parity   = parity;        // parity bit
      dcb.StopBits = stopbits;    // stop bits
  
      if(FALSE == SetCommState(*handle, &amp;dcb))
      {
          printf(&quot;ERROR: Setting new state of COM%d failed.\r\n&quot;, portNumber);
          PrintLastErrorText();
          return 0;
      }
  
      if(FALSE == SetCommMask(*handle, EV_RXCHAR | EV_CTS | EV_RLSD))
      {
          printf(&quot;ERROR: Setting new COM MASK (events) for COM%d failed.\r\n&quot;, portNumber);
          PrintLastErrorText();
          return 0;
      }
  
      timeouts.ReadIntervalTimeout = MAXDWORD;
      timeouts.ReadTotalTimeoutMultiplier = 0;
      timeouts.ReadTotalTimeoutConstant = 0;
      timeouts.WriteTotalTimeoutMultiplier = 0;
      timeouts.WriteTotalTimeoutConstant = 0;
      if(FALSE == SetCommTimeouts(*handle, &amp;timeouts))
      {
          printf(&quot;ERROR: Setting timeout parameters for COM%d failed.\r\n&quot;, portNumber);
          PrintLastErrorText();
          return 0;
      }
  
      (*overlapped).hEvent = CreateEvent(
          NULL,   // default security attributes 
          TRUE,   // manual-reset event 
          FALSE,  // not signaled 
          NULL    // no name
      );
  
      
      if(NULL == overlapped-&gt;hEvent)
      {
          printf(&quot;ERROR: CreateEvent for COM%d failed.\r\n&quot;, portNumber);
          PrintLastErrorText();
          return 0;
      }
  
      // Initialize the rest of the OVERLAPPED structure to zero.
      overlapped-&gt;Internal = 0;
      overlapped-&gt;InternalHigh = 0;
      overlapped-&gt;Offset = 0;
      overlapped-&gt;OffsetHigh = 0;
  
      return 1;
  }
  
  int CloseSerialConnection(HANDLE* handle)
  {
      if(FALSE == CloseHandle(*handle))
      {
          printf(&quot;ERROR: Cannot close handle 0x8.8%X\r\n&quot;, *handle);
          PrintLastErrorText();
          return 0;
      }
      
      *handle = NULL;
      return 1;
  }
  
  int ReadSerial(HANDLE* handle, LPOVERLAPPED ov, int num, char* buffer, int max_len)
  {
      DWORD readTotal = 0;
  
      if(FALSE == ClearCommError(*handle, NULL, NULL))
      {
          printf(&quot;ClearCommError failed with error:\r\n&quot;);
          PrintLastErrorText();
          return 0;
      }
      else
      {
          memset(buffer, 0, max_len);
          if(FALSE == ReadFile(*handle, buffer, max_len, &amp;readTotal, ov))
          {
              printf(&quot;ERROR: Reading from port COM%d failed\r\n&quot;, num);
              if(ERROR_IO_PENDING == GetLastError())
              {
                  printf(&quot;I/O is pending (ReadFile)...\r\n&quot;);
                  
                  if(FALSE == GetOverlappedResult(*handle, ov, &amp;readTotal, TRUE))
                  {
                      printf(&quot;GetOverlappedResult failed with error:\r\n&quot;);
                      PrintLastErrorText();
                      return 0;
                  }
              }
              else
              {
                  PrintLastErrorText();
                  return 0;
              }
          }
          else
          {
              PrintCurrentDateTime();
              printf(&quot;Received %d characters on port COM%d: &quot;, readTotal, num);
              PrintBufferContent(buffer, readTotal);
          }
      }
  
      return 1;
  }
  </code></pre>
  <p>The utils.c:</p>
  <pre><code>#include &lt;Windows.h&gt;
  #include &lt;stdio.h&gt;
  #include &quot;utils.h&quot;
  
  void PrintLastErrorText(void)
  {
      DWORD retSize;
      LPTSTR pTemp = NULL;
  
      retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&amp;pTemp, 0, NULL);
      if ((retSize &gt; 0) &amp;&amp;
          (pTemp != NULL))
      {
          printf(&quot;Last error: %s (0x%08X)\r\n&quot;, pTemp, GetLastError());
          LocalFree((HLOCAL)pTemp);
      }
  }
  
  void PrintCurrentDateTime(void)
  {
      SYSTEMTIME systime;
      GetLocalTime(&amp;systime);
      printf(&quot;%04d.%02d.%02d %02d:%02d:%02d:%03d &quot;, systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds);
  }
  
  void PrintBufferContent(char* buff, int len)
  {
      int i;
      for(i = 0; i&lt;len; i++)
      {
          printf(&quot;%02X &quot;, buff[i]);
      }
  }
  </code></pre>