Matthew said:
Can you explain this part please, if you could edit the code i gave
showing me where to make the changes that would be brilliant.
I am trying to do this honestly.
------------------------------------------------------
First of all, the class that holds the code you show below needs a
reference to the active instance of some other part of the UI. In VB6,
this reference will be globally available under the name of the form,
in VB.NET it's not. You need to explicitly put a variable in the
class (or a global variable, but if a member is possible use that,
it's better from a design point of view) with the ProcessCommands sub
and set it to the instance of your main form. Suppose we call that
variable MainForm.
------------------------------------------------------
Upon reading your code better, it would appear all these functions are
inside a single Form class. Am I right?
If so, you can pretty much ignore the paragraph above, and follow these
instructions. You say you want to run the entire ProcessCommands method in
another thread. That's certainly possible, but do note it will be slightly
slower than using a method that takes no parameters. Still, in your case
it's probably necessary to do it this way (or redesign a large part of your
code), because of some of the methods you call. You must keep in mind that
the System.Windows.Forms.Control class is not thread safe (all controls and
forms are children of this class). I quote the documentation:
"Note: There are four methods on a control that are safe to call from any
thread: Invoke, BeginInvoke, EndInvoke, and CreateGraphics. For all other
method calls, you should use one of the invoke methods to marshal the call
to the control's thread."
But back to the business at hand. You want to use Invoke to run
ProcessCommands in the UI thread, and since ProcessCommands has a non-empty
argument list you need a custom delegate type.
Add to the top of your form a declaration for this delegate type:
Private Delegate Sub ProcessCommandsDelegate(ByVal strMessage As String)
-----------------------------------------
THIS PART IS NEXT
-----------------------------------------
Public Sub DoRead(ByVal ar As IAsyncResult)
Dim BytesRead As Integer
Dim strMessage As String
Try
' Finish asynchronous read into readBuffer and return
number of bytes read.
BytesRead = client.GetStream.EndRead(ar)
If BytesRead < 1 Then
' If no bytes were read server has close. Disable
input window.
Exit Sub
End If
' Convert the byte array the message was saved into, minus
two for the
'Chr(13) and Chr(10)
strMessage = Encoding.ASCII.GetString(readBuffer, 0,
BytesRead - 2)
Now, replace the call to ProcessCommands with the following:
Me.Invoke(New ProcessCommandsDelegate(AddressOf ProcessCommands), _
New Object() {strMessage})
Now ProcessCommands gets run in the proper thread context.
' Start a new asynchronous read into readBuffer.
client.GetStream.BeginRead(readBuffer, 0, READ_BUFFER_SIZE,
AddressOf DoRead, Nothing)
Catch e As Exception
MsgBox(e.Message)
Don't use MsgBox. It's the VB6 way. The .Net way is MessageBox.Show(). Also,
always(!) use the overloads that take an IWin32Window owner as their first
parameter. I've found it to be rather unreliable in picking the owner in
certain situations if you don't explicitly specify it, especially if you're
doing this in a different thread from the form that's supposed to be the
owner. Therefore, replace the call to MessageBox with this:
MessageBox.Show(Me, e.Message, "Error!")
-----------------------------------------
THE FOLLOWING SUB PROCESSES THE COMMANDS
-----------------------------------------
Public Sub ProcessCommands(ByVal strMessage As String)
'TMSG|1234567890|Matt|1234567890|Message
Dim dataArray() As String
Dim lstR As ListViewItem
dataArray = Split(strMessage, Chr(124))
Select Case dataArray(0)
Case "RNICK"
'lstR = lstContacts.Items.Add(dataArray(2))
'lstR.SubItems.Add(dataArray(1))
-----------------------------------------
THIS IS THE PROBLEM AREA, IDEALLY IT WOULD BE GOOD TO HAVE THIS WHOLE
SUB RUNNING OUT OF THE THREAD SO I CAN EXECUTE CODE HERE
-----------------------------------------
Case "TMSG"
'open message window
'display received message
'Open a new window, or open window with tabs
If F4 Is Nothing Then
F4 = New frmMessage
F4.Show()
End If
Case "ERROR"
MsgBox(dataArray(1), MsgBoxStyle.Exclamation, "An Error
Has Occured")
As above: MessageBox.Show(Me, dataArray(1), "An Error has occurred",
MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
End Select
End Sub
-----------------------------------------
Hope this helps. Also, you might want to make some of your methods Private
instead of Public. Anything that doesn't need to be called from another
class should be Private.