VB InvokeRequired doesn't appear to detect different threads - vb.net

I have a logging function that get called from different threads. The logging function uses InvokeRequired to determine if the caller is in the same thread as the textbox was created in. If all the code is put into the same class it works fine. But when separated out InvokeRequired always returns false.
Imports System.Threading
Public Class Test_Main
Dim tt_object As Test_Thread = Test_Thread.Get_Test_Thread_Class()
Private Shared logger_lock As New Object
Delegate Sub WriteLogMessage_Callback(text As String)
Private Sub btn_start_Click(sender As Object, e As EventArgs) Handles btn_start.Click
WriteLogMessage("From - btn_start_Click")
tt_object.Start_Threads()
End Sub
Public Sub WriteLogMessage(ByVal message As String)
If (Me.InvokeRequired) Then
Dim d As New WriteLogMessage_Callback(AddressOf WriteLogMessage)
Me.Invoke(d, New Object() {[message]})
Else
SyncLock logger_lock
log_box.Text += System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") & " " & message & vbCrLf
log_box.SelectionStart = log_box.Text.Length
log_box.ScrollToCaret()
End SyncLock
End If
Application.DoEvents()
End Sub
End Class
Public Class Test_Thread
Private Shared _thisInstance As Test_Thread = Nothing
Private t_1 As Thread
Private t_2 As Thread
Protected Sub New() 'Class constructor
t_1 = New Thread(AddressOf Thread_1)
t_2 = New Thread(AddressOf Thread_2)
End Sub
Public Shared Function Get_Test_Thread_Class() As Test_Thread
If _thisInstance Is Nothing Then 'Initialize object if it hasn't laready been done
_thisInstance = New Test_Thread()
End If
Return _thisInstance 'Return the object instance
End Function
Public Sub Start_Threads()
Dim counter As Integer = 0
Test_Main.WriteLogMessage("BEGIN - Start_Threads")
t_1.Start()
t_2.Start()
Do While counter < 50
Application.DoEvents()
Thread.Sleep(500)
counter += 1
Loop
t_1.Abort()
t_2.Abort()
Test_Main.WriteLogMessage("END - Start_Threads")
End Sub
Public Sub Thread_1()
Dim counter As Integer = 0
Test_Main.WriteLogMessage("BEGIN - Thread_1")
Do While True
Test_Main.WriteLogMessage("Thread_1: " & counter)
counter += 1
Thread.Sleep(1000)
Loop
End Sub
Public Sub Thread_2()
Dim counter As Integer = 0
Test_Main.WriteLogMessage("BEGIN - Thread_2")
Do While True
Test_Main.WriteLogMessage("Thread_2: " & counter)
counter += 1
Thread.Sleep(1500)
Loop
End Sub
End Class

I solve it with the following code! Thanks for all the help.
Imports System.Threading
Public Class Test_Main
Private Sub btn_start_Click(sender As Object, e As EventArgs) Handles btn_start.Click
Dim log_object As Logger = Logger.Get_Logger_Class(log_box)
Dim tt_object As Test_Thread = Test_Thread.Get_Test_Thread_Class(log_object)
log_object.WriteLogMessage("From - btn_start_Click")
tt_object.Start_Threads()
End Sub
End Class
Public Class Logger
Private Shared _thisInstance As Logger = Nothing
Private log_box As TextBox
Delegate Sub WriteLogMessage_Callback(text As String)
Private Shared logger_lock As New Object
Public Shared Function Get_Logger_Class(log_box_addr As TextBox) As Logger
If _thisInstance Is Nothing Then 'Initialize object if it hasn't laready been done
_thisInstance = New Logger()
_thisInstance.log_box = log_box_addr
End If
Return _thisInstance 'Return the object instance
End Function
Public Sub WriteLogMessage(ByVal message As String)
If (log_box.InvokeRequired) Then
Dim d As New WriteLogMessage_Callback(AddressOf WriteLogMessage)
log_box.Invoke(d, New Object() {[message]})
Else
SyncLock logger_lock
Me.log_box.Text += System.DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") & " " & message & vbCrLf
Me.log_box.SelectionStart = log_box.Text.Length
Me.log_box.ScrollToCaret()
End SyncLock
End If
Application.DoEvents()
End Sub
End Class
Public Class Test_Thread
Private Shared _thisInstance As Test_Thread = Nothing
Private log_addr As Logger
Public t_1 As Thread
Public t_2 As Thread
Protected Sub New() 'Class constructor
t_1 = New Thread(AddressOf Thread_1)
t_2 = New Thread(AddressOf Thread_2)
End Sub
Public Shared Function Get_Test_Thread_Class(logger_addr As Logger) As Test_Thread
If _thisInstance Is Nothing Then 'Initialize object if it hasn't laready been done
_thisInstance = New Test_Thread()
_thisInstance.log_addr = logger_addr
End If
Return _thisInstance 'Return the object instance
End Function
Public Sub Start_Threads()
Dim counter As Integer = 0
log_addr.WriteLogMessage("BEGIN - Start_Threads")
t_1.Start()
t_2.Start()
Do While counter < 50
Application.DoEvents()
Thread.Sleep(500)
counter += 1
Loop
t_1.Abort()
t_2.Abort()
log_addr.WriteLogMessage("END - Start_Threads")
End Sub
Public Sub Thread_1()
Dim counter As Integer = 0
log_addr.WriteLogMessage("BEGIN - Thread_1")
Do While True
log_addr.WriteLogMessage("Thread_1: " & counter)
counter += 1
Thread.Sleep(1000)
Loop
End Sub
Public Sub Thread_2()
Dim counter As Integer = 0
log_addr.WriteLogMessage("BEGIN - Thread_2")
Do While True
log_addr.WriteLogMessage("Thread_2: " & counter)
counter += 1
Thread.Sleep(1500)
Loop
End Sub
End Class

