C# - 批处理文件输出不显示“按任意键继续...”直到我按下一个键

Posted

技术标签:

【中文标题】C# - 批处理文件输出不显示“按任意键继续...”直到我按下一个键【英文标题】:C# - Batch file output not displaying "Press any key to continue..." until after I press a key 【发布时间】:2020-09-25 21:14:52 【问题描述】:

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

@echo off
pause
echo DONE
pause

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

"Press any key to continue..."

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

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

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

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

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

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

这里是result。

代码如下:

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);
        
    

究竟我需要做什么才能在按下键之前显示“Press any key to continue...”?

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

我有很多批处理文件,其中显示了很多选项,用户需要知道这些选项是什么才能让我的应用程序正常工作。所以这个功能就像主要的部分。 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);
        
    

非常感谢!

【问题讨论】:

在我看来 "Press any key to continue..." 没有被 pause 命令刷新。也就是说,在另一个命令正确刷新流之前,它不会调用OutputDataReceived。看到这个问题,它可能会回答你的问题:***.com/questions/3995151/… 如果 Matthew 是对的(我认为他是对的)而不是 pause,请使用 echo Press any key...pause &gt;nul。与 set /p "var=Prompt:" as echo Prompt:` 和 set /p var= 相同。怀疑的原因:pauseset /p 在按下ENTER 之前都不要写CRLF,C# 会在完成时捕获该行(使用CRLF @Stephan 您好,我正在尝试浏览 Matthew 目前提供的链接。在这种情况下,虽然我无法更改 bat 文件,因为它们是由外部源提供的。在我的案例中,应用程序只是一个运行批处理文件、给出答案并返回输出的 gui。谢谢 批量中,您可以使用&gt; nul 隐藏输入,就像@Stephan 在他的评论中展示的那样。如果您希望在暂停之前提示进行 quarentee 解析,请使用 Stephan 的建议,echo Prompt for input &amp;&amp; pause &gt;nul @NekoMusume 嗨,在我的情况下,这是不可能的,bat 文件将未经编辑,因为它们是从外部提供的,并且会定期更新。我的应用程序只是一个启动批处理文件并允许用户输入响应的 gui。在我的情况下,编辑 bat 文件不是一个选项。谢谢 【参考方案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。

请参阅我在此解决方案中使用的任务完成后采取特定操作的帖子:How to get notification that a System.Threading.Tasks.Task has completed

编辑

由于没有预定义appendAction,我的第一个答案出现错误,并且子字符串bufferString.Substring(read.Result) 应该是bufferString.Substring(0, read.Result)。这些错误已得到修复。这是一个使用StringReader 演示工作示例的小提琴:https://dotnetfiddle.net/LinVWc

【讨论】:

嗨,所以我尝试了你的代码,我确实在这里遇到了一个错误: if (!stdout.EndOfStream) readTask = stdout.ReadAsync(buffer, 0, BUFFER_SIZE); //readTask.ContinueWith(appendAction); //注释掉,因为它指出 var 未分配。 只是为了测试我尝试了以下操作,但控制台中没有返回任何内容: // 在此处添加新文本。 注意:新文本可能不是完整的行。 Console.WriteLine(newText);我会以错误的方式解决这个问题吗?谢谢 @SmellyFox,您的想法绝对正确。我在代码中犯了一些错误。我们需要预定义readTask 以避免您指出的错误。另外,bufferString.Substring(read.Result) 应该是bufferString.Substring(0, read.Result),因为第一个总是会产生一个空字符串。我在答案中修改了我的代码,并为示例实现提供了一个 Fiddle。

以上是关于C# - 批处理文件输出不显示“按任意键继续...”直到我按下一个键的主要内容,如果未能解决你的问题,请参考以下文章

批处理(bat)命令之echo命令

系统(“暂停”)说明

pause 和 title

关于解决VS下运行控制台程序不显示“按任意键继续……”的解决方法

c++,在VS2010中CTRL+F5运行下面的语句,控制台不显示运行结果,只有按任意键继续。

pause