VB.net ApplicationFramework plus SplashScreen: InvalidOperationException - PullRequest
6 голосов
/ 28 декабря 2010

Я недавно изменил свое приложение с использования пользовательского SplashScreen (это была просто форма с таймером, загрузившим основную форму и закрывшая себя) на Application Framework.

Вот что я сделал:

  • Создан новый SplashScreenForm, который показывает версию приложения и т. Д.
  • Выбрал эту форму в: Мой проект -> Приложение -> SplashScreen
  • Перенес длинный код инициализации из конструктора главной формы в событие запуска ApplicationEvents

Это полностью делает то, что я хочу. Сначала отображается SplashScreen, затем запускается событие запуска и работает. 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 ]

5 голосов
/ 27 июня 2012

Поместите это в свой всплеск от. Если есть некоторые компоненты, эта подпрограмма может быть уже объявлена ​​в файле Designer.vb. Просто переместите его содержимое в исходный код и вставьте первую строку.

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

Я провел глубокий анализ, включая декомпиляцию сборок фреймворка, и это должно сработать. Подробное объяснение будет более длинной историей.

Я не могу воспроизвести эту проблему на своем компьютере, но ошибка возникает на разных клиентских компьютерах. Кажется невозможным воспроизвести его даже при злонамеренных звонках. Нет условий HW или SW, чтобы смоделировать проблему, но обычно это происходит на компьютерах с медленной или высокой загрузкой процессора, когда сообщения цикла событий задерживаются и рабочие потоки переключаются в неправильный момент.

1 голос
/ 29 января 2011

Это моё решение. Я закончил, просто проглотив любое InvalidOperationException в событии UnhandledException, пока SplashScreen не исчез.

Для этого я добавил Свойство MainFormLoadingComplete в свой класс MyApplication, для которого установлено значение true в Показанном событии моей главной формы (заставка остается до обработки события 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

Код формы 1:

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
1 голос
/ 28 декабря 2010
  1. Можете ли вы воспроизвести проблему (т. Е. Выделить определенные сценарии, в которых проблема возникает и не возникает
  2. Какие события вы обрабатываете в MyApplication class?
  3. Попробуйте добавить следующий обработчик в этот класс, возможно, здесь будет поймано исключение, которое предоставит вам больше информации о стеке
  4. Когда вы достигнете обработчика, проверьте, есть ли InnerException s рекурсивно, и определите, действительно ли ошибка, которую вы видите, является исходной ошибкой или просто повторной передачей.
  5. Отключите «Просто мой код» (подробности читайте здесь ), и вы сможете найти источник проблемы

НТН


Private Sub MyApplication_UnhandledException(
    ByVal sender As Object, 
    ByVal e As ApplicationServices.UnhandledExceptionEventArgs) _
       Handles Me.UnhandledException
    Stop
End Sub
0 голосов
/ 20 апреля 2011

только что с этим сталкивался, у нас точно такая же проблема с использованием той же техники.

Я собираюсь попробовать ваше решение, которое работает, но я просто хотел, чтобы вы знали, как его воспроизвести:

Наши сотрудники службы поддержки потратили много времени на это и, наконец, сузили его до того, что это происходит только в Windows 7 и происходит только после того, как Windows была запущена из загрузки.

Если вы перезагрузите Windows, то сразу же запустите ваше приложение, которое использует этот метод заставки, ошибка будет происходить почти все время.

Если вы перезагрузите Windows, подождите несколько минут, затем запустите приложение, и вы никогда не увидите ошибку.

Я решил эту проблему, поместив sleep (400) в конец события загрузки моей основной формы, однако некоторые все еще видели ошибку, и вместо этого я собираюсь попробовать ваше решение.

...