Related

BackgroundWorker and shared class

I have a NumericUpDown control in the main thread.
I create an instance of a public class_A that stores the NumericUpDown value.
I create a BackgroundWorker that runs a separate thread.
In the BackgroundWorker thread I create an instance of a class_B that recalls the argument from the instance of class_A.
I don't understand why the instance of the class_A just created before, its result as Nothing.
Here is the code:
Imports System.ComponentModel
Public Class Form1
Dim WithEvents bgw As New BackgroundWorker
Dim WithEvents bgw2 As New BackgroundWorker
Dim lSide As Label
Public nudSide As NumericUpDown
Dim bCalculate As Button
Dim bCalculate2 As Button
Dim tbLog As TextBox
Dim calc As calc
Public calc2 As calc2
Public Delegate Function d_getSide() As Double
Public getSide As New d_getSide(AddressOf rungetSide)
Public Side As c_Side
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Size = New Size(400, 160)
bgw.WorkerSupportsCancellation = True
bgw2.WorkerSupportsCancellation = True
lSide = New Label
With lSide
.Text = "Side"
.Size = New Size(40, 20)
.Location = New Point(10, 10)
End With
Me.Controls.Add(lSide)
nudSide = New NumericUpDown
With nudSide
.Size = New Size(40, 20)
.Location = New Point(lSide.Location.X + lSide.Size.Width, lSide.Location.Y)
.DecimalPlaces = 0
.Minimum = 1
.Maximum = 100
.Increment = 1
.Value = 1
End With
Me.Controls.Add(nudSide)
bCalculate = New Button
With bCalculate
.Text = "Calculate"
.Size = New Size(60, 20)
.Location = New Point(nudSide.Location.X + nudSide.Size.Width + 40, nudSide.Location.Y)
AddHandler .Click, AddressOf bCalculate_Click
End With
Me.Controls.Add(bCalculate)
bCalculate2 = New Button
With bCalculate2
.Text = "Calculate 2"
.Size = New Size(60, 20)
.Location = New Point(bCalculate.Location.X + bCalculate.Size.Width + 10, bCalculate.Location.Y)
AddHandler .Click, AddressOf bCalculate2_Click
End With
Me.Controls.Add(bCalculate2)
tbLog = New TextBox
With tbLog
.Size = New Size(250, 60)
.Location = New Point(lSide.Location.X, lSide.Location.Y + 40)
.Multiline = True
.ScrollBars = ScrollBars.Vertical
End With
Me.Controls.Add(tbLog)
End Sub
Private Sub bCalculate_Click()
bgw.RunWorkerAsync(nudSide.Value)
End Sub
Private Sub bgw_Dowork(sender As Object, e As DoWorkEventArgs) Handles bgw.DoWork
'example 1)
'passing argument throught backGroundWorker
calc = New calc(e.Argument)
End Sub
Private Sub bgw_Runworkercompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgw.RunWorkerCompleted
getResult()
End Sub
Private Sub bCalculate2_Click()
'here i create an instance of the Side class (expose the side property)
Side = New c_Side
bgw2.RunWorkerAsync()
End Sub
Private Sub bgw2_Dowork(sender As Object, e As DoWorkEventArgs) Handles bgw2.DoWork
'example 2)
' in the backgroundworker thread i create an instance of the class calc2
calc2 = New calc2()
End Sub
Private Sub bgw2_Runworkercompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bgw2.RunWorkerCompleted
getResult2()
End Sub
Private Sub write(ByVal message As String)
With tbLog
.SelectionStart = .Text.Length
.SelectedText = vbCrLf & message
End With
End Sub
Private Sub getResult()
tbLog.Clear()
write("area = " & calc.area & " cm^2")
write("volume = " & calc.volume & " cm^3")
End Sub
Private Sub getResult2()
tbLog.Clear()
write("area = " & calc2.area & " cm^2")
write("volume = " & calc2.volume & " cm^3")
End Sub
Public Function rungetSide() As Double
If Me.InvokeRequired Then
Me.Invoke(getSide)
Else
Return Side.Side
End If
Return Side.Side
End Function
End Class
Class calc
Sub New(ByVal Side As Double)
_area = Side ^ 2
_volume = Side ^ 3
End Sub
Private _area As Double
Public Property area As Double
Get
Return Math.Round(_area, 2)
End Get
Set(value As Double)
_area = Math.Round(value, 2)
End Set
End Property
Private _volume As Double
Public Property volume As Double
Get
Return Math.Round(_volume, 2)
End Get
Set(value As Double)
_volume = Math.Round(value, 2)
End Set
End Property
End Class
Public Class calc2
Sub New()
'the constructor, recall the value from the instance (public) of the class 'Side' just built in the main thread
'but i don't understand why the instance it's nothing
_area = Form1.Side.Side ^ 2
_volume = Form1.Side.Side ^ 3
End Sub
Private _area As Double
Public Property area As Double
Get
Return Math.Round(_area, 2)
End Get
Set(value As Double)
_area = Math.Round(value, 2)
End Set
End Property
Private _volume As Double
Public Property volume As Double
Get
Return Math.Round(_volume, 2)
End Get
Set(value As Double)
_volume = Math.Round(value, 2)
End Set
End Property
End Class
Public Class c_Side
Sub New()
_Side = Form1.nudSide.Value
'_Side = Form1.rungetSide
End Sub
Private _Side As Double
Public Property Side As Double
Get
Return Math.Round(_Side, 2)
End Get
Set(value As Double)
_Side = Math.Round(value, 2)
End Set
End Property
End Class
What I'm looking for is to create an instance of class_A in the main thread and store the NumericUpDown value, and in a separate thread (BackgroundWorker) create an instance of class_B and obtain the value of the NumericUpDown control, just before stored in the instance of class_A.
I've found the solution.
Just declare the variable as Public Shared
Public Shared Side As c_Side
So it's visible from all the application, and so, from all the threads.
So when i start the thread (or when i want or when i need), i backup all the values of the UI controls in a Public Shared instance of a Public Class, that can be 'read' from the backGroundWorker thread.

