2017-07-27 51 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'的参数,尽管我通过使用全局变量来存储哪个文本框来输出它(我知道我不应该这样做,但它的工作原理:))。 –