从WPF Windows应用程序输出Console.WriteLine到实际控制台

背景:我正在努力为现有的WPF Windows应用程序添加命令行和批处理function。 当我在启动时检测到一些选项时,我禁止窗口出现,进行一些处理并立即退出。 现在,因为没有UI,我想将一些消息输出到stdout / stderr。 考虑以下代码:

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); } } } 

当我从命令行运行时,我希望以下输出:

 Start Stop 

但反而:

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

但是,您可以重定向输出:

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

不幸的是,重定向到CON不起作用:

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

另一个问题是WpfConsoleTest.exe在启动后立即退出。 所以:

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

但:

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

到目前为止我能够提供的最佳解决方案是使用start /B /wait

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

这种方法大多没问题 – 如果你把它包装成一个蝙蝠,你可以保留错误代码等等。 一个巨大的垮台是你在申请结束后获得输出,即你无法跟踪进度,你必须等待正在进行的任何事情才能完成。

因此,我的问题是: 如何从WPF Windows应用程序输出到父控制台? 另外,为什么很难从WPF中获取stdout / stderr?

我知道我可以在项目设置中将应用程序类型更改为控制台应用程序 ,但这有一个令人讨厌的副作用 – 控制台窗口始终可见,即使您只是双击exe。 此解决方案也不会这样做,因为它创建了一个新的控制台,即使应用程序是从cmd运行的。

编辑:澄清一下,我希望我的应用程序输出到现有的控制台(如果有的话),如果缺少则不要创建新的控制台。

经过深入挖掘后,我找到了答案 。 代码现在是:

 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); } } } 

直接调用exe仍然有一个令人讨厌的副作用,与立即返回的调用相关联:

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

解决方案是再次使用start

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

感谢您的投入!

我过去做的是将它作为一个控制台应用程序,并在我显示WPF窗口后调用P / Invoke隐藏应用程序的关联控制台窗口:

 //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 } } } 

WPF应用程序默认情况下没有控制台,但您可以轻松地为它创建一个,然后像在控制台应用程序中一样写入它。 我之前使用过这个助手类:

 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(); } 

要在您的示例中使用它,您应该能够这样做:

 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); } } } 

现在,如果从命令行运行它,您应该看到写入控制台的“开始”和“停止”。

在项目属性中,您可以将项目类型从Windows应用程序更改为控制台应用程序,而AFAIK唯一的区别是您可以在整个应用程序的生命周期内使用控制台。 我没有尝试使用WPF。

如果要打开和关闭控制台,则应使用Alloc/FreeConsole ,但更改项目类型通常更简单。