Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - .NET

Страница: 1 |

 

  Вопрос: SerialPort - утечка памяти Добавлено: 28.02.07 22:33  

Автор вопроса:  Морячок | ICQ: 115534934 
Здравствуйте!

Возникла проблема с использованием класса System.IO.Ports.SerialPort. Может кто уже знаком с вопросом? Ситуация:

По таймеру вызываю метод ReadLine(), читаю значение в одну и ту же
локальную переменную.
Получаю приличную утечку памяти. Мало того, что ресурсы ограничены (дело происходит на КПК с Framework 2.0), так ещё и через какое-то время порт глухо виснет. Подозреваю, что причина одна.

Что я делаю не так?
Что я не делаю из того, что надо?

Помогите, а?

Ответить

  Ответы Всего ответов: 15  

Номер ответа: 1
Автор ответа:
 Artyom



Разработчик

Вопросов: 130
Ответов: 6602
 Профиль | | #1 Добавлено: 28.02.07 22:50
покажи код

Ответить

Номер ответа: 2
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #2 Добавлено: 28.02.07 23:07

Public Class Jonathan
    Private WithEvents OurSerialPort As New SerialPort
    
    Public Event DataReceived(ByVal MessageID As String)

'Подключение к указанному последовательному порту
    Public Function ConnectToSerialPort(ByVal PortName As String, ByVal BaudRate As Integer, ByVal ex As Exception) As Boolean
        Dim IsOK As Boolean = True
        OurSerialPort.PortName = PortName
        OurSerialPort.BaudRate = BaudRate
        Try
            OurSerialPort.Open()
        Catch ex
            IsOK = False
        End Try
        m_IsOpen = IsOK
        Return IsOK
    End Function

Private Sub OurSerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles OurSerialPort.DataReceived
        Dim arr() As String
        Dim nmeaCommandString As String
        nmeaCommandString = OurSerialPort.ReadLine
                RaiseEvent DataReceived(arr(0).ToString)
End Sub

End Class


вот уже в таком виде память уходит

Ответить

Номер ответа: 3
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #3 Добавлено: 28.02.07 23:10
прошу прощения
повырезал лишнее, чтоб глаза не мозолило, и увлёкся.


'На последовательном порту появились новые данные
    Private Sub OurSerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles OurSerialPort.DataReceived
        Dim arr() As String
        Dim nmeaCommandString As String
        nmeaCommandString = OurSerialPort.ReadLine
        arr = Split(nmeaCommandString, ",";)
        Select Case arr(0).ToString
            Case "$GPGGA" 'Global Positioning System Fixed Data
                            Case "$GPGLL" 'Geographic Position-Latitude/Longitude

            Case "$GPGSA" 'GNSS DOP and Active Satellites

            Case "$GPGSV" 'GNSS Satellites in View

            Case "$GPRMC" 'Recommended Minimum Specific GNSS Data

            Case Else

        End Select
        RaiseEvent DataReceived(arr(0).ToString)
    End Sub

Ответить

Номер ответа: 4
Автор ответа:
 Viper



ICQ: 249094859 

Вопросов: 0
Ответов: 310
 Профиль | | #4 Добавлено: 01.03.07 10:26
много вырезал

Ответить

Номер ответа: 5
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #5 Добавлено: 01.03.07 11:01
Вот написал новый класс, простой, но по тем же принципам, чтоб не вырезать ничего. Проблема здесь та же-утечка памяти... Что я делаю не так? MSDN читаю третий день, рою примеры в нете - везде всё просто, все открывают порт, что-то из него читают - и сразу закрывают. А у меня его надо держать открытым, пока не скажет пользователь. Я так понимаю где-то накапливается мусор, который я не знаю как почистить... Код класса вот:


Imports System.IO.Ports

