Creating instances of forms inside a thread - vb.net

i am trying to create a new instance of a form if its not allready been created the only problem is is that the instance creation is inside a thread.
Private Sub doRead(ByVal ar As System.IAsyncResult)
Dim totalRead As Integer
Try
totalRead = client.GetStream.EndRead(ar) 'Ends the reading and returns the number of bytes read.
Catch ex As Exception
'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections
'to this client and remove it from the list of connected clients.
End Try
If totalRead > 0 Then
'the readBuffer array will contain everything read from the client.
Dim receivedString As String = System.Text.Encoding.UTF8.GetString(readBuffer, 0, totalRead)
messageReceived(receivedString)
End If
Try
client.GetStream.BeginRead(readBuffer, 0, BYTES_TO_READ, AddressOf doRead, Nothing) 'Begin the reading again.
Catch ex As Exception
'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections
'to this client and remove it from the list of connected clients.
MessageBox.Show(ex.ToString)
End Try
End Sub
The problem lies when the form is created on the line .showDialog() it stops here untill the application is closed. ive tryed using .show() but then the new "Convo window just hangs"
Private Sub messageReceived(ByVal message As String)
Dim data() As String = message.Split("|"c)
Select Case data(0)
Case "MESSAGE"
Dim chatDialog As New RichTextBox
Try
If conversations.ContainsKey(data(1)) Then
Dim convoWindow As ChatWindow
convoWindow = New ChatWindow
convoWindow = conversations.Item(data(1))
chatDialog = convoWindow.RichTextBox1
Else
Try
Dim convoWindow As New ChatWindow()
conversations.Add(data(1), convoWindow)
convoWindow = conversations.Item(data(1))
convoWindow.ShowDialog()
chatDialog = convoWindow.RichTextBox1
AppendTextChatWindows(data(2), chatDialog)
Thanks
Houlahan

Related

TCP Client-Side Not Recieveing Data Properly VB.NET

I'm trying to make a simple client-side application to recieve small text data, compare it and then does something on client machine depending on what server sent.
Server Logic: The server side is made in java, so can't change anything there. Server sends string "abc001" on connecting to client.
Client Logic: Client recieves the string "abc001" from server & checks if it's recieved string is the same as "abc001", then does something accordingly.
Problem: When the client recieves data, I display it in msgbox. But instead of just "abc001", there pops up an extra blank msgbox(image included).
Client Code - On Start:
Try
' declare vals
Dim ip As String = "127.0.0.1"
Dim port As Integer = 5000
' set client
_client = New TcpClient(ip, port)
' disable cross thread calls checking
CheckForIllegalCrossThreadCalls = False
' recieve msg
Threading.ThreadPool.QueueUserWorkItem(AddressOf RecieveMessages)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Client Code - Recieve Data
Private Sub RecieveMessages(state As Object)
Try
While True
Dim ns As NetworkStream = _client.GetStream()
Dim toRecieve(_client.ReceiveBufferSize) As Byte
ns.Read(toRecieve, 0, CInt(_client.ReceiveBufferSize))
Dim txt As String = Encoding.ASCII.GetString(toRecieve)
MsgBox(txt)
End While
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
MsgBox 1
MsgBox 2
How to not get the blank msgbox. Even when compared, the data recived does not match parameters. Tried to use delay, tried fixing the buffer size to 6 bytes but no use.. Any help is appreciated. Thanks.
EDIT 1: Tried my best to figure it out but can't.. Tried cleaning the returned string data and even tried storing each return data in array. Saw the stack and it says the msgbox has "nothing" in it. It's null.. I don't even know what to do.. Here's the code for strings clean:
Private Sub RecieveMessages(state As Object)
Dim message(0) As String
Dim command_raw, command_clean, command As String
Dim counter As Integer = 0
Try
While True
Dim ns As NetworkStream = _client.GetStream()
Dim toRecieve(_client.ReceiveBufferSize) As Byte
ns.Read(toRecieve, 0, CInt(_client.ReceiveBufferSize))
Dim txt As String = Encoding.ASCII.GetString(toRecieve)
message(0) = txt
command_raw = message(0)
command_clean = command_raw.Replace(vbCrLf, Nothing)
command = command_clean.Substring(0, 6)
MsgBox(command)
End While
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub

Task function within form and error messages

I have a form whose role is to show the user a circular progress graphic while the user is waiting on particular stuff to be done. This is the simple code of it:
Public Class FrmCircularProgress
Sub New(progressType As DevComponents.DotNetBar.eCircularProgressType)
InitializeComponent()
CircularProgress1.ProgressBarType = progressType
StartCircular()
End Sub
Public Sub StartCircular()
Me.CircularProgress1.IsRunning = True
End Sub
Public Sub StopCircular()
Me.CircularProgress1.IsRunning = False
End Sub
End Class
Below is an example of how I use it (in this case two places)
Dim createArticle As New Artikel
'http://stackoverflow.com/questions/33030706/put-long-running-method-into-task-showing-new-form-meantime-and-closing-it-once
Dim pic As New FrmCircularProgress(eCircularProgressType.Donut)
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
'--Run lenghty task
Dim resu = False
Try
resu = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)
'--Close form once done (on GUI thread)
Catch sqlex As Exception
pic.Invoke(Sub() MessageBox.Show(pic, sqlex.Message))
' pic.Invoke(Sub() MessageBox.Show(pic, ex.Message))
'pic.Invoke(Sub() TaskDialog.Show(pic, New TaskDialogInfo("Information", eTaskDialogIcon.BlueStop, "WizardPageDescriptionUberblick_BeforePageDisplayed", ex.ToString, eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing)))
Finally
End Try
pic.Invoke(New Action(Sub() pic.StopCircular()))
pic.Invoke(New Action(Sub() pic.Close()))
Return resu
End Function)
'--Show the form
pic.ShowDialog()
Task.WaitAll(tsk)
If tsk.Result = True Then
TaskDialog.Show(New TaskDialogInfo("Information", eTaskDialogIcon.BlueStop, "Infor", "New articel and every data has been added correctly", eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing))
'http://stackoverflow.com/questions/33030706/put-long-running-method-into-task-showing-new-form-meantime-and-closing-it-once
pic = New FrmCircularProgress(eCircularProgressType.Line)
Dim work As Task = Task.Factory.StartNew(Sub()
'--Run lenghty task
PrepareUberblick()
'--Close form once done (on GUI thread)
pic.Invoke(New Action(Sub() pic.StopCircular()))
pic.Invoke(New Action(Sub() pic.Close()))
End Sub)
'--Show the form
pic.ShowDialog()
Task.WaitAll(work)
If WYSWIG_Uberblick.Document IsNot Nothing Then
WYSWIG_Uberblick.Document.Write(String.Empty)
End If
'--Pobranie wszystkich html'ow wszystkich podsekcji artykulow (w tym wypadku numerów artykułów jako podsekcji) (dla sekcji Uberblick)
WYSWIG_Uberblick.DocumentText = _htmlFactory.GetAllUberblickHTML
Else
TaskDialog.Show(New TaskDialogInfo("Information", eTaskDialogIcon.NoEntry, "Infor", "Critical error occured", eTaskDialogButton.Ok, eTaskDialogBackgroundColor.Blue, Nothing, Nothing, Nothing, "Jakis footer text", Nothing))
e.Cancel = True
End If
ProcessArticle function:
Public Function ProcessArticle(artikel As ArticlesVariations) As Boolean
Dim result = True
Dim strcon = New AppSettingsReader().GetValue("ConnectionString", GetType(System.String)).ToString()
Using connection As New SqlConnection(strcon)
'-- Open generall connection for all the queries
connection.Open()
'-- Make the transaction.
Dim transaction As SqlTransaction
transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)
Dim newArticleRowId As Integer = 0
Dim articleIndex As Integer = 0
Try
For Each kvp As KeyValuePair(Of Integer, Artikel) In artikel.collection
Dim ckey As Integer = kvp.Key
articleIndex = kvp.Key 'save article key
Dim data As Artikel = kvp.Value
'-- If given article contains images list (artikel_images is a list with pictures associated with article)
If Not IsNothing(artikel.collection(articleIndex).ArtikelImages) Then
For Each img In artikel.collection(articleIndex).ArtikelImages
'--Insert article's images if exists
Using cmd As New SqlCommand("INSERT INTO T_Article_Image (Path, FK_Artikel_ID, Position) VALUES (#Path, #FK_Artikel_ID, #Position)", connection)
cmd.CommandType = CommandType.Text
cmd.Connection = connection
cmd.Transaction = transaction
cmd.Parameters.AddWithValue("#Path", img.Path)
cmd.Parameters.AddWithValue("#FK_Artikel_ID", newArticleRowId)
cmd.Parameters.AddWithValue("#Position", img.Position)
cmd.ExecuteScalar()
End Using
Next
End If
'-- If given article contains articles variations list (artikel_variation_attributes is a list with variations associated with article)
If Not IsNothing(artikel.collection(articleIndex)._artikel_variation_attributes) Then
For Each var In artikel.collection(articleIndex)._artikel_variation_attributes
'--Insert article's images if exists
Using cmd As New SqlCommand("INSERT INTO T_Artikel_T_Variation (FK_Variation_VariationAttribute_ID, FK_Artikel_ID, Position) VALUES (#FK_Variation_VariationAttribute_ID, #FK_Artikel_ID, #Position)", connection)
cmd.CommandType = CommandType.Text
cmd.Connection = connection
cmd.Transaction = transaction
cmd.Parameters.AddWithValue("#FK_Variation_VariationAttribute_ID", New Variation_VariationAttribute(var.FkVariationId, var.FkVariationAttributeId).GetId())
cmd.Parameters.AddWithValue("#FK_Artikel_ID", newArticleRowId)
cmd.Parameters.AddWithValue("#Position", var.Position)
cmd.ExecuteScalar()
End Using
Next
End If
Next
transaction.Commit()
Catch ex As Exception
result = False
'-- Roll the transaction back.
Try
transaction.Rollback()
Catch ex2 As Exception
' This catch block will handle any errors that may have occurred
' on the server that would cause the rollback to fail, such as
' a closed connection.
'Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType())
'Console.WriteLine(" Message: {0}", ex2.Message)
End Try
End Try
End Using
Return result
End Function
Everything works correctly, however, when it comes to error or whatever within those methods (from our example):
Dim resu As Boolean = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)
or this method:
PrepareUberblick()
My circural form is not closing, but it's still running (it's stuck). When I do Alt+F4 to kill my circular form, I see an error message. I assume that when an error occurs, the error message window is not going to be shown in front but it's hidden behind the circular form.
Here's the question: do you know how to fix it so when an error occurs, an error message show up in front, so user could acknowledge and then the circular form would be closed?
If you want to alert the user that something happened, you could show the MessageBox from your circular form, which should appear on top of it because it's generated on the same thread. You can show the MessageBox in the Catch
Try
'--Run lenghty task
resu = createArticle.ProcessArticle(_artikelsAndTheirVariationsFinal)
Catch ex As Exception
pic.Invoke(Sub() MessageBox.Show(ex.message))
End Try
'--Close form once done (on GUI thread)
pic.Invoke(New Action(Sub() pic.StopCircular()))
pic.Invoke(New Action(Sub() pic.Close()))
This way, the user will need to click OK on the MessageBox before the circular form closes.
Your whole issue stemmed from the fact that you were not calling MessageBox.Show() on the same thread that the form was created on. It's not clear from your example where the form is created, whether it's on the UI thread or not. In either case, whichever thread the form is created on must be the same one that the message box is raised on, in order for the MessageBox to be modal to the form. By calling pic.Invoke(Sub() MessageBox.Show(ex.message)), you ensure it's shown on the form's thread, and will be modal to it. You can typically force the parent window by using the overload which has
Public Shared Function Show (
owner As IWin32Window,
text As String
) As DialogResult
which would be
pic.Invoke(Sub() MessageBox.Show(pic, ex.message))
Also see:
Does MessageBox.Show() automatically marshall to the UI Thread?
Why use a owner window in MessageBox.Show?