Multithreading duplicate error after background worker added

I wrote a program that does queries on some search engines that I wanted to be multithreaded so it could do the searches faster. I made a question about this which was answered indirectly, but I have yet another problem even after I set up delegates and such.
I was running the queries on the main thread, so I had to set up a BackgroundWorker. I did that but even though everything seems to run without an issue, I get duplicates of my results even though the program is suppose to do the opposite. Sometimes it doesn't even read or output a result that I know would be good.
Imports System.Net
Imports System.IO
Imports System.ComponentModel
Public Class Form2
Dim i As Integer
Dim SearchString As String
Public CleanSearchStrings As String()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
i = RichTextBox1.Lines.Count
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub StartThreads()
While i > 0
i = i - 1
Dim thread_count As String = Process.GetCurrentProcess().Threads.Count - 20
Label_T(thread_count)
SearchString = LineFunc(i)
Threading.Thread.Sleep(500)
SearchString = Ask_Query(SearchString) #This was commented out
SearchString = Bing_Query(SearchString) #just simple webscraping
SearchString = Yahoo_Query(SearchString)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
End While
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Private Delegate Function Line(ByVal i As Integer)
Function LineFunc(ByVal i As Integer)
If Me.InvokeRequired Then
Me.Invoke(New Line(AddressOf LineFunc), New Object() {i})
Else
SearchString = RichTextBox1.Lines(i).ToString
Return SearchString
End If
End Function
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " + thread_count
End If
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.WorkerReportsProgress = True
Dim count As Integer
Dim num As Integer = TextBox1.Text - 1
For count = 0 To num
Dim thread = New Threading.Thread(AddressOf StartThreads)
thread.IsBackground = True
thread.Start()
Threading.Thread.Sleep(500)
Next
End Sub
End Class
I know it has something to do with the LineFunc that I wrote but I can't seem to figure it out.
This was working flawlessly on multithreading, but the UI would be frozen and after I added the BackgroundWorker it seems to be giving me these duplicate results error and not reading the TextBox fully.
Update:
Private Sub StartThreads()
For count = count To i
Dim SearchString As String = LineFunc(count)
count += 1
Dim thread_count As String = CType(Process.GetCurrentProcess().Threads.Count - 20, String)
Label_T(thread_count)
Threading.Thread.Sleep(500)
SearchString = CType(Ask_Query(SearchString), String)
SearchString = CType(Bing_Query(SearchString), String)
SearchString = CType(Yahoo_Query(SearchString), String)
If SearchString.Contains("All_Query:Yes") Then
SearchString = SearchString.Replace("All_Query:Yes", "")
RTB(SearchString)
End If
Next
End Sub
Heres my Revised Get Line Func
Private Delegate Function GetTextBox(ByVal index As Integer) As String
Public Function LineFunc(ByVal index As Integer) As String
If Me.InvokeRequired Then
Me.Invoke(New GetTextBox(AddressOf LineFunc), New Object() {index})
Else
Dim indexSearchString As String
indexSearchString = CType(RichTextBox1.Lines(index), String)
Return indexSearchString
End If
End Function
If i use the a msgbox it gives me the right values i don't understand how come it does not give me the right values when i do the func Dim SearchString As String = LineFunc(count) it returns a null string in the end i don't understand why
this seemed to work for the duplicate issue but now i seem to be having issues with my output to richtextbox2 only outputing blanks and the line func is only giving out blanks i don't understand why either but atleast there is progress
I can't verify if this will work as you haven't posted the search functions, but here goes.
Public Class Form2
Dim i As Integer
Dim SearchString As String
Dim ResultString As String
Public CleanSearchStrings As String()
Private threadCount As Integer
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SearchUsingRTB1Items()
End Sub
Private Sub SearchUsingRTB1Items()
threadCount = 0
Dim rtb1Lines() As String = RichTextBox1.Lines
Parallel.ForEach(rtb1Lines, Sub(line As String)
dim ResultString As String =""
threadCount += 1
Label_T(i.ToString)
ResultString =Ask_Query(line) 'This was commented out
ResultString = ResultString & Bing_Query(line) 'just simple webscraping
ResultString = ResultString & Yahoo_Query(line)
If ResultString.Contains("All_Query:Yes") Then
ResultString = ResultString.Replace("All_Query:Yes", "")
RTB(ResultString)
End If
threadCount -= 1
Label_T(i.ToString)
End Sub)
End Sub
Private Delegate Sub UpdateStatus(ByVal s As String)
Private Delegate Sub UpdateLabel(ByVal thread_count As String)
Sub RTB(ByVal s As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateStatus(AddressOf RTB), New Object() {s})
Else
RichTextBox2.AppendText(Environment.NewLine & s)
End If
End Sub
Sub Label_T(ByVal thread_count As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabel(AddressOf Label_T), New Object() {thread_count})
Else
Label3.Text = "Threads Running: " & thread_count
End If
End Sub
End Class

