6

コマンドライン プロセスを実行し、そのプロセスがまだ実行されている間に出力を取得するにはどうすればよいですか?

つまり、独自のプログレスバーを使用して CLI プロセスを実行することです。実行可能ファイル自体が操作を完了するのに長い時間がかかるため、独自のプロセスからその進行状況情報を取得して、アプリケーションで進行状況を表示したいと考えています。プロセスが終了するまで進行状況を表示するための情報はありません。

コンソール アプリではなく、WindowsForm プロジェクトで作業しています。

FFMPEG.exe (x64) を使用して同じことを試みましたが、FFMPEG の実行中に「進行状況」を読み取ることができます。FFMPEG から進行状況を選択して、必要なことを行うことができますが、この実行可能ファイルではできませんそれが可能かどうかはわかりません。

プログラムは「dbPowerAmp CoreConverter」で、音楽コンバーターです。出力を読み取るには、出力エンコーディングをUnicodeに設定する必要があるため、プログラムはすべての出力をUnicodeエンコーディングで送信すると思います。

...その他の問題は、Unicode を使用してもこのプロセスの StandardError 出力を読み取る方法が見つからないことです。

アプリケーションは次のとおりです: 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

アップデート:

本当に私はとても絶望的です、私の意図はすべて壮大な失敗です、私は自分のスキルができることをすべて試しました(しかしそれはそれほど多くはありません).

メインスレッドから出力を取得しようとしているときにマルチスレッドを使用して別のスレッドでプロセスを実行しても、プロセスが終了するまでプロセス出力を取得しようとすることはできません。

ただ、私は毎日何時間も無駄にしているというクレイジーなことです.COMオブジェクトを作成することはできるかもしれないと私に言う人もいます.COMオブジェクトを作成する方法を学ぶのに何ヶ月も費やしたくありません.コンソールからいくつかの文字を選択するには、その月の学習は私の人生でこれ以上何の役にも立ちません。単純に、もっと基本的なものが必要です。バッファコンソールを読むというアイデアはうまくいくかもしれませんが、確かにそうではありませんプロセスが終了するまでバッファを読み取ることができるようにします。

そう。このいまいましいプロセスで何ができますか?

私自身の絶望的な言葉を言うために私の質問を更新するだけでなく、私が試したマルチスレッドのものをここに貼り付けます。

...私が言ったように、プロセスがまだ実行されている間に出力を読み取ろうとすることはできず、エラー出力は、プロセスが終了しても(もちろん意図的なエラーで)読み取れません(文字列は常に空です)。 .

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
4

3 に答える 3