donjkurian

Member
Joined
Oct 6, 2009
Messages
9
Programming Experience
1-3
Hi,
Please help me introduce multithreading into my code so that the UI is more responsive.

Here is what i've done:
I have a program which searches the entire registry for a keyword and adds the matching keys/values into a listview. The UI becomes non responsive if i attempt to move the form or click on any of the other buttons in the form, while the search is going on.

Can you guys tell me how i can restructure my code so that the long searching operation is in a different thread and all the UI stuffs remain in the UI thread itself.

I have googled enough and got so many links, but ive not been able to implement it so far with my code. It confuses me a lot.

Im including my code below:

Imports Microsoft.Win32
Public Class Form1
Dim count As Integer

Sub FullRegSearch(ByVal root As RegistryKey, ByVal searchKey As String)
Dim val As String = Nothing
Try
For Each keyname As String In root.GetSubKeyNames
TextBox2.Refresh()
TextBox2.Text = "Searching :" + root.ToString
TextBox3.Text = count.ToString + " items found"
Try
Using key As RegistryKey = root.OpenSubKey(keyname)
Try
If keyname.Contains(searchKey) Then
ListView1.Refresh()
ListView1.Items.Add("Key :" + key.Name)
ListView1.Refresh()
count = count + 1
End If
Catch ex As Exception
End Try
Try
For Each valuename As String In key.GetValueNames
val = (key.GetValue(valuename))
Try
If val.ToString.Contains(searchKey) Then
ListView1.Refresh()
ListView1.Items.Add("Key :" + key.Name)
ListView1.Refresh()
ListView1.Items.Add("Value :" + val)
ListView1.Refresh()
count = count + 2
End If
Catch ex As Exception
End Try
Next
Catch ex As Exception
End Try
FullRegSearch(key, searchKey)
End Using
Catch ex As Exception
End Try
TextBox3.Refresh()
Next
Catch ex As Exception
End Try
End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

ListView1.Items.Clear()

'#check if search keyword is empty in textbox1
If TextBox1.Text = "" Then
MsgBox("Please enter the search keyword", MsgBoxStyle.Information)
Exit Sub
End If

'#If checkbox4 is checked (HKEY_CLASSES_ROOT)
If CheckBox4.Checked = True Then
FullRegSearch(Registry.ClassesRoot, TextBox1.Text)
End If

'#If checkbox5 is checked (HKEY_CURRENT_USER)
If CheckBox5.Checked = True Then
FullRegSearch(Registry.CurrentUser, TextBox1.Text)
End If

'#If checkbox6 is checked (HKEY_LOCAL_MACHINE)
If CheckBox6.Checked = True Then
FullRegSearch(Registry.LocalMachine, TextBox1.Text)
End If

'#If checkbox7 is checked (HKEY_USERS)
If CheckBox7.Checked = True Then
FullRegSearch(Registry.Users, TextBox1.Text)
End If

'#If checkbox8 is checked (HKEY_CURRENT_CONFIG)
If CheckBox8.Checked = True Then
FullRegSearch(Registry.CurrentConfig, TextBox1.Text)
End If


'After search is complete

If ListView1.Items.Count = 0 Then
MsgBox("Search completed ! No matching keys/values found in registry.", MsgBoxStyle.Information, "PristineReg")
count = Nothing
TextBox2.Text = ""
TextBox3.Text = ""
Exit Sub
End If

MsgBox("Search completed !", MsgBoxStyle.Information, "PristineReg")
count = Nothing

End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.MaximizeBox = False
ListView1.CheckBoxes = True
CheckBox4.Checked = True
CheckBox5.Checked = True
CheckBox6.Checked = True
CheckBox7.Checked = True
CheckBox8.Checked = True

End Sub
End Class


Thanks in advance,
donjkurian
 
Thanks,
I had googled myself and got a lot of similar links which explains multi threading. But i already said, they confuse me a lot and i was unable to implement them in my code since im not very experienced in VB.Net.
 
Put the code you want in a new thread in a new sub, lets call it Sub1.
Put this code in where the code you put into a new thread was previously:
VB.NET:
        Dim t As System.Threading.Thread
        t = New System.Threading.Thread(AddressOf Me.Sub1)
        t.Start()
If you are editing any controls from the main thread, then put this in Sub1:
VB.NET:
        Control.CheckForIllegalCrossThreadCalls = False
 
Hi untamed,
Thank you. My confusion is that when you say,
t = New System.Threading.Thread(AddressOf Me.Sub1), my sub FullRegSearch(ByVal root As RegistryKey, ByVal searchKey As String) that you see in the code has two parameters to be passed. root and searchkey. Im not able to handle this in the part that comes after 'AddressOf' in the line, t = New System.Threading.Thread(AddressOf Me.Sub1). It is giving me some overload resolution failure or a similar kind of error. I hope you got my point.
 
Thank you.
Finally I have made some progress and have implemented threading and my Application is very responsive now. I'm still working on it and will post the new code shortly. currently trying to overcome the problem with restarting threads. I'm aborting the threads when user click on the stop button. but again when i click on the search button, there is an exception which says terminated threads cannot be restarted. Any suggestions are welcome

donjkurian
 
Once the thread has been terminated, it cannot be restarted by calling the Start() function.

That is why you are getting the error.

Perhaps try pausing/blocking the thread by calling Thread.Sleep or Thread.Suspend.
 
Hi,
Thank You. Inorder to make my thread restart, i put the variable in the button click event so that everytime the button is clicked a new instance of the thread is started.

sthread = New System.Threading.Thread(AddressOf searchallhives)
If sthread.ThreadState And ThreadState.Unstarted <> 0 Then
sthread.Start()
End If


As of now , all my problems are solved. I'm succesfully able to implement threading in my project so far. I have a small module to be completed. ie the deletion of the selected registry keys after the search is completed. I'm working on that now.

Below is the complete code which searches the entire registry for a keyword from a textbox

Imports Microsoft.Win32
Imports System.Threading

Public Class Form1

Dim count As Integer

Dim sthread As Thread
Sub searchallhives()

Control.CheckForIllegalCrossThreadCalls = False

Button7.Enabled = True
ListView1.Refresh()
ListView1.Items.Clear()
ListView1.Refresh()

If CheckBox4.Checked = True Then
SearchSubKeys(Registry.ClassesRoot, TextBox1.Text)
End If
If CheckBox5.Checked = True Then
SearchSubKeys(Registry.CurrentUser, TextBox1.Text)
End If
If CheckBox6.Checked = True Then
SearchSubKeys(Registry.LocalMachine, TextBox1.Text)
End If
If CheckBox7.Checked = True Then
SearchSubKeys(Registry.Users, TextBox1.Text)
End If
If CheckBox8.Checked = True Then
SearchSubKeys(Registry.CurrentConfig, TextBox1.Text)
End If

MsgBox("Search Completed !", MsgBoxStyle.Information, "PristineReg")
TextBox2.Text = "Search completed !"
Button1.Enabled = True
Button7.Enabled = False
count = 0

End Sub

Sub SearchSubKeys(ByVal root As RegistryKey, ByVal searchKey As String)
Dim sAns As String = Nothing
Try
For Each keyname As String In root.GetSubKeyNames
TextBox2.Refresh()
TextBox2.Text = "Searching :" + root.ToString
TextBox3.Text = count.ToString + " items found"
Try
Using key As RegistryKey = root.OpenSubKey(keyname)
Try
If key.Name.Contains(searchKey) Then
ListView1.Refresh()
ListView1.Items.Add("Key :" + key.Name)
ListView1.Refresh()
count = count + 1
End If
Catch ex As Exception
End Try
Try
For Each valuename As String In key.GetValueNames
sAns = (key.GetValue(valuename))
Try
If sAns.ToString.Contains(searchKey) Then
ListView1.Items.Add("Key Name :" + key.Name)
ListView1.Refresh()
ListView1.Items.Add("Value Data :" + sAns)
count = count + 2
End If
Catch ex As Exception
End Try
Next
Catch ex As Exception
End Try
SearchSubKeys(key, searchKey)
End Using
Catch ex As Exception
End Try
TextBox3.Refresh()
Next
Catch ex As Exception
End Try
End Sub

