4

I am developing a C# component for Grasshopper for Rhino. As I am running some pretty heavy iterative analysis I would like to output results continuously to a cmd window just to make sure that the analysis is actually running.

Here's what I tried:

using System.Diagnostics;


Result results = new Result();
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();

do {
    results = RunHeavyOperation(results);
    cmd.StandardInput.WriteLine("echo " + results.usefulInfo);
} while (!results.conditionForEnd);

cmd.WaitForExit();

Result RunHeavyOperation(Result previousResults) {
    Result res = doHeavyStuff(previousResults);
    return res;
}

I realise that I am missing part, but what is it?

Toivo Säwén
  • 1,905
  • 2
  • 17
  • 33
  • For the record, I temporarily resolved the issue using `System.Diagnostics.Debug.Write(results.usefulInformation);`, but this won't work if the application enters production. – Toivo Säwén Mar 23 '17 at 15:06
  • https://stackoverflow.com/questions/3616010/start-command-windows-and-run-commands-inside – bh_earth0 Sep 06 '18 at 15:20

2 Answers2

9

Your approach is wrong: You currently don't write to a console window. Instead you created a process by starting cmd.exe and write to the standard input pipe of that process. cmd.exe is not aware of that. It's not the same as typing in a console via your keyboard, and even that can have strange effects.
Imagine you output a new line character, so cmd.exe might try to "execute" what you output before as a command.

The correct way is to invoke AllocConsole. With this call you can create a console window for your process and use it simply via Console.WriteLine().

When you finished your work and logging, you'll eventually need to close and free this console again via FreeConsole.

So import these two native methods:

internal sealed class NativeMethods
{
    [DllImport("kernel32.dll")]
    public static extern bool AllocConsole();

    [DllImport("kernel32.dll")]
    public static extern bool FreeConsole();
}

And use them in your code:

NativeMethods.AllocConsole();

// start work
Console.WriteLine("log messages...");

// finished work

NativeMethods.FreeConsole();

Note that FreeConsole() will close the console window, so all your log messages get lost. And a console only has a so large buffer and you can't scroll back to older messages if the leave the buffer.

So it may be a better idea to simply write your log messages into a file that you can analyze later.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • Yes, this is what I am looking for. Thanks! – Toivo Säwén Mar 23 '17 at 15:28
  • 1
    Can I do this from within a winforms app? I can open the console, but nothing is written to it! – Olivier Jacot-Descombes Mar 23 '17 at 15:45
  • @OlivierJacot-Descombes Yes you can, I just tested it again and it works for me. – René Vogt Mar 23 '17 at 15:46
  • I had to use the code from [this](http://stackoverflow.com/a/34170767/880990) answer to make it work. But the output is still redirected to the debug ouput window when starting the app from within VS 2017. It only works when starting the app from outside VS. – Olivier Jacot-Descombes Mar 23 '17 at 16:14
  • @OlivierJacot-Descombes It works for me from within VS2017. Did you start with the debugger attached? Then of course it won't work as there already is a kind of console attached (the debugger). Since OP wanted it to work in production, I think my code is ok. It works if you start without debugging. – René Vogt Mar 23 '17 at 16:17
  • It works if I explicitly "Start Without Debugging Ctrl+F5" from within VS; however I still have to write the additional code in order to set the standard output stream explicitly. – Olivier Jacot-Descombes Mar 23 '17 at 16:27
  • @OlivierJacot-Descombes That's strange. I can reproduce that in debugging (starting with F5) the output stream is redirected to the VS output window, but when starting without debugging (ctrl+f5) I don't need any extra code. Don't know what's the difference between our two apps, though. – René Vogt Mar 23 '17 at 16:30
0

Create a Console App in Visual Studio. In VS 2017 it looks like this (on the start page):

enter image description here

Console apps open a command console automatically. Then you can write to it with

Console.WriteLine("hello");

The console closes automatically when the program terminates. So make sure to call Console.ReadKey(); at the end, if you want to keep it open.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • That is all well and good, but the app is already deep in development - is it an easy matter of migrating the existing app to a Console App? – Toivo Säwén Mar 23 '17 at 15:12
  • 1
    It depends whether you already made a WinForms or WPF application and already created the UI or whether you only wrote business logic. In the latter case, there will be nothing you will have to transform. Of course an application cannot be a console and WinForms or WPF application at the same time. – Olivier Jacot-Descombes Mar 23 '17 at 15:15