klappt im Form1_Load aber nicht im processExited

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    klappt im Form1_Load aber nicht im processExited

    Hi,

    ich habe ein simples Problem, dessen Lösung ich einfach nicht finde.

    Ich habe 2 Prozeduren, eine zum Zählen der Menge bestimmter Dateien in einem Ordner

    VB.NET-Quellcode

    1. If Directory.Exists("files\") Then
    2. ToolStrip1.Text = CStr(My.Computer.FileSystem.GetFiles("files\", FileIO.SearchOption.SearchTopLevelOnly, "*.txt").Count)
    3. Else : ToolStrip1.Text = "Ordner nicht gefunden!"
    4. End If


    und eine, um anzuzeigen, ob eine Datei bestimmten Namens und Typs in diesem Ordner ist.

    VB.NET-Quellcode

    1. If Directory.Exists("files\") Then
    2. If My.Computer.FileSystem.FileExists(files\ & bliblablub & ".txt") Then : ToolStrip2.Text = "Datei vorhanden" : end if
    3. End If


    packe ich diese Prozeduren in Form1_Load, funktionieren beide subs.
    Packe ich diese hingegen in ein processExited, funktioniert die Prozedur, welche die Anzahl an Dateien ausgibt. Die andere, welche eine bestimmte Datei sucht, funktioniert hingegen nicht.

    Ich steh ein bisschen auf dem Schlauch.

    Woran kann das liegen?
    Ein paar Dinge vorab:
    If ... Then : ... : end if
    Dafür gibt's die Einzeiler-Variante: If ... Then ... (Ohne Doppelpunkte und ohne "End If").

    Verwende nicht My.Computer.FileSystem, sondern System.IO. Siehe auch: Böses aus VB6/VB2003 - und die richtigen VB.NET-Alternativen
    My ist eigentlich nur für Ressourcen gut. Und eventuell für Settings, aber da gibt's auch Alternativen.

    Also zum eigentlichen Problem:
    funktioniert hingegen nicht.
    Das ist keine aussagekräftige Beschreibung des Problems. Siehe: 5 Regeln für sinnvolles Fragen
    Ich habe aber schon eine Vermutung.
    Es könnte sein, dass das ProcessExited-Event in einem anderen Thread ausgeführt wird. Und Zugriffe auf Controls sind nur von dem Thread aus erlaubt, der das Control erstellt hat.
    Schau mal die Dokumentation des Events im ObjectBrowser oder in MSDN an. Da sollte das drin stehen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    Ein paar Dinge vorab:
    Dafür gibt's die Einzeiler-Variante: If ... Then ... (Ohne Doppelpunkte und ohne "End If").

    Danke, wieder ein paar Wörter gespart (:

    Verwende nicht My.Computer.FileSystem, sondern System.IO. Siehe auch: Böses aus VB6/VB2003 - und die richtigen VB.NET-Alternativen
    My ist eigentlich nur für Ressourcen gut. Und eventuell für Settings, aber da gibt's auch Alternativen.

    Danke Dir für die Sammlung, aber sorecht weiß ich nie, ob ich grad "gutes" oder "Böses" in mein Programm einbau. Kann man sowas nicht vorab schon "rausschmeißen"?

    Also zum eigentlichen Problem:
    funktioniert hingegen nicht.
    Das ist keine aussagekräftige Beschreibung des Problems. Siehe: 5 Regeln für sinnvolles Fragen
    Ich habe aber schon eine Vermutung.
    Es könnte sein, dass das ProcessExited-Event in einem anderen Thread ausgeführt wird. Und Zugriffe auf Controls sind nur von dem Thread aus erlaubt, der das Control erstellt hat.
    Schau mal die Dokumentation des Events im ObjectBrowser oder in MSDN an. Da sollte das drin stehen.

    Habe ich auch gedacht, wenn die Sache nur nicht so wäre, das ich die Prozedur zum Datei zählen im ProcessExited Event aufrufen kann und diese den Wert auch prompt aktualisiert. Die andere hingegen tuts nicht.
    "Funktioniert nicht" bedeutet in dem Falle ganz einfach "es ändert sich nichts am Label".

    Die externe Anwendung die ich starte, erstellt halt eine Datei. Nach dem beenden der Anwendung möchte ich direkt überprüfen ob die Datei vorhanden ist und wieviele Datein insgesamt da sind.


    Kann man sowas nicht vorab schon "rausschmeißen"?

    Kann man teilweise.
    Z.B. kannst Du die Projekteinstellungen öffnen und dort unter Verweise den Haken bei Microsoft.VisualBasic rausnehmen. Damit kommt man nicht in Versuchung, Sachen wie MsgBox oder so zu schreiben.
    My müsste man halt einfach nicht verwenden.
    Es gibt auch noch andere Dinge, wie z.B: Pokemon-ExceptionHandling: Simple 3D zu 2D Projektion vb-paradise.de/allgemeines/tip…ch-ist-ein-heisses-eisen/

    es ändert sich nichts am Label

    Hast Du mal einen Haltepunkt in die Methoden gesetzt? Wenn die Mehtoden nicht ausgeführt werden, kann sich nichts ändern.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich habe da jetzt mal einige Zeit mit rum experimentiert und bin um einige Erkenntnisse reicher geworden.

    Ich habe diese Funktion bis jetzt nie über die Entwicklungsumgebung getestet, sondern habe mir meine Anwendung dahin kopiert wo sie später laufen wird und es da probiert. (Liegt daran, das ich sonst immer soviel am Quellcode ändern und Datein im Debug Verzeichniss reinkopieren muss).
    Dabei habe ich festgestellt, das im "echten" Testlauf einfach "nichts" passiert.
    Starte ich jedoch über die IDE, bekomm ich in dem Moment (wie du schon recht vermutet hast) eine Fehlermeldung, in dem die Prozedur versucht, die Labels zu schreiben.

    Eine nicht behandelte Ausnahme des Typs "System.InvalidOperationException" ist in System.Windows.Forms.dll aufgetreten.
    Zusätzliche Informationen: Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Form1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.



    Ich habe den Code jetzt einfach mal mit kompletten Pfadangaben (C:/Dir1/Dir2/programm.exe) versehen und lasse das Programm einfach Testen, ob seine eigene exe vorhanden ist.
    Starte ich die Anwendung über den Explorer, funktionieren beide Prozeduren mit einmal aus dem ProcessExited Event herraus,
    starte ich jedoch über die IDE, bekomm ich bei beiden Prozeduren, oben genannten Fehler.


    Ist das ein Verhalten, das so auftreten "kann", oder habe ich mir hier schon wieder einen erneuten Fehler eingebaut?
    Scheint als nutzest du mehrere Threads. Rufe von deinem Nebenthread Invoke bzw. BeginInvoke auf, um diese Exception zu berichtigen
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    Das Problem ist tatsächlich, dass EventHandler des Exited-Events in einem anderen Thread ausgeführt werden.
    Das dürfte für die Zugriffe auf die Platte keine Probleme darstellen.
    Aber jedes Mal, wenn Du mit der GUI interagieren willst, musst Du Invoke verwenden:

    VB.NET-Quellcode

    1. Sub ...
    2. 'In einem anderen Thread
    3. Dim NewLabelText = "Anzahl Dateien: " & ...
    4. Me.Invoke(Sub() Label1.Text = NewLabelText)
    5. End Sub

    Oder BeginInvoke.
    Invoke wartet, bis der Code im GUI-Thread fertig ist, BeginInvoke wartet nicht.
    In Deinem Fall dürfte BeginInvoke ausreichen.

    Das Problem wird bei Release-Versionen übrigens verschleiert, weil Threads Exceptions eigentlich verschlucken und dann beendet werden, wenn die Exception nicht behandelt wird (mit einer ThreadAbortException wird auch beispielsweise ein Thread abgebrochen).
    Wenn Du im GUI-Thread eine Exception wirfst, fliegt die in etwa durch diese Methoden von unten nach oben:
    • Program.Main
    • Application.Run
    • Application.RunMessageLoop
    • ...
    • Control.WmProc
    • Control.OnMouseDown
    • Control.OnClick
    • Form1.Button1_Click

    Irgendwo auf dem Weg nach oben wird die Exception gefangen. Und dann wird das Fensterchen mit der Standard-Fehlermeldung angezeigt.
    Nur gibt's das nicht, wenn man einen separaten Thread startet. Und deshalb wird auch nirgends eine Fehlermeldung angezeigt. Nur bei angehängtem Debugger geht das irgendwie, dass der das mitbekommt.

    Damit Dir die Exception angezeigt wird, müsstest Du ein TryCatch drumrum bauen:

    VB.NET-Quellcode

    1. Sub Dings() Handles Process.Exited
    2. Try
    3. 'Dein Code
    4. #If Debug Then
    5. Catch When False 'Beim Debuggen Exceptions nicht fangen, denn der Debugger weiß es besser.
    6. #Else
    7. Catch ex As Exception
    8. #End If
    9. 'Hier so viele Infos wie möglich sammeln und passend anzeigen, damit man ganz genau weiß, wo die Exception geworfen wurde.
    10. End Try
    11. End Sub
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Ich danke Dir für Deine überaus ausführliche Antwort Niko :)
    Mit Invoke hat es geklappt. Keine Fehlermeldung mehr, auch nicht von VS.

    Ich habe auch noch herrausgefunden, warum ich nur im Load Event prüfen konnte, ob eine Datei existiert. Im Dateipfad war eine Variable aus einer anderen Form eingebracht.
    Scheinbar kann man aus dem ProcessExited Event herraus auch keine Form fremden Variablen lesen. Kann das sein?
    Es hat nämlich zumindest nur geklappt, wenn ich den zu prüfenden Dateipfad direkt eingab, jedoch nicht mit "pfad..." & TeilEinesPfadesAusEinerVariablen & "text.exe"

    Schönen Sonntag noch!
    Ich nehme an, du hast Formname.Variable geschrieben.
    Lies Dir dazu das durch: Instanziierung von Forms und Aufruf von Dialogen
    Kurz gesagt: Das nennt sich Standardinstanz. Und es gibt für jeden Thread eine eigene Standardinstanz. Also ist das Form1.Variable im Form_Load was anderes als Form1.Variable im Code vom Exited-Event.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils