Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Console.Write() will hang in WPF, but works in Console application

Please read the answer by Scott Chamberlain to see why is it related to WINAPI.

Create a new WPF application in Visual Studio and change the code in MainWindow.xaml.cs as below. Run the application. The code will hang on second call to Console.Write().

MainWindow.xaml.cs

using System;
using System.Text;
using System.Windows;

namespace TestWpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            byte[] msg = new byte[1024];

            string msgStr = Encoding.Default.GetString(msg);

            for (int i = 0; i < 10; i++)
            {
                Console.Write(msgStr);
            }
        }
    }
}

Now create a new Console application in Visual Studio and change the code in Program.cs as below. Run the application. It will run successfully i.e. it will not hang.

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] msg = new byte[1024];

            string msgStr = Encoding.Default.GetString(msg);

            for (int i = 0; i < 100; i++)
            {
                Console.Write(msgStr);
            }
        }
    }
}

Questions:

  1. Why the second call to Console.Write() hangs in the WPF application?
  2. Why the behavior is different in console application?
  3. Why does it only happen if the string is a string of \0? (It works fine if you do 1024 spaces.)
like image 227
Roman Byshko Avatar asked Mar 27 '14 05:03

Roman Byshko


People also ask

How do I keep the console in C#?

The first solution is to run the application without debugging by using Ctrl+F5 instead of just F5. The console window will remain open when the program has finished.

What does console Write do in C#?

While Write() and WriteLine() both are the Console Class methods. The only difference between the Write() and WriteLine() is that Console. Write is used to print data without printing the new line, while Console. WriteLine is used to print data along with printing the new line.

Which function do we call to write something on the console window?

The WriteConsole function writes characters to the console screen buffer at the current cursor position. The cursor position advances as characters are written.

How do I debug console application?

Press F5 to run the program in Debug mode. Another way to start debugging is by choosing Debug > Start Debugging from the menu. Enter a string in the console window when the program prompts for a name, and then press Enter . Program execution stops when it reaches the breakpoint and before the Console.


1 Answers

Basic Explanation: It hangs because the buffer Console.Write writes to before the text is displayed is getting full and is not draining out for WPF applications when passing in null characters (\0) for reasons beyond my knowledge.


Detailed Explanation: When you call Console.Write it creates a Handle to output it's data to and eventually calls WriteFile on that handle. The other end of the handle needs to process the data that was written to it then return control to the caller. There are two major differences between WPF and a console application I could find:

First, if you inspect the handle type with a console application you get a handle of type FILE_TYPE_CHAR, from WPF you get FILE_TYPE_PIPE.

Console.Write(msgStr);

var cOut = Console.OpenStandardOutput();
var handle = cOut.GetType().GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(cOut);
var method = Type.GetType("Microsoft.Win32.Win32Native").GetMethod("GetFileType", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
var type = method.Invoke(null, new object[] { handle });
Debugger.Break();

Second, how the handle is processed on the receiving end is different. In a console application the handle is read in by conhost.exe, in WPF it is read in by visual studio.

The hang itself comes from the fact that there is limited space in the buffer and only so much text can be queued up before the handle has to block new incoming requests so the existing information can drain out. It appears that the handle for the console application can process large numbers of \0 characters but the handle that WPF generates can not. If that difference is from it being a different kind of handle or from the processor on the other side of the handle reading in data differently I don't know.

Hopefully someone who has more experience than me with the Windows API call WriteFile that can explain the differences between the two handle types and will give us a better idea if this is because of the handle type or because of the receiving program.

like image 70
Scott Chamberlain Avatar answered Oct 15 '22 13:10

Scott Chamberlain