在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);
}
你知道怎么做吗?谢谢!
从System.Diagnostics.StandardOutput
读取(如果您使用阻塞读取,则必须在单独的线程中执行),直到找到该字符串的匹配,然后显示消息框并根据用户选择将字符发送到进程的StandardInput
。
我们尝试的事情的快速总结:
- 使用
BeginOutputReadLine
->的"正常"异步读取肯定会失败,因为来自应用程序的消息没有以''n'
终止; - 异步读取1字节块->似乎失败,因为应用程序没有刷新缓冲区;
- 添加一个
fflush(stdout)
到C应用程序+前面的方法:成功!显然,程序没有在getch()
. 之前刷新输出缓冲区。
cin
绑定到cout
,并且在cin
上的任何输入操作发生之前,cout
会自动刷新。我认为这是合理的,这样的事情也发生在stdin
/stdout
,但我似乎找不到任何参考它进入标准(事实上,聊天getch()
是非标准的,不同于其他IO函数在未缓冲可能是相关的)。
要了解更多信息,请参阅评论。:)