MFC串口编程——使用标准SerialCom类

附件为实现visual studio C++串口通讯的类

使用方法,定义一个类:CSerialCom m_serialCom;

然后使用

m_serialCom.InitPort(this, nPort, nBaud, 'E');
m_serialCom.StartMonitoring();

开始监控报文

 

使用

m_serialCom.ClosePort();

关闭串口

 

同时需要定义一个串口数据消息回调接收函数

ON_MESSAGE(WM_COMM_RXCHAR, &OnReceiveData)

1 LRESULT CVS_CCO_FOR_UpgradeDlg::OnReceiveData(WPARAM wParam, LPARAM lParam)
2 {
3     Uart_Has_RecOneByte = TRUE;
4     uart_time_count = 0;
5     ringq_push(&ringq_rbuff, (BYTE)wParam);
6     
7     return 0;
8 }

 

 

 

附件:SerialCom.cpp

  1 #include "stdafx.h"
  2 #include "SerialCom.h"
  3 #include <assert.h>
  4 //
  5 // Constructor
  6 //
  7 #pragma warning(disable:4996)
  8 CSerialCom::CSerialCom()
  9 {
 10     m_hComm = NULL;
 11     // initialize overlapped structure members to zero
 12     m_ov.Offset = 0;
 13     m_ov.OffsetHigh = 0;
 14     // create events
 15     m_ov.hEvent = NULL;
 16     m_hWriteEvent = NULL;
 17     m_hShutdownEvent = NULL;
 18     m_szWriteBuffer = NULL;
 19     m_nWriteSize = 1;
 20     m_bThreadAlive = FALSE;
 21 }
 22 //
 23 // Delete dynamic memory
 24 //
 25 CSerialCom::~CSerialCom()
 26 {
 27     do
 28     {
 29         SetEvent(m_hShutdownEvent);
 30     } while (m_bThreadAlive);
 31 
 32     TRACE("Thread ended/n");
 33     delete[] m_szWriteBuffer;
 34 }
 35 //
 36 // Initialize the port. This can be port 1 to 4.
 37 //
 38 BOOL CSerialCom::InitPort(CWnd* pPortOwner, // the owner (CWnd) of the port (receives message)
 39     UINT  portnr,  // portnumber (1..8)
 40     UINT  baud,   // baudrate
 41     char  parity,  // parity 
 42     UINT  databits,  // databits 
 43     UINT  stopbits,  // stopbits 
 44     DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc
 45     UINT  writebuffersize) // size to the writebuffer
 46 {
 47     assert(portnr > 0 && portnr < 20);
 48     assert(pPortOwner != NULL);
 49     // if the thread is alive: Kill
 50     if (m_bThreadAlive)
 51     {
 52         do
 53         {
 54             SetEvent(m_hShutdownEvent);
 55         } while (m_bThreadAlive);
 56         TRACE("Thread ended/n");
 57     }
 58     // create events
 59     if (m_ov.hEvent != NULL)
 60         ResetEvent(m_ov.hEvent);
 61     m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 62     if (m_hWriteEvent != NULL)
 63         ResetEvent(m_hWriteEvent);
 64     m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 65 
 66     if (m_hShutdownEvent != NULL)
 67         ResetEvent(m_hShutdownEvent);
 68     m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 69     // initialize the event objects
 70     m_hEventArray[0] = m_hShutdownEvent; // highest priority
 71     m_hEventArray[1] = m_hWriteEvent;
 72     m_hEventArray[2] = m_ov.hEvent;
 73     // initialize critical section
 74     InitializeCriticalSection(&m_csCommunicationSync);
 75 
 76     // set buffersize for writing and save the owner
 77     m_pOwner = pPortOwner;
 78     if (m_szWriteBuffer != NULL)
 79         delete[] m_szWriteBuffer;
 80     m_szWriteBuffer = new char[writebuffersize];
 81     m_nPortNr = portnr;
 82     m_nWriteBufferSize = writebuffersize;
 83     m_dwCommEvents = dwCommEvents;
 84     BOOL bResult = FALSE;
 85     char *szPort = new char[50];
 86     char *szBaud = new char[50];
 87     // now it critical!
 88     EnterCriticalSection(&m_csCommunicationSync);
 89     // if the port is already opened: close it
 90     if (m_hComm != NULL)
 91     {
 92         CloseHandle(m_hComm);
 93         m_hComm = NULL;
 94     }
 95     // prepare port strings
 96     sprintf(szPort, "COM%d", portnr);
 97     sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
 98     // get a handle to the port
 99     m_hComm = CreateFileA(szPort,      // communication port string (COMX)
100         GENERIC_READ | GENERIC_WRITE, // read/write types
101         0,        // comm devices must be opened with exclusive access
102         NULL,       // no security attributes
103         OPEN_EXISTING,     // comm devices must use OPEN_EXISTING
104         FILE_FLAG_OVERLAPPED,   // Async I/O
105         0);       // template must be 0 for comm devices
106     if (m_hComm == INVALID_HANDLE_VALUE)
107     {
108         // port not found
109         delete[] szPort;
110         delete[] szBaud;
111         return FALSE;
112     }
113     // set the timeout values
114     m_CommTimeouts.ReadIntervalTimeout = 1000;
115     m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;
116     m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
117     m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;
118     m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
119     // configure
120     if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
121     {
122         if (SetCommMask(m_hComm, dwCommEvents))
123         {
124             if (GetCommState(m_hComm, &m_dcb))
125             {
126                 m_dcb.EvtChar = 'q';
127                 m_dcb.fRtsControl = RTS_CONTROL_ENABLE;  // set RTS bit high!
128                 if (BuildCommDCBA(szBaud, &m_dcb))
129                 {
130                     if (SetCommState(m_hComm, &m_dcb))
131                         ; // normal operation... continue
132                     else
133                         ProcessErrorMessage("SetCommState()");
134                 }
135                 else
136                     ProcessErrorMessage("BuildCommDCB()");
137             }
138             else
139                 ProcessErrorMessage("GetCommState()");
140         }
141         else
142             ProcessErrorMessage("SetCommMask()");
143     }
144     else
145         ProcessErrorMessage("SetCommTimeouts()");
146     delete[] szPort;
147     delete[] szBaud;
148     // flush the port
149     PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
150     // release critical section
151     LeaveCriticalSection(&m_csCommunicationSync);
152     TRACE("Initialisation for communicationport %d completed./nUse Startmonitor to communicate./n", portnr);
153     return TRUE;
154 }
155 //
156 //  The CommThread Function.
157 //
158 UINT CSerialCom::CommThread(LPVOID pParam)
159 {
160     // Cast the void pointer passed to the thread back to
161     // a pointer of CSerialCom class
162     CSerialCom *port = (CSerialCom*)pParam;
163 
164     // Set the status variable in the dialog class to
165     // TRUE to indicate the thread is running.
166     port->m_bThreadAlive = TRUE;
167 
168     // Misc. variables
169     DWORD BytesTransfered = 0;
170     DWORD Event = 0;
171     DWORD CommEvent = 0;
172     DWORD dwError = 0;
173     COMSTAT comstat;
174     memset(&comstat, 0, sizeof(COMSTAT));
175     BOOL  bResult = TRUE;
176 
177     // Clear comm buffers at startup
178     if (port->m_hComm)  // check if the port is opened
179         PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
180     // begin forever loop.  This loop will run as long as the thread is alive.
181     for (;;)
182     {
183         // Make a call to WaitCommEvent().  This call will return immediatly
184         // because our port was created as an async port (FILE_FLAG_OVERLAPPED
185         // and an m_OverlappedStructerlapped structure specified).  This call will cause the 
186         // m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to 
187         // be placed in a non-signeled state if there are no bytes available to be read,
188         // or to a signeled state if there are bytes available.  If this event handle 
189         // is set to the non-signeled state, it will be set to signeled when a 
190         // character arrives at the port.
191         // we do this for each port!
192         bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);
193         if (!bResult)
194         {
195             // If WaitCommEvent() returns FALSE, process the last error to determin
196             // the reason..
197             switch (dwError = GetLastError())
198             {
199             case ERROR_IO_PENDING:
200             {
201                 // This is a normal return value if there are no bytes
202                 // to read at the port.
203                 // Do nothing and continue
204                 break;
205             }
206             case 87:
207             {
208                 // Under Windows NT, this value is returned for some reason.
209                 // I have not investigated why, but it is also a valid reply
210                 // Also do nothing and continue.
211                 break;
212             }
213             default:
214             {
215                 // All other error codes indicate a serious error has
216                 // occured.  Process this error.
217                 port->ProcessErrorMessage("WaitCommEvent()");
218                 break;
219             }
220             }
221         }
222         else
223         {    /*
224             // If WaitCommEvent() returns TRUE, check to be sure there are
225             // actually bytes in the buffer to read.  
226             //
227             // If you are reading more than one byte at a time from the buffer 
228             // (which this program does not do) you will have the situation occur 
229             // where the first byte to arrive will cause the WaitForMultipleObjects() 
230             // function to stop waiting.  The WaitForMultipleObjects() function 
231             // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state
232             // as it returns.  
233             //
234             // If in the time between the reset of this event and the call to 
235             // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again
236             // to the signeled state. When the call to ReadFile() occurs, it will 
237             // read all of the bytes from the buffer, and the program will
238             // loop back around to WaitCommEvent().
239             // 
240             // At this point you will be in the situation where m_OverlappedStruct.hEvent is set,
241             // but there are no bytes available to read.  If you proceed and call
242             // ReadFile(), it will return immediatly due to the async port setup, but
243             // GetOverlappedResults() will not return until the next character arrives.
244             //
245             // It is not desirable for the GetOverlappedResults() function to be in 
246             // this state.  The thread shutdown event (event 0) and the WriteFile()
247             // event (Event2) will not work if the thread is blocked by GetOverlappedResults().
248             //
249             // The solution to this is to check the buffer with a call to ClearCommError().
250             // This call will reset the event handle, and if there are no bytes to read
251             // we can loop back through WaitCommEvent() again, then proceed.
252             // If there are really bytes to read, do nothing and proceed.
253             */
254             bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
255             if (comstat.cbInQue == 0)
256                 continue;
257         } // end if bResult
258           // Main wait function.  This function will normally block the thread
259           // until one of nine events occur that require action.
260         Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
261         switch (Event)
262         {
263         case 0:
264         {
265             // Shutdown event.  This is event zero so it will be
266             // the higest priority and be serviced first.
267             CloseHandle(port->m_hComm);
268             port->m_hComm = NULL;
269             port->m_bThreadAlive = FALSE;
270 
271             // Kill this thread.  break is not needed, but makes me feel better.
272             AfxEndThread(100);
273             break;
274         }
275         case 2: // read event
276         {
277             GetCommMask(port->m_hComm, &CommEvent);
278             if (CommEvent & EV_RXCHAR)
279                 // Receive character event from port.
280                 ReceiveChar(port, comstat);
281             if (CommEvent & EV_CTS)
282                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
283             if (CommEvent & EV_BREAK)
284                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
285             if (CommEvent & EV_ERR)
286                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
287             if (CommEvent & EV_RING)
288                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
289 
290             if (CommEvent & EV_RXFLAG)
291                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM)0, (LPARAM)port->m_nPortNr);
292 
293             break;
294         }
295         case 1: // write event
296         {
297             // Write character event from port
298             WriteChar(port);
299             break;
300         }
301         } // end switch
302     } // close forever loop
303     return 0;
304 }
305 //
306 // start comm watching
307 //
308 BOOL CSerialCom::StartMonitoring()
309 {
310     if (!(m_Thread = AfxBeginThread(CommThread, this)))
311         return FALSE;
312     TRACE("Thread started/n");
313     return TRUE;
314 }
315 //
316 // Restart the comm thread
317 //
318 BOOL CSerialCom::RestartMonitoring()
319 {
320     TRACE("Thread resumed/n");
321     m_Thread->ResumeThread();
322     return TRUE;
323 }
324 
325 //
326 // Suspend the comm thread
327 //
328 BOOL CSerialCom::StopMonitoring()
329 {
330     TRACE("Thread suspended/n");
331     m_Thread->SuspendThread();
332     return TRUE;
333 }
334 
335 //
336 // If there is a error, give the right message
337 //
338 void CSerialCom::ProcessErrorMessage(char* ErrorText)
339 {
340     char *Temp = new char[200];
341 
342     LPVOID lpMsgBuf;
343     FormatMessage(
344         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
345         NULL,
346         GetLastError(),
347         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
348         (LPTSTR)&lpMsgBuf,
349         0,
350         NULL
351         );
352     sprintf(Temp, "WARNING:  %s Failed with the following error: /n%s/nPort: %d/n", ErrorText, (char*)lpMsgBuf, m_nPortNr);
353     MessageBoxA(NULL, Temp, "Application Error", MB_ICONSTOP);
354     LocalFree(lpMsgBuf);
355     delete[] Temp;
356 }
357 //
358 // Write a character.
359 //
360 void CSerialCom::WriteChar(CSerialCom* port)
361 {
362     BOOL bWrite = TRUE;
363     BOOL bResult = TRUE;
364     DWORD BytesSent = 0;
365     ResetEvent(port->m_hWriteEvent);
366     // Gain ownership of the critical section
367     EnterCriticalSection(&port->m_csCommunicationSync);
368     if (bWrite)
369     {
370         // Initailize variables
371         port->m_ov.Offset = 0;
372         port->m_ov.OffsetHigh = 0;
373         // Clear buffer
374         PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
375         bResult = WriteFile(port->m_hComm,       // Handle to COMM Port
376             port->m_szWriteBuffer,     // Pointer to message buffer in calling finction
377                                        //       strlen((char*)port->m_szWriteBuffer), // Length of message to send
378             port->m_nWriteSize, // Length of message to send
379             &BytesSent,        // Where to store the number of bytes sent
380             &port->m_ov);       // Overlapped structure
381                                 // deal with any error codes
382         if (!bResult)
383         {
384             DWORD dwError = GetLastError();
385             switch (dwError)
386             {
387             case ERROR_IO_PENDING:
388             {
389                 // continue to GetOverlappedResults()
390                 BytesSent = 0;
391                 bWrite = FALSE;
392                 break;
393             }
394             default:
395             {
396                 // all other error codes
397                 port->ProcessErrorMessage("WriteFile()");
398             }
399             }
400         }
401         else
402         {
403             LeaveCriticalSection(&port->m_csCommunicationSync);
404         }
405     } // end if(bWrite)
406     if (!bWrite)
407     {
408         bWrite = TRUE;
409 
410         bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port 
411             &port->m_ov,  // Overlapped structure
412             &BytesSent,  // Stores number of bytes sent
413             TRUE);    // Wait flag
414         LeaveCriticalSection(&port->m_csCommunicationSync);
415         // deal with the error code 
416         //  if (!bResult)  
417         {
418             //   port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");
419         }
420     } // end if (!bWrite)
421       // Verify that the data size send equals what we tried to send
422       // if (BytesSent != strlen((char*)port->m_szWriteBuffer))
423     {
424         //  TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d/n", BytesSent, strlen((char*)port->m_szWriteBuffer));
425     }
426     // ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_TXEMPTY_DETECTED, (WPARAM) RXBuff, (LPARAM) port->m_nPortNr);
427     ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_TXEMPTY_DETECTED, 0, (LPARAM)port->m_nPortNr);
428 }
429 //
430 // Character received. Inform the owner
431 //
432 void CSerialCom::ReceiveChar(CSerialCom* port, COMSTAT comstat)
433 {
434     BOOL  bRead = TRUE;
435     BOOL  bResult = TRUE;
436     DWORD dwError = 0;
437     DWORD BytesRead = 0;
438     unsigned char RXBuff;
439     for (;;)
440     {
441         // Gain ownership of the comm port critical section.
442         // This process guarantees no other part of this program 
443         // is using the port object. 
444 
445         EnterCriticalSection(&port->m_csCommunicationSync);
446         // ClearCommError() will update the COMSTAT structure and
447         // clear any other errors.
448 
449         bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
450         LeaveCriticalSection(&port->m_csCommunicationSync);
451         // start forever loop.  I use this type of loop because I
452         // do not know at runtime how many loops this will have to
453         // run. My solution is to start a forever loop and to
454         // break out of it when I have processed all of the
455         // data available.  Be careful with this approach and
456         // be sure your loop will exit.
457         // My reasons for this are not as clear in this sample 
458         // as it is in my production code, but I have found this 
459         // solutiion to be the most efficient way to do this.
460 
461         if (comstat.cbInQue == 0)
462         {
463             // break out when all bytes have been read
464             break;
465         }
466 
467         EnterCriticalSection(&port->m_csCommunicationSync);
468         if (bRead)
469         {
470             bResult = ReadFile(port->m_hComm,  // Handle to COMM port 
471                 &RXBuff,    // RX Buffer Pointer
472                 1,     // Read one byte
473                 &BytesRead,   // Stores number of bytes read
474                 &port->m_ov);  // pointer to the m_ov structure
475                                // deal with the error code 
476             if (!bResult)
477             {
478                 switch (dwError = GetLastError())
479                 {
480                 case ERROR_IO_PENDING:
481                 {
482                     // asynchronous i/o is still in progress 
483                     // Proceed on to GetOverlappedResults();
484                     bRead = FALSE;
485                     break;
486                 }
487                 default:
488                 {
489                     // Another error has occured.  Process this error.
490                     port->ProcessErrorMessage("ReadFile()");
491                     break;
492                 }
493                 }
494             }
495             else
496             {
497                 // ReadFile() returned complete. It is not necessary to call GetOverlappedResults()
498                 bRead = TRUE;
499             }
500         }  // close if (bRead)
501         if (!bRead)
502         {
503             bRead = TRUE;
504             bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port 
505                 &port->m_ov,  // Overlapped structure
506                 &BytesRead,  // Stores number of bytes read
507                 TRUE);    // Wait flag
508                           // deal with the error code 
509             if (!bResult)
510             {
511                 port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");
512             }
513         }  // close if (!bRead)
514 
515         LeaveCriticalSection(&port->m_csCommunicationSync);
516         // notify parent that a byte was received
517         ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)RXBuff, (LPARAM)port->m_nPortNr);//发送消息,对应的消息函数接收数据
518     } // end forever loop
519 }
520 //
521 // Write a string to the port
522 //
523 void CSerialCom::WriteToPort(char* string)
524 {
525     assert(m_hComm != 0);
526 
527     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
528     strcpy(m_szWriteBuffer, string);
529     m_nWriteSize = strlen(string);
530     // set event for write
531     SetEvent(m_hWriteEvent);
532 }
533 
534 void CSerialCom::WriteToPort(char* string, int n)
535 {
536     assert(m_hComm != 0);
537     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
538     // memset(m_szWriteBuffer, 0, n);
539     // strncpy(m_szWriteBuffer, string, n);
540     memcpy(m_szWriteBuffer, string, n);
541     m_nWriteSize = n;
542     // set event for write
543     SetEvent(m_hWriteEvent);
544 }
545 
546 
547 #if 0
548 void CSerialCom::WriteToPort(LPCTSTR string)
549 {
550     assert(m_hComm != 0);
551     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
552     strcpy(m_szWriteBuffer, string);
553     m_nWriteSize = strlen(string);
554     // set event for write
555     SetEvent(m_hWriteEvent);
556 }
557 #endif
558 void CSerialCom::WriteToPort(LPCTSTR string, int n)
559 {
560     assert(m_hComm != 0);
561     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));
562     // strncpy(m_szWriteBuffer, string, n);
563     memcpy(m_szWriteBuffer, string, n);
564     m_nWriteSize = n;
565     // set event for write
566     SetEvent(m_hWriteEvent);
567 }
568 //
569 // Return the device control block
570 //
571 DCB CSerialCom::GetDCB()
572 {
573     return m_dcb;
574 }
575 //
576 // Return the communication event masks
577 //
578 DWORD CSerialCom::GetCommEvents()
579 {
580     return m_dwCommEvents;
581 }
582 //
583 // Return the output buffer size
584 //
585 DWORD CSerialCom::GetWriteBufferSize()
586 {
587     return m_nWriteBufferSize;
588 }
589 
590 void CSerialCom::ClosePort()
591 {
592     SetEvent(m_hShutdownEvent);
593 }
594 
595 void CSerialCom::EnumerateSerialPorts(CUIntArray& ports)
596 {
597     ports.RemoveAll();    //Make sure we clear out any elements which may already be in the array
598 
599                         //Determine what OS we are running on
600     OSVERSIONINFO osvi;
601     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
602     BOOL bGetVer = GetVersionEx(&osvi);
603 
604     //On NT use the QueryDosDevice API
605     if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT))
606     {
607         //Use QueryDosDevice to look for all devices of the form COMx. This is a better
608         //solution as it means that no ports have to be opened at all.
609         TCHAR szDevices[65535];
610         DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);
611         if (dwChars) {
612             int i = 0;
613             for (;;) {
614                 TCHAR* pszCurrentDevice = &szDevices[i];    //Add the port number to the array which will be returned
615                                                             //If it looks like "COMX" then
616                                                             //add it to the array which will be returned
617                 int nLen = _tcslen(pszCurrentDevice);
618                 if (nLen > 3 && _tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0) {
619                     int nPort = _ttoi(&pszCurrentDevice[3]);    //Work out the port number
620                     ports.Add(nPort);        //clear out com_0
621                 }
622                 // Go to next NULL character
623                 while (szDevices[i] != _T('\0')) i++;
624                 i++;    // Bump pointer to the next string
625                         // The list is double-NULL terminated, so if the character is
626                         // now NULL, we're at the end
627                 if (szDevices[i] == _T('\0')) break;
628             }
629         }
630         else TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError());
631     }
632     else {
633         //On 95/98 open up each port to determine their existence
634         //Up to 255 COM ports are supported so we iterate through all of them seeing
635         //if we can open them or if we fail to open them, get an access denied or general error error.
636         //Both of these cases indicate that there is a COM port at that number. 
637         for (UINT i = 1; i<256; i++)
638         {
639             //Form the Raw device name
640             CString sPort;
641             sPort.Format(_T("\\\\.\\COM%d"), i);
642 
643             //Try to open the port
644             BOOL bSuccess = FALSE;
645             HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
646             if (hPort == INVALID_HANDLE_VALUE)
647             {
648                 DWORD dwError = GetLastError();
649                 //Check to see if the error was because some other app had the port open or a general failure
650                 if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE)
651                     bSuccess = TRUE;
652             }
653             else {
654                 bSuccess = TRUE;    //The port was opened successfully                
655                 CloseHandle(hPort);    //Don't forget to close the port, since we are going to do nothing with it anyway
656             }
657             if (bSuccess) ports.Add(i);    //Add the port number to the array which will be returned
658         }
659     }
660 }

 

