Salida Console.WriteLine desde WPF Windows Applications a la consola real

Antecedentes: Tengo dificultades para agregar capacidades de procesamiento por lotes y línea de comandos a una aplicación Windows WPF existente. Cuando detecto algunas opciones al inicio, evito que aparezca la ventana, hago algún procesamiento y salgo de inmediato. Ahora, como no hay interfaz de usuario, me gustaría enviar algunos mensajes a stdout / stderr. Considera seguir el código:

namespace WpfConsoleTest { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { Console.WriteLine("Start"); System.Threading.Thread.Sleep(1000); Console.WriteLine("Stop"); Shutdown(0); } } } 

Cuando corro desde la línea de comando esperaría el siguiente resultado:

 Start Stop 

Pero en lugar:

 C:\test>WpfConsoleTest.exe C:\test> 

Sin embargo, puedes redirigir la salida:

 C:\test>WpfConsoleTest.exe > out.txt C:\test>type out.txt Start Stop 

Redirigir a CON no funciona, desafortunadamente:

 C:\test>WpfConsoleTest.exe > CON C:\test> 

Otro problema es que WpfConsoleTest.exe cierra inmediatamente después del inicio. Asi que:

 C:\test>WpfConsoleTest.exe > out.txt & type out.txt C:\test> 

Pero:

 C:\test>WpfConsoleTest.exe > out.txt & ping localhost > nul & type out.txt Start Stop 

La mejor solución con la que he podido llegar hasta ahora es usar start /B /wait :

 C:\test>start /B /wait WpfConsoleTest.exe > out.txt & type out.txt Start Stop 

En general, este enfoque está bien; si lo envuelve en un bate, puede conservar el código de error, y así sucesivamente. La única gran caída es que obtienes resultados una vez que finaliza la aplicación, es decir, no hay manera de que puedas seguir el progreso, tienes que esperar a que todo lo que está pasando termine.

Por lo tanto, mi pregunta es: ¿Cómo dar salida a la consola principal desde la aplicación Windows de WPF? Además, ¿por qué es tan difícil obtener stdout / stderr de WPF?

Sé que podría cambiar el tipo de aplicación a la aplicación de consola en la configuración del proyecto, pero esto tiene un desagradable efecto secundario: la ventana de la consola está visible todo el tiempo, incluso si simplemente hace doble clic en el archivo ejecutable. Esta solución tampoco funcionará, ya que crea una consola nueva , incluso si la aplicación se ejecutó desde cmd.

EDITAR: para aclarar, quiero que mi aplicación salga a la consola existente si hay una y no crear una nueva si falta.

Después de excavar un poco, encontré esta respuesta . El código ahora es:

 namespace WpfConsoleTest { public partial class App : Application { [DllImport("Kernel32.dll")] public static extern bool AttachConsole(int processId); protected override void OnStartup(StartupEventArgs e) { AttachConsole(-1); Console.WriteLine("Start"); System.Threading.Thread.Sleep(1000); Console.WriteLine("Stop"); Shutdown(0); } } } 

Llamar al exe directamente todavía tiene un desagradable efecto secundario, conectado con la llamada que regresa inmediatamente:

 C:\test>WpfConsoleTest.exe C:\test>Start Stop ^^^^ The cursor will stay here waiting for the user to press enter! 

La solución es, una vez más, utilizar start :

 C:\test>start /wait WpfConsoleTest.exe Start Stop 

Gracias por la entrada!

Lo que hice en el pasado es convertirlo en una aplicación de consola y llamar a P / Invoke para ocultar la ventana de consola asociada de la aplicación una vez que he mostrado mi ventana de WPF:

 //added using statements per comments... using System.Diagnostics; using System.Runtime.InteropServices; internal sealed class Win32 { [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); public static void HideConsoleWindow() { IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle; if (hWnd != IntPtr.Zero) { ShowWindow(hWnd, 0); // 0 = SW_HIDE } } } 

Una aplicación WPF no tendrá una consola de forma predeterminada, pero puede crearla fácilmente y luego escribir en ella como en una aplicación de consola. He usado esta clase de ayudante antes:

 public class ConsoleHelper { ///  /// Allocates a new console for current process. ///  [DllImport("kernel32.dll")] public static extern Boolean AllocConsole(); ///  /// Frees the console. ///  [DllImport("kernel32.dll")] public static extern Boolean FreeConsole(); } 

Para usar esto en su ejemplo, debería poder hacer esto:

 namespace WpfConsoleTest { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { ConsoleHelper.AllocConsole(); Console.WriteLine("Start"); System.Threading.Thread.Sleep(1000); Console.WriteLine("Stop"); ConsoleHelper.FreeConsole(); Shutdown(0); } } } 

Y ahora, si lo ejecuta desde la línea de comando, debería ver “Comenzar” y “Detener” escritos en la consola.

En las propiedades del proyecto, puede cambiar el tipo de proyecto de una aplicación de Windows a una aplicación de consola, y AFAIK la única diferencia es que obtiene una consola para usar durante toda la vida de la aplicación. No lo he intentado con WPF sin embargo.

Si desea abrir y cerrar una consola, debe usar Alloc/FreeConsole , pero generalmente es más sencillo cambiar el tipo de proyecto.