Konsole "live" auslesen

  • VB.NET

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von OnkelR.

    Konsole "live" auslesen

    Hallo,

    ich packe mit der 7z.exe mit meinem Programm (große) Archive...
    Wenn man den Befehl direkt in der Konsole ausführt, wird während des Packens der Fortschritt in Prozent angezeigt.
    Den Konsoleninhalt muss ich jetzt irgendwie auslesen um den Fortschritt rauszufiltern. Wichtig ist, dass das Konsolenfenster dabei nicht sichtbar ist.
    Bisher benutze ich den Code von hier. Mein Code sieht so aus:

    VB.NET-Quellcode

    1. Private Sub bgw_zip_DoWork(.......)
    2. 'Pfad zur 7z.exe
    3. SevenZip.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory & "7z.exe"
    4. 'Parameter für die 7z-Konsole
    5. SevenZip.StartInfo.Arguments = parameter
    6. ' kein Window erzeugen
    7. SevenZip.StartInfo.CreateNoWindow = True
    8. ' UseShellExecute auf falsch setzen
    9. SevenZip.StartInfo.UseShellExecute = False
    10. ' StandardOutput von Console umleiten
    11. SevenZip.StartInfo.RedirectStandardOutput = True
    12. ' Eventhandler für Redirection definieren
    13. AddHandler SevenZip.OutputDataReceived, AddressOf WriteProcessOutput
    14. ' Prozess starten
    15. SevenZip.Start()
    16. ' Asynchrones Lesen starten
    17. SevenZip.BeginOutputReadLine()
    18. SevenZip.Start()
    19. 'Wartet bis 7-Zip fertig ist (=automat. geschlossen wurde)
    20. SevenZip.WaitForExit()
    21. End Sub
    22. ' EventHandler Routine für umgeleiteten Output
    23. Private Sub WriteProcessOutput(.....)
    24. ' Daten kommen nicht auf GUI Thread -> per anonymer Methode Invoken
    25. If outLine.Data IsNot Nothing Then
    26. TextBox1.Dispatcher.Invoke(Sub() TextBox1.AppendText(outLine.Data & Environment.NewLine))
    27. End If
    28. End Sub

    Das Funktioniert zwar, aber der Konsoleninhalt wird erst ausgegeben, wenn die Konsolenanwendung fertig ist. Ich möchte die Konsole aber "live" auslesen, während sie noch arbeitet.
    Kennt da jemand eine Lösung?

    Vielen Dank ;)

    VB.NET-Quellcode

    1. Private Delegate Sub AddL(Byval s As String)
    2. Private Output As StreamReader
    3. Private Sub DoWork_blablabla
    4. SevenZip.StartInfo.CreateNoWindow = True
    5. SevenZip.StartInfo.UseShellExecute = False
    6. SevenZip.StartInfo.RedirectStandardOutput = True
    7. SevenZip.Start()
    8. SevenZip.BeginOutputReadLine()
    9. Output = SevenZip.StandardOutput
    10. Dim t As New Thread(AddressOf Read)
    11. t.IsBackground = True
    12. t.Start()
    13. End Sub
    14. Private Sub Read()
    15. Do
    16. Dim line As String = Output.ReadLine
    17. If line Is Nothing Then Exit Do
    18. Me.BeginInvoke(New AddL(AddressOf AddLine), line)
    19. Loop
    20. End Sub
    21. Private Sub AddLine(Byval s As String)
    22. TextBox1.AppendText(s & Environment.NewLine)
    23. End Sub
    24. 'Kurz ausm Kopf geschrieben, ungetestet.
    Der Code is nicht von mir!
    Ich hab den mal so ähnlich am laufen gehabt, finde aber das Projekt nicht mehr.

    Hab den Windows Form Designer generated code mal drin gelassen, vielleicht hilfts.

    Spoiler anzeigen


    VB.NET-Quellcode

    1. Option Explicit On
    2. Option Strict On
    3. Option Compare Binary
    4. Imports Microsoft.VisualBasic
    5. Imports System.Diagnostics
    6. Imports System.Threading
    7. Imports System.Windows.Forms
    8. ' <remarks>
    9. ' Hauptformular der Anwendung.
    10. ' </remarks>
    11. Public Class MainForm
    12. Inherits System.Windows.Forms.Form
    13. Private m_Process As Process
    14. Private m_OutputThread As Thread
    15. Private m_ErrorThread As Thread
    16. Private m_strTextToAdd As String
    17. #Region " Windows Form Designer generated code "
    18. Public Sub New()
    19. MyBase.New()
    20. InitializeComponent()
    21. End Sub
    22. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    23. If disposing Then
    24. If Not (components Is Nothing) Then
    25. components.Dispose()
    26. End If
    27. End If
    28. MyBase.Dispose(disposing)
    29. End Sub
    30. Private components As System.ComponentModel.IContainer
    31. Friend WithEvents txtCommandInput As System.Windows.Forms.TextBox
    32. Friend WithEvents txtConsole As System.Windows.Forms.TextBox
    33. Friend WithEvents btnSend As System.Windows.Forms.Button
    34. <System.Diagnostics.DebuggerStepThrough()> _
    35. Private Sub InitializeComponent()
    36. Me.txtCommandInput = New System.Windows.Forms.TextBox()
    37. Me.btnSend = New System.Windows.Forms.Button()
    38. Me.txtConsole = New System.Windows.Forms.TextBox()
    39. Me.SuspendLayout()
    40. '
    41. 'txtCommandInput
    42. '
    43. Me.txtCommandInput.Anchor = ((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
    44. Or System.Windows.Forms.AnchorStyles.Right)
    45. Me.txtCommandInput.Location = New System.Drawing.Point(16, 352)
    46. Me.txtCommandInput.Name = "txtCommandInput"
    47. Me.txtCommandInput.Size = New System.Drawing.Size(462, 20)
    48. Me.txtCommandInput.TabIndex = 1
    49. Me.txtCommandInput.Text = ""
    50. '
    51. 'btnSend
    52. '
    53. Me.btnSend.Anchor = (System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right)
    54. Me.btnSend.FlatStyle = System.Windows.Forms.FlatStyle.System
    55. Me.btnSend.Location = New System.Drawing.Point(486, 350)
    56. Me.btnSend.Name = "btnSend"
    57. Me.btnSend.Size = New System.Drawing.Size(64, 24)
    58. Me.btnSend.TabIndex = 2
    59. Me.btnSend.Text = "&Senden"
    60. '
    61. 'txtConsole
    62. '
    63. Me.txtConsole.Anchor = (((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom) _
    64. Or System.Windows.Forms.AnchorStyles.Left) _
    65. Or System.Windows.Forms.AnchorStyles.Right)
    66. Me.txtConsole.Font = New System.Drawing.Font("Courier New", 8.25!, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
    67. Me.txtConsole.Location = New System.Drawing.Point(16, 16)
    68. Me.txtConsole.Multiline = True
    69. Me.txtConsole.Name = "txtConsole"
    70. Me.txtConsole.ReadOnly = True
    71. Me.txtConsole.ScrollBars = System.Windows.Forms.ScrollBars.Both
    72. Me.txtConsole.Size = New System.Drawing.Size(534, 326)
    73. Me.txtConsole.TabIndex = 3
    74. Me.txtConsole.Text = ""
    75. '
    76. 'MainForm
    77. '
    78. Me.AcceptButton = Me.btnSend
    79. Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
    80. Me.ClientSize = New System.Drawing.Size(568, 390)
    81. Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.txtConsole, Me.btnSend, Me.txtCommandInput})
    82. Me.MinimumSize = New System.Drawing.Size(576, 424)
    83. Me.Name = "MainForm"
    84. Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
    85. Me.Text = "RedirectConsole"
    86. Me.ResumeLayout(False)
    87. End Sub
    88. #End Region
    89. ' <summary>
    90. ' Schreibt den im Parameter <paramref name="strText"/>
    91. ' angebenen Text auf den Ausgabestrom.
    92. ' </summary>
    93. ' <param name="strText">Text, der auf den Ausgabestrom
    94. ' geschrieben werden soll.</param>
    95. Private Sub StreamInput(ByVal strText As String)
    96. m_Process.StandardInput.WriteLine(strText)
    97. m_Process.StandardInput.Flush()
    98. End Sub
    99. ' <summary>
    100. ' Liest vom Fehlerstream und gibt die
    101. ' gelesenen Informationen aus.
    102. ' </summary>
    103. Private Sub StreamError()
    104. Dim strLine As String = _
    105. m_Process.StandardError.ReadLine()
    106. Try
    107. Do While strLine.Length >= 0
    108. strLine = m_Process.StandardError.ReadLine()
    109. If strLine.Length <> 0 Then
    110. AddText(strLine)
    111. End If
    112. Loop
    113. Catch
    114. AddText("cmd wurde beendet!")
    115. End Try
    116. End Sub
    117. ' <summary>
    118. ' Liest vom Ausgabestream und gibt
    119. ' die gelesenen Informationen aus.
    120. ' </summary>
    121. Private Sub StreamOutput()
    122. Dim strLine As String = _
    123. m_Process.StandardOutput.ReadLine()
    124. Try
    125. Do While strLine.Length >= 0
    126. If strLine.Length <> 0 Then
    127. AddText(strLine)
    128. End If
    129. strLine = m_Process.StandardOutput.ReadLine()
    130. Loop
    131. Catch
    132. AddText("cmd wurde beendet!")
    133. End Try
    134. End Sub
    135. ' <summary>
    136. ' Fügt den im Parameter <paramref name="strText"/>
    137. ' übergebenen String einer TextBox an.
    138. ' </summary>
    139. ' <param name="strText">Text, der der TextBox
    140. ' hinzugefügt werden soll.</param>
    141. Private Sub AddText(ByVal strText As String)
    142. m_strTextToAdd = strText
    143. Me.Invoke(CType(AddressOf Me.AddTextToTextBox, MethodInvoker))
    144. End Sub
    145. ' <summary>
    146. ' Wird über Invoking aufgerufen, um einen Text hinzuzufügen.
    147. ' <summary>
    148. Private Sub AddTextToTextBox()
    149. txtConsole.AppendText(String.Concat(m_strTextToAdd, _
    150. ControlChars.NewLine))
    151. txtConsole.SelectionStart = txtConsole.Text.Length
    152. End Sub
    153. Private Sub MainForm_Load( _
    154. ByVal sender As System.Object, _
    155. ByVal e As System.EventArgs) _
    156. Handles MyBase.Load
    157. ' Um das Programm zu benutzen, um einen
    158. ' Shell-Befehl auf der Konsole auszuführen
    159. ' (z.B. netstat oder ping) kann man anstelle
    160. ' von "cmd" bei Arguments einfach den
    161. ' entsprechenden Befehl (z.B. "ping") einfügen
    162. ' und in der Eigenschaft Arguments
    163. ' die entsprechenden Attribute
    164. ' (beispielsweise bei ping die IP-Adresse) angeben.
    165. m_Process = New Process()
    166. With m_Process.StartInfo
    167. .FileName = "cmd"
    168. .Arguments = ""
    169. .UseShellExecute = False
    170. .CreateNoWindow = True
    171. .RedirectStandardOutput = True
    172. .RedirectStandardError = True
    173. .RedirectStandardInput = True
    174. End With
    175. m_Process.Start()
    176. ' Ändern der Streams, sodass wir bei
    177. ' Änderungen etwas mitbekommen.
    178. Dim ts1 As ThreadStart = New ThreadStart(AddressOf StreamOutput)
    179. m_OutputThread = New Thread(ts1)
    180. m_OutputThread.Start()
    181. Dim ts2 As ThreadStart = New ThreadStart(AddressOf StreamError)
    182. m_ErrorThread = New Thread(ts2)
    183. m_ErrorThread.Start()
    184. End Sub
    185. Private Sub btnSend_Click( _
    186. ByVal sender As System.Object, _
    187. ByVal e As System.EventArgs) _
    188. Handles btnSend.Click
    189. StreamInput(txtCommandInput.Text)
    190. txtCommandInput.Clear()
    191. End Sub
    192. Private Sub MainForm_Closing( _
    193. ByVal sender As Object, _
    194. ByVal e As System.ComponentModel.CancelEventArgs) _
    195. Handles MyBase.Closing
    196. m_OutputThread.Abort()
    197. m_ErrorThread.Abort()
    198. End Sub
    199. End Class




    mfg OnkelR