SerialCom.h

 1 #pragma once
 2 
 3 #define WM_COMM_BREAK_DETECTED  WM_USER+1 // A break was detected on input.
 4 #define WM_COMM_CTS_DETECTED  WM_USER+2 // The CTS (clear-to-send) signal changed state. 
 5 #define WM_COMM_DSR_DETECTED  WM_USER+3 // The DSR (data-set-ready) signal changed state. 
 6 #define WM_COMM_ERR_DETECTED  WM_USER+4 // A line-status error occurred. Line-status errors are CE_FRAME, CE_OVERRUN, and CE_RXPARITY. 
 7 #define WM_COMM_RING_DETECTED  WM_USER+5 // A ring indicator was detected. 
 8 #define WM_COMM_RLSD_DETECTED  WM_USER+6 // The RLSD (receive-line-signal-detect) signal changed state. 
 9 #define WM_COMM_RXCHAR    WM_USER+7 // A character was received and placed in the input buffer. 
10 #define WM_COMM_RXFLAG_DETECTED  WM_USER+8 // The event character was received and placed in the input buffer.  
11 #define WM_COMM_TXEMPTY_DETECTED WM_USER+9 // The last character in the output buffer was sent. 
12 class CSerialCom
13 {
14 public:
15     int m_nWriteSize;
16     void ClosePort();
17     // contruction and destruction
18     CSerialCom();
19     virtual  ~CSerialCom();
20     // port initialisation           
21     BOOL  InitPort(CWnd* pPortOwner, UINT portnr = 1, UINT baud = 9600, char parity = 'N', UINT databits = 8, UINT stopbits = 1, DWORD dwCommEvents = EV_RXCHAR, UINT writebuffersize = 1024);
22     HANDLE    m_hComm;
23     // start/stop comm watching
24     BOOL  StartMonitoring();
25     BOOL  RestartMonitoring();
26     BOOL  StopMonitoring();
27     DWORD  GetWriteBufferSize();
28     DWORD  GetCommEvents();
29     DCB   GetDCB();
30     void  WriteToPort(char* string);
31     void  WriteToPort(char* string, int n);
32     void  WriteToPort(LPCTSTR string);
33     void  WriteToPort(LPCTSTR string, int n);
34     void EnumerateSerialPorts(CUIntArray& ports);
35 protected:
36     // protected memberfunctions
37     void  ProcessErrorMessage(char* ErrorText);
38     static UINT CommThread(LPVOID pParam);
39     static void ReceiveChar(CSerialCom* port, COMSTAT comstat);
40     static void WriteChar(CSerialCom* port);
41     // thread
42     CWinThread*   m_Thread;
43     // synchronisation objects
44     CRITICAL_SECTION m_csCommunicationSync;
45     BOOL    m_bThreadAlive;
46     // handles
47     HANDLE    m_hWriteEvent;
48     HANDLE    m_hShutdownEvent;
49     // Event array. 
50     // One element is used for each event. There are two event handles for each port.
51     // A Write event and a receive character event which is located in the overlapped structure (m_ov.hEvent).
52     // There is a general shutdown when the port is closed. 
53     HANDLE    m_hEventArray[3];
54     // structures
55     OVERLAPPED   m_ov;
56     COMMTIMEOUTS  m_CommTimeouts;
57     DCB     m_dcb;
58     // owner window
59     CWnd*    m_pOwner;
60     // misc
61     UINT    m_nPortNr;
62     char*    m_szWriteBuffer;
63     DWORD    m_dwCommEvents;
64     DWORD    m_nWriteBufferSize;    
65 };

 

posted on 2017-02-20 17:16  程序天空下的骆驼  阅读(9040)  评论(0编辑  收藏  举报

导航