How to update an MS Access database using a dataset in visual basic?

Hi I am currently working on a project on visual Basic 2010, what i am stuck on now is updating my MS Access database triggered by a button click.
I already have the connection and data adapter established and i generated a data set for the data adapter, and i have used the data set. what i am trying to do is read from a data grid view entries the user have typed in and save these changes to the data set, and finally save the dataset back into the database using the oledbdataadapter.update(dataset) command. I tried everything and i have been stuck for a while, there are no errors in the code and I can see the changes made to the dataset are successful and i can view them (i am getting the "update successful" at the end of the try so i am sure the code is executing till then and not going to exception), but i simply don't see the changes in the database.
below is the code, i will appreciate any help you can offer thank you.
For j As Integer = 6 To DataGridView1.Rows.Count
Try
Dim s As String = DataGridView1.Rows(j).Cells(0).Value
Dim Quantaties As Integer = DataGridView1.Rows(j).Cells(3).Value
For i As Integer = 0 To DataSet21.Tables("Stock").Rows.Count
Dim foundRow As DataRow = DataSet21.Tables("Stock").Rows.Find(i)
If foundRow IsNot Nothing Then
If foundRow(1) = s Then
DataSet21.Tables("Stock").Rows(i).Item(7) = Quantaties
DataSet21.AcceptChanges()
Try
Dim builder As New OleDbCommandBuilder(OleDbDataAdapter1)
Me.Validate()
OleDbDataAdapter1.UpdateCommand = builder.GetUpdateCommand()
OleDbDataAdapter1.Update(DataSet21.Stock)
DataSet21.AcceptChanges()
MsgBox("Update successful")
Catch ex As Exception
MsgBox("Update failed")
End Try
End If
End If
Next
BindingSource1.EndEdit()
Catch ex As Exception
End Try
Next
thank you for your reply.
I guess both ways work OleDbDataAdapter1.Update(DataSet21.Stock) and OleDbDataAdapter1.Update("DataSet21"), because i figured out what was wrong with my code. the problem was in the DataSet21.AcceptChanges() i should not have placed it before the OleDbDataAdapter1.Update(DataSet21.Stock).
the OleDbDataAdapter.update() saves changes done in the dataset to the database and the dataset.acceptchanges() makes the dataset save the changes done to it making it seem that it doesn't have changes in it anymore. so the OleDbDataAdapter.update() was not executing since the dataset didn't have changes done to it because of the dataset.acceptchanges()
so what i did was remove dataset.acceptchanges() and it finally worked. my code looks like this now.
For j As Integer = 6 To DataGridView1.Rows.Count
Try
Dim s As String = DataGridView1.Rows(j).Cells(0).Value
Dim Quantaties As Integer = DataGridView1.Rows(j).Cells(3).Value
For i As Integer = 0 To DataSet21.Tables("Stock").Rows.Count
Dim foundRow As DataRow = DataSet21.Tables("Stock").Rows.Find(i)
If foundRow IsNot Nothing Then
If foundRow(1) = s Then
DataSet21.Tables("Stock").Rows(foundRow(0) - 2).Item(7) = Quantaties
Try
BindingSource1.EndEdit()
OleDbDataAdapter1.Update(DataSet21.Stock)
MsgBox("Update successful")
Catch ex As Exception
MsgBox("Update failed")
End Try
End If
End If
Next
Catch ex As Exception
End Try
Next

