Search code examples
c#batch-filecmdstartprocessinfo

Opening a command line and reading outputs without closing


I know similar questions are overflowing this website (pun intended), but I cannot find get this to work without closing the .bat file I'm running. I'm sorry that I'm not very skillful at this, but any help is seriously appreciated.

What works:

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = @"C:\Temp\batch.bat";            
p.Start();          
string output = p.StandardOutput.ReadToEnd();

string DataDate =(output.Substring(output.LastIndexOf("echo date:") + 11));
string DataID1 =(output.Substring(output.LastIndexOf("echo id1:") + 10));
string DataID2 =(output.Substring(output.LastIndexOf("echo id2:") + 10));
string DataStatus =(output.Substring(output.LastIndexOf("echo status:") + 13));

This here opens a batch.bat file, which prints several lines that I can get to strings, such as: "echo date: 15.02.2019" goes to string DataDate. But I would like to open a command prompt and type new values myself without the command prompt closing. I'm using a button to run that code above. I think I to open the cmd process and store it every time there is a new line? How can I keep process alive and update my strings with newer values? For example I could type in the cmd prompt "echo date: 18.02.2019" and then that value would be saved.


Solution

  • If I understand your intention correctly you want an interaction with your process. Thus, your process must support this interaction. For example, you batch file may prompt commands and look like this:

    @echo off
    
    :loop
    echo Enter a command:
    set /p userCommand=""
    %userCommand%
    goto :loop
    

    You can't use p.StandardOutput.ReadToEnd() since the output stream will not be finished yet until the output will be finished. You can use OutputDataReceived to perform asynchronous read. Try this code with the batch commands above:

    Process process = new Process();
    process.StartInfo.FileName = @"C:\Temp\batch.bat";
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.UseShellExecute = false;
    process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
    {
        // Prepend line numbers to each line of the output.
        if (!String.IsNullOrEmpty(e.Data))
        {
            Console.WriteLine(e.Data);// to see what happens
            // parse e.Data here
        }
    });
    
    process.Start();
    
    // Asynchronously read the standard output of the spawned process. 
    // This raises OutputDataReceived events for each line of output.
    process.BeginOutputReadLine();
    
    process.WaitForExit();
    process.Close();
    

    Update

    For Windows Forms app to make it work you need to change in VS Project Properties -> Application -> Output Type from Windows Application to Console Application. Or you can do it by editing *.csproj file and replacing <OutputType>WinExe</OutputType> by <OutputType>Exe</OutputType>. A a consequence of this, the console will be displayed during all app run time which maybe undesired for you. Honestly, I don't know how to make it in other way.