在WinForm进程中,如何检测命令行子进程何时需要输入

本文关键字:命令行 检测 子进程 何时需 输入 进程 WinForm 何检测 | 更新日期: 2023-09-27 18:09:08

在调用第三方命令行工具的WinForm应用程序中,可能会有一段时间工具需要用户输入,例如询问是否应该覆盖文件:

printf("%s already exists, overwrite?: <Y>es, <N>o, <A>ll, <Q>uit?",FName);
for ( ; ; )
    switch ( toupper(getch()) ) {
        case 'A':
            YesToAll=true;
        case ''r': 
        case 'Y':
            remove(FName);
            return true;
        case 0x1B: 
        case 'Q':
            printf("quit'n"); exit(-1);
        case 'N':                       
            return false;
    }

当发生这种情况时,我希望在对话框中显示来自printf()的消息和选项,并将按钮单击重定向为流程的输入。它可能涉及到使用System.Diagnostics.Process.StandardInput发送输入。但是,如果不知道工具何时期望输入,我就不知道何时在GUI中做出相应的反应。当进程处于for循环时,我的WinForm进程将冻结。

EDIT:这是通过在另一个线程中启动进程来解锁UI的代码,但是我仍然无法读取输出,如果我选择的文件将导致工具询问覆盖选项。proc_OutputDataReceived (EDIT2:或proc.StandardOutput.BaseStream.BeginRead中的readStdOut)将永远不会被调用,除非工具不要求输入)。

    private BackgroundWorker worker = new BackgroundWorker();
    private void fileChosenHandler(object sender, EventArgs e)
    {
        OpenFileDialog dialog = sender as OpenFileDialog;
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.RunWorkerAsync(dialog.FileName);
    }
    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        string exePath = @"F:'test'test.exe";
        Process proc = new Process();
        proc.StartInfo.FileName = exePath; 
        proc.StartInfo.Arguments = "'"" + (string)e.Argument + "'""; 
        proc.StartInfo.UseShellExecute = false; 
        proc.StartInfo.CreateNoWindow = true;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
        proc.Start();
        // method 1: read lines
        //proc.BeginOutputReadLine();
        // method 2: read characters
        proc.StandardOutput.BaseStream.BeginRead(stdOutBuffer, 0, stdOutBuffer.Length, readStdOut, proc);
        proc.WaitForExit();
    }
    private void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        MessageBox.Show("Output: " + e.Data);
    }
    private byte[] stdOutBuffer = new byte[20]; 
    private void readStdOut(IAsyncResult result)
    {
        Process proc = result.AsyncState as Process;
        int bytesNumber = proc.StandardOutput.BaseStream.EndRead(result);
        if (bytesNumber != 0)
        {
            string text = System.Text.Encoding.ASCII.GetString(stdOutBuffer, 0, bytesNumber);
            MessageBox.Show("Output: " + text);
        }
        // set up the callback again
        proc.StandardOutput.BaseStream.BeginRead(stdOutBuffer, 0, stdOutBuffer.Length, readStdOut, proc);
    }

你知道怎么做吗?谢谢!

在WinForm进程中,如何检测命令行子进程何时需要输入

System.Diagnostics.StandardOutput读取(如果您使用阻塞读取,则必须在单独的线程中执行),直到找到该字符串的匹配,然后显示消息框并根据用户选择将字符发送到进程的StandardInput


我们尝试的事情的快速总结:

  • 使用BeginOutputReadLine ->的"正常"异步读取肯定会失败,因为来自应用程序的消息没有以''n'终止;
  • 异步读取1字节块->似乎失败,因为应用程序没有刷新缓冲区;
  • 添加一个fflush(stdout)到C应用程序+前面的方法:成功!显然,程序没有在getch() .
  • 之前刷新输出缓冲区。
有趣的是,这可能不会发生在使用标准iostreams的c++应用程序中,因为cin绑定到cout,并且在cin上的任何输入操作发生之前,cout会自动刷新。我认为这是合理的,这样的事情也发生在stdin/stdout,但我似乎找不到任何参考它进入标准(事实上,聊天getch()是非标准的,不同于其他IO函数在未缓冲可能是相关的)。

要了解更多信息,请参阅评论。:)