c# - Console.Write() 将在 WPF 中挂起,但在控制台应用程序中有效

标签 c# wpf winapi console-application

请阅读 Scott Chamberlain 的回答,了解为什么它与 WINAPI 相关。

在 Visual Studio 中创建一个新的 WPF 应用程序并更改 MainWindow.xaml.cs 中的代码,如下所示。运行应用程序。代码将在第二次调用 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);
            }
        }
    }
}

现在在 Visual Studio 中创建一个新的控制台应用程序并更改 Program.cs 中的代码,如下所示。运行应用程序。它将成功运行,即不会挂起。

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);
            }
        }
    }
}

问题:

  1. 为什么对 Console.Write() 的第二次调用在 WPF 应用程序中挂起?
  2. 为什么控制台应用程序中的行为不同?
  3. 为什么只有字符串是\0时才会发生? (如果你做 1024 个空格,它工作正常。)

最佳答案

基本解释: 它挂起是因为缓冲区 Console.Write 在显示文本之前写入已满,并且在传入 null 时不会耗尽 WPF 应用程序字符 (\0) 超出我所知的原因。


详细说明:当您调用 Console.Write 时,它会创建一个 Handle将其数据输出到并最终调用 WriteFile在那个 handle 上。句柄的另一端需要处理写入它的数据,然后将控制权返回给调用者。我可以找到 WPF 和控制台应用程序之间的两个主要区别:

首先,如果你inspect the handle type使用控制台应用程序,您可以获得 FILE_TYPE_CHAR 类型的句柄,从 WPF 中,您可以获得 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();

其次,接收端处理句柄的方式不同。在控制台应用程序中,句柄由 conhost.exe 读取,在 WPF 中,它由 visual studio 读取。

挂起本身是因为缓冲区中的空间有限,在句柄必须阻止新的传入请求之前只能排队这么多文本,以便现有信息可以耗尽。控制台应用程序的句柄似乎可以处理大量的 \0 字符,但 WPF 生成的句柄不能。如果这种差异是由于它是不同类型的句柄或句柄另一侧的处理器以不同方式读取数据,我不知道。

希望比我在 Windows API 调用 WriteFile 方面有更多经验的人可以解释这两种句柄类型之间的差异,并且如果这是因为句柄类型或因为接收程序。

关于c# - Console.Write() 将在 WPF 中挂起,但在控制台应用程序中有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22678681/

相关文章:

python - 确定是否继承 ntfs 权限的可靠方法

c - Windows 的 SIGCHLD 替换

c# - 在用 C# 加密的 SQL Anywhere 16 中解密 AES,反之亦然

c# - 37signals Highrise .NET (c#) API

c# - 允许 'pasting data' 进入 WPF 文本框

带有两个拇指的 WPF slider

c# - C# 中的通用 Map/Reduce 列表扩展

c# - 使用 GCP 的数据存储时如何区分代码是在模拟器中运行还是在 GKE 中运行

c# - 在 WPF MVVM Observable 集合中实现 IsDirty

c++ - 将窗口置于最前面的正确方法是什么