C# 实时获取另一个应用程序标准输出

C# 实时获取另一个应用程序标准输出,c#,winforms,process,real-time,stdout,C#,Winforms,Process,Real Time,Stdout,我想通过我的WinForm应用程序实时获取控制台应用程序的输出(与通过cmd.exe运行相同)。我在非UI线程中执行的所有操作(使用BackgroundWorker的方法bwRezerve_DoWork)AddTextToTextbox使用Invoke更新UI 但现在我只在应用程序退出时接收输出。 我在这里和其他网站上读到了很多问题,读到了类似的问题,但仍然找不到解决办法。 下面是代码片段: private void bwRezerve_DoWork(object sender, DoWorkE

我想通过我的WinForm应用程序实时获取控制台应用程序的输出(与通过cmd.exe运行相同)。我在非UI线程中执行的所有操作(使用BackgroundWorker的方法bwRezerve_DoWork)
AddTextToTextbox
使用Invoke更新UI

但现在我只在应用程序退出时接收输出。 我在这里和其他网站上读到了很多问题,读到了类似的问题,但仍然找不到解决办法。 下面是代码片段:

private void bwRezerve_DoWork(object sender, DoWorkEventArgs e)
{
    proc = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = Application.StartupPath + Path.DirectorySeparatorChar + "7z.exe",
            Arguments = e.Argument,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true,
        }
    };
    proc.EnableRaisingEvents = true;
    proc.OutputDataReceived += (who, what) => AddTextToTextbox(what.Data);
    proc.ErrorDataReceived += (who, what) => AddTextToTextbox(what.Data);

    proc.Start();
    proc.BeginOutputReadLine();
    proc.BeginErrorReadLine();
    //same result with next line commented
    proc.WaitForExit(5 * 60 * 1000);
}
我也尝试了这个方法,而不是
OutputDataReceived
,但结果是一样的

while (!proc.StandardOutput.EndOfStream)
{
    string line = proc.StandardOutput.ReadLine();
    AddTextToTextbox(line);
}
试试这个代码

private void bwRezerve_DoWork(object sender, DoWorkEventArgs e)
{
    ProcessStartInfo psi = new ProcessStartInfo();
    psi.FileName = Application.StartupPath + Path.DirectorySeparatorChar + "7z.exe";
    psi.Arguments = e.Argument;
    psi.UseShellExecute = false;
    psi.RedirectStandardError = true;
    psi.RedirectStandardOutput = true;
    psi.CreateNoWindow = true;

    Process proc = Process.Start(psi);
    proc.WaitForExit();

    while (!proc.StandardOutput.EndOfStream)
    {
       string line = proc.StandardOutput.ReadLine();
       AddTextToTextbox(line);
    }
}

我认为你们的线程有问题,你们的进程在主线程下运行,所以你们的输出只有在进程完成时才会显示。 所以您需要使用后台工作线程,也可以使用dispatcher从当前进程获取输出

while (!proc.StandardOutput.EndOfStream)
{

  Application.Current.Dispatcher.Invoke(new Action(() =>
     {
    string line = proc.StandardOutput.ReadLine();
    AddTextToTextbox(line);
     }), null);

}
希望它对你有用

编辑

您可以使用 窗口基库

程序集:WindowsBase(在WindowsBase.dll中)()


7zip不使用标准输出-您可以很容易地看到,因为它不断地重写屏幕(以显示进度)。无法进行流式处理。

在这种情况下,我根本没有收到任何输入。我使用了ReadLine()和ReadToEnd()-结果仍然相同。新的更新正在运行,我刚刚在我的机器上检查了代码名称结果。从代码中很容易看出——在进程退出之前,我没有收到任何更新:
proc.WaitForExit()在标准输出读取之前。如果
proc.WaitForExit(),则结果相同在读取输出之后。我不能使用“Application.Current.Dispatcher.Invoke”,因为它是WinForms项目,而不是WPF。但是我在BackgroundWorker(bwRezerve_DoWork)中执行的所有操作。在“AddTextToTextbox”方法中,我使用Invoke在UI线程中执行更新。我不需要进度,我需要得到输出(在那里)。控制台应用程序本身不发送百分比。相同的结果-在控制台应用程序退出后显示输出(是的,
WaitForExit()
在该代码块之后)。但7zip不知何故将数据发送到cmd.exe,不是吗?我想捕获这些数据。@Varro不,
cmd
与此无关-那只是一个命令处理器。它将数据直接发送到控制台,如果您在应用程序中创建控制台,它将显示输出,就像
cmd
。如果不创建控制台,则无法获得输出。默认情况下,标准输出显示在控制台中,但这并不意味着控制台中显示的所有内容都要通过标准输出:)@Varro在C中的等价物是,例如,当您执行
console.CursorTop=0
-现在您正在写入控制台缓冲区而不是标准输出。现在,基础设施足够智能,您最终可以在stdout中获得输出,但它不能给您任何改变-stdout没有“倒带”功能,它只是一个流。您确定吗?根据7zip帮助(与此处相同),默认情况下,它会将标准输出消息重定向到标准输出流。@Varro您可以自己查看它。Stdout是append only-控制台是否仅从7z append输出?使用
>x.x
在cmd中运行7z。在解压过程中,文件是否立即包含您想要的所有内容(最新信息)(显然,请尝试使用大文件)?不,因为数据还没有在标准输出上-只在控制台中(当重定向标准输出时,控制台输出被禁用)。
-bd
开关应该已经解决了这个问题,但实际上似乎没有。
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
            {
                string line = proc.StandardOutput.ReadLine();
                AddTextToTextbox(line);
            }), null);