No output to console from a WPF application?
Asked Answered
B

10

170

I'm using Console.WriteLine() from a very simple WPF test application, but when I execute the application from the command line, I'm seeing nothing being written to the console. Does anyone know what might be going on here?

I can reproduce it by creating a WPF application in VS 2008, and simply adding Console.WriteLine("text") anywhere where it gets executed. Any ideas?

All I need for right now is something as simple as Console.WriteLine(). I realize I could use log4net or somet other logging solution, but I really don't need that much functionality for this application.

Edit: I should have remembered that Console.WriteLine() is for console applications. Oh well, no stupid questions, right? :-) I'll just use System.Diagnostics.Trace.WriteLine() and DebugView for now.

Burtis answered 2/10, 2008 at 2:12 Comment(3)
Possible duplicates here and here (newer, but with some interesting answers using AttachConsole from Kernel32.dll)Rodrigues
@Max, those questions are possible duplicates of this question. This question was asked 2-4 years before either of those questions you posted.Burtis
This isn't a stupid question at all @Rob. Over the years I've seen Debug and Console change roles a number of times.Darnley
C
102

You'll have to create a Console window manually before you actually call any Console.Write methods. That will init the Console to work properly without changing the project type (which for WPF application won't work).

Here's a complete source code example, of how a ConsoleManager class might look like, and how it can be used to enable/disable the Console, independently of the project type.

With the following class, you just need to write ConsoleManager.Show() somewhere before any call to Console.Write...

