Creating a Command Prompt

196 views Asked by At

I want to create a Command prompt in WPF where the user can type the command and get the output in the same window, exactly how the original Command Prompt works.

Initially I used Process.Start() and put it into another thread to not block the main thread. I have used StreamReader and StreamWriter to write and capture the output. However I am unable to continuously listen for output or write the commands.

Here's my code till now -

public class TerminalController
{
    public Process CmdProcess { get; set; }
    public StreamReader Reader { get; set; }
    public StreamWriter Writer { get; set; }
    public void Init()
    {
        if (CmdProcess != null)
        {
            try
            {
                Close();
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }
        }
        CmdProcess = new Process();
        System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
        startInfo.FileName = "cmd";
        startInfo.WindowStyle = ProcessWindowStyle.Normal;
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardInput = true;
        startInfo.RedirectStandardOutput = true;
        startInfo.UseShellExecute = false;
        CmdProcess.StartInfo = startInfo;
        CmdProcess.Start();
        Writer = CmdProcess.StandardInput;

        StartReading();
    }
    public void Init(string command)
    {
        if (CmdProcess != null)
        {
            try
            {
                Close();
            }
            catch (Exception ex)
            {
                Logger.LogException(ex);
            }
        }
        CmdProcess = new Process();
        System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
        startInfo.FileName = "cmd";
        startInfo.WindowStyle = ProcessWindowStyle.Normal;
        startInfo.CreateNoWindow = true;
        startInfo.RedirectStandardInput = true;
        startInfo.RedirectStandardOutput = true;
        startInfo.UseShellExecute = false;
        CmdProcess.StartInfo = startInfo;
        CmdProcess.Start();

    }

    private void Write(String command)
    {
        using (Writer = CmdProcess.StandardInput)
        {
            Writer.Write(command);
        }
    }

    private void StartReading()
    {
        using (Reader = CmdProcess.StandardOutput)
        {
            RaiseTerminalReadEvent(null, Reader.ReadToEnd());
        }
    }
    public async void RunCommand(String command)
    {
        RaiseTerminalWriteEvent(command);
        await Task.Run(() => Write(command));
        await Task.Run(() => StartReading());
        //Close();
    }

    public Task InitAsync()
    {
        return Task.Run(() => Init());
    }

    public void Close()
    {
        try
        {
            CmdProcess.Close();
            Reader.Close();
            Writer.Close();
            CmdProcess = null;
        }
        catch (Exception ex)
        {
            Logger.LogException(ex);
        }
    }

    internal Task RunCommandAsync(string command)
    {
        return Task.Run(() => RunCommand(command));
    }
}

I can run the commands only once, this is the output when I sent dir command -

dir
Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

E:\Microsoft\WPF\Example\Example\bin\Debug>More? 

If I send the command again, it gives the following exception -

Cannot write to a closed TextWriter.
at System.IO.__Error.WriterClosed()
   at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
   at System.IO.StreamWriter.Write(String value)
   at Example.Controllers.TerminalController.Write(String command) in e:\Microsoft\WPF\Example\Example\Controllers\TerminalController.cs:line 91

So how can I continuously run the command and listen for output. Do I need to create a new process everytime? Is there any other alternative?

1

There are 1 answers

1
SLaks On BEST ANSWER

Your using blocks dispose the streams as soon as you first use them.

Therefore, you can't use them again.

Don't do that.