Запись в консольное окно не через стандартный вывод - PullRequest
2 голосов
/ 25 августа 2010

как я могу написать ПРЯМО в консоль, не беспокоясь о stdout в c #? Я обновляю какую-то старую программу, у которой ее стандартный вывод перенаправлен в файл (потому что вывод имеет значение), и мне нужно каким-то образом писать прямо в консоль, и этот текст не будет отображаться в стандартном выводе. Возможно ли это (без использования WinAPI)?

РЕДАКТИРОВАТЬ: я знаю о возможности записи в stderr, возможно ли установить позицию курсора для stderr на консоли?

Ответы [ 3 ]

6 голосов
/ 25 августа 2010

Вы можете записать в Console.Error, что, хотя и может быть перенаправлено, отдельно от stdout.

возможно ли установить позицию курсора для stderr на консоли?

Редактировать : Предполагая, что stderr не был перенаправлен, см. Console.CursorTop и Console.CursorLeftConsole классе есть различные другие члены, которые могут оказаться полезными.

Чтобы ответить на ваш вопрос напрямую, используйте функцию Win32 WriteConsole.Насколько я вижу, .NET Framework не имеет методов для прямой записи в окно консоли.

0 голосов
/ 26 сентября 2016

Я фактически закончил реализацию низкого уровня WriteConsoleOutput некоторое время назад как часть реализации Tetris, основанной на терминалах, которую я написал, так как вывод цветной консоли с Console.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;
    }
}

Атрибуты персонажа :

[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();            
    }
}
0 голосов
/ 25 августа 2010

Если я запускаю вашу программу и перенаправляю ее StandardOutput и StandardError, что вы ожидаете от ваших записей, когда консоли нет?

По этой причине ответ скорее всего «вы не можете»(за исключением, возможно, использования сумасшедших хаков, которые, вероятно, включают в себя Windows API, который, как вы сказали, не хотите использовать).

Думайте об окне консоли как о не более чем элементе пользовательского интерфейса, который позволяет пользователю просматриватьстандартный вывод вашей программы (и предоставление стандартного ввода).На самом деле его не существует ни для каких других целей.

...