5

If I run my Program.exe from an existing command line window, then when it finishes and exits, the Console Output is still there and viewable.

If I just double click my Program.exe, then it'll open a new command line window, for Console Output ... but when my exe finishes, that window will close, taking the Outputs with it.

In the latter case, to prevent loss of output logs, I might want to have the final 2 lines of my Main() be Console.WriteLine("Press any key to exit"); Console.ReadKey();

But if I do that in the former case then it's mildly annoying.

Is there any way to detect the difference between those 2 scenarios, so that I can do that "wait for the user to say I can close" conditionally ... only if necessary?

Brondahl
  • 7,402
  • 5
  • 45
  • 74
  • Figure out if you can extract some useful information from the [parent process](https://stackoverflow.com/questions/394816/how-to-get-parent-process-in-net-in-managed-way). Maybe the name is enough to determine if it was a Cmd that started your application. – Bent Tranberg Feb 05 '22 at 10:52
  • I think you have the wrong idea about how things work. When you start a Cmd.exe, that's a program. If you start your program from a Cmd.exe (the command shell), then that Cmd.exe is your program's parent process. If you start your program by double clicking, then there is no Cmd.exe involved, and some other Windows process is your program's parent. Not 100% sure, but you'll find out for sure. – Bent Tranberg Feb 05 '22 at 10:55
  • 1
    It sounds like you're interested in keeping logs visible, so Instead of only logging to the console, why not log to a file? That'll be accessible even when closing the console window. – Xerillio Feb 05 '22 at 10:55
  • From Docs: _A console is closed when the last process attached to it terminates or calls FreeConsole._ – Fabio Feb 05 '22 at 10:56
  • Closing behavior is "by design" :). Did you consider to write output to the file? – Fabio Feb 05 '22 at 10:58
  • There are various command shells, so just looking for parent Cmd.exe is not foolproof. I think Windows PowerShell comes with Windows, so that one you might test for also. – Bent Tranberg Feb 05 '22 at 11:17
  • @Fabio there is already logging in addition to the Console Output, but it logs to a tedious-to-find file, and is generally just a little bit less useful to have, than Console Outputs – Brondahl Feb 06 '22 at 08:20

3 Answers3

3

If you want to check if your app is started from the command line in .NET, you can use Console.GetCursorPosition(). The reason that this works is that when you start it from the command line, the cursor moves away from the initial point ((0, 0)) because you typed something in the terminal (the name of the app). You can do this with an equality check:

// .NET 6
class Program
{
    public static void Main(string[] args)
    {
        if (Console.GetCursorPosition() == (0, 0))
        {
            //something GUI
        }
        else
        {
            //something not GUI
        }
    }
}

Note: You must set the output type to Console Application as other output types will make Console.GetCursorPosition() throw an exception.

ZP-ZPanda
  • 107
  • 1
  • 10
  • 2
    This works well. For `.Net` before 5, the check is `((Console.CursorLeft == 0) && (Console.CursorTop == 0))`. – Axel Kemper Feb 05 '22 at 18:17
2

For the cases of running a console app from a command line and running it from Visual Studio, Process.GetCurrentProcess().MainWindowTitle is empty. In these cases, you do NOT need the extra Console.ReadLine().

When you run it by double clicking it in Windows Explorer, the window title is the path of the exe. In this case, you DO need the extra Console.ReadLine().

So a somewhat hacky approach (which I've only tested for the three cases above!) could be to add this to the end of Main():

if (!string.IsNullOrEmpty(Process.GetCurrentProcess().MainWindowTitle))
    Console.ReadLine();

I wouldn't use this in production code, but it could be useful as a quick hack for test utilities etc.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

Before .Net5:

if (Console.Title == System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName)
{
    //Title in Explorer (and VS) contains path + filename
    Console.WriteLine("Executed in Explorer");
    Console.ReadLine();
}

if (Console.Title.Contains("Command Prompt"))
    Console.WriteLine("Executed in a 'Command Prompt'");

if (Console.Title.Contains("PowerShell"))
    Console.WriteLine("Executed in PowerShell");