【问题标题】:Console.Out Output is showing in Output Window, Needed in AllocConsole()Console.Out 输出显示在输出窗口中,AllocConsole() 中需要
【发布时间】:2017-05-28 04:55:33
【问题描述】:

好的,当需要 Winform 时,我也一直使用 AllocConsole() 方法进行控制台输出,因为在写入控制台时我使用了多种颜色。

使用 VS 2015 及以下版本,调试模式下的 AllocConsole 始终正常工作,Console.WriteLine 正确写入。现在使用 VS 2017,控制台会在调用 AllocConsole 时显示,但是,控制台不会输出到该控制台,而是输出到 Visual Studio 的输出窗口。

我更喜欢使用 AllocConsole 而不是输出窗口,因为我非常依赖颜色。我已经针对如何解决此问题进行了大量搜索,但似乎找不到答案。

【问题讨论】:

  • 因为 VS2017 还处于 RC 阶段,I would ask them directly
  • 可能重复...这是您可以在项目中设置的内容。查看 Chaz 的回答 How do I show a console output/window in a forms
  • @JohnG 谢谢!一种更简单的方法来完成所需的工作。
  • 遇到同样的问题,有更新吗?
  • @Ashkan JohnQ 提供的链接就足够了。我将应用程序更改为控制台应用程序,然后在不需要时将控制台隐藏起来。像魅力一样工作。

标签: c# console output visual-studio-2017


【解决方案1】:

AllocConsole() 不能单独工作,因为 VS 2017 做了一些“调试标准输出重定向魔术”。要解决此问题,您需要使用 AllocConsole() 创建一个控制台并修复标准输出句柄。

这是我找到的片段:

[DllImport("kernel32.dll",
    EntryPoint = "AllocConsole",
    SetLastError = true,
    CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateFile(
    string lpFileName,
    uint dwDesiredAccess,
    uint dwShareMode,
    uint lpSecurityAttributes,
    uint dwCreationDisposition,
    uint dwFlagsAndAttributes,
    uint hTemplateFile);

private const int MY_CODE_PAGE = 437;
private const uint GENERIC_WRITE = 0x40000000;
private const uint FILE_SHARE_WRITE = 0x2;
private const uint OPEN_EXISTING = 0x3;

public static void CreateConsole()
{
    AllocConsole();

    IntPtr stdHandle = CreateFile(
        "CONOUT$",
        GENERIC_WRITE,
        FILE_SHARE_WRITE,
        0, OPEN_EXISTING, 0, 0
    );

    SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true);
    FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write);
    Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE);
    StreamWriter standardOutput = new StreamWriter(fileStream, encoding);
    standardOutput.AutoFlush = true;
    Console.SetOut(standardOutput);

    Console.Write("This will show up in the Console window.");
}

特别感谢 Ramkumar Ramesh 的解决方法: Console Output is gone in VS2017

【讨论】:

    【解决方案2】:

    基于 wischi 的回答,如果您希望静态 Console 类的属性正常工作,例如 Console.ForegroundColor,将所需的访问权限设置为 GENERIC_READ | 很重要。 GENERIC_WRITE。我认为原因是控制台在内部使用 GetConsoleScreenBufferInfo,当我尝试在 CreateFile 返回的句柄上使用该方法时,只有 GENERIC_WRITE 给了我一个 ACCESS_DENIED 错误。

        [DllImport("kernel32.dll")]
    private static extern bool AllocConsole();
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr CreateFile(string lpFileName
        , [MarshalAs(UnmanagedType.U4)] DesiredAccess dwDesiredAccess
        , [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode
        , uint lpSecurityAttributes
        , [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition
        , [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes
        , uint hTemplateFile);
    
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetStdHandle(StdHandle nStdHandle, IntPtr hHandle);
    
    private enum StdHandle : int
    {
        Input = -10,
        Output = -11,
        Error = -12
    }
    
    [Flags]
    enum DesiredAccess : uint
    {
        GenericRead = 0x80000000,
        GenericWrite = 0x40000000,
        GenericExecute = 0x20000000,
        GenericAll = 0x10000000
    }
    
    public static void CreateConsole()
    {
        if (AllocConsole())
        {
            //https://developercommunity.visualstudio.com/content/problem/12166/console-output-is-gone-in-vs2017-works-fine-when-d.html
            // Console.OpenStandardOutput eventually calls into GetStdHandle. As per MSDN documentation of GetStdHandle: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx will return the redirected handle and not the allocated console:
            // "The standard handles of a process may be redirected by a call to  SetStdHandle, in which case  GetStdHandle returns the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle to a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle to a console's active screen buffer."
            // Get the handle to CONOUT$.    
            var stdOutHandle = CreateFile("CONOUT$", DesiredAccess.GenericRead | DesiredAccess.GenericWrite, FileShare.ReadWrite, 0, FileMode.Open, FileAttributes.Normal, 0);
    
            if (stdOutHandle == new IntPtr(-1))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
    
            if (!SetStdHandle(StdHandle.Output, stdOutHandle))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
    
            var standardOutput = new StreamWriter(Console.OpenStandardOutput());
            standardOutput.AutoFlush = true;
            Console.SetOut(standardOutput);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多