2009-12-16 6 views
2

Je jouais avec la méthode qui a été suggérée comme une réponse à une autre de mes questions (Automate website log-in and form filling?), et j'ai remarqué quelque chose de curieux.InvalidCastException avec WebBrowser.IsBusy ou ReadyState (VB .NET)

La réponse à la question ci-dessus consistait à utiliser une série d'appels javascript comme URL afin de remplir un formulaire Web et de le soumettre. J'ai essayé de le faire automatiquement dans un programme VB .NET sans succès.

L'exemple d'origine m'a donné ne fonctionne pas, sans doute parce que vous êtes en attente sur le même fil que celui dans lequel le contrôle WebBrowser fonctionne:

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 

Si vous n'attendez pas du tout, ça ne marche pas non plus, bien sûr. L'URL à laquelle vous avez accédé à l'origine est interrompue. Mais, chose intéressante, vous ne pouvez pas non plus effectuer les "navigations" des appels javascript.

J'ai donc essayé deux autres méthodes: utiliser l'événement DocumentCompleted pour attendre que l'explorateur ait fini de charger la page. Malheureusement, DocumentCompleted ne se déclenche pas toujours et ne semble pas se déclencher après chaque URL javascript.

La deuxième méthode que j'ai essayé était de mettre l'attente dans un thread séparé:

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 

La chose curieuse est que le chèque de ReadyState (ou IsBusy, pour cette matière) dans la boucle d'attente va parfois jeter une InvalidCastException. Probablement les appels à ceux-ci ne sont pas thread safe? Je n'ai aucune idée. Si je mets l'appel incriminé dans un bloc Try, la boucle d'attente ne fonctionne pas. En fait, il semble même que l'exception "persiste" à tout bousiller, car même en traversant le code avec le bloc try, Visual Studio se fige pendant 10 à 20 secondes (il fait la même chose sans le bloc try).

Des idées?

Répondre

1

Après msdn article: "Il existe quatre méthodes sur un contrôle qui sont thread-safe pour appeler: Invoke, BeginInvoke, EndInvoke et CreateGraphics et InvokeRequired propriété"

appeler Par conséquent WebBrowser1.ReadyState en Afrique sub attente est pas thread sécurité

3

l'une des questions les plus intéressantes que je l'avais connu et qui je n'ai pas pu trouver une solution à iNet - était problème lié à contrôle WebBrowser. Le fait est que lorsque j'essayais d'accéder à la propriété Document de l'instance de contrôle WebBrowser, j'obtenais "Exception de transtypage invalide". Le fait est que le contrôle WebBrowser est conçu pour fonctionner dans un thread. Pour résoudre ce problème, vous devez uniquement vérifier la propriété InvokeRequired et, si sa valeur est true, appelez la logique du délégué, dans la méthode browser.Invoke (...).

Source