Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
721 views
in Technique[技术] by (71.8m points)

vb.net - InvalidCastException with WebBrowser.IsBusy or ReadyState (VB .NET)

I was playing around with the method that was suggested as an answer to another of my questions (Automate website log-in and form filling?), and noticed something curious.

The answer to the above question was to use a series of javascript calls as URL's in order to fill in a web form and submit it. I have been trying to do this automatically inside a VB .NET program with no success.

The original example I was given doesn't work, presumably because you are waiting on the same thread as that in which the WebBrowser control is working:

WebBrowser1.Navigate("http://www.google.com")
Do While WebBrowser1.IsBusy OrElse WebBrowser1.ReadyState <> WebBrowserReadyState.Complete
    Threading.Thread.Sleep(1000)
Application.DoEvents()
Loop
WebBrowser1.Navigate("javascript:function%20f(){document.forms[0]['q'].value='stackoverflow';}f();")
Threading.Thread.Sleep(2000) 'wait for javascript to run
WebBrowser1.Navigate("javascript:document.forms[0].submit()")
Threading.Thread.Sleep(2000) 'wait for javascript to run

If you don't wait at all, it doesn't work either, of course. The URL you originally browse to is interrupted. But interestingly, you cannot perform the "navigations" to the javascript calls without delay, either.

So I've tried two other methods: using the DocumentCompleted event to wait to browse to the nest URL until the browser has finished loading the page. Unfortunately, DocumentCompleted does not always fire, and doesn't seem to fire after each javascript URL.

The second method I tried was to put the wait in a separate thread:

 Private Delegate Sub SetTextDelegate(ByVal TheText As String)
 Private Sub delSetText(ByVal TheText As String)
     WebBrowser1.Navigate(TheText)
 End Sub

 Private Sub BrowseTo(ByVal URL As String)
     If WebBrowser1.InvokeRequired Then
         Me.BeginInvoke(New SetTextDelegate(AddressOf delSetText), URL)
     Else
         WebBrowser1.Navigate(URL)
     End If
 End Sub

 Private Sub TargetURL()
   BrowseTo("http://www.google.com")
 End Sub

 Private Sub TypeSomethingIn()
     BrowseTo("javascript:function%20f(){document.forms[0]['g'].value='test';}f();")
 End Sub

 Private Sub SubmitForm()
     BrowseTo("javascript:document.forms[0].submit()")
 End Sub

 Private Sub Wait()
     While True
         If WebBrowser1.ReadyState = WebBrowserReadyState.Complete Then Exit Sub
         Threading.Thread.Sleep(100)
     End While
 End Sub

 Private Sub AutoBrowse()
     TargetURL()
     Wait()
     TypeSomethingIn()
     Wait()
     SubmitForm()
 End Sub

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
     Dim t As Threading.Thread
     t = New Threading.Thread(AddressOf AutoBrowse)
     t.Start()
 End Sub

The curious thing is that the check of ReadyState (or IsBusy, for that matter) in the wait loop will sometimes throw a InvalidCastException. Presumably calls to these are not thread safe? I have no idea. If I put the offending call inside a Try block, the wait loop just fails to work. In fact, it even seems the exception "persists" to screw everything up, because even stepping through the code with the try block Visual Studio freezes for a good 10 to 20 seconds (it does the same without the try block).

Any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

One of the most interesting issues I had experienced and which for I was not able to find a solution in inet - was problem related to WebBrowser control. The thing is that when I was trying to access the Document property of the WebBrowser control instance, I was getting "Invalid cast exception". The thing is that the WebBrowser control is designed to work in one thread. So to fix this you must only check the InvokeRequired property and if it's value is true, then call the logic from the delegate, given into browser.Invoke(...) method.

Source


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...