web-dev-qa-db-ja.com

WPF Windowsアプリケーションから実際のコンソールへのConsole.WriteLineの出力

背景:既存のWPFWindowsアプリケーションにコマンドラインとバッチ処理機能を追加するのに苦労しています。起動時にいくつかのオプションを検出すると、ウィンドウが表示されないようにし、いくつかの処理を行ってすぐに終了します。さて、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>

ただし、can出力をリダイレクトします。

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

C:\test>type out.txt
Start
Stop

残念ながらCONへのリダイレクトは機能しません:

C:\test>WpfConsoleTest.exe > CON

C:\test>

もう1つの問題は、WpfConsoleTest.exeが起動後に終了することですimmedietaly。そう:

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

このアプローチはほとんど問題ありません。バットにまとめると、エラーコードなどを保持できます。 1つの大きな落とし穴は、アプリケーションの終了後に出力を取得することです。つまり、進行状況を追跡する方法はなく、進行中の処理が完了するまで待つ必要があります。

したがって、私の質問は次のとおりです。WPFから親コンソールに出力する方法Windows Applicationまた、WPFからstdout/stderrを取得するのが難しいのはなぜですか。

プロジェクトの設定でアプリケーションの種類をConsole Applicationに変更できることはわかっていますが、これには厄介な副作用があります。単にダブルクリックしても、コンソールウィンドウが常に表示されます。 EXE。 このソリューション も実行されません。これは、アプリケーションがcmdから実行された場合でも新しいコンソールが作成されるためです。

編集:明確にするために、アプリにexistingコンソールがある場合はそれを出力し、notがない場合は新しいコンソールを作成するようにします。

27
gwiazdorrr

少し掘り下げたところ、 この答え が見つかりました。コードは次のとおりです。

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

入力ありがとうございます!

25
gwiazdorrr

私が過去にやったことは、それをコンソールアプリケーションにして、P/Invokeを呼び出して、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
            }
        }
    }
17
Steve Danner

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

あなたの例でこれを使用するには、これを行うことができるはずです:

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

コマンドラインから実行すると、コンソールに「開始」と「停止」が表示されます。

8
Matt Burland