My programm gets a high-speed data from serialport, and timer reads it , after timer gets value , timer is disabled and code does sting operations where add value which accepted earlier from com to listview. THe problem is that UI thread is not completely freezing but it seems laggy when i drag the form also, That code which add +1 every time on the subitem.text - is not smooth.
founditem.SubItems(4).Text = founditem.SubItems(4).Text + 1
Why is that as knows timer creats its own thread, and it shouldnot freeze an UI( i cant get rid of timer, becsouse its neccesary to accept correct data from serial)
Any tips? i tried invoke,begininvoke and background_worker, maybe not correctly.
Also can i call background worker from timer event? I'm not good at asyc tasks. My code is:
Private Sub spOpen()
Try
spClose()
spObj.PortName = "COM4"
spObj.BaudRate = 230400
spObj.Parity = IO.Ports.Parity.None
spObj.DataBits = 8
spObj.StopBits = IO.Ports.StopBits.One
spObj.Handshake = IO.Ports.Handshake.None
spObj.DtrEnable = False 'imp
spObj.RtsEnable = False 'imp
spObj.NewLine = vbCr
spObj.ReadTimeout = 0
spObj.WriteTimeout = 250
spObj.ReceivedBytesThreshold = 1
spObj.Open()
Catch ex As Exception
'catch
End Try
End Sub
Private Sub spClose()
Try
If spObj.IsOpen Then
spObj.Close()
spObj.Dispose()
End If
Catch ex As Exception
'handle the way you want
End Try
End Sub
Function ReverseString(ByVal sText As String) As String
Dim lenText As Long, lPos As Long
If Len(sText) = 0 Then Exit Function
lenText = Len(sText)
ReverseString = Space(lenText)
For lPos = lenText To 1 Step -2
If lPos > 0 Then Mid(ReverseString, lenText - lPos + 1, 2) = Mid(sText, lPos - 1, 2)
If lPos = 0 Then Mid(ReverseString, lenText - lPos + 1, 2) = Mid(sText, lPos, 2)
Next lPos
'Return
End Function
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
'stop the timer (stops this function being called while it is still working
Timer1.Enabled = False
' get any new data and add the the global variable receivedData
receivedData = ReceiveSerialData()
'If receivedData contains a "<" and a ">" then we have data
If ((receivedData.Contains("<") And receivedData.Contains(">"))) Then
'parseData()
first_msg = 1
parseData()
End If
' restart the timer
Timer1.Enabled = True
End Sub
Function ReceiveSerialData() As String
Dim Incoming As String
Try
Incoming = spObj.ReadExisting()
If Incoming Is Nothing Then
Return "nothing" & vbCrLf
Else
Return Incoming
End If
Catch ex As TimeoutException
Return "Error: Serial Port read timed out."
End Try
End Function
Function parseData()
' uses the global variable receivedData
Dim pos1 As Integer
Dim pos2 As Integer
Dim length As Integer
Dim newCommand As String
Dim done As Boolean = False
Dim count As Integer = 0
While (Not done)
pos1 = receivedData.IndexOf("<") + 1
pos2 = receivedData.IndexOf(">") + 1
'occasionally we may not get complete data and the end marker will be in front of the start marker
' for exampe "55><T0056><"
' if pos2 < pos1 then remove the first part of the string from receivedData
If (pos2 < pos1) Then
receivedData = Microsoft.VisualBasic.Mid(receivedData, pos2 + 1)
pos1 = receivedData.IndexOf("<") + 1
pos2 = receivedData.IndexOf(">") + 1
End If
If (pos1 = 0 Or pos2 = 0) Then
' we do not have both start and end markers and we are done
done = True
Else
' we have both start and end markers
length = pos2 - pos1 + 1
If (length > 0) Then
'remove the start and end markers from the command
newCommand = Mid(receivedData, pos1 + 1, length - 2)
' show the command in the text box
RichTextBox1.Text = ""
RichTextBox1.AppendText(newCommand & vbCrLf)
'remove the command from receivedData
receivedData = Mid(receivedData, pos2 + 1)
'RichTextBox1.Text &= receivedData
uart_in = RichTextBox1.Text
data = ""
'RichTextBox2.Text = Mid(RichTextBox1.Text, 6, 3)
'If RichTextBox1.TextLength = 26 Then
can_id = Mid(uart_in, 6, 3) 'extracting and id
dlc = Mid(uart_in, 10, 1)
data = uart_in.Substring(26 - (dlc * 2))
hex2ascii(data)
data = data.InsertEveryNthChar(" ", 2)
' data = ReverseString(data)
Dim articlecheck As String = can_id
Dim founditem As ListViewItem = ListView1.FindItemWithText(articlecheck)
If Not (founditem Is Nothing) Then
founditem.SubItems(0).Text = can_id
founditem.SubItems(1).Text = dlc
' If founditem.SubItems(2).Text <> data Then
' founditem.SubItems(2).ForeColor = Color.LightYellow
founditem.SubItems(2).Text = data
' End If
founditem.SubItems(3).Text = timer_count - founditem.SubItems(3).Text
founditem.SubItems(4).Text = founditem.SubItems(4).Text + 1
founditem.SubItems(5).Text = asciival
' timer_count = 1
first_msg = 0
Else
Dim lvi As New ListViewItem(can_id)
lvi.SubItems.Add(dlc)
lvi.SubItems.Add(data)
lvi.SubItems.Add(timer_count)
lvi.SubItems.Add(count)
lvi.SubItems.Add(asciival)
ListView1.Items.Add(lvi)
End If
End If ' (length > 0)
End If '(pos1 = 0 Or pos2 = 0)
End While
End Function
Function hex2ascii(ByVal hextext As String) As String
Dim a As Integer
Dim y As Integer
Dim value As String
Dim num As String
For y = 1 To Len(hextext) Step 2
num = Mid(hextext, y, 2)
a = Val("&h" & num)
If a = 160 Or a = 0 Or a = 9 Or a = 32 Or a = 11 Then a = 46
value = value & Chr(a)
Next
asciival = value
End Function
Dim System.Threading.Thread yourthread As New System.Threading.Thread(AddressOf yourfunction())
yourthread.Priority = System.Threading.Priority.Highest
yourthread.Start();
you can create a loop in your function and add System.Threading.Thread.Sleep(1000) in the end of the loop to make it work like a timer. You can call all your existing functions through this thread, even the timer.
Be careful while accessing your controls through the thread.
Invoke(Sub() yourcontrol.property = someproperty)
Related
Today i continue my work, Building a menu with a vb.net console application. I found more samples to build with Windows forms. Still i try to get Basic Knowledge with the console surface.I was not able to put the following marquee text in a scroll menu, the second Code past the marquee text.
Module Module1
Dim aTimer As New System.Timers.Timer
Const marqueeText As String = "The quick brown fox... "
Dim sb As New System.Text.StringBuilder
Dim direction As Boolean = False
Sub Main()
aTimer.AutoReset = True
aTimer.Interval = 100 '1/10 second
AddHandler aTimer.Elapsed, AddressOf tick
aTimer.Start()
Console.ReadKey()
End Sub
Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
Console.Clear()
If sb.Length = 0 Then sb.Append(marqueeText)
If direction Then
sb.Insert(0, sb(sb.Length - 1))
sb.Remove(sb.Length - 1, 1)
Else
sb.Append(sb(0))
sb.Remove(0, 1)
End If
Console.CursorLeft = 10 'no visible change
Console.CursorTop = 10 'visible change
Console.Write("{0}{1}", vbCr, sb.ToString)
End Sub
End Module
The marquee text Output from above is not easy to manage with the console.cursorleft command. I have no clue how to move it to the right or to put the marquee Output in the following Code, a scroll menu, on the third line.
Module Module1
Dim MenuList As New List(Of String)
Sub PrintMenu(highlight As Integer, left As Integer, top As Integer)
Dim Nickvektor() As Integer = {1, 2, 3, 4, 5}
For I = 0 To MenuList.Count - 1
Console.CursorLeft = left
Console.CursorTop = top + I
If I = highlight Then
Console.Write("{0}", "[" & Nickvektor(I) & "]")
Else
Console.Write(MenuList(I))
End If
Next
End Sub
Sub Main()
Console.CursorVisible = False
Dim x As Integer = 0
Dim Nickvektor() As String = {" "}
For counter As Integer = 0 To 0
Do
For Each s In Nickvektor
MenuList.Add(s)
Next
x += 1
Loop Until x = 5
Next
Console.SetCursorPosition(10, 16)
Console.Write("[ ]")
Dim CurrentItem As Integer = 0
Dim CurrentKey As ConsoleKey
While CurrentKey <> ConsoleKey.Enter
PrintMenu(CurrentItem, 10, 10)
CurrentKey = Console.ReadKey(True).Key
Select Case CurrentKey
Case ConsoleKey.DownArrow
CurrentItem += 1
Case ConsoleKey.UpArrow
CurrentItem -= 1
End Select
CurrentItem = (CurrentItem + MenuList.Count) Mod MenuList.Count
End While
End Sub
End Module
The menu Frame for the above Code can be used with the up and down arrows on the Keyboard.
Maybe it is to much work but i have no clue how to continue.
The first Solution for the marquee Output is an easy change of the original code. The wrap, vbCr, was the main Problem to move the text output toward the right edge oft he screen. The following code can be used to change the cursorTop Positon and also the cursorLeft Position of the Text.
Console.CursorVisible = False
Console.CursorLeft = 30
Console.CursorTop = 10
Console.Write("{0}", sb.ToString)
The heavy part are the Menu code Lines. To answer my own question some additional help was necessary.
I posted my question on the MS developer Network written in german language. With the following link it can be viewed.
For the case the link should be broken or other cases i post the code on this site.
Module Module1
Dim MenuList As New List(Of String)
Dim aTimer As New System.Timers.Timer
Const marqueeText As String = "The quick brown fox... "
Dim sb As New System.Text.StringBuilder
Dim direction As Boolean = False
Sub PrintMenu(highlight As Integer, left As Integer, top As Integer)
Dim Nickvektor() As Integer = {1, 2, 3, 4, 5}
For I = 0 To MenuList.Count - 1
Console.CursorLeft = left
Console.CursorTop = top + I
If I = highlight Then
Console.Write("{0}", "[" & Nickvektor(I) & "]")
Else
Console.Write(MenuList(I))
End If
Next
End Sub
Sub Main()
Console.CursorVisible = False
aTimer.AutoReset = True
aTimer.Interval = 100 '1/10 second
AddHandler aTimer.Elapsed, AddressOf tick
Dim x As Integer = 0
Dim Nickvektor() As String = {" "}
For counter As Integer = 0 To 0
Do
For Each s In Nickvektor
MenuList.Add(s)
Next
x += 1
Loop Until x = 5
Next
Console.SetCursorPosition(10, 16)
Console.Write("[ ]")
Dim CurrentItem As Integer = 0
Dim CurrentKey As ConsoleKey
While CurrentKey <> ConsoleKey.Enter
If CurrentItem = 2 Then ' Zero can be used to show the marquee output prompt
aTimer.Start() ' With a change to two or four the timer can be stoped:
'Else
'If aTimer.Enabled Then
' aTimer.Stop()
'End If
End If
PrintMenu(CurrentItem, 10, 10)
CurrentKey = Console.ReadKey(True).Key
Select Case CurrentKey
Case ConsoleKey.DownArrow
CurrentItem += 1
Case ConsoleKey.UpArrow
CurrentItem -= 1
End Select
CurrentItem = (CurrentItem + MenuList.Count) Mod MenuList.Count
End While
End Sub
Private Sub tick(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)
If sb.Length = 0 Then sb.Append(marqueeText)
If direction Then
sb.Insert(0, sb(sb.Length - 1))
sb.Remove(sb.Length - 1, 1)
Else
sb.Append(sb(0))
sb.Remove(0, 1)
End If
Console.CursorVisible = False
Console.CursorLeft = 20
Console.CursorTop = 12 ' For the first Element CursorTop=10, fort he third 12
Console.Write("{0}", sb.ToString)
End Sub
End Module
To learn an other language like English i have to search a lot. Visual Basic Code is mostly written with English key words for the commands. I think it is easier to look up the maintainable changes for your self. To search is not every day funny.
About above picture I set the first variable in machine with word "hello"
(SerialPort.Write())
02 "0A" 14 "01hello" 03
Image *
Then I request the first variable in machine (SerialPort.ReadExisting())
02 "0B01" 03
Image *
The output is
૯୫1A૯୫01hello૯୫૯୫2A૯୫01hello૯୫ ૯୫3A૯୫01hello૯୫ ....
If I click the button request, number before A, always change and sequence until the number 9
How to get string desired result is just hello?
* I cannot post the picture because I need at least 10 reputation to post image.
Some code I use
Private Sub readMemoryButton_Click(sender As Object, e As EventArgs) Handles readMemoryButton.Click
'copy
'Received.AppendText("TX" & vbCrLf) ' Switch to a new line after every transmission
'SpaceCount = 0
Dim TextString As String
Dim TXArray(2047) As Byte
Dim I As Integer
Dim J As Integer = 0
Dim Ascii As Boolean = False
Dim Quote As Boolean = False
Dim Temp As Boolean
Dim Second As Boolean = False
Dim TXByte As Byte = 0
Dim CharByte As Byte
If COMPort.IsOpen Then
TextString = Received.Text
For I = 0 To TextString.Length - 1
CharByte = Asc(TextString.Chars(I))
If CharByte = 34 Then ' If " Then
Temp = Ascii
Ascii = Ascii Or Quote
Quote = Not (Temp And Quote)
Else
Ascii = Ascii Xor Quote
Quote = False
End If
If Not Quote Then
If Ascii Then
TXArray(J) = CharByte
J = J + 1
Else
If (CharByte <> 32) And (CharByte <> 10) And (CharByte <> 13) Then ' Skip spaces, LF and CR
CharByte = (CharByte - 48) And 31 ' And 31 makes it case insensitive
If CharByte > 16 Then
CharByte = CharByte - 7
End If
If Second Then
TXArray(J) = TXByte + CharByte
Second = False
J = J + 1
Else
TXByte = CharByte << 4
Second = True
End If
End If
End If
End If
Next
Try
COMPort.Write(TXArray, 0, J)
Dim vLabelMemory As String = COMPort.ReadExisting()
labelMemory.Text = vLabelMemory
Catch ex As Exception
MsgBox(ex.Message & " Check CTS signal or set Flow Control to None.")
End Try
Else
MsgBox("COM port is closed. Please select a COM port")
End If
End Sub
I send and receive statusnumbers via my comport, that works fine. If I send a new status, I actualize a datagridview, this also works like I want it to, so the algorithm should be ok.
The other way I also receive statusnumbers, write the new ones in my database and then want to actualize the datagridview. Here is the problem.
The com-port-receive method is in an own module. it calls a sub "Empfangen" which ist located in a form class. This sub Empfangen() extracts the reveived statusnumber and other information, it is tested and works satisfying. After that I call a sub StatusAnzeigen_DataGridViewMA() which changes the colors in the datagridview to the new status. And here must be the problem, datagridview.rowcount tells me 1 row exactly I have 4 rows in here,
So my idea was, to use delegate.
I declared the following delegate:
Public Delegate Sub StatusAnzeigen_DataGridViewMADelegate(ByVal msg As String)
And here part of the color changing code (remember it works, if I send the status)
Private Sub StatusAnzeigen_DataGridViewMA()
On Error Resume Next
' On Error GoTo StatusAnzeigen_DataGridViewMA_ERR
Dim treeIcon As Icon
Dim Anzahl As Integer
Dim count As Integer
Dim Farbe As String
Dim cell As DataGridViewImageCell
If DataGridViewMA.InvokeRequired Then
DataGridViewMA.BeginInvoke(New StatusAnzeigen_DataGridViewMADelegate(AddressOf StatusAnzeigen_DataGridViewMA), New Object())
Return
End If
Anzahl = DataGridMA.RowCount
For count = 0 To Anzahl - 1
It never uses invokerequired = true.
I have 2 questions, is the idea the right one? Is the thread the problem?
And if it is, where is my error, probably the place of implemention is wrong?
I tried this the first time and I'm really interested in help.
***Edit because of question to the hole picture:
This ist my COM Receive routine:
Public Sub MSCom_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles MSCom.DataReceived
Dim buffer As Object
Dim count As Integer
buffer = ""
count = 1
Do
Try
buffer = CStr(MSCom.ReadLine) ' Receive the data
Debug.Print("buffer: " & buffer)
If (InStrRev(buffer, ": 13")) > 0 Then
message = message + buffer
buffer = ""
End If
If Len(message) > 0 And InStrRev(buffer, "84") Then
buffer = message + buffer
message = ""
End If
Catch ex As Exception
buffer = ex.Message ' Exception handling
Exit Sub
End Try
Loop Until (InStrRev(buffer, ": 13") > 0 Or InStrRev(buffer, ": 12") > 0 Or InStrRev(buffer, "AFF") > 0)
If (InStrRev(buffer, ": 13") > 0 Or InStrRev(buffer, ": 12") > 0 Or InStrRev(buffer, "AFF") > 0) Then
Form_Dashboard.Empfangen(buffer)
End If
End Sub
The following code, is my sub Empfangen which takes the number, status etc. out of the received string.
Public Sub Empfangen(ByVal msg As String)
On Error Resume Next
Dim pos As Integer
Dim pos1 As Integer
Dim anrufer As String 'Rufnummer des Anrufers
Dim anruferdez As Integer
Dim hexStatus As String
Dim decstatus As Integer
Dim Statusstring As String
Dim strT As String
Dim typ As Integer
Dim test As String
Dim test1 As String
strInput = ""
If Len(msg) > 1 Then
pos = InStrRev(strInput, db.eigeneRNR)
pos1 = InStrRev(strInput, ": 13")
test = Mid(strInput, 14, 7) 'Rufnummer sender
test1 = Mid(strInput, pos + 10, 4) 'Status
'-----------Status Eingang einfach-------------------------------------------
If (pos > 0 And pos1 > 0) Then
' Anrufer und hexstatus aus strInput herauskopieren
anrufer = Mid(strInput, 13, 7) ' 6 Stellen der Teilnehmernummer des Anrufers
hexStatus = "&H" & Mid(msg, 36, Len(msg)) ' Status als Hexzahl
If Microsoft.VisualBasic.Strings.Right(hexStatus, 3) <> "AFF" Then ' Wenn Adressat nicht ausgeschaltet 4AFF oder 5AFF
'
hexStatus = Microsoft.VisualBasic.Strings.Right(hexStatus, 5)
hexStatus = Microsoft.VisualBasic.Strings.Left(hexStatus, 4)
decstatus = CLng("&H" & hexStatus) ' umwandeln in Dezimalzahl (Integer)
decstatus = db.FindeTNStatusNr(decstatus)
anruferdez = db.FindeTNPK(anrufer)
db.Schreibe_StatusTN(anruferdez, decstatus, 1) 'Prüfen, ob Decstatus integer ist
StatusAnzeigen_DataGridViewMA()
Else
decstatus = 98 'TN ausgeschaltet
db.Schreibe_StatusTN(anrufer, decstatus, 1)
StatusAnzeigen_DataGridViewMA()
End If
End If
pos1 = InStrRev(strInput, ": 12")
'-----------Status Eingang Quittung-------------------------------------------
If (pos > 0 And pos1 > 0) Then
'hexStatus = Microsoft.VisualBasic.Strings.Right(hexStatus, 5)
'hexStatus = Microsoft.VisualBasic.Strings.Left(hexStatus, 4)
anrufer = Mid(strInput, 13, 7) ' 6 Stellen der Teilnehmernummer des Anrufers
If Microsoft.VisualBasic.Strings.Right(msg, 3) <> "AFF" Then ' Wenn Adressat nicht ausgeschaltet 4AFF oder 5AFF
' Anrufer und hexstatus aus strInput herauskopieren
decstatus = 99
db.Schreibe_StatusTN(anrufer, decstatus, 1) 'Prüfen, ob Decstatus integer ist
Else
decstatus = 98 ''TN ausgeschaltet
db.Schreibe_StatusTN(anrufer, decstatus, 1)
End If
StatusAnzeigen_DataGridViewMA()
End If
strInput = ""
End If
End Sub
This is all functional validated, the status changes in the database. Only the datagridview doesn't actualize.
i me using e.HasMorePages with code
For x As Integer = RowNo To dgv.Rows.Count - 1
Dim mypen As New Pen(Color.Black, 6)
e.Graphics.DrawString(dgv.Rows(x - 1).Cells(0).Value.ToString(), f, Brushes.Black, 645, yElementy)
If RowNo Mod 6 = 0 Then
RowNo += 1
e.HasMorePages = True
Exit For
End If
RowNo += 1
Next
how to using e.HasMorePages With code
For Each myRow In dtn.Rows
ListView1.Items.Add(n + ListView1.Items.Count + 1)
ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(myRow.Item(13).ToString())
ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(myRow.Item(5).ToString())
ListView1.Items(ListView1.Items.Count - 1).SubItems.Add(myRow.Item(14).ToString())
'i want to add here
Next
Typical layout: count variable(class level) for remembering what position we are at in the items printing. I like a List(Of String) for looping and printing. Inside the printPage event you need to have a variable for what row(y axis) your printing the records to and increment it with each iteration. Since it's graphics based you can also use a Rectangle structure and print contents to it using a StringFormat object for text wrapping and layout.
Print Document
Example off the top of my head - not tested.
Public Class Form1 ' your form name here
Private count As Integer
Private row As Integer
Private Sub print_Page(...) Handles ...
row = 100 'starting point from the top
Using p As New Pen(Brushes.Bisque) 'self disposing graphics object
'we use the variable here to know where we are if we have to go to next page
Dim rowCount = dg.Rows.Count - 1
For i As Integer = count To rowCount
e.Graphics.DrawString({value},p, Font, x, y)
row += 16 'basically the font height and some space in-between
If row = e.MarginBounds.Bottom - 20 Then
e.HasMorePages = True
If i <> rowCount Then 'are we on the last row?
count = i ' remember where we left off
Exit Sub ' cause this event will fire again and we need to start over
End If
End If
Next
End Using
End Sub
'...
End Class
Public Class frmTestHasMorePages
Dim Font12 As Font = New Drawing.Font("Arial", 12, FontStyle.Regular)
Dim Font8 As Font = New Drawing.Font("Arial", 8, FontStyle.Regular)
Dim sBrush As Drawing.Brush
Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
Static count As Integer
Static topMargin As Integer = 50
Static line As Integer
Static s, z As Integer
Dim linesPerPage = 65
Dim lineCount = 350
Static totalpages As Integer = IIf(lineCount Mod linesPerPage = 0, (lineCount / linesPerPage), (lineCount / linesPerPage) + 1)
sBrush = Brushes.Black
Dim pageBottom = e.PageBounds.Bottom
For i As Integer = count To lineCount
If z > lineCount Then
sBrush = Brushes.Blue
e.Graphics.DrawString("Page " & s + 1 & "/" & totalpages, Font8, sBrush, 750, pageBottom - 20)
sBrush = Brushes.Red
e.Graphics.DrawString("End of document ", Font8, sBrush, 50, pageBottom - 20)
e.HasMorePages = False
Exit Sub
End If
e.Graphics.DrawString("Testing hasmorepages with different options " & z, Font12, sBrush, 45, (i * 16) + topMargin)
line += 15
z += 1
If i = linesPerPage AndAlso s <= totalpages Then
e.HasMorePages = True
sBrush = Brushes.Blue
s += 1
e.Graphics.DrawString("Page " & s & "/" & totalpages, Font8, sBrush, 750, pageBottom - 20)
e.Graphics.DrawString("Continued...", Font8, sBrush, 50, pageBottom - 20)
i = 0
If i <> lineCount Then REM if it is the last line to print
Exit Sub
End If
End If
Next
End Sub
End Class
Thanks for reading - I am using the class below to calculate the CRC32 checksum of a specified file.
My question is how would I go about reporting the progress of file completion (in %) to a progressbar on a different form. I have tried (i / count) * 100 under the New() sub but I am not having any luck, or setting the progress bar with it for that matter. Can anyone help?
Thanks in advance
Steve
Public Class CRC32
Private crc32Table() As Integer
Private Const BUFFER_SIZE As Integer = 1024
Public Function GetCrc32(ByRef stream As System.IO.Stream) As Integer
Dim crc32Result As Integer
crc32Result = &HFFFFFFFF
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim count As Integer = stream.Read(buffer, 0, readSize)
Dim i As Integer
Dim iLookup As Integer
Do While (count > 0)
For i = 0 To count - 1
iLookup = (crc32Result And &HFF) Xor buffer(i)
crc32Result = ((crc32Result And &HFFFFFF00) \ &H100) And &HFFFFFF
crc32Result = crc32Result Xor crc32Table(iLookup)
Next i
count = stream.Read(buffer, 0, readSize)
Loop
GetCrc32 = Not (crc32Result)
End Function
Public Sub New()
Dim dwPolynomial As Integer = &HEDB88320
Dim i As Integer, j As Integer
ReDim crc32Table(256)
Dim dwCrc As Integer
For i = 0 To 255
Form1.CRCWorker.ReportProgress((i / 255) * 100) 'Report Progress
dwCrc = i
For j = 8 To 1 Step -1
If (dwCrc And 1) Then
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
dwCrc = dwCrc Xor dwPolynomial
Else
dwCrc = ((dwCrc And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
End If
Next j
crc32Table(i) = dwCrc
Next i
'file complete
End Sub
End Class
'------------- END CRC32 CLASS--------------
'-------------- START FORM1 --------------------------
Private Sub CRCWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles CRCWorker.DoWork
For i = CurrentInt To dgv.Rows.Count - 1
CRCWorker.ReportProgress(0, i & "/" & Total_Files)
Current_File_Num = (i + 1)
SetControlText(lblCurrentFile, Str(Current_File_Num) & "/" & Total_Files)
result = CheckFile(SFV_Parent_Directory & "\" & dgv.Rows(i).Cells(0).Value, dgv.Rows(i).Cells(1).Value)
Select Case result
Case 0 ' missing file
UpdateRow(i, 2, "MISSING")
'dgv.Rows(i).Cells(2).Value = "MISSING"
Missing_Files = Missing_Files + 1
SetControlText(lblMissingFiles, Str(Missing_Files))
Case 1 ' crc match
UpdateRow(i, 2, "OK")
' dgv.Rows(i).Cells(2).Value = "OK"
Good_Files = Good_Files + 1
SetControlText(lblGoodFiles, Str(Good_Files))
Case 2 'crc bad
UpdateRow(i, 2, "BAD")
' dgv.Rows(i).Cells(2).Value = "BAD"
Bad_Files = Bad_Files + 1
SetControlText(lblBadFiles, Str(Bad_Files))
End Select
If CRCWorker.CancellationPending = True Then
e.Cancel = True
Exit Sub
End If
Next
End Sub
Private Sub CRCWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles CRCWorker.ProgressChanged
Dim val As Integer = e.ProgressPercentage
ProgressBar2.Maximum = 100
ProgressBar2.Value = e.ProgressPercentage
Debug.Print(val)
End Sub
Function CheckFile(ByVal tocheck_filepath As String, ByVal expected_crc As String) As Integer 'returns result of a file check 0 = missing 1 = good 2 = bad
If File.Exists(tocheck_filepath) = False Then
Return 0 'return file missing
End If
Dim f As FileStream = New FileStream(tocheck_filepath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
Dim c As New CRC32()
crc = c.GetCrc32(f)
Dim crcResult As String = "00000000"
crcResult = String.Format("{0:X8}", crc)
f.Close()
End Function
It appears your .ReportProgress() call is in the New() subroutine, which is the part that makes the lookup table for the CRC calculation. The New() subroutine is called once, before the main CRC routine. The main CRC routine is the one that takes up all the time and needs the progress bar.
Shouldn't the progress bar updating be in the GetCrc32() function? Something like this:
Public Function GetCrc32(ByRef stream As System.IO.Stream, _
Optional prbr As ProgressBar = Nothing) As UInteger
Dim crc As UInteger = Not CUInt(0)
Dim buffer(BUFFER_SIZE) As Byte
Dim readSize As Integer = BUFFER_SIZE
Dim left As Long = stream.Length
If Not (prbr Is Nothing) Then ' ProgressBar setup for counting down amount left.
prbr.Maximum = 100
prbr.Minimum = 0
prbr.Value = 100
End If
Dim count As Integer : Do
count = stream.Read(buffer, 0, readSize)
For i As Integer = 0 To count - 1
crc = (crc >> 8) Xor tbl((crc And 255) Xor buffer(i))
Next
If Not (prbr Is Nothing) Then ' ProgressBar updated here
left -= count
prbr.Value = CInt(left * 100 \ stream.Length)
prbr.Refresh()
End If
Loop While count > 0
Return Not crc
End Function
In Windows Forms BackgroundWorker Class is often used to run intensive tasks in another thread and update progress bar without blocking the interface.
Example of using BackgroundWorker in VB.Net
The problem is when you use use the form in your code without instantiating it Form1.CRCWorker.ReportProgress((i / 255) * 100) there is a kind of hidden "auto-instantiation" happening and new instance of Form1 is created each time.