Ele*_*ios 6 .net vb.net unicode winforms
如何在该进程仍在运行时运行命令行进程并获取输出?
我的意思是使用自己的进度条运行CLI进程,可执行文件本身需要很长时间才能完成操作,因此我想从自己的进程中获取进度信息以显示应用程序的进度,其他方式我不知道t有任何信息显示进度,直到过程结束.
我在WindowsForm项目中工作,而不是控制台应用程序.
我尝试使用FFMPEG.exe(x64)做同样的事情,我可以在FFMPEG运行时读取"进度",我可以从FFMPEG中选择进度并做我想要的,但是使用这个可执行文件我就是不能这样做,我不知道是否可能.
该程序是"dbPowerAmp CoreConverter",它是一个音乐转换器,我认为该程序以Unicode编码发送所有输出,因为要读取我需要将输出编码设置为Unicode的输出.
...其他问题是我找不到一种方法来读取此过程的StandardError输出,即使使用Unicode,所以如果有人可以帮助我解决这两个问题.
这是应用程序:http://www.dbpoweramp.com/install/dMC-R14.4-Ref-Trial.exe
以下是直接从CMD启动的程序的示例输出:

(我需要的是在进程运行时选择进度条"*"星号字符数量来计算并在我的应用程序中显示该百分比)
这是我的代码:
Private Shared CoreConverter As New Process()
Private Shared CoreConverter_Info As New ProcessStartInfo() With { _
.CreateNoWindow = True, _
.UseShellExecute = False, _
.RedirectStandardOutput = True, _
.RedirectStandardError = True _
}
Private Shared Sub Run_CoreConverter()
' Just for testing CMD Unicode output:
'
' CoreConverter_Info.FileName = "cmd"
' CoreConverter_Info.Arguments = "/U /C C:\CoreConverter.exe " & CoreConverter_Info.Arguments
CoreConverter_Info.FileName = "C:\CoreConverter.exe"
CoreConverter_Info.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""mp3 (Lame)""" ..., blah blah blah)
CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
CoreConverter.StartInfo = CoreConverter_Info
CoreConverter.EnableRaisingEvents = True
CoreConverter.Start()
CoreConverter.WaitForExit()
Dim readerStdOut As IO.StreamReader = CoreConverter.StandardOutput
' This part works with FFMPEG executable but not with Coreconverter.exe,
' What I mean is that the msgbox is displayed when CoreConverter.exe finishes :(
' but with FFMPEG I can read the output while FFMPEG still running.
While CoreConverter.StandardOutput.EndOfStream = True
MsgBox(CoreConverter.StandardOutput.ReadLine)
End While
If CoreConverter.ExitCode <> 0 Then
' Throw New Exception(CoreConverter.StandardError.ReadToEnd)
' No way to read the ErrorOutput...
MessageBox.Show(CoreConverter.StandardError.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
MessageBox.Show(CoreConverter.StandardOutput.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
更新:
真的我非常沮丧,我所有的意图都是史诗般的失败,我已经尝试了所有我的技能可以做的事情(但这并不多).
即使使用多线程在分离的线程中运行进程,而我尝试从主线程获取输出,我也无法尝试检索进程输出,直到进程退出,这太疯狂了!我不明白为什么会发生这种情况.
有些人告诉我,或许制作一个COM对象,我可以做到这一点,这是一个疯狂的事情,好吧,我不想花几个月学习如何制作一个COM对象从控制台中挑选几个角色,那几个月的学习对我生活中的任何事情都没有帮助,就像那样,我需要更基本的东西,也许读取缓冲控制台的想法可行,但我肯定不会能够读取缓冲区,直到进程退出,所以.
所以.我该怎么办这个该死的过程?
只是为了更新我的问题来说出我自己的desesperation字样,我将在这里粘贴一个我尝试过的多线程的东西.
...就像我说的那样,当进程仍在运行时我无法尝试读取输出,并且即使进程完成(错误的故障),错误输出也无法被重新编译(字符串始终为空) .
Public Shared error_output As String
Public Shared standard_output As String
Public Shared active As Boolean = False ' CoreConverter Thread is active?
Public Shared MyThread As Threading.Thread = New Threading.Thread(AddressOf Run_CoreConverter)
Public Shared Sub Convert_To_MP3(ByVal In_File As String, _
' blah blah blah
'Run_CoreConverter()
MyThread = New Threading.Thread(AddressOf Run_CoreConverter)
' MyThread.IsBackground = True
active = True
MyThread.Start()
Get_Output()
End Sub
Public Shared Sub Get_Output()
While active ' While Coreconverter.exe is runing...
Try
If Not CoreConverter.HasExited Then
MsgBox(CoreConverter.StandardOutput.ReadToEnd) ' This will not be displayed until process has exited...
End If
Catch ex As Exception
End Try
If error_output IsNot Nothing Then
MsgBox(error_output) ' This will not be displayed until process has exited...
End If
If standard_output IsNot Nothing Then
MsgBox(standard_output) ' This will not be displayed until process has exited...
End If
End While
MsgBox("end active")
End Sub
Public Shared Sub Run_CoreConverter()
CoreConverter_Info.FileName = CoreConverter_Location
CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
CoreConverter.StartInfo = CoreConverter_Info
CoreConverter.EnableRaisingEvents = False
CoreConverter.Start()
' CoreConverter.WaitForExit()
' Threading.Thread.Sleep(2000)
' For x As Integer = 0 To 99999999
error_output = CoreConverter.StandardError.ReadToEnd
standard_output = CoreConverter.StandardOutput.ReadToEnd
' Next
If CoreConverter.ExitCode <> 0 Then
Throw New Exception(CoreConverter.StandardError.ReadToEnd)
MessageBox.Show(CoreConverter.StandardError.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
MessageBox.Show(CoreConverter.StandardOutput.ReadToEnd, "CoreConverter", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
CoreConverter.Close()
active = False
End Sub
Run Code Online (Sandbox Code Playgroud)
我认为dbPowerAmp的编码可能存在错误.在cmd.exe/u Unicode环境中输出看起来很棒,但是当你挂钩.Net Process对象时,它最终会在字符之间出现空字节.您可以通过在良好的UTF8字符之间丢弃空字节来解决此问题.
我在PowerShell中更流利,所以这就是我写的,以证明这将有效.
$progressCounter = 0.0
$progressScaleString = "0%-----------25%-----------50%-----------75%-----------100%"
$psi = new-object system.diagnostics.processstartinfo
$psi.FileName = "C:\Program Files (x86)\Illustrate\dBpoweramp\CoreConverter.exe"
# Moby Dick audiobook available at <http://ia600208.us.archive.org/0/items/moby_dick_librivox/mobydick_135_melville.mp3>
$psi.arguments = '-infile="C:\AudioBooks\mobydick_135_melville.mp3" -outfile="c:\AudioBooks\mobydick_135_melville.flac" -convert_to="flac" -encoding="SLOW"'
$psi.StandardOutputEncoding = [System.Text.Encoding]::Unicode
$psi.RedirectStandardOutput = $true
$psi.UseShellExecute = $false
$proc = new-object System.Diagnostics.Process
$proc.StartInfo = $psi
$proc.Start();
#Look for the magic progress bar string
$outputBuf = ""
while($true){ $chr = [char]$proc.StandardOutput.BaseStream.ReadByte(); if($chr -ne [char]0){ $outputBuf += $chr; } if($outputBuf.Contains($progressScaleString)){ break; }else{ sleep .01; }}
#We've seen the progress ruler, now start counting the pips.
while($progressCounter -le 100.0){ $chr = $proc.StandardOutput.BaseStream.ReadByte(); if($chr -lt 0){break;} if([char]$chr -eq [char]"*"){ $progressCounter += 100.0/($progressScaleString.Length+1); write-host $progressCounter; }}
Run Code Online (Sandbox Code Playgroud)
这是我将此移植到VB的难点; 只需在工作线程上运行它并将PercentDone挂钩到您的UI:
Public Event PercentDone(ByVal Percent As Float)
Private Shared CoreConverter As New Process()
Private Shared CoreConverter_Info As New ProcessStartInfo() With { _
.CreateNoWindow = True, _
.UseShellExecute = False, _
.RedirectStandardOutput = True, _
.RedirectStandardError = True _
}
Private Shared Sub Run_CoreConverter()
Dim ProgressScaleString As String = "0%-----------25%-----------50%-----------75%-----------100%"
Dim ProgressCounter As Float = 0.0
CoreConverter_Info.FileName = "C:\CoreConverter.exe"
CoreConverter_Info.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""mp3 (Lame)""" ..., blah blah blah)
CoreConverter_Info.StandardErrorEncoding = System.Text.Encoding.Unicode
CoreConverter_Info.StandardOutputEncoding = System.Text.Encoding.Unicode
CoreConverter.StartInfo = CoreConverter_Info
CoreConverter.Start()
Dim OutputBuf As String = ""
Dim chr As Byte;
While True
chr = CoreConverter.StandardOutput.BaseStream.ReadByte();
If chr < 0 Then
Exit While
ElseIf chr <> 0
OutputBuf += CType(chr, Char)
End If
If OutputBuf.Contains(ProgressScaleString) Then
Exit While
Else
System.Threading.Thread.Sleep(10)
End If
End While
While ProgressCounter <= 100
chr = CoreConverter.StandardOutput.BaseStream.ReadByte()
If chr <= 0 Then
Exit While
End If
If chr == CType("*"C, Char) Then
ProgressCounter += 100.0/($progressScaleString.Length+1)
RaiseEvent PercentDone(ProgressCounter)
End If
End While
End Sub
Run Code Online (Sandbox Code Playgroud)