[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
    private const string Kernel32_DllName = "kernel32.dll";

    [DllImport(Kernel32_DllName)]
    private static extern bool AllocConsole();

    [DllImport(Kernel32_DllName)]
    private static extern bool FreeConsole();

    [DllImport(Kernel32_DllName)]
    private static extern IntPtr GetConsoleWindow();

    [DllImport(Kernel32_DllName)]
    private static extern int GetConsoleOutputCP();

    public static bool HasConsole
    {
        get { return GetConsoleWindow() != IntPtr.Zero; }
    }

    /// <summary>
    /// Creates a new console instance if the process is not attached to a console already.
    /// </summary>
    public static void Show()
    {
        //#if DEBUG
        if (!HasConsole)
        {
            AllocConsole();
            InvalidateOutAndError();
        }
        //#endif
    }

    /// <summary>
    /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
    /// </summary>
    public static void Hide()
    {
        //#if DEBUG
        if (HasConsole)
        {
            SetOutAndErrorNull();
            FreeConsole();
        }
        //#endif
    }

    public static void Toggle()
    {
        if (HasConsole)
        {
            Hide();
        }
        else
        {
            Show();
        }
    }

    static void InvalidateOutAndError()
    {
        Type type = typeof(System.Console);

        System.Reflection.FieldInfo _out = type.GetField("_out",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.FieldInfo _error = type.GetField("_error",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        Debug.Assert(_out != null);
        Debug.Assert(_error != null);

        Debug.Assert(_InitializeStdOutError != null);

        _out.SetValue(null, null);
        _error.SetValue(null, null);

        _InitializeStdOutError.Invoke(null, new object[] { true });
    }

    static void SetOutAndErrorNull()
    {
        Console.SetOut(TextWriter.Null);
        Console.SetError(TextWriter.Null);
    }
} 
Cavy answered 5/4, 2009 at 7:14 Comment(15)
I like this, it works, & I can use this in other projects. However because it launches a new console window it causes an issue with a current project. If I pass in command line options would like to be able to output to the console that it was launched from so the user gets the output there. In my app if command line options are provided it stays a console app and then does its work and then exits. This allows for the app to be automated and schedule to do tasks, or the user can just do something quickly and get out. However I want to output some things , like the help usage stuff, etc.Indigent
Is it possible to embed the console window within a WPF window using this or any other technique?Packhorse
Why would you want to do this? After all -- it won't look good, and I can easily make WPF control to have the same features (but it would look better).Harwin
It's possible to try to call AttachConsole(-1) first and check its return value to attach to the parent process' console; if it returns false, call AllocConsole. However, the application still 'returns' first and only then outputs to the console, I'll post more if I find a solution. Also, if you set the WPF app type to Console Application, the problem disappears but you can't detach the console without it showing on the screen briefly when the program is started, so it kinda looks awkward (but if you can live with it, it works great).Coverup
Eh, actually no, I don't think it's possible to have it both ways; a Console application is marked as CUI in its PE header and thus cooperates well with CMD automatically. A GUI application on the other hand returns control to CMD immediately, and even if it can reattach to the console, reading and writing will be intermingled with the next outputs in the pipeline, which is obviously very bad. If on the other hand you mark the application as Console application, you only have to live with CMD showing briefly at app startup; you can then use FreeConsole to detach and Attach/Alloc later etcCoverup
Why do this when the answer from Brian works as well and much easier.Mallory
Might be obvious, but I found that Console.WriteLine still did not work using this technique when the Visual Studio debugger was attached. When I ran the app outside of VS it worked a treat. Thanks.Solifidian
Problem with using this Apporach is that when you close this Console from close button, the whole application closes.Baroja
@Baroja I know, that sucks but that's not necessarily a limitation of Windows and I actually do believe that it's possible to detach the console from the process in such a way that this does not happen. Anyway, if you really want an interactive console session with your app, just roll your own GUI, it's going to be superior to the ConHost either way. This really just is something you can do, if you want to and not something that's particularly great. It does work but I don't think it's what you ought to really be doing...Cavy
@John Leidegren any lead to help me on deattaching the consle from the process as I am new to this ? will be much apperciated :) I created a question for this that can be found here : #18379304Baroja
@Baroja Yeah, but it doesn't work... There's a SetConsoleCtrlHandler function that allows to be notified when the CTRL_CLOSE_EVENT event happens but you can't do anything with it, there's nothing that's allowing your application to continue. You will be shut down. If you feel like hacking, you could probably swap the windows message handler for the console process and just drop the WM_CLOSE message, I have never tried this but it could work. It's just another window but with that said, unless you want to entertain this idea you effort is probably better spent doing something else.Cavy
Fantastic. Works for me, in VS 2013 over Win Pro 8.1. Good apport!!Gutturalize
Even though everyone uses the other solution where to convert the app to Console Application, I really prefer this solution.Rocray
finally something that works, many thanks. it's an absolute shame how VS makes it so terribly confusing and intricate to just monitor console output. -100 for microsoftBrewmaster
If I start the app from cmd, do I still need this?Kirbie
C
229

You can use

Trace.WriteLine("text");

This will output to the "Output" window in Visual Studio (when debugging).

make sure to have the Diagnostics assembly included:

using System.Diagnostics;
Corvette answered 2/10, 2008 at 2:20 Comment(7)
this is the best answer, but has not the highest ratingAmalgamation
I agree - this is exactly what op is asking for. Great alternative to Console.WriteLine() - the solution marked as the answer is a neat exercise but unreasonable to include in a production application.Gosling
PS for Windows Store apps (Windows Runtime) the equivalent of Trace.WriteLine is Debug.WriteLine()Gosling
This is a simple, clean solution, however didn't work for me. Didn't work in entity framework's seed method during update-database. Otherwise, works everywhere else!Onyx
This is the best solution. Would be better if the answer also explained that Console.WriteLine is not intended for WPF applications at all, and that it is intended only for command-line apps.Syrup
Perfect, but no "tw(tab)(tab)" output which is just a pain.Bruin
Key point here is "when debugging". It won't work if you run without debugging.Gaiety
D
157

Right click on the project, "Properties", "Application" tab, change "Output Type" to "Console Application", and then it will also have a console, the WPF Applications still runs as expected (even if the Application output type is switched to "Console Application").

Dimitry answered 2/10, 2008 at 2:17 Comment(7)
The only issue with that is you will have a cmd open in the background, but it works :).Cockatoo
Great, but command-line window will be created when application is not executed from cmd.exe (two windows created for one application). But for this there is also solution: you can hide cmd window by ShowWindow(hWnd, 0). https://mcmap.net/q/145029/-output-console-writeline-from-wpf-windows-applications-to-actual-console . Using this solution you will see text in console only when WPF application is executed from command-line.Craal
Note you'll have to switch it back to "Window Application" while working in Blend, as it only shows XAML (with no access to the Design View) for "Console Application" types. (as of Blend 2013)Casto
Not correct ans. Hides main Windows. Just console comes up.Rossy
Thanks! This solution is MUST when you do what @John Leidegren showed in the answer aboveBritt
For people not using Visual Studio, set <OutputType>Exe</OutputType> instead of <OutputType>WinExe</OutputType> in your csproj file (see here learn.microsoft.com/en-us/visualstudio/msbuild/…).Murphey
right click where? 'project' is pretty vague... I don't see any application tabSweepings
C
102

You'll have to create a Console window manually before you actually call any Console.Write methods. That will init the Console to work properly without changing the project type (which for WPF application won't work).

Here's a complete source code example, of how a ConsoleManager class might look like, and how it can be used to enable/disable the Console, independently of the project type.

With the following class, you just need to write ConsoleManager.Show() somewhere before any call to Console.Write...

[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
    private const string Kernel32_DllName = "kernel32.dll";

    [DllImport(Kernel32_DllName)]
    private static extern bool AllocConsole();

    [DllImport(Kernel32_DllName)]
    private static extern bool FreeConsole();

    [DllImport(Kernel32_DllName)]
    private static extern IntPtr GetConsoleWindow();

    [DllImport(Kernel32_DllName)]
    private static extern int GetConsoleOutputCP();

    public static bool HasConsole
    {
        get { return GetConsoleWindow() != IntPtr.Zero; }
    }

    /// <summary>
    /// Creates a new console instance if the process is not attached to a console already.
    /// </summary>
    public static void Show()
    {
        //#if DEBUG
        if (!HasConsole)
        {
            AllocConsole();
            InvalidateOutAndError();
        }
        //#endif
    }

    /// <summary>
    /// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
    /// </summary>
    public static void Hide()
    {
        //#if DEBUG
        if (HasConsole)
        {
            SetOutAndErrorNull();
            FreeConsole();
        }
        //#endif
    }

    public static void Toggle()
    {
        if (HasConsole)
        {
            Hide();
        }
        else
        {
            Show();
        }
    }

    static void InvalidateOutAndError()
    {
        Type type = typeof(System.Console);

        System.Reflection.FieldInfo _out = type.GetField("_out",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.FieldInfo _error = type.GetField("_error",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
            System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

        Debug.Assert(_out != null);
        Debug.Assert(_error != null);

        Debug.Assert(_InitializeStdOutError != null);

        _out.SetValue(null, null);
        _error.SetValue(null, null);

        _InitializeStdOutError.Invoke(null, new object[] { true });
    }

    static void SetOutAndErrorNull()
    {
        Console.SetOut(TextWriter.Null);
        Console.SetError(TextWriter.Null);
    }
} 
Cavy answered 5/4, 2009 at 7:14 Comment(15)
I like this, it works, & I can use this in other projects. However because it launches a new console window it causes an issue with a current project. If I pass in command line options would like to be able to output to the console that it was launched from so the user gets the output there. In my app if command line options are provided it stays a console app and then does its work and then exits. This allows for the app to be automated and schedule to do tasks, or the user can just do something quickly and get out. However I want to output some things , like the help usage stuff, etc.Indigent
Is it possible to embed the console window within a WPF window using this or any other technique?Packhorse
Why would you want to do this? After all -- it won't look good, and I can easily make WPF control to have the same features (but it would look better).Harwin
It's possible to try to call AttachConsole(-1) first and check its return value to attach to the parent process' console; if it returns false, call AllocConsole. However, the application still 'returns' first and only then outputs to the console, I'll post more if I find a solution. Also, if you set the WPF app type to Console Application, the problem disappears but you can't detach the console without it showing on the screen briefly when the program is started, so it kinda looks awkward (but if you can live with it, it works great).Coverup
Eh, actually no, I don't think it's possible to have it both ways; a Console application is marked as CUI in its PE header and thus cooperates well with CMD automatically. A GUI application on the other hand returns control to CMD immediately, and even if it can reattach to the console, reading and writing will be intermingled with the next outputs in the pipeline, which is obviously very bad. If on the other hand you mark the application as Console application, you only have to live with CMD showing briefly at app startup; you can then use FreeConsole to detach and Attach/Alloc later etcCoverup
Why do this when the answer from Brian works as well and much easier.Mallory
Might be obvious, but I found that Console.WriteLine still did not work using this technique when the Visual Studio debugger was attached. When I ran the app outside of VS it worked a treat. Thanks.Solifidian
Problem with using this Apporach is that when you close this Console from close button, the whole application closes.Baroja
@Baroja I know, that sucks but that's not necessarily a limitation of Windows and I actually do believe that it's possible to detach the console from the process in such a way that this does not happen. Anyway, if you really want an interactive console session with your app, just roll your own GUI, it's going to be superior to the ConHost either way. This really just is something you can do, if you want to and not something that's particularly great. It does work but I don't think it's what you ought to really be doing...Cavy
@John Leidegren any lead to help me on deattaching the consle from the process as I am new to this ? will be much apperciated :) I created a question for this that can be found here : #18379304Baroja
@Baroja Yeah, but it doesn't work... There's a SetConsoleCtrlHandler function that allows to be notified when the CTRL_CLOSE_EVENT event happens but you can't do anything with it, there's nothing that's allowing your application to continue. You will be shut down. If you feel like hacking, you could probably swap the windows message handler for the console process and just drop the WM_CLOSE message, I have never tried this but it could work. It's just another window but with that said, unless you want to entertain this idea you effort is probably better spent doing something else.Cavy
Fantastic. Works for me, in VS 2013 over Win Pro 8.1. Good apport!!Gutturalize
Even though everyone uses the other solution where to convert the app to Console Application, I really prefer this solution.Rocray
finally something that works, many thanks. it's an absolute shame how VS makes it so terribly confusing and intricate to just monitor console output. -100 for microsoftBrewmaster
If I start the app from cmd, do I still need this?Kirbie
D
29

Old post, but I ran into this so if you're trying to output something to Output in a WPF project in Visual Studio, the contemporary method is:

Include this:

using System.Diagnostics;

And then:

Debug.WriteLine("something");
Destitution answered 19/1, 2017 at 2:7 Comment(0)
T
15

Although John Leidegren keeps shooting down the idea, Brian is correct. I've just got it working in Visual Studio.

To be clear a WPF application does not create a Console window by default.

You have to create a WPF Application and then change the OutputType to "Console Application". When you run the project you will see a console window with your WPF window in front of it.

It doesn't look very pretty, but I found it helpful as I wanted my app to be run from the command line with feedback in there, and then for certain command options I would display the WPF window.

Tallula answered 27/4, 2009 at 11:52 Comment(1)
Perfect. Does the job.Goldia
T
14

It's possible to see output intended for console by using command line redirection.

For example:

C:\src\bin\Debug\Example.exe > output.txt

will write all the content to output.txt file.

Talley answered 30/5, 2014 at 15:10 Comment(2)
Best answer as it is simple and doesn't require changes to the sourceForked
... and of course, the next step is to open the file in notepad++ and select 'View -> Monitoring (tail -f)' to watch it update in real timeFragonard
F
5

Brian's solution is to always open a console when your WPF application starts. If you want to dynamically enable console output (for example, only when launched with certain commandline arguments) call AttachConsole:

[DllImport("kernel32.dll")]
static extern bool AttachConsole(uint dwProcessId);

const uint ATTACH_PARENT_PROCESS = 0x0ffffffff;

Then, when you want to start writing to the console:

AttachConsole(ATTACH_PARENT_PROCESS);
Console.WriteLine("Hello world!");
Console.WriteLine("Writing to the hosting console!");
Finisterre answered 6/10, 2022 at 9:51 Comment(3)
This solution seems works, but if you write something like "yourapp.exe > result.txt" You will notice that the output does not redirect to the file.Priggery
i couldnt figure out where to put this code. everywhere I tried gave me an errorSweepings
@johnk The first part should go inside a class, outside of any functions. The second part should be in the function where you want to write to the console.Finisterre
S
4

I use Console.WriteLine() for use in the Output window...

Scroll answered 2/10, 2008 at 5:50 Comment(1)
It's a 4 year old question that's been edited heavily since I first saw it. Now of course the question has been better worded and my response was made irrelevant.Scroll
I
2

I've create a solution, mixed the information of varius post.

Its a form, that contains a label and one textbox. The console output is redirected to the textbox.

There are too a class called ConsoleView that implements three publics methods: Show(), Close(), and Release(). The last one is for leave open the console and activate the Close button for view results.

The forms is called FrmConsole. Here are the XAML and the c# code.

The use is very simple:

ConsoleView.Show("Title of the Console");

For open the console. Use:

System.Console.WriteLine("The debug message");

For output text to the console.

Use:

ConsoleView.Close();

For Close the console.

ConsoleView.Release();

Leaves open the console and enables the Close button

XAML

<Window x:Class="CustomControls.FrmConsole"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:CustomControls"
    mc:Ignorable="d"
    Height="500" Width="600" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" Topmost="True" Icon="Images/icoConsole.png">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="40"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Name="lblTitulo" HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center" FontFamily="Arial" FontSize="14" FontWeight="Bold" Content="Titulo"/>
    <Grid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="10"/>
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="1" Name="txtInner" FontFamily="Arial" FontSize="10" ScrollViewer.CanContentScroll="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" TextWrapping="Wrap"/>
    </Grid>
    <Button Name="btnCerrar" Grid.Row="2" Content="Cerrar" Width="100" Height="30" HorizontalAlignment="Center" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"/>
</Grid>

The code of the Window:

partial class FrmConsole : Window
{
    private class ControlWriter : TextWriter
    {
        private TextBox textbox;
        public ControlWriter(TextBox textbox)
        {
            this.textbox = textbox;
        }

        public override void WriteLine(char value)
        {
            textbox.Dispatcher.Invoke(new Action(() =>
            {
                textbox.AppendText(value.ToString());
                textbox.AppendText(Environment.NewLine);
                textbox.ScrollToEnd();
            }));
        }

        public override void WriteLine(string value)
        {
            textbox.Dispatcher.Invoke(new Action(() =>
            {
                textbox.AppendText(value);
                textbox.AppendText(Environment.NewLine);
                textbox.ScrollToEnd();
            }));
        }

        public override void Write(char value)
        {
            textbox.Dispatcher.Invoke(new Action(() =>
            {
                textbox.AppendText(value.ToString());
                textbox.ScrollToEnd();
            }));
        }

        public override void Write(string value)
        {
            textbox.Dispatcher.Invoke(new Action(() =>
            {
                textbox.AppendText(value);
                textbox.ScrollToEnd();
            }));
        }

        public override Encoding Encoding
        {
            get { return Encoding.UTF8; }

        }
    }

    //DEFINICIONES DE LA CLASE
    #region DEFINICIONES DE LA CLASE

    #endregion


    //CONSTRUCTORES DE LA CLASE
    #region CONSTRUCTORES DE LA CLASE

    public FrmConsole(string titulo)
    {
        InitializeComponent();
        lblTitulo.Content = titulo;
        Clear();
        btnCerrar.Click += new RoutedEventHandler(BtnCerrar_Click);
        Console.SetOut(new ControlWriter(txtInner));
        DesactivarCerrar();
    }

    #endregion


    //PROPIEDADES
    #region PROPIEDADES

    #endregion


    //DELEGADOS
    #region DELEGADOS

    private void BtnCerrar_Click(object sender, RoutedEventArgs e)
    {
        Close();
    }

    #endregion


    //METODOS Y FUNCIONES
    #region METODOS Y FUNCIONES

    public void ActivarCerrar()
    {
        btnCerrar.IsEnabled = true;
    }

    public void Clear()
    {
        txtInner.Clear();
    }

    public void DesactivarCerrar()
    {
        btnCerrar.IsEnabled = false;
    }

    #endregion  
}

the code of ConsoleView class

static public class ConsoleView
{
    //DEFINICIONES DE LA CLASE
    #region DEFINICIONES DE LA CLASE
    static FrmConsole console;
    static Thread StatusThread;
    static bool isActive = false;
    #endregion

    //CONSTRUCTORES DE LA CLASE
    #region CONSTRUCTORES DE LA CLASE

    #endregion

    //PROPIEDADES
    #region PROPIEDADES

    #endregion

    //DELEGADOS
    #region DELEGADOS

    #endregion

    //METODOS Y FUNCIONES
    #region METODOS Y FUNCIONES

    public static void Show(string label)
    {
        if (isActive)
        {
            return;
        }

        isActive = true;
        //create the thread with its ThreadStart method
        StatusThread = new Thread(() =>
        {
            try
            {
                console = new FrmConsole(label);
                console.ShowDialog();
                //this call is needed so the thread remains open until the dispatcher is closed
                Dispatcher.Run();
            }
            catch (Exception)
            {
            }
        });

        //run the thread in STA mode to make it work correctly
        StatusThread.SetApartmentState(ApartmentState.STA);
        StatusThread.Priority = ThreadPriority.Normal;
        StatusThread.Start();

    }

    public static void Close()
    {
        isActive = false;
        if (console != null)
        {
            //need to use the dispatcher to call the Close method, because the window is created in another thread, and this method is called by the main thread
            console.Dispatcher.InvokeShutdown();
            console = null;
            StatusThread = null;
        }

        console = null;
    }

    public static void Release()
    {
        isActive = false;
        if (console != null)
        {
            console.Dispatcher.Invoke(console.ActivarCerrar);
        }

    }
    #endregion
}

I hope this result usefull.

Ithyphallic answered 6/8, 2018 at 6:42 Comment(0)
C
1

Old problem, got stuck with @Bip901 solution that sometimes worked but sometimes not, at last came to this code that works in all cases:

// writing to parent console https://stackoverflow.com/a/73971822
public class WriteToConsoleHelper
{
    const uint parentProcessId = 0x0ffffffff;

    [DllImport("kernel32.dll")]
    static extern bool AttachConsole(uint dwProcessId);

    public static void WriteLineToConsole(string message)
    {
        var currentProcessId = (uint)Environment.ProcessId;
        AttachConsole(parentProcessId);

        var originalConsoleOut = Console.Out;
        var writer = new StreamWriter(Console.OpenStandardOutput())
        {
            AutoFlush = true
        };

        Console.SetOut(writer);
        Console.WriteLine(message);
        Console.SetOut(originalConsoleOut);
        
        writer.Dispose();

        AttachConsole(currentProcessId);
    }
}
Cameroncameroon answered 20/12, 2023 at 10:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.