none
webbrowserコントロールを使用するvb.netアプリが応答なしになる RRS feed

  • 質問

  • はじめて投稿させていただきます。
    宜しくお願いします。

    現在web自動巡回プログラム(指定したURLを指定した時間表示するだけのプログラム)を作成しております。
    プロジェクトの構成は

    formにwebbrowserコントロールとtimerコントロールを貼り付けています。
    コードは以下のようになります。

     Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.Text = My.Application.Info.AssemblyName
        Me.ControlBox = False
    
        WebBrowser1.ScrollBarsEnabled = False
        WebBrowser1.Dock = DockStyle.Fill
    
        Dim Rect As Rectangle = Screen.PrimaryScreen.Bounds
        Me.SetDesktopBounds(0, 0, Rect.Width, Rect.Height)
        Me.TopMost = False
    
        Timer1.Interval = 100
        Timer1.Enabled = True
      End Sub
    
    
      Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Try
          Timer1.Enabled = False
          ' hairetu と言う名前のCollections.ArrayList()
          ' applicationevents.vbで外部ファイルから読み込んでいます。
    
          WebBrowser1.Navigate( hairetu(n)(0).ToString   )
        Catch ex As Exception
          Timer1.Interval = 100
          Timer1.Enabled = True
        End Try
      End Sub
    
    
      Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        ' hairetu(n)(1) n番目の時刻をタイマーにセット
        Timer1.Interval = CInt( hairetu(n)(1) ) * 1000
        Timer1.Enabled = True
        n += 1
        If (n >= hairetu.Count) Then
          n = 0
        End If
      End Sub

    ビルドではエラーが出ないので、運用環境で動かしたところ(releaseフォルダ以下をコピーしました)

    場合によっては数分で応答なし。数時間問題ない場合もあります。
    また、開発環境でも応答なしは発生します。
    webbrowserコントロールで表示している内容(url)は、hairetu というCollections.ArrayListに入れてるのですが
    内容は csv 形式ファイルから読み取っています
    (csvの内容)
    http://www.yahoo.co.jp , 10
    http://www.goo.ne.jp , 10
    登録は5行ほどです。巡回表示させています。


    応答なしになる場合は、flashコンテンツを含んだページで発生しているようです。
    (応答なしになった場合に表示されている内容から)


    [試したこと]
    visual studio 2008 expressでデバッグを実行したところ

    BindingFailure が検出されました。
    Message: 表示名 'Microsoft.mshtml' を伴うアセンブリを、ID 1 を伴う AppDomain の 'LoadFrom' バインド コンテキストで読み込めませんでした。失敗の原因は次のとおりです: System.IO.FileNotFoundException: ファイルまたはアセンブリ 'Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'、またはその依存関係の 1 つが読み込めませんでした。指定されたファイルが見つかりません。ファイル名 'Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' です。

    とありましたので、実行ファイルと同一ディレクトリにmicrosoft.mshtml.dll を配置したところ
    上記エラーは発生しなくなりましたが、応答なしは発生しております(タイミングは不定)。


    vs2008のデバッグ実行時でも応答なしにはなるのですが、出力メッセージにエラーらしきものは表示されません。
    また、applicationevents.vbのUnhandledExceptionにmsgbox()でエラー表示をさせるようにしていますが
    エラーが表示されることもありません。


    フォームにラベルを貼り付けてメッセージを表示させ、どのタイミングで応答なしになるかを確認したところ
    timer_tick と WebBrowser_DocumentCompleted の間で起こっているように見受けられます。
    (timer_tick, webbrowser_documetcompleted sub関数の中で起こっているようには見えないのです...)

    開発環境は vista sp1 visual studio 2008 + .net 3.5sp1 です
    運用環境は vista sp2 + .net3.5sp1です



    プログラム開発については初心者なので、
    どこで応答なしになっているのか切り分ける手段がまったくわかりません。
    切り分け方法やコードの不備・解決方法などありましたらご教授願います。

    また、webbrowserコントロールが使用できているのに microsot.mshtml.dllが要求されたのもわかりません。

    長文で申し訳ありませんが、宜しくお願いします。

    2009年7月3日 5:33

回答

  • > 気になるのは、ご指摘頂いた timer1_tick内の catchで timer1を有効にしている点です。
    > ここを無効設定にしてしばらく動かしてみたいと思います。

    それより例外をキャッチしないようにして、テストしてみたらどうですか?

    • 回答としてマーク mst0829 2009年7月9日 23:44
    2009年7月7日 13:41

すべての返信

  • アップされたコードを見る限りですが、DocumentCompleted イベントが発生しないと、
    次に進めないようですが、いかがですか?

    そうであれば、ある URI に Navigate された後、何かの問題で DocumentCompleted
    イベントが発生しないことが無応答になる原因だと思います。

    Timer をもう一つ設けて、Navigate した後ある時間待って DocumentCompleted イベ
    ントが発生しなければ、次の URI へ Navigate するようにしてはいかがですか?

    2009年7月3日 11:33
  • SurfOnWWW様 回答ありがとうございます。

    documentcompleteは、必ず発生するものだと思っていたので、
    メッセージが発生しない場合のことを忘れておりました。

    指摘いただいたとおり、timer2をフォームに貼り付けてコードを以下のように変更しました。

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        (省略)
        Timer2.Interval = TIMEOUT ' timer1より大きい秒数 タイムアウト時間
        Timer2.Enabled = False
    	
        Timer1.Interval = 100
        Timer1.Enabled = True
      End Sub
    
    
      Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Try
          Timer1.Enabled = False
          Timer2.Enabled = True
    
          ' hairetu と言う名前のCollections.ArrayList()
          ' applicationevents.vbで外部ファイルから読み込んでいます。
    
          WebBrowser1.Navigate( hairetu(n)(0).ToString   )
        Catch ex As Exception
          Timer1.Interval = 100
          Timer1.Enabled = True
        End Try
      End Sub
    
    
      Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
        ' hairetu(n)(1) n番目の時刻をタイマーにセット
        Timer1.Interval = CInt( hairetu(n)(1) ) * 1000
        Timer1.Enabled = True
        Timer2.Enabled = False
        n += 1
        If (n >= hairetu.Count) Then
          n = 0
        End If
      End Sub
    
    
     Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
        Timer2.Enabled = False
        Timer1.Enabled = False
    
        n += 1
        If (n >= hairetu.Count) Then
          n = 0
        End If
    
        Timer2.Enabled = True
        WebBrowser1.Navigate( hairetu(n)(0).ToString   )
    
      End Sub

    実際動かしてみると timer2_tickが何度も発生しており、
    応答なしの原因は documentcompletedメッセージが発生していないことだとわかりました。
    ありがとうございます。


    ただ、 timer2を追加してコードを変更したことで 応答なし の現象が発生することはなくなりましたが
    System.StackOverflowException が発生する時が時々おこるようです。
    デバッグで走らせて30分ほどで System.StackOverflowException  が表示されたのですが
    6時間ほど走らせて出ないこともあります。

    メッセージから再帰を繰り返しているようなのですが...。

    切り分け方法などありましたらよろしくお願いいたします。

    2009年7月5日 3:00
  • > System.StackOverflowException が発生する時が時々おこるようです。

    問題が起こったときは Sub Timer1_Tick の Try ブロックで WebBrowser1.Navigate が例外を
    スローしていませんか? Catch ブロックの中で、n をインクリメントして、次の URI に
    Navigate するようにしたら解決できませんか?

    2009年7月5日 6:39
  •  
    SurferOnWww様回答ありがとうございます。

    昨日より、もう一度確認のために コードを変更せずにデバッグで動かしてみたのですが、
    timer1_tickの try~catchで例外に引っかかることがありませんでした。
    (timer1_tick内で例外が発生した場合、フォームに貼り付けているラベルに
    メッセージを出すようにしたのですが、メッセージの表示もありませんでした。)

    ほぼ1日動かしてみて 「system.stackoverflowexceptionはハンドルされませんでした」 のメッセージは表示されませんでした。


    またtimer1_tick内で
    try~catchの間に Throw New InvalidOperationException を挿入。
    デバッグメニューの例外で、スローされる時をいったん全て解除。system.stackoverflowのみチェックをつけて再度実行してみたのですが
    これでもstackoverflowエラー検出はできませんでした。


    後、stackoverflow例外が発生したときのエラーの詳細を挙げるのを忘れておりました。
    stackoverflowの例外が発生した際に、「例外の詳細をクリップボードに追加」で取得したメッセージは以下のようになります。

    ---
     System.StackOverflowException はハンドルされませんでした。
     Message: 'System.StackOverflowException' のハンドルされていない例外が 不明なモジュールです。 で発生しました。
    ---


    どのタイミングでエラーが出ているのか、よくわかない状況です。
    プログラミング自体の経験があまりないものですから、この切り分け方で正しいのかも疑問なのですが。。。。

    気になるのは、ご指摘頂いた timer1_tick内の catchで timer1を有効にしている点です。
    ここを無効設定にしてしばらく動かしてみたいと思います。

    何かお気づきの点などありましたらご指摘お願いします。


    2009年7月7日 10:24
  • > 気になるのは、ご指摘頂いた timer1_tick内の catchで timer1を有効にしている点です。
    > ここを無効設定にしてしばらく動かしてみたいと思います。

    それより例外をキャッチしないようにして、テストしてみたらどうですか?

    • 回答としてマーク mst0829 2009年7月9日 23:44
    2009年7月7日 13:41
  • SuferOnWWW様回答ありがとうございます。
    例外を無視するようにコードを変更して、しばらく動かしておりました。
    以後、エラーが出ることはなくなったので、とりあえずこれで大丈夫かなと思っております。

    回答ありがとうございました。

    2009年7月9日 23:44