'######### HANDLING SEARCH BUTTON CLICK ######### (Button1)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'#check if search keyword is empty in textbox1
If TextBox1.Text = "" Then
MsgBox("Please enter the search keyword", MsgBoxStyle.Information)
Exit Sub
End If

'#check if atleast one registry hive is selected for search
If CheckBox4.Checked = False And _
CheckBox5.Checked = False And _
CheckBox6.Checked = False And _
CheckBox7.Checked = False And _
CheckBox8.Checked = False Then
MsgBox("Please select atleast one registry hive", MsgBoxStyle.Information)
Exit Sub
End If

Button1.Enabled = False
Button7.Visible = True

sthread = New System.Threading.Thread(AddressOf searchallhives) 'If this statement is not on a button
'click event, then it will be impossible to restart the search thread. Hence do not miss this statement.
If sthread.ThreadState And ThreadState.Unstarted <> 0 Then
sthread.Start()
End If
End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Me.MaximizeBox = False
ListView1.CheckBoxes = True
CheckBox4.Checked = True
CheckBox5.Checked = True
CheckBox6.Checked = True
CheckBox7.Checked = True
CheckBox8.Checked = True

End Sub

'######### HANDLING STOP BUTTON CLICK ######### (Button7)
Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click

Button1.Enabled = True
Button7.Enabled = False
sthread.Abort()
MsgBox("Search Aborted!", MsgBoxStyle.Critical, "PristineReg")
TextBox2.Text = "Search Aborted !"
count = 0

End Sub
End Class


Cheers,
donjkurian
 
CheckForIllegalCrossThreadCalls is a debug feature, don't use it! "Cross-thread calls will always raise an exception when an application is started outside the debugger."

I invite you to review the attached project, I think you will have no problems understanding the code and learn a lot from it, even if it is more advanced than your current level. It is a rewrite of your code that has better separation of UI and the worker thread. It is using the BackgroundWorker component which is very easy to use for multithread background work when integrating UI. Matches is reported slightly different, IMO easier to read.
 

Attachments

  • vbnet35-RegSearchSample.zip
    17 KB · Views: 29
Hi JohnH,
I knew it wasn't the correct approach, but since it got rid of the headache of the moment, i thought of using it. I would definitely not stop here. In fact I've been waiting for something like what you provided. Im so glad that you gave me this project to dig. I hope i will definitely learn a lot from this.

Thank You,
donjkurian
 
CheckForIllegalCrossThreadCalls is a debug feature, don't use it! "Cross-thread calls will always raise an exception when an application is started outside the debugger."

I invite you to review the attached project, I think you will have no problems understanding the code and learn a lot from it, even if it is more advanced than your current level. It is a rewrite of your code that has better separation of UI and the worker thread. It is using the BackgroundWorker component which is very easy to use for multithread background work when integrating UI. Matches is reported slightly different, IMO easier to read.


John,

You are the man! I've been meaning to take the time to learn how to "correctly" write multi-threaded apps. for a while now and never took the time because of confusing snippets. That little project was a boon for me! It's so simple it's ridiculous! Thanks!
 
There can be a lot more to multi-threading than just using the BackgroundWorker, in relation to threading the sample only show basic usage of this component, but the sample project also show some other techniques that I thought could be helpful for donjkurian to see in relation to the earlier posted code. Glad to hear it is useful to others also! In many cases threading can be simple as that, but there exist several other threading tools in the .Net library that is not that difficult once you try them out.
 
Back
Top