Link to home
Start Free TrialLog in
Avatar of John
JohnFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Telnet via VB

I found a really nice looking example of how to do telnet over VB.  

It is the last post on this page:

http://stackoverflow.com/questions/9113632/test-telnet-communication-on-remote-computer-using-vb-net

It looks to be exactly what I need, but I don't know how to use it.  

I want to use it to connect to cisco routers and issue commands.  

I've built a form to do it, but, I have a really silly problem.  I don't know how to instantiate the class, set the settings and use it!

I don't do a lot of VB and this bit has stumped me.  

Ideally, if you checkout the code below and assuming it is ok,  tell me how to:
1.  Connect to a telnet device using the hostname from a textbox called txtHostRouter and the port number from a textbox called txtPortNumber
2.  Recieve whatever output (probably a password prompt)  into a text box called txtOutput.  
3.  Send some input from a text box called txtInput for example "show Run"
4.  Recieve the output into a different text box called txtOutput.  

So I can keep doing 3) and 4) until I am finished and then close the connection.  

I am not sure where to start, so even if you just get me started, I bet I can work it out.  

I have pasted the code below

Any help would be appreciated

Thanks in advance

Imports System.Threading
Imports System.IO
Imports System.IO.Pipes

Public Class TelnetClient
  Private Server As String
  Private NetWorkProtocolClient As System.Net.Sockets.TcpClient
  Private ServerStream As System.Net.Sockets.NetworkStream
  Private DoReader As Boolean
  Private ReaderThread As Thread
  Private OutputPipe As AnonymousPipeServerStream
  Private WaitForString As String
  Private WaitForStringEvent As New AutoResetEvent(False)

  ReadOnly Property IsConnected() As Boolean
    Get
      Return (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected))
    End Get
  End Property

  ReadOnly Property ConnectedTo() As String
    Get
      If (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected)) Then
        Return NetWorkProtocolClient.Client.RemoteEndPoint.ToString()
      Else
        Return "Nothing"
      End If
    End Get
  End Property

  'Set the Server string to connect to.
  Public Sub SetServer(ByVal new_server As String)
    'double check this later
    Server = new_server
  End Sub
  'Connects if possilbe. If already conneced to some thing it Disconnects from old Telnet and connects to new Telnet.
  Public Sub Connect()
    Try
      If (Not (IsNothing(NetWorkProtocolClient))) AndAlso NetWorkProtocolClient.Connected Then
        Disconnect()
      End If
      If Not IsNothing(Server) Then
        NetWorkProtocolClient = New System.Net.Sockets.TcpClient(Server, 23)
        If NetWorkProtocolClient.Connected Then
          'clear on a new client
          WaitForString = Nothing
          WaitForStringEvent.Reset()

          NetWorkProtocolClient.NoDelay = True
          ServerStream = NetWorkProtocolClient.GetStream()
          ServerStream.ReadTimeout = 1000
          DoReader = True
          ReaderThread = New Thread(AddressOf ReaderTask)
          ReaderThread.IsBackground = True
          ReaderThread.Priority = ThreadPriority.AboveNormal
          ReaderThread.Start()
        End If
      End If
    Catch ex As System.Net.Sockets.SocketException
      Console.WriteLine("SocketException Connect: {0}", ex)
    End Try
  End Sub

  'Disconnects if connected, otherwise does nothing.
  Public Sub Disconnect()
    Try
      If ReaderThread.IsAlive Then
        DoReader = False
        ReaderThread.Join(1000)
      End If
      If (Not (IsNothing(NetWorkProtocolClient))) Then
        ServerStream.Close()
        NetWorkProtocolClient.Close()
      End If
    Catch ex As System.Net.Sockets.SocketException
      Console.WriteLine("SocketException Disconnect: {0}", ex)
    End Try
  End Sub

  'Returns true if found before timeout milliseconds. Use -1 to have infinite wait time.
  'Returns false if timeout occured.
  Public Function WaitFor(ByVal command As String, ByVal timeout As Integer) As Boolean
    WaitForString = New String(command)
    WaitForStringEvent.Reset()
    Dim was_signaled As Boolean = False
    'Block until a the right value from reader or user defined timeout
    was_signaled = WaitForStringEvent.WaitOne(timeout)
    WaitForString = Nothing
    Return was_signaled
  End Function

  Public Sub Write(ByVal command As String)
    Try
      If (Not (IsNothing(NetWorkProtocolClient))) Then
        If NetWorkProtocolClient.Connected Then
          'Write the value to the Stream
          Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command)
          SyncLock ServerStream
            ServerStream.Write(bytes, 0, bytes.Length)
          End SyncLock
        End If
      End If
    Catch ex As System.Net.Sockets.SocketException
      Console.WriteLine("SocketException Write: {0}", ex)
    End Try
  End Sub

  'appends CrLf for the caller
  Public Sub WriteLine(ByVal command As String)
    Try
      If (Not (IsNothing(NetWorkProtocolClient))) Then
        If NetWorkProtocolClient.Connected Then
          'Write the value to the Stream
          Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command & vbCrLf)
          SyncLock ServerStream
            ServerStream.Write(bytes, 0, bytes.Length)
          End SyncLock
        End If
      End If
    Catch ex As System.Net.Sockets.SocketException
      Console.WriteLine("SocketException Write: {0}", ex)
    End Try
  End Sub

  'Get a pipe to read output. Note: anything written by WriteLine may be echoed back if the other Telnet offers to do it.
  Public Function GetPipeHandle() As String
    If Not IsNothing(ReaderThread) AndAlso ReaderThread.IsAlive AndAlso Not IsNothing(OutputPipe) Then
      Return OutputPipe.GetClientHandleAsString
    Else
      Return Nothing
    End If
  End Function

  'Task that watches the tcp stream, passes info to the negotiation function and signals the WaitFor task.
  Private Sub ReaderTask()
    Try
      OutputPipe = New AnonymousPipeServerStream(PipeDirection.Out)
      Dim prevData As New String("")
      While (DoReader)
        If (Not (IsNothing(NetWorkProtocolClient))) Then

          If ServerStream.DataAvailable Then

            'Grab Data
            Dim data As [Byte]() = New [Byte](NetWorkProtocolClient.ReceiveBufferSize) {}
            Dim bytes As Integer = ServerStream.Read(data, 0, data.Length)

            'Negotiate anything that came in
            bytes = Negotiate(data, bytes)

            If (bytes > 0) Then
              'append previous to the search sting incase messages were fragmented
              Dim s As New String(prevData & System.Text.ASCIIEncoding.ASCII.GetChars(data))

              'If Pipe is connected send it remaining real data
              If OutputPipe.IsConnected Then
                OutputPipe.Write(data, 0, bytes)
              End If

              'Check remaining against WaitForString
              If Not IsNothing(WaitForString) Then
                If s.Contains(WaitForString) Then
                  WaitForStringEvent.Set()
                  'clear prevData buffer because the WaitForString was found
                  prevData = New String("")
                Else
                  'Nothing found make the current string part of the next string.
                  prevData = New String(s)
                End If
              Else
                prevData = New String("")
              End If
            End If

          Else
            Thread.Sleep(100)
          End If
        End If
      End While
      OutputPipe.Close()
      OutputPipe.Dispose()
    Catch ex As System.IO.IOException
      Console.WriteLine("IO Error: {0}", ex)
    Catch ex As System.Net.Sockets.SocketException
      Console.WriteLine("SocketException Reader: {0}", ex)
    End Try
  End Sub

  'Shamelessly adapted from http://www.codeproject.com/Articles/63201/TelnetSocket
  'The basic algorithm used here is:
  ' Iterate across the incoming bytes
  ' Assume that an IAC (byte 255) is the first of a two- or three-byte Telnet command and handle it:
  '   If two IACs are together, they represent one data byte 255
  '   Ignore the Go-Ahead command
  '   Respond WONT to all DOs and DONTs
  '   Respond DONT to all WONTs
  '   Respond DO to WILL ECHO and WILL SUPPRESS GO-AHEAD
  '   Respond DONT to all other WILLs
  ' Any other bytes are data; ignore nulls, and shift the rest as necessary
  ' Return the number of bytes that remain after removing the Telnet command and ignoring nulls
  Private Function Negotiate(ByVal data As Byte(), ByVal length As Int32) As Int32
    Dim index As Int32 = 0
    Dim remaining As Int32 = 0

    While (index < length)
      If (data(index) = TelnetBytes.IAC) Then
        Try
          Select Case data(index + 1)
            Case TelnetBytes.IAC
              data(remaining) = data(index)
              remaining += 1
              index += 2

            Case TelnetBytes.GA
              index += 2

            Case TelnetBytes.WDO
              data(index + 1) = TelnetBytes.WONT
              SyncLock ServerStream
                ServerStream.Write(data, index, 3)
              End SyncLock
              index += 3

            Case TelnetBytes.DONT
              data(index + 1) = TelnetBytes.WONT
              SyncLock ServerStream
                ServerStream.Write(data, index, 3)
              End SyncLock
              index += 3

            Case TelnetBytes.WONT
              data(index + 1) = TelnetBytes.DONT
              SyncLock ServerStream
                ServerStream.Write(data, index, 3)
              End SyncLock
              index += 3

            Case TelnetBytes.WILL
              Dim action As Byte = TelnetBytes.DONT

              Select Case data(index + 2)

                Case TelnetBytes.ECHO
                  action = TelnetBytes.WDO

                Case TelnetBytes.SUPP
                  action = TelnetBytes.WDO

              End Select
              data(index + 1) = action
              SyncLock ServerStream
                ServerStream.Write(data, index, 3)
              End SyncLock
              index += 3

          End Select

        Catch ex As System.IndexOutOfRangeException
          index = length
        End Try
      Else
        If (data(index) <> 0) Then
          data(remaining) = data(index)
          remaining += 1
        End If
        index += 1
      End If
    End While

    Return remaining
  End Function

  Private Structure TelnetBytes

    'Commands
    Public Const GA As Byte = 249
    Public Const WILL As Byte = 251
    Public Const WONT As Byte = 252
    Public Const WDO As Byte = 253 'Actually just DO but is protected word in vb.net 
    Public Const DONT As Byte = 254
    Public Const IAC As Byte = 255

    'Options
    Public Const ECHO As Byte = 1
    Public Const SUPP As Byte = 3
  End Structure
