2017-01-12 22 views
2

Хорошо, я всегда использовал метод AllocConsole() для вывода консоли, когда дело дошло до необходимости использования Winform, поскольку я использую широкий спектр цветов, когда он приходит к написанию на консоль.Console.Out Выход отображается в окне вывода, необходимо в AllocConsole()

Использование VS 2015 и ниже, AllocConsole в режиме отладки всегда работало должным образом, Console.WriteLine правильно написано. Теперь, используя VS 2017, Console показывает, когда вызывается AllocConsole, вместо выходов console.WriteLine, идущих на эту консоль, он переходит в окно вывода Visual Studio.

Я предпочитаю использовать окно AllocConsole, а не окно Output, потому что я сильно полагаюсь на цвет. Я сделал много исследований, как это исправить, но я не могу найти ответ.

+1

Будучи, что VS2017 все еще находится в стадии RC, [Я хотел бы спросить их непосредственно] (https://docs.microsoft.com/en-us/visualstudio/ide/how-to-report-a- problem-with-visual-studio-2017) –

+0

Возможный дубликат ... Это то, что вы можете установить в проекте. Проверьте ответ Чаза [Как показать вывод/окно консоли в формах] (http://stackoverflow.com/questions/4362111/how-do-i-show-a-console-output-window-in-a -форм-приложение) – JohnG

+0

@JohnG Спасибо! Более простой способ сделать именно то, что нужно. – apotter96

ответ

2

AllocConsole() не работает самостоятельно, потому что VS 2017 выполняет некоторую «отладку магии перенаправления stdout». Чтобы исправить это, вам нужно создать консоль с AllocConsole() и исправить дескриптор stdout.

Вот это отрезала я нашел:

[DllImport("kernel32.dll", 
    EntryPoint = "AllocConsole", 
    SetLastError = true, 
    CharSet = CharSet.Auto, 
    CallingConvention = CallingConvention.StdCall)] 
private static extern int AllocConsole(); 

[DllImport("kernel32.dll", SetLastError = true)] 
private static extern IntPtr CreateFile(
    string lpFileName, 
    uint dwDesiredAccess, 
    uint dwShareMode, 
    uint lpSecurityAttributes, 
    uint dwCreationDisposition, 
    uint dwFlagsAndAttributes, 
    uint hTemplateFile); 

private const int MY_CODE_PAGE = 437; 
private const uint GENERIC_WRITE = 0x40000000; 
private const uint FILE_SHARE_WRITE = 0x2; 
private const uint OPEN_EXISTING = 0x3; 

public static void CreateConsole() 
{ 
    AllocConsole(); 

    IntPtr stdHandle = CreateFile(
     "CONOUT$", 
     GENERIC_WRITE, 
     FILE_SHARE_WRITE, 
     0, OPEN_EXISTING, 0, 0 
    ); 

    SafeFileHandle safeFileHandle = new SafeFileHandle(stdHandle, true); 
    FileStream fileStream = new FileStream(safeFileHandle, FileAccess.Write); 
    Encoding encoding = System.Text.Encoding.GetEncoding(MY_CODE_PAGE); 
    StreamWriter standardOutput = new StreamWriter(fileStream, encoding); 
    standardOutput.AutoFlush = true; 
    Console.SetOut(standardOutput); 

    Console.Write("This will show up in the Console window."); 
} 

Особая благодарность Рамкумар Рамеш для работы вокруг: Console Output is gone in VS2017

1

Опираясь на ответ от wischi, если вы хотите свойства для статический класс консоли для правильной работы, например Console.ForegroundColor, важно установить желаемый доступ к GENERIC_READ | GENERIC_WRITE. Я думаю, причина в том, что Console использует GetConsoleScreenBufferInfo внутренне, и когда я попытался использовать этот метод для дескриптора, возвращаемого CreateFile, только с GENERIC_WRITE, который дал мне ошибку ACCESS_DENIED.

[DllImport("kernel32.dll")] 
private static extern bool AllocConsole(); 

[DllImport("kernel32.dll", SetLastError = true)] 
private static extern IntPtr CreateFile(string lpFileName 
    , [MarshalAs(UnmanagedType.U4)] DesiredAccess dwDesiredAccess 
    , [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode 
    , uint lpSecurityAttributes 
    , [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition 
    , [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes 
    , uint hTemplateFile); 

[DllImport("kernel32.dll", SetLastError = true)] 
private static extern bool SetStdHandle(StdHandle nStdHandle, IntPtr hHandle); 

private enum StdHandle : int 
{ 
    Input = -10, 
    Output = -11, 
    Error = -12 
} 

[Flags] 
enum DesiredAccess : uint 
{ 
    GenericRead = 0x80000000, 
    GenericWrite = 0x40000000, 
    GenericExecute = 0x20000000, 
    GenericAll = 0x10000000 
} 

public static void CreateConsole() 
{ 
    if (AllocConsole()) 
    { 
     //https://developercommunity.visualstudio.com/content/problem/12166/console-output-is-gone-in-vs2017-works-fine-when-d.html 
     // Console.OpenStandardOutput eventually calls into GetStdHandle. As per MSDN documentation of GetStdHandle: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx will return the redirected handle and not the allocated console: 
     // "The standard handles of a process may be redirected by a call to SetStdHandle, in which case GetStdHandle returns the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle to a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle to a console's active screen buffer." 
     // Get the handle to CONOUT$.  
     var stdOutHandle = CreateFile("CONOUT$", DesiredAccess.GenericRead | DesiredAccess.GenericWrite, FileShare.ReadWrite, 0, FileMode.Open, FileAttributes.Normal, 0); 

     if (stdOutHandle == new IntPtr(-1)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     if (!SetStdHandle(StdHandle.Output, stdOutHandle)) 
     { 
      throw new Win32Exception(Marshal.GetLastWin32Error()); 
     } 

     var standardOutput = new StreamWriter(Console.OpenStandardOutput()); 
     standardOutput.AutoFlush = true; 
     Console.SetOut(standardOutput); 
    } 
}