1

正如标题所说,我有一个使用暂停的批处理文件。这是我将用来解释问题的示例批处理文件:

@echo off
pause
echo DONE
pause

从资源管理器运行批处理文件时,它显示以下内容:

"Press any key to continue..."

命令0

然后当用户按下一个键时,将显示以下内容:

Press any key to continue...
DONE
Press any key to continue...

cmd1

我遇到的问题是,当从我的 Windows 窗体应用程序运行这个 .bat 文件时,输出不会显示“按任意键继续...”,直到用户按下一个键。这是一个问题,因为用户需要知道他们需要在按下某个键之前按下它。这是显示该问题的视频。

当批处理文件执行时,左侧的圆圈变为灰色。然后鼠标移动到文本框,我按下键盘上的一个键。然后输出文本框显示文本。

所以我正在试验,我在 .bat 文件中添加了一行:

@echo off
echo Why is this line showing but the other line doesn't until i press a key?
pause
echo DONE
pause

这是结果

所以这里是代码:

void StartNewProcess(string batchFile)
    {
        //Focuses the input textbox
        Input_TextBox.Focus();
        //Set up process
        ProcessStartInfo processStartInfo = new ProcessStartInfo(batchFile);
        processStartInfo.WorkingDirectory = appDir;
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardError = true;
        processStartInfo.RedirectStandardInput = true;
        processStartInfo.UseShellExecute = false;
        processStartInfo.CreateNoWindow = true;
        process = new Process();
        process.EnableRaisingEvents = true;
        process.StartInfo = processStartInfo;
        //Start process
        process.Start();
        process.BeginOutputReadLine();
        //This is the input textbox
        stdin = process.StandardInput;

        process.OutputDataReceived += (s, evt) =>
        {
            if (evt.Data != null)
            {
                BeginInvoke(new MethodInvoker(() => {

                    newOutputLine = evt.Data; //Reference to current incoming line of text
                    Output_TextBox.AppendText(newOutputLine + Environment.NewLine);
                    Output_TextBox.ScrollToCaret();
                    if (evt.Data == "DONE")
                    {
                        MessageBox.Show("Task completed successfully!", "Notification");
                        Output_TextBox.Text = ""; //Clear the output textbox
                    }
                }));
            }
        };
        
        process.Exited += (s, evt) => {
            process.Close();
            if (process != null)
            {
                process.Dispose();
            }
        };
    }

    private void Input_Panel_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar == (char)Keys.Enter)
        {
            stdin.WriteLine(Input_TextBox.Text);
        }
    }

我到底需要做什么才能在按下键之前显示“按任意键继续...”?

这不是我遇到的这个问题的唯一例子。例如,如果批处理文件需要输入一个值作为对选择的响应,则在输入答案之前不会显示问题......例如“输入您的姓名:”直到用户输入后才会显示输入名称并按回车键,此时将显示“输入您的姓名:样品名称”。这对用户没有帮助,因为他们需要知道在输入之前需要输入名称。

我有许多批处理文件,其中显示了很多选择,并且用户需要知道这些选择是什么才能使我的应用程序正常工作。所以这个功能就像主要的部分。xD

有任何想法吗?

谢谢

编辑 所以感谢@MatthewMiller 为我提供了解决方案。所以这里适用于其他所有人:

void StartNewProcess(string batchFile)
    {
        //Set up process
        ProcessStartInfo processStartInfo = new   ProcessStartInfo(batchFile);
        processStartInfo.WorkingDirectory = appDir;
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardError = true;
        processStartInfo.RedirectStandardInput = true;
        processStartInfo.UseShellExecute = false;
        processStartInfo.CreateNoWindow = true;
        process = new Process();
        process.EnableRaisingEvents = true;
        process.StartInfo = processStartInfo;
        //Start process
        process.Start();
        //process.BeginOutputReadLine();
        //This is the input textbox
        stdin = process.StandardInput;

        // Get the output stream from the new process.
        StreamReader stdout = process.StandardOutput;

        // Define a buffer we will use to store characters read.
        const int BUFFER_SIZE = 1;
        char[] buffer = new char[BUFFER_SIZE];

        // The following specifies reading from the output stream to a buffer
        // and then appending the result to the form.
        Task<int> readTask = stdout.ReadAsync(buffer, 0, BUFFER_SIZE);
        Action<Task<int>> appendAction = null;

        appendAction = (read) => {
            string bufferString = new string(buffer);
            // `read.Result` represents the number of characters read.
            string newText = bufferString.Substring(0, read.Result);
            // *Append new text to form here.* NOTE: New text might not be a complete line.
            SetText(newText); //Have to set text this way due to other      thread
            // If we read in an entire buffer of text, we need to keep     reading.
            // Otherwise, stop reading and finish up.
            if (read.Result == BUFFER_SIZE)
            {
                readTask = stdout.ReadAsync(buffer, 0, BUFFER_SIZE);
                readTask.ContinueWith(appendAction);
            }
            else
            {
                // *Handle process has ended here.*
            }
        };
        readTask.ContinueWith(appendAction);
}

private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.Output_TextBox.InvokeRequired)
        {
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            Output_TextBox.AppendText(text);
        }
    }

非常感谢!

4

1 回答 1

1

尝试以下操作:

不使用process.OutputDataReceived事件,而是使用进程的标准输出流。

// Get the output stream from the new process.
StreamReader stdout = process.StandardOutput;

// Define a buffer we will use to store characters read.
const int BUFFER_SIZE = 1;
char[] buffer = new char[BUFFER_SIZE];

// The following specifies reading from the output stream to a buffer
// and then appending the result to the form.
Task<int> readTask = stdout.ReadAsync(buffer, 0, BUFFER_SIZE);
Action<Task<int>> appendAction = null;

appendAction = (read) => {
  string bufferString = new string(buffer);
  // `read.Result` represents the number of characters read.
  string newText = bufferString.Substring(0, read.Result); 
  // *Append new text to form here.* NOTE: New text might not be a complete line.

  // If we read in an entire buffer of text, we need to keep reading.
  // Otherwise, stop reading and finish up.
  if (read.Result == BUFFER_SIZE)
  {
    readTask = stdout.ReadAsync(buffer, 0, BUFFER_SIZE);
    readTask.ContinueWith(appendAction);
  }
  else
  {
    // *Handle process has ended here.*
  }
};
readTask.ContinueWith(appendAction);

这基本上与您的原始代码做同样的事情。但是,这一次,我们使用标准输出流来一个一个地读取字符。此代码以异步方式执行它,以免阻塞您的 GUI。让我知道它是否有效或您有任何问题。我无法测试它,因为我没有运行 Windows。

请参阅我在此解决方案中使用的任务完成后采取特定操作的帖子:如何获取 System.Threading.Tasks.Task 已完成的通知

编辑

我的第一个答案有一个错误,因为没有预定义appendAction,子字符串bufferString.Substring(read.Result)应该是bufferString.Substring(0, read.Result). 这些错误已得到修复。这是一个 Fiddle 演示使用的工作示例StringReaderhttps ://dotnetfiddle.net/LinVWc

于 2020-06-06T20:04:15.387 回答