title: InvalidCastException with WebBrowser.IsBusy or ReadyState (VB .NET)
body: <p>I was playing around with the method that was suggested as an answer to another of my questions (<a href="https://stackoverflow.com/questions/1731752/automate-website-log-in-and-form-filling">Automate website log-in and form filling?</a>), and noticed something curious.</p>
  
  <p>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.</p>
  
  <p>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:</p>
  
  <pre><code>WebBrowser1.Navigate("http://www.google.com")
  Do While WebBrowser1.IsBusy OrElse WebBrowser1.ReadyState &lt;&gt; 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
  </code></pre>
  
  <p>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.</p>
  
  <p>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.</p>
  
  <p>The second method I tried was to put the wait in a separate thread:</p>
  
  <pre><code> 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
  </code></pre>
  
  <p>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).</p>
  
  <p>Any ideas?</p>