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 >nul
。与 set /p "var=Prompt:" as
echo Prompt:` 和 set /p var=
相同。怀疑的原因:pause
和set /p
在按下ENTER
之前都不要写CRLF
,C# 会在完成时捕获该行(使用CRLF
)
@Stephan 您好,我正在尝试浏览 Matthew 目前提供的链接。在这种情况下,虽然我无法更改 bat 文件,因为它们是由外部源提供的。在我的案例中,应用程序只是一个运行批处理文件、给出答案并返回输出的 gui。谢谢
批量中,您可以使用> nul
隐藏输入,就像@Stephan 在他的评论中展示的那样。如果您希望在暂停之前提示进行 quarentee 解析,请使用 Stephan 的建议,echo Prompt for input && pause >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# - 批处理文件输出不显示“按任意键继续...”直到我按下一个键的主要内容,如果未能解决你的问题,请参考以下文章
关于解决VS下运行控制台程序不显示“按任意键继续……”的解决方法