2016-03-07 42 views
0

我有一些代碼:如何從控制檯應用程序接收顏色輸出(如Far)?

cmdProcess = new Process(); 
var procStartInfo = new ProcessStartInfo("cmd", "/k "C:\\Program Files (x86)\\Far Manager\\Far.exe""); 

procStartInfo.RedirectStandardOutput = true; 
procStartInfo.RedirectStandardInput = true; 
procStartInfo.UseShellExecute = false; 

procStartInfo.CreateNoWindow = true; 
cmdProcess.OutputDataReceived += (s, e) => { 
     callbackFn(e.Data + "\n"); 
}; 
cmdProcess.StartInfo = procStartInfo; 

cmdProcess.Start(); 
cmdProcess.BeginOutputReadLine(); 

但有了這個代碼,我只能啓動過程和得到的東西,但不完全,而不是顏色。此外,我試過ReceiveConsoleOutput函數,我只收到空白緩衝區。 使用WinAPI我只能啓動控制檯,沒有別的 - 我不明白。但我並不反對WinAPI的例子,因爲我認爲我的問題可以用它解決。 如果有人能幫助我,我將不勝感激。

P.S.對於壞英語我很抱歉。

+0

我懷疑,你可以讀取輸出 –

+0

在這些項目中的顏色,它是某種可能: [鏈接](https://github.com/cbucher/console) [鏈接](https://github.com/Maximus5/ConEmu) –

+0

我沒有看到任何證據表明這些項目創建子進程,然後捕獲輸出的每個字符的顏色。無論如何,如果我錯了,那麼我想你可以從這些項目中讀取代碼。 –

回答

-1

隨着ReadConsoleOutput代碼是不能工作,因爲它應該,因爲它不是FreeConsole函數被調用 - 豁免從自己的控制檯應用程序

Proof

 public static IEnumerable<string> ReadFromBuffer(IntPtr hOutput, short x, short y, short width, short height) 
     { 
     IntPtr buffer = Marshal.AllocHGlobal(width * height * Marshal.SizeOf(typeof(CHAR_INFO))); 
     if (buffer == null) 
      throw new OutOfMemoryException(); 

     try 
     { 
      COORD coord = new COORD(); 
      SMALL_RECT rc = new SMALL_RECT(); 
      rc.Left = x; 
      rc.Top = y; 
      rc.Right = (short)(x + width - 1); 
      rc.Bottom = (short)(y + height - 1); 

      COORD size = new COORD(); 
      size.X = width; 
      size.Y = height; 

      if (!ReadConsoleOutput(hOutput, buffer, size, coord, ref rc)) 
      { 
       // 'Not enough storage is available to process this command' may be raised for buffer size > 64K (see ReadConsoleOutput doc.) 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 

      IntPtr ptr = buffer; 
      for (int h = 0; h < height; h++) 
      { 
       StringBuilder sb = new StringBuilder(); 
       for (int w = 0; w < width; w++) 
       { 
        CHAR_INFO ci = (CHAR_INFO)Marshal.PtrToStructure(ptr, typeof(CHAR_INFO)); 
        char[] chars = Console.OutputEncoding.GetChars(ci.charData); 
        sb.Append(chars[0]); 
        ptr += Marshal.SizeOf(typeof(CHAR_INFO)); 
       } 
       yield return sb.ToString(); 
      } 
     } 
     finally 
     { 
      Marshal.FreeHGlobal(buffer); 
     } 
    } 

...

 Process proc = new Process(); 
     proc.StartInfo.FileName = "cmd.exe"; 
     proc.StartInfo.Arguments = command; 
     //proc.StartInfo.UseShellExecute = false; 
     proc.Start(); 

     Thread.Sleep(1000); 

     bool resultFree = ConsoleApi.FreeConsole(); 

     if (resultFree) 
     { 
      Debug.WriteLine("FreeConsole: {0}", true); 
     } 
     else 
     { 
      Debug.WriteLine("FreeConsole: {0}", false); 
     } 

     Debug.WriteLine("Process ID: {0}", Convert.ToUInt32(proc.Id)); 

     bool result = ConsoleApi.AttachConsole(Convert.ToUInt32(proc.Id)); 

     Debug.WriteLine("AttachConsole: {0}", result); 

     IntPtr _consoleH = ConsoleApi.GetStdHandle(ConsoleApi.STD_OUTPUT_HANDLE); 

     ConsoleApi.CONSOLE_SCREEN_BUFFER_INFO _bufferInfo; 

     bool getInfo = ConsoleApi.GetConsoleScreenBufferInfo(_consoleH, out _bufferInfo); 

     if (getInfo) 
     { 
      Debug.WriteLine("GetConsoleScreenBufferInfo: {0}x{1}", _bufferInfo.dwSize.X, _bufferInfo.dwSize.Y); 
     } 
     else 
     { 
      Debug.WriteLine("GetConsoleScreenBufferInfo: {0}", false); 
     } 

     short _widthConsole = _bufferInfo.dwSize.X; 
     short _heightConsole = _bufferInfo.dwSize.Y; 

     IEnumerable<string> rows = ConsoleApi.ReadFromBuffer(_consoleH, 0, 0, _widthConsole,_heightConsole); 

     foreach (string row in rows) 
     { 
      Debug.WriteLine(row); 
     } 

閱讀顏色:

    [DllImport("kernel32.dll")] 
        public static extern bool ReadConsoleOutputAttribute(IntPtr hConsoleOutput, 
     [Out] ushort[] lpAttribute, uint nLength, COORD dwReadCoord, 
     out uint lpNumberOfAttrsRead); 

...

    string[] colors = new string[]{ 
         "black", 
         "darkblue", 
         "darkgreen", 
         "darkcyan", 
         "darkred", 
         "darkmagenta", 
         "brown", 
         "white", 
         "lightgrey", 
         "blue", 
         "green", 
         "cyan", 
         "red", 
         "magenta", 
         "yellow", 
         "white" 
        }; 

       for (int i = 0; i < _rowsList.Length; i++) 
       { 

        ushort[] lpAttr = new ushort[_widthConsole]; 

        ConsoleApi.COORD _coordReadAttr = new ConsoleApi.COORD(0,(short)i); 

        uint lpReadALast; 

        bool readAttr = ConsoleApi.ReadConsoleOutputAttribute(_consoleH, lpAttr, Convert.ToUInt32(_widthConsole), _coordReadAttr, out lpReadALast); 

        string[] attrText = new string[_widthConsole]; 

        for (int _attr = 0; _attr < lpAttr.Length; _attr++) 
        { 
         string _text = colors[lpAttr[_attr] & 0x0F]; 
         string _background = colors[((lpAttr[_attr] & 0xF0) >> 4) & 0x0F]; 

         attrText[_attr] = _text + "|" + _background; 
        } 
       } 
+0

使用此方法可以獲得背景顏色和文本:ReadConsoleOutputAttribute –

+0

這是否回答您提問的問題? –

+0

@David Heffernan是的 –

2

你談論兩件不同的事情。 ConEmu和原來的控制檯有顏色支持,但是這是通過console buffer APIhere是一個完整的C#庫)實現的。控制檯不僅支持着色,還支持光標和鼠標。然而,他們中沒有一個與標準輸出有關。

但是,如果您想要在標準輸出中接收顏色信息,則可以使用終端通信中的標準ANSI escape sequences(也可用於ANSI graphics art),還支持顏色和光標定位,並且可以被編碼爲字符流。

但是,如果您調用的進程不轉儲ANSI序列,則(cmd不會執行此操作),您將不會收到任何顏色信息。

+0

那麼,你能解釋一下如何在C#中使用控制檯緩衝區API?或者請帶上我的工作教程/例子的幾個鏈接? –

+0

我已經編輯了答案,已添加到C#庫的鏈接。 – taffer

+0

該庫創建的控制檯應用程序比C#中的標準程度更低,但不適用於已創建控制檯進程的數據,但仍感謝您的答案! –

相關問題