que - switch en c#
No hay salida de consola cuando se utiliza AllocConsole y la arquitectura de destino x86 (4)
Cuando "Habilitar depuración de código nativo" está habilitado, 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 ocurre en x86 y no en AnyCPU es porque solo puede depurar el 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 para que la consola no genere texto es cuando escribe en la consola antes de llamar a AllocConsole
.
Independientemente del motivo, este código restaurará la salida si se redirigió 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 el controlador de stdout
generalmente equivale a.
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();
}
¿ Ver cómo detectar si Console.In (stdin) ha sido redirigido? para otra forma de detectar si los manejadores de la consola han sido redirigidos.
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 arquitectura de destino establecida en "Cualquier CPU", pero cuando la cambio a "x86", no se muestra nada ( Console.Read()
aún funciona 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 intenté this respuesta, pero no funcionó, también probé Console.SetOut(GetStdHandle(-11))
, que tampoco funcionó.
Establecer la arquitectura de destino en ''Cualquier CPU'' no es una opción para mí.
Así que aquí están mis dos preguntas:
- ¿Por qué es así solo cuando la arquitectura de destino se establece en x86?
- ¿Cómo puedo enviar a mi consola cuando ejecuto dentro de Visual Studio?
Los siguientes funcionaron para mí en vs 2015, ninguno funcionó a partir 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!");
}
}
}
Ninguna de las respuestas anteriores me funcionó bien con VS2017 y Windows 10 (por ejemplo, fallaron si se inicia la aplicación en modo de depuración).
A continuación puedes encontrar un poco de código mejorado. La idea es la misma, pero los números mágicos se eliminan (Ceztko ya lo mencionó) y se inicializan todos los flujos de entrada y salida necesarios.
Este código funciona para mí si crea una nueva consola (alwaysCreateNewConsole = true).
La conexión a la consola del proceso padre (alwaysCreateNewConsole = false) tiene varios inconvenientes. Por ejemplo, no pude imitar completamente el comportamiento de la aplicación de consola iniciada 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 usar 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
}
Yo también tuve este problema. Cada vez que intentaba depurar mi aplicación, la consola estaba en blanco. Extrañamente, el lanzamiento del exe sin el depurador funcionó bien.
Descubrí que tenía que Enable the Visual Studio hosting process
desde el menú 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 ninguno de los dos lugares hasta que habilité el proceso de alojamiento de Visual Studio.
Esta podría haber sido la razón por la que simplemente deshabilitar la depuración de código nativo no solucionó su problema.