29

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

もう 1 つの問題は、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

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

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

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

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

4

4 に答える 4

27

少し掘り下げた後、私はこの答えを見つけました。コードは次のとおりです。

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

ご意見ありがとうございます。

于 2012-07-21T10:01:47.940 に答える
17

私が過去に行ったことは、それをコンソール アプリケーションにし、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
            }
        }
    }
于 2012-05-02T14:48:37.850 に答える
8

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

これで、コマンド ラインから実行すると、コンソールに "Start" と "Stop" が表示されるはずです。

于 2012-05-02T14:42:20.823 に答える
-1

プロジェクトのプロパティで、プロジェクトの種類を Windows アプリケーションからコンソール アプリケーションに変更できます。私の知る限り、唯一の違いは、アプリケーションの有効期間を通じてコン​​ソールを使用できることです。ただし、WPFで試したことはありません。

コンソールを開いたり閉じたりする場合は、 を使用する必要がありますAlloc/FreeConsoleが、通常はプロジェクト タイプを変更する方が簡単です。

于 2012-05-02T14:47:44.407 に答える