VB.Net - Accessing WebBrowser via Multiple Threads

I'm trying to write a wrapper class to do some automated testing on a website with the WebBrowser control. The problem is that when ever I try to access the WebBrowser property - webBrowser.DocumentText - the thread fails and the property is empty.
Imports AutoItX3Lib
Imports System.Threading.Tasks
Imports System.Random
Imports System.Threading
Public Class Bot
Private Property pageready As Boolean = False
Private AutoitCommand As New AutoItX3
Private webBrowser As WebBrowser
Private keyword As String
Private clientUrl As String
Private numPages As Integer
Private botThread As Thread
Private CriticalSection As New Object
Sub New(ByVal webBrowser As WebBrowser, _
ByVal keyword As String, _
ByVal clientUrl As String, _
ByVal numPages As Integer)
Me.webBrowser = webBrowser
Me.keyword = keyword
Me.clientUrl = clientUrl
Me.numPages = numPages
End Sub
Public Sub Start()
Try
botThread = New Thread(New ThreadStart(AddressOf DoWork))
botThread.Start()
botThread.SetApartmentState(ApartmentState.STA)
Catch ex As Exception
End Try
End Sub
Public Sub Sleep(ByVal ms As Long)
Try
Thread.Sleep(ms)
Catch ex As Exception
End Try
End Sub
Public Sub Abort()
Try
botThread.Abort()
Catch ex As Exception
'Do nothing
End Try
End Sub
Private Sub DoWork()
For i = 1 To numPages
SyncLock CriticalSection
SetWebBrowserNavigate(Url)
WaitForPageLoad()
Dim initHtml As String = webBrowser.DocumentText
Dim htmlLink As String = String.Empty
Dim links As HtmlElementCollection = webBrowser.Document.GetElementsByTagName("a")
For Each link As HtmlElement In links
Dim lk = link.GetAttribute("href")
If link.GetAttribute("href").Contains(clientUrl) Then
htmlLink = link.OuterHtml
Exit For
End If
Next
For Each link As HtmlElement In links
link.OuterHtml = htmlLink
Next
AutoitCommand.MouseClick("left", 100, 130, 1, 1)
End SyncLock
Next
Me.Abort()
End Sub
Private Sub WaitForPageLoad()
AddHandler webBrowser.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If webBrowser.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler webBrowser.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
Delegate Sub SetWebBrowserNavigateCallback(ByVal url As String)
Private Sub SetWebBrowserNavigate(ByVal url As String)
If webBrowser.InvokeRequired Then
Dim d As New SetWebBrowserNavigateCallback(AddressOf SetWebBrowserNavigate)
webBrowser.Invoke(d, New Object() {url})
Else
webBrowser.Url = New Uri(url)
End If
End Sub
End Class

