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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10415807/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 13:45:53  来源:igfitidea点击:

Output Console.WriteLine from WPF Windows Applications to actual console

c#wpfbatch-filecmd

提问by gwiazdorrr

Background: I am struggling to add command line and batch processing capabilities to an existing WPF Windows Application. When I detect some options at startup I suppress the window from appearing, do some processing and quit immedietally. Now, because there's no UI I'd like to output some messages to stdout/stderr. Consider following code:

背景:我正在努力向现有的 WPF Windows 应用程序添加命令行和批处理功能。当我在启动时检测到一些选项时,我会抑制窗口出现,进行一些处理并立即退出。现在,因为没有 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);
        }
    }
}

When I run from command line I would expect following output:

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

Start
Stop

But instead:

但反而:

C:\test>WpfConsoleTest.exe

C:\test>

You canredirect output, though:

不过,您可以重定向输出:

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

C:\test>type out.txt
Start
Stop

Redirecting to CON does not work, unfortunately:

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

C:\test>WpfConsoleTest.exe > CON

C:\test>

Another problem is that WpfConsoleTest.exe quits immedietalyafter start. So:

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

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

C:\test>

But:

但:

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

The best solution I was able to come with so far is to use start /B /wait:

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

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

This approach is mostly ok - if you wrap it up in a bat you can preserve error code and so on. The one huge downfall is that you get output after application ends, i.e. there's no way you can track progress, you have to wait for whatever is going on to finish.

这种方法基本上没问题——如果你把它包在一个蝙蝠里,你可以保留错误代码等等。一个巨大的缺点是您在应用程序结束后获得输出,即您无法跟踪进度,您必须等待正在发生的任何事情完成。

Therefore, my question is: How to output to parent console from WPF Windows Application?Also, why is so hard to grab stdout/stderr from WPF?

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

I know that I could change application type to Console Applicationin project settings, but this has a nasty side effect - console window is visible all the time, even if you simply double click the exe. This solutionalso won't do, because it create a newconsole, even if application was run from cmd.

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

EDIT: to clarify, I want my app to output to the existingconsole if there is one and notto create a new one if it is missing.

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

采纳答案by gwiazdorrr

After digging up a bit, I found this answer. The code is now:

经过一番挖掘,我找到了这个答案。现在的代码是:

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

Calling the exe directly still has a nasty side effect, connected with the call returning immediately:

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

C:\test>WpfConsoleTest.exe

C:\test>Start
Stop

^^^^
The cursor will stay here waiting for the user to press enter!

The solution is, once again, to use start:

解决方案是再次使用start

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

Thanks for input!

感谢您的输入!

回答by Matt Burland

A WPF application will not have a console by default, but you can easily create one for it and then write to it just like in a console app. I've used this helper class before:

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

public class ConsoleHelper
{
    /// <summary>
    /// Allocates a new console for current process.
    /// </summary>
    [DllImport("kernel32.dll")]
    public static extern Boolean AllocConsole();

    /// <summary>
    /// Frees the console.
    /// </summary>
    [DllImport("kernel32.dll")]
    public static extern Boolean FreeConsole();
}

To use this in your example, you should be able to do this:

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

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

And now, if you run it from the command line, you should see "Start" and "Stop" written to the console.

现在,如果您从命令行运行它,您应该会看到“Start”和“Stop”写入控制台。

回答by Kendall Frey

In the project properties, you can change the project type from a Windows application to a Console application, and AFAIK the only difference is that you get a console to use throughout the application's lifetime. I haven't tried it with WPF though.

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

If you want to open and close a console, you should use Alloc/FreeConsole, but it is usually simpler to change the project type.

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

回答by Steve Danner

What I've done in the past is to make it a console application and call P/Invoke to hide the app's associated Console window once I've shown my WPF Window:

我过去所做的是使其成为控制台应用程序,并在显示 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
            }
        }
    }