webbrowser auto navigation event - vb.net

I am using webbrowser to navigate to a website then automating the login. Everything works perfectly up until the point of the comment "Navigating Event" After entering one credential it will login and navigate to another website. After the event none of the code will work as it is not picking up the new site. I am using a waitforpageload() function to let me know when it is completed loading however when I check the url it is still pointing to the original site. Any ideas why it would be doing this and how to possibly get around it?
Private Property pageready As Boolean = False
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
waitforpageload()
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
'Navigation event happens here
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
waitforpageload()
End If
#Region "Page Loading Functions"
Private Sub waitforpageload()
AddHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If webBrowser1.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler webBrowser1.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
#End Region

Please, for the love of god, get rid of that waitforpageload() function! Using Application.DoEvents() is BAD PRACTICE and in a loop like that, will utilize 100% of your CPU!
The person who originally wrote that function (it's from another Stack Overflow post) clearly didn't know what he/she was doing at the time. Using Application.DoEvents() creates more problems than it solves, and should NEVER be used in anyone's code (it exists mostly because it is used by internal methods).
Refer to: Keeping your UI Responsive and the Dangers of Application.DoEvents for more info.
The WebBrowser has a dedicated DocumentCompleted event that is raised every time a page (or part of a page, such as an iframe) has been completely loaded.
To make sure that the page really is fully loaded, subscribe to the DocumentCompleted event and check if the ReadyState property is equal to WebBrowserReadyState.Complete.
To be able to run code more "dynamically" when the DocumentCompleted event is raised you can utilize lambda expressions as a way of creating inline methods.
In your case they can be used like this:
'Second step (these must always be in descending order since the first step must be able to reference the second, and so on).
Dim credentialHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser HASN'T finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, credentialHandler
'Entering username
If webpageelement.GetAttribute("name") = "Login_Id" Then
webpageelement.SetAttribute("value", "xxxxxxx")
End If
'Entering Password
If webpageelement.GetAttribute("name") = "Password" Then
webpageelement.SetAttribute("value", "xxxxxxxxx")
End If
'logging in
If webpageelement.GetAttribute("name") = "submit_button" Then
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
End Sub
'First step.
Dim loginHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, loginHandler
Dim allelements As HtmlElementCollection = webBrowser1.Document.All
For Each webpageelement As HtmlElement In allelements
'NPI #
If webpageelement.GetAttribute("name") = "Provider_Id" Then
webpageelement.SetAttribute("value", "xxxxxx")
'-- Why would you even wait in here?? There's no reason for you to wait after only changing an attribute since nothing is loaded from the internet.
End If
'Clicking enter to input NPI
If webpageelement.GetAttribute("name") = "submit1" Then
'Adding the event handler performing our next step.
AddHandler webBrowser1.DocumentCompleted, credentialHandler
webpageelement.InvokeMember("focus")
webpageelement.InvokeMember("click")
End If
Next
End Sub
'Add the event handler performing our first step.
AddHandler webBrowser1.DocumentCompleted, loginHandler
webBrowser1.Navigate("https://www.lamedicaid.com/sprovweb1/provider_login/provider_login.asp")
Now every time you need to wait for the document/website to be fully loaded, just declare a new lambda and add it as an event handler to DocumentCompleted:
Dim thirdStepHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(wsender As Object, we As WebBrowserDocumentCompletedEventArgs)
'If the WebBrowser hasn't finished loading, do not continue.
If webBrowser1.ReadyState <> WebBrowserReadyState.Complete Then Return
'Remove the event handler to avoid this code being called twice.
RemoveHandler webBrowser1.DocumentCompleted, thirdStepHandler
'Your goes code here...
End Sub
'To wait until performing the next step (be sure to do this BEFORE navigating):
AddHandler webBrowser1.DocumentCompleted, thirdStepHandler

Related

InvokeMember("click") does not trigger WebBrowser.DocumentCompleted event

This old unresolved question seems to relate most to my issue WebBrowser control not responding to InvokeMember("click")
The main difference is where the conversation petered out, my webpage does respond to ContentPlaceHolder1_btnComtrsView.click() correctly, where in the original question it did not.
I am trying to pull up a lat/long result after clicking the "View" button after entering in a value for COMTRS (use "M11S19E20" for example): https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx
I've got the 2 separate document completed event handlers working correctly and all of that. So is it possible to handle the event of the document updating after clicking view? My code does work if I just click once to load the page and click, and a second time to pull the data out.
WebBrowserTRS.ScriptErrorsSuppressed = True
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
WebBrowserTRS.Navigate("https://www.earthpoint.us/TownshipsCaliforniaSearchByDescription.aspx")
Private Sub ClickViewButton(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
If e.Url.ToString() = "about:blank" Then Return
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf ClickViewButton
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim elem_Input_Submit As HtmlElement = trsDoc.GetElementById("ContentPlaceHolder1_btnComtrsView")
trsDoc.GetElementById("ContentPlaceHolder1_Comtrs").InnerText = _comtrs
AddHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
elem_Input_Submit.InvokeMember("click")
End Sub
Private Sub GetLatLong(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
RemoveHandler WebBrowserTRS.DocumentCompleted, AddressOf GetLatLong
Dim trsDoc As HtmlDocument = WebBrowserTRS.Document
Dim centroidFound As Boolean = False
For Each el As HtmlElement In trsDoc.GetElementsByTagName("tr")
Dim val As String
For Each el1 As HtmlElement In el.GetElementsByTagName("TD")
val = el1.InnerText
If val IsNot Nothing AndAlso val.Contains("Centroid") Then
centroidFound = True
' ...
WebBrowserTRS = New WebBrowser
Return
End If
Next
Next
If Not centroidFound Then
MsgBox("Unable to parse the township and range.",
MsgBoxStyle.Information, "Error in location lookup")
End If
Cursor = Cursors.Default
toolstripViewMap.Enabled = True
End Sub

reread content of webbrowser window/wait for user input

In my program I want to give 2 input-fields within a webbrowser-window a value and then wait for the user to click a login button. After this, I want the program to break out of the loop when the screen contents "Welcome!" (which it contains after logging in).
But now the problem: When the values for username and password are set, the do-loop starts instantly. So even if I click the login-button, the loop still contains the content of the webpage before the button was clicked and it will loop forever.
How can I solve this? I thought about two ways so far:
Reread the html code after button clicked so the "Welcome!" will be inside the code and then the loop will break, or
Wait for the user to press the login-button.
But in both ways I have no real idea how to solve it.
WebBrowserWindow.WebBrowser1.Navigate("[...]")
Do
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then Exit Do
End If
Application.DoEvents()
Loop
If WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.ToString.Contains("Login") Then
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Application.DoEvents()
Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Put the code that should be executed when the user has logged in here.
MsgBox("it works")
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End If
WebBrowserWindow.Close()
Me.Close()
I noticed the problem when I tried to put the html code in a message box. It just contained the 'old' code.
Thanks in advance
The golden rule of WinForms is: NEVER, EVER use Application.DoEvents() to keep your UI responsive! If you need to use it then you are almost always doing something wrong (see: Keeping your UI Responsive and the Dangers of Application.DoEvents).
Heavy operations should never be done on the UI thread, but in a background thread. There are multiple ways of taking the work of the UI, for instance Tasks, Threads or using the BackgroundWorker.
HOWEVER in this case, you don't even need a loop. The WebBrowser has got a DocumentCompleted event that is raised every time a page (or an iframe inside the page) has loaded completely. Use that to know when to execute your code.
Having that said, here's how you'd migrate it to DocumentCompleted:
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Dim DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Put the code that should be executed when the user has logged in here.
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, DocumentCompletedHandler
'Any code put here won't wait for the user to log in, it wil be executed pretty much immediately.
Here's a little test project: http://www.mydoomsite.com/sourcecodes/WebBrowser_WaitForUserInteraction.zip
Ultimately, your entire code can be changed to:
WebBrowserWindow.WebBrowser1.Navigate("[...]")
Dim FirstDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub()
'Check if:
' - The web browser has finished loading.
' - WebBrowser1.Document is not Null.
' - WebBrowser1.Document.Body is not Null.
' - WebBrowser1.Document.Body.InnerHtml is not Null.
' - WebBrowser1.Document.Body.InnerHtml contains "Login".
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then
'The code put in here will execute when the page loads the first time, and the above conditions are met.
'We are at the login page. Enter the credentials.
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
Dim SecondDocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler = _
Sub(dcsender As Object, dcargs As WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler
'The code put in here will be executed after the user has pressed "Login".
MsgBox("it works")
WebBrowserWindow.Close()
Me.Close()
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, SecondDocumentCompletedHandler 'Add the second DocumentCompleted event handler.
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler 'Remove the first DocumentCompleted event handler.
End If
End Sub
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, FirstDocumentCompletedHandler
'Again, any code put here will execute almost immediately, thus NOT waiting for the page to load.
Alternatively
...if you think it's too messy having lambdas everywhere, you can fall back to using regular methods:
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
WebBrowserWindow.WebBrowser1.Navigate("[...]")
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted
End Sub
Private Sub WebBrowserWindow_FirstDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
'Check if:
' - The web browser has finished loading.
' - WebBrowser1.Document is not Null.
' - WebBrowser1.Document.Body is not Null.
' - WebBrowser1.Document.Body.InnerHtml is not Null.
' - WebBrowser1.Document.Body.InnerHtml contains "Login".
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso _
WebBrowserWindow.WebBrowser1.Document IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml IsNot Nothing AndAlso _
WebBrowserWindow.WebBrowser1.Document.Body.InnerHtml.Contains("Login") Then
'We are at the login page. Enter the credentials.
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("username").SetAttribute("value", sUser)
WebBrowserWindow.WebBrowser1.Document.Window.Frames(2).Document.GetElementById("password").SetAttribute("value", sPass)
AddHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted 'Add the second DocumentCompleted event handler.
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_FirstDocumentCompleted 'Remove the first DocumentCompleted event handler.
End If
End Sub
Private Sub WebBrowserWindow_SecondDocumentCompleted(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
If WebBrowserWindow.WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then
RemoveHandler WebBrowserWindow.WebBrowser1.DocumentCompleted, AddressOf WebBrowserWindow_SecondDocumentCompleted
'Put the code that should be executed when the user has logged in here.
MsgBox("it works")
WebBrowserWindow.Close()
Me.Close()
End If
End Sub

How to Know the Process Name at Process Exited Event

I run multiple exe with different names by using Process.start() and enables Raisingevents to True. To check the status of Process, I intimated User at Process Exited event and show a message to user.
But the problem is I want to show the particular Exe Name to User at that Exit event. My code for For process Start is:
Private Sub StartExe()
Private psi As ProcessStartInfo
Private cmd As Process
Dim filePath As String = "vision.exe"
psi = New ProcessStartInfo(filePath)
Dim systemencoding As System.Text.Encoding = _
System.Text.Encoding.GetEncoding(Globalization.CultureInfo.CurrentUICulture.TextInfo.OEMCodePage)
With psi
.Arguments = "Some Input String"
.UseShellExecute = False
.RedirectStandardError = True
.RedirectStandardOutput = True
.RedirectStandardInput = True
.CreateNoWindow = False
.StandardOutputEncoding = systemencoding
.StandardErrorEncoding = systemencoding
End With
cmd = New Process With {.StartInfo = psi, .EnableRaisingEvents = True}
AddHandler cmd.ErrorDataReceived, AddressOf Async_Data_Received
AddHandler cmd.OutputDataReceived, AddressOf Async_Data_Received
AddHandler cmd.Exited, AddressOf processExited
cmd.Start()
cmd.BeginOutputReadLine()
cmd.BeginErrorReadLine()
End Sub
'For Receiving the Output of Exe, I used a TextBox to view
Private Sub Async_Data_Received(ByVal sender As Object, ByVal e As DataReceivedEventArgs)
Me.Invoke(New InvokeWithString(AddressOf Sync_Output1), e.Data)
End Sub
Private Sub Sync_Output1(ByVal text As String)
txtLog.AppendText(text & Environment.NewLine)
End Sub
'At the Exit event, I inform the user that an Exe exited due to some reason etc.
Private Sub processExited(ByVal sender As Object, ByVal e As EventArgs)
Me.BeginInvoke(New Action(Function()
MessageBox.Show("The Stream for " &Particular Exe& "is Exited.", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End Function))
End Sub
At the Process Exited Event, how can I show name of that particular Exe which fired that event. Like in that particular code, I started an "vision.exe", So I want to inform the user that vision.exe is terminated due to some reason etc.
By the time the Exited event runs, the process is already dead and you cannot retrieve its properties anymore. Since you already use lambda expressions, you can solve this one too by writing one that captures the filePath variable. Like this:
AddHandler cmd.Exited,
Sub(s, e)
Me.BeginInvoke(New Action(
Sub()
MessageBox.Show(filePath + " has ended")
End Sub))
End Sub
Do beware that you'll have to keep your Form object alive until the process terminates or your own program exits. If you don't then the BeginInvoke() call is going to be made on a disposed form, also a problem in your original code. You can avoid this by checking Me.InvokeRequired. If it returns false then don't do anything.

Confusing System.NullReferenceException error on a defined variable - VB

Alright so I am new here so I apologize in advance if I post incorrectly or am a little vague. My problem is that I run into a NullReferenceException when I try to run my code but while debugging and hovering my mouse over the problematic variable, I do indeed see the value of the variable.
Here is the VB code that I am working with:
Private Sub Login_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles login.Click
status.Text = "Connecting...."
WebBrowser2.Navigate("http://*****.com/?op=login")
WebBrowser2.Document.GetElementById("loginUsername").InnerText = username.Text
WebBrowser2.Document.GetElementById("loginPassword").InnerText = password.Text
WebBrowser2.Document.GetElementById("loginSubmit").InvokeMember("click")
End Sub
Here is the snapshot of what is going on:
------------ EDIT : SOLUTION -------------------
WebBrowser2.Url = New Uri("http://*****.com/?op=login")
WaitForPageLoad() ' <---------- ADDED NEW FUNCTION TO WAIT FOR PAGE LOAD
WebBrowser2.Document.GetElementById("loginUsername").InnerText = username.Text
WebBrowser2.Document.GetElementById("loginPassword").InnerText = password.Text
WebBrowser2.Document.GetElementById("loginSubmit").InvokeMember("click")
status.Text = "Completed"
So I created a new function (credits go to BGM in How to wait until WebBrowser is completely loaded in VB.NET?) called WaitForPageLoad() which essentially loops through a check for the page to be ready and then once it is, is kills the handler so the login is successful and the page does not loop. Here is the WaitForPageLoad():
Private Property pageready As Boolean = False
Private Sub WaitForPageLoad()
AddHandler WebBrowser2.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
While Not pageready
Application.DoEvents()
End While
pageready = False
End Sub
Private Sub PageWaiter(ByVal sender As Object, ByVal e As WebBrowserDocumentCompletedEventArgs)
If WebBrowser2.ReadyState = WebBrowserReadyState.Complete Then
pageready = True
RemoveHandler WebBrowser2.DocumentCompleted, New WebBrowserDocumentCompletedEventHandler(AddressOf PageWaiter)
End If
End Sub
WebBrowser2.Navigate takes some time to load the document, but is asynchronous. That means that the next code gets executed before the document finishes loading.
Consequently, in the next line, GetElementById cannot yet find the target element and returns Nothing. To prevent this, you cannot execute code after calling Navigate – instead, you need to create an event handler for the event that is fired once the document finished loading, and execute the code there. – This is the DocumentCompleted event.
On that line in particular...
Document could be null
The result of GetElementById("loginUsername") could be null.
Why do you think that username is null?
I bet that WebBrowser2.Document.GetElementById("loginUsername") returns null.
The other possibility is Document to be null.

Vb.Net Wait for webbrowser finish navigate

How can i wait till webbrowser loaded the page?
i tried:
webbrowser1.navigate(url)
msgbox("done")
This is the approach I used when I was having the same problem. By adding a handler you dont have to use a timer to unnecessary processing instead the event will fire as soon as the document has loaded. Dont be fooled by the name documentcompleted, it's actually waiting for the webpage to load.
AddHandler (webbrowser1.DocumentCompleted), AddressOf WebpageLoaded
webbrowser1.Navigate(url)
Public Sub WebpageLoaded(sender As System.Object, e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
MessageBox.Show("Done")
End Sub
Im not saying this is the best way to go but it worked well for me :)
Do While wb.ReadyState <> WebBrowserReadyState.Complete
Application.DoEvents()
Loop
I inherit a new class from WebBrowser control:
Public Class WebBrowserSyncFW
Inherits WebBrowser
Public Async Function NavigateSync(ByVal urlString As String, Optional ByVal timeoutmillisec As Integer = 30000) As Task(Of Boolean)
Dim IsLoaded As Boolean = False
Me.ScriptErrorsSuppressed = True
Me.Navigate(urlString)
AddHandler Me.DocumentCompleted, Sub(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
IsLoaded = True
End Sub
For i = 1 To timeoutmillisec / 100
Await Task.Delay(100).ConfigureAwait(False)
If IsLoaded = True Then Return True
Next
Return False
End Function
End Class
Usage:
If Await WebBrowserSyncFW1.NavigateSync("http://www.youtube.com") Then
MsgBox("Page is loaded!", MsgBoxStyle.Information)
Else
MsgBox("Timeout!", MsgBoxStyle.Exclamation)
End If