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

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

Related

memory mapped files disappear randomly

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()

visual basic .NET get user input without pressing enter

I know of the existence of the code character = System.Console.ReadKey().tostring.
This will read one character.
Also in another stack overflow post I found:
Public Shared Function ReadPipedInfo() As StreamReader
'call with a default value of 5 milliseconds
Return ReadPipedInfo(5000)
End Function
Public Shared Function ReadPipedInfo(waitTimeInMilliseconds As Integer) As StreamReader
'allocate the class we're going to callback to
Dim callbackClass As New ReadPipedInfoCallback()
'to indicate read complete or timeout
Dim readCompleteEvent As New AutoResetEvent(False)
'open the StdIn so that we can read against it asynchronously
Dim stdIn As Stream = Console.OpenStandardInput()
'allocate a one-byte buffer, we're going to read off the stream one byte at a time
Dim singleByteBuffer As Byte() = New Byte(0) {}
'allocate a list of an arbitary size to store the read bytes
Dim byteStorage As New List(Of Byte)(4096)
Dim asyncRead As IAsyncResult = Nothing
Dim readLength As Integer = 0
'the bytes we have successfully read
Do
'perform the read and wait until it finishes, unless it's already finished
asyncRead = stdIn.BeginRead(singleByteBuffer, 0, singleByteBuffer.Length, New AsyncCallback(AddressOf callbackClass.ReadCallback), readCompleteEvent)
If Not asyncRead.CompletedSynchronously Then
readCompleteEvent.WaitOne(waitTimeInMilliseconds)
End If
'end the async call, one way or another
'if our read succeeded we store the byte we read
If asyncRead.IsCompleted Then
readLength = stdIn.EndRead(asyncRead)
'If readLength > 0 Then
byteStorage.Add(singleByteBuffer(0))
'End If
End If
Loop While asyncRead.IsCompleted AndAlso readLength > 0
'we keep reading until we fail or read nothing
'return results, if we read zero bytes the buffer will return empty
Return New StreamReader(New MemoryStream(byteStorage.ToArray(), 0, byteStorage.Count))
End Function
Private Class ReadPipedInfoCallback
Public Sub ReadCallback(asyncResult As IAsyncResult)
'pull the user-defined variable and strobe the event, the read finished successfully
Dim readCompleteEvent As AutoResetEvent = TryCast(asyncResult.AsyncState, AutoResetEvent)
readCompleteEvent.[Set]()
End Sub
End Class
which reads input if the user pressed enter
how could I make some code that reads (multiple) character(s) without letting the user press enter all the time? But instead use time as the indicator to stop reading the console?
You can use System.Console.Read() here. It reads as character from standard input stream. https://msdn.microsoft.com/en-us/library/system.console.read(v=vs.110).aspx
According to here I found out how to deal with it:
Public Module ConsoleHelper
Sub Main()
msgbox(ReadKeyWithTimeOut(10000).key.ToString)
End Sub
Public Function ReadKeyWithTimeOut(timeOutMS As Integer) As ConsoleKeyInfo
Dim timeoutvalue As DateTime = DateTime.Now.AddMilliseconds(timeOutMS)
While DateTime.Now < timeoutvalue
If Console.KeyAvailable Then
Dim cki As ConsoleKeyInfo = Console.ReadKey()
Return cki
Else
System.Threading.Thread.Sleep(100)
End If
End While
Return New ConsoleKeyInfo(" "C, ConsoleKey.Spacebar, False, False, False)
End Function
End Module
Now just finding out how to give attribute key NULL or something if it timed out.

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

How to correctly read a random access file in VB.NET

I am attempting to read a random access file, but I am getting the following error on the first file Error 5 (unable to read beyond end of the stream). I am not sure what I am doing wrong here, how might I fix this issue?
Structure StdSections
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(15), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=15)> Public A() As Char 'BEAM --- complete beam designation 15
'UPGRADE_WARNING: Fixed-length string size must fit in the buffer. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="3C1E4426-0B80-443E-B943-0627CD55D48B"'
<VBFixedString(2), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst:=2)> Public B() As Char 'DSG --- shape ie "W" or "C" 2
Dim C As Single 'DN --- nominal depth of section 4
Dim d As Single 'WGT --- weight 4
.
.
.
End structure
''Note 'File1'is the existing RAF and holds complete path!
Dim i,ffr,fLength,lastmembNo as integer
sectionFound = False
Dim std As new StdSections
fLength = Len(std)
If fLength = 0 Then fLength = 168 ' 177
ffr = FreeFile()
FileOpen(ffr, File1, OpenMode.Random, OpenAccess.Read, OpenShare.LockRead, fLength)
lastmembNo = CInt(LOF(ffr)) \ fLength
For i = 1 To lastmembNo
FileGet(ffr, std, i)
>>Error 5 (unable to read beyond end of the stream) <<<
If Trim(memberID) = Trim(std.A) Then
sectionFound = True
end if
next i
Wow Freefile! That's a blast from the past!
I haven't really used the old OpenFile etc. file access methods in VB.NET, so I'm just speculating, but in .NET many of the variable types got changed in size. e.g. an Integer is now 32-bits (4 bytes), I think a Boolean is different, though a Single is still 4 bytes.
Also, strings in .NET are by default in Unicode, not ASCII, so you cannot rely on 1 character=1 byte in a .NET String variable. In fact, .NET actualy "JIT compiles" programs on the PC before running, so you can't really lay out structures in memory easily like the old days.
If you want to switch to the new "Stream" based objects, here's some code to get you started:
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strTest As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Call My.Computer.FileSystem.WriteAllText(strFilename, strTest, False)
Dim byt(2) As Byte
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
fs.Seek(16, SeekOrigin.Begin)
fs.Read(byt, 0, 3)
Dim s As String = Chr(byt(0)) & Chr(byt(1)) & Chr(byt(2))
MsgBox(s)
fs.Seek(5, SeekOrigin.Begin)
fs.Write(byt, 0, 3)
End Using
Dim strModded As String = My.Computer.FileSystem.ReadAllText(strFilename)
MsgBox(strModded)
I wouldn't blame you for keeping the old method though: with the new method, you'll need to define a class, and then have a custom routine to convert from Byte() to the properties of the class. More work than simply loading bytes from the file into memory.
OK, I think you should switch to the ".NET way", as follows:
Imports System.IO
Imports System.Xml
Public Class Form1
Public Const gintRecLen_CONST As Integer = 177
Class StdSections2
Private mstrA As String
Public Property A() As String
Get
Return mstrA
End Get
Set(ByVal value As String)
If value.Length <> 15 Then
Throw New Exception("Wrong size")
End If
mstrA = value
End Set
End Property
Private mstrB As String
Public Property B() As String
Get
Return mstrB
End Get
Set(ByVal value As String)
If value.Length <> 2 Then
Throw New Exception("Wrong size")
End If
mstrB = value
End Set
End Property
Public C(39) As Single
Public Shared Function FromBytes(byt() As Byte) As StdSections2
Dim output As New StdSections2
If byt.Length <> gintRecLen_CONST Then
Throw New Exception("Wrong size")
End If
For i As Integer = 0 To 14
output.mstrA &= Chr(byt(i))
Next i
For i As Integer = 15 To 16
output.mstrB &= Chr(byt(i))
Next i
For i As Integer = 0 To 39
Dim bytTemp(3) As Byte
output.C(i) = BitConverter.ToSingle(byt, 17 + 4 * i)
Next i
Return output
End Function
End Class
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim strFilename As String = "C:\Junk\Junk.txt"
Dim strMemberID As String = "foo"
Dim intRecCount As Integer = CInt(My.Computer.FileSystem.GetFileInfo(strFilename).Length) \ gintRecLen_CONST
Dim blnSectionFound As Boolean = False
Using fs As New FileStream(strFilename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
For intRec As Integer = 0 To intRecCount - 1
Dim intRecPos As Integer = gintRecLen_CONST * intRec
fs.Seek(intRecPos, SeekOrigin.Begin)
Dim byt(gintRecLen_CONST - 1) As Byte
fs.Read(byt, 0, gintRecLen_CONST)
Dim ss2 As StdSections2 = StdSections2.FromBytes(byt)
'MsgBox(ss2.A & ":" & ss2.C(3)) 'debugging
If strMemberID.Trim = ss2.A.Trim Then
blnSectionFound = True
Exit For
End If
Next intRec
End Using
MsgBox(blnSectionFound.ToString)
End Sub
End Class
We define a class called StdSections2 which uses .NET strings and an array of Singles. We use 0-based arrays everywhere. We load the file using the new FileStream object, and use the Seek() command to find the position we want. We then load raw bytes out of the file, and use Chr() and BitConverter.ToSingle() to convert the raw bytes into strings and singles.
I'm not sure about your example but this one however, works:
Public Class Form1
Const maxLenName = 30
Structure person
<VBFixedString(maxLenName)> Dim name As String
Dim age As Byte
End Structure
Private Sub Form1_Load(sender As [Object], e As EventArgs) Handles MyBase.Load
Dim entryIn As New person
Dim recordLen As Integer = Len(entryIn)
Dim entry As person
If FileIO.FileSystem.FileExists("test.raf") Then Kill("test.raf")
FileOpen(1, "test.raf", OpenMode.Random,,, recordLen)
'write
entry.name = LSet("Bill", maxLenName)
entry.age = 25
FilePut(1, entry, 6) 'write to 6th record
'read
Dim nRecords As Integer = LOF(1) \ recordLen
FileGet(1, entryIn, nRecords)
FileClose(1)
Dim personName As String = RTrim(entryIn.name)
Dim personAge As Byte = entryIn.age
MsgBox(personName & "'s age is " & personAge)
End Sub
End Class

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