【问题标题】:Writing to console window not via stdout不通过标准输出写入控制台窗口
【发布时间】:2010-08-25 12:14:53
【问题描述】:

我怎样才能直接写入控制台,而不用在 c# 中使用标准输出?我正在升级一些旧程序,它的标准输出重定向到文件中(因为输出很重要),我需要以某种方式直接写入控制台,并且文本不会出现在标准输出中。有可能(不使用 WinAPI)吗?

编辑:我知道写入 stderr 的可能性,但是否可以在控制台上为 stderr 设置光标位置?

【问题讨论】:

  • 如果您的问题只是设置光标位置,请查看 --> msdn.microsoft.com/en-us/library/…
  • 呃,我的错。我想,设置光标位置仅适用于 Console.Write,而不适用于 Console.Error.Write。谢谢。

标签: c# console console-application


【解决方案1】:

你可以写信给Console.Error,虽然它可以被重定向,但它与标准输出是分开的。

是否可以在控制台上设置 stderr 的光标位置?

编辑:假设stderr没有被重定向,参见Console.CursorTopConsole.CursorLeftvarious other members on the Console class 可能对您有用。

要直接回答您的问题,请使用 Win32 WriteConsole 函数。据我所知,.NET 框架没有直接写入控制台窗口的方法。

【讨论】:

    【解决方案2】:

    如果我运行你的程序并重定向它的 StandardOutput 和 StandardError,那么当没有控制台时,你希望你的写入会发生什么?

    出于这个原因,答案很可能是“你不能”(除了可能使用疯狂的 hack,这可能涉及你说你不想使用的 Windows API)。

    将控制台窗口视为一个 UI 元素,它允许用户查看程序的标准输出/标准错误(并提供标准输入)。它并没有真正用于任何其他目的。

    【讨论】:

    • 奇怪的是 telnet.exe 不使用 stdout 或 stderr,但仍会写入控制台。我还不知道怎么做!
    • 仅供参考,telnet使用WriteConsoleOutputW和ReadConsoleInputA,了解更多见stackoverflow.com/questions/45805785/…
    【解决方案3】:

    实际上,作为我编写的基于终端的俄罗斯方块实现的一部分,我实际上最终实现了低级别 WriteConsoleOutput,因为使用 Console.BackgroundColorConsole.Write 进行彩色控制台输出对于全屏刷新来说太慢了.执行原始缓冲区输出要快得多

    注意,这会将文本写入屏幕上的某个位置(例如 5,10),但不会自行更新或跟踪光标位置 - 使用此方法写入将更新文本缓冲区并显示输出,但光标不会移动。您需要使用其他方法手动移动和跟踪控制台光标,这应该不会太难。

    这是我的代码:

    主互操作类:

    public static class LowLevelConsole {
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern SafeFileHandle CreateFile(
            string fileName,
            [MarshalAs(UnmanagedType.U4)] uint fileAccess,
            [MarshalAs(UnmanagedType.U4)] uint fileShare,
            IntPtr securityAttributes,
            [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
            [MarshalAs(UnmanagedType.U4)] int flags,
            IntPtr template);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool WriteConsoleOutput(
          SafeFileHandle hConsoleOutput,
          CharInfo[] lpBuffer,
          Coord dwBufferSize,
          Coord dwBufferCoord,
          ref SmallRect lpWriteRegion);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct Coord {
            public short X;
            public short Y;
    
            public Coord(short X, short Y) {
                this.X = X;
                this.Y = Y;
            }
        };
    
        [StructLayout(LayoutKind.Explicit)]
        public struct CharUnion {
            [FieldOffset(0)]
            public char UnicodeChar;
            [FieldOffset(0)]
            public byte AsciiChar;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        public struct CharInfo {
            [FieldOffset(0)]
            public CharUnion Char;
            [FieldOffset(2)]
            public ushort Attributes;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct SmallRect {
            public short Left;
            public short Top;
            public short Right;
            public short Bottom;
        }
    
    
        [STAThread]
        public static void Write(string line, CharacterAttribute attribute, short xLoc, short yLoc) {
            SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
    
            short writeHeight = 1;
            short writeWidth = (short)line.Length;
    
            if (!h.IsInvalid) {
                CharInfo[] buf = new CharInfo[writeWidth * writeHeight];
                SmallRect rect = new SmallRect() { Left = xLoc, Top = yLoc, Right = (short)(writeWidth + xLoc), Bottom = (short)(writeHeight + yLoc) };
    
                for (int i = 0; i < writeWidth; i++) {
                    buf[i].Attributes = (ushort)attribute;
                    buf[i].Char.UnicodeChar = line[i];
                }
    
                bool b = WriteConsoleOutput(h, buf, new Coord() { X = writeWidth, Y = writeHeight }, new Coord() { X = 0, Y = 0 }, ref rect);
            }
        }
    
        [STAThread]
        public static bool WriteBuffer(CharInfo[,] buffer) { // returns true of success
            SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
    
            if (!h.IsInvalid) {
                short BufferWidth = (short)buffer.GetLength(0);
                short BufferHeight = (short)buffer.GetLength(1);
                CharInfo[] buf = new CharInfo[BufferWidth * BufferHeight];
                SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = BufferWidth, Bottom = BufferHeight };
    
    
                for (int y = 0; y < BufferHeight; y++) {
                    for (int x = 0; x < BufferWidth; x++) {
                        buf[y * BufferWidth + x] = buffer[x, y];
                    }
                }
                return WriteConsoleOutput(h, buf, new Coord() { X = BufferWidth, Y = BufferHeight }, new Coord() { X = 0, Y = 0 }, ref rect);
            }
            return false;
        }
    }
    

    Character attributes:

    [Flags]
    public enum CharacterAttribute : ushort {
        FOREGROUND_BLUE = 0x0001,
        FOREGROUND_GREEN = 0x0002,
        FOREGROUND_RED = 0x0004,
        FOREGROUND_INTENSITY = 0x0008,
        BACKGROUND_BLUE = 0x0010,
        BACKGROUND_GREEN = 0x0020,
        BACKGROUND_RED = 0x0040,
        BACKGROUND_INTENSITY = 0x0080,
        COMMON_LVB_LEADING_BYTE = 0x0100,
        COMMON_LVB_TRAILING_BYTE = 0x0200,
        COMMON_LVB_GRID_HORIZONTAL = 0x0400,
        COMMON_LVB_GRID_LVERTICAL = 0x0800,
        COMMON_LVB_GRID_RVERTICAL = 0x1000,
        COMMON_LVB_REVERSE_VIDEO = 0x4000,
        COMMON_LVB_UNDERSCORE = 0x8000
    }
    

    测试代码:

    class Program {
        static void Main(string[] args) {
            // write to location 0,0
            LowLevelConsole.Write("Some test text", CharacterAttribute.BACKGROUND_BLUE | CharacterAttribute.FOREGROUND_RED, 0, 0);
            // write to location 5,10
            LowLevelConsole.Write("another test at a different location", 
                CharacterAttribute.FOREGROUND_GREEN | CharacterAttribute.FOREGROUND_BLUE,
                5, 10);
            Console.ReadLine();            
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-09
      • 1970-01-01
      • 1970-01-01
      • 2018-03-09
      • 2015-02-11
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      相关资源
      最近更新 更多