2017-07-27 85 views
1

我想讓應用程序運行多個(adb專用)命令並獲取輸出並顯示在標籤中。無法更新文本框vb.net -crossthreading

首先,我需要啓動進程來執行命令。感謝stackoverflow和@pasty我發現這(第二個回覆):How to get Output of a Command Prompt Window line by line in Visual Basic?

嗯,我認爲,因爲它輸出到控制檯,它會很簡單,只要將它寫入標籤。大錯!它給我一個交叉線程錯誤! 谷歌搜索和堆棧溢出一點點,我發現這一點:vb.net accessed from a thread other than the thread it was created on

好了,我想實現這一點,但該程序只是崩潰凍結。

下面是代碼:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    ' store error output lines 

    Dim executable As String() = {"adb", "adb"} 
    Dim arguments As String() = {"help", "reboot"} 
    For i As Integer = 0 To 0 
     Dim process = New Process() 
     process.StartInfo = createStartInfo(executable(i), arguments(i)) 
     process.EnableRaisingEvents = True 
     AddHandler process.Exited, Sub(ByVal sendera As Object, ByVal ea As System.EventArgs) 
             Console.WriteLine(process.ExitTime) 
             Console.WriteLine(". Processing done.") 
             'UpdateTextBox(ea) 

            End Sub 
     ' catch standard output 
     AddHandler process.OutputDataReceived, Sub(ByVal senderb As Object, ByVal eb As DataReceivedEventArgs) 
                If (Not String.IsNullOrEmpty(eb.Data)) Then 
                 Console.WriteLine(String.Format("{0}> {1}", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss"), eb.Data)) 
                 'UpdateTextBox(eb.Data) 

                End If 
               End Sub 
     ' catch errors 
     AddHandler process.ErrorDataReceived, Sub(ByVal senderc As Object, ByVal ec As DataReceivedEventArgs) 
                Console.WriteLine(String.Format("! {0}", ec.Data)) 
                Dim a As String = String.Format("! {0}", ec.Data) 
                'UpdateTextBox(a) 
               End Sub 
     ' start process 
     Dim result = process.Start() 
     ' and wait for output 
     process.BeginOutputReadLine() 
     ' and wait for errors :-) 
     process.BeginErrorReadLine() 
     process.WaitForExit() 

    Next 

End Sub 

Private Sub UpdateTextBox(ByVal a As String) 
    If Me.InvokeRequired Then 
     Dim args() As String = {a} 
     Me.Invoke(New Action(Of String)(AddressOf UpdateTextBox), args) 
     Return 
    End If 
    Label1.Text += "a" 
End Sub 

Private Function createStartInfo(ByVal executable As String, ByVal arguments As String) As ProcessStartInfo 
    Dim processStartInfo = New ProcessStartInfo(executable, arguments) 
    processStartInfo.WorkingDirectory = Path.GetDirectoryName(executable) 
    ' we want to read standard output 
    processStartInfo.RedirectStandardOutput = True 
    ' we want to read the standard error 
    processStartInfo.RedirectStandardError = True 
    processStartInfo.UseShellExecute = False 
    processStartInfo.ErrorDialog = False 
    processStartInfo.CreateNoWindow = True 
    Return processStartInfo 

End Function 

和源代碼:https://github.com/iAmAOpenSource/SyncfusionWindowsFormsApplication3

+0

'該程序剛崩潰'您是否正在調試,並且您收到錯誤消息?或者是什麼? – djv

+0

@djv它只是凍結。應該更好地重寫它:)。沒有輸出或任何東西。需要在Visual Studio中學習調試。還有很長的一段路要走 –

+0

我的猜測是,調用'process.WaitForExit()'會阻塞UI線程,直到過程結束,並且當你在調用'process.OutputDataReceived'時得到一行輸出時'Me.Invoke',它試圖在被阻塞的UI線程上運行代碼,所以...凍結。您可能需要將啓動進程的邏​​輯移動到不同的線程上 - 也許只是將'Button1_Click'的內容包裝在'Task.Run'中。 – Mark

回答

0

process.WaitForExit()調用將阻塞UI線程直到衍生的進程退出,但在處理在process.OutputDataReceived事件輸出你正在調用Me.Invoke,它試圖在被阻塞的UI線程上運行代碼,所以程序凍結。您可以將Button1_Click中的邏輯移動到另一個線程上,例如

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    Task.Run(
     Sub() 
      ... current logic 
     End Sub 
    ) 
End Sub 

這樣的UI線程不會被堵塞,Me.Invoke調用不會導致死鎖。

+0

非常感謝。仍然有一個小問題,因爲'textbox'不被接受爲函數'UpdateTextBox'的參數,儘管我通過使用全局變量來存儲哪個文本框來輸出它(我知道我不應該這樣做,但它的工作原理:))。 –