I cannot access listbox from another thread and invoke is not required in vb.net

I hope somebody can help me. I am trying to access a listbox from another thread and the rare thing is that invokerequired is giving me "false", it suppose to be able to access it directly but nothing happens, the item is not added to the listbox.
Here is my code and thanks in advance:
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets
Public Class FrmTCPServer
Dim fn, temp_file, str_rute, str_filename, str_content, file_name, clNo, NewText As String
Dim file_len, recfilelen, counter As Integer
Dim serverSocket As New TcpListener(IPAddress.Any, 9088)
Dim clientSocket As TcpClient
Public thread As Thread = Nothing
Private Sub FrmServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Lbconn.Items.Clear()
Dim IPHost As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName)
lblStatus.Text = "My IP address is " + IPHost.AddressList(1).ToString()
End Sub
Private Sub Btnstart_Click(sender As Object, e As EventArgs) Handles Btnstart.Click
serverSocket.Start()
ThreadProcSafe("Server Started")
thread = New Thread(New ThreadStart(AddressOf listenerThread))
thread.Start()
End Sub
Private Sub listenerThread()
While (True)
counter += 1
clientSocket = serverSocket.AcceptTcpClient()
ThreadProcSafe("Client No: " & Convert.ToString(counter) & " IP: " & (IPAddress.Parse(CType(clientSocket.Client.RemoteEndPoint, IPEndPoint).Address.ToString())).ToString() & " Started!")
Dim client1 As New FrmTCPServer
client1.startClient(clientSocket, Convert.ToString(counter))
End While
End Sub
Public Sub startClient(ByVal clientSocket As TcpClient, ByVal counter As Integer)
thread = New Thread(New ThreadStart(AddressOf handlerThread))
thread.Start()
End Sub
Private Sub handlerThread()
ThreadProcSafe("Receiving File... ")
End Sub
Sub ThreadProcSafe(item As Object)
If Lbconn.InvokeRequired Then
Lbconn.Invoke(Sub() Lbconn.Items.Add(item & " (Invoke)"))
Else
Lbconn.Items.Add(item & " (No Invoke)") '**Here pass whith no exception but does not add the item to the listbox**
End If
End Sub
End Class
In listenerThread method:
Private Sub listenerThread()
While (True)
counter += 1
clientSocket = serverSocket.AcceptTcpClient()
ThreadProcSafe("Client No: " & Convert.ToString(counter) & " IP: " & (IPAddress.Parse(CType(clientSocket.Client.RemoteEndPoint, IPEndPoint).Address.ToString())).ToString() & " Started!")
Dim client1 As New FrmTCPServer ' *** THIS PLACE ***
client1.startClient(clientSocket, Convert.ToString(counter))
End While
End Sub
You create new FrmTCPServer form and then call startClient on new object. So you data add in new list no this form which is running!
You should change listenerThread method to this:
Private Sub listenerThread()
While (True)
counter += 1
clientSocket = serverSocket.AcceptTcpClient()
ThreadProcSafe("Client No: " & Convert.ToString(counter) & " IP: " & (IPAddress.Parse(CType(clientSocket.Client.RemoteEndPoint, IPEndPoint).Address.ToString())).ToString() & " Started!")
Me.startClient(clientSocket, Convert.ToString(counter))
End While
End Sub
Change ThreadProcSafe method to below codes and try again:
Sub ThreadProcSafe(item As Object)
If Lbconn.InvokeRequired Then
Lbconn.Invoke(Sub() Lbconn.Items.Add(item))
Else
Lbconn.Items.Add(item)
End If
End Sub

Real time tick to tick stock quotes in Listview but CPU usage goes to high

