一个vb用API对串口操作的类

2019-04-14 16:02发布

'*************************************************************************'**模 块 名:SPort'**by zdt 20081110'**用API 对Com进行操作'*************************************************************************Option Explicit
'Private Type COMSTAT'    fCtsHold As Long'    fDsrHold As Long'    fRlsdHold As Long'    fXoffHold As Long'    fXoffSent As Long'    fEof As Long'    fTxim As Long'    fReserved As Long'    cbInQue As Long'    cbOutQue As Long'End Type
Private Type COMSTAT    fBitFields As Long                                     ' See Comment in Win32API.Txt COMSTAT    cbInQue As Long    cbOutQue As LongEnd Type
Private Type COMMTIMEOUTS    ReadIntervalTimeout As Long    ReadTotalTimeoutMultiplier As Long    ReadTotalTimeoutConstant As Long    WriteTotalTimeoutMultiplier As Long    WriteTotalTimeoutConstant As LongEnd Type
Private Type DCB    DCBlength As Long    BaudRate As Long        fBitFields As Long 'See Comments in Win32API.Txt    wReserved As Integer    XonLim As Integer    XoffLim As Integer    ByteSize As Byte    Parity As Byte    StopBits As Byte    XonChar As Byte    XoffChar As Byte    ErrorChar As Byte    EofChar As Byte    EvtChar As Byte    wReserved1 As Integer 'Reserved; Do Not UseEnd Type
Private Type OVERLAPPED    Internal As Long    InternalHigh As Long    offset As Long    OffsetHigh As Long    hEvent As LongEnd Type
Private Type SECURITY_ATTRIBUTES    nLength As Long    lpSecurityDescriptor As Long    bInheritHandle As LongEnd Type
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As LongPrivate Declare Function GetLastError Lib "kernel32" () As LongPrivate Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As OVERLAPPED) As LongPrivate Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, lpOverlapped As OVERLAPPED) As Long 'OVERLAPPEDPrivate Declare Function SetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As LongPrivate Declare Function GetCommTimeouts Lib "kernel32" (ByVal hFile As Long, lpCommTimeouts As COMMTIMEOUTS) As LongPrivate Declare Function GetOverlappedResult Lib "kernel32" (ByVal hFile As Long, lpOverlapped As OVERLAPPED, lpNumberOfBytesTransferred As Long, ByVal bWait As Long) As LongPrivate Declare Function BuildCommDCB Lib "kernel32" Alias "BuildCommDCBA" (ByVal lpDef As String, lpDCB As DCB) As LongPrivate Declare Function SetCommState Lib "kernel32" (ByVal hCommDev As Long, lpDCB As DCB) As LongPrivate Declare Function GetCommState Lib "kernel32" (ByVal nCid As Long, lpDCB As DCB) As LongPrivate Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As LongPrivate Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As LongPrivate Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (lpEventAttributes As SECURITY_ATTRIBUTES, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As String) As LongPrivate Declare Function SetCommMask Lib "kernel32" (ByVal hFile As Long, ByVal dwEvtMask As Long) As LongPrivate Declare Function SetEvent Lib "kernel32" (ByVal hEvent As Long) As LongPrivate Declare Function SetupComm Lib "kernel32" (ByVal hFile As Long, ByVal dwInQueue As Long, ByVal dwOutQueue As Long) As LongPrivate Declare Function PurgeComm Lib "kernel32" (ByVal hFile As Long, ByVal dwFlags As Long) As LongPrivate Declare Function ClearCommError Lib "kernel32" (ByVal hFile As Long, lpErrors As Long, lpStat As COMSTAT) As LongPrivate Declare Function WaitCommEvent Lib "kernel32 " (ByVal hFile As Long, lpEvtMask As Long, lpOverlapped As OVERLAPPED) As LongPrivate Declare Function ResetEvent Lib "kernel32 " (ByVal hFile As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As LongPrivate Declare Function GetTickCount Lib "kernel32" () As LongPrivate Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Const INVALID_HANDLE_VALUE = -1Private Const GENERIC_WRITE = &H40000000Private Const GENERIC_READ = &H80000000Private Const OPEN_EXISTING = 3Private Const FILE_ATTRIBUTE_NORMAL = &H80Private Const FILE_FLAG_OVERLAPPED = &H40000000Private Const DTR_CONTROL_DISABLE = &H0Private Const RTS_CONTROL_ENABLE = &H1Private Const PURGE_RXABORT = &H2Private Const PURGE_RXCLEAR = &H8Private Const PURGE_TXABORT = &H1Private Const PURGE_TXCLEAR = &H4Private Const ERROR_IO_PENDING = 997Private Const STATUS_WAIT_0 = &H0Private Const WAIT_OBJECT_0 = (STATUS_WAIT_0 + 0)Private Const WAIT_TIMEOUT = 258&
Private Const EV_RXCHAR = &H1                '  Any Character received
Private m_OverlappedRead As OVERLAPPEDPrivate m_OverlappedWrite As OVERLAPPED
Private com_Handle As LongPrivate com_RxBy As LongPrivate com_TxBy As Long
Public Property Get ReceivedByte() As Long    ReceivedByte = com_RxByEnd PropertyPublic Property Get SendedByte() As Long    SendedByte = com_TxByEnd Property
Public Property Let ReceivedByte(x As Long)    com_RxBy = 0End PropertyPublic Property Let SendedByte(x As Long)    com_TxBy = 0End Property
Public Property Get Handle() As Long    Handle = com_HandleEnd Property
'Public Property Let Handle(id As Long)'    com_Handle = id'End Property
'*************************************************************************'**函 数 名:OpenPort'**ComPort:形式如:COM1、COM2、LPT1等等'**Comsettings:形式如:"9600,n,8,1"'**lngInSize:写入缓冲区大小'**lngOutSize:写出缓冲区大小'*************************************************************************Public Function OpenPort(ComPort As String, Comsettings As String, Optional lngInSize As Long = 1024, Optional lngOutSize As Long = 1024) As Long    On Error GoTo handelinitcom    Dim RetVal As Long    '定义标志值    Dim flag As Long
    '定义设备控制块    Dim typDCB As DCB
    Dim CtimeOut As COMMTIMEOUTS, dcbs As DCB    Dim strCOM As String, strConfig As String
    '    strCOM = "COM" & Format(ComNumber, "0")    strCOM = ComPort    '    Com_Handle = CreateFile(strCOM, GENERIC_READ Or GENERIC_WRITE, 0, ByVal 0, _         '                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_OVERLAPPED, 0)
    com_Handle = CreateFile(strCOM, _            GENERIC_READ Or GENERIC_WRITE, 0, ByVal 0, _            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL Or FILE_FLAG_OVERLAPPED, 0)
    If com_Handle = INVALID_HANDLE_VALUE Then        OpenPort = -1        Exit Function    End If
    '********获取出错信息********    Dim errNum As Long    errNum = GetLastError()    '    Debug.Print "出错信息:" & errNum
    '********获取设备控制块********    flag = GetCommState(com_Handle, typDCB)    '    Debug.Print "获取串口DCB:" & flag        Dim SetDb() As String    SetDb = Split(Comsettings, ",")
    If UBound(SetDb) >= 3 Then        typDCB.BaudRate = CLng(SetDb(0))                             '定义波特率        If UCase(SetDb(1)) = "N" Then                                    'NOPARITY           typDCB.Parity = 0                                    'NOPARITY                               '无校验位        Else           typDCB.Parity = 1        End If        typDCB.ByteSize = CByte(SetDb(2))                                   '数据位                typDCB.StopBits = CByte(SetDb(3))                                   '停止位 0/1/2 = 1/1.5/2    Else        typDCB.BaudRate = 9600                             '定义波特率        typDCB.Parity = 0                                  'NOPARITY                               '无校验位        typDCB.ByteSize = 8                                '数据位        typDCB.StopBits = 0                                '停止位 0/1/2 = 1/1.5/2    End If

    '********设置串口参数********    flag = SetCommState(com_Handle, typDCB)    '    Debug.Print "设置串口参数:" & flag
    '********设置缓冲区大小********    flag = SetupComm(com_Handle, lngInSize, lngOutSize)    '    flag = SetupComm(com_Handle, 8192, 8192)
    CtimeOut.ReadIntervalTimeout = -1                      '0    CtimeOut.ReadTotalTimeoutConstant = 0                  '2500    CtimeOut.ReadTotalTimeoutMultiplier = 0               '0    CtimeOut.WriteTotalTimeoutConstant = 0             '20  '2500    CtimeOut.WriteTotalTimeoutMultiplier = 0            '200  '0    '********超时设置********    flag = SetCommTimeouts(com_Handle, CtimeOut)
    flag = SetCommMask(com_Handle, EV_RXCHAR)              '设置监视的事件为接收到字符    '********清空读写缓冲区********    Call PurgeComm(com_Handle, PURGE_RXABORT Or PURGE_RXCLEAR Or PURGE_TXABORT Or PURGE_TXCLEAR)    '清除缓冲区
    If flag = -1 Then        RetVal = GetLastError()        OpenPort = flag        RetVal = CloseHandle(com_Handle)        Exit Function    End If
    '获取信号句柄    Dim lpEventAttributes1 As SECURITY_ATTRIBUTES    Dim lpEventAttributes2 As SECURITY_ATTRIBUTES
    m_OverlappedRead.hEvent = CreateEvent(lpEventAttributes1, 1, 0, 0)    m_OverlappedWrite.hEvent = CreateEvent(lpEventAttributes2, 1, 0, 0)
    '判断设置参数是否成功   设置输入和输出缓冲区是否成功    If m_OverlappedRead.hEvent = 0 Or m_OverlappedWrite.hEvent = 0 Then        RetVal = GetLastError()        OpenPort = RetVal        If (m_OverlappedRead.hEvent <> 0) Then CloseHandle (m_OverlappedRead.hEvent)        If (m_OverlappedWrite.hEvent <> 0) Then CloseHandle (m_OverlappedWrite.hEvent)        Call CloseHandle(com_Handle)        com_Handle = 0        Exit Function    End If
    OpenPort = 0    Exit Functionhandelinitcom:    Call CloseHandle(com_Handle)    com_Handle = 0    OpenPort = -1    Exit FunctionEnd Function
'*************************************************************************'**函 数 名:ClosePort'*************************************************************************Public Function ClosePort() As Long    If com_Handle = INVALID_HANDLE_VALUE Then        Exit Function    End If
    Call SetCommMask(com_Handle, 0)    Call SetEvent(m_OverlappedRead.hEvent)    Call SetEvent(m_OverlappedWrite.hEvent)
    If (m_OverlappedRead.hEvent <> 0) Then CloseHandle (m_OverlappedRead.hEvent)    If (m_OverlappedWrite.hEvent <> 0) Then CloseHandle (m_OverlappedWrite.hEvent)
    If CloseHandle(com_Handle) <> 0 Then        ClosePort = 0    Else        ClosePort = -1    End If
    com_Handle = INVALID_HANDLE_VALUEEnd Function
'*************************************************************************'**函 数 名:ClearInBuf'**输    入:无'**输    出:无'**功能描述:清空输入缓冲区'*************************************************************************Public Function ClearInBuf() As Long    If (com_Handle = INVALID_HANDLE_VALUE) Then        ClearInBuf = 1        Exit Function    End If    Call PurgeComm(com_Handle, PURGE_RXABORT Or PURGE_RXCLEAR)    ClearInBuf = 0End Function
'*************************************************************************'**函 数 名:ClearOutBuf'**输    入:无'**输    出:(Long) -'**功能描述:清空输出缓冲区'*************************************************************************Public Function ClearOutBuf() As Long    If (com_Handle = INVALID_HANDLE_VALUE) Then        ClearOutBuf = 1        Exit Function    End If    Call PurgeComm(com_Handle, PURGE_TXABORT Or PURGE_TXCLEAR)    ClearOutBuf = 0End Function
'*************************************************************************'**函 数 名:SendData'**输    入:bytBuffer()(Byte) - 数据'**        :lngSize(Long)     - 数据长度'**输    出:(Long) -'**功能描述:发送数据'*************************************************************************Public Function SendData(bytBuffer() As Byte, lngSize As Long) As Long
    On Error GoTo Routine_Exit                                   '打开错误陷阱    Dim errNum As Long    Dim flag As Long    Dim i As Long    If (com_Handle = 0) Then        SendData = 1        Exit Function    End If
    Dim dwBytesWritten As Long    Dim bWriteStat As Long    Dim ComStats As COMSTAT    Dim dwErrorFlags As Long
    '    dwBytesWritten = lngSize
    Call ClearCommError(com_Handle, dwErrorFlags, ComStats)
    bWriteStat = WriteFile(com_Handle, bytBuffer(0), lngSize, dwBytesWritten, m_OverlappedWrite)    '>>正常编译时候就这样就可以了    Call GetOverlappedResult(com_Handle, m_OverlappedWrite, dwBytesWritten, 1)    '等待直到发送完毕    '<<正常编译时候就这样就可以了    '    ''>>这样在调试状态下可以的或在编译为P代码的情况下是可以正常运行    '    If Not bWriteStat Then    '        If GetLastError() = ERROR_IO_PENDING Then    '            Call GetOverlappedResult(com_Handle, m_OverlappedWrite, dwBytesWritten, 1)    '等待直到发送完毕    '        End If    '    End If    '    ''<<这样在调试状态下可以的或在编译为P代码的情况下是可以正常运行        com_TxBy = com_TxBy + dwBytesWritten    SendData = dwBytesWritten    ClearOutBuf                                            '清除缓冲区
    ''    '发送数据    ''    For i = 0 To UBound(bytBuffer)    ''        flag = WriteFile(Com_Handle, bytBuffer(i), 1, dwBytesWritten, m_OverlappedWrite)    ''        If Not flag Then    ''            '获取出错码    ''            errNum = GetLastError()    ''            If (errNum = ERROR_IO_PENDING) Then    ''                flag = 0    ''                flag = GetOverlappedResult(Com_Handle, m_OverlappedWrite, dwBytesWritten, 1)    ''                SendData = SendData + dwBytesWritten    ''                Debug.Print "errNum = ERROR_IO_PENDING"    ''            Else    ''            End If    ''        End If    ''    ''        '        '间隔时间(用于需要设定每字节间间隔时间的发送协议)    ''        '                Sleep (intIntervalTime)    ''    Next
    Exit Function    '----------------Routine_Exit:    SendData = -1End Function
'*************************************************************************'**函 数 名:ReadData'**输    入:bytBuffer()(Byte) - 读取到的数据'**        :Outtime(Long)     - 等待时间ms'**输    出:(Long) -读取的字节数量'**功能描述:读取数据'*************************************************************************'Public Function ReadData(bytBuffer() As Byte, lngSize As Long, Optional Outtime As Long = 2000) As LongPublic Function ReadData(bytBuffer() As Byte, Optional lngSize As Long = 255, Optional Outtime As Long = 2000) As Long    On Error GoTo Routine_Exit                                   '打开错误陷阱
    If (com_Handle = 0) Then        ReadData = 0        Exit Function    End If
    Dim lngBytesRead As Long    Dim fReadStat As Long    Dim dwRes  As Long
    Dim lngErrorFlags As Long    Dim lngStatus As Long    Dim udtCommStat As COMSTAT    Dim evtMask As Long    Dim ret As Long
    '    lngBytesRead = lngSize
    '清除之前的一切错误与获取当前的状态    lngStatus = ClearCommError(com_Handle, lngErrorFlags, _            udtCommStat)
    '    Debug.Print "udtCommStat.cbInQue " & udtCommStat.cbInQue
    '读数据    If lngStatus <> 0 And udtCommStat.cbInQue > 0 And lngSize > 0 Then        If lngSize = 255 And udtCommStat.cbInQue > 255 Then            lngSize = udtCommStat.cbInQue        End If
        ReDim bytBuffer(lngSize) As Byte
        fReadStat = ReadFile(com_Handle, bytBuffer(0), lngSize, lngBytesRead, m_OverlappedRead)        com_RxBy = com_RxBy + lngBytesRead
        If fReadStat = 0 Then
            Call PurgeComm(com_Handle, PURGE_RXABORT Or PURGE_RXCLEAR Or PURGE_TXABORT Or PURGE_TXCLEAR)    '清除缓冲区            '        lngStatus = GetLastError            '        If lngStatus = ERROR_IO_PENDING Then            '               Call PurgeComm(Com_Handle, PURGE_RXABORT Or PURGE_RXCLEAR Or PURGE_TXABORT Or PURGE_TXCLEAR) '清除缓冲区            '        Else            '            ' Some other error occurred.            '            lngBytesRead = -1            '            '                lngStatus = SetCommErrorEx("CommRead (ReadFile)", _                         '                             '                        Com_Handle)            '            GoTo Routine_Exit            '            '        End If
        End If
        ClearInBuf                                         '清除缓冲区    End If    ReadData = lngBytesRead        Exit FunctionRoutine_Exit:    ReadData = 0End Function'*************************************************************************'**函 数 名:Class_Initialize'*************************************************************************Private Sub Class_Initialize()   com_Handle = INVALID_HANDLE_VALUE   com_RxBy = 0   com_TxBy = 0End Sub
'*************************************************************************'**函 数 名:Class_Terminate'*************************************************************************Private Sub Class_Terminate()    Call ClosePortEnd Sub