Public Class ExapleClass

    Public Event DataReceived(ByVal MessageID As String)

    Private WithEvents OurSerialPort As New SerialPort


    'Подключение к указанному последовательному порту
    Public Function ConnectToSerialPort(ByVal PortName As String, ByVal BaudRate As Integer, ByVal ex As Exception) As Boolean
        Dim IsOK As Boolean = True
        OurSerialPort.PortName = PortName
        OurSerialPort.BaudRate = BaudRate
        OurSerialPort.NewLine = vbCrLf
        OurSerialPort.ReadTimeout = 300
        Try
            OurSerialPort.Open()
        Catch ex
            IsOK = False
        End Try
        Return IsOK
    End Function

    Public Function DisconnectFromSerialPort() As Boolean
        Dim IsOK As Boolean = True
        Dim ex As Exception
        Try
            OurSerialPort.Close()
        Catch ex
            IsOK = False
        End Try
        Return IsOK
    End Function

    'На последовательном порту появились новые данные
    Private Sub OurSerialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles OurSerialPort.DataReceived
        Dim nmeaCommandString As String
        Try
            nmeaCommandString = OurSerialPort.ReadLine
        Catch ex1 As Exception
            Exit Sub
        End Try
        RaiseEvent DataReceived(nmeaCommandString)
    End Sub
End Class

Ответить

Номер ответа: 6
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #6
Добавлено: 01.03.07 14:33
Морячок

Утечка памяти в .NET, в принципе не возможна.
Потому, как она и так утекает, не пойми куда.:) Шучу.

С чего ты взял, что у тебя утечка памяти?
Ресурсы быстро заканчиваются?

Private Sub OurSerialPort_DataReceived(ByVal sender As

Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles OurSerialPort.DataReceived
        
Dim nmeaCommandString As String


Вынеси объявление строки за пределы процедуры.
Возможно потеря ресурсов происходит именно из-за
этого. CLR будет выделять память под строку раз за разом, вызывая конструктор класса, что не связано с утечкой памяти. Просто сборщик мусора, не успевает освободить ненужный ресурс.
Впрочем? теорию CLR я уже подзабыл.:)

Что касается зависания порта, то мне кажется ты просто не все параметры правильно инициализировал (а может причина в нехватке ресурсов?).
В NET 1.1 был пример работы с последовательными
портами и модемом. Но там все опиралось на API. В 2.0 созданы специальные классы, но тем не менее, принцип тот же.
    
Возможно неправильно заданы параметры порта?

   
Private miTimeout As Integer = 70   ' Timeout in ms
    Private miBaudRate As Integer = 9600
    Private meParity As DataParity = 0
    Private meStopBit As DataStopBit = 0
    Private miDataBit As Integer = 8

Ответить

Номер ответа: 7
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #7 Добавлено: 01.03.07 15:13
В Windows Mobile 2003 можно посмотреть свободную и занятую память - Пуск-Настройка-Память-Основная. Занятая память довольно так шустро растёт, синхронно с чтением из порта. Примерно на одну и ту же величину.
Если закомментарить
'nmeaCommandString = OurSerialPort.ReadLine

то утечка памяти прекращается.
пробовал делать так:
nmeaCommandString = OurSerialPort.ReadLine
            OurSerialPort.DiscardInBuffer()
            GC.Collect()

утечка становится меньше, но тем не менее продолжается.
При выключении порта тоже через раз виснет. Пробовал сделать выключение через делегат - всё равно... Да ясно, что порт не виноват - просто мне надо руки выпрямлять. Что и пытаюсь делать, набираясь ума, и с вами консультируясь.

Ответить

Номер ответа: 8
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #8
Добавлено: 01.03.07 15:33
 Морячок

Ну а если все - таки, объявить строку nmeaCommandString, как глобальную переменную?
Ведь чтение идет именно в нее. Интересно, что получится?

У порта есть метод Dispose?
Если есть (а он должен быть), то сделай так.


OurSerialPort.Dispose()
OurSerialPort = null


Collect можно не вызывать, он все пройдется когда захочет. Принудительный вызов мало что дает.

Ответить

Номер ответа: 9
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #9 Добавлено: 01.03.07 16:27
Ну а если все - таки, объявить строку nmeaCommandString, как глобальную переменную?
Ведь чтение идет именно в нее. Интересно, что получится?


Попробовал, сразу же. Проблема остаётся.

Как я понимаю,
OurSerialPort.Dispose()
OurSerialPort = null

освобождает ресурсы порта и убивает его. При обработке события OurSerialPort_DataReceived, мы не должны закрывать порт, он открывается один раз, много всего принимает, и закрывается в конце работы... То есть не подходит. Или я чего-то не понял?

Ответить

Номер ответа: 10
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #10
Добавлено: 01.03.07 16:40
Морячок

освобождает ресурсы порта и убивает его.