Shared Resource in Parallel.ForEach

How do I control access to a shared resource in a Parallel.ForEach loop? I am trying to download multiple files in parallel, and I want to capture information about downloads that fail, so that the user can re-attempt the download later. However, I am worried that if more than one download fails at the same time, the application will throw an exception because one thread will attempt to access the file while it is being written to by another.
In the code below, I would like to know how to control access to the file at RepeateRequestPath. A RequestSet is a list of strings that represent IDs of the resource I am trying to download.
Dim DownloadCnt As Integer = 0
Dim ParallelOpts As New ParallelOptions()
ParallelOpts.MaxDegreeOfParallelism = 4
Parallel.ForEach(RequestSets, ParallelOpts, Sub(RequestSet)
Try
DownloadCnt += 1
Dim XmlUrl As String = String.Format("{0}{1}{2}", "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=", String.Join(",", RequestSet), "&retmode=xml&rettype=abstract")
DownloadFile(XmlUrl, String.Format("{0}\TempXML{1}.xml", XMLCacheDir, DownloadCnt))
Catch ex As WebException
Using Response As WebResponse = ex.Response
Dim statCode As Integer = CInt(DirectCast(Response, HttpWebResponse).StatusCode)
MessageBox.Show(String.Format("Failed to retrieve XML due to HTTP error {0}. Please hit the 'Retrieve XML' button to re-run retrieval after the current set is complete.", statCode))
If Not File.Exists(RepeatRequestPath) Then
File.WriteAllLines(RepeatRequestPath, RequestSet)
Else
File.AppendAllLines(RepeatRequestPath, RequestSet)
End If
End Using
End Try
End Sub)
The usual way to protect a shared resource in VB.NET is to use SyncLock.
So, you would create a lock object before the Parallel.ForEach() loop:
Dim lock = New Object
and then you would use that inside the loop:
SyncLock lock
File.AppendAllLines(RepeatRequestPath, RequestSet)
End SyncLock
Also note that you can use AppendAllLines() even if the file doesn't exist yet, so you don't have to check for that.
You need to use a semaphore to control access to a shared resource. You want only one thread to access the error file at one time, so initialize the semaphore to only allow 1 thread in. Calling _pool.WaitOne should seize the semaphore, and then release it once it finishes creating/writing to the file.
Private Shared _pool As Semaphore
_pool = = New Semaphore(0, 1)
Dim DownloadCnt As Integer = 0
Dim ParallelOpts As New ParallelOptions()
ParallelOpts.MaxDegreeOfParallelism = 4
Parallel.ForEach(RequestSets, ParallelOpts, Sub(RequestSet)
Try
DownloadCnt += 1
Dim XmlUrl As String = String.Format("{0}{1}{2}", "http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=", String.Join(",", RequestSet), "&retmode=xml&rettype=abstract")
DownloadFile(XmlUrl, String.Format("{0}\TempXML{1}.xml", XMLCacheDir, DownloadCnt))
Catch ex As WebException
Using Response As WebResponse = ex.Response
Dim statCode As Integer = CInt(DirectCast(Response, HttpWebResponse).StatusCode)
MessageBox.Show(String.Format("Failed to retrieve XML due to HTTP error {0}. Please hit the 'Retrieve XML' button to re-run retrieval after the current set is complete.", statCode))
_pool.WaitOne()
Try
If Not File.Exists(RepeatRequestPath) Then
File.WriteAllLines(RepeatRequestPath, RequestSet)
Else
File.AppendAllLines(RepeatRequestPath, RequestSet)
End If
Catch ex as Exception
'Do some error handling here.
Finally
_pool.Release()
End Try
End Using
End Try
End Sub)
svick's solution is almost right. However if you need to protect access to a shared variable you also need to declare your lock object as shared at class level.
This works correctly:
Friend Class SomeClass
Private Shared _lock As New Object
Private Shared sharedInt As Integer = 0
Sub Main()
SyncLock _lock
sharedInt += 1
End SyncLock
End Sub
End Class
If you use a non-shared lock object, synclock will protect the variable only from multiple accessing threads within the same instance, not across instances.

