Страница: 1 |
Страница: 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-сайт:
Профиль | | #6
Добавлено: 01.03.07 14:33
Морячок
Утечка памяти в .NET, в принципе не возможна.
Потому, как она и так утекает, не пойми куда. Шучу.
С чего ты взял, что у тебя утечка памяти?
Ресурсы быстро заканчиваются?
Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles OurSerialPort.DataReceived
Dim nmeaCommandString As String
Вынеси объявление строки за пределы процедуры.
Возможно потеря ресурсов происходит именно из-за
этого. CLR будет выделять память под строку раз за разом, вызывая конструктор класса, что не связано с утечкой памяти. Просто сборщик мусора, не успевает освободить ненужный ресурс.
Впрочем? теорию CLR я уже подзабыл.
Что касается зависания порта, то мне кажется ты просто не все параметры правильно инициализировал (а может причина в нехватке ресурсов?).
В NET 1.1 был пример работы с последовательными
портами и модемом. Но там все опиралось на API. В 2.0 созданы специальные классы, но тем не менее, принцип тот же.
Возможно неправильно заданы параметры порта?
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 можно посмотреть свободную и занятую память - Пуск-Настройка-Память-Основная. Занятая память довольно так шустро растёт, синхронно с чтением из порта. Примерно на одну и ту же величину.
Если закомментарить
то утечка памяти прекращается.
пробовал делать так:
OurSerialPort.DiscardInBuffer()
GC.Collect()
утечка становится меньше, но тем не менее продолжается.
При выключении порта тоже через раз виснет. Пробовал сделать выключение через делегат - всё равно... Да ясно, что порт не виноват - просто мне надо руки выпрямлять. Что и пытаюсь делать, набираясь ума, и с вами консультируясь.
Номер ответа: 8
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #8
Добавлено: 01.03.07 15:33
Морячок
Ну а если все - таки, объявить строку nmeaCommandString, как глобальную переменную?
Ведь чтение идет именно в нее. Интересно, что получится?
У порта есть метод Dispose?
Если есть (а он должен быть), то сделай так.
OurSerialPort.Dispose()
OurSerialPort = null
Collect можно не вызывать, он все пройдется когда захочет. Принудительный вызов мало что дает.
Номер ответа: 9
Автор ответа:
Морячок
ICQ: 115534934
Вопросов: 4
Ответов: 17
Профиль | | #9
Добавлено: 01.03.07 16:27
Ведь чтение идет именно в нее. Интересно, что получится?
Попробовал, сразу же. Проблема остаётся.
Как я понимаю,
OurSerialPort = null
освобождает ресурсы порта и убивает его. При обработке события OurSerialPort_DataReceived, мы не должны закрывать порт, он открывается один раз, много всего принимает, и закрывается в конце работы... То есть не подходит. Или я чего-то не понял?
Номер ответа: 10
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #10
Добавлено: 01.03.07 16:40
Морячок
Да, все правильно.
Тогда даже не знаю. Если мы ждем, чего - то конкретного, от порта, возможно стоит убивать строку?
В отладчике не видно какое значение начинает расти? Строка, сам порт?
Если расход памяти происходит из-за порта, то я бы например ограничил размер буфера.
Номер ответа: 11
Автор ответа:
vito
Разработчик Offline Client
Вопросов: 23
Ответов: 879
Web-сайт:
Профиль | | #11
Добавлено: 01.03.07 18:33
Вообще задачка не такая простая как кажется.
Посмотри, какой класс был создан для в 1.1.
Привожу выдержки.
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.
<llImport("kernel32.dll"> Private Shared Function
BuildCommDCB( _
ByVal lpDef As String, ByRef lpDCB As DCB) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
ClearCommError( _
ByVal hFile As Integer, ByVal lpErrors As Integer, _
ByVal l As Integer) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
CloseHandle( _
ByVal hObject As Integer) As Integer
End Function
<llImport("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
<llImport("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
<llImport("kernel32.dll"> Private Shared Function
EscapeCommFunction( _
ByVal hFile As Integer, ByVal ifunc As Long) As Boolean
End Function
<llImport("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
<llImport("kernel32.dll"> Public Shared Function
GetCommModemStatus( _
ByVal hFile As Integer, ByRef lpModemStatus As Integer)
As Boolean
End Function
<llImport("kernel32.dll"> Private Shared Function
GetCommState( _
ByVal hCommDev As Integer, ByRef lpDCB As DCB) As
Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
GetCommTimeouts( _
ByVal hFile As Integer, ByRef lpCommTimeouts As
COMMTIMEOUTS) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
GetLastError() As Integer
End Function
<llImport("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
<llImport("kernel32.dll"> Private Shared Function
PurgeComm( _
ByVal hFile As Integer, ByVal dwFlags As Integer) As
Integer
End Function
<llImport("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
<llImport("kernel32.dll"> Private Shared Function
SetCommTimeouts( _
ByVal hFile As Integer, ByRef lpCommTimeouts As
COMMTIMEOUTS) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
SetCommState( _
ByVal hCommDev As Integer, ByRef lpDCB As DCB) As
Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
SetupComm( _
ByVal hFile As Integer, ByVal dwInQueue As Integer, _
ByVal dwOutQueue As Integer) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
SetCommMask( _
ByVal hFile As Integer, ByVal lpEvtMask As Integer) As
Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
WaitCommEvent( _
ByVal hFile As Integer, ByRef Mask As EventMasks, _
ByRef lpOverlap As OVERLAPPED) As Integer
End Function
<llImport("kernel32.dll"> Private Shared Function
WaitForSingleObject( _
ByVal hHandle As Integer, ByVal dwMilliseconds As
Integer) As Integer
End Function
<llImport("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-сайт:
Профиль | | #13
Добавлено: 02.03.07 03:10
Может это чем-то поможет.
Сначала мы открываем порт.
' 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.DataBits Property
и т.д.
Далее мы начинаем опрашивать порт.
' 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 (у меня все функции - сишная привычка).
' 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
Вот собственно и все.
Обрати внимание на граммотную обработку исключений.
Например.
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)