Да, все правильно.

Тогда даже не знаю. Если мы ждем, чего - то конкретного, от порта, возможно стоит убивать строку?

В отладчике не видно какое значение начинает расти? Строка, сам порт?
Если расход памяти происходит из-за порта, то я бы например ограничил размер буфера.
SerialPort.ReadBufferSize Property

Ответить

Номер ответа: 11
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #11
Добавлено: 01.03.07 18:33
Вообще задачка не такая простая как кажется.

Посмотри, какой класс был создан для в 1.1.

Привожу выдержки.

Option Strict On

Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Threading

' This class provides all the necessary support for

communicating
'   with the Comm Port (otherwise known as the Serial Port, or
'   RS232 port).
Public Class Rs232
    ' Declare the necessary class variables, and their initial

values.
    Private mhRS As Integer = -1   ' Handle to Com Port


    Private miPort As Integer = 1   ' Default is COM1
    Private miTimeout As Integer = 70   ' Timeout in ms
    Private miBaudRate As Integer = 9600
    Private meParity As DataParity = 0
    Private meStopBit As DataStopBit = 0
    Private miDataBit As Integer = 8
    Private miBufferSize As Integer = 512   ' Buffers size default

to 512 bytes
    Private mabtRxBuf As Byte()   ' Receive buffer
    Private meMode As Mode  ' Class working mode
    Private mbWaitOnRead As Boolean
    Private mbWaitOnWrite As Boolean
    Private mbWriteErr As Boolean
    Private muOverlapped As OVERLAPPED
    Private muOverlappedW As OVERLAPPED
    Private muOverlappedE As OVERLAPPED
    Private mabtTmpTxBuf As Byte()  ' Temporary buffer used

by Async Tx
    Private moThreadTx As Thread
    Private moThreadRx As Thread
    Private miTmpBytes2Read As Integer
    Private meMask As EventMasks

#Region "Events"
    ' These events allow the program using this class to react

to Comm Port
    '   events.
    Public Event DataReceived(ByVal Source As Rs232, ByVal

DataBuffer() As Byte)
    Public Event TxCompleted(ByVal Source As Rs232)
    Public Event CommEvent(ByVal Source As Rs232, ByVal

Mask As EventMasks)
#End Region

#Region "Methods"

    ' This subroutine invokes a thread to perform an

asynchronous read.
    '   This routine should not be called directly, but is used
    '   by the class.
    Public Sub _R()
        Dim iRet As Integer = Read(miTmpBytes2Read)
    End Sub

    ' This subroutine invokes a thread to perform an

asynchronous write.
    '   This routine should not be called directly, but is used
    '   by the class.
    Public Sub _W()
        Write(mabtTmpTxBuf)
    End Sub

    ' This subroutine uses another thread to read from the

Comm Port. It
    '   raises RxCompleted when done. It reads an integer.
    Public Overloads Sub AsyncRead(ByVal Bytes2Read As

Integer)
        If meMode <> Mode.Overlapped Then Throw New

