C# 不通过标准输出写入控制台窗口

C# 不通过标准输出写入控制台窗口,c#,console,console-application,C#,Console,Console Application,如何直接写入控制台,而不必使用c#中的标准输出?我正在升级一些旧程序,它将标准输出重定向到文件中(因为输出很重要),我需要以某种方式直接写入控制台,并且文本不会出现在标准输出中。是否可能(不使用WinAPI) 编辑:我知道可以写入stderr,不过,可以在控制台上为stderr设置光标位置吗?您可以写入控制台。错误,虽然可以重定向,但它与stdout是分开的 可以在控制台上为stderr设置光标位置吗 编辑:假设stderr未被重定向,请参阅控制台.CursorTop和控制台.CursorLef

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


编辑:我知道可以写入stderr,不过,可以在控制台上为stderr设置光标位置吗?

您可以写入
控制台。错误
,虽然可以重定向,但它与stdout是分开的

可以在控制台上为stderr设置光标位置吗

编辑:假设stderr未被重定向,请参阅
控制台.CursorTop
控制台.CursorLeft
。有一些你可能会觉得有用的东西


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

如果我运行您的程序并重定向其StandardOutput和StandardError,您希望在没有控制台的情况下写入操作会发生什么

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


将console窗口视为一个UI元素,它允许用户查看程序的stdout/stderr(并提供stdin)。它并不是为了其他目的而存在的。

我实际上在不久前实现了低级别,作为我编写的基于终端的俄罗斯方块实现的一部分,因为使用
控制台进行彩色控制台输出。BackgroundColor
console.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;
    }
}
测试代码:

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

如果您的问题只是设置光标位置,请查看-->呃,我的问题。我想,设置光标位置只适用于Console.Write,而nto适用于Console.Error.Write。谢谢。奇怪的是,telnet.exe不使用stdout或stderr,但仍然会写入控制台。我还不知道怎么做!仅供参考,telnet使用WriteConsoleOutputW和ReadConsoleInputA了解更多信息,请参阅
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();            
    }
}