Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to log message to cmd.exe in C#/.Net?

Tags:

c#

.net

logging

cmd

Is it possible to log message from WinForms app to cmd.exe process started programmatically? I've tried to do all kinds of variations of following code:

private void button1_Click(object sender, EventArgs e)
{
    Log("Button has been pressed");
}

private void Log(string message)
{
    var process = Process.Start(new ProcessStartInfo("cmd.exe", @"/K ""more""")
    {
        UseShellExecute = false,
        RedirectStandardInput = true,
    });
    process.StandardInput.WriteLine(message);
}

Unfortunately, console window blinks for a half of a second and that's it.

Please don't answer what I really want to do, because right now I'm just curious if it's possible :)

like image 529
prostynick Avatar asked Jul 01 '11 10:07

prostynick


3 Answers

You're in luck. I just solved this for a code generator toy project I had floating around here.

Using AttachConsole or AllocConsole Win32 API's you can achieve the result, by just using System.Console.WriteLine (or Read, or Error.WriteLine etc) like you normally would.

The following snippet figures out when a forms app was started from a Console window, and attaches to it's parent console; If that doesn't work, it will create it's own console, and remember to keep it open (so it doesn't vanish before the user can read the output, for example).

    [DllImport("kernel32.dll")] static extern bool AllocConsole();
    [DllImport("kernel32.dll")] static extern bool AttachConsole(int pw);
    private static bool _hasConsole, _keepConsoleOpen;
    static private void EnsureConsole()
    {
        _hasConsole      =  _hasConsole || AttachConsole(-1);
        _keepConsoleOpen = !_hasConsole || _keepConsoleOpen;
        _hasConsole      =  _hasConsole || AllocConsole();
    }

    [STAThread]
    private static void Main(string[] args)
    {
          EnsureConsole();

          // the usual stuff -- your program

          if (_keepConsoleOpen)
          {
              Console.WriteLine("(press enter)...");
              Console.Read();
          }
    }
like image 198
sehe Avatar answered Nov 14 '22 16:11

sehe


Not the final answer, but it should help at least a little:

First of all, declare that process outside your Log routine so it doesn't go out of scope when you want to log more.

Anyway I tried the following:

Process process = Process.Start(new ProcessStartInfo("cmd.exe", "/K more") {
  UseShellExecute = false,
  RedirectStandardInput = true,
  RedirectStandardError = true,
  RedirectStandardOutput = false
});

private void button1_Click(object sender, EventArgs e) {
  Log("Button has been pressed");
  MessageBox.Show(process.StandardError.ReadToEnd());
}

private void Log(string message) {
  process.StandardInput.WriteLine(message);
}

After clicking the button, your app will hang (it's waiting for the console to close, ReadToEnd literally reads to the end). When you close the console you will get a messagebox with the error output:

The handle is invalid.
The handle is invalid.
The handle is invalid.
'Button' is not recognized as an internal or external command,
operable program or batch file.
The handle is invalid.
The handle is invalid.

It seems not to be possible to redirect only the input without redirecting the output when running CMD. I'm not sure why, maybe trying different commandline options will help. I also tried removing the More command and logging "dir" instead:

Log("dir");

The result was a bit scary:

The handle is invalid.
...
There is not enough space on the disk.
The handle is invalid.
The handle is invalid.

Interesting I must say! Looks like you've opened a can of worms :-)

like image 24
Louis Somers Avatar answered Nov 14 '22 15:11

Louis Somers


You have to insert a pause command after printing to the console.

The process terminates as soon as the command is executing, resulting in the blink you see.

like image 24
Zebi Avatar answered Nov 14 '22 16:11

Zebi