运行命令行进程并在该进程仍在运行时获取输出?

时间:2013-10-03 22:17:32

标签: .net vb.net winforms unicode

如何在该进程仍在运行时运行命令行进程并获取输出?

我的意思是使用自己的进度条运行CLI进程,可执行文件本身需要很长时间才能完成操作,所以我想从自己的进程中获取进度信息,以便在我的应用程序中显示进度,其他方式在处理完成之前,我没有任何信息显示进度。

我在WindowsForm项目中工作,而不是控制台应用。

我尝试使用FFMPEG.exe(x64)做同样的事情,我可以在FFMPEG运行时读取“进度”,我可以从FFMPEG中选择进度并做我想要的,但是这个可执行文件我只是不能做到,我不知道是否可能。

该程序是“dbPowerAmp CoreConverter”,它是一个音乐转换器,我认为程序以Unicode编码发送所有输出,因为要读取我需要将输出编码设置为Unicode的输出。

...其他问题是我找不到一种方法来读取此过程的StandardError输出,即使使用Unicode也是如此,如果有人可以帮我解决这两个问题。

以下是申请:http://www.dbpoweramp.com/install/dMC-R14.4-Ref-Trial.exe

以下是直接从CMD启动的程序的示例输出:

enter image description here

(我需要的是在进程运行时选择进度条“*”星号字符数量来计算并在我的应用程序中显示该百分比)

这是我的代码:

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
  

更新:

我真的很沮丧,所有的意图都是史诗般的失败,我已经尝试了所有我的技能可以做的事情(但这并不多)。

即使使用多线程在分离的线程中运行进程,而我尝试从主线程获取输出,我也无法尝试检索进程输出,直到进程退出,这很疯狂!,我不明白为什么有时候是这样的。

有些人告诉我,或许制作一个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

3 个答案:

答案 0 :(得分:5)

我认为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; }}

这是我将此移植到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

答案 1 :(得分:3)

这个过程正在写一行星(*)。我可以检查它将输出重定向到文件(>out.txt)。您应该使用CoreConverter.StandardOutput.Read

让我们有一个带有多行TextBox的表单,名为txtResult,按钮为cmdStart:

Private Sub cmdStart_Click(sender As Object, e As EventArgs) Handles cmdStart.Click
        Dim ProcInfo As New ProcessStartInfo With
            {.FileName = "C:\dbpower\dBpoweramp\CoreConverter.exe",
             .RedirectStandardOutput = True, .UseShellExecute = False,
             .WorkingDirectory = "C:\dbpower\dBpoweramp", .Arguments = "-infile=""0.mp3"" -outfile=""1.mp3"" -convert_to=""mp3 (lame)"""} '
        Dim proc As Process = Process.Start(ProcInfo)
        Dim counter As Integer = 0
        While Not proc.HasExited

            Dim a As String = ChrW(proc.StandardOutput.Read)
            If a = "*" Then
                counter += 1
                txtResult.Text = counter
                Application.DoEvents()
            End If
            Threading.Thread.Sleep(3)
            Application.DoEvents()
        End While

End Sub

将进度写入TextBox,编号为1-59。您可以轻松将其转换为进度条。 Plase不要忘记更改.exe路径。

答案 2 :(得分:1)

最后这就是我为解决问题所做的工作,以便能够以“简单的方式”检索两个输出:

#Region " Process Info "

' CoreConverter Process Information.
Private Shared CoreConverter As New Process() With { _
    .StartInfo = New ProcessStartInfo With { _
    .CreateNoWindow = True, _
    .UseShellExecute = False, _
    .RedirectStandardError = True, _
    .RedirectStandardOutput = True, _
    .StandardErrorEncoding = System.Text.Encoding.Unicode, _
    .StandardOutputEncoding = System.Text.Encoding.Unicode}}

#End Region

' Some code
' Blah blah blah...

#Region " Run Converter Procedure "

Private Shared Sub Run_CoreConverter()

    CoreConverter.StartInfo.FileName = CoreConverter_Location
    CoreConverter.Start()

    While Not CoreConverter.HasExited

        OutputCharacter = ChrW(CoreConverter.StandardOutput.Read)

        If OutputCharacter = "*" Then
            CurrentProgress += 1 ' Maximum value is 59, so a ProgressBar Maximum property value would be 59.
            RaiseEvent PercentDone(CurrentProgress, Nothing)
        End If

        If CurrentProgress = 59 Then
            ' I store only the last line 'cause it has interesting information:
            ' Example message: Conversion completed in 30 seconds x44 realtime encoding
            StandardOutput = CoreConverter.StandardOutput.ReadToEnd.Trim
        End If

    End While

    ErrorOutput = CoreConverter.StandardError.ReadToEnd

    Select Case CoreConverter.ExitCode

        Case 0 : RaiseEvent Exited(StandardOutput, Nothing) ' Return StandardOutput
        Case Else : RaiseEvent Exited(ErrorOutput, Nothing) ' Return ErrordOutput

    End Select

    CurrentProgress = 0
    OutputCharacter = Nothing
    StandardOutput = Nothing
    ErrorOutput = Nothing
    ' CoreConverter.Close()

End Sub

#End Region
  

更新:

如果有人需要,这是完整的课程:

#Region " CoreConverter Helper "



' [ CoreConverter Helper ]
'
' // By Elektro H@cker
'
'
' Instructions:
'
' 1. Add the "CoreConverter.exe" into the project,
'    together with the dbPoweramp Effects and Codec folders.
'
' Examples :
'
' -------------------
' CONVERT FILE TO MP3
' -------------------
' CoreConverter.Convert_To_MP3("C:\Input.wav", "C:\Output.mp3", _
'                              CoreConverter.Lame_Bitrate.kbps_320, _
'                              CoreConverter.Lame_Bitrate_Mode.cbr, _
'                              CoreConverter.Lame_Profile.SLOW, _
'                              CoreConverter.Lame_Quality.Q0_Maximum, _
'                              CoreConverter.Lame_Khz.Same_As_Source, _
'                              CoreConverter.Lame_Channels.auto, _
'                              { _
'                                CoreConverter.DSP_Effects.Delete_Output_File_on_Error, _
'                                CoreConverter.DSP_Effects.Recycle_Source_File_After_Conversion _
'                              }, _
'                              False, _
'                              CoreConverter.Priority.normal)
'
' -------------------
' CONVERT FILE TO WAV
' -------------------
' CoreConverter.Convert_To_WAV_Uncompressed("C:\Input.mp3", "C:\Output.wav", _
'                                           CoreConverter.WAV_Uncompressed_Bitrate.Same_As_Source, _
'                                           CoreConverter.WAV_Uncompressed_Khz.Same_As_Source, _
'                                           CoreConverter.WAV_Uncompressed_Channels.Same_As_Source, , False)
'
' -------------------
' CONVERT FILE TO WMA
' -------------------
' CoreConverter.Convert_To_WMA("C:\Input.mp3", "C:\Output.wma", _
'                              CoreConverter.WMA_9_2_BitRates.Kbps_128, _
'                              CoreConverter.WMA_9_2_Khz.Khz_44, _
'                              CoreConverter.WMA_9_2_Channels.stereo, , False)
'
' ------
' EVENTS
' ------
' Public WithEvents Converter As New CoreConverter()
'
' Sub Converter_Progress(Progress As Integer, e As EventArgs) Handles Converter.PercentDone
'     ProgressBar1.Maximum = 59
'     ProgressBar1.Step = 1
'     ProgressBar1.PerformStep()
' End Sub
'
' Sub Converter_Message(Message As String, e As EventArgs) Handles Converter.Exited
'     ProgressBar1.Value = 0
'     MessageBox.Show(Message)
' End Sub



Public Class CoreConverter : Implements IDisposable

#Region " Variables "

    ' <summary>
    ' Gets or sets CoreConverter.exe executable path.
    ' </summary>
    Public Shared CoreConverter_Location As String = ".\CoreConverter.exe"

    ' Stores the CoreConverter process progress
    Private Shared CurrentProgress As Integer = 0

    ' Stores the CoreConverter process StandarOutput
    Private Shared StandardOutput As String = String.Empty

    ' Stores the CoreConverter process ErrorOutput
    Private Shared ErrorOutput As String = String.Empty

    ' Stores the next output character
    Private Shared OutputCharacter As Char = Nothing

    ' Stores the DSP Effects formatted string
    Private Shared Effects As String = String.Empty

#End Region

#Region " Events "

    ' <summary>
    ' Event raised when conversion progress changes.
    ' </summary>
    Public Shared Event PercentDone As EventHandler(Of PercentDoneEventArgs)
    Public Class PercentDoneEventArgs : Inherits EventArgs
        Public Property Progress As Integer
    End Class

    ' <summary>
    ' Event raised when CoreConverter process has exited.
    ' </summary>
    Public Shared Event Exited As EventHandler(Of ExitedEventArgs)
    Public Class ExitedEventArgs : Inherits EventArgs
        Public Property Message As String
    End Class

#End Region

#Region " Process Info "

    ' CoreConverter Process Information.
    Private Shared CoreConverter As New Process() With { _
        .StartInfo = New ProcessStartInfo With { _
        .CreateNoWindow = True, _
        .UseShellExecute = False, _
        .RedirectStandardError = True, _
        .RedirectStandardOutput = True, _
        .StandardErrorEncoding = System.Text.Encoding.Unicode, _
        .StandardOutputEncoding = System.Text.Encoding.Unicode}}

#End Region

#Region " CoreConverter Enumerations "

    ' Priority level of CoreConverter.exe
    Enum Priority
        idle
        low
        normal
        high
    End Enum

    ' DSP Effects
    Public Enum DSP_Effects
        Delete_Output_File_on_Error ' Delete failed conversion (not deletes source file).
        Delete_Source_File_After_Conversion ' Delete source file after conversion.
        Recycle_Source_File_After_Conversion ' Send source file to recycle bin after conversion.
        Karaoke_Remove_Voice ' Remove voice from file.
        Karaoke_Remove_Instrument ' Remove instruments from file.
        Reverse ' Reverse complete audio file.
        Write_Silence ' Write silence at start of file.
    End Enum

#End Region

#Region " Codec Enumerations "

    Enum Lame_Bitrate
        kbps_8 = 8
        kbps_16 = 16
        kbps_24 = 24
        kbps_32 = 32
        kbps_40 = 40
        kbps_48 = 48
        kbps_56 = 56
        kbps_64 = 64
        kbps_80 = 80
        kbps_96 = 96
        kbps_112 = 112
        kbps_128 = 128
        kbps_144 = 144
        kbps_160 = 160
        kbps_192 = 192
        kbps_224 = 224
        kbps_256 = 256
        kbps_320 = 320
    End Enum

    Enum Lame_Bitrate_Mode
        cbr
        abr
    End Enum

    Enum Lame_Profile
        NORMAL
        FAST
        SLOW
    End Enum

    Enum Lame_Quality
        Q0_Maximum = 0
        Q1 = 1
        Q2 = 2
        Q3 = 3
        Q4 = 4
        Q5 = 5
        Q6 = 6
        Q7 = 7
        Q8 = 8
        Q9_Minimum = 9
    End Enum

    Enum Lame_Khz
        Same_As_Source
        khz_8 = 8000
        khz_11 = 11000
        khz_12 = 12000
        khz_16 = 16000
        khz_22 = 22000
        khz_24 = 24000
        khz_32 = 32000
        khz_44 = 44100
        khz_48 = 48000
    End Enum

    Enum Lame_Channels
        auto
        mono
        stereo
        joint_stereo
        forced_joint_stereo
        forced_stereo
        dual_channels
    End Enum

    Enum WAV_Uncompressed_Bitrate
        Same_As_Source
        bits_8 = 8
        bits_16 = 16
        bits_24 = 24
        bits_32 = 32
    End Enum

    Enum WAV_Uncompressed_Khz
        Same_As_Source
        khz_8 = 8000
        khz_11 = 11000
        khz_12 = 12000
        khz_16 = 16000
        khz_22 = 22000
        khz_24 = 24000
        khz_32 = 32000
        khz_44 = 44100
        khz_48 = 48000
        khz_96 = 96000
        khz_192 = 192000
    End Enum

    Enum WAV_Uncompressed_Channels
        Same_As_Source
        Channels_1_Mono = 1
        Channels_2_Stereo = 2
        Channels_3 = 3
        Channels_4_Quadraphonic = 4
        Channels_5_Surround = 5
        Channels_6_Surround_DVD = 6
        Channels_7 = 7
        Channels_8_Theater = 8
    End Enum

    Enum WMA_9_2_BitRates
        Kbps_12 = 12
        Kbps_16 = 16
        Kbps_20 = 20
        Kbps_22 = 22
        Kbps_24 = 24
        Kbps_32 = 32
        Kbps_40 = 40
        Kbps_48 = 48
        Kbps_64 = 64
        Kbps_80 = 80
        Kbps_96 = 96
        Kbps_128 = 128
        Kbps_160 = 160
        Kbps_192 = 192
        Kbps_256 = 256
        Kbps_320 = 320
    End Enum

    Enum WMA_9_2_Khz
        Khz_8 = 8
        Khz_16 = 16
        Khz_22 = 22
        Khz_32 = 32
        Khz_44 = 44
        Khz_48 = 48
    End Enum

    Enum WMA_9_2_Channels
        mono
        stereo
    End Enum

#End Region

#Region " Codec Procedures "

#Region " MP3 Lame "

    ' <summary>
    ' Converts a file to MP3 using Lame codec.
    ' </summary>
    Public Shared Sub Convert_To_MP3(ByVal In_File As String, _
                             ByVal Out_File As String, _
                             ByVal Bitrate As Lame_Bitrate, _
                             ByVal Bitrate_Mode As Lame_Bitrate_Mode, _
                             ByVal Encoding_Profile As Lame_Profile, _
                             ByVal Quality As Lame_Quality, _
                             ByVal Khz As Lame_Khz, _
                             ByVal Channels As Lame_Channels, _
                             Optional ByVal DSP_Effects() As DSP_Effects = Nothing, _
                             Optional ByVal Update_Tag As Boolean = True, _
                             Optional ByVal Priority As Priority = Priority.normal, _
                             Optional ByVal Processor As Short = 1)

        If DSP_Effects IsNot Nothing Then

            Effects = String.Empty

            For X As Integer = 0 To DSP_Effects.Length - 1
                Effects &= String.Format(" -dspeffect{0}={1}", _
                                         X + 1, _
                                         Format_DSP_Effect(DSP_Effects(X).ToString))
            Next

        End If

        CoreConverter.StartInfo.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""mp3 (Lame)"" {2} {3} -priority=""{4}"" -processor=""{5}"" -b {6} {7} -encoding=""{8}"" -freq=""{9}"" -channels=""{10}"" --noreplaygain --extracli=""-q {11}""", _
                                       In_File, _
                                       Out_File, _
                                       If(Not Update_Tag, "-noidtag", ""), _
                                       Effects, _
                                       Priority.ToString, _
                                       Processor, _
                                       CInt(Bitrate), _
                                       "--" & Bitrate_Mode.ToString, _
                                       Encoding_Profile.ToString, _
                                       If(Khz = Lame_Khz.Same_As_Source, "", CInt(Khz)), _
                                       If(Channels = Lame_Channels.auto, "", Channels), _
                                       CInt(Quality))
        Run_CoreConverter()

    End Sub

#End Region

#Region " WAV Uncompressed "

    ' <summary>
    ' Converts a file to WAV
    ' </summary>
    Public Shared Sub Convert_To_WAV_Uncompressed(ByVal In_File As String, _
                                 ByVal Out_File As String, _
                                 ByVal Bitrate As WAV_Uncompressed_Bitrate, _
                                 ByVal Khz As WAV_Uncompressed_Khz, _
                                 ByVal Channels As WAV_Uncompressed_Channels, _
                                 Optional ByVal DSP_Effects() As DSP_Effects = Nothing, _
                                 Optional ByVal Update_Tag As Boolean = True, _
                                 Optional ByVal Priority As Priority = Priority.normal, _
                                 Optional ByVal Processor As Short = 1)

        If DSP_Effects IsNot Nothing Then

            Effects = String.Empty

            For X As Integer = 0 To DSP_Effects.Length - 1
                Effects &= String.Format(" -dspeffect{0}={1}", _
                                         X + 1, _
                                         Format_DSP_Effect(DSP_Effects(X).ToString))
            Next

        End If

        CoreConverter.StartInfo.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""Wave"" {2} {3} -priority=""{4}"" -processor=""{5}"" -compression=""PCM"" -bits=""{6}"" -freq=""{7}"" -channels=""{8}""", _
                                       In_File, _
                                       Out_File, _
                                       If(Not Update_Tag, "-noidtag", ""), _
                                       Effects, _
                                       Priority.ToString, _
                                       Processor, _
                                       If(Bitrate = WAV_Uncompressed_Bitrate.Same_As_Source, "", CInt(Bitrate)), _
                                       If(Khz = WAV_Uncompressed_Khz.Same_As_Source, "", CInt(Khz)), _
                                       If(Channels = WAV_Uncompressed_Channels.Same_As_Source, "", CInt(Channels)))
        Run_CoreConverter()

    End Sub

#End Region

#Region " WMA 9.2 "

    ' <summary>
    ' Converts a file to WMA 9.2
    ' </summary>
    Public Shared Sub Convert_To_WMA(ByVal In_File As String, _
                                 ByVal Out_File As String, _
                                 ByVal Bitrate As WMA_9_2_BitRates, _
                                 ByVal Khz As WMA_9_2_Khz, _
                                 ByVal Channels As WMA_9_2_Channels, _
                                 Optional ByVal DSP_Effects() As DSP_Effects = Nothing, _
                                 Optional ByVal Update_Tag As Boolean = True, _
                                 Optional ByVal Priority As Priority = Priority.normal, _
                                 Optional ByVal Processor As Short = 1, _
                                 Optional ByVal LogFile As String = ".\CoreConverter.log")

        If DSP_Effects IsNot Nothing Then

            Effects = String.Empty

            For X As Integer = 0 To DSP_Effects.Length - 1
                Effects &= String.Format(" -dspeffect{0}={1}", _
                                         X + 1, _
                                         Format_DSP_Effect(DSP_Effects(X).ToString))
            Next

        End If

        CoreConverter.StartInfo.Arguments = String.Format("-infile=""{0}"" -outfile=""{1}"" -convert_to=""Windows Media Audio 10"" {2} {3} -priority=""{4}"" -processor=""{5}"" -codec=""Windows Media Audio 9.2"" -settings=""{6} kbps, {7} kHz, {8} CBR""",
                                       In_File, _
                                       Out_File, _
                                       If(Not Update_Tag, "-noidtag", ""), _
                                       Effects, _
                                       Priority.ToString, _
                                       Processor, _
                                       CInt(Bitrate), _
                                       CInt(Khz), _
                                       Channels.ToString)
        Run_CoreConverter()

    End Sub

#End Region

#End Region

#Region " Run Converter Procedure "

    Private Shared Sub Run_CoreConverter()

        CoreConverter.StartInfo.FileName = CoreConverter_Location
        CoreConverter.Start()

        While Not CoreConverter.HasExited

            OutputCharacter = ChrW(CoreConverter.StandardOutput.Read)

            If OutputCharacter = "*" Then
                CurrentProgress += 1 ' Maximum value is 59, so a ProgressBar Maximum property value would be 59.
                RaiseEvent PercentDone(CurrentProgress, Nothing)
            End If

            If CurrentProgress = 59 Then
                ' I store only the last line 'cause it has interesting information:
                ' Example message: Conversion completed in 30 seconds x44 realtime encoding
                StandardOutput = CoreConverter.StandardOutput.ReadToEnd.Trim
            End If

        End While

        ' Stores the Error Message (If any)
        ErrorOutput = CoreConverter.StandardError.ReadToEnd

        Select Case CoreConverter.ExitCode

            Case 0 : RaiseEvent Exited(StandardOutput, Nothing) ' Return StandardOutput
            Case Else : RaiseEvent Exited(ErrorOutput, Nothing) ' Return ErrordOutput

        End Select

        CurrentProgress = 0
        OutputCharacter = Nothing
        StandardOutput = Nothing
        ErrorOutput = Nothing
        CoreConverter.Close()

    End Sub

#End Region

#Region " Miscellaneous functions "

    ' <summary>
    ' Checks if CoreConverter process is avaliable.
    ' </summary>
    Public Shared Function Is_Avaliable() As Boolean
        Return IO.File.Exists(CoreConverter_Location)
    End Function

    ' Returns the DSP Effects formatted string
    Private Shared Function Format_DSP_Effect(ByVal Effect As String)

        Select Case Effect
            Case "Reverse" : Return """Reverse"""
            Case "Delete_Output_File_on_Error" : Return """Delete Destination File on Error="""
            Case "Recycle_Source_File_After_Conversion" : Return """Delete Source File=-recycle"""
            Case "Delete_Source_File_After_Conversion" : Return """Delete Source File="""
            Case "Karaoke_Remove_Voice" : Return """Karaoke (Voice_ Instrument Removal)="""
            Case "Karaoke_Remove_Instrument" : Return """Karaoke (Voice_ Instrument Removal)=-i"""
            Case "Write_Silence" : Return """Write Silence=-lengthms={qt}2000{qt}""" ' 2 seconds
            Case Else : Return String.Empty
        End Select

    End Function

#End Region

#Region " Dispose Objects "

    Public Sub Dispose() Implements IDisposable.Dispose
        ' CoreConverter_Location = Nothing ' Don't touch
        OutputCharacter = Nothing
        StandardOutput = Nothing
        ErrorOutput = Nothing
        CurrentProgress = Nothing
        Effects = Nothing
        CoreConverter.Close()
        GC.SuppressFinalize(Me)
    End Sub

#End Region

End Class

#End Region