ApplicationException( _
            "Async Methods allowed only when

WorkingMode=Overlapped";)
        miTmpBytes2Read = Bytes2Read
        moThreadTx = New Thread(AddressOf _R)
        moThreadTx.Start()
    End Sub

    ' This subroutine uses another thread to write to the Comm

Port. It
    '   raises TxCompleted when done. It writes an array of

bytes.
    Public Overloads Sub AsyncWrite(ByVal Buffer() As Byte)
        If meMode <> Mode.Overlapped Then Throw New

ApplicationException( _
            "Async Methods allowed only when

WorkingMode=Overlapped";)
        If mbWaitOnWrite = True Then Throw New

ApplicationException( _
            "Unable to send message because of pending

transmission.";)
        mabtTmpTxBuf = Buffer
        moThreadTx = New Thread(AddressOf _W)
        moThreadTx.Start()
    End Sub

    ' This subroutine uses another thread to write to the Comm

Port. It
    '   raises TxCompleted when done. It writes a string.
    Public Overloads Sub AsyncWrite(ByVal Buffer As String)
        Dim oEncoder As New System.Text.ASCIIEncoding()
        Dim aByte() As Byte = oEncoder.GetBytes(Buffer)
        Me.AsyncWrite(aByte)
    End Sub

    ' This function takes the ModemStatusBits and returns a

boolean value
    '   signifying whether the Modem is active.
    Public Function CheckLineStatus(ByVal Line As

ModemStatusBits) As Boolean
        Return Convert.ToBoolean(ModemStatus And Line)
    End Function

    ' This subroutine clears the input buffer.
    Public Sub ClearInputBuffer()
        If Not mhRS = -1 Then
            PurgeComm(mhRS, PURGE_RXCLEAR)
        End If
    End Sub

    ' This subroutine closes the Comm Port.
    Public Sub Close()
        If mhRS <> -1 Then
            CloseHandle(mhRS)
            mhRS = -1
        End If
    End Sub

    ' This subroutine opens and initializes the Comm Port
    Public Overloads Sub Open()
        ' Get Dcb block,Update with current data
        Dim uDcb As DCB, iRc As Integer
        ' Set working mode
        Dim iMode As Integer = Convert.ToInt32(IIf(meMode =

Mode.Overlapped, _
            FILE_FLAG_OVERLAPPED, 0))
        ' Initializes Com Port
        If miPort > 0 Then
            Try
                ' Creates a COM Port stream handle
                mhRS = CreateFile("COM" & miPort.ToString, _
                GENERIC_READ Or GENERIC_WRITE, 0, 0, _
                OPEN_EXISTING, iMode, 0)
                If mhRS <> -1 Then
                    ' Clear all comunication errors
                    Dim lpErrCode As Integer
                    iRc = ClearCommError(mhRS, lpErrCode, 0&;)
                    ' Clears I/O buffers
                    iRc = PurgeComm(mhRS, PurgeBuffers.RXClear

Or _
                        PurgeBuffers.TxClear)
                    ' Gets COM Settings
                    iRc = GetCommState(mhRS, uDcb)
                    ' Updates COM Settings
                    Dim sParity As String = "NOEM"
                    sParity = sParity.Substring(meParity, 1)
                    ' Set DCB State
                    Dim sDCBState As String = String.Format( _
                        "baud={0} parity={1} data={2} stop={3}", _
                        miBaudRate, sParity, miDataBit,

CInt(meStopBit))
                    iRc = BuildCommDCB(sDCBState, uDcb)
                    iRc = SetCommState(mhRS, uDcb)
                    If iRc = 0 Then
                        Dim sErrTxt As String =

pErr2Text(GetLastError())
                        Throw New CIOChannelException( _
                            "Unable to set COM state0" & sErrTxt)
                    End If
                    ' Setup Buffers (Rx,Tx)
                    iRc = SetupComm(mhRS, miBufferSize,

miBufferSize)
                    ' Set Timeouts
                    pSetTimeout()
                Else
                    ' Raise Initialization problems
                    Throw New CIOChannelException( _
                        "Unable to open COM" & miPort.ToString)
                End If
            Catch Ex As Exception
                ' Generica error
                Throw New CIOChannelException(Ex.Message, Ex)
            End Try
        Else
            ' Port not defined, cannot open
            Throw New ApplicationException("COM Port not

defined, " + _
                "use Port property to set it before invoking InitPort";)
        End If
    End Sub

    ' This subroutine opens and initializes the Comm Port

(overloaded
    '   to support parameters).
    Public Overloads Sub Open(ByVal Port As Integer, _
        ByVal BaudRate As Integer, ByVal DataBit As Integer, _
        ByVal Parity As DataParity, ByVal StopBit As

DataStopBit, _
        ByVal BufferSize As Integer)

        Me.Port = Port
        Me.BaudRate = BaudRate
        Me.DataBit = DataBit
        Me.Parity = Parity
        Me.StopBit = StopBit
        Me.BufferSize = BufferSize
        Open()
    End Sub

    ' This function translates an API error code to text.
    Private Function pErr2Text(ByVal lCode As Integer) As

String
        Dim sRtrnCode As New StringBuilder(256)
        Dim lRet As Integer

        lRet = FormatMessage(&H1000, 0, lCode, 0, sRtrnCode,

256, 0)
        If lRet > 0 Then
            Return sRtrnCode.ToString
        Else
            Return "Error not found."
        End If

    End Function

    ' This subroutine handles overlapped reads.
    Private Sub pHandleOverlappedRead(ByVal Bytes2Read As

Integer)
        Dim iReadChars, iRc, iRes, iLastErr As Integer
        muOverlapped.hEvent = CreateEvent(Nothing, 1, 0,

Nothing)
        If muOverlapped.hEvent = 0 Then
            ' Can't create event
            Throw New ApplicationException( _
                "Error creating event for overlapped read.";)
        Else
            ' Ovellaped reading
            If mbWaitOnRead = False Then
                ReDim mabtRxBuf(Bytes2Read - 1)
                iRc = ReadFile(mhRS, mabtRxBuf, Bytes2Read, _
                    iReadChars, muOverlapped)
                If iRc = 0 Then
                    iLastErr = GetLastError()
                    If iLastErr <> ERROR_IO_PENDING Then
                        Throw New ArgumentException("Overlapped

Read Error: " & _
                            pErr2Text(iLastErr))
                    Else
                        ' Set Flag
                        mbWaitOnRead = True
                    End If
                Else
                    ' Read completed successfully
                    RaiseEvent DataReceived(Me, mabtRxBuf)
                End If
            End If
        End If
        ' Wait for operation to be completed
        If mbWaitOnRead Then
            iRes = WaitForSingleObject(muOverlapped.hEvent,

miTimeout)
            Select Case iRes
                Case WAIT_OBJECT_0
                    ' Object signaled,operation completed
                    If GetOverlappedResult(mhRS, muOverlapped, _
                        iReadChars, 0) = 0 Then

                        ' Operation error
                        iLastErr = GetLastError()
                        If iLastErr = ERROR_IO_INCOMPLETE Then
                            Throw New ApplicationException( _
                                "Read operation incomplete";)
                        Else
                            Throw New ApplicationException( _
                                "Read operation error " &

iLastErr.ToString)
                        End If
                    Else
                        ' Operation completed
                        RaiseEvent DataReceived(Me, mabtRxBuf)
                        mbWaitOnRead = False
                    End If
                Case WAIT_TIMEOUT
                    Throw New IOTimeoutException("Timeout error";)
                Case Else
                    Throw New ApplicationException("Overlapped

read error";)
            End Select
        End If
    End Sub

    ' This subroutine handles overlapped writes.
    Private Function pHandleOverlappedWrite(ByVal Buffer()

As Byte) As Boolean
        Dim iBytesWritten, iRc, iLastErr, iRes As Integer, bErr As

Boolean
        muOverlappedW.hEvent = CreateEvent(Nothing, 1, 0,

Nothing)
        If muOverlappedW.hEvent = 0 Then
            ' Can't create event
            Throw New ApplicationException( _
                "Error creating event for overlapped write.";)
        Else
            ' Overllaped write
            PurgeComm(mhRS, PURGE_RXCLEAR Or

PURGE_TXCLEAR)
            mbWaitOnRead = True
            iRc = WriteFile(mhRS, Buffer, Buffer.Length, _
                iBytesWritten, muOverlappedW)
            If iRc = 0 Then
                iLastErr = GetLastError()
                If iLastErr <> ERROR_IO_PENDING Then
                    Throw New ArgumentException("Overlapped

Read Error: " & _
                        pErr2Text(iLastErr))
                Else
                    ' Write is pending
                    iRes =

WaitForSingleObject(muOverlappedW.hEvent, INFINITE)
                    Select Case iRes
                        Case WAIT_OBJECT_0
                            ' Object signaled,operation completed
                            If GetOverlappedResult(mhRS,

muOverlappedW, _
                                iBytesWritten, 0) = 0 Then

                                bErr = True
                            Else
                                ' Notifies Async tx completion,stops

thread
                                mbWaitOnRead = False
                                RaiseEvent TxCompleted(Me)
                            End If
                    End Select
                End If
            Else
                ' Wait operation completed immediatly
                bErr = False
            End If
        End If
        CloseHandle(muOverlappedW.hEvent)
        Return bErr
    End Function

    ' This subroutine sets the Comm Port timeouts.
    Private Sub pSetTimeout()
        Dim uCtm As COMMTIMEOUTS
        ' Set ComTimeout
        If mhRS = -1 Then
            Exit Sub
        Else
            ' Changes setup on the fly
            With uCtm
                .ReadIntervalTimeout = 0
                .ReadTotalTimeoutMultiplier = 0
                .ReadTotalTimeoutConstant = miTimeout
                .WriteTotalTimeoutMultiplier = 10
                .WriteTotalTimeoutConstant = 100
            End With
            SetCommTimeouts(mhRS, uCtm)
        End If
    End Sub

    ' This function returns an integer specifying the number of

bytes
    '   read from the Comm Port. It accepts a parameter

specifying the number
    '   of desired bytes to read.
    Public Function Read(ByVal Bytes2Read As Integer) As

Integer
        Dim iReadChars, iRc As Integer

        ' If Bytes2Read not specified uses Buffersize
        If Bytes2Read = 0 Then Bytes2Read = miBufferSize
        If mhRS = -1 Then
            Throw New ApplicationException( _
                "Please initialize and open port before using this

method";)
        Else
            ' Get bytes from port
            Try
                ' Purge buffers
                'PurgeComm(mhRS, PURGE_RXCLEAR Or

PURGE_TXCLEAR)
                ' Creates an event for overlapped operations
                If meMode = Mode.Overlapped Then
                    pHandleOverlappedRead(Bytes2Read)
                Else
                    ' Non overlapped mode
                    ReDim mabtRxBuf(Bytes2Read - 1)
                    iRc = ReadFile(mhRS, mabtRxBuf, Bytes2Read,

iReadChars, Nothing)
                    If iRc = 0 Then
                        ' Read Error
                        Throw New ApplicationException( _
                            "ReadFile error " & iRc.ToString)
                    Else
                        ' Handles timeout or returns input chars
                        If iReadChars < Bytes2Read Then
                            Throw New IOTimeoutException("Timeout

error";)
                        Else
                            mbWaitOnRead = True
                            Return (iReadChars)
                        End If
                    End If
                End If
            Catch Ex As Exception
                ' Others generic erroes
                Throw New ApplicationException("Read Error: " &

Ex.Message, Ex)
            End Try
        End If
    End Function

    ' This subroutine writes the passed array of bytes to the
    '   Comm Port to be written.
    Public Overloads Sub Write(ByVal Buffer As Byte())
        Dim iBytesWritten, iRc As Integer

        If mhRS = -1 Then
            Throw New ApplicationException( _
                "Please initialize and open port before using this

method";)
        Else
            ' Transmit data to COM Port
            Try
                If meMode = Mode.Overlapped Then
                    ' Overlapped write
                    If pHandleOverlappedWrite(Buffer) Then
                        Throw New ApplicationException( _
                            "Error in overllapped write";)
                    End If
                Else
                    ' Clears IO buffers
                    PurgeComm(mhRS, PURGE_RXCLEAR Or

PURGE_TXCLEAR)
                    iRc = WriteFile(mhRS, Buffer, Buffer.Length, _
                        iBytesWritten, Nothing)
                    If iRc = 0 Then
                        Throw New ApplicationException( _
                            "Write Error - Bytes Written " & _
                            iBytesWritten.ToString & " of " & _
                            Buffer.Length.ToString)
                    End If
                End If
            Catch Ex As Exception
                Throw
            End Try
        End If
    End Sub

    ' This subroutine writes the passed string to the
    '   Comm Port to be written.
    Public Overloads Sub Write(ByVal Buffer As String)
        Dim oEncoder As New System.Text.ASCIIEncoding()
        Dim aByte() As Byte = oEncoder.GetBytes(Buffer)
        Me.Write(aByte)
    End Sub

#End Region

#Region "Win32API"
    ' The following functions are the required Win32 functions

needed to
    '   make communication with the Comm Port possible.

    <;DllImport("kernel32.dll";)> Private Shared Function

BuildCommDCB( _
        ByVal lpDef As String, ByRef lpDCB As DCB) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

ClearCommError( _
        ByVal hFile As Integer, ByVal lpErrors As Integer, _
        ByVal l As Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

CloseHandle( _
        ByVal hObject As Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

CreateEvent( _
        ByVal lpEventAttributes As Integer, ByVal bManualReset

As Integer, _
        ByVal bInitialState As Integer, _
        <MarshalAs(UnmanagedType.LPStr)> ByVal lpName As

String) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

CreateFile( _
        <MarshalAs(UnmanagedType.LPStr)> ByVal lpFileName

As String, _
        ByVal dwDesiredAccess As Integer, ByVal dwShareMode

As Integer, _
        ByVal lpSecurityAttributes As Integer, _
        ByVal dwCreationDisposition As Integer, _
        ByVal dwFlagsAndAttributes As Integer, _
        ByVal hTemplateFile As Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

EscapeCommFunction( _
        ByVal hFile As Integer, ByVal ifunc As Long) As Boolean
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

FormatMessage( _
        ByVal dwFlags As Integer, ByVal lpSource As Integer, _
        ByVal dwMessageId As Integer, ByVal dwLanguageId As

Integer, _
        <MarshalAs(UnmanagedType.LPStr)> ByVal lpBuffer As

String, _
        ByVal nSize As Integer, ByVal Arguments As Integer) As

Integer
    End Function

    Private Declare Function FormatMessage Lib "kernel32"

Alias _
     "FormatMessageA" (ByVal dwFlags As Integer, ByVal

lpSource As Integer, _
     ByVal dwMessageId As Integer, ByVal dwLanguageId As

Integer, _
     ByVal lpBuffer As StringBuilder, ByVal nSize As Integer, _
     ByVal Arguments As Integer) As Integer

    <;DllImport("kernel32.dll";)> Public Shared Function

GetCommModemStatus( _
        ByVal hFile As Integer, ByRef lpModemStatus As Integer)

As Boolean
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

GetCommState( _
        ByVal hCommDev As Integer, ByRef lpDCB As DCB) As

Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

GetCommTimeouts( _
        ByVal hFile As Integer, ByRef lpCommTimeouts As

COMMTIMEOUTS) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

GetLastError() As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

GetOverlappedResult( _
        ByVal hFile As Integer, ByRef lpOverlapped As

OVERLAPPED, _
        ByRef lpNumberOfBytesTransferred As Integer, _
        ByVal bWait As Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

PurgeComm( _
        ByVal hFile As Integer, ByVal dwFlags As Integer) As

Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

ReadFile( _
        ByVal hFile As Integer, ByVal Buffer As Byte(), _
        ByVal nNumberOfBytesToRead As Integer, _
        ByRef lpNumberOfBytesRead As Integer, _
        ByRef lpOverlapped As OVERLAPPED) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

SetCommTimeouts( _
        ByVal hFile As Integer, ByRef lpCommTimeouts As

COMMTIMEOUTS) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

SetCommState( _
        ByVal hCommDev As Integer, ByRef lpDCB As DCB) As

Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

SetupComm( _
        ByVal hFile As Integer, ByVal dwInQueue As Integer, _
        ByVal dwOutQueue As Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

SetCommMask( _
        ByVal hFile As Integer, ByVal lpEvtMask As Integer) As

Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

WaitCommEvent( _
        ByVal hFile As Integer, ByRef Mask As EventMasks, _
        ByRef lpOverlap As OVERLAPPED) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

WaitForSingleObject( _
        ByVal hHandle As Integer, ByVal dwMilliseconds As

Integer) As Integer
    End Function

    <;DllImport("kernel32.dll";)> Private Shared Function

WriteFile( _
        ByVal hFile As Integer, ByVal Buffer As Byte(), _
        ByVal nNumberOfBytesToWrite As Integer, _
        ByRef lpNumberOfBytesWritten As Integer, _
        ByRef lpOverlapped As OVERLAPPED) As Integer
    End Function

#End Region


Вот так... Но надо сказать что этот класс почти "на все случаи".

Ответить

Номер ответа: 12
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #12 Добавлено: 01.03.07 22:03
здорово. завтра с утра буду разбираться :-)
я по твоему совету ограничил размер буфера, и - yesss! утечки памяти прекратились. спасибо за отличную мысль, я в эту сторону и не думал... мне хотелось что-то очищать, освобождать в динамике.
Остаются две проблемы - через какое-то время с порта перестаёт приходить информация. Буду разбираться с этим. И более непонятное - периодическое зависание на SerialPort.Close при попытке закрытия. Проблема взаимодействия потоков?

Ответить

Номер ответа: 13
Автор ответа:
 vito



Разработчик Offline Client

Вопросов: 23
Ответов: 879
 Web-сайт: softvito.narod2.ru
 Профиль | | #13
Добавлено: 02.03.07 03:10
Может это чем-то поможет.

Сначала мы открываем порт.

' This function attempts to open the passed Comm Port. If it is
    '   available, it returns True, else it returns False. To determine
    '   availability a Try-Catch block is used.
    Private Function IsPortAvailable(ByVal ComPort As Integer) As Boolean
        Try
            m_CommPort.Open(ComPort, 115200, 8, Rs232.DataParity.Parity_None, _
                Rs232.DataStopBit.StopBit_1, 4096)
            ' If it makes it to here, then the Comm Port is available.
            'm_CommPort.Close()
            Return True
        Catch
            ' If it gets here, then the attempt to open the Comm Port
            '   was unsuccessful.
            Return False
        End Try
    End Function

Обрати внимание на параметры порта - четность, скорость и т.д.
Функция Open представлена в классе, который я выложил.
Все эти параметры можно (и нужно) задать в свойствах класса.

SerialPort.BaudRate Property
SerialPort.DataBits Property

и т.д.

Далее мы начинаем опрашивать порт.

  
' This subroutine is fired when the timer event is raised. It writes whatever
    '   is in the Comm Port buffer to the output window.
    Private Sub tmrReadCommPort_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrReadCommPort.Tick
        Try
            ' As long as there is information, read one byte at a time and
            '   output it.
            While (m_CommPort.Read(1) <> -1)
                ' Write the output to the screen.
                  WriteMessage(Chr(m_CommPort.InputStream(0)), False)
            End While
        Catch exc As Exception
            ' An exception is raised when there is no information to read.
            '   Don't do anything here, just let the exception go.
        End Try

    End Sub

Функция Read (у меня все функции - сишная привычка).

' This function returns an integer specifying the number of bytes
    '   read from the Comm Port. It accepts a parameter specifying the number
    '   of desired bytes to read.
    Public Function Read(ByVal Bytes2Read As Integer) As Integer
        Dim iReadChars, iRc As Integer

        ' If Bytes2Read not specified uses Buffersize
        If Bytes2Read = 0 Then Bytes2Read = miBufferSize
        If mhRS = -1 Then
            Throw New ApplicationException( _
                "Please initialize and open port before using this method";)
        Else
            ' Get bytes from port
            Try
                ' Purge buffers
                'PurgeComm(mhRS, PURGE_RXCLEAR Or PURGE_TXCLEAR)
                ' Creates an event for overlapped operations
                If meMode = Mode.Overlapped Then
                    pHandleOverlappedRead(Bytes2Read)
                Else
                    ' Non overlapped mode
                    ReDim mabtRxBuf(Bytes2Read - 1)
                    iRc = ReadFile(mhRS, mabtRxBuf, Bytes2Read, iReadChars, Nothing)
                    If iRc = 0 Then
                        ' Read Error
                        Throw New ApplicationException( _
                            "ReadFile error " & iRc.ToString)
                    Else
                        ' Handles timeout or returns input chars
                        If iReadChars < Bytes2Read Then
                            Throw New IOTimeoutException("Timeout error";)
                        Else
                            mbWaitOnRead = True
                            Return (iReadChars)
                        End If
                    End If
                End If
            Catch Ex As Exception
                ' Others generic erroes
                Throw New ApplicationException("Read Error: " & Ex.Message, Ex)
            End Try
        End If
    End Function


Вот собственно и все.
Обрати внимание на граммотную обработку исключений.
Например.

' Handles timeout or returns input chars
                        If iReadChars < Bytes2Read Then
                            Throw New IOTimeoutException("Timeout error";)
                        Else
                            mbWaitOnRead = True
                             Return (iReadChars)


Это позволит тебе найти причины сбоя, грамотно их обработать и соответственно не подвешивать порт.

Ответить

Номер ответа: 14
Автор ответа:
 Морячок



ICQ: 115534934 

Вопросов: 4
Ответов: 17
 Профиль | | #14 Добавлено: 07.03.07 10:40
А что такое SerialPort.DataBits и SerialPort.StopBits?
А то в MSDN уж как-то всё очень лаконично сказано...

Ответить

Номер ответа: 15
Автор ответа:
 Viper



ICQ: 249094859 

Вопросов: 0
Ответов: 310
 Профиль | | #15 Добавлено: 07.03.07 12:07
Число битов на байт (обычно 8) и число битов отделяющих одну единицу данных от других (обычно 1)

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам