Announcement

Collapse
No announcement yet.

externes Programm im Hintergrund laufen lassen bzw. mit ProgressBar

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • externes Programm im Hintergrund laufen lassen bzw. mit ProgressBar

    Hallo zusammen,

    in meinem Programm wird auf Knopfdruck ein externes Programm gestartet, was dann wiederum remote ein Script ausführt. Funtioniert auch alles wunderbar, nur dass während der Ausführung des externen Programms mein Programm einfriert, während es auf Feedback des externen wartet um dann dessen Ausgabe in einer Textbox anzuzeigen. Wie kann ich das externe Programm im Hintergrund laufen lassen und am besten noch ein Marquee-ProgressBar einbinden, dass man sieht, dass es noch herumwerkelt? Den Code benutze ich:
    [highlight=vbnet]

    Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
    Dim ProcessInfo As New ProcessStartInfo
    Dim p As New Process

    p.StartInfo.FileName = "psexec"
    p.StartInfo.Arguments = "\\10.1.1.1 -u user -p passwort C:\import\import.cmd"
    p.StartInfo.UseShellExecute = False
    p.StartInfo.CreateNoWindow = True
    p.StartInfo.RedirectStandardError = True
    Try
    Application.DoEvents()
    p.Start()

    txtOutput.Text = p.StandardError.ReadToEnd()
    p.WaitForExit()
    p.Close()
    Catch ex As Exception
    End Try

    End Sub

    [/highlight]

  • #2
    Hallo,

    lass das externe Programm in einem Thread starten und warte auch im Thread darauf. Wenn das Programm fertig ist wird vom Thread ein Event gefeuert und iin der UI darauf reagiert.


    mfG Gü
    "Any fool can write code that a computer can understand. Good programmers write code that humans can understand". - Martin Fowler

    Comment


    • #3
      Hallo Gü,

      das ist eine gute Alternative, ich hab jetzt allerdings die wahrscheinlich einfachste(vielleicht nicht die eleganteste) Lösung gefunden:
      [highlight=vbnet]
      p.Start()
      Do While Not p.HasExited

      Application.DoEvents()

      Loop

      p.WaitForExit()
      If p.HasExited = True Then
      txtOutput.Text = p.StandardError.ReadToEnd()

      p.Close()

      End If
      [/highlight]

      Aber trotzden Danke für deinen Tip, ich werde es demnächst mal damit versuchen! :-)
      Allerdings ist es mir bisher nicht gelungen, die Ausgabe in der cmd in Echtzeit in der Textbox auszugeben. Der statische Text nach Ablauf des externen Prozesses wird dargestellt, was allerdings davor "live" in der cmd passiert(wenn eine cmd angezeigt werden würde) lässt sich irgendwie nicht anzeigen, oder doch? Beispiel: beim Kommandozeilen-Winrar wird auf der Konsole der Packfortschritt dargestellt, bei Konsolenumleitung in die Textbox wird bis zum Ende nix angezeigt, das Programm scheint eingefroren bis zum Pack-Ende, das Form lässt sich aber verschieben... :-(

      Comment


      • #4
        Asynchrones auslesen geht über die Process.BeginOutputReadLine Methode.
        Dabei bekommst du jedesmal einen Event wenn der Process etwas in die Console schreibt.

        Bei deinem Code müsstest du beim Start des Processes den EventHandler verdrahten und das asynchrone Abfangen der Meldung mit oben erwähnter Methode starten

        [Highlight=VB.Net]AddHandler p.OutputDataReceived, AddressOf OutputDataReceivedHandler
        p.Start()
        p.BeginOutputReadLine()[/Highlight]

        Im EventHandler kannst du dann deine TextBox mit den eingehenden Daten füllen. Achtung der EventHandler läuft in einem anderen Thread(ist ja asynchron). Also den Crossthread Call berücksichtigen.


        [Highlight=VB.Net]Private Sub OutputDataReceivedHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
        txtOutput.Invoke(Sub() txtOutput.Text += outLine.Data + Environment.NewLine)
        End Sub[/Highlight]

        Und berücksichtigen solltest du auch das man synchrones und asynchrones auslesen nicht gleichzeitig kann. Wenn du obiges tust geht also

        [Highlight=VB.Net]p.StandardError.ReadToEnd()[/Highlight]

        nicht mehr. War in deinem Code eh problematisch da du StandardError erst nach WaitForExit() ausliest.

        Comment


        • #5
          Hallo Ralf,

          vielen Dank für die blitzartige Antwort, das klingt genau so wie es brauche ;-)
          Ich wollte es gerade mal schnell testen, allerdings meckert VS bei
          Code:
          txtOutput.Invoke(Sub() txtOutput.Text += outLine.Data + Environment.NewLine)
          an der Stelle (Sub() meint VS "Ausdruck erwartet"
          Was muss denn da noch hin?

          Comment


          • #6
            Was muss denn da noch hin?
            Das ist Syntax der mit Visual Studio 2010 eingeführt wurde. Welche IDE mit welchem Framework benutzt du.

            Comment


            • #7
              Ich nutze VS 2008

              Comment


              • #8
                Also wohl noch .NET Framework 3.5

                Comment


                • #9
                  Dann must du wohl ohne anonyme Delegaten/Methoden auskommen.
                  Heißt Delgaten selber schreiben und aufrufen.


                  [Highlight=VB.Net]
                  Private Sub OutputDataReceivedHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
                  txtOutput.Invoke(New UpdateHandler(AddressOf UpdateControl), outLine.Data)
                  End Sub

                  Private Delegate Sub UpdateHandler(ByVal text As String)

                  Private Sub UpdateControl(ByVal text As String)
                  txtOutput.Text += text + Environment.NewLine
                  End Sub[/Highlight]

                  Comment


                  • #10
                    Guten Morgen,

                    ich habs gleich mal getestet (mit einem Programm, was mehr shell-Ausgabe anbietet), allerdings kommt jetzt gar kein Text mehr, weder während das Programm läuft, noch wenn es fertig ist :-(
                    Hier mal der komplette Code:
                    [highlight=vbnet]
                    Private Sub OutputDataReceivedHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
                    txtLog.Invoke(New UpdateHandler(AddressOf UpdateControl), outLine.Data)
                    End Sub

                    Private Delegate Sub UpdateHandler(ByVal text As String)

                    Private Sub UpdateControl(ByVal text As String)
                    txtLog.Text += text + Environment.NewLine
                    End Sub

                    Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click

                    txtLog.Text = ""

                    Dim p As New Process

                    p.StartInfo.FileName = "C:\Program Files\VMware\VMware Server\vmware-vdiskmanager.exe "
                    p.StartInfo.Arguments = "-d " & txtGans.Text & txtInput.Text & ""
                    p.StartInfo.UseShellExecute = False
                    p.StartInfo.RedirectStandardOutput = True
                    p.StartInfo.CreateNoWindow = True
                    p.StartInfo.RedirectStandardError = True

                    Try
                    Application.DoEvents()
                    AddHandler p.OutputDataReceived, AddressOf OutputDataReceivedHandler
                    p.Start()
                    Do While Not p.HasExited
                    p.BeginOutputReadLine()
                    Application.DoEvents()
                    Loop

                    p.WaitForExit()
                    If p.HasExited = True Then
                    p.Close()

                    End If

                    Catch ex As Exception
                    End Try
                    End Sub
                    [/highlight]

                    Es kommt aber auch keine Fehlermeldung... hab ich da was übersehen oder vergessen? *grübel*
                    Zuletzt editiert von communi; 08.09.2010, 09:01. Reason: Zeile"Dim ProcessInfo As New ProcessStartInfo", gehört ja da nicht hin...

                    Comment


                    • #11
                      Öhm Du startest den neuen Prozess jetzt nicht in einem anderen Thread? Dann kannst Dir auch das txtLog.Invoke sparen.

                      Comment


                      • #12
                        Na eigentlich nicht (zumindest nicht bewusst ;-)) So langsam komme ich echt ins grübeln, ob ich mir das Ganze nicht einfach in ein batch-file werfe, das läuft sofort aber das löst das Problem nicht und man lernt nix dabei ;-)

                        Comment


                        • #13
                          Also ich habs jetzt nochmal mit einem einfachen ping als process probiert und da funktioniert es tadellos, das heißt das Programm verschluckt sich irgendwie beim Zusammenfummeln der Arguments - obwohl ich daran garnichts geändert hab im Vergleich zu der Version wo der output erst nach Abarbeitung des Prozesses angezeigt wurde... sehr seltsam....

                          Comment


                          • #14
                            Bei der Version so wies da steht sollte es auch einfach so gehen:

                            [highlight=vbnet]
                            Private Sub OutputDataReceivedHandler(ByVal sendingProcess As Object, ByVal outLine As DataReceivedEventArgs)
                            txtLog.Text += text + Environment.NewLine
                            End Sub
                            [/highlight]

                            Also das ganze Dispatching kannst Du Dir sparen

                            Comment


                            • #15
                              Hab ich grade mal in meinem einfachen Ping-Form versucht, das funktioniert aber nicht:

                              System.InvalidOperationException wurde nicht behandelt.
                              Message="Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement TextBox1 erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."

                              Wobei wie gesagt die vorherige Langfassung funktioniert, allerdings schein ich echt zu blöde zu sein, dem Prozess die Argumente in der gewünschten Form zu übergeben, die ganzen Anführungszeichen haben mich gestern schon in den Wahnsinn getrieben weil es nich so funktioniert hat wie es sollte.... und das, was dann gestern auf der Consolenausgabe funktioniert hat seltsamerweise heute nicht mehr... grrrr...
                              Das hier gebe ich normalerweise direkt in der cmd ein(inklusive aller Anführungszeichen) und es funktioniert:
                              "C:\Program Files\VMware\VMware Server\vmware-vdiskmanager.exe" -d "D:\XP Pro Clean-000001.vmdk"

                              Gebe ich im Programm nur
                              [highlight=vbnet]
                              p.StartInfo.FileName = "C:\Program Files\VMware\VMware Server\vmware-vdiskmanager.exe"
                              [/highlight]

                              ohne Argumente ein, wird das auch noch ausgeführt, dann wird mir korrekt die Hilfe der .exe in der Textbox angezeigt.
                              Ich schaffe es nur nicht, die Arguments mit allen Anführungszeichen korrekt anzugeben. Der Pfad zur vmdk-Datei wird ja aus der Textbox txtInput ausgelesen, die komplette Zeile sieht so aus:
                              [highlight=vbnet]
                              p.StartInfo.Arguments = "-d " & """ & txtInput.Text & """
                              [/highlight]
                              Aber das passt irgendwie nich wegen der Anführungszeichen... es ist zum in den Tisch beißen...

                              Comment

                              Working...
                              X