End Class

Open in new window

Avatar of John
John
Flag of United Kingdom of Great Britain and Northern Ireland image

ASKER

I have half-solved it.  If you could please check the comment below and point me in the right direction...

It seems that the basics of working with classes are easy enough.  I used this code to connect to a telnet device:

When clicked, it checks if we are already connected, if so it will disconnect, if not it will connect.  It changes the button text from 'connect' to 'disconnect'.   To double check, it also checks the connection and tells you where it is connected to.  

    
Private Sub btnConnect_Click(sender As System.Object, e As System.EventArgs) Handles btnConnect.Click
        Select Case connTelnet.IsConnected
            Case True
                connTelnet.Disconnect()
                'MsgBox(connTelnet.IsConnected)
                If connTelnet.IsConnected = False Then Me.btnConnect.Text = "Connect"
            Case False
                connTelnet.SetServer(Me.txtServer.Text)
                connTelnet.SetPort(Me.txtPort.Text)
                connTelnet.Connect()
                'MsgBox(connTelnet.IsConnected)
                If connTelnet.IsConnected = True Then Me.btnConnect.Text = "Disconnect"
                MsgBox("Connected to:" & connTelnet.ConnectedTo)
            Case Else
                MsgBox("Oops, not true or false!")
        End Select
    End Sub

Open in new window


I don't know how to use the connection.  I need some way of detecting when there is output from the telnet client so I can call the sub that reads the data.  I assume I need some kind of async call and a delegate, but I haven't been able to figure this bit out yet.  

If you read the bit above, you will realize I am using a method not present in the original code.  I added a small section to the previous code to allow me to specify the port number, so it now reads:

Imports System.Threading
Imports System.IO
Imports System.IO.Pipes

Public Class clsTelnetClient
    Private Server As String

Open in new window


This line

    Private Port As String

Open in new window


continued...

    Private NetWorkProtocolClient As System.Net.Sockets.TcpClient
    Private ServerStream As System.Net.Sockets.NetworkStream
    Private DoReader As Boolean
    Private ReaderThread As Thread
    Private OutputPipe As AnonymousPipeServerStream
    Private WaitForString As String
    Private WaitForStringEvent As New AutoResetEvent(False)

    ReadOnly Property IsConnected() As Boolean
        Get
            Return (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected))
        End Get
    End Property

    ReadOnly Property ConnectedTo() As String
        Get
            If (Not (IsNothing(NetWorkProtocolClient)) AndAlso (NetWorkProtocolClient.Connected)) Then
                Return NetWorkProtocolClient.Client.RemoteEndPoint.ToString()
            Else
                Return "Nothing"
            End If
        End Get
    End Property

    'Set the Server string to connect to.
    Public Sub SetServer(ByVal new_server As String)
        'double check this later
        Server = new_server
    End Sub

Open in new window



and this bit:

    'Set the Server port to connect to.
    Public Sub SetPort(ByVal new_port As String)
        'double check this later
        Port = new_port
    End Sub

Open in new window


continued...

    'Connects if possilbe. If already conneced to some thing it Disconnects from old Telnet and connects to new Telnet.
    Public Sub Connect()
        Try
            If (Not (IsNothing(NetWorkProtocolClient))) AndAlso NetWorkProtocolClient.Connected Then
                Disconnect()
            End If
            If Not IsNothing(Server) Then
                NetWorkProtocolClient = New System.Net.Sockets.TcpClient(Server, Port)
                If NetWorkProtocolClient.Connected Then
                    'clear on a new client
                    WaitForString = Nothing
                    WaitForStringEvent.Reset()

                    NetWorkProtocolClient.NoDelay = True
                    ServerStream = NetWorkProtocolClient.GetStream()
                    ServerStream.ReadTimeout = 1000
                    DoReader = True
                    ReaderThread = New Thread(AddressOf ReaderTask)
                    ReaderThread.IsBackground = True
                    ReaderThread.Priority = ThreadPriority.AboveNormal
                    ReaderThread.Start()
                End If
            End If
        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine("SocketException Connect: {0}", ex)
        End Try
    End Sub

    'Disconnects if connected, otherwise does nothing.
    Public Sub Disconnect()
        Try
            If ReaderThread.IsAlive Then
                DoReader = False
                ReaderThread.Join(1000)
            End If
            If (Not (IsNothing(NetWorkProtocolClient))) Then
                ServerStream.Close()
                NetWorkProtocolClient.Close()
            End If
        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine("SocketException Disconnect: {0}", ex)
        End Try
    End Sub

    'Returns true if found before timeout milliseconds. Use -1 to have infinite wait time.
    'Returns false if timeout occured.
    Public Function WaitFor(ByVal command As String, ByVal timeout As Integer) As Boolean
        WaitForString = New String(command)
        WaitForStringEvent.Reset()
        Dim was_signaled As Boolean = False
        'Block until a the right value from reader or user defined timeout
        was_signaled = WaitForStringEvent.WaitOne(timeout)
        WaitForString = Nothing
        Return was_signaled
    End Function

    Public Sub Write(ByVal command As String)
        Try
            If (Not (IsNothing(NetWorkProtocolClient))) Then
                If NetWorkProtocolClient.Connected Then
                    'Write the value to the Stream
                    Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command)
                    SyncLock ServerStream
                        ServerStream.Write(bytes, 0, bytes.Length)
                    End SyncLock
                End If
            End If
        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine("SocketException Write: {0}", ex)
        End Try
    End Sub

    'appends CrLf for the caller
    Public Sub WriteLine(ByVal command As String)
        Try
            If (Not (IsNothing(NetWorkProtocolClient))) Then
                If NetWorkProtocolClient.Connected Then
                    'Write the value to the Stream
                    Dim bytes() As Byte = System.Text.Encoding.ASCII.GetBytes(command & vbCrLf)
                    SyncLock ServerStream
                        ServerStream.Write(bytes, 0, bytes.Length)
                    End SyncLock
                End If
            End If
        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine("SocketException Write: {0}", ex)
        End Try
    End Sub

    'Get a pipe to read output. Note: anything written by WriteLine may be echoed back if the other Telnet offers to do it.
    Public Function GetPipeHandle() As String
        If Not IsNothing(ReaderThread) AndAlso ReaderThread.IsAlive AndAlso Not IsNothing(OutputPipe) Then
            Return OutputPipe.GetClientHandleAsString
        Else
            Return Nothing
        End If
    End Function

    'Task that watches the tcp stream, passes info to the negotiation function and signals the WaitFor task.
    Private Sub ReaderTask()
        Try
            OutputPipe = New AnonymousPipeServerStream(PipeDirection.Out)
            Dim prevData As New String("")
            While (DoReader)
                If (Not (IsNothing(NetWorkProtocolClient))) Then

                    If ServerStream.DataAvailable Then

                        'Grab Data
                        Dim data As [Byte]() = New [Byte](NetWorkProtocolClient.ReceiveBufferSize) {}
                        Dim bytes As Integer = ServerStream.Read(data, 0, data.Length)

                        'Negotiate anything that came in
                        bytes = Negotiate(data, bytes)

                        If (bytes > 0) Then
                            'append previous to the search sting incase messages were fragmented
                            Dim s As New String(prevData & System.Text.ASCIIEncoding.ASCII.GetChars(data))

                            'If Pipe is connected send it remaining real data
                            If OutputPipe.IsConnected Then
                                OutputPipe.Write(data, 0, bytes)
                            End If

                            'Check remaining against WaitForString
                            If Not IsNothing(WaitForString) Then
                                If s.Contains(WaitForString) Then
                                    WaitForStringEvent.Set()
                                    'clear prevData buffer because the WaitForString was found
                                    prevData = New String("")
                                Else
                                    'Nothing found make the current string part of the next string.
                                    prevData = New String(s)
                                End If
                            Else
                                prevData = New String("")
                            End If
                        End If

                    Else
                        Thread.Sleep(100)
                    End If
                End If
            End While
            OutputPipe.Close()
            OutputPipe.Dispose()
        Catch ex As System.IO.IOException
            Console.WriteLine("IO Error: {0}", ex)
        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine("SocketException Reader: {0}", ex)
        End Try
    End Sub

    'Shamelessly adapted from http://www.codeproject.com/Articles/63201/TelnetSocket
    'The basic algorithm used here is:
    ' Iterate across the incoming bytes
    ' Assume that an IAC (byte 255) is the first of a two- or three-byte Telnet command and handle it:
    '   If two IACs are together, they represent one data byte 255
    '   Ignore the Go-Ahead command
    '   Respond WONT to all DOs and DONTs
    '   Respond DONT to all WONTs
    '   Respond DO to WILL ECHO and WILL SUPPRESS GO-AHEAD
    '   Respond DONT to all other WILLs
    ' Any other bytes are data; ignore nulls, and shift the rest as necessary
    ' Return the number of bytes that remain after removing the Telnet command and ignoring nulls
    Private Function Negotiate(ByVal data As Byte(), ByVal length As Int32) As Int32
        Dim index As Int32 = 0
        Dim remaining As Int32 = 0

        While (index < length)
            If (data(index) = TelnetBytes.IAC) Then
                Try
                    Select Case data(index + 1)
                        Case TelnetBytes.IAC
                            data(remaining) = data(index)
                            remaining += 1
                            index += 2

                        Case TelnetBytes.GA
                            index += 2

                        Case TelnetBytes.WDO
                            data(index + 1) = TelnetBytes.WONT
                            SyncLock ServerStream
                                ServerStream.Write(data, index, 3)
                            End SyncLock
                            index += 3

                        Case TelnetBytes.DONT
                            data(index + 1) = TelnetBytes.WONT
                            SyncLock ServerStream
                                ServerStream.Write(data, index, 3)
                            End SyncLock
                            index += 3

                        Case TelnetBytes.WONT
                            data(index + 1) = TelnetBytes.DONT
                            SyncLock ServerStream
                                ServerStream.Write(data, index, 3)
                            End SyncLock
                            index += 3

                        Case TelnetBytes.WILL
                            Dim action As Byte = TelnetBytes.DONT

                            Select Case data(index + 2)

                                Case TelnetBytes.ECHO
                                    action = TelnetBytes.WDO

                                Case TelnetBytes.SUPP
                                    action = TelnetBytes.WDO

                            End Select
                            data(index + 1) = action
                            SyncLock ServerStream
                                ServerStream.Write(data, index, 3)
                            End SyncLock
                            index += 3

                    End Select

                Catch ex As System.IndexOutOfRangeException
                    index = length
                End Try
            Else
                If (data(index) <> 0) Then
                    data(remaining) = data(index)
                    remaining += 1
                End If
                index += 1
            End If
        End While

        Return remaining
    End Function

    Private Structure TelnetBytes

        'Commands
        Public Const GA As Byte = 249
        Public Const WILL As Byte = 251
        Public Const WONT As Byte = 252
        Public Const WDO As Byte = 253 'Actually just DO but is protected word in vb.net 
        Public Const DONT As Byte = 254
        Public Const IAC As Byte = 255

        'Options
        Public Const ECHO As Byte = 1
        Public Const SUPP As Byte = 3
    End Structure
End Class

Open in new window

Avatar of John

ASKER

I have been tinkering and have some more clarity on the problem now.  

The code that sends and receives text over telnet is called in a separate thread to the form.  It is also in a separate class to the form.  

I can use delegates to populate a textbox on the form when the code is in the same class, but not when it is in a different class.  

In the bit of code where it outputs data to a pipe, I can msgbox the output from telnet ok.  

I just replace lines 120 to 123  in the listing above with :

            datastring = Encoding.ASCII.GetString(data)
            MsgBox(datastring)
            'This next line doesn't work:
            frmMain.txtOutput.Text += vbCrLf & datastring

Open in new window


I just can't populate the textbox on the form.  

So I bet this is a dead easy one to answer for someone who understands how to use delegates better than I do.
Avatar of Chinmay Patel
Hi,

I was skeptical when you initially posted the question but you made a good progress and worked out things on your own.
Now for the final piece,

Private Delegate Sub PopulateTextBox(ByVal data As String)

Private Sub PopulateTextBox(ByVal data As String)
    If frmMain.txtOutput.InvokeRequired Then
        frmMain.txtOutput.Invoke(New PopulateTextBox(New Object() {frmMain.txtOutput, data})
    Else
        frmMain.txtOutput.Text += vbCrLf & data
    End If
End Sub

Open in new window


In your code whenever you want to update the content of txtOutput, just call this method
PopulateTextBox(datastring)

I have not tested this code and did not write it in an IDE so please do check in case I missed something.

Regards,
Chinmay.
Avatar of John

ASKER

Thanks Chinmay

I've been on this all day and taking a well deserved break.  

It's been tough going.  I know mostly what I want to do, but I'm fighting with syntax etc which really slows you down.

This last bit is way outside of my experience, so I really appreciate your input.  

I will try your suggestion later tonight.  

Thanks again

John
No problem John. If you have some free time I am bit curious to know few things

1. Any specific reason you are working with VB.Net?
2. What exactly you are trying to achieve by interfacing your app to Telnet? I understand you want to send commands to routers but why using the app? if providing GUI is a concern there are other ways you could do this.

Regards,
Chinmay.
Avatar of John

ASKER

Hi chinmay, I get the following:

'PopulateTextBox' is already declared as 'Delegate Sub PopulateTextBox(data As String)' in this class.      

I pasted your code into the class that handles the Telnet code rather than into the form code.  

I guess it is because the delegate has the same name as the sub it points at.  I'll have a tinker and see what I can make work.    

I use VB.net because I have some vb6 and vbscript/ASP experience.  I find it easier to read than c#.  

Initially, I am writing an app to manage port forwardings as well as rdp ports and firewall settings on servers.  I have it doing registry entries, the cisco bit is the next bit ands then the Windows firewall.  I want to be able to list the port forwards and then be able select some to remove and to be able to add new ones.  I need to interact with the UI to do this and store the details in a database so I have an offline record for all managed customers.  

But I am also writing an app to automate several things.  I want to be able to issue a command to many cisco routers/ switches/ APs at once.  I have a database of hardware I manage and I'd like to select a group of them and issue a command, perhaps change enable passwords, change snmp community, syslog server, ntp settings etc.  As I use cisco more and more, I find new things that I'd like in all of my configs and I want to use this as a tool to do that to save time.  I also want to regularly back configs up as a scheduled task from the same app to the same database.  I now have enough to get on with this project again.  I need to master the threading/delegate stuff for the first project though.  

I am new to threading and delegates and cross-class cross threading is something I don't know how to do and I am one of those people who can't just give up.  I am happy to hear of other ways to do things, but I can't give up on something I don't know.
ASKER CERTIFIED SOLUTION
Avatar of Chinmay Patel
Chinmay Patel
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of John

ASKER

Thanks Chinmay, I've tried this, but I've had problems.  

The telnet code is in a different class to the form and your snippet doesn't work across classes.  

I don't really understand delegates and threads but a couple of days of reading around the subject and sitting outside my comfort zone has yielded some results.  

It was difficult taking my program and modifying it.  So I built a very simple form and class and tinkered untiI got something working:
'This is my pattern for calling other threads.  
'It allows me to do the following:
'1.  Call a local sub as a thread
'2.  The local sub call s a sub in another class from this new thread - It could even be a functiuon which makes it easy to get data from a thread.  
'3.  Pass several parameters from the calling class to the worker sub inthe thread
'4.  Allow the worker code in the second class to effect changes in the UI (Calling Class)

Imports System.Threading
Public Class Form1
    'Create Delegate for the sub in this class that will be called from another class
    Delegate Sub dDelegate(mresulttext As String)
    Public dd As New dDelegate(AddressOf subDelegated)

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim t1 As Thread
        t1 = New Thread(AddressOf Me.subThread)
        t1.Start(5)
    End Sub
    Private Sub subThread(intNumber As Integer)
        'This is a thread in the current class. It can call methods from another class 
        ' - and pass many parameters instead of just one.  
        Dim clsOtherClass As New clsWork
        'If I call a shared sub or funtion, I don't need to instantiate the class as above.    
        clsOtherClass.subWorkloadInOtherClass(intNumber, dd)
    End Sub
    Private Sub subDelegated(ByVal resulttext As String)
        If Me.Label1.InvokeRequired Then
            Dim d As New dDelegate(AddressOf subDelegated)
            Me.Invoke(d, New Object() {resulttext})
        Else
            Me.Label1.Text = resulttext
        End If
    End Sub

End Class
Public Class clsWork
    Public Sub subWorkloadInOtherClass(ByVal intNumber As Object, ByVal dele As Form1.dDelegate)
        If TypeOf intNumber Is Integer Then
            Dim resulttext As String = Form1.Label1.Text
            Dim i As Integer = 0
            For i = 1 To intNumber
                resulttext = resulttext & " " & Form1.TextBox1.Text
                dele.Invoke(resulttext)
                Thread.Sleep(500)
            Next
        End If
    End Sub
End Class

Open in new window


This seems to work OK.  But as I am new to this, I'd like you to look it over and tell me if it is OK to do it this way or whether I am asking for trouble.  

I am going to try and use this method in my main app now.  

Thanks for your help

John
My understanding of delegates and threading is based on C# and I do not think that it makes any difference if you call a delegate from another class or same class as long as the delegate and the target method both are accessible to the calling function, it should not be an issue (And of course target method is visible to delegate).

My snippet would not work across the classes as they were both marked Private. Mark them Public and see the magic.
Avatar of John

ASKER

I will try that on monday when I'm, back at work.  thanks
Awaiting user comment