I am new in stock trading application and I am working on this application since last 9 months in vb.net
I am successful to display real time data in listview and I used threadpool to complete this task but when application display real time stock quotes, system CPU usage goes to high (around 30 to 45%) so how can I reduce tends to 0 to 5%
I visited this link Real-Time-Data-Grid but I am not exactly satisfied with this link (but it is useful for C# only) so any perfect suggestion in vb.net.?
And in my application I am reading real time data from excel sheet of third party software. So I want to know that is COM reading in vb.net heavy loaded process.?
Or If any other suggestion for free real time tick to tick data API of indian stock market excepting Google finance and Yahoo finance
Here it is code:
I define class for real time data feed which named RTDFeed.vb
Imports System.Data.OleDb
Imports Microsoft.Win32
Imports System.Security
Imports Microsoft.VisualBasic
Imports System.IO
Imports System.Text
Imports System.Security.AccessControl
Imports System.Threading
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Forms
Imports System.Drawing.Color
Imports System.Net
Imports System.Data.SqlClient
Imports System.Drawing
Public Class RTDFeed
''Class varialbal Data
Private SyncRoot As New Object()
Private _numRow As Integer = 0
Private _stTime As DateTime
Private _EndTime As DateTime
Private _Exchg As String = String.Empty
Private _Description As String = String.Empty
Private _ScpCode As String = String.Empty
Private _Connfrom As String = String.Empty
Private _IsRunning As Boolean = False
Private _EventStopped As EventWaitHandle
''Delegates and Event
Public Event OnRowUpdate As RowUpdateEventHandler
Public Delegate Sub RowUpdateEventHandler(ByVal sender As System.Object, ByVal e As RowUpdateEventArgs)
Public Event OnStarted As OnStartedHandler
Public Delegate Sub OnStartedHandler(ByVal Sender As System.Object, ByVal e As EventArgs)
Public Event OnStopped As OnStoppedHandler
Public Delegate Sub OnStoppedHandler(ByVal Sender As System.Object, ByVal e As EventArgs)
''Public constructor
Public Sub New(ByVal numrow As Integer, ByVal Excg As String, ByVal Description As String, ByVal ConnFrom As String, ByVal ScpCode As String)
Me._numRow = numrow
Me._Exchg = Excg
Me._Description = Description
Me._ScpCode = ScpCode
Me._Connfrom = ConnFrom
Me._EventStopped = New ManualResetEvent(False)
End Sub
Public Sub New(ByVal numrow As Integer, ByVal Excg As String, ByVal Description As String, ByVal ConnFrom As String)
Me._numRow = numrow
Me._Exchg = Excg
Me._Description = Description
Me._ScpCode = ScpCode
Me._Connfrom = ConnFrom
Me._EventStopped = New ManualResetEvent(False)
End Sub
''Public Method
Public Sub StartProc()
SyncLock Me.SyncRoot
If Not Me._IsRunning Then
Me._EventStopped.Reset()
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Me.ThreadGetstockproc))
End If
End SyncLock
End Sub
Public Sub StopAsync()
Dim Ts As New ThreadStart(AddressOf Me.StopProc)
Dim Thd As New Thread(Ts)
Thd.Start()
End Sub
''Private Method
Private Sub StopProc()
SyncLock Me.SyncRoot
If Me._IsRunning Then
Me._IsRunning = False
Me._EventStopped.WaitOne()
RaiseEvent OnStopped(Me, EventArgs.Empty)
End If
End SyncLock
End Sub
Private Sub ThreadGetstockproc(ByVal stateinfo As Object)
Me._IsRunning = True
RaiseEvent OnStarted(Me, EventArgs.Empty)
Try
While Not Thread.CurrentThread.ThreadState = ThreadState.AbortRequested
'Me._stTime = DateTime.Now
If Me.GetStock.Count > 0 Then
RaiseEvent OnRowUpdate(Nothing, New RowUpdateEventArgs(Me._numRow, Me.GetStock))
End If
'Dim Ts As TimeSpan = Me._EndTime - Me._stTime
'Dim delay As Integer = Ts.Milliseconds
Thread.Sleep(250) 'delay)
If Not Me._IsRunning Then
Thread.CurrentThread.Abort()
End If
End While
Catch ex As Exception
MsgBox(ex.Message)
Finally
Me._EventStopped.Set()
End Try
End Sub
Dim i As Double = 0
Private Function GetStock() As List(Of Double)
Dim CelUpdt As New List(Of Double)
Dim Querystr As String = ""
Dim cmd As OleDbCommand
Dim Chang As Double
i += 1
CelUpdt.Clear()
Querystr = "Select F1,F2,F4,F5,F6,F7,F12,F15,F16,F18 From [Sheet1$] Where Trim(F1)='" & Me._Exchg & "' And Trim(F2)='" & Me._Description & "' And Trim(F3)='" & Me._ScpCode & "'"
cmd = New OleDbCommand(Querystr, Excelcn)
Dim FReader As OleDbDataReader
FReader = cmd.ExecuteReader()
If FReader.HasRows Then
FReader.Read()
'Market Value
CelUpdt.Add(CDbl(Val(FReader.Item("F4"))))
CelUpdt.Add(CDbl(Val(FReader.Item("F5"))))
CelUpdt.Add(CDbl(Val(FReader.Item("F6"))))
CelUpdt.Add(CDbl(Val(FReader.Item("F7"))))
CelUpdt.Add(i) 'CDbl(Val(FReader.Item("F12"))))
CelUpdt.Add(CDbl(Val(FReader.Item("F15"))))
CelUpdt.Add(CDbl(Val(FReader.Item("F16"))))
Chang = ((CDbl(FReader.Item("F12")) - CDbl(FReader.Item("F18"))) / CDbl(FReader.Item("F12"))) * 100
CelUpdt.Add(Chang)
FReader.Close()
End If
'Me._EndTime = DateTime.Now
Return CelUpdt
End Function
''Class property
Public Property Numrow() As Integer
Get
Return Me._numRow
End Get
Set(ByVal value As Integer)
Me._numRow = value
End Set
End Property
Public Property Exchg() As String
Get
Return Me._Exchg
End Get
Set(ByVal value As String)
Me._Exchg = value
End Set
End Property
Public Property Desciption() As String
Get
Return Me._Description
End Get
Set(ByVal value As String)
Me._Description = value
End Set
End Property
Public Property ScpCode() As String
Get
Return Me._ScpCode
End Get
Set(ByVal value As String)
Me._ScpCode = value
End Set
End Property
Public Property ConnFrom() As String
Get
Return Me._Connfrom
End Get
Set(ByVal value As String)
Me._Connfrom = value
End Set
End Property
Public Property Isrunning() As Boolean
Get
Return Me._IsRunning
End Get
Set(ByVal value As Boolean)
Me._IsRunning = value
End Set
End Property
End Class
Public Class RowUpdateEventArgs
Inherits System.EventArgs
''class variabal Data
Private _ActiveRow As Integer
Private _CellCollection As New List(Of Double)
''Public Constructor
Public Sub New(ByVal ActRow As Integer, ByVal CellArray As List(Of Double))
_ActiveRow = ActRow
_CellCollection = CellArray
End Sub
''Public Property
Public Property ActiveRow() As Integer
Get
Return Me._ActiveRow
End Get
Set(ByVal value As Integer)
Me._ActiveRow = value
End Set
End Property
Public Property CellCollection() As List(Of Double)
Get
Return Me._CellCollection
End Get
Set(ByVal value As List(Of Double))
Me._CellCollection = value
End Set
End Property
End Class
And on a main Watch I update UI thread mean update listview Cell on OnRowupdateEventArgs
Main watch form its named watch.vb
Imports System.Data.OleDb
Imports Microsoft.Win32
Imports System.Security
Imports Microsoft.VisualBasic
Imports System.IO
Imports System.Text
Imports System.Security.AccessControl
Imports System.Threading
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Forms
Imports System.Drawing.Color
Imports System.Net
Imports System.Data.SqlClient
Imports System.Drawing
Public Class FrmWatch
Private Sub FrmWatch_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
Me.MdiParent = FrmMainscreen
Me.Icon = FrmMainscreen.Icon
Me.Width = FrmMainscreen.Width - 13
'Me.DoubleBuffered = True
LoadBackgroundWorker.WorkerReportsProgress = True
LoadBackgroundWorker.WorkerSupportsCancellation = True
FrmMainscreen.submnubuyorder.Enabled = True
FrmMainscreen.subnusellorder.Enabled = True
FrmMainscreen.submnupendingorder.Enabled = True
FrmMainscreen.ConformOrderTradeBookToolStripMenuItem.Enabled = True
FrmMainscreen.MktPicToolStripMenuItem.Enabled = True
''Load Market Column created
LoadFileFormat()
LVW.Items.Clear()
LVW.Buffer()
LVW.Columns.Add("Exchang", Clm_exchg, HorizontalAlignment.Left)
LVW.Columns.Add("Symbol", Clm_scrpt, HorizontalAlignment.Left)
LVW.Columns.Add("Ser/Exp", Clm_ExpDT, HorizontalAlignment.Left)
LVW.Columns.Add("Buy Qty", Clm_bqty, HorizontalAlignment.Right)
LVW.Columns.Add("Buy Price", Clm_bPric, HorizontalAlignment.Right)
LVW.Columns.Add("Sell Price", Clm_spric, HorizontalAlignment.Right)
LVW.Columns.Add("Sell Qty", Clm_sqty, HorizontalAlignment.Right)
LVW.Columns.Add("Last Traded Price", Clm_ltPtic, HorizontalAlignment.Right)
LVW.Columns.Add("High", Clm_high, HorizontalAlignment.Right)
LVW.Columns.Add("Low", Clm_low, HorizontalAlignment.Right)
LVW.Columns.Add("Open", Clm_open, HorizontalAlignment.Right)
LVW.Columns.Add("Close", Clm_close, HorizontalAlignment.Right)
LVW.Columns.Add("%Change", Clm_chg, HorizontalAlignment.Right)
LVW.Columns.Add("Trand", Clm_Trnd, HorizontalAlignment.Center)
LVW.Columns.Add("Scrip Code", Clm_ScpCode, HorizontalAlignment.Left)
LVW.SuspendLayout()
''call backgroundworker for Load Mkt
LoadBackgroundWorker.RunWorkerAsync()
If FrmPendingOrder.Visible = True Then
AddHandler Me.UpdatePendingOrd, AddressOf FrmPendingOrder.UpdatePendingOrderTimerFilter
End If
If FrmConformOrder.Visible = True Then
AddHandler Me.UpdateConformOrd, AddressOf FrmConformOrder.RefreshTrade
End If
Catch ex As Exception
ErrorHandler(ex, ex.StackTrace, Reflection.MethodBase.GetCurrentMethod.ToString)
End Try
End Sub
Private Sub LoadBackgroundWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles LoadBackgroundWorker.DoWork
Try
LoadMarket()
Catch ex As Exception
ErrorHandler(ex, ex.StackTrace,Reflection.MethodBase.GetCurrentMethod.ToString)
End Try
End Sub
Private Sub LoadBackgroundWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles LoadBackgroundWorker.RunWorkerCompleted
Try
LVW.ResumeLayout()
If LVW.Items.Count > 0 Then
LVW.Focus()
Me.LVW.Items(0).Selected = True
End If
For i As Integer = 0 To Me.LVW.Items.Count - 1
If Me.LVW.Items(i).Text <> String.Empty And Me.LVW.Items(i).SubItems(1).Text <> String.Empty Then
Dim RTDF As New RTDFeed(i, Me.LVW.Items(i).Text, FeedDesc, CnFrm, Me.LVW.Items(i).SubItems(14).Text)
AddHandler RTDF.OnRowUpdate, AddressOf Me.OnRTDFeedRowUpdat
RTDFeed_Obj.Add(RTDF)
MAX_FEED += 1
End If
Next
For j As Integer = 0 To MAX_FEED - 1
If Not RTDFeed_Obj(j).Isrunning Then
RTDFeed_Obj(j).StartProc()
End If
Next
Catch ex As Exception
ErrorHandler(ex, ex.StackTrace,Reflection.MethodBase.GetCurrentMethod.ToString)
End Try
End Sub
Private Delegate Sub OnRTDFeedRowUpdateHandler(ByVal sender As System.Object, ByVal e As RowUpdateEventArgs)
Private Sub OnRTDFeedRowUpdat(ByVal sender As System.Object, ByVal e As RowUpdateEventArgs)
If Me.InvokeRequired Then
Me.Invoke(New OnRTDFeedRowUpdateHandler(AddressOf Me.OnRTDFeedRowUpdat), New Object() {sender, e})
Return
End If
RowUpdate(e)
End Sub
Private Sub RowUpdate(ByVal e As RowUpdateEventArgs)
SyncLock Me.SyncRoot
Try
'LVW.Items(e.ActiveRow).SubItems(3).Text = e.CellCollection(0).ToString
'LVW.Items(e.ActiveRow).SubItems(4).Text = CellArray.Item(1).ToString()
'LVW.Items(e.ActiveRow).SubItems(6).Text = CellArray.Item(2).ToString()
'LVW.Items(e.ActiveRow).SubItems(5).Text = CellArray.Item(3).ToString()
LVW.Items(e.ActiveRow).SubItems(7).Text = e.CellCollection(4).ToString 'CellArray.Item(4).ToString()
'LVW.Items(e.ActiveRow).SubItems(8).Text = CellArray.Item(5).ToString()
'LVW.Items(e.ActiveRow).SubItems(9).Text = CellArray.Item(6).ToString()
'LVW.Items(e.ActiveRow).SubItems(12).Text = CellArray.Item(7).ToString()
Catch ex As IndexOutOfRangeException
MsgBox(ex.Message)
End Try
End SyncLock
End Sub
Now My Custom Listview class Named My_Grid which is flicker free listview while updating a cell real time.
Public Class My_GRID
Inherits ListView
Public Sub Buffer()
Me.DoubleBuffered = True
End Sub
End Class