2010-08-25 94 views
2

如何直接寫入控制檯,而不打擾c#中的標準輸出?我正在升級一些舊程序,它將stdout重定向到文件中(因爲輸出很重要),並且我需要以某種方式直接寫入控制檯,並且文本不會顯示在stdout中。有沒有可能(不使用WinAPI)?不通過標準輸出寫入控制檯窗口

編輯:我知道有可能寫信給stderr,通過,是否可以在控制檯上爲stderr設置光標位置?

+1

如果您的問題正好被設置光標位置有看看 - > http://msdn.microsoft.com/en-us/library/system.console.setcursorposition.aspx – digEmAll 2010-08-25 12:24:06

+0

呃,我的不好。我認爲,設置光標位置僅適用於Console.Write,適用於Console.Error.Write。謝謝。 – nothrow 2010-08-25 12:24:45

回答

6

你可以寫信給Console.Error,雖然它可以被重定向,但它與stdout是分開的。

是否可以在控制檯上爲stderr設置光標位置?

編輯:假設標準錯誤並沒有被重定向,請參閱Console.CursorTopConsole.CursorLeft。有various other members on the Console class,你可能會發現有用的。

要直接回答您的問題,請使用Win32 WriteConsole函數。就我所見,.NET框架沒有直接寫入控制檯窗口的方法。

+0

謝謝,但請參閱我的編輯。 – nothrow 2010-08-25 12:18:37

0

如果我運行程序並重定向它的StandardOutput和StandardError,那麼當沒有控制檯時,您希望寫入什麼?因爲這個原因,答案很可能是「你不行」(除非使用瘋狂的黑客,這可能涉及你稱爲不想使用的Windows API)。

將控制檯窗口想象成一個UI元素,它允許用戶查看程序的stdout/stderr(並提供stdin)。它並不存在任何其他用途。

+0

奇怪的是,telnet.exe不使用stdout或stderr,但仍然寫入控制檯。我還沒有找到如何! – 2015-01-17 16:48:42

0

其實我最終實現了低級別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();    
    } 
} 
相關問題