为什么在使用CreateFile(“CONOUT $”…)将控制台重定向回活动屏幕缓冲区后没有文字颜色?

我有一个基于此设置的旧应用程序(但更高级): https : //stackoverflow.com/a/33441726/1236397

基本上,它运行,处理东西和关闭,只在需要时打开一个窗口(通过另一个应用程序运行)。 自从在Windows 10上将其移植到Visual Studio 2017后,输出窗口无法工作。 经过一番调查后,问题似乎与标准输出被重定向到控制台应用程序有关(输出类型必须是“Windows应用程序”才能最初隐藏所有窗口)。 在这种情况下,在调试时,没有文本输出,这需要重置重定向的输出。 这是使用CreateFile("CONOUT$", ...)来获取并将控制台重定向回显示缓冲区输出。

 [DllImport("kernel32.dll", CharSet = CharSet.Auto)] //, EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall private static extern IntPtr CreateFileW( string lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile ); const UInt32 GENERIC_WRITE = 0x40000000; const UInt32 GENERIC_READ = 0x80000000; const UInt32 OPEN_EXISTING = 0x00000003; const int STD_INPUT_HANDLE = -10; const int STD_OUTPUT_HANDLE = -11; const int STD_ERROR_HANDLE = -12; var outFile = CreateFileW("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, IntPtr.Zero); var safeHandle = new SafeFileHandle(outFile, true); SetStdHandle(STD_OUTPUT_HANDLE, outFile); var fs = new FileStream(safeHandle, FileAccess.Write); var writer = new StreamWriter(fs) { AutoFlush = true }; Console.SetOut(writer); 

这有效; 但是,没有颜色支持。 如何启用颜色?

事实certificate,经过大量挖掘后,似乎有一种模式在应用程序以“Windows应用程序”模式运行时无法设置:

ENABLE_VIRTUAL_TERMINAL_INPUT ( doc )

这是如何设置它:

 if (GetConsoleMode(outFile, out var cMode)) SetConsoleMode(outFile, cMode | ENABLE_VIRTUAL_TERMINAL_INPUT); 

但是,它仍然不起作用,这就是我的问题所在。 if语句总是会失败,因为只为CreateFileW()指定了GENERIC_WRITE ! 变成GENERIC_READ需要设置,否则,你无法读取当前模式。 CreateFileW行应该是这样的:

 var outFile = CreateFileW("CONOUT$", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, IntPtr.Zero); 

我的最终代码与此不同,但如果需要,我在这里为其他人编写了一个示例:

 var outFile = CreateFileW("CONOUT$", GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, /*FILE_ATTRIBUTE_NORMAL*/0, IntPtr.Zero); var safeHandle = new SafeFileHandle(outFile, true); SetStdHandle(STD_OUTPUT_HANDLE, outFile); var fs = new FileStream(safeHandle, FileAccess.Write); var writer = new StreamWriter(fs) { AutoFlush = true }; Console.SetOut(writer); if (GetConsoleMode(outFile, out var cMode)) SetConsoleMode(outFile, cMode | ENABLE_VIRTUAL_TERMINAL_INPUT); 

大量的时间浪费在试图从各处分散的信息中解决这个问题,所以我希望这有助于节省别人的时间。 ;)