2010-05-02 65 views
37

我想了解是否有另一種(更快)的方式來輸出文本使用C#.NET比單純控制檯應用程序窗口,BACKGROUNDCOLORForegroundColor方法和屬性?我瞭解到每個單元格都有一個背景顏色和一個前景色,我想要比使用上述方法更快地緩存/緩衝/寫入。如何將快速彩色輸出寫入控制檯?

也許有一些使用Out緩衝區的幫助,但我不知道如何將顏色編碼到流中,如果這是顏色數據所在的位置。

這是一個逆向文本遊戲,我想實現在哪裏使用標準顏色和ascii字符來佈置遊戲。

請幫助:)

更新:

OUT和緩衝可能不是什麼,我需要與周圍亂。似乎有一個由控制檯擁有的屏幕緩衝區。我不知道如何訪問它,也許我只是運氣不好,除非我導入一些dll。

回答

38

更新:增加了一個樣本
如果你準備做一些P/Invoke的東西,這可能會有所幫助。

基本上,如果你得到一個控制檯緩衝區的句柄,那麼你可以使用標準的Win32 API來操作緩衝區,甚至可以將整個緩衝區關閉屏幕,並將其傳送到控制檯。

唯一棘手的部分是獲取控制檯緩衝區的句柄。我沒有在.NET中嘗試過這種方式,但在過去的幾年中,您可以通過使用CreateFile(您將需要P/Invoke this)來獲取當前控制檯的句柄,並打開「CONOUT $」,然後您可以使用句柄將返回傳遞給其他API。

的P/Invoke爲的CreateFile
http://www.pinvoke.net/default.aspx/kernel32/CreateFile.html

你也可以使用WriteConsoleOutput所有的人物和他們的屬性從內存緩衝區控制檯緩衝區中移動。
http://msdn.microsoft.com/en-us/library/ms687404(VS.85).aspx

您可以將一個很好的庫放在一起,以提供對控制檯緩衝區的低級訪問。

因爲我想讓我的.NET再次受到傷害,所以我想我會試試看這個,看看我能否得到它的工作。這是一個樣例,它將填滿所有字母A-Z並貫穿所有forground屬性0-15。我想你會對錶演留下深刻的印象。我會說實話,我沒有花太多時間閱讀這段代碼,所以錯誤檢查是零,這裏或那裏可能有一個小錯誤,但它應該讓你去與其餘的API。

using System; 
using System.IO; 
using System.Runtime.InteropServices; 
using Microsoft.Win32.SafeHandles; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 

    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    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)] 
    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 short Attributes; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct SmallRect 
    { 
     public short Left; 
     public short Top; 
     public short Right; 
     public short Bottom; 
    } 


    [STAThread] 
    static void Main(string[] args) 
    { 
     SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero); 

     if (!h.IsInvalid) 
     { 
     CharInfo[] buf = new CharInfo[80 * 25]; 
     SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = 80, Bottom = 25 }; 

     for (byte character = 65; character < 65 + 26; ++character) 
     { 
      for (short attribute = 0; attribute < 15; ++attribute) 
      { 
      for (int i = 0; i < buf.Length; ++i) 
      { 
       buf[i].Attributes = attribute; 
       buf[i].Char.AsciiChar = character; 
      } 

      bool b = WriteConsoleOutput(h, buf, 
       new Coord() { X = 80, Y = 25 }, 
       new Coord() { X = 0, Y = 0 }, 
       ref rect); 
      } 
     } 
     } 
     Console.ReadKey(); 
    } 
    } 
} 
+0

非常感謝您的幫助!我現在只是能夠得到一些基本的輸出後一些亂七八糟。我使用GetStdHandle獲取緩衝區,然後將它傳遞給CharInfo的矩形數組。將檢查你的下一個! – Statement 2010-05-02 20:55:26

+2

實際上,GetStdHandle可以取代CreateFile的調用。 – 2010-05-02 21:06:40

+0

額外酷.... – IAbstract 2011-06-12 17:49:24

5

如果您看看Console的改變控制檯顏色屬性的實現,它們將從kernel32.dll委託給SetConsoleTextAttribute方法。此方法使用character attributes作爲輸入來設置前景色和背景色。

從幾個MSDN文檔頁面,每個屏幕緩衝區(其中一個控制檯有一個)都有一個二維數組的字符信息記錄,每個記錄由CHAR_INFO表示。這決定了每個角色的顏色。您可以使用SetConsoleTextAttribute方法來處理此操作,但這適用於寫入控制檯的任何新文本 - 您無法操作控制檯上已存在的文本。

除非在控制檯文本顏色屬性(看起來不太可能)中存在較低級別的鉤子,否則我認爲您使用這些方法時會卡住。


有一兩件事你可以嘗試是創建一個新的屏幕緩衝區,寫了出來,然後切換它是使用SetConsoleActiveScreenBuffer控制檯的當前緩衝區。這個可能會產生更快的輸出,因爲您會將所有輸出寫入非活動緩衝區。