Don't get any data from socket when data should be there, and no exceptions raised, connection is open. Using DataAvailable to wait for data

I have a problem reading data from an RFID-reader. I connect to the reader by tcp and wait for DataAvailable to be true, then reading the data until I got a end of data character. Then I just go back and waiting for a new DataAvailable. This is done in a own thread for the function.
There seems to be some kind of timeout, If I don't got any data in a couple of minutes, then it just sits there in the do/loop waiting for DataAvailable. I hold the card to the RFID reader, it beeps, but there is no data available. I don't get any exceptions, and the information says that the clientsocket is still connected. Are there anything more I can check?
If I put the card to the reader in a minute-interval it seems as this will never occur. So 2-3 minutes idle:ing seems to do this.
Here are my code to read data from the socket, I have taken away some irrelevant code:
Sub test(ByVal ip As String, ByVal port As Integer)
' this sub is meant to run forever
Try
Dim clientSocket As New System.Net.Sockets.TcpClient()
clientSocket.Connect(ip, port)
Using serverStream As NetworkStream = clientSocket.GetStream()
Do 'loop forever or until error occur
'Every new dataentry starts here
Dim inStream(0) As Byte
Dim returndata As String = ""
Do 'loop forever
Do Until serverStream.DataAvailable 'loop until data exists to read
If clientSocket.Connected = False Then
'this will never happen.
'but if there are more than 5 minutes between data then
'it never got data again as if no data was sent.
Exit Sub
End If
Application.DoEvents()
Loop
'there is data to read, read first byte and
serverStream.Read(inStream, 0, 1)
If inStream(0) = 13 Then
'got end of data
'exit loop if reading chr 13.
returndata &= System.Text.Encoding.ASCII.GetString(inStream)
Exit Do
End If
Loop
GotData(returndata)
Loop
End Using
Catch ex As Exception
' handle error
Finally
'close connection if open
End Try
End Sub
I found out that socket.Connected only reports the status for when the last command was runned on the connection.
So in the Do Until serverStream.DataAvailable loop I used this trick to check if the connection was closed instead:
Dim test As Boolean = clientSocket.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead)
If test = True And serverStream.DataAvailable = False Then
'restart connection
End If
So now finally got control over what is happening and know that its because of the client connection is closed that I dont got any data.
So, then I figured, now that I know that the connection is closed, how do I prevent it? That was easier, just send data to the tcpip-server every 10 second and it will hold it open.
The result that works for me (this is not the production code, just an example of the solution):
Dim s As Date = Now
Do Until serverStream.DataAvailable
Dim r As Boolean = clientSocket.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead)
If DateDiff(DateInterval.Second, s, Now) > 10 Then
Dim dta(0) As Byte
dta(0) = 0
clientSocket.Client.Send(dta)
s = Now
End If
If r = True And serverStream.DataAvailable = False Then
'restart sub
Exit Sub
End If
loop
So now it doesnt even close and need to restart every x minutes.
My problems are solved and Im a happy coder. ;)