4

I have a windows form that executes a batch file. I want to transfer everything that happends in my console to a panel in my form. How can I do this? How can my DOS console comunicate with my windows form panel???

Thanks

Zhaph - Ben Duguid
  • 26,785
  • 5
  • 80
  • 117
user62958
  • 4,669
  • 5
  • 32
  • 35

6 Answers6

7

You can call the DOS or batch program from your Form application and redirect the output to a string:

using (var p = new System.Diagnostics.Process( ))
{
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.FileName = PathToBatchFile;
    p.StartInfo.Arguments = args;
    p.Start( );
    string o = p.StandardOutput.ReadToEnd( );
    p.WaitForExit( );
}
Dour High Arch
  • 21,513
  • 29
  • 75
  • 90
  • You probably want to move the WaitForExit() call before the line that reads the input from the redirected output stream. Also, if desired, you can add the WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden flag to keep the console app from appearing, so long as it doesn't need to interact with the user. – LBushkin Jun 24 '09 at 20:42
  • Thank you... And is there a way that I can actually hide the OS window??? It works right now but shows empty OS consoles... – user62958 Jun 24 '09 at 22:35
  • 1
    You do not need to WaitForExit before reading input, but you do need to Dispose() the process afterward. I have added this. Unknown Yahoo, I get no console window, are you sure this is the batch file? Try setting p.StartInfo.CreateNoWindow = true; – Dour High Arch Jun 24 '09 at 23:25
  • 4
    you MUST NOT put the WaitForExit() before ReadToEnd. The output buffer of the process may fill up, and this will suspend the process. Which means it will never exit. So call ReadToEnd before WaitForExit() as the code is above. – Cheeso Jul 03 '09 at 20:18
3

The doc states that if you want to read both StandardError and StandardOutput, you need to read at least one of them asynchronously in order to avoid deadlocks.

Also, if you call ReadToEnd on one of the redirected streams, you must do so before calling WaitForExit(). If you WaitForExit before ReadToEnd, the output buffer can fill up, suspending the process, which means it will never exit. That would be a very long wait. This is also in the doc!

example:

string output;
string error;
System.Diagnostics.Process p = new System.Diagnostics.Process
    {
        StartInfo =
        {
            FileName = program,
            Arguments = args,
            WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden,
            UseShellExecute = false,
        }
    };

if (waitForExit)
{
    StringBuilder sb = new StringBuilder();
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    Action<Object,DataReceivedEventArgs> stdErrorRead = (o,e) =>
    {
        if (!String.IsNullOrEmpty(e.Data))
            sb.Append(e.Data);
    };

    p.ErrorDataReceived += stdErrorRead;
    p.Start();
    // begin reading stderr asynchronously
    p.BeginErrorReadLine();
    // read stdout synchronously
    output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();
    // return code is in p.ExitCode

    if (sb.Length > 0)
        error= sb.ToString();

}
Cheeso
  • 189,189
  • 101
  • 473
  • 713
2

You should start off by adding a reference to System.Diagnostics, then calling the batch file like this:

string myFile = "c:\\path\\to\\batch_file.bat";
ProcessStartInfo psi = new ProcessStartInfo(myFile);
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardOutput = true;
Process proc = Process.Start(psi);

Now, if you want the call to be blocking (I.E., your application will freeze until the file is done), then just use string result = proc.StandardOutput.ReadToEnd() to read the entirety of your batch file's output.

However, if you want to have the application continue to respond, as well as display output in real-time, then you'll need to have to use BeginOutputReadLine.

MiffTheFox
  • 21,302
  • 14
  • 69
  • 94
1

I've been fooling around with the System.Diagnostics.Process class for calling console based applications and formating and returning the output. I think it will work with Batch files, as well. I'll take a moment here to test that. Here is some sample code:

   System.Diagnostics.ProcessStartInfo start = new System.Diagnostics.ProcessStartInfo();
    start.UseShellExecute = false;
    start.RedirectStandardInput = true;
    start.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

    start.RedirectStandardOutput = true;
    start.FileName = "at";
System.Diagnostics.Process myP = System.Diagnostics.Process.Start(start);
String strOutput = myP.StandardOutput.ReadToEnd();
if (strOutput.Contains("There are no entries in the list."))
{
    litMsg.Text = "There are no jobs";
}
else
{
    strOutput = strOutput.Replace("\r", "");
    foreach (String line in strOutput.Split("\n".ToCharArray()))
    {
        //(0,7)  (7,5)(12, 24)                (36, 14)      (50, )
        //Status ID   Day                     Time          Command Line
        //-------------------------------------------------------------------------------
        //        1   Tomorrow                3:00 AM       dir *
        if (line.Length > 50)
        {
            String Status = line.Substring(0, 7);
            String ID = line.Substring(7, 5);
            String Day = line.Substring(12, 24);
            String Time = line.Substring(35, 14);
            String Command = line.Substring(49);
        }
    }
}
stephenbayer
  • 12,373
  • 15
  • 63
  • 98
0

I recently build a tiny app where I was interacting with batch files. I found this snippit of code that allowed me to do this:

Process proc = new Process
               {
                   StartInfo =
                       {
                           RedirectStandardError = true,
                           RedirectStandardOutput = true,
                           UseShellExecute = false,
                       }
               };
proc.Start();

string errorMessage = proc.StandardError.ReadToEnd();
proc.WaitForExit();
string outputMessage = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();

From here, just direct those strings into a usercontrol of your choice.


EDITS

Note: This is not a general solution. It can lead to deadlocks. From the doc for RedirectStandardError:
Synchronous read operations introduce a dependency between the caller reading from the StandardError stream and the child process writing to that stream. These dependencies can cause deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits for the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits for the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait for each other to complete an operation, and neither can continue. You can avoid deadlocks by evaluating dependencies between the caller and child process.

Cheeso
  • 189,189
  • 101
  • 473
  • 713
Matthew Ruston
  • 4,282
  • 7
  • 38
  • 47
  • 1
    In fact this will not work, because there is a race condition between stderr and stdout. Suppose the process you run writes first to stdout, then to stderr. By calling ReadToEnd() on stderr, you will wait forever. On the other hand if the process writes in the opposite order, then reading from stderr is ok. But there is no guarantee. Hence a race condition. You need to use async reads to avoid this race. See the doc on Process.Start() for more info. – Cheeso Jun 25 '09 at 02:39
  • I guess that's why this code led to my batch window freezing up at times. I had I feeling that something might have been out of whack. I am going to leave my answer incorrect for educational purposes. – Matthew Ruston Jun 25 '09 at 03:06
0

I'm pretty sure there are better options but you can route the output of the command to a temp file

Redirecting Command-Line Output to Files

For programs that display a lot of text, consider redirecting text that is usually displayed on stdout to a file. Displaying a lot of text will slow down execution; scrolling text in a terminal window on a workstation can cause an I/O bottleneck (increased elapsed time) and use more CPU time.

The following commands show how to run the program more efficiently by redirecting output to a file and then displaying the program output:

myprog > results.lis more results.lis Redirecting output from the program will change the times reported because of reduced screen I/O.

I think you could just route it to a variable as well, not 100% sure though. There's probably far better options but at least this is one.

Allen Rice
  • 19,068
  • 14
  • 83
  • 115