6

私は最近、アプリをカスタム SplashScreen の使用からアプリケーション フレームワークに変更しました。

これが私がしたことです:

  • アプリのバージョンなどを表示する新しい SplashScreenForm を作成しました。
  • そのフォームを選択: My Project -> Application -> SplashScreen
  • 長時間実行される初期化コードをメイン フォームのコンストラクターから ApplicationEvents スタートアップ イベントに移動しました。

それは私が望むことを完全に行います。SplashScreen が最初に表示され、Startup イベントが発生して機能します。SplashScreen が閉じ、実際のメイン フォームが表示されます。

ここまでは順調ですね。しかし、私たちのお客様は、起動時に次の厄介な例外を受け取ることがあります。

System.InvalidOperationException: Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.
   bei System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle)
   bei System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
   bei System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
   bei System.Windows.Forms.Control.Invoke(Delegate method)
   bei Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.HideSplashScreen()
   bei Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.MainFormLoadingDone(Object sender, EventArgs e)
   bei System.EventHandler.Invoke(Object sender, EventArgs e)
   bei System.Windows.Forms.Form.OnLoad(EventArgs e)
   bei System.Windows.Forms.Form.OnCreateControl()
   bei System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
   bei System.Windows.Forms.Control.CreateControl()
   bei System.Windows.Forms.Control.WmShowWindow(Message& m)
   bei System.Windows.Forms.Control.WndProc(Message& m)
   bei System.Windows.Forms.ScrollableControl.WndProc(Message& m)
   bei System.Windows.Forms.Form.WmShowWindow(Message& m)
   bei System.Windows.Forms.Form.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

HideSplashScreen() 中にエラーが発生したようですが、スタック全体が制御不能になっているため、この例外をキャッチすることはできません。

助言がありますか?

4

4 に答える 4

5

これをスプラッシュフロムに入れます。コンポーネントがいくつかある場合、このサブは Designer.vb ファイルですでに宣言されている可能性があります。その内容をソース コードに移動し、最初の行を挿入するだけです。

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then My.Application.SplashScreen = Nothing
    MyBase.Dispose(disposing)
End Sub

フレームワークアセンブリの逆コンパイルを含む詳細な分析を実行しましたが、これでうまくいくはずです。詳細な説明は話が長くなります。

この問題を自分のコンピューターで再現することはできませんが、さまざまなクライアント コンピューターでエラーが発生します。悪質な呼び出しでも再現不可能のようです。この問題をシミュレートするためのハードウェアまたはソフトウェア関連の条件はありませんが、イベント ループ メッセージが遅延し、作業スレッドが間違ったタイミングで切り替えられた場合に、低速または CPU 使用率の高い PC で通常発生します。

于 2012-06-27T15:40:26.697 に答える
1
  1. 問題を再現できますか(つまり、問題が発生するシナリオと発生しない特定のシナリオを区別します)
  2. でどのようなイベントを処理していMyApplication classますか?
  3. そのクラスに次のハンドラーを追加してみてください。例外がここでキャッチされ、スタックに関する詳細情報が提供される可能性があります。
  4. ハンドラーに到達したら、がInnerException再帰的に存在するかどうかを確認し、表示されるエラーが実際にソースエラーなのか、それとも単なる再スローなのかを判断します。
  5. 「JustMyCode」を無効にすると(詳細はこちらをお読みください)、問題の原因を突き止めることができる場合があります

HTH


Private Sub MyApplication_UnhandledException(
    ByVal sender As Object, 
    ByVal e As ApplicationServices.UnhandledExceptionEventArgs) _
       Handles Me.UnhandledException
    Stop
End Sub
于 2010-12-28T08:29:26.133 に答える
1

これが私の解決策です。SplashScreen がなくなるまで、UnhandledException イベントで InvalidOperationException を飲み込むだけで終わりました。

そのために、メイン フォームの Shown イベントで true に設定された MyApplication クラスにプロパティを追加しましたMainFormLoadingComplete(Form_Load イベントが処理されるまでスプラッシュスクリーンは残ります)。

MinimumSplashScreenDisplayTimeまた、効果を上げるには事前に設定する必要があることもわかりましたOnInitialize()。そもそも例外を回避するのに役立つことを願っています。しかし、この例外は完全にランダムなので、私は

SplashScreen コード:

Public Class SplashScreen

    Private Sub SplashScreen_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
        ' Simulate InvalidOperationException
        Throw New InvalidOperationException
    End Sub

End Class

Form1 コード:

Public Class Form1

    Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        My.MyApplication.MainFormLoadingComplete = True
    End Sub

End Class

MyApplication コード:

Partial Friend Class MyApplication

    Public Shared Property MainFormLoadingComplete As Boolean

    Protected Overrides Function OnInitialize(ByVal commandLineArgs As System.Collections.ObjectModel.ReadOnlyCollection(Of String)) As Boolean
        ' MinimumSplashScreenDisplayTime has to be set before OnInitialize to be effective
        MinimumSplashScreenDisplayTime = 3000 
        Return MyBase.OnInitialize(commandLineArgs)
    End Function

    Private Sub MyApplication_Startup( _
        ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
        ' Simulate application init process
        System.Threading.Thread.Sleep(5000)
    End Sub

    Private Sub MyApplication_UnhandledException(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs) Handles Me.UnhandledException

        ' Swallow InvalidOperationException if the MainForm has not been shown
        If MainFormLoadingComplete = False AndAlso IsCausedByHideSplashScreen(e.Exception) Then
            ' Logging stuff...

            ' Prevent application exit
            e.ExitApplication = False
        End If

    End Sub

    Private Function IsCausedByHideSplashScreen(ByVal ex As Exception) As Boolean
        If ex.GetType Is GetType(InvalidOperationException) Then
            Return New StackTrace(ex).GetFrames().Count(Function(x) x.GetMethod().Name = "HideSplashScreen") > 0
        Else
            Return False
        End If
    End Function

End Class
于 2011-01-29T14:20:06.307 に答える
-1

これに出くわしたばかりですが、同じ手法を使用してまったく同じ問題があります。

機能するソリューションを試してみますが、それを再現する方法をお知らせしたかっただけです:

私たちのサポート担当者はこれに多くの時間を費やし、最終的に Windows 7 でのみ発生し、Windows がブートから開始された直後にのみ発生するように絞り込みました。

Windows を再起動してから、このスプラッシュ スクリーン手法を使用するアプリをすぐに起動すると、ほぼ常にエラーが発生します。

Windows を再起動し、数分待ってからアプリを起動すると、エラーは表示されません。

メイン フォームのロード イベントの下部に sleep(400) を配置することで回避しましたが、まだエラーが表示されているものもあり、代わりに解決策を試してみます。

于 2011-04-20T16:02:08.477 に答える