Sin salida de consola cuando se usa AllocConsole y la architecture de destino x86

Tengo un proyecto de WinForms, y si el usuario quiere una consola de depuración, AllocConsole() una consola con AllocConsole() .

Toda la salida de la consola funciona normalmente con la architecture de destino establecida en “Cualquier CPU”, pero cuando la cambio a “x86” no produce nada ( Console.Read() sigue funcionando como se esperaba). Si abro el EXE directamente, la salida funciona. Parece que Visual Studio lo redirige a su propia ventana de “Salida”.

También probé esta respuesta, pero no funcionó, también probé Console.SetOut(GetStdHandle(-11)) , que tampoco funcionó.

Establecer la architecture de destino en ‘Cualquier CPU’ no es una opción para mí.

Así que aquí están mis dos preguntas:

  • ¿Por qué es este el único caso cuando la architecture de destino está configurada en x86?
  • ¿Cómo puedo exportar a mi consola cuando se ejecuta dentro de Visual Studio?

Cuando se habilita “Habilitar la depuración de código nativo”, la salida de las consolas creadas con AllocConsole se redirige a la ventana de salida de depuración.

La razón por la que esto solo sucede en x86 y no en AnyCPU es porque solo puede depurar código nativo en una aplicación x86.

Tenga en cuenta que este comportamiento solo ocurre con las consolas creadas con AllocConsole. La salida de una aplicación de consola no se redirige.

EDITAR: La otra razón por la que la consola no emite texto es cuando usted escribió en la consola antes de llamar a AllocConsole.

Independientemente de la razón, este código restaurará la salida si fue redirigido y volverá a abrir la consola en caso de que no sea válida. Utiliza el número mágico 7, que es lo que suele ser el manejo de stdout.

 using System; using System.IO; using System.Runtime.InteropServices; public static class ConsoleHelper { public static void CreateConsole() { AllocConsole(); // stdout's handle seems to always be equal to 7 IntPtr defaultStdout = new IntPtr(7); IntPtr currentStdout = GetStdHandle(StdOutputHandle); if (currentStdout != defaultStdout) // reset stdout SetStdHandle(StdOutputHandle, defaultStdout); // reopen stdout TextWriter writer = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true }; Console.SetOut(writer); } // P/Invoke required: private const UInt32 StdOutputHandle = 0xFFFFFFF5; [DllImport("kernel32.dll")] private static extern IntPtr GetStdHandle(UInt32 nStdHandle); [DllImport("kernel32.dll")] private static extern void SetStdHandle(UInt32 nStdHandle, IntPtr handle); [DllImport("kernel32")] static extern bool AllocConsole(); } 

Consulte Cómo detectar si Console.In (stdin) se ha redirigido? para otra forma de detectar si los controladores de la consola han sido redirigidos.

Siguiendo trabajó para mí en vs 2015, ninguno funcionó de otras respuestas:

Fuente: https://social.msdn.microsoft.com/profile/dmitri567/?ws=usercard-mini

 using System; using System.Windows.Forms; using System.Text; using System.IO; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; namespace WindowsApplication { static class Program { [DllImport("kernel32.dll", EntryPoint = "GetStdHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern IntPtr GetStdHandle(int nStdHandle); [DllImport("kernel32.dll", EntryPoint = "AllocConsole", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int AllocConsole(); private const int STD_OUTPUT_HANDLE = -11; private const int MY_CODE_PAGE = 437; static void Main(string[] args) { Console.WriteLine("This text you can see in debug output window."); AllocConsole(); IntPtr stdHandle=GetStdHandle(STD_OUTPUT_HANDLE); 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.WriteLine("This text you can see in console window."); MessageBox.Show("Now I'm happy!"); } } } 

Yo también tuve este problema. Cada vez que intenté depurar mi aplicación, la consola estaba en blanco. Extrañamente, lanzar el exe sin el depurador funcionó bien.

Descubrí que tenía que Enable the Visual Studio hosting process desde el menú de Debug del proyecto.

Stephen tiene razón en que Enable native code debugging redirige la consola a la ventana de Salida. Sin embargo, independientemente de la configuración de depuración del código nativo, no vi ningún resultado en ningún lugar hasta que habilité el proceso de alojamiento de Visual Studio.

Esta podría haber sido la razón por la que simplemente la desactivación de la depuración del código nativo no resolvió su problema.

Ninguna de las respuestas anteriores funcionó bien para mí con VS2017 y Windows 10 (por ejemplo, fallaron si la aplicación de inicio se encontraba en modo de depuración).

A continuación puede encontrar un código poco mejorado. La idea es la misma, pero se eliminan los números mágicos (Ceztko ya lo mencionó) y se inicializan todos los flujos in \ out necesarios.

Este código funciona para mí si creas una nueva consola (alwaysCreateNewConsole = true).

La vinculación a la consola del proceso primario (alwaysCreateNewConsole = false) tiene varios inconvenientes. Por ejemplo, no pude imitar por completo el comportamiento de la aplicación de consola lanzada desde cmd. Y no estoy seguro de que sea posible en absoluto.

Y lo más importante: después de la revisión de la clase de consola, reconsideré la idea general de utilizar la clase de consola con la consola creada manualmente. Funciona bien (espero) para la mayoría de los casos, pero puede traer mucho dolor en el futuro.

  static class WinConsole { static public void Initialize(bool alwaysCreateNewConsole = true) { bool consoleAttached = true; if (alwaysCreateNewConsole || (AttachConsole(ATTACH_PARRENT) == 0 && Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED)) { consoleAttached = AllocConsole() != 0; } if (consoleAttached) { InitializeOutStream(); InitializeInStream(); } } private static void InitializeOutStream() { var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write); if (fs != null) { var writer = new StreamWriter(fs) { AutoFlush = true }; Console.SetOut(writer); Console.SetError(writer); } } private static void InitializeInStream() { var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read); if (fs != null) { Console.SetIn(new StreamReader(fs)); } } private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode, FileAccess dotNetFileAccess) { var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true); if (!file.IsInvalid) { var fs = new FileStream(file, dotNetFileAccess); return fs; } return null; } #region Win API Functions and Constants [DllImport("kernel32.dll", EntryPoint = "AllocConsole", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int AllocConsole(); [DllImport("kernel32.dll", EntryPoint = "AttachConsole", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern UInt32 AttachConsole(UInt32 dwProcessId); [DllImport("kernel32.dll", 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 ); private const UInt32 GENERIC_WRITE = 0x40000000; private const UInt32 GENERIC_READ = 0x80000000; private const UInt32 FILE_SHARE_READ = 0x00000001; private const UInt32 FILE_SHARE_WRITE = 0x00000002; private const UInt32 OPEN_EXISTING = 0x00000003; private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80; private const UInt32 ERROR_ACCESS_DENIED = 5; private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF; #endregion }