hkn
hkn

Reputation: 13

Programmatic use of cmd.exe from C#

  1. I want to run a series of commands on cmd.exe from C#.
  2. I need to open only one window of cmd
  3. I need to keep the cmd window open through the execution and after the completion.
  4. I need to display the commands [edit]in the opened cmd window[/edit] executed as well as the output of the commands.

So basically I want to open and use the cmd.exe just like a manual user would. I tried some methods, but none could do all 4 items above.

Below code works but does not display the commands/outputs and terminates after completion. Any help?

Process p = new Process();
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
info.RedirectStandardInput = true;
info.UseShellExecute = false;
info.CreateNoWindow = false;
info.Arguments = "/k";

p.StartInfo = info;
p.Start();

using (StreamWriter sw = p.StandardInput)
{
    if (sw.BaseStream.CanWrite)
    {
         sw.WriteLine("dir");
         sw.WriteLine("ipconfig");
    }
}

Upvotes: 1

Views: 3987

Answers (2)

Daniel
Daniel

Reputation: 16464

The RedirectStandard...-properties are misleading. As soon as you set one of them, all three streams will be redirected. This is because the underlying Windows API only has a single flag to control redirection - STARTF_USESTDHANDLES.

Because you didn't set the RedirectStandardOutput property to true, the stdout streams isn't made available to your code, but instead will be redirected to the Console.Out stream of your own process. Thus, your code works fine as long as the parent process is a console application; but in a Windows application, the output gets redirected into nothingness.

An easy workaround is to temporarily turn your parent process into a console application:

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool FreeConsole();

static void Main(string[] args)
{
    Process p = new Process();
    ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
    info.RedirectStandardInput = true;
    info.UseShellExecute = false;
    info.CreateNoWindow = false;

    p.StartInfo = info;
    AllocConsole();
    p.Start();
    FreeConsole();


    using (StreamWriter sw = p.StandardInput)
    {
        if (sw.BaseStream.CanWrite)
        {
             sw.WriteLine("dir");
             sw.WriteLine("ipconfig");
        }
    }
}

As for keeping the console open: you could just remove the FreeConsole() call so that the parent process keeps the console around even after cmd.exe exits. However this may be a problem if you need multiple consoles, as your parent process can't be associated with more than one console at a time.

Alternatively, don't close the input stream so that cmd.exe keeps running.

Upvotes: 4

KF2
KF2

Reputation: 10171

For seeing the out put insert Console.ReadLine();(application stop until you send a key so you can see the result) after command executed.

  static void Main(string[] args)
            {
                Process p = new Process();
                ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
                info.RedirectStandardInput = true;
                info.UseShellExecute = false;
                info.CreateNoWindow = false;

                p.StartInfo = info;
                p.Start();

                using (StreamWriter sw = p.StandardInput)
                {
                    if (sw.BaseStream.CanWrite)
                    {
                        sw.WriteLine("dir");

                        sw.WriteLine("ipconfig");
                    }
                }
                Console.ReadLine();
            }

Upvotes: 0

Related Questions