memory mapped files disappear randomly - vb.net

I have a camera management system with the following components in vb.net
This has worked well for several years, but is now randomly failing in different programs with a 'file not found' error when accessing the memory file or simply freezing. This occurred after I added a new memory file (GPS2Memory) The design of the system is to have several data readers assembling data from a their own data streams and overwriting the prior values , while 3 control applications read these records and control servos. These actions are asynchronous.
I have tried deleting the MMF.Dispose but the apps continue to fail.
CreateMemoryFiles - Creates 5 memory files (Switch_Memory, INS_Memory, GPS_Memory, AHRS_Memory, GPS2Memory) each is 400 bytes except Switch - which is 20.
ReadAHRS reads a data stream on a com port, and places a formatted csv string in AHRSMemory about every 50 ms.
ReadSecondGPS reads a data stream on a com port and places a formatted csv string in GPS2Memory about every 30 ms.
ReadIMUData reads a data stream on a com port and places a formatted csv string in IMU_Memory about every 30 ms.
ReadSwitch reads a switch status on a USB port and places a formatted csv string in SwitchMemory about every 50 ms.
BankCompensator reads IMU_Memory (for roll data), and SwitchMemory (On or Off) to start servo control.
CameraControl reads GPS2Memory (for WAAS data) IMUMemory (for pitch, roll and heading) and SwitchMemory for starting an stopping servos and shutter events.
I have run all programs in Debug mode :
ReadSecondGPS failed after 16843 cycles - Failed on 'Openexisting" statement with 'Unable to find specified file.
ReadAHRS failed after 12652 cycles, with same error and message
ReadIMUData failed after 45331 cycles with same message
CreateMemoryFiles was still running and when I set a breakpoint, it was at 3679 cycles (Incrementing every 1000 ms) and continued.
I have tested the string length written to the files, and the longest is 109 characters - I set the length longer as the strings get more data as new data becomes available.
Why would Windows lose track of 3 memory files when the initiator was still active?
Here is the create code - this is an endless loop so the memory files should not disappear.
Option Explicit On
Option Strict On
Imports System
Imports System.Net
Imports System.Text
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Timers
Imports System.Threading
Public Class Form1
Public WithEvents MEMSTimer As New System.Windows.Forms.Timer()
Dim LoopForever As Boolean = True
ReadOnly GPSINS_Memory_File_Name As String = "GPSINSMemoryData"
ReadOnly GPS2_Memory_File_Name As String = "GPRMCmemoryData"
ReadOnly AHRS_Memory_File_Name As String = "AHRSMemoryData"
ReadOnly Switch_Memory_File_Name As String = "SwitchMemoryData"
Dim CycleCount As Integer = 1
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim GPS2 = MemoryMappedFile.CreateNew(GPS2_Memory_File_Name, 20, MemoryMappedFileAccess.ReadWrite)
Dim MMS = MemoryMappedFile.CreateNew(Switch_Memory_File_Name, 400, MemoryMappedFileAccess.ReadWrite)
Dim GPS = MemoryMappedFile.CreateNew(GPSINS_Memory_File_Name, 400, MemoryMappedFileAccess.ReadWrite)
Dim AHRS = MemoryMappedFile.CreateNew(AHRS_Memory_File_Name, 400, MemoryMappedFileAccess.ReadWrite)
CycleCountOut.Text = CType(CycleCount, String)
Do Until LoopForever = False
CycleCount += 1
CycleCountOut.Clear()
CycleCountOut.Text = CType(CycleCount, String)
Thread.Sleep(1000)
Loop
Application.Exit()
End Sub
Public Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
LoopForever = False
Application.Exit()
End Sub
Private Sub CycleCountOut_TextChanged(sender As Object, e As EventArgs) Handles CycleCountOut.TextChanged
End Sub
End Class
Here is a typical Write code
Sub WriteAHRS_To_Memory()
Dim MMF = MemoryMappedFile.OpenExisting(AHRS_Memory_File_Name)
Dim Bytes As Byte()
Bytes = StrToByteArray(AHRS_Data_Out)
Try
Using writer = MMF.CreateViewAccessor(0, Bytes.Length)
writer.WriteArray(Of Byte)(0, Bytes, 0, Bytes.Length)
' writer.Dispose()
End Using
Catch ex As Exception
MsgBox("mem write error = " & ex.ToString)
End Try
stop_time = Now
AHRS_elapsed_time = stop_time.Subtract(start_time)
AHRS_Update_Time.Clear()
AHRS_Update_Time.AppendText(AHRS_elapsed_time.TotalSeconds.ToString("0.000000"))
start_time = Now
MMF.Dispose()
End Sub
And typical Read code
Sub GetIMUData()
Dim MMS = MemoryMappedFile.OpenExisting(Switch_Memory_File_Name)
Using Switchreader = MMS.CreateViewAccessor(0, 20, MemoryMappedFileAccess.Read)
Dim SwitchByteString = New Byte(20) {}
Switchreader.ReadArray(Of Byte)(0, SwitchByteString, 0, SwitchByteString.Length)
outMessage = Convert.ToString(SwitchByteString)
teststring = ""
teststring = BitConverter.ToString(SwitchByteString)
For i As Integer = 0 To SwitchByteString.Length - 1
SwitchdataIn = System.Text.Encoding.ASCII.GetString(SwitchByteString)
Next
End Using
Dim SwitchString() As String
SwitchString = Split(SwitchdataIn, ",")
SwitchdataIn = SwitchString(0)
SwitchPositionDisplay.Clear()
SwitchPositionDisplay.Text = SwitchdataIn
MMS.Dispose()

Related

The sample rate of my sound card changes slightly. Counteract?

I read this thread because I also wanted to find out if the sample rate of my sound card is always the same or if the value fluctuates. I downloaded the Soundcheck programme recommended in the thread. According to the Windows settings, my sound card is set as follows:
Sample rate: 48000 Hz
Channels: 2
Resolution: 24 bits.
A long time ago I wrote an application that does a Fourier transform and displays the magnitudes of the individual frequencies as a bar (chart).
I have recorded a video for you because it is difficult for me to explain the problem. As you can see, according to Soundcheck, the bytes per second are changing all the time. I have also seen larger value deviations (up to ±1 %). I claim that this problem is the reason why the bars in the Fourier transformation programme jump up and down a bit, especially those that should not be visible at all.
Please note that due to the video editing programme it seems as if the played 2000 Hz test tone trills, but it does not. It is always the same volume.
Is there anything that can be done to get the true sample rate of the sound card, or is the code for getting the audio bytes not good enough?
I will delete the video in a few days.
This is the VB.NET source code to get the audio data (minimal example). You must download NAudio from Visual Studio's own NuGet package manager.
Imports Microsoft.VisualBasic.ControlChars
Public NotInheritable Class FormMain
Private continue_ As Boolean = True
''' <summary>
''' sample rate of the soundcard in Hertz
''' </summary>
Private Samplerate As Integer = 48000
''' <summary>
''' 1024
''' </summary>
Private ReadOnly BufferSize As Integer = CInt(Math.Pow(2, 10)) ' 1024
Private Shared wi As NAudio.Wave.WaveIn = Nothing
Private bwp As NAudio.Wave.BufferedWaveProvider = Nothing
''' <summary>
''' 21.333 ms
''' </summary>
Private usedMilliseconds As Double
Private cnt As Integer = 0
''' <summary>
''' to hold the latest soundcard data that we will graph. <para></para>
''' Size of this array becomes BufferSize ÷ 2, i.e., 512.
''' </summary>
Private DataArray As Double()
Private Sub AudioDataAvailable(ByVal sender As Object, e As NAudio.Wave.WaveInEventArgs)
bwp.AddSamples(e.Buffer, 0, e.BytesRecorded)
End Sub
Private Sub Start_Listening()
wi = New NAudio.Wave.WaveIn()
wi.DeviceNumber = 1
wi.WaveFormat = New NAudio.Wave.WaveFormat(Samplerate, 16, 1)
wi.BufferMilliseconds = CInt(CDbl(BufferSize) / CDbl(Samplerate) * 1000.0)
usedMilliseconds = CDbl(BufferSize) / CDbl(Samplerate) * 1000.0
AddHandler wi.DataAvailable, AddressOf AudioDataAvailable
bwp = New NAudio.Wave.BufferedWaveProvider(wi.WaveFormat)
bwp.BufferLength = BufferSize * 2
bwp.DiscardOnBufferOverflow = True
Try
wi.StartRecording()
Catch ex As NAudio.MmException
MessageBox.Show($"Could not record from audio device!{NewLine}{NewLine}{ex.Message}",
"",
MessageBoxButtons.OK,
MessageBoxIcon.Error)
End Try
End Sub
Public Sub GetLatestData()
Dim audioBytes As Byte() = New Byte(BufferSize - 1) {}
bwp.Read(audioBytes, 0, BufferSize)
If audioBytes.Length = 0 Then Return
'If audioBytes(BufferSize - 2) = 0 Then Return
Dim BYTES_PER_POINT As Integer = 2
Dim PointCount As Integer = audioBytes.Length \ BYTES_PER_POINT
DataArray = (New Double(PointCount - 1) {})
For i As Integer = 0 To PointCount - 1 Step 2
DataArray(i) = CDbl(BitConverter.ToInt16(audioBytes, i * BYTES_PER_POINT))
Next
End Sub
Private Async Sub ButtonStart_Click(sender As Object, e As EventArgs) Handles ButtonStart.Click
Start_Listening()
continue_ = True
While continue_
Await Task.Run(Sub() FT())
Await Task.Run(Sub() Plot())
End While
End Sub
Private Sub ButtonStop_Click(sender As Object, e As EventArgs) Handles ButtonStop.Click
If wi IsNot Nothing Then
wi.StopRecording()
RemoveHandler wi.DataAvailable, AddressOf AudioDataAvailable
wi.Dispose()
End If
continue_ = False
PictureBox1.Image = Nothing
GC.Collect()
End Sub
Private Sub Plot()
' plot the bars
End Sub
Private Sub FT()
GetLatestData()
If DataArray Is Nothing Then
Return
End If
' do a fourier transform here
End Sub
Private Sub NumericUpDown_Samplerate_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown_Samplerate.ValueChanged
Me.Samplerate = CInt(NumericUpDown_Samplerate.Value)
End Sub
End Class
Addition for future readers
May 2, 2022, 11:19 a.m.,
Thank you, Hans, for this interesting article. No sarcasm. The article describes exactly the problems I am experiencing and states that this is normal and because the measurement data is finite instead of infinite.
My problems are in fact:
1.) The rectangles in the chart of wrong, neighbouring frequencies also rise.
2.) There is a wave effect, i.e., the individual bars rise and fall from right to left like a wave. “…an FFT of these data produces spectral values “riding” on a curve, not a single point at a single frequency as you might expect.”
Figure 3b best illustrates the situation: a pure 17.5 Hz sine wave shows up in the graph making the neighbouring points at 16 Hz and 18 Hz rise (instead of being peaked at 17.5 Hz).
So I assume (as of now) that the approach to get the sound card data is sufficient and there are simply some errors which are documented in scientific papers.

TCP Client not receiving all the messages

I am trying to write a small client which will listen to a server on a certain port. When I run my code it seems to hang, then it will only give me the first message and not receive anymore after? Im wrecking my brains here. Any help appreciated.
Option Strict On
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
'Form Controls.
Private lblPort As New Label
Private txtPort As New TextBox
Private lblIp As New Label
Private txtIp As New TextBox
Private lblSend As New Label
Private txtSend As New TextBox
Private WithEvents btnConnectSendReceive As New Button
Private lblReceived As New Label
Private lvwReceived As New ListView
Private txtBoxrecieved As New RichTextBox
'Global Objects.
Private gSocket As Socket = Nothing
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Setup form controls.
With Me
.Text = "SplitPackManagerTest"
.Controls.Add(lblPort)
.Controls.Add(txtPort)
.Controls.Add(lblIp)
.Controls.Add(txtIp)
.Controls.Add(lblSend)
.Controls.Add(txtSend)
.Controls.Add(btnConnectSendReceive)
.Controls.Add(lblReceived)
.Controls.Add(lvwReceived)
.Controls.Add(txtBoxrecieved)
.Height = 600
End With
With lblPort
.Text = "Port:"
.Location = New Point(12, 12)
.AutoSize = True
End With
With txtPort
.Text = "3001" 'Same port that server is listening on.
.Location = New Point(100, 12)
End With
With lblIp
.Text = "IP:"
.Location = New Point(12, 42)
.AutoSize = True
End With
With txtIp
.Text = "127.0.0.1" 'Loop-back IP address (localhost).
.Location = New Point(100, 42)
End With
With lblSend
.Text = "Send:"
.Location = New Point(12, 72)
.AutoSize = True
End With
With txtSend
.Text = Chr(2) & "(login (term-id 2))" & Chr(3)
.Location = New Point(100, 72)
End With
With btnConnectSendReceive
.Text = "Connect"
.Location = New Point(12, 122)
.Width = 260
End With
With lblReceived
.Text = "Received Bytes:"
.Location = New Point(12, 182)
.AutoSize = True
End With
With lvwReceived
.Height = 100
.Dock = DockStyle.Bottom
.View = View.Details
.GridLines = True
.FullRowSelect = True
.MultiSelect = False
.Scrollable = True
.Columns.Add("Dec")
.Columns.Add("Hex")
.Columns.Add("Chr")
For Each vCol As ColumnHeader In .Columns
vCol.Width = CInt(Math.Floor(.Width / .Columns.Count)) - CInt(Math.Floor(30 / .Columns.Count))
Next
End With
With txtBoxrecieved
.Height = 200
.Dock = DockStyle.Bottom
.ScrollBars = RichTextBoxScrollBars.Both
End With
End Sub
Private Function ConnectSendReceive(ByVal pSendData As Byte(), ByVal pIp As String, ByVal pPort As Integer) As Byte()
'Try creating IP endpoint.
If String.IsNullOrEmpty(pIp) Then Return Nothing
If Not IPAddress.TryParse(pIp, Nothing) Then Return Nothing
Dim vIp As IPAddress = IPAddress.Parse(txtIp.Text)
Dim vEndPoint As New IPEndPoint(vIp, CInt(txtPort.Text))
'Timeout will be 0.5 seconds.
Dim vTimeout As Integer = 500000
'For our little example, we expect all messages to be 1024 bytes or below (arbitrary amount).
Dim vMessageLength As Integer = 1002400000
'Remember, when dimensioning arrays, the integer specified is the upper bounds, not the length.
Dim vServerResponse As Byte() = Nothing
'Initiate socket.
Dim gSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
'Connect.
Try
gSocket.Connect(vEndPoint)
Catch ex As Exception
Return Nothing
End Try
If Not gSocket.Connected Then Return Nothing
'Send.
'Socket.SendTimeout = vTimeout
gSocket.Send(pSendData)
txtBoxrecieved.AppendText("Sending.. " & txtSend.Text)
'Receive response.
'Socket.ReceiveTimeout = vTimeout
Dim vBuffer(vMessageLength - 1) As Byte
Dim vNumOfBytesReceived As Integer = 0
Try
vNumOfBytesReceived = gSocket.Receive(vBuffer, 0, vMessageLength, SocketFlags.None)
Catch ex As Exception
Return Nothing
End Try
'Return received bytes.
ReDim vServerResponse(vNumOfBytesReceived - 1)
Array.Copy(vBuffer, vServerResponse, vNumOfBytesReceived)
'Disconnect (since we're using a "Using" statement, the socket will be disconnected here without us explicitly doing it).
Return vServerResponse
End Function
Private Sub btnConnectSendReceive_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnectSendReceive.Click
'Send message and get response from server.
Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.ASCII.GetBytes(txtSend.Text), txtIp.Text, CInt(txtPort.Text))
'Did we receive a response?
If vServerResponse Is Nothing Then MessageBox.Show("Server not reachable / Received no response from server.") : Exit Sub
'Do something with response.
For Each vByte As Byte In vServerResponse
Dim vLvi As New ListViewItem
With vLvi
'Decimal column.
.Text = vByte.ToString
'Hexidecimal column.
.SubItems.Add(vByte.ToString("X2"))
'Character column.
.SubItems.Add(ChrW(vByte))
End With
With lvwReceived
.Items.Add(vLvi)
.EnsureVisible(.Items.Count - 1)
End With
Next
txtBoxrecieved.AppendText(UnicodeBytesToString(vServerResponse))
End Sub
Private Function UnicodeBytesToString(
ByVal bytes() As Byte) As String
Return System.Text.Encoding.ASCII.GetString(bytes)
End Function
End Class
THanks
David
You need to know what's happening on both sides of this conversation. To do that, you need to listen in with a tool like Wireshark. Download Wireshark and learn to use it.
The reason I tend to agree with the_lotus is that the very large buffer you have allocated (ignoring the likely sizing bug) implies that you are expecting a fairly large response. Packet payloads can be up to 64KB but that's uncommon and even if such a thing occurs the protocol allows for fragmentation en route.
So if the data is split over several packets you'll need to keep reading until you have a complete payload. This may entail looking for boundary markers in a stream, and if there's a possibility of receiving more payloads over the same connection you'll need to preserve the start of the next payload in a way that allows you to accumulate the rest of it.
If you do that you will probably see a complete packet with a partial payload, as described by the_lotus in a comment posted while I was still writing.
I think he's probably right, but he could also be wrong, and a tool like Wireshark will allow you to find out, instead of guessing and hacking your code around in a blind attempt to validate your hypotheses.
The style of I/O that you are using is called polling. Sometimes it's necessary to do it that way, eg embedded systems often don't support anything more sophisticated, there isn't space for it. But on a system with a full .NET framework you really ought to use IOCP. It's not strictly necessary for a single user app, but if you pick up the right habits you won't create scalability problems.
OK, as to why the response is truncated, after examining your code (VB makes my eyes hurt) I'm almost sure the_lotus is right. You are reading exactly once from the socket and then you are closing it without any attempt to check whether you have the entire response or any attempt to read more data.
This looks like a first year university assignment, so presumably you have some sort of specification. To determine whether you have the entire response you need to know either one of the following
an expected payload length
the location and structure of data in the payload telling you how long the remainder is (or sometimes the size of the total packet)
an end of payload marker, this will be a particular sequence of bytes guaranteed not to otherwise occur in the payload.
Some pseudocode
open the connection
while not CheckForCompletePayload(buffer)
read some data and append it to your buffer
close the connection.

store and play microphone data in real time vb.net

as the title says, i'm trying to store and play microphone data in real time with vb.net 2010 and NAudio library. I got this code in C# from the NAudio Codeplex website and i translated it in vb.net.
There's no error in the code and the program works (i put a counter that keeps increasing and updating a label each time mic data is available to see if it's actually working), but i can't hear anything.
here is the code
Imports NAudio
Imports System.IO
'Libraries I'm using
Private Sub wi_dataAvailable(ByVal obj As Object, ByVal e As Wave.WaveInEventArgs) Handles wi.DataAvailable
count += 1 'here is where the counter increases
Label1.Text = count 'and here the label is updated and it seems to work fine
play_packet(e.Buffer)
End Sub
Private Sub play_packet(ByVal DR() As Byte)
Dim MS As New MemoryStream(DR)
Dim frmt As New Wave.WaveFormat
frmt = Wave.WaveFormat.CreateALawFormat(8000, 1)
Dim rsws As New Wave.RawSourceWaveStream(MS, frmt)
Dim pcms As Wave.WaveStream = Wave.WaveFormatConversionStream.CreatePcmStream(rsws)
Dim m_bwp As New Wave.BufferedWaveProvider(New Wave.WaveFormat(8000, 16, 1))
Dim dec() As Byte = cnssb(pcms)
m_bwp.AddSamples(dec, 0, dec.Length)
Dim latency As Integer
Dim cbi As Wave.WaveCallbackInfo = Wave.WaveCallbackInfo.NewWindow
Dim out_dev As New Wave.WaveOut(cbi)
out_dev.DesiredLatency = latency
out_dev.Init(m_bwp)
out_dev.Play()
End Sub
Private Function cnssb(ByVal nss As Wave.WaveStream) As Byte()
Dim memstr As New MemoryStream
Dim buff(1024) As Byte
Dim bytes As Integer
bytes = nss.Read(buff, 0, buff.Length)
While bytes > 0
memstr.Write(buff, 0, bytes)
bytes = nss.Read(buff, 0, buff.Length)
End While
Dim by() As Byte = memstr.ToArray
Return by
End Function
hope you can help me!
You shouldn't be creating a new WaveOut and BufferedWaveProvider every time a recorded buffer is received. Instead create one of each, and just add the audio into the BufferedWaveProvider as you receive it.
Solved!
I declared a boolean variable and then i edited the play_packet function like this:
dim initialized as boolean
'in the form load i set the variable to false
'and then here is the function
Private Sub play_packet(ByVal DR() As Byte)
Dim MS As New MemoryStream(DR)
Dim dec() As Byte = MS.ToArray
m_bwp.AddSamples(dec, 0, dec.Length)
MS.Close()
MS.Dispose()
Dim latency As Integer = 50
Dim cbi As Wave.WaveCallbackInfo = Wave.WaveCallbackInfo.NewWindow
Dim out_dev As New Wave.DirectSoundOut
out_dev.Volume = 1
If initialized = False Then
out_dev.Init(m_bwp)
out_dev.Play()
initialized = True
End If
End Sub

Convert VB6 Open For Binary to VB.Net (Fixed String Array)

I am trying to convert a VB6 app that reads a binary file. I have listed the VB6 and the converted VB.Net code I am trying to use. I have tried everything I can think of and I either get Unable to read beyond the end of the stream or Cannot determine array type because it is nothing. Please help!
'#################### VB6 Code ####################
Private Const DIGITALOUTS = 24
Private Const PAUSES = 8
Private PLabel(PAUSES - 1) As String * 30
Private EventLab(DIGITALOUTS - 1) As String * 20
Private Sub ReadFile()
Dim FileNumber As Integer
FileNumber = FreeFile
Open "C:\TEST.BAT" For Binary As #FileNumber
Get #FileNumber, 3000, PLabel 'automatic pausing instruction labels
Get #FileNumber, 3500, EventLab 'digital output channel labels
Close #FileNumber
End Sub
'#################### Converted VB.Net Code ####################
Private Const DIGITALOUTS As Short = 24
Private Const PAUSES As Short = 8
<VBFixedArray(PAUSES - 1)> <VBFixedString(30)> Dim PLabel() As String
<VBFixedArray(DIGITALOUTS - 1)> <VBFixedString(20)> Dim EventLab() As String
Private Sub ReadFile()
Dim f As Short = FreeFile()
FileOpen(f, "C:\TEST.BAT", OpenMode.Binary)
FileGet(f, PLabel, 3000) 'automatic pausing instruction labels <===Error: Unable to read beyond the end of the stream
FileGet(f, EventLab, 3500) 'digital output channel labels
FileClose(f)
End Sub
I figured it out
Private Const DIGITALOUTS As Short = 24
Private Const PAUSES As Short = 8
Private Structure Pause
<VBFixedString(30)> Dim Label() As String
End Structure
Private Structure Digital
<VBFixedString(20)> Dim Label() As String
End Structure
Dim PLabel(PAUSES - 1) as Pause
Dim EventLab(DIGITALOUTS - 1) as Digital
Private Sub ReadFile()
Dim f As Short = FreeFile()
FileOpen(f, "C:\Test.BAT", OpenMode.Binary)
FileGet(f, PLabel, 3000) 'automatic pausing instruction labels
FileGet(f, EventLab, 3500) 'digital output channel labels
FileClose(f)
End Sub

Error In VB.Net code

I am getting the error "Format Exception was unhandled at "Do While objectReader.Peek <> -1
" and after. any help would be wonderful.
'Date: Class 03/20/2010
'Program Purpose: When code is executed data will be pulled from a text file
'that contains the named storms to find the average number of storms during the time
'period chosen by the user and to find the most active year. between the range of
'years 1990 and 2008
Option Strict On
Public Class frmHurricane
Private _intNumberOfHuricanes As Integer = 5
Public Shared _intSizeOfArray As Integer = 7
Public Shared _strHuricaneList(_intSizeOfArray) As String
Private _strID(_intSizeOfArray) As String
Private _decYears(_intSizeOfArray) As Decimal
Private _decFinal(_intSizeOfArray) As Decimal
Private _intNumber(_intSizeOfArray) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'The frmHurricane load event reads the Hurricane text file and
'fill the combotBox object with the data.
'Initialize an instance of the StreamReader Object and declare variable page 675 on the book
Dim objectReader As IO.StreamReader
Dim strLocationAndNameOfFile As String = "C:\huricanes.txt"
Dim intCount As Integer = 0
Dim intFill As Integer
Dim strFileError As String = "The file is not available. Please restart application when available"
'This is where we code the file if it exist.
If IO.File.Exists(strLocationAndNameOfFile) Then
objectReader = IO.File.OpenText(strLocationAndNameOfFile)
'Read the file line by line until the file is complete
Do While objectReader.Peek <> -1
**_strHuricaneList(intCount) = objectReader.ReadLine()
_strID(intCount) = objectReader.ReadLine()
_decYears(intCount) = Convert.ToDecimal(objectReader.ReadLine())
_intNumber(intCount) = Convert.ToInt32(objectReader.ReadLine())
intCount += 1**
Loop
objectReader.Close()
'With any luck the data will go to the Data Box
For intFill = 0 To (_strID.Length - 1)
Me.cboByYear.Items.Add(_strID(intFill))
Next
Else
MsgBox(strFileError, , "Error")
Me.Close()
End If
End Sub
Put a break-point on these lines and step through your code:
_decYears(intCount) = Convert.ToDecimal(objectReader.ReadLine())
_intNumber(intCount) = Convert.ToInt32(objectReader.ReadLine())
Whatever is being returned by ReadLine isn't in the proper decimal or integer format when passed to the converters. You'll need to add some try/catch blocks around the do-while loop operations to handle it gracefully and make sure your data is formatted the way you expected since the wrong parts are being used in this scenario.
Also, each call to ReadLine is returning an entirely new line and the Peek check won't account for those. As long as you can trust your data that's fine.
Instead of using Convert.ToDecimal an Convert.ToInt32, try using Decimal.TryParse() and Int32.TryParse(). If they don't parse, you know your file isn't setup correctly. If they do parse, then you've loaded the value into a variable for your use.
EDIT:
Use it like this.
Dim myDecimal As Decimal
If Decimal.TryParse(objectReader.ReadLine(), myDecimal) Then
'your string successfully parsed. Use myDecimal however you want. It has the parsed value.
Else
'your string is not a decimal. Now that you know that, you can handle this situation here without having to catch an exception.
End If