在调用第三方命令行工具的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进程将冻结。
编辑:这是通过在另一个线程中启动进程来取消阻止UI的代码,但是如果我选择的文件将导致该工具询问覆盖选项,我仍然无法读取输出。除非工具不要求输入,否则永远不会调用proc_OutputDataReceived
( EDIT2 :或readStdOut
中的proc.StandardOutput.BaseStream.BeginRead
)。
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);
}
知道怎么做吗?谢谢!
答案 0 :(得分:2)
从System.Diagnostics.StandardOutput
读取(如果您使用阻止读取,则必须在单独的线程中执行此操作),直到找到该字符串的匹配项,然后显示您的消息框并将该字符发送到{{ 1}}根据用户选择的过程。
我们尝试的事情的快速摘要:
StandardInput
进行“正常”异步读取 - &gt;肯定会失败,因为来自应用程序的消息没有以BeginOutputReadLine
; '\n'
+以前的方法:成功!显然程序没有在fflush(stdout)
之前刷新输出缓冲区。有趣的是,这可能不会在使用标准iostream的C ++应用程序中发生,因为getch()
与cin
绑定,并且在cout
上的任何输入操作发生之前{{1}自动刷新。我认为cin
/ cout
也发生类似这样的事情是合理的,但我似乎无法在标准中找到任何引用(事实上聊天stdin
是非标准的,与其他IO功能的不同之处可能是无缓冲的。)
更多信息请参阅评论。 :)