I am trying to run some vb.net code that indicates if i'm connected to the internet
If My.Computer.Network.IsAvailable Then
MsgBox("Computer is connected.")
Else
MsgBox("Computer is not connected.")
End If
This works fine if I'm connecting to a WiFi signal that doesn't require a login. If I connect to a public WiFi signal that I'm required to login/pay and I execute the code before completing this step it still tells me I'm connected (in theory yes but without paying/logging in I'm not)
Any ideas how set this up?
Thanks
You could check for an internet connection by trying to read Google.com:
Public Shared Function CheckForInternetConnection() As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead("http://www.google.com")
Return True
End Using
End Using
Catch
Return False
End Try
End Function
Taken from: Here
I use this
Public Function HaveInternetConnection() As Boolean
Try
Return My.Computer.Network.Ping("www.google.com")
Catch
Return False
End Try
End Function
I create this class to track internet connection changes. This class can check the stable internet connections also (stable means, that the connection not change during N second). The class raise events, if the connection changes.
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports System.Text
Imports System.Collections.Generic
Imports System.Linq
Imports System.Net.NetworkInformation
Imports System.Net
Public Enum InternetConnectionState
Connected
Disconnected
End Enum
Public Class NetworkConnections
Implements IDisposable
Public Shared Property CheckHostName As String = "www.google.com"
Public Property ConnectionStableAfterSec As Integer = 10
Private MonitoringStarted As Boolean = False
Private StableCheckTimer As System.Threading.Timer
Private IsFirstCheck As Boolean = True
Private wConnectionIsStable As Boolean
Private PrevInternetConnectionState As InternetConnectionState = InternetConnectionState.Disconnected
Public Event InternetConnectionStateChanged(ByVal ConnectionState As InternetConnectionState)
Public Event InternetConnectionStableChanged(ByVal IsStable As Boolean, ByVal ConnectionState As InternetConnectionState)
Public Sub StartMonitoring()
If MonitoringStarted = False Then
AddHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
MonitoringStarted = True
NetworkAddressChanged(Me, Nothing)
End If
End Sub
Public Sub StopMonitoring()
If MonitoringStarted = True Then
Try
RemoveHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
Catch ex As Exception
End Try
MonitoringStarted = False
End If
End Sub
Public ReadOnly Property ConnectionIsStableNow As Boolean
Get
Return wConnectionIsStable
End Get
End Property
<DllImport("wininet.dll")> _
Private Shared Function InternetGetConnectedState(ByRef Description As Integer, ByVal ReservedValue As Integer) As Boolean
End Function
Private Shared Function IsInternetAvailable() As Boolean
Try
Dim ConnDesc As Integer
Dim conn As Boolean = InternetGetConnectedState(ConnDesc, 0)
Return conn
Catch
Return False
End Try
End Function
Private Shared Function IsInternetAvailableByDns() As Boolean
Try
Dim iheObj As IPHostEntry = Dns.GetHostEntry(CheckHostName)
Return True
Catch
Return False
End Try
End Function
Public Shared Function CheckInternetConnectionIsAvailable() As Boolean
Return IsInternetAvailable() And IsInternetAvailableByDns()
End Function
Private Sub NetworkAddressChanged(sender As Object, e As EventArgs)
wConnectionIsStable = False
StableCheckTimer = New System.Threading.Timer(AddressOf ElapsedAndStable, Nothing, New TimeSpan(0, 0, ConnectionStableAfterSec), New TimeSpan(1, 0, 0))
If IsFirstCheck Then
If CheckInternetConnectionIsAvailable() Then
PrevInternetConnectionState = InternetConnectionState.Connected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Connected)
Else
PrevInternetConnectionState = InternetConnectionState.Disconnected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Disconnected)
End If
IsFirstCheck = False
Else
If CheckInternetConnectionIsAvailable() Then
If PrevInternetConnectionState <> InternetConnectionState.Connected Then
PrevInternetConnectionState = InternetConnectionState.Connected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Connected)
End If
Else
If PrevInternetConnectionState <> InternetConnectionState.Disconnected Then
PrevInternetConnectionState = InternetConnectionState.Disconnected
RaiseEvent InternetConnectionStateChanged(InternetConnectionState.Disconnected)
End If
End If
End If
End Sub
Private Sub ElapsedAndStable()
If wConnectionIsStable = False Then
wConnectionIsStable = True
Dim hasnet As Boolean = CheckInternetConnectionIsAvailable()
RaiseEvent InternetConnectionStableChanged(True, IIf(hasnet, InternetConnectionState.Connected, InternetConnectionState.Disconnected))
End If
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
Try
RemoveHandler NetworkChange.NetworkAddressChanged, AddressOf NetworkAddressChanged
Catch ex As Exception
End Try
End If
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
' ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
' Dispose(False)
' MyBase.Finalize()
'End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class
Track changes on a form with 2 listbox. Important! The events are thread unsafe, that need to be handle with invoke method.
Imports System.Net.NetworkInformation
Imports System.Net
Public Class frmNetworkConnections
Private WithEvents conn As NetworkConnections
Delegate Sub AddToList1Callback(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
Delegate Sub AddToList2Callback(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
conn = New NetworkConnections
End Sub
Sub AddToList1(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
If Me.InvokeRequired = True Then
Dim d As New AddToList1Callback(AddressOf AddToList1)
Me.Invoke(d, ConnectionState, IsStable)
Else
ListBox1.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
End If
End Sub
Sub AddToList2(ByVal ConnectionState As InternetConnectionState, ByVal IsStable As Boolean)
If Me.InvokeRequired = True Then
Dim d As New AddToList2Callback(AddressOf AddToList2)
Me.Invoke(d, ConnectionState, IsStable)
Else
ListBox1.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
ListBox2.Items.Add(Now & " - State: " & ConnectionState.ToString() & ", Stable: " & IsStable)
End If
End Sub
Private Sub conn_InternetConnectionStableChanged(IsStable As Boolean, ConnectionState As InternetConnectionState) Handles conn.InternetConnectionStableChanged
AddToList2(ConnectionState, IsStable)
End Sub
Private Sub conn_InternetConnectionStateChanged(ConnectionState As InternetConnectionState) Handles conn.InternetConnectionStateChanged
AddToList1(ConnectionState, False)
End Sub
Private Sub btnStartMonitoring_Click(sender As Object, e As EventArgs) Handles btnStartMonitoring.Click
btnStopMonitoring.Enabled = True
btnStartMonitoring.Enabled = False
conn.StartMonitoring()
End Sub
Private Sub btnStopMonitoring_Click(sender As Object, e As EventArgs) Handles btnStopMonitoring.Click
btnStopMonitoring.Enabled = False
btnStartMonitoring.Enabled = True
conn.StopMonitoring()
End Sub
End Class
The result is:
I use the stable connection changes.
If you dont want to track changes, only check the connection, you can use the CheckInternetConnectionIsAvailable() shared function.
You could use the Ping class to try to reach a host in the Internet. In order not to wait too long, you should set a timeout when using Send.
A good way to check if the user is connected to the internet is
If My.Computer.Network.Ping("www.google.com") Then
MsgBox("Computer is connected to the internet.")
End If
You can also use this code, however it's slower
Public Shared Function CheckForInternetConnection() As Boolean
Try
Using client = New WebClient()
Using stream = client.OpenRead("http://www.google.com")
Return True
End Using
End Using
Catch
Return False
End Try
End Function
***** Best *****
The best Code For it, it not make any bug or Any slow.
Button Or Timer .. Etc
Try
If My.Computer.Network.Ping("www.google.com") Then
Label1.Text = "Internet Founded"
End If
Catch ex As Exception
'' Else ''
Label1.Text = "No internet Acess"
End Try
At least hope you gave me that
"Question Answer", it the best solution .Thanks.
(you can try it out)
Try
Dim client = New Net.WebClient
client.OpenRead("http://www.google.com")
Label21.Text = "Internet : Connected"
Catch
Label21.Text = "Internet : Disconnected"
End Try
Use this code in vb.net 100% solved, you can use this code form loading.
I am using this code and is working very well:
Public Function IsConnectedToInternet() As Boolean
If My.Computer.Network.IsAvailable Then
Try
Dim IPHost As IPHostEntry = Dns.GetHostEntry("www.google.com")
Return True
Catch
Return False
End Try
Else
Return False
End If
End Function
My.Computer.Network.Ping gave me problems so I used this function
Public Function fVerificaConnessioneInternet() As Boolean
Dim objPing As New System.Net.NetworkInformation.Ping
Try
Return If(objPing.Send("www.google.it").Status = IPStatus.Success, True, False)
Catch
Return False
End Try
End Function
or you could use this, a little better function to use. this should help you out if you need a c# version
http://www.guideushow.com/code-snippet/function-to-check-if-you-can-connect-to-the-internet-vb-net-c/
Public Function IsConnectionAvailable() As Boolean
' Returns True if connection is available
' Replace www.yoursite.com with a site that
' is guaranteed to be online - perhaps your
' corporate site, or microsoft.com
Dim objUrl As New System.Uri("http://www.google.com/")
' Setup WebRequest
Dim objWebReq As System.Net.WebRequest
objWebReq = System.Net.WebRequest.Create(objUrl)
objWebReq.Proxy = Nothing
Dim objResp As System.Net.WebResponse
Try
' Attempt to get response and return True
objResp = objWebReq.GetResponse
objResp.Close()
objWebReq = Nothing
Return True
Catch ex As Exception
' Error, exit and return False
objResp.Close()
objWebReq = Nothing
Return False
End Try
End Function
Related
I have been trying to find a solution to why the ExitTool I am using is not properly closing out after I close the main application. What is happening is that when I close my application, the ExifTool stays running in the background and I have to manually kill it.
Here is the code snippet of the process startup.
Public Shared Sub ExecuteExifTool()
If ExifToolStarted Then Exit Sub
ExifToolStarted = True
Dim NowString As String = Date.Now.ToString("yyyyMMddHHmmss")
If Not IO.Directory.Exists(".\Runtime") Then IO.Directory.CreateDirectory(".\Runtime")
Dim GetDirectory As New IO.DirectoryInfo(".\Runtime")
If GetDirectory.GetFiles.Count > 0 Then
For Each i As IO.FileInfo In GetDirectory.GetFiles
If i.FullName.Contains("exif.Yv") AndAlso i.FullName.Contains("-cL") AndAlso i.FullName.Contains(".exe") Then : Try : i.Delete() : Catch : End Try : End If
Next
End If
HostName = ".\Runtime\exif.Yv" & NowString.Substring(0, 8) & "-cL" & NowString.Substring(8, 6) & ".exe"
IO.File.Copy(".\exiftool.exe", HostName)
Using ExifToolProcess As New Process
With ExifToolProcess
.StartInfo.RedirectStandardInput = True
.StartInfo.FileName = HostName
.StartInfo.UseShellExecute = False
.StartInfo.Arguments = "-stay_open" & " True -# " & "-"
.StartInfo.RedirectStandardOutput = True
.StartInfo.RedirectStandardError = True
.StartInfo.CreateNoWindow = True
.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
.Start()
.BeginOutputReadLine()
.BeginErrorReadLine()
End With
End Using
End Sub
The latest attempt to solve this issue was to try and launch another executable application; which essentially, is another Windows.Forms.Form that waits for the main application to close and then it will attempt to kill the process immediately afterwards, then dispose of itself. Here is the snippet.
Public Class KillProcess
Private _ProcessName As String
Public Property ProcessName As String
Get
Return _ProcessName
End Get
Set(value As String)
_ProcessName = value
End Set
End Property
Private _MainApp As Form
Public Property MainApplication As Form
Get
Return _MainApp
End Get
Set(value As Form)
_MainApp = value
End Set
End Property
Private Sub KillProcess_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CleanupProcess()
End Sub
Public Sub CleanupProcess()
While Not MainApplication.IsDisposed
Dim FilesToDelete As New List(Of String)
Dim ProcessesToKill As New List(Of Process)
For Each p As Process In Process.GetProcesses
If p.ProcessName = ProcessName Then
FilesToDelete.Add(p.MainModule.FileName)
ProcessesToKill.Add(p)
End If
Next
For Each p As Process In ProcessesToKill
Try
p.Kill()
p.WaitForExit(10000)
p.Close()
Catch winException As System.ComponentModel.Win32Exception
Catch invalidException As InvalidOperationException
End Try
Next
End While
Me.Dispose()
End Sub
End Class
And here is the code snippet of the startup.
Public Sub CleanupTask()
Dim Handler As New Custodian.KillProcess With {.ProcessName = ExifToolHooker.HostName, .MainApplication = Me}
Windows.Forms.Application.Run(Handler)
End Sub
Private Sub CloseApplication(sender As Object, e As FormClosingEventArgs) Handles Me.Closing
Dim TaskHandler As Thread = New Thread(AddressOf CleanupTask)
TaskHandler.SetApartmentState(ApartmentState.STA)
TaskHandler.Start()
...
End Sub
I have an app that connects a Windows VPN (not OpenVPN) using the rasphone.exe interface. I can successfully establish the connection but It prompts for the password each time. Is there a way to get the interface to remember the password so that if the connection is lost the connection can automatically be re-established programatically? As a note when I start the process for rasphone.exe I'm getting exceptions when I try to pass more than 1 parameter to it. The only parameter I can successfully pass is the entry name, I can't add parameters like -d, -h, or -f.
Here is the code I have:
Imports System.Linq
Imports System.Net.NetworkInformation
Public Class clsVPN
Public Delegate Sub delPing()
Public Delegate Sub delConnect()
Public Delegate Sub delIdle()
Public Delegate Sub delDisconnect()
Public Delegate Sub delStatus(blnConnected As Boolean)
Public Event Ping As delPing
Public Event Con As delConnect
Public Event Discon As delDisconnect
Public Event Idle As delIdle
Public Event StatusChanged As delStatus
Public strRASPhone As String = "C:\WINDOWS\system32\rasphone.exe"
Public strIPAddress As String = ""
Public strVPNCon As String = ""
Public blnConnected As Boolean = False
Dim file As String = "C : \Users\Tom\AppData\Roaming\Microsoft\Network\Connections\Pbk\rasphone.pbk"
Protected Sub OnStatusChanged(blnConnected As Boolean)
RaiseEvent StatusChanged(blnConnected)
End Sub
Protected Sub OnDisconnect()
RaiseEvent Discon()
End Sub
Protected Sub OnPing()
RaiseEvent Ping()
End Sub
Protected Sub OnIdle()
RaiseEvent Idle()
End Sub
Protected Sub OnConnect()
RaiseEvent Con()
End Sub
Public ReadOnly Property Connected() As Boolean
Get
Return blnConnected
End Get
End Property
Public Property ConName() As String
Get
Return strVPNCon
End Get
Set(strValue As String)
strVPNCon = strValue
End Set
End Property
Public Function Test() As Boolean
Dim blnSucceed As Boolean = False
OnPing()
Dim p As New Ping()
If p.Send(strIPAddress).Status = IPStatus.Success Then
blnSucceed = True
Else
blnSucceed = False
End If
p = Nothing
If blnSucceed <> blnConnected Then
blnConnected = blnSucceed
OnStatusChanged(blnConnected)
End If
OnIdle()
Return blnSucceed
End Function
Public Function Connect() As Boolean
Dim blnSucceed As Boolean = False
Dim optionstr As String = "-f " & file & " -d "
OnConnect()
'MessageBox.Show("strVPNCon = " )
'Process.Start(strRASPhone, Convert.ToString(" -f ") & file & Convert.ToString(" -d ") _
' & strVPNCon)
optionstr = ""
Dim wait As Boolean = True
ProcessExec(strRASPhone, optionstr & strVPNCon, wait)
Application.DoEvents()
System.Threading.Thread.Sleep(5000)
Application.DoEvents()
blnSucceed = True
OnIdle()
Return blnSucceed
End Function
Public Function Disconnect() As Boolean
Dim blnSucceed As Boolean = False
Dim optionstr As String = "-h "
OnDisconnect()
optionstr = ""
Dim wait As Boolean = True
ProcessExec(strRASPhone, optionstr & strVPNCon, wait)
Application.DoEvents()
System.Threading.Thread.Sleep(8000)
Application.DoEvents()
blnSucceed = True
OnIdle()
Return blnSucceed
End Function
Public Function CheckConnection() As Boolean
Dim niVPN As NetworkInterface() =
NetworkInterface.GetAllNetworkInterfaces
Dim blnExist As Boolean =
niVPN.AsEnumerable().Any(Function(x) x.Name = ConName)
If blnExist Then
'MessageBox.Show("VPN Exists")
Else
' MessageBox.Show("VPN Does Not Exist")
End If
Return blnExist
End Function
Public Sub ProcessExec(processarg As String, param As String, wait As Boolean)
' Start the child process.
Dim p As New ProcessStartInfo
' Redirect the output stream of the child process.
p.FileName = processarg
p.Arguments = param
p.UseShellExecute = True
p.WindowStyle = ProcessWindowStyle.Normal
Dim proc As Process = Process.Start(p)
' Do Not wait for the child process to exit before
' reading to the end of its redirected stream.
If wait = True Then
proc.WaitForExit()
End If
End Sub
End Class
I know this was asked more than one year before.
I suppose that the described problem is not caused of the Visual Basic code. The problem may be caused from the file rasphone.pbk. It is generally contained in
%APPDATA%\Microsoft\Network\Connections\Pbk
This file can be read with a text editor. There exist an option PreviewUserPw after [YOURVPNNAME]. The value 1 generates a prompting before dialing in.
Changing of this line to
PreviewUserPw=0
will help.
I have some problem and couldn't see so far what i am doing wrong. My application user can open some form multiple times and within each of it i want to make ping time to time to some remote host then show status on status bar, therefore to not block main thread and ui i decided to go asyn/await. Unfortunetly within 'DoWork' method 'StartNew' is highlited within this line:
Await Task.Factory.StartNew(IsDestinationReachable(IPAddress))
Severity Code Description Project File Line Suppression State
Error BC36645 Data type(s) of the type parameter(s) in method 'Public
Overloads Function StartNew(Of TResult)([function] As Func(Of
TResult)) As Task(Of TResult)' cannot be inferred from these
arguments. Specifying the data type(s) explicitly might correct this
error.
And by the way is it right way i am doing it? Check my code below:
Public Class FrmDrukujEtykiete
Private Property IPAddress As String
Private WithEvents mytimer As Timer
Sub New(ipaddress As String)
InitializeComponent()
AddHandler mytimer.Tick, AddressOf dowork
mytimer.Interval = 6000
mytimer.Enabled = True
mytimer.Start()
Me.IPAddress = ipaddress
End Sub
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim MMOO As Task(Of Boolean) = Await Task.Factory.StartNew(IsDestinationReachable(IPAddress))
If MMOO.Result Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Function IsDestinationReachable(ByVal hostnameOrAddress As String) As Boolean
Dim reachable As Boolean = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(hostnameOrAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function
End Class
EDIT:
i think i was able to make it happen - one thing which still considering me is why when user opening new form before it show up its about 4 seconds... second thing is it correct - i mean can you check my code is there any wrong task conception usage? Generally working...
Public Class FrmDrukujEtykiete
Private etykieta As New Etykieta
Private Property IPAddress As String
Private WithEvents mytimer As New Timer
Sub New(ipaddress As String)
InitializeComponent()
Me.IPAddress = ipaddress
AddHandler mytimer.Tick, AddressOf dowork
mytimer.Interval = 6000
mytimer.Enabled = True
mytimer.Start()
DoSomethingElse()
End Sub
Private Sub DoSomethingElse()
For i = 1 To 100000
' Threading.Thread.Sleep(1000)
ListBox1.Items.Add(i)
Next
End Sub
Private Sub btnWyjdz_Click(sender As Object, e As EventArgs) Handles btnWyjdz.Click
Close()
End Sub
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim tsk As Task(Of Boolean) = Task.Factory.StartNew(Of Boolean)(Function()
'--Run lenghty task
Dim reachable = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(IPAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function)
Await tsk
ListBox2.Items.Add("a teraz zmiana")
If tsk.Result Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Function IsDestinationReachable(ByVal hostnameOrAddress As String)
Dim reachable = False
Try
reachable = My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(hostnameOrAddress)
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function
End Class
Your updated code is not typically how you would use Async/Await. More usual would be something like:
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim isReachable As Boolean = Await Task.Factory.StartNew(Function() IsDestinationReachable(IPAddress))
If isReachable Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
The Await suspends the method until the task completes and then returns the result of the task, so there is no need to hold onto the Task object and use .Result. While the method is suspended, execution of the non-Awaiting code continues on the main thread, and the method is resumed on the main thread when the async method completes.
However, since network IO is naturally async, you would be better off using the Ping.SendPingAsync method instead of Task.Factory.StartNew. That would be something like this (untested code):
Public Async Sub dowork(sender As Object, e As EventArgs)
Dim isReachable As Boolean = Await IsDestinationReachable(IPAddress)
If isReachable Then
tsPingResultIcon.BackColor = Color.Green
tsPingResultIcon.Text = "OK - Remote ip reachable"
Else
tsPingResultIcon.BackColor = Color.Red
tsPingResultIcon.Text = "NOT OK - Remote ip NOT reachable"
End If
End Sub
Public Async Function IsDestinationReachable(ByVal hostnameOrAddress As String) As Boolean
Dim reachable As Boolean = False
Try
If My.Computer.Network.IsAvailable Then
Dim pinger As Ping = New Ping()
Dim result As PingReply = Await pinger.SendPingAsync(hostnameOrAddress)
reachable = result.Status = IPStatus.Success
End If
Catch pingException As System.Net.NetworkInformation.PingException
Catch genericNetworkException As System.Net.NetworkInformation.NetworkInformationException
' Fail silently and return false
End Try
Return reachable
End Function
I've defined a SerialPort object as the following:
Public WithEvents SerialComm As New System.IO.Ports.SerialPort
SerialComm is setup and opened in the object constructor and closed when the object is disposed. My handler signature is as follows:
Private Sub OnComm(sender as Object, e as SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
I'm trying to get a DataReceived event to fire from HyperTerminal. After sending some data, I can set a breakpoint and check the value of SerialComm.BytesToRead and see that it has updated to the proper number of bytes.
I have confirmed that the SerialPort is open and is receiving data, but I can't get the event to fire.
I've also tried manually wiring up the event (after removing the WithEvents definition) using AddHandler, but I was still unable to get the event to trigger.
What am I missing?
Update:
This is the class that I'm having trouble with:
Imports System.IO.Ports
Public Class CopyCat
Implements IDisposable
Private RxString As String
Private LastReceiveTime As DateTime
Public WithEvents SerialComm As New SerialPort
Public Property Timeout As TimeSpan
Public Sub New(commPort As String, timeout As TimeSpan)
Me.Timeout = timeout
Enable(commPort)
End Sub
Public Sub New(commPort As String)
Me.New(commPort, TimeSpan.FromMilliseconds(1000))
End Sub
Public Sub Enable()
CommUtilities.SetupComm(SerialComm, commPort, 115200, 8, Parity.Odd, StopBits.One, Handshake.None, System.Text.Encoding.Default)
End Sub
Public Sub Disable()
SerialComm.Close()
End Sub
Private Sub OnComm(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
If(DateTime.Now - LastReceivedTime > Timeout) Then RxString = ""
Do While(SerialComm.BytesToRead > 0)
Dim readChar As String
Dim termChar As Char = Chr(RxString.ToByteList().XorAll())
readChar = SerialComm.ReadChar
RxString &= readChar
if (readChar = termChar) Then
SerialComm.Write((From item In GetResponse(RxString).Build()
Select item.Data).ToRawString)
RxString = ""
End If
Loop
End Sub
Public Function GetResponse(commandString As String) As MessageResponse
Dim response As MessageResponse = MessageResponse.GetMessageResponseFromByteList(commandString.ToByteList())
if (response.GetType = GetType(GetStatusResponse)) Then
response.DataBytes(8).Data = Math.Floor(Rnd() * 255)
response.DataBytes(9).Data = Math.Floor(Rnd() * 255)
End If
Return response
End Function
Private disposedValue as Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
SerialComm.Dispose()
End If
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class
I have a feature whereby a class in a dll displays a form asking a user to clear a fault on a printer before clicking a button to say "Retry". The users have been just hitting retry without bothering to clear the fault so I am now coding an interlock:
The button on the invoked form is disabled until a call is made to an 'enable' method on the form.
This is done with delegate invocation as the events triggering these changes come from other dlls running on different threads.
The form's 'enable' method is wired into an EVENT HANDLER handling an event coming in from a different thread (one that monitors an ethernet IO Server).
The problem I have is that THE "_Fault_StateChanged" EVENT NEVER FIRES. I suspected the cause was the "ShowDialog" and "DialogResult" technique I have used here, but I have used this exact same technique elsewhere in this application.
Any suggestions would be great
See code extract below:
MAIN CLASS excerpt
Public Class StatePrintHandler
Private WithEvents _RetryForm As frmRetryReject
Private Delegate Sub delShowRetryDialog()
Private Delegate Sub delResetEnable()
Private Sub InvokeResetEnable()
Dim del As delResetEnable
del = New delResetEnable(AddressOf ResetEnable)
del.Invoke()
End Sub
Private Sub InvokeRetryDialogue()
Dim del As delShowRetryDialog
del = New delShowRetryDialog(AddressOf ShowRetryDialog)
del.Invoke()
End Sub
Private Sub ShowRetryDialog()
_RetryForm = New frmRetryReject
_RetryForm.Prep()
_RetryForm.ShowDialog()
If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
Me._RetryForm.Visible = False
End If
End Sub
Private Sub ResetEnable()
If (Not IsNothing(_RetryForm)) Then
_RetryForm.ResetEnable()
Else
AuditTrail("Retry form not active, no action", True)
End If
End Sub
'Event handler for status change coming in on a different thread
Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
If (e.NewState) Then
AuditTrail("Labeller has faulted out during cycling", True)
Else
InvokeResetEnable()
End If
End Sub
End Class
RETRY FORM CLASS excerpt
Public Class frmRetryReject
Private Delegate Sub delEnable()
Public Event Complete()
Public Sub Prep()
Me.OK_Button.Enabled = False
End Sub
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.OK
Me.Close()
End Sub
Public Sub ResetEnable()
If (IsHandleCreated) Then
Dim params() As Object = {}
Me.Invoke(New delEnable(AddressOf InvokeEnable), params)
End If
End Sub
Private Sub InvokeEnable()
Me.OK_Button.Enabled = True
End Sub
End Class
Additional detail in response to Daniel's comments
The code is incomplete here, it's an excerpt. The fault object is a subscription to an external library and is a handler for an ethernet IO server.
The _fault StateChanged event fires when a digital input on an IOServer changes. I know the following:
My trace files show the signal change high, this invokes the retry form.
The signal physically changes low again when the retry screen is still showing.
...but the event does not fire
It's as if the application cannot service the event coming in until the ShowDialog/DialogResult completes - but I am confused about this because I understood that the ShowDialog in .NET 2.0 did not block, I should still be able to service events, and have used this same pattern elsewhere in the app.
A couple of things to note:
The MAIN CLASS is instantiated dynamically at runtime via reflection based on configuration.
This is VS2005 SP2
I will post the entire class in another code box if this helps, but it may crowd the scene...
Thanks
Andy
Imports System.IO
Imports ACS.Interfaces
Imports ACS.Pallet
Public Class StateCimPAKPrintHandler
Inherits StateBase
Private WithEvents _ioManager As ACS.Components.DigitalIOManager
Private _config As StateCimPAKPrintHandlerBootstrap
Private CONST_OutcomeOK As String = "OK"
Private CONST_OutcomeRetry As String = "Retry"
Private CONST_OutcomeException As String = "Exception"
Private WithEvents _busy As ACS.Drivers.Common.InputSignal
Private WithEvents _fault As ACS.Drivers.Common.InputSignal
Private WithEvents _print As ACS.Drivers.Common.OutputSignal
Private WithEvents _palletRelease As ACS.Drivers.Common.OutputSignal
Private _labellingInProgress As Boolean
Private _faulted As Boolean
Private _retryScreenInvoked As Boolean
Private WithEvents _timeout As System.Timers.Timer
Private WithEvents _faultTimer As System.Timers.Timer
Private WithEvents _RetryForm As frmRetryReject
Private Delegate Sub delShowRetryDialog()
Private Delegate Sub delResetEnable()
Private Sub InvokeResetEnable()
Dim del As delResetEnable
del = New delResetEnable(AddressOf ResetEnable)
del.Invoke()
End Sub
Private Sub InvokeRetryDialogue()
Dim del As delShowRetryDialog
del = New delShowRetryDialog(AddressOf ShowRetryDialog)
del.Invoke()
End Sub
Private Sub ShowRetryDialog()
_timeout.Stop()
_retryScreenInvoked = True
_RetryForm = New frmRetryReject
_RetryForm.Prep()
AuditTrail("Displaying Retry screen", True)
_RetryForm.ShowDialog()
If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
AuditTrail("User clicked RETRY LINE on the RETRY dialogue", True)
_retryScreenInvoked = False
Me._RetryForm.Visible = False
Me.SetOutcome(CONST_OutcomeRetry)
End If
End Sub
Private Sub ResetEnable()
If (Not IsNothing(_RetryForm)) Then
_RetryForm.ResetEnable()
Else
AuditTrail("Retry form not active, no action", True)
End If
End Sub
Public Sub New(ByVal Sequencer As ISequencer, ByVal ParentPlt As ACS.Interfaces.IPallet, ByVal Name As String)
MyBase.New(Sequencer, ParentPlt, Name)
_timeout = New System.Timers.Timer
_faultTimer = New System.Timers.Timer
_config = New StateCimPAKPrintHandlerBootstrap(Me._myIniFileName, Name)
_timeout.Interval = _config.CycleTimeoutMS
_faultTimer.Interval = 750
_retryScreenInvoked = False
_RetryForm = New frmRetryReject
Me._RetryForm.Visible = False
_ioManager = ACS.Components.DigitalIOManager.GetInstance
_busy = _ioManager.GetInput("Busy")
_fault = _ioManager.GetInput("CimPAKFault")
_print = _ioManager.GetOutput("Print")
_palletRelease = _ioManager.GetOutput("PalletRelease")
End Sub
Public Overrides Sub Kill()
_ioManager = Nothing
_RetryForm = Nothing
_busy = Nothing
_fault = Nothing
_print = Nothing
_timeout = Nothing
_faultTimer = Nothing
_pallet = Nothing
End Sub
Public Overrides Sub Execute()
AuditTrail("Pulsing Print Signal", True)
_print.PulseOutput(3000)
_labellingInProgress = True
_timeout.Start()
End Sub
Private Sub _busy_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _busy.StateChanged
_timeout.Stop()
AuditTrail("Busy signal changed to : " & e.NewState, True)
If (e.NewState) Then
_faulted = False
AuditTrail("CimPAK = Busy High", True)
_labellingInProgress = True
Else
AuditTrail("CimPAK = Busy Low", True)
AuditTrail("Wait 750 milliseconds for any faults", True)
_faultTimer.Start()
End If
End Sub
Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
AuditTrail("Fault signal changed to : " & e.NewState, True)
If (e.NewState) Then
If (_labellingInProgress = True) Then
AuditTrail("Labeller has faulted out during cycling", True)
_faulted = True
If (Not _retryScreenInvoked) Then
InvokeRetryDialogue()
End If
Else
AuditTrail("Labeller has faulted out between cycles, no action can be taken", True)
End If
Else
If (_retryScreenInvoked) Then
AuditTrail("Enable button on Retry screen", True)
InvokeResetEnable()
End If
_faulted = False
End If
End Sub
Private Sub _faultTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _faultTimer.Elapsed
_faultTimer.Stop()
If (_faulted) Then
AuditTrail("System has faulted", True)
Else
AuditTrail("No fault occured, assume pallet is OK to release", True)
AuditTrail("CimPAK cycle complete", True)
_labellingInProgress = False
_palletRelease.PulseOutput(3000)
Me.SetOutcome(CONST_OutcomeOK)
End If
End Sub
Private Sub _timeout_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timeout.Elapsed
_timeout.Stop()
AuditTrail("Labeller print cycle timed out", True)
If (Not _retryScreenInvoked) Then
_retryScreenInvoked = True
InvokeRetryDialogue()
InvokeResetEnable()
End If
End Sub
End Class
#Region "Bootstrap"
Public Class StateCimPAKPrintHandlerBootstrap
Private Const CONST_CycleTimeoutMS As String = "CycleTimeoutMS"
Private _CycleTimeoutMS As Long
#Region "Properties"
Public ReadOnly Property CycleTimeoutMS() As Long
Get
Return _CycleTimeoutMS
End Get
End Property
#End Region
Public Sub New(ByVal IniFile As String, ByVal Name As String)
Try
Dim _cfgFile As String = Environ("ACSVAR") & "\" & IniFile
' Check to see if the CFG file exits
If File.Exists(_cfgFile) = False Then
Throw New Exception("Configuration file does not exist: " & _cfgFile)
Else
'Get values
_CycleTimeoutMS = ACS.Utility.Configuration.GetLong(_cfgFile, Name, CONST_CycleTimeoutMS)
End If
Catch ex As Exception
Throw
End Try
End Sub
End Class
#End Region
Try to look at
Visual Basic, Child Thread Blocking Main Thread
answer for in Multithreading example and
New Thread is still blocking UI-Thread
answer from ( me ) for In Model Threading.... Those 2 should give you writen code to start aswell.
It's been a long time since I did any Winforms work, but are you showing the dialog modally? Because that could be the cause of the delegate invokation not arriving.
Asynchronous delegates work by serializing the invokation details into a memory location internal to the framework and then posting a window message to the top-level window for the relevant thread. Modal dialogs work by going into a message processing loop that steals all the messages for the thread so that only that one dialog can respond. You can see how this might conflict.