CSerialPort類解析

 

CSerialPort類的功能及成員函數介紹

CSerialPort類是免費提供的串口累,Codeguru是一個非常不錯的源代碼網站

CSerialPort類支持線連接(非MODEM)的串口編程操作。

CSerialPort類是基於多線程的,其工作流程如下:首先設置好串口參數,再開啓串口檢測工作線程,串口檢測工作線程檢測到串口接收到的數據、流控制事件或其他串口事件後,就以消息方式通知主程序,激發消息處理函數來進行數據處理,這是對接受數據而言的,發送數據可直接向串口發送。

CSerialPort類定義的消息如表

消息名稱

消息號

功能說明

WM_COMM_BREAK_DETECTED

WM_USER+1

檢測到輸入中斷

WM_COMM_CTS_DETECTED

WM_USER+2

檢測到CTS(清除發送)信號狀態改變

WM_COMM_DSR_DETECTED

WM_USER+3

檢測到DSR(數據設備準備就緒)信號狀態改變

WM_COMM_ERR_DETECTED

WM_USER+4

發生線狀態錯誤(包括CE_FRAMECE_OVERRUN,和CE_RXPARITY

WM_COMM_RING_DETECTED

WM_USER+5

檢測到響鈴指示信號

WM_COMM_RLSD_DETECTED

WM_USER+6

檢測到RLSD(接收線信號)狀態改變

WM_COMM_RXCHAR

WM_USER+7

接收到一個字符並已放入接受緩衝區

WM_COMM_RXFLAG_DETECTED

WM_USER+8

檢測到接受到字符(該字符已放入接受緩衝區)事件

WM_COMM_TXEMPTY_DETECTED

WM_USER+9

檢測到發送緩衝區最後一個字符已經被髮送

介紹幾個經常用到的函數:
1、串口初始化函數InitPort

 

BOOL CSerialPort::InitPort(CWnd *pPortOwner,    // the owner (CWnd) of the port (receives message) 
                           UINT  portnr,        // portnumber (1..4) 
                           UINT  baud,            // baudrate 
                           char  parity,        // parity 
                           UINT  databits,        // databits 
                           UINT  stopbits,        // stopbits 
                           DWORD dwCommEvents,    // EV_RXCHAR, EV_CTS etc 
                           UINT  writebuffersize)    // size to the writebuffer 

    assert(portnr > 0 && portnr < 5); 
    assert(pPortOwner != NULL); 
 
    // if the thread is alive: Kill 
    if (m_bThreadAlive) 
    { 
        do 
        { 
            SetEvent(m_hShutdownEvent); 
        } 
        while (m_bThreadAlive); 
        TRACE("Thread ended\n"); 
    } 
 
    // create events 
    if (m_ov.hEvent != NULL) 
        ResetEvent(m_ov.hEvent); 
    m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
    if (m_hWriteEvent != NULL) 
        ResetEvent(m_hWriteEvent); 
    m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
    if (m_hShutdownEvent != NULL) 
        ResetEvent(m_hShutdownEvent); 
    m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
 
    // initialize the event objects 
    m_hEventArray[0] = m_hShutdownEvent;    // highest priority 
    m_hEventArray[1] = m_ov.hEvent; 
    m_hEventArray[2] = m_hWriteEvent; 
 
    // initialize critical section 
    InitializeCriticalSection(&m_csCommunicationSync); 
 
    // set buffersize for writing and save the owner 
    m_pOwner = pPortOwner; 
 
    if (m_szWriteBuffer != NULL) 
        delete [] m_szWriteBuffer; 
    m_szWriteBuffer = new char[writebuffersize]; 
 
    m_nPortNr = portnr; 
 
    m_nWriteBufferSize = writebuffersize; 
    m_dwCommEvents = dwCommEvents; 
 
    BOOL bResult = FALSE; 
    char *szPort = new char[50]; 
    char *szBaud = new char[50]; 
 
    // now it critical! 
    EnterCriticalSection(&m_csCommunicationSync); 
 
    // if the port is already opened: close it 
    if (m_hComm != NULL) 
    { 
        CloseHandle(m_hComm); 
        m_hComm = NULL; 
    } 
 
    // prepare port strings 
    sprintf(szPort, "COM%d", portnr); 
    sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits); 
 
    // get a handle to the port 
    m_hComm = CreateFile(szPort,                        // communication port string (COMX) 
                         GENERIC_READ | GENERIC_WRITE,    // read/write types 
                         0,                                // comm devices must be opened with exclusive access 
                         NULL,                            // no security attributes 
                         OPEN_EXISTING,                    // comm devices must use OPEN_EXISTING 
                         FILE_FLAG_OVERLAPPED,            // Async I/O 
                         0);                            // template must be 0 for comm devices 
 
    if (m_hComm == INVALID_HANDLE_VALUE) 
    { 
        // port not found 
        delete [] szPort; 
        delete [] szBaud; 
 
        return FALSE; 
    } 
 
    // set the timeout values 
    m_CommTimeouts.ReadIntervalTimeout = 1000
    m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000
    m_CommTimeouts.ReadTotalTimeoutConstant = 1000
    m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000
    m_CommTimeouts.WriteTotalTimeoutConstant = 1000
 
    // configure 
    if (SetCommTimeouts(m_hComm, &m_CommTimeouts)) 
    { 
        if (SetCommMask(m_hComm, dwCommEvents)) 
        { 
            if (GetCommState(m_hComm, &m_dcb)) 
            { 
                m_dcb.fRtsControl = RTS_CONTROL_ENABLE;        // set RTS bit high! 
                if (BuildCommDCB(szBaud, &m_dcb)) 
                { 
                    if (SetCommState(m_hComm, &m_dcb)) 
                        ; // normal operation... continue 
                    else 
                        ProcessErrorMessage("SetCommState()"); 
                } 
                else 
                    ProcessErrorMessage("BuildCommDCB()"); 
            } 
            else 
                ProcessErrorMessage("GetCommState()"); 
        } 
        else 
            ProcessErrorMessage("SetCommMask()"); 
    } 
    else 
        ProcessErrorMessage("SetCommTimeouts()"); 
 
    delete [] szPort; 
    delete [] szBaud; 
 
    // flush the port 
    PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 
 
    // release critical section 
    LeaveCriticalSection(&m_csCommunicationSync); 
 
    TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr); 
 
    return TRUE; 

這個函數是用來初始化串口的,即設置串口的通信參數:需要打開的串口號、波特率、奇偶校驗方式、數據位、停止位,這裏還可 以用來進行事件的設定。

如果串口初始化成功,就返回TRUE,若串口被其他設備佔用、不存在或存在其他股佔,就返回FALSE,編程者可以在這兒提示串口操作是否成功。

如果在當前主串口調用這個函數,那麼pPortOwner可用this指針表示,串口號在函數中做了限制,只能用1234四個串口號,而事實上在編程時可能用到更多串口號,可以通過通過註釋掉本函數中的“assert(portur>0&&portnr<5)”語句取消對串口號的限制。

 

2、啓動串口通信監測線程函數StartMonitoring()

 

串口初始化成功後,就可以調用BOOL StartMonitoring()來啓動串口檢測線程,線程啓動成功,發揮TRUE

BOOL CSerialPort::StartMonitoring() 

if (!(m_Thread = AfxBeginThread(CommThread, this))) 

return FALSE; 

TRACE("Thread started\n"); 

return TRUE; 

3、暫停或停止監測線程函數StopMonitoring()

該函數暫停或停止串口檢測,要注意的是,調用該函數後,串口資源仍然被佔用
// Suspend the comm thread 
// 
BOOL CSerialPort::StopMonitoring() 

     TRACE("Thread suspended\n"); 
     m_Thread->SuspendThread(); 
     return TRUE; 

4、關閉串口函數ClosePort()

該函數功能是關閉串口,釋放串口資源,調用該函數後,如果要繼續使用串口,還需要調用InitPort()函數

5、通過串口發送字符/寫串口函數WriteToPort()

該函數完成寫串口功能,即向串口發送字符。

// Write a string to the port 

void CSerialPort::WriteToPort(char *string) 

{

assert(m_hComm != 0); 

memset(m_szWriteBuffer, 0sizeof(m_szWriteBuffer)); 

strcpy(m_szWriteBuffer, string); 
 

// set event for write 

SetEvent(m_hWriteEvent); 


以上是常用的函數介紹,熟悉該類的使用後,可以仔細看看其他函數,對上面介紹的函數,在對串口資源的使用上要記住一下三點:

打開串口用調用InitPort()和StartMonitoring();關閉串口用StopMonitoring()和ClosePort()而且以上函數的調用順序不能亂

通過串口發送字符調用函數WriteToPort()

接受串口收到的字符需要自己編寫WM_COMM_RXCHAR消息處理函數,需要手工添加。

操作:

首先,需要操作一個串口,所以只需要定義1個類對象就可以了,如要操作多個串口,則要爲每個串口均定一個類對象,這可以通過數據方式來實現,這裏定義的類對象爲m_SerialPort,再定義一個布爾變量m_bSerialPortOpened用來標誌串口是否打開。

CserialPort類中有多個串口事件可以響應,在一般串口編程中,只需要處理WM_COMM_RXCHAR消息就可以了,該類所有的消息均需要人工添加消息處理函數,將處理函數名定義爲OnComm(),首先在SerialPortTestDlg.h(頭文件)中添加串口字符接受消息WM_COMM_RXCHAR(串口接受緩衝區內有一個字符)的響應函數聲明:

//Generated message map funnctions 
//{{AFX_MSG(CSCportTestView) 
afx_msg long OnComm(WPARAM ch, LPARAM port); 
//}}AFX_MSG 
 

然後在,SerilPortTestDlg.cpp文件中進行WM_COMM_RXCHAR消息映射

BEGIN_MESSAE_MAP(CSerialPortTestDlg, CDialog)s 
//{{AFX_MSG_MAP(CSerialPortTestDlg) 
ON_MESSAGE(WM_COMM_RXCHAR, OnComm) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 接着,在SerialPortTestDlg.cpp文件中加入函數OnComm()的實現,並在其中完成對節誒受到的字符的處理,將接收到的字符顯示在接受編輯框中:

long CSerialPortTestDlg::OnComm(WPARAM ch, LPARAM port) 
    m_strEditReceiveMsg += ch; 
    UpdateData(FLASE);//將接收到的字符顯示在接受編輯框中 
    returne 0

說明:WPARAMLPARAM類型是多態數據類型,在WIN32中爲32位,支持多種數據類型,根據需要自動適應,這樣,程序有很強的適應性,再次,我們可以分貝理解爲charinteger類型數據,每當串口接受緩衝區內有一個字符時,就會產生一個WM_COMM_RXCHAR消息,除法OnComm()函數,這時就可以在函數中進行數據處理,所以,這個消息就是整個程序的源頭。


雖然CSerialPort類是一個非常好的類,但畢竟只是集中了作者一個人的智慧和經驗,他也有許多缺陷,

原類只能發送字符(ASCII文本)不能處理二進制發送(也就是不能發送0X00

該類不能很好的釋放串口

存在內存泄漏

可以進行如下改進

改進一、ASCII文本和二進制數據發送方式兼容

CSerialPort類中只有一個發送函數WriteToPort()

// 
// Write a string to the port 
// 
void CSerialPort::WriteToPort(char *string) 
    assert(m_hComm != 0); 
 
    memset(m_szWriteBuffer, 0sizeof(m_szWriteBuffer)); 
    strcpy(m_szWriteBuffer, string); 
 
    // set event for write 
    SetEvent(m_hWriteEvent); 
調用上面的函數就只能用字符串方式,而c語言中,空字符(NULL,其中ASCII碼值爲0,即通常所說的十六禁止0x00字符),是串結束符,當檢測到NULL字符後,就認爲該字符串結束了,所以0x00字符以ASCII文本方式是不能從串口發送出去的,那麼解決這一問題的方法就是用二進制發送,其實這裏說的二進制,只不過是不以我們通常所說的“可見”或“能顯示的字符”發送,比如,要發如下的一組值:
char chSend[5]={0x33,0x96,0x00,0x31,0xf1};

下面來對類做一些改進,解決這個問題,原理就是用字符數據來發送數據,並在發送時指定其長度,這樣,數據沒有發送完,發送過程就不會停止,CSerialPort類是用API函數編寫的在,只要在WriteFile()函數中指定其實際要發送的長度,就可以將數據全部發送出去:

實現步驟如下:

1、SerialPort.h文件中爲CSerialPort類添加一個整形public成員變量,:int m_nWriteSize;用於指定發送字符數據的長度

添加三個發送函數

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

 

cpp文件:
  1. CSerialPort.cpp   
  2. /*  
  3.   
  4. ** FILENAME CSerialPort.cpp  
  5.   
  6. **  
  7.   
  8. ** PURPOSE This class can read, write and watch one serial port.  
  9.   
  10. ** It sends messages to its owner when something happends on the port  
  11.   
  12. ** The class creates a thread for reading and writing so the main  
  13.   
  14. ** program is not blocked.  
  15.   
  16. **  
  17.   
  18. ** CREATION DATE 15-09-1997  
  19.   
  20. ** LAST MODIFICATION 12-11-1997  
  21.   
  22. **  
  23.   
  24. ** AUTHOR Remon Spekreijse  
  25.   
  26. **  
  27.   
  28. **  
  29.   
  30. */   
  31.    
  32.    
  33. #include "stdafx.h"   
  34.    
  35. #include "CSerialPort.h"   
  36.    
  37. #include <assert.h>   
  38.    
  39.    
  40. //   
  41.    
  42. // Constructor   
  43.    
  44. //   
  45.    
  46. CSerialPort::CSerialPort()   
  47.    
  48. {   
  49.    
  50.     m_hComm = NULL;   
  51.    
  52.    
  53.     // initialize overlapped structure members to zero   
  54.    
  55.     m_ov.Offset = 0;   
  56.    
  57.     m_ov.OffsetHigh = 0;   
  58.    
  59.    
  60.     // create events   
  61.    
  62.     m_ov.hEvent = NULL;   
  63.    
  64.     m_hWriteEvent = NULL;   
  65.    
  66.     m_hShutdownEvent = NULL;   
  67.    
  68.    
  69.     m_szWriteBuffer = NULL;   
  70.    
  71.    
  72.     m_bThreadAlive = FALSE;   
  73.    
  74.    
  75.     m_nWriteSize = 0;   
  76.    
  77. }   
  78.    
  79.    
  80. //   
  81.    
  82. // Delete dynamic memory   
  83.    
  84. //   
  85.    
  86. CSerialPort::~CSerialPort()   
  87.    
  88. {   
  89.    
  90.     do   
  91.    
  92.     {   
  93.    
  94.         SetEvent(m_hShutdownEvent);   
  95.    
  96.     }   
  97.     while (m_bThreadAlive);   
  98.    
  99.    
  100.     TRACE("Thread ended\n");   
  101.    
  102.    
  103.     delete [] m_szWriteBuffer;   
  104.    
  105. }   
  106.    
  107.    
  108. //   
  109.    
  110. // Initialize the port. This can be port 1 to 4.   
  111.    
  112. //   
  113.    
  114. BOOL CSerialPort::InitPort(CWnd *pPortOwner, // the owner (CWnd) of the port (receives message)   
  115.    
  116.                            UINT  portnr, // portnumber (1..4)   
  117.    
  118.                            UINT  baud, // baudrate   
  119.    
  120.                            char  parity, // parity   
  121.    
  122.                            UINT  databits, // databits   
  123.    
  124.                            UINT  stopbits, // stopbits   
  125.    
  126.                            DWORD dwCommEvents, // EV_RXCHAR, EV_CTS etc   
  127.    
  128.                            UINT  writebuffersize) // size to the writebuffer   
  129.    
  130. {   
  131.    
  132.     assert(portnr > 0 && portnr < 5);   
  133.    
  134.     assert(pPortOwner != NULL);   
  135.    
  136.    
  137.     // if the thread is alive: Kill   
  138.    
  139.     if (m_bThreadAlive)   
  140.    
  141.     {   
  142.    
  143.         do   
  144.    
  145.         {   
  146.    
  147.             SetEvent(m_hShutdownEvent);   
  148.    
  149.         }   
  150.         while (m_bThreadAlive);   
  151.    
  152.         TRACE("Thread ended\n");   
  153.    
  154.     }   
  155.    
  156.    
  157.     // create events   
  158.    
  159.     if (m_ov.hEvent != NULL)   
  160.    
  161.         ResetEvent(m_ov.hEvent);   
  162.    
  163.     else   
  164.    
  165.         m_ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   
  166.    
  167.    
  168.     if (m_hWriteEvent != NULL)   
  169.    
  170.         ResetEvent(m_hWriteEvent);   
  171.    
  172.     else   
  173.    
  174.         m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   
  175.    
  176.    
  177.     if (m_hShutdownEvent != NULL)   
  178.    
  179.         ResetEvent(m_hShutdownEvent);   
  180.    
  181.     else   
  182.    
  183.         m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);   
  184.    
  185.    
  186.     // initialize the event objects   
  187.    
  188.     m_hEventArray[0] = m_hShutdownEvent; // highest priority   
  189.    
  190.     m_hEventArray[1] = m_ov.hEvent;   
  191.    
  192.     m_hEventArray[2] = m_hWriteEvent;   
  193.    
  194.    
  195.     // initialize critical section   
  196.    
  197.     InitializeCriticalSection(&m_csCommunicationSync);   
  198.    
  199.    
  200.     // set buffersize for writing and save the owner   
  201.    
  202.     m_pOwner = pPortOwner;   
  203.    
  204.    
  205.     if (m_szWriteBuffer != NULL)   
  206.    
  207.         delete [] m_szWriteBuffer;   
  208.    
  209.     m_szWriteBuffer = new char[writebuffersize];   
  210.    
  211.    
  212.     m_nPortNr = portnr;   
  213.    
  214.    
  215.     m_nWriteBufferSize = writebuffersize;   
  216.    
  217.     m_dwCommEvents = dwCommEvents;   
  218.    
  219.    
  220.     BOOL bResult = FALSE;   
  221.    
  222.     char *szPort = new char[50];   
  223.    
  224.     char *szBaud = new char[50];   
  225.    
  226.    
  227.     // now it critical!   
  228.    
  229.     EnterCriticalSection(&m_csCommunicationSync);   
  230.    
  231.    
  232.     // if the port is already opened: close it   
  233.    
  234.     if (m_hComm != NULL)   
  235.    
  236.     {   
  237.    
  238.         CloseHandle(m_hComm);   
  239.    
  240.         m_hComm = NULL;   
  241.    
  242.     }   
  243.    
  244.    
  245.     // prepare port strings   
  246.    
  247.     sprintf(szPort, "COM%d", portnr);   
  248.    
  249.     sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);   
  250.    
  251.    
  252.     // get a handle to the port   
  253.    
  254.     m_hComm = CreateFile(szPort, // communication port string (COMX)   
  255.    
  256.                          GENERIC_READ | GENERIC_WRITE, // read/write types   
  257.    
  258.                          0, // comm devices must be opened with exclusive access   
  259.    
  260.                          NULL, // no security attributes   
  261.    
  262.                          OPEN_EXISTING, // comm devices must use OPEN_EXISTING   
  263.    
  264.                          FILE_FLAG_OVERLAPPED, // Async I/O   
  265.    
  266.                          0); // template must be 0 for comm devices   
  267.    
  268.    
  269.     if (m_hComm == INVALID_HANDLE_VALUE)   
  270.    
  271.     {   
  272.    
  273.         // port not found   
  274.    
  275.         delete [] szPort;   
  276.    
  277.         delete [] szBaud;   
  278.    
  279.    
  280.         return FALSE;   
  281.    
  282.     }   
  283.    
  284.    
  285.     // set the timeout values   
  286.    
  287.     m_CommTimeouts.ReadIntervalTimeout = 1000;   
  288.    
  289.     m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;   
  290.    
  291.     m_CommTimeouts.ReadTotalTimeoutConstant = 1000;   
  292.    
  293.     m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;   
  294.    
  295.     m_CommTimeouts.WriteTotalTimeoutConstant = 1000;   
  296.    
  297.    
  298.     // configure   
  299.    
  300.     if (SetCommTimeouts(m_hComm, &m_CommTimeouts))   
  301.    
  302.     {   
  303.    
  304.         if (SetCommMask(m_hComm, dwCommEvents))   
  305.    
  306.         {   
  307.    
  308.             if (GetCommState(m_hComm, &m_dcb))   
  309.    
  310.             {   
  311.    
  312.                 m_dcb.fRtsControl = RTS_CONTROL_ENABLE; // set RTS bit high!   
  313.    
  314.                 if (BuildCommDCB(szBaud, &m_dcb))   
  315.    
  316.                 {   
  317.    
  318.                     if (SetCommState(m_hComm, &m_dcb))   
  319.    
  320.                         ; // normal operation... continue   
  321.    
  322.                     else   
  323.    
  324.                         ProcessErrorMessage("SetCommState()");   
  325.    
  326.                 }   
  327.    
  328.                 else   
  329.    
  330.                     ProcessErrorMessage("BuildCommDCB()");   
  331.    
  332.             }   
  333.    
  334.             else   
  335.    
  336.                 ProcessErrorMessage("GetCommState()");   
  337.    
  338.         }   
  339.    
  340.         else   
  341.    
  342.             ProcessErrorMessage("SetCommMask()");   
  343.    
  344.     }   
  345.    
  346.     else   
  347.    
  348.         ProcessErrorMessage("SetCommTimeouts()");   
  349.    
  350.    
  351.     delete [] szPort;   
  352.    
  353.     delete [] szBaud;   
  354.    
  355.    
  356.     // flush the port   
  357.    
  358.     PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);   
  359.    
  360.    
  361.     // release critical section   
  362.    
  363.     LeaveCriticalSection(&m_csCommunicationSync);   
  364.    
  365.    
  366.     TRACE("Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", portnr);   
  367.    
  368.    
  369.     return TRUE;   
  370.    
  371. }   
  372.    
  373.    
  374. //   
  375.    
  376. //  The CommThread Function.   
  377.    
  378. //   
  379.    
  380. UINT CSerialPort::CommThread(LPVOID pParam)   
  381.    
  382. {   
  383.    
  384.     // Cast the void pointer passed to the thread back to   
  385.    
  386.     // a pointer of CSerialPort class   
  387.    
  388.     CSerialPort *port = (CSerialPort *)pParam;   
  389.    
  390.    
  391.     // Set the status variable in the dialog class to   
  392.    
  393.     // TRUE to indicate the thread is running.   
  394.    
  395.     port->m_bThreadAlive = TRUE;   
  396.    
  397.    
  398.     // Misc. variables   
  399.    
  400.     DWORD BytesTransfered = 0;   
  401.    
  402.     DWORD Event = 0;   
  403.    
  404.     DWORD CommEvent = 0;   
  405.    
  406.     DWORD dwError = 0;   
  407.    
  408.     COMSTAT comstat;   
  409.    
  410.     BOOL  bResult = TRUE;   
  411.    
  412.    
  413.     // Clear comm buffers at startup   
  414.    
  415.     if (port->m_hComm) // check if the port is opened   
  416.    
  417.         PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);   
  418.    
  419.    
  420.     // begin forever loop.  This loop will run as long as the thread is alive.   
  421.    
  422.     for (;;)   
  423.    
  424.     {   
  425.    
  426.    
  427.         // Make a call to WaitCommEvent().  This call will return immediatly   
  428.    
  429.         // because our port was created as an async port (FILE_FLAG_OVERLAPPED   
  430.    
  431.         // and an m_OverlappedStructerlapped structure specified).  This call will cause the   
  432.    
  433.         // m_OverlappedStructerlapped element m_OverlappedStruct.hEvent, which is part of the m_hEventArray to   
  434.    
  435.         // be placed in a non-signeled state if there are no bytes available to be read,   
  436.    
  437.         // or to a signeled state if there are bytes available.  If this event handle   
  438.    
  439.         // is set to the non-signeled state, it will be set to signeled when a   
  440.    
  441.         // character arrives at the port.   
  442.    
  443.    
  444.         // we do this for each port!   
  445.    
  446.    
  447.         bResult = WaitCommEvent(port->m_hComm, &Event, &port->m_ov);   
  448.    
  449.    
  450.         if (!bResult)   
  451.    
  452.         {   
  453.    
  454.             // If WaitCommEvent() returns FALSE, process the last error to determin   
  455.    
  456.             // the reason..   
  457.    
  458.             switch (dwError = GetLastError())   
  459.    
  460.             {   
  461.    
  462.             case ERROR_IO_PENDING:   
  463.    
  464.             {   
  465.    
  466.                 // This is a normal return value if there are no bytes   
  467.    
  468.                 // to read at the port.   
  469.    
  470.                 // Do nothing and continue   
  471.    
  472.                 break;   
  473.    
  474.             }   
  475.    
  476.             case 87:   
  477.    
  478.             {   
  479.    
  480.                 // Under Windows NT, this value is returned for some reason.   
  481.    
  482.                 // I have not investigated why, but it is also a valid reply   
  483.    
  484.                 // Also do nothing and continue.   
  485.    
  486.                 break;   
  487.    
  488.             }   
  489.    
  490.             default:   
  491.    
  492.             {   
  493.    
  494.                 // All other error codes indicate a serious error has   
  495.    
  496.                 // occured.  Process this error.   
  497.    
  498.                 port->ProcessErrorMessage("WaitCommEvent()");   
  499.    
  500.                 break;   
  501.    
  502.             }   
  503.    
  504.             }   
  505.    
  506.         }   
  507.    
  508.         else   
  509.    
  510.         {   
  511.    
  512.             // If WaitCommEvent() returns TRUE, check to be sure there are   
  513.    
  514.             // actually bytes in the buffer to read.   
  515.    
  516.             //   
  517.    
  518.             // If you are reading more than one byte at a time from the buffer   
  519.    
  520.             // (which this program does not do) you will have the situation occur   
  521.    
  522.             // where the first byte to arrive will cause the WaitForMultipleObjects()   
  523.    
  524.             // function to stop waiting.  The WaitForMultipleObjects() function   
  525.    
  526.             // resets the event handle in m_OverlappedStruct.hEvent to the non-signelead state   
  527.    
  528.             // as it returns.   
  529.    
  530.             //   
  531.    
  532.             // If in the time between the reset of this event and the call to   
  533.    
  534.             // ReadFile() more bytes arrive, the m_OverlappedStruct.hEvent handle will be set again   
  535.    
  536.             // to the signeled state. When the call to ReadFile() occurs, it will   
  537.    
  538.             // read all of the bytes from the buffer, and the program will   
  539.    
  540.             // loop back around to WaitCommEvent().   
  541.    
  542.             //   
  543.    
  544.             // At this point you will be in the situation where m_OverlappedStruct.hEvent is set,   
  545.    
  546.             // but there are no bytes available to read.  If you proceed and call   
  547.    
  548.             // ReadFile(), it will return immediatly due to the async port setup, but   
  549.    
  550.             // GetOverlappedResults() will not return until the next character arrives.   
  551.    
  552.             //   
  553.    
  554.             // It is not desirable for the GetOverlappedResults() function to be in   
  555.    
  556.             // this state.  The thread shutdown event (event 0) and the WriteFile()   
  557.    
  558.             // event (Event2) will not work if the thread is blocked by GetOverlappedResults().   
  559.    
  560.             //   
  561.    
  562.             // The solution to this is to check the buffer with a call to ClearCommError().   
  563.    
  564.             // This call will reset the event handle, and if there are no bytes to read   
  565.    
  566.             // we can loop back through WaitCommEvent() again, then proceed.   
  567.    
  568.             // If there are really bytes to read, do nothing and proceed.   
  569.    
  570.    
  571.             bResult = ClearCommError(port->m_hComm, &dwError, &comstat);   
  572.    
  573.    
  574.             if (comstat.cbInQue == 0)   
  575.    
  576.                 continue;   
  577.    
  578.         } // end if bResult   
  579.    
  580.    
  581.         // Main wait function.  This function will normally block the thread   
  582.    
  583.         // until one of nine events occur that require action.   
  584.    
  585.         Event = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);   
  586.    
  587.    
  588.         switch (Event)   
  589.    
  590.         {   
  591.    
  592.         case 0:   
  593.    
  594.         {   
  595.    
  596.             // Shutdown event.  This is event zero so it will be   
  597.    
  598.             // the higest priority and be serviced first.   
  599.    
  600.    
  601.             port->m_bThreadAlive = FALSE;   
  602.    
  603.    
  604.             // Kill this thread.  break is not needed, but makes me feel better.   
  605.    
  606.             AfxEndThread(100);   
  607.    
  608.             break;   
  609.    
  610.         }   
  611.    
  612.         case 1: // read event   
  613.    
  614.         {   
  615.    
  616.             GetCommMask(port->m_hComm, &CommEvent);   
  617.    
  618.             if (CommEvent & EV_CTS)   
  619.    
  620.                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_CTS_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);   
  621.    
  622.             if (CommEvent & EV_RXFLAG)   
  623.    
  624.                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RXFLAG_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);   
  625.    
  626.             if (CommEvent & EV_BREAK)   
  627.    
  628.                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_BREAK_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);   
  629.    
  630.             if (CommEvent & EV_ERR)   
  631.    
  632.                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_ERR_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);   
  633.    
  634.             if (CommEvent & EV_RING)   
  635.    
  636.                 ::SendMessage(port->m_pOwner->m_hWnd, WM_COMM_RING_DETECTED, (WPARAM) 0, (LPARAM) port->m_nPortNr);   
  637.    
  638.    
  639.             if (CommEvent & EV_RXCHAR)   
  640.    
  641.                 // Receive character event from port.   
  642.    
  643.                 ReceiveChar(port, comstat);   
  644.    
  645.    
  646.             break;   
  647.    
  648.         }   
  649.    
  650.         case 2: // write event   
  651.    
  652.         {   
  653.    
  654.             // Write character event from port   
  655.    
  656.             WriteChar(port);   
  657.    
  658.             break;   
  659.    
  660.         }   
  661.    
  662.    
  663.         } // end switch   
  664.    
  665.    
  666.     } // close forever loop   
  667.    
  668.    
  669.     return 0;   
  670.    
  671. }   
  672.    
  673.    
  674. //   
  675.    
  676. // start comm watching   
  677.    
  678. //   
  679.    
  680. BOOL CSerialPort::StartMonitoring()   
  681.    
  682. {   
  683.    
  684.     if (!(m_Thread = AfxBeginThread(CommThread, this)))   
  685.    
  686.         return FALSE;   
  687.    
  688.     TRACE("Thread started\n");   
  689.    
  690.     return TRUE;   
  691.    
  692. }   
  693.    
  694.    
  695. //   
  696.    
  697. // Restart the comm thread   
  698.    
  699. //   
  700.    
  701. BOOL CSerialPort::RestartMonitoring()   
  702.    
  703. {   
  704.    
  705.     TRACE("Thread resumed\n");   
  706.    
  707.     m_Thread->ResumeThread();   
  708.    
  709.     return TRUE;   
  710.    
  711. }   
  712.    
  713.    
  714.    
  715. //   
  716.    
  717. // Suspend the comm thread   
  718.    
  719. //   
  720.    
  721. BOOL CSerialPort::StopMonitoring()   
  722.    
  723. {   
  724.    
  725.     TRACE("Thread suspended\n");   
  726.    
  727.     m_Thread->SuspendThread();   
  728.    
  729.     return TRUE;   
  730.    
  731. }   
  732.    
  733.    
  734.    
  735. //   
  736.    
  737. // If there is a error, give the right message   
  738.    
  739. //   
  740.    
  741. void CSerialPort::ProcessErrorMessage(char *ErrorText)   
  742.    
  743. {   
  744.    
  745.     char *Temp = new char[200];   
  746.    
  747.    
  748.     LPVOID lpMsgBuf;   
  749.    
  750.    
  751.     FormatMessage(   
  752.    
  753.         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,   
  754.    
  755.         NULL,   
  756.    
  757.         GetLastError(),   
  758.    
  759.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language   
  760.    
  761.         (LPTSTR) &lpMsgBuf,   
  762.    
  763.         0,   
  764.    
  765.         NULL   
  766.    
  767.     );   
  768.    
  769.    
  770.     sprintf(Temp, "WARNING:  %s Failed with the following error: \n%s\nPort: %d\n", (char *)ErrorText, lpMsgBuf, m_nPortNr);   
  771.    
  772.     MessageBox(NULL, Temp, "Application Error", MB_ICONSTOP);   
  773.    
  774.    
  775.     LocalFree(lpMsgBuf);   
  776.    
  777.     delete[] Temp;   
  778.    
  779. }   
  780.    
  781.    
  782. //   
  783.    
  784. // Write a character.   
  785.    
  786. //   
  787.    
  788. void CSerialPort::WriteChar(CSerialPort *port)   
  789.    
  790. {   
  791.    
  792.     BOOL bWrite = TRUE;   
  793.    
  794.     BOOL bResult = TRUE;   
  795.    
  796.    
  797.     DWORD BytesSent = 0;   
  798.    
  799.    
  800.     ResetEvent(port->m_hWriteEvent);   
  801.    
  802.    
  803.     // Gain ownership of the critical section   
  804.    
  805.     EnterCriticalSection(&port->m_csCommunicationSync);   
  806.    
  807.    
  808.     if (bWrite)   
  809.    
  810.     {   
  811.    
  812.         // Initailize variables   
  813.    
  814.         port->m_ov.Offset = 0;   
  815.    
  816.         port->m_ov.OffsetHigh = 0;   
  817.    
  818.    
  819.         // Clear buffer   
  820.    
  821.         PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);   
  822.    
  823.    
  824.         bResult = WriteFile(port->m_hComm, // Handle to COMM Port   
  825.    
  826.                             port->m_szWriteBuffer, // Pointer to message buffer in calling finction   
  827.    
  828.                             //原句 strlen((char*)port->m_szWriteBuffer), // Length of message to send   
  829.    
  830.                             port->m_nWriteSize,//更改後,Length of message to send   
  831.    
  832.                             &BytesSent, // Where to store the number of bytes sent   
  833.    
  834.                             &port->m_ov); // Overlapped structure   
  835.    
  836.    
  837.         // deal with any error codes   
  838.    
  839.         if (!bResult)   
  840.    
  841.         {   
  842.    
  843.             DWORD dwError = GetLastError();   
  844.    
  845.             switch (dwError)   
  846.    
  847.             {   
  848.    
  849.             case ERROR_IO_PENDING:   
  850.    
  851.             {   
  852.    
  853.                 // continue to GetOverlappedResults()   
  854.    
  855.                 BytesSent = 0;   
  856.    
  857.                 bWrite = FALSE;   
  858.    
  859.                 break;   
  860.    
  861.             }   
  862.    
  863.             default:   
  864.    
  865.             {   
  866.    
  867.                 // all other error codes   
  868.    
  869.                 port->ProcessErrorMessage("WriteFile()");   
  870.    
  871.             }   
  872.    
  873.             }   
  874.    
  875.         }   
  876.    
  877.         else   
  878.    
  879.         {   
  880.    
  881.             LeaveCriticalSection(&port->m_csCommunicationSync);   
  882.    
  883.         }   
  884.    
  885.     } // end if(bWrite)   
  886.    
  887.    
  888.     if (!bWrite)   
  889.    
  890.     {   
  891.    
  892.         bWrite = TRUE;   
  893.    
  894.    
  895.         bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port   
  896.    
  897.                                       &port->m_ov, // Overlapped structure   
  898.    
  899.                                       &BytesSent, // Stores number of bytes sent   
  900.    
  901.                                       TRUE);  // Wait flag   
  902.    
  903.    
  904.         LeaveCriticalSection(&port->m_csCommunicationSync);   
  905.    
  906.    
  907.         // deal with the error code   
  908.    
  909.         if (!bResult)   
  910.    
  911.         {   
  912.    
  913.             port->ProcessErrorMessage("GetOverlappedResults() in WriteFile()");   
  914.    
  915.         }   
  916.    
  917.     } // end if (!bWrite)   
  918.    
  919.    
  920.     // Verify that the data size send equals what we tried to send   
  921.    
  922.     //原句 if (BytesSent != strlen((char*)port->m_szWriteBuffer))   
  923.    
  924.     if(BytesSent |= port->m_nWriteSize) //修改後,Length of message to send   
  925.    
  926.     {   
  927.    
  928.         TRACE("WARNING: WriteFile() error.. Bytes Sent: %d; Message Length: %d\n", BytesSent, strlen((char *)port->m_szWriteBuffer));   
  929.    
  930.     }   
  931.    
  932. }   
  933.    
  934.    
  935. //   
  936.    
  937. // Character received. Inform the owner   
  938.    
  939. //   
  940.    
  941. void CSerialPort::ReceiveChar(CSerialPort *port, COMSTAT comstat)   
  942.    
  943. {   
  944.    
  945.     BOOL  bRead = TRUE;   
  946.    
  947.     BOOL  bResult = TRUE;   
  948.    
  949.     DWORD dwError = 0;   
  950.    
  951.     DWORD BytesRead = 0;   
  952.    
  953.     unsigned char RXBuff;   
  954.    
  955.    
  956.     for (;;)   
  957.    
  958.     {   
  959.    
  960.         // Gain ownership of the comm port critical section.   
  961.    
  962.         // This process guarantees no other part of this program   
  963.    
  964.         // is using the port object.   
  965.    
  966.    
  967.    
  968.         //添加信息 防止死鎖   
  969.    
  970.         if(WaitForSingleObject(port->m_hShutdownEvent, 0) == WAIT_OBJECT_0)   
  971.    
  972.             return ;   
  973.    
  974.    
  975.    
  976.         EnterCriticalSection(&port->m_csCommunicationSync);   
  977.    
  978.    
  979.         // ClearCommError() will update the COMSTAT structure and   
  980.    
  981.         // clear any other errors.   
  982.    
  983.    
  984.         bResult = ClearCommError(port->m_hComm, &dwError, &comstat);   
  985.    
  986.    
  987.         LeaveCriticalSection(&port->m_csCommunicationSync);   
  988.    
  989.    
  990.         // start forever loop.  I use this type of loop because I   
  991.    
  992.         // do not know at runtime how many loops this will have to   
  993.    
  994.         // run. My solution is to start a forever loop and to   
  995.    
  996.         // break out of it when I have processed all of the   
  997.    
  998.         // data available.  Be careful with this approach and   
  999.    
  1000.         // be sure your loop will exit.   
  1001.    
  1002.         // My reasons for this are not as clear in this sample   
  1003.    
  1004.         // as it is in my production code, but I have found this   
  1005.    
  1006.         // solutiion to be the most efficient way to do this.   
  1007.    
  1008.    
  1009.         if (comstat.cbInQue == 0)   
  1010.    
  1011.         {   
  1012.    
  1013.             // break out when all bytes have been read   
  1014.    
  1015.             break;   
  1016.    
  1017.         }   
  1018.    
  1019.    
  1020.         EnterCriticalSection(&port->m_csCommunicationSync);   
  1021.    
  1022.    
  1023.         if (bRead)   
  1024.    
  1025.         {   
  1026.    
  1027.             bResult = ReadFile(port->m_hComm, // Handle to COMM port   
  1028.    
  1029.                                &RXBuff, // RX Buffer Pointer   
  1030.    
  1031.                                1, // Read one byte   
  1032.    
  1033.                                &BytesRead, // Stores number of bytes read   
  1034.    
  1035.                                &port->m_ov); // pointer to the m_ov structure   
  1036.    
  1037.             // deal with the error code   
  1038.    
  1039.             if (!bResult)   
  1040.    
  1041.             {   
  1042.    
  1043.                 switch (dwError = GetLastError())   
  1044.    
  1045.                 {   
  1046.    
  1047.                 case ERROR_IO_PENDING:   
  1048.    
  1049.                 {   
  1050.    
  1051.                     // asynchronous i/o is still in progress   
  1052.    
  1053.                     // Proceed on to GetOverlappedResults();   
  1054.    
  1055.                     bRead = FALSE;   
  1056.    
  1057.                     break;   
  1058.    
  1059.                 }   
  1060.    
  1061.                 default:   
  1062.    
  1063.                 {   
  1064.    
  1065.                     // Another error has occured.  Process this error.   
  1066.    
  1067.                     port->ProcessErrorMessage("ReadFile()");   
  1068.    
  1069.                     break;   
  1070.    
  1071.                 }   
  1072.    
  1073.                 }   
  1074.    
  1075.             }   
  1076.    
  1077.             else   
  1078.    
  1079.             {   
  1080.    
  1081.                 // ReadFile() returned complete. It is not necessary to call GetOverlappedResults()   
  1082.    
  1083.                 bRead = TRUE;   
  1084.    
  1085.             }   
  1086.    
  1087.         }  // close if (bRead)   
  1088.    
  1089.    
  1090.         if (!bRead)   
  1091.    
  1092.         {   
  1093.    
  1094.             bRead = TRUE;   
  1095.    
  1096.             bResult = GetOverlappedResult(port->m_hComm, // Handle to COMM port   
  1097.    
  1098.                                           &port->m_ov, // Overlapped structure   
  1099.    
  1100.                                           &BytesRead, // Stores number of bytes read   
  1101.    
  1102.                                           TRUE);  // Wait flag   
  1103.    
  1104.    
  1105.             // deal with the error code   
  1106.    
  1107.             if (!bResult)   
  1108.    
  1109.             {   
  1110.    
  1111.                 port->ProcessErrorMessage("GetOverlappedResults() in ReadFile()");   
  1112.    
  1113.             }   
  1114.    
  1115.         }  // close if (!bRead)   
  1116.    
  1117.    
  1118.         LeaveCriticalSection(&port->m_csCommunicationSync);   
  1119.    
  1120.    
  1121.         // notify parent that a byte was received   
  1122.    
  1123.         ::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM) RXBuff, (LPARAM) port->m_nPortNr);   
  1124.    
  1125.     } // end forever loop   
  1126.    
  1127.    
  1128. }   
  1129.    
  1130.    
  1131. //   
  1132.    
  1133. // Write a string to the port   
  1134.    
  1135. //   
  1136.    
  1137. void CSerialPort::WriteToPort(char *string)   
  1138.    
  1139. {   
  1140.    
  1141.     assert(m_hComm != 0);   
  1142.    
  1143.    
  1144.     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));   
  1145.    
  1146.     strcpy(m_szWriteBuffer, string);   
  1147.    
  1148.     m_nWriteSize = strlen(string);   
  1149.    
  1150.    
  1151.     // set event for write   
  1152.    
  1153.     SetEvent(m_hWriteEvent);   
  1154.    
  1155. }   
  1156.    
  1157.    
  1158. //   
  1159.    
  1160. // Return the device control block   
  1161.    
  1162. //   
  1163.    
  1164. DCB CSerialPort::GetDCB()   
  1165.    
  1166. {   
  1167.    
  1168.     return m_dcb;   
  1169.    
  1170. }   
  1171.    
  1172.    
  1173. //   
  1174.    
  1175. // Return the communication event masks   
  1176.    
  1177. //   
  1178.    
  1179. DWORD CSerialPort::GetCommEvents()   
  1180.    
  1181. {   
  1182.    
  1183.     return m_dwCommEvents;   
  1184.    
  1185. }   
  1186.    
  1187.    
  1188. //   
  1189.    
  1190. // Return the output buffer size   
  1191.    
  1192. //   
  1193.    
  1194. DWORD CSerialPort::GetWriteBufferSize()   
  1195.    
  1196. {   
  1197.    
  1198.     return m_nWriteBufferSize;   
  1199.    
  1200. }   
  1201.    
  1202.    
  1203.    
  1204. void CSerialPort::WriteToPort(char *string, int n)   
  1205.    
  1206. {   
  1207.    
  1208.     assert(m_hComm != 0);   
  1209.    
  1210.     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));   
  1211.    
  1212.     memcpy(m_szWriteBuffer, string, n);   
  1213.    
  1214.     m_nWriteSize = n;   
  1215.    
  1216.     //set event for write   
  1217.    
  1218.     SetEvent(m_hWriteEvent);   
  1219.    
  1220. }   
  1221.    
  1222.    
  1223. void CSerialPort::WriteToPort(LPCTSTR string)   
  1224.    
  1225. {   
  1226.    
  1227.     assert(m_hComm != 0);   
  1228.    
  1229.     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));   
  1230.    
  1231.     strcpy(m_szWriteBuffer, string);   
  1232.    
  1233.     m_nWriteSize = strlen(string);   
  1234.    
  1235.     //set event for write   
  1236.    
  1237.     SetEvent(m_hWriteEvent);   
  1238.    
  1239. }   
  1240.    
  1241.    
  1242. void CSerialPort::WriteToPort(LPCTSTR string, int n)   
  1243.    
  1244. {   
  1245.    
  1246.     assert(m_hComm != 0);   
  1247.    
  1248.     memset(m_szWriteBuffer, 0, sizeof(m_szWriteBuffer));   
  1249.    
  1250.     memcpy(m_szWriteBuffer, string, n);   
  1251.    
  1252.     m_nWriteSize = n;   
  1253.    
  1254.     //set event for write   
  1255.    
  1256.     SetEvent(m_hWriteEvent);   
  1257.    
  1258. }   
  1259.    
  1260.    
  1261. void CSerialPort::ClosePort()   
  1262.    
  1263. {   
  1264.    
  1265.     if (m_bThreadAlive)   
  1266.    
  1267.     {   
  1268.    
  1269.         MSG message;   
  1270.    
  1271.         while (m_bThreadAlive)   
  1272.    
  1273.         {   
  1274.    
  1275.             if(::PeekMessage(&message, m_pOwner->m_hWnd, 0, 0, PM_REMOVE))   
  1276.    
  1277.             {   
  1278.    
  1279.                 ::TranslateMessage(&message);   
  1280.    
  1281.                 ::DispatchMessage(&message);   
  1282.    
  1283.             }   
  1284.    
  1285.             SetEvent(m_hShutdownEvent);   
  1286.    
  1287.         }   
  1288.    
  1289.         TRACE("Thread ended\n");   
  1290.    
  1291.    
  1292.     }   
  1293.    
  1294.     if(m_szWriteBuffer != NULL)   
  1295.    
  1296.     {   
  1297.    
  1298.         delete [] m_szWriteBuffer;   
  1299.    
  1300.         m_szWriteBuffer = NULL;   
  1301.    
  1302.     }   
  1303.    
  1304.    
  1305.     if(m_hComm)   
  1306.    
  1307.     {   
  1308.    
  1309.         CloseHandle(m_hComm);   
  1310.    
  1311.         m_hComm = NULL;   
  1312.     }   
  1313. }   

 

發佈了3 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章