Note that there are some explanatory texts on larger screens.

plurals
  1. POIn a WinForm process, how to detect when a command line child process is demanding input?
    text
    copied!<p>In a WinForm application that calls a third-party command line tool, there may be a time when the tool is expecting user input, such as asking if it should overwrite a file:</p> <pre><code>printf("%s already exists, overwrite?: &lt;Y&gt;es, &lt;N&gt;o, &lt;A&gt;ll, &lt;Q&gt;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; } </code></pre> <p>When that happens, I want to display the message from <code>printf()</code> and the options in a dialog box, and redirect the button click as input to the process. It probably involves using <code>System.Diagnostics.Process.StandardInput</code> to send the input. But without knowing when exactly the tool will be expecting input, I would have no idea when to react accordingly in the GUI. When the process is in this for-loop, my WinForm process will just freeze. </p> <p><strong>EDIT</strong>: Here's the code that unblocks the UI by starting the process in another thread, however I still could not read the output, if the file I select will cause the tool to ask overwriting options. <code>proc_OutputDataReceived</code> (<strong>EDIT2</strong>: or <code>readStdOut</code> in <code>proc.StandardOutput.BaseStream.BeginRead</code>'s case) will never be called , unless the tool does not ask for input).</p> <pre><code> 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); } </code></pre> <p>Any idea how to do this? Thanks!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload