2010-12-28 12 views
6

Recentemente ho cambiato la mia app dall'utilizzo di uno SplashScreen personalizzato (era solo un Modulo con un Timer che caricava il modulo principale e si chiudeva da solo) in Application Framework.VB.net ApplicationFramework plus SplashScreen: InvalidOperationException

Ecco quello che ho fatto:

  • creato una nuova SplashScreenForm che mostra la versione app ecc
  • selezionate che si formano a: Il mio progetto -> Applicazioni -> SplashScreen
  • Mosso inizializzazione lunga corsa codice dal costruttore del modulo principale all'evento di avvio di ApplicationEvents

Ciò che fa completamente ciò che voglio. SplashScreen viene visualizzato per primo, e l'evento di avvio si attiva e funziona. SplashScreen si chiude e vengono visualizzate le forme principali effettive.

Fin qui tutto bene. Ma i nostri clienti a volte ottengono questa brutta eccezione durante l'avvio:

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) 

Sembra che ci sia un errore durante HideSplashScreen(), ma la cosa è che l'intero stack è fuori dal mio controllo, quindi non posso solo prendere questo eccezione.

Qualche suggerimento?

+0

Sei in grado di riprodurre il problema? – Shimmy

+0

Qualche aggiornamento su questo problema? Sto ancora ricevendo lo stesso problema. Grazie. –

+0

Ho aggiunto questa riga all'avvio del mio evento ApplicationStartup: 'MinimumSplashScreenDisplayTime = 3000' e finora non ho avuto questa eccezione. Ma dal momento che questa esecuzione è totalmente casuale, non posso dire con certezza se ciò sia stato di aiuto. –

risposta

5

Metti questo nello splash da. Se ci sono alcuni componenti, questo sottotitolo potrebbe essere già dichiarato nel file Designer.vb. Basta spostare il contenuto al codice sorgente e inserire la prima riga.

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

Ho eseguito analisi approfondite, compresa la decompilazione di assiemi di framework e questo dovrebbe fare il trucco. Una spiegazione dettagliata sarebbe una storia più lunga.

Non riesco a riprodurre questo problema sul mio computer, ma si verifica un errore su vari computer client. Sembra impossibile riprodurlo anche con chiamate maligne. Non esiste alcuna condizione relativa a HW o SW per simulare il problema, ma di solito si verifica nei PC con CPU lente o alte quando i messaggi del ciclo degli eventi vengono ritardati e i thread di lavoro vengono commutati nel momento sbagliato.

+0

Grazie, lo proverò. gestione degli errori per questo, i client non noteranno mai questa eccezione, ma sul mio computer sviluppatore ciò accade una volta alla settimana o due (anche durante il debug). Aggiornamento –

+0

: Da quando ho aggiornato il mio codebase, questo errore non è mai più successo (almeno durante il debug su la mia macchina dev.) Finora sembra finita –

+0

Purtroppo, esiste ancora una piccola possibilità che questa eccezione si verifichi. C'è la chiamata Invoke al metodo Dispose in HideSplashScreen e questo è ctice. Perché quando il richiamo enqueued viene licenziato troppo velocemente il controllo viene eliminato e il conseguente WaitForWaitHandle potrebbe generare un'eccezione in questa situazione. Questo errore non può essere risolto dal codice e si verificherà in modo appropriato sulla CPU single core quando i thread vengono commutati in un momento non idoneo. – PavlinII

1
  1. si è in grado di riprodurre il problema (cioè distinguere alcuni scenari in cui il problema fa e non si verifica
  2. Quali eventi sono di manovrare nel MyApplication class?
  3. tenta di aggiungere il seguente gestore in quella classe , forse l'eccezione verrà catturata qui e fornirà ulteriori informazioni sullo stack
  4. Quando si raggiunge il gestore, verificare se ci sono InnerException s in modo ricorsivo e determinare se l'errore visualizzato è effettivamente l'errore di origine, o solo un
  5. Disattiva "Just My Code" (leggi this per i dettagli) e si potrebbe essere in grado di risalire alla fonte del problema

HTH


Private Sub MyApplication_UnhandledException(
    ByVal sender As Object, 
    ByVal e As ApplicationServices.UnhandledExceptionEventArgs) _ 
     Handles Me.UnhandledException 
    Stop 
End Sub 
+0

+1 per il suggerimento numero 4 - molto interessante, grazie. Gestisco già l'UnhandledException per mostrare una schermata di errore personalizzata. E l'unico altro evento è l'evento di avvio. L'errore non è riproducibile perché si è verificato solo in modo completamente casuale un paio di volte sui computer client. Forse dovrei prima dare una compilazione di debug e sperare che la traccia dello stack sia più prolissa. –

+0

È accaduto anche nel tuo computer? Forse puoi sapere secondo il sistema operativo di quei client unici (forse tutti sono x64/server/qualunque), o succede in TUTTI i computer? – Shimmy

+0

Sull'errore personalizzato, prova a capire se c'è 'InnerException' nella principale. – Shimmy

1

Questa è la mia soluzione. Ho finito con l'ingerire qualsiasi InvalidOperationException nell'evento UnhandledException fino a quando lo SplashScreen non è andato.

Per fare ciò ho aggiunto una proprietà MainFormLoadingComplete alla mia classe MyApplication impostata su true nell'evento illustrato del mio modulo principale (lo splashscreen rimane attivo fino all'elaborazione dell'evento Form_Load).

Ho anche capito che devo impostare MinimumSplashScreenDisplayTime prima di OnInitialize() per essere efficace. Speriamo che questo aiuti a evitare l'eccezione in primo luogo.Ma dal momento che questa eccezione è del tutto casuale che

codice 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 codice:

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 

codice 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

appena imbattuto in questo, abbiamo la lo stesso identico problema con la stessa tecnica.

ho intenzione di tentare la soluzione che funziona, ma volevo solo farvi sapere come riprodurlo:

La nostra gente di supporto speso un sacco di tempo su questo e, infine, limitata alle accadendo solo in Windows 7 e si verifica solo subito dopo l'avvio di Windows.

Se riavvii Windows, avvia immediatamente la tua app che utilizza questa tecnica dello splash screen che l'errore si verifica quasi sempre.

Se riavvii Windows, attendi qualche minuto, quindi avvia l'app non vedrai mai l'errore.

Ho lavorato attorno ad esso inserendo un sleep (400) nella parte inferiore dell'evento di caricamento del mio modulo principale, tuttavia alcuni stavano ancora vedendo l'errore e ho intenzione di provare la soluzione.

+0

Ho anche capito che questa eccezione sembra essere in qualche modo correlata all'evento di caricamento del modulo (anche se non ti dice nello stacktrace), poiché non tutto il codice dall'evento di caricamento viene eseguito (nel mio caso Carico un usercontrol con una casella di accesso che non viene mai visualizzata dopo l'eccezione si verifica anche con la mia soluzione. Così ho spostato la maggior parte del codice per l'evento 'Shown'. –

Problemi correlati