从流程重定向StandardOutput

时间:2015-12-22 07:46:00

标签: winforms process ffmpeg c++-cli

我正在研究C ++ / CLI winforms 如何将标准输出重定向到文本框? 我关注了这个视频,但它没有用 https://www.youtube.com/watch?v=BDTCviA-5M8

我可以在控制台窗口看到输出,但直到进程完成GUI冻结!

ProcessStartInfo ^psi = gcnew ProcessStartInfo("D://ffmpeg.exe", "-y -i D://1.avi D://process.mp4");        
psi->WindowStyle = ProcessWindowStyle::Hidden;
psi->UseShellExecute = false;
psi->RedirectStandardOutput = true;
process->StartInfo = psi;

process->Start();
String^ details = process->StandardOutput->ReadToEnd();
textBox1->Text = details; 
Console::WriteLine(details); 

我哪里错了?

1 个答案:

答案 0 :(得分:1)

您读取标准输出有什么问题。由于您的代码只涉及一个threadf,因此没有其他选择可以让所有事情连续发生。如果要查看长时间运行的命令工具的进度/输出,则需要使用Process实例中的OutputDataReceived事件。

以下代码使用该技术来实现您的目标:

ref class ProcessForm:Form
{
    TextBox ^textBox1 = gcnew TextBox();
    Button ^button = gcnew Button();

public:
    ProcessForm() {
        this->Width = 325;
        this->Height = 450;
        textBox1->Top = 20;
        textBox1->Width = 300;
        textBox1->Height = 400;
        textBox1->Multiline = true;

        button->Text = "Start";
        button->Click += gcnew System::EventHandler(this, &ProcessForm::OnClick);

        this->Controls->Add(textBox1);
        this->Controls->Add(button);
    }

    void ProcessForm::OnClick(System::Object ^sender, System::EventArgs ^e)
    {
        Process ^process = gcnew Process();
        // "D://ffmpeg.exe", "-y -i D://1.avi D://process.mp4"
        ProcessStartInfo ^psi = gcnew ProcessStartInfo("cmd.exe", "/c dir \\*.exe /s");
        psi->WindowStyle = ProcessWindowStyle::Hidden;
        psi->UseShellExecute = false;
        psi->RedirectStandardOutput = true;
        process->StartInfo = psi;

        // handle incoming data from the standard output stream
        process->OutputDataReceived += gcnew DataReceivedEventHandler(this, &ProcessForm::OnOutputDataReceived);

        process->Start();
        // start reading from the standard ouput stream on a different thread
        process->BeginOutputReadLine();

        // prevent starting again ...
        process->Exited += gcnew System::EventHandler(this, &ProcessForm::OnExited);
        this->button->Enabled = false;
    }

    delegate void UpdateHandler(System::String ^text);

    // output the stuff on screen
    void ProcessForm::Update(System::String ^text)
    {
        textBox1->Text += text;
        Console::WriteLine(text);
    }

    // is invoked on a seperate thread if the process writes 
    // to the console
    void  ProcessForm::OnOutputDataReceived(System::Object ^sender, System::Diagnostics::DataReceivedEventArgs ^e)
    {
        // handle switching to the UI thread
        if (textBox1->InvokeRequired)
        {
            UpdateHandler^ handler = gcnew UpdateHandler(this, &ProcessForm::Update);
            textBox1->Invoke(handler, e->Data);
        }
        else 
        {
            Update(e->Data);
        }
    }

    // if we're done enable the button again
    void ProcessForm::OnExited(System::Object ^sender, System::EventArgs ^e)
    {
        this->button->Enabled = true;
    }

};

请注意,需要使用Invoke,因为从非UI线程调用事件方法。