26

I've some library code that is used by both console and WPF apps. In the library code, there are some Console.Read() calls. I only want to do those input reads if the app is a console app not if it's a GUI app - how to tell in the dll if the app has a console?

Pang
  • 9,564
  • 146
  • 81
  • 122
Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • 1
    [How can a C# Windows Console application tell if it is run interactively](http://stackoverflow.com/a/8711036/344541) – Kay Zed Dec 02 '16 at 02:23
  • Possible duplicate of [How can a C# Windows Console application tell if it is run interactively](http://stackoverflow.com/questions/1188658/how-can-a-c-sharp-windows-console-application-tell-if-it-is-run-interactively) – Glenn Slayden Feb 22 '17 at 22:33
  • @GlennSlayden No - this is not a duplicate of that question - as demonstrated by the accepted answer to that question NOT applying as correct in this case. For that question Environment.UserInteractive is correct but for this question it is not (see comments to the answer below that suggests it). – Ricibob Mar 06 '17 at 17:56

11 Answers11

24

This works for me (using native method).

First, declare:

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

After that, check with elegance... hahaha...:

if (GetConsoleWindow() != IntPtr.Zero)
{
    Console.Write("has console");
}
CarenRose
  • 1,266
  • 1
  • 12
  • 24
Sergio Cabral
  • 6,490
  • 2
  • 35
  • 37
22
if (Environment.UserInteractive)
{
    // A console is opened
}

See: http://msdn.microsoft.com/en-us/library/system.environment.userinteractive(v=vs.110).aspx

Gets a value indicating whether the current process is running in user interactive mode.

Pedro
  • 3,511
  • 2
  • 26
  • 31
  • 4
    Works for distinguishing windows server from console/wpf app but doesn't actually identify a console i.e distinguish betwee console and wpf. – Ricibob Nov 14 '14 at 09:57
  • 1
    Correct, services can run in interactive mode on WIndows systems, this has been the case for a long time. For a simple desktop app this method may be acceptable. If you're writing code which may run in a windows process as well as desktop (such as logging code) then this method may have unintended consequences (such as wasting cycles writing console output when running as a service.) – Shaun Wilson Feb 06 '16 at 07:47
  • 1
    In .Net Core it returns true for an MVC site. – Luca Apr 15 '19 at 12:52
19

In the end I did as follows:

// Property:
private bool? _console_present;
public bool console_present {
    get {
        if (_console_present == null) {
            _console_present = true;
            try { int window_height = Console.WindowHeight; }
            catch { _console_present = false; }
        }
        return _console_present.Value;
    }
}

//Usage
if (console_present)
    Console.Read();

Following thekips advice I added a delegate member to library class to get user validation - and set this to a default implimentation that uses above to check if theres a console and if present uses that to get user validation or does nothing if not (action goes ahead without user validation). This means:

  1. All existing clients (command line apps, windows services (no user interaction), wpf apps) all work with out change.
  2. Any non console app that needs input can just replace the default delegate with someother (GUI - msg box etc) validation.

Thanks to all who replied.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • @rolls Exceptions are meant to be "exceptions", that's why that try catch is not a good practice design wise. Moreover, Exceptions are quite heavy object and the program has a performance impact for each exception, therefore they should be handled to address specific issues (such as missing files, lost connections and so on). – Luca Apr 30 '19 at 13:40
  • @Luca is there a better method to achieve this then? – rollsch May 01 '19 at 03:00
  • 1
    @rolls I found this https://stackoverflow.com/a/53716169/3065132 it works but it is of course a Windows only solution, therefore it is not a good solution for core. It is quite similar to the answer below. Probably the safest solution is a setting to turn on or off the console writing. For added safety you should write something to console (if on) at startup so you can check immediately it the app starts or not. – Luca May 03 '19 at 16:18
12

You can use this code:

public static bool HasMainWindow()
{
    return (Process.GetCurrentProcess().MainWindowHandle != IntPtr.Zero);
}

Worked fine with quick test on Console vs. WinForms application.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • 1
    Thanks - this is the kind of answere I wanted - unfortunately it returns true for me for both a console and wpf app.. :-( – Ricibob Jun 21 '11 at 07:02
  • @Rici that's weird.. my test Console return plain `false` - how exactly you build this console application? How you run it? – Shadow The GPT Wizard Jun 21 '11 at 07:12
  • @Shadow Wizard : Remember the code is in a library dll - the client is just a normal console app. I've posted an answer below that works for me - rather cludgy but get the job done - which at the moment is all I need! – Ricibob Jun 21 '11 at 07:25
  • @Rici exactly my test case. What OS? Windows 7 here. – Shadow The GPT Wizard Jun 21 '11 at 07:28
  • @Shadow Wizard: Um Win7 here too - thats weird - might be related to where its being called - maybe your calling it earlier than me in start up sequence. – Ricibob Jun 21 '11 at 07:34
  • @Rici I call the function right from the `static void Main(string[] args)` of the main class.. – Shadow The GPT Wizard Jun 21 '11 at 07:48
4

You should fix this in your design. This is a nice example of a place in which inversion of control would be very handy. As the calling code is aware of which UI is available, this code should specify an instance of an IInputReader interface, for example. This way, you can use the same code for multiple scenarios for getting input from the user.

Pang
  • 9,564
  • 146
  • 81
  • 122
thekip
  • 3,660
  • 2
  • 21
  • 41
  • 2
    Thank you - Im aware this is a design flaw - and your suggestion is the correct approach to fix this - but this particular case at this time doesn't justify a correct redesign - I just want to simple turn off console read. – Ricibob Jun 21 '11 at 07:14
  • In that case you can just use a property which you set from the UI? IsConsole and use boolean logic? – thekip Jun 21 '11 at 07:22
  • 2
    The code "calling in" will still need to determine this value, at some level.. hence back to the original question without a viable answer. Consider a Windows Service running from a console vs. running as a normal background task. – user2864740 Oct 30 '19 at 23:11
3

You can pass argument on initialize.

for example:

In your library class, add constructor with 'IsConsole' parameter.

public YourLibrary(bool IsConsole)
{
  if (IsConsole)
  {
     // Do console work
  }
  else 
  {
     // Do wpf work
  }
}

And from Console you can use:

YourLibrary lib = new YourLibrary(true);

Form wpf:

YourLibrary lib = new YourLibrary(false);
Vano Maisuradze
  • 5,829
  • 6
  • 45
  • 73
2

I rewrote @Ricibob's answer

public bool console_present {
    get {
        try { return Console.WindowHeight > 0; }
        catch { return false; }
    }
}

//Usage
if (console_present) { Console.Read(); }

It is simpler, but I prefer this native implementation:

[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();

//Usage
if (GetConsoleWindow() != IntPtr.Zero) { Console.Read(); }
Alan Baljeu
  • 2,383
  • 4
  • 25
  • 40
Sergio Cabral
  • 6,490
  • 2
  • 35
  • 37
2

This SO question may provide you a solution.

Another solution is:

Console.Read() returns -1 in windows forms applications without opening up a console window. In a console app, it returns the actual value. So you can write something like:

int j = Console.Read();
if (j == -1)
    MessageBox.Show("It's not a console app");
else
    Console.WriteLine("It's a console app");

I tested this code on console and winforms apps. In a console app, if the user inputs '-1', the value of j is 45. So it will work.

CarenRose
  • 1,266
  • 1
  • 12
  • 24
matrix
  • 3,000
  • 3
  • 24
  • 35
  • 2
    Thanks - but I need to know at app startup and I dont want to require an input from console at this time (and in a console app Console.Read will do that). Also in wpf Console.Read causes a hang (or an exception depending on when its called). – Ricibob Jun 21 '11 at 07:10
2

There are already a lot of (unsatisfying) answers... Here is a very simple and elegant one:

if (Console.LargestWindowWidth != 0) { /* we have a console */ }

LargestWindowWidth doesn't throw and returns 0 when there is no Console window.

(otherwise, I think it's safe to assume it will never return 0)

Wizou
  • 1,336
  • 13
  • 24
1

This is a modern (2018) answer to an old question.

var isReallyAConsoleWindow = Environment.UserInteractive && Console.Title.Length > 0;

The combination of Environment.UserInteractive and Console.Title.Length should give a proper answer to the question of whether there is a console window. It is a simple and straightforward solution.

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Vilhelm H.
  • 1,315
  • 1
  • 7
  • 15
  • 1
    Accessing `Console.Title` gives invalid operation – Stephen Lautier Jun 25 '19 at 15:31
  • Unless the engineer behind the console app disables user-interactive input because they don't want the single-threaded apartment to pause when the user grabs the current screen and pauses execution. – John Zabroski Oct 18 '19 at 17:43
0

If you want a good design, abstract the GUI dependences using an interface.

Implement a concrete class for the console version, another for the WPF version, and inject the correct version using any way (dependency injection, inversion of control, etc).

Pang
  • 9,564
  • 146
  • 81
  • 122
Steve B
  • 36,818
  